Skip to content

feat(cfg): ip65 refit — un-break BACKEND=ip65 via cert_buf/verify-scratch union - #68

Merged
JC-000 merged 1 commit into
masterfrom
feat/ip65-refit
Jul 29, 2026
Merged

feat(cfg): ip65 refit — un-break BACKEND=ip65 via cert_buf/verify-scratch union#68
JC-000 merged 1 commit into
masterfrom
feat/ip65-refit

Conversation

@JC-000

Copy link
Copy Markdown
Owner

Summary

Plain make BACKEND=ip65 has failed since the nistcurves bump with BSS overflows CRYPTO_COLD_SHADOW by 1406 bytes. The gap is exactly
LIB_NISTCURVES_P256_BSS (1,312 B) — pure ECDSA-verify-time scratch, whose
lifetime is disjoint from cert_buf's (dead once the Certificate handler has
extracted the pubkey). This PR time-shares the two:

  • cfg/c64-https-ip65.cfg: new non-file SCRATCH_UNION region at $A000
    (size $600 — capped at cert_buf's span so lib-BSS growth is a link error,
    never silent corruption); LIB_NISTCURVES_P256_BSS routed there; new
    CERT_BUF_BSS segment pinned start=$A000; TABLES_BSS declared last so
    it packs at exactly $BA00-$BFFF (sqtab_reserved lands $BC00 — the onchip
    bake invariant holds with no extra pinning).
  • src/der_decode.s: cert_buf moved to CERT_BUF_BSS with the lifetime
    contract documented at the declaration (future chain-validation work must
    break the union first).
  • src/net/ip65/exports.s: link-time .assert cert_buf = $A000 drift guard
    (ip65-only TU).
  • UCI cfgs: CERT_BUF_BSS declared first in cold shadow — layout-neutral
    (62,977 B PRG, byte-count identical).

Unblocks BOTH ip65 profiles (REU + onchip). c64-nist-curves#54
(minimal-archive) becomes optional headroom, not a blocker. Groundwork for
the REU-less stock-C64 story (with #67's fe25519 fix, branch in flight).

Validation

  • make BACKEND=ip65 → links, 47,105 B PRG; labels: cert_buf=$A000=fp_wide
    (union live), tls_rec_buf=$A600 (outside union, live during verify)
  • make BACKEND=ip65 USE_NISTCURVES_ONCHIP=1 → links; sqtab_reserved=$BC00
    grep guard passes
  • UCI plain / onchip / comb → all link, 62,977 B (unchanged)
  • VICE KATs (ip65 build, -reu): test_x25519.py 71/71; test_x509.py 11/11 —
    incl. 3c/3d parse→verify→parse sequences that scribble the union between
    cert parses (the exact hazard the design must survive)
  • Lifetime audit in the commit message (CV handler reads only tls_rec_buf +
    transcript + pubkey slots; cert_tbs_ptr/len have zero in-tree importers)

🤖 Generated with Claude Code

…atch union
Plain `make BACKEND=ip65` has failed since the nistcurves bump with
`BSS overflows CRYPTO_COLD_SHADOW by 1406 bytes`. The gap is exactly
LIB_NISTCURVES_P256_BSS (1,312 B) — pure ECDSA-verify-time scratch
(fp_wide/fp_r0/fp_inv_*/ec_*/ecdsa_* in libs/nistcurves data_p256.s).
Close it by time-sharing that scratch with cert_buf's 1,536 B, whose
lifetime is disjoint:
- cert_buf is written+parsed only inside x509_parse_cert /
x509_extract_pubkey (via tls_handle_certificate); the pubkey is
extracted into CRYPTO_BSS slots at Certificate-processing time.
- cert_tbs_ptr/cert_tbs_len point into cert_buf but have zero
in-tree readers (exported, never imported).
- tls_handle_cert_verify (where the lib scratch is live) reads only
tls_rec_buf + the transcript + the pubkey slots — audited
src/tls_cert.s lines 535-743: sig parse from tls_rec_buf+8,
signed-content rebuild from transcript hash.
- tools/test_x509.py rewrites cert_buf before every parse use; its
verify tests (3a-3d) stage inputs directly and never re-read
cert_buf. tools/test_x25519.py doesn't touch it.
Changes:
- cfg/c64-https-ip65.cfg: new SCRATCH_UNION region ($A000, $600,
non-file) overlapping CRYPTO_COLD_SHADOW's head;
LIB_NISTCURVES_P256_BSS routed there; new CERT_BUF_BSS segment
pinned start=$A000 (tls_rec_buf stays in BSS_TAIL at $A600 —
it is live during verify and must not be in the union span);
TABLES_BSS declared last so it packs at $BA00-$BFFF, putting
mul_dma at $BA00/$BB00 and sqtab at $BC00 — the onchip profile's
sqtab_reserved=$BC00 bake invariant holds with no extra pinning.
- src/der_decode.s: cert_buf moved BSS_TAIL -> CERT_BUF_BSS with the
lifetime contract documented at the declaration.
- cfg/c64-https-uci{,-onchip}.cfg: declare CERT_BUF_BSS first in
CRYPTO_COLD_SHADOW (same total occupancy; UCI needs no union).
- src/net/ip65/exports.s: link-time .assert cert_buf=$A000 so the
union anchor cannot silently drift.
Verified:
- make BACKEND=ip65 LINK OK (47,105 B)
- make BACKEND=ip65 USE_NISTCURVES_ONCHIP=1 LINK OK, sqtab guard OK
- make BACKEND=uci / +ONCHIP / +ONCHIP_COMB all LINK OK (62,977 B,
byte-count identical to pre-change)
- ip65 map: code tops out at $9EE8 (<$A000), cold shadow ends $BFFF,
union layered at $A000-$A51F under CERT_BUF_BSS $A000-$A5FF
- VICE KATs on the ip65 build (-reu): test_x25519.py 71/71,
test_x509.py 11/11 (3c/3d full verifies scribble the union between
the parse tests — the exact hazard the union design must survive)
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@JC-000
JC-000 merged commit 9ad4eb3 into masterJul 29, 2026
JC-000 added a commit that referenced this pull request Aug 12, 2026
The benchmark tables predated three merged changes and one open fix, and
several status claims had gone stale. Measured numbers only — no
extrapolated figures.
**e2e wall-clock.** The 2026-07-20 campaign rows are kept as history and
labelled as such; a new "Post-#74 e2e numbers" block records HEAD:
device profile clock pre-#71 post-#71 post-#74
C64U onchip 48 MHz 51.0 s 125.4 s 44.6 s
C64U onchip 64 MHz 39.7 s (unmeas.) 33.7 s
U64E REU 48 MHz 82.1 s 161.0 s 82.1 s
Both onchip rows land BELOW their pre-regression baselines and the REU row
lands exactly AT it — a REU build cannot contain #69 (its change is inside
.ifdef USE_NISTCURVES_ONCHIP), so the pair is a clean control showing #69
is a SPEEDUP at turbo, not a cost. The doc now states that explicitly,
including why the sign is easy to get wrong: the profile's 1 MHz penalty
exists only because REU DMA is cheap relative to the CPU down there, and
inverts above the crossover. (I got this backwards during the campaign;
recording the reasoning so the next reader doesn't.)
**New: ip65 / stock-C64 wall-clock**, the first ip65 e2e figures we have —
36.0 min honest 1 MHz REU-less, with the phase breakdown, plus the
accelerated runs. Notes that the verify stretch came in 1.4% off the
T(f)=D+C/f prediction three orders of magnitude from where that model was
fit, and that ip65's drain budget is byte-identically unchanged by #74 so
the numbers stand at HEAD.
**Corrected stale claims:**
- "ip65 is NOT packaged: does not link" — it links (#68). Explains the
SCRATCH_UNION lifetime argument and its guards, notes packaging it is now
a live option since a stock C64 + RR-Net has no shipped PRG today, and
demotes c64-nist-curves#54 from blocker to optional headroom.
- The CRYPTO_COLD_SHADOW "1,662 B overflow, cfg relief exhausted" entry,
same fix.
- The X25519-sibling entry claimed the old BSS overflow. Re-measured
2026-07-29: USE_X25519_SIBLING=1 under ip65 still fails, but on a
DIFFERENT problem — X25519_RODATA over CRYPTO_OVERLAY by 2,048 B and
LIB_NISTCURVES_P256_CODE over CRYPTO_RESIDENT by 103 B, i.e. code/rodata
placement (ip65's overlay slot is 4,212 B vs UCI's 7.5 KB), not BSS.
Better to state the measured failure than leave a fixed one on the page.
**New design note** for the post-ServerHello drain: the ip65 property that
motivates it (no MSS in SYN + ACK-only-when-polled), the offline-verify
failure signature it prevents, why the budget must be per-backend (~40 ms
per UCI net_poll vs a cheap ip65 pump — the #73 regression), current
values, and the two open follow-ups (in-crypto polling for large flights;
a wall-clock/idle bound instead of an iteration count, which is what the
section's own rule actually demands).
**New Smoke-tests subsection** for the hardware-free VICE ip65 rig, with
the two prerequisites that are easiest to lose: the patched
ethernet-capable VICE (stock macOS builds gate pcap on geteuid()==0) and
the /dev/bpf permissions that reset every reboot. Also replaces the
"blocked on an upstream ip65 bug (see lost memory note)" line with what is
actually known now.
Stacked on fix/drain-backend-budget: the post-#74 rows describe that PR's
tree, not master's.
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
JC-000 added a commit that referenced this pull request Aug 13, 2026
Two doc-drift nits from the branch review:
- net_tuning.inc and tls13.s quoted the per-UCI-net_poll cost as ~37 ms
(~2.8 ms fence, ~70 s for ip65's 2000-poll budget). CLAUDE.md derives
~40 ms from the measured regression (80.8 s / 1984 polls C64U onchip,
78.9 s / 1984 U64E REU) and is authoritative; the .s comments were
stale by one round of measurement. Anyone sizing NET_SH_DRAIN_INNER
against a wall-clock target now reads one number.
- CLAUDE.md's Variables entry for USE_X25519_SIBLING=1 still pointed at
a "tracked BSS overflow", contradicting the Known-issues entry this
branch rewrote: that BSS overflow was fixed by the #68 refit and the
remaining ip65 failure is a code/rodata placement problem.
Comment-only; both backends rebuild clean (ip65 47,105 B, uci 62,977 B).
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@JC-000