Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
8cffc5b
test(https_e2e): add P-384 cert profile to test listener (Phase 4c)
JC-000 May 15, 2026
a473c33
chore(submodules): bump libs/nistcurves to 90830c9 (post-PR #23 + #24)
JC-000 May 15, 2026
bed099d
build(p384-overlay): wire SHA-384 + ecdsa_verify_with_message_384 wra…
JC-000 May 15, 2026
811158d
build(p384-overlay): split overlay into sha384 + curve halves to fit …
JC-000 May 16, 2026
09fe64d
feat(tls): negotiate ecdsa_secp384r1_sha384 (0x0503) in addition to P…
JC-000 May 16, 2026
f284efa
feat(crypto): activate dual-overlay swap dispatcher (P-384 SHA + curv…
JC-000 May 16, 2026
26a82d4
feat(crypto): TLS-side P-384 verify dispatcher (dual-overlay swap + s…
JC-000 May 16, 2026
baa2fb1
test(p384): KAT smoke test for ecdsa_verify_384 dual-overlay flow
JC-000 May 16, 2026
3fe02a7
fix(p384): shrink CertificateVerify signed blob 146 -> 130 B (Phase 5…
JC-000 May 16, 2026
1c31f8d
fix(p384): separate 48 B P-384 pubkey BSS slots (Phase 5 Fix B)
JC-000 May 16, 2026
251fe53
build(p384): generate overlay-resident equates from labels at build t…
JC-000 May 16, 2026
002952b
build(p384): order-only labels.txt dep on overlay-bin + script harden…
JC-000 May 16, 2026
42a8b1e
test(p384): tools/uci/test_https_local_p384.py + CLAUDE.md update (Ph…
JC-000 May 16, 2026
3c60550
fix(uci): bounded uci_wait_not_busy (TOD-budgeted, mirrors uci_wait_i…
JC-000 May 16, 2026
e52216e
refactor(tools/uci): factor P-384 arbiter monkey-patch into shared he…
JC-000 May 16, 2026
4c6d4a3
test(uci): adopt new c64-test-harness lock/health pattern in test_htt…
JC-000 May 16, 2026
0ae3ee5
test(uci): bump SENTINEL_POLL_TIMEOUT to 5400s for P-384 e2e
JC-000 May 16, 2026
8f28941
fix(uci): bound uci_drain_resp + uci_drain_status (TOD, mirrors uci_w…
JC-000 May 16, 2026
28e042e
build(make): emit cc65 debug info (-g + --dbgfile) for PRG + overlays
JC-000 May 16, 2026
f9f746d
docs(CLAUDE.md): note cc65 .dbg sidecars in Build section
JC-000 May 16, 2026
226cc24
feat: c64-lib-contract alignment + nistcurves v0.3.0 / x25519 v0.5.0+…
JC-000 May 21, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .gitignore
Original file line numberDiff line numberDiff line change
Expand Up@@ -6,7 +6,8 @@ ip65-build/*.bin
ip65-build/*.map
.claude/*
!.claude/settings.json
tools/https_e2e/certs/
tools/https_e2e/certs/*
!tools/https_e2e/certs/README
tools/diag_4de0_*.py
tools/diag_read_live.py
.serena/
276 changes: 215 additions & 61 deletions CLAUDE.md

Large diffs are not rendered by default.

194 changes: 179 additions & 15 deletions Makefile
Original file line numberDiff line numberDiff line change
Expand Up@@ -34,8 +34,8 @@ IP65_DIR := ip65
IP65_BUILD := ip65-build
IP65_BIN := $(IP65_BUILD)/ip65-c64.bin

CA65FLAGS := -I src -I src/inc -I src/crypto/shared -I src/net/$(BACKEND) --debug-info
LD65FLAGS := -C $(CFG) -Ln build/labels.txt -m build/c64-https.map
CA65FLAGS := -I src -I src/inc -I src/crypto/shared -I src/net/$(BACKEND) -I build --debug-info
LD65FLAGS := -C $(CFG) -Ln build/labels.txt -m build/c64-https.map --dbgfile build/c64-https.dbg

# Source inventory.
TOP_SRCS := $(wildcard src/*.s)
Expand DownExpand Up@@ -90,6 +90,65 @@ CRYPTO_SRCS := $(CRYPTO_SRCS_EFFECTIVE)
else ifeq ($(BACKEND),uci)
NET_SRCS := $(UCI_SRCS)
CRYPTO_SRCS := $(CRYPTO_SRCS_EFFECTIVE)

# --- W3: EMBED_P256_OVERLAY=1 stages the P-256 verify .bin as a
# .incbin into CRYPTO_OVERLAY at PRG-load time. Mutually exclusive
# with USE_OVERLAY_P384_EMBED (same slot at $4200) — the rules below
# turn the P-384 SHA embed off when EMBED_P256_OVERLAY=1 to avoid
# overflowing the 7,680 B slot. Default 0 so the un-flagged UCI
# build is byte-identical to today.
#
# Mirrors the P-384 USE_OVERLAY_P384_EMBED bootstrap pattern: the user-
# visible Make flag is `EMBED_P256_OVERLAY=1`; the ca65-level symbol
# `USE_OVERLAY_P256_EMBED` (which gates the .incbin in
# src/crypto/shared/p256_overlay_blobs.s) defaults to the same value
# but can be explicitly overridden via the command line for the
# bootstrap prelim link (avoids the overlay-bin <-> labels.txt cycle on
# a clean tree). Bootstrap workflow:
# make BACKEND=uci EMBED_P256_OVERLAY=1 USE_OVERLAY_P256_EMBED=0
# make BACKEND=uci EMBED_P256_OVERLAY=1
EMBED_P256_OVERLAY ?= 0
USE_OVERLAY_P256_EMBED ?= $(EMBED_P256_OVERLAY)

# Phase 3: embed the two P-384 split overlay blobs in the PRG so boot
# can populate REU banks 6/7 at startup. Gated to UCI (ip65 has no
# room for the SHA blob in main RAM) and to !USE_X25519_SIBLING (the
# sibling rodata occupies CRYPTO_OVERLAY at PRG load time, displacing
# the SHA blob). Adds a build-order dep on the .bin files; a missing
# .bin causes the .incbin to fail, so we extend PRG_DEPS below.
ifneq ($(USE_X25519_SIBLING),1)
# Phase 5 Fix D: respect a command-line USE_OVERLAY_P384_EMBED=0 so the
# bootstrap rule below can do a no-overlay-embed prelim link to break
# the overlay-bin <-> labels.txt cycle on a clean tree. Default is
# still 1 unless the operator explicitly disables it. W3: also
# auto-turn-off when EMBED_P256_OVERLAY=1 (mutually-exclusive slot).
ifeq ($(EMBED_P256_OVERLAY),1)
USE_OVERLAY_P384_EMBED ?= 0
else
# W5 / libs/nistcurves cfa9085+ bump: PR #25's SHA-384 rotr LUTs
# (LIB_NISTCURVES_SHA384_TABLES, 3 KB page-aligned) push the SHA-384
# overlay-half archive above the 7.5 KB CRYPTO_OVERLAY slot limit by
# ~1.5 KB. Default flips to 0 until the SHA-384 LUTs are either:
# - relocated out of the overlay slot (consumer-side path: route
# LIB_NISTCURVES_SHA384_TABLES to a separate resident region and
# teach the standalone overlay cfg to omit them from the .bin), or
# - shrunk on the library side (eg by sharing rotr LUTs across the
# 8 shift amounts, or runtime-generating them at boot).
# Set USE_OVERLAY_P384_EMBED=1 explicitly to attempt the embed (will
# fail at link with an overflow until the SHA-384 LUTs are dealt with).
USE_OVERLAY_P384_EMBED ?= 0
endif
ifeq ($(USE_OVERLAY_P384_EMBED),1)
CA65FLAGS += -D USE_OVERLAY_P384_EMBED=1
endif
endif

# W3: propagate USE_OVERLAY_P256_EMBED to ca65 (the .incbin in
# src/crypto/shared/p256_overlay_blobs.s is gated on this). The
# default-derivation from EMBED_P256_OVERLAY happens above.
ifeq ($(USE_OVERLAY_P256_EMBED),1)
CA65FLAGS += -D USE_OVERLAY_P256_EMBED=1
endif
# Phase C.3: add c64-nist-curves P-384 primitives as a REU overlay.
# Variable-base P-384 point ops (double/add/jacobian-to-affine) only —
# see tools/integration/build_nistcurves_p384.sh for the scope rationale.
Expand All@@ -107,7 +166,12 @@ CRYPTO_SRCS := $(CRYPTO_SRCS_EFFECTIVE)
# integration can be re-enabled by uncommenting the two lines below once
# the cfg is extended.
#CA65FLAGS += -D USE_NISTCURVES_P384=1
#SIBLING_LIB_ARCHIVES += build/lib/nistcurves-p384.a
# Phase 1.5 split the monolithic nistcurves-p384.a into two halves
# (nistcurves-p384-sha384.a + nistcurves-p384-curve.a) since the
# combined image overflowed the live 7.5 KB CRYPTO_OVERLAY slot.
# Either-of approach for the production wire-up will be Phase 4a.
#SIBLING_LIB_ARCHIVES += build/lib/nistcurves-p384-sha384.a
#SIBLING_LIB_ARCHIVES += build/lib/nistcurves-p384-curve.a
else
$(error Unknown BACKEND=$(BACKEND); expected ip65 or uci)
endif
Expand All@@ -134,24 +198,64 @@ else
PRG_DEPS := $(ALL_OBJS)
endif

# Phase 3: when USE_OVERLAY_P384_EMBED is on, add the two .bin files
# to PRG_DEPS so make builds them before the .incbin in
# src/crypto/shared/p384_overlay_blobs.s tries to read them.
ifeq ($(USE_OVERLAY_P384_EMBED),1)
PRG_DEPS += build/lib/overlay-p384-sha384.bin build/lib/overlay-p384-curve.bin
PRG_DEPS += build/p384_overlay_equates.inc
build/crypto/shared/p384_overlay_blobs.o: build/lib/overlay-p384-sha384.bin build/lib/overlay-p384-curve.bin
endif

# W3: when USE_OVERLAY_P256_EMBED is on, add the P-256 verify .bin to
# PRG_DEPS so make builds it before the .incbin in
# src/crypto/shared/p256_overlay_blobs.s tries to read it. The .bin
# rule below also has an order-only dep on build/labels.txt for the
# main-PRG label lookup (same bootstrap cycle as P-384). Gated on the
# ca65-level USE_OVERLAY_P256_EMBED rather than EMBED_P256_OVERLAY so
# the bootstrap prelim link (with USE_OVERLAY_P256_EMBED=0) skips the
# .bin dep cleanly.
ifeq ($(USE_OVERLAY_P256_EMBED),1)
PRG_DEPS += build/lib/nistcurves-p256-verify.bin
build/crypto/shared/p256_overlay_blobs.o: build/lib/nistcurves-p256-verify.bin
endif

$(PRG): $(PRG_DEPS)
@mkdir -p build
$(LD65) $(LD65FLAGS) -o $@ $(ALL_OBJS) $(SIBLING_LIB_ARCHIVES)
# Rewrite ca65 label format `al XXXXXX .name` -> VICE format `al C:XXXX .name`
# so the c64-test-harness Labels.from_file() reader can parse it.
sed -i '' 's/^al 00\([0-9a-fA-F]\{4\}\) /al C:\1 /' $(LABELS)

# Phase 5 Fix D: $(LABELS) is normally a side-effect of the $(PRG)
# link recipe; we don't add an explicit rule. The overlay-bin rule
# below has an order-only dep on $(LABELS) so its lookup_label()
# resolves the main PRG's runtime mul_dma_lo / mul_dma_hi /
# mul_cached_a / reu_fetch_mul_row to real addresses (was: silent
# $0000 fallback that produced a curve overlay whose fp_mul_384
# read/wrote $0000 and silently corrupted downstream state).
#
# Bootstrap workflow (clean tree under USE_OVERLAY_P384_EMBED=1):
# make BACKEND=uci USE_OVERLAY_P384_EMBED=0 # produce labels.txt
# make BACKEND=uci # real link with overlays
# After this two-step bootstrap, plain `make BACKEND=uci` rebuilds
# incrementally without intervention. The script
# tools/integration/build_nistcurves_p384_bin.sh prints a clear error
# pointing at this two-step procedure if it runs without labels.txt
# (vs the old silent $0000 stub fallback).


link: $(PRG)

build/%.o: src/%.s
@mkdir -p $(dir $@)
$(CA65) $(CA65FLAGS) -o $@ $<

# Phase C.3: c64-nist-curves sibling archive (libs/nistcurves/ submodule).
# Same gating as x25519: only linked under BACKEND=uci; ip65 continues
# without P-384 entirely. Exports only the variable-base primitives
# (see the build script for the excluded symbols and why).
build/lib/nistcurves-p384.a:
# Phase 1.5 split: produces TWO archives, one per overlay half. The
# script writes both with a single invocation; the second target is a
# pseudo-rule that piggybacks on the first.
build/lib/nistcurves-p384-sha384.a build/lib/nistcurves-p384-curve.a:
@mkdir -p build/lib
bash tools/integration/build_nistcurves_p384.sh

Expand All@@ -176,18 +280,78 @@ build/lib/x25519.a:
@mkdir -p build/lib
bash tools/integration/build_x25519.sh

# Phase C.3b: P-384 overlay IMAGE + labels for harness-time use only.
# The production PRG does NOT link nistcurves-p384.a — this is smoke-test
# infrastructure. tools/test_p384_symbols.py loads overlay-p384.bin into
# REU at test time via a trampoline, then calls crypto_swap_to_p384 to
# page it into the live slot. Keeps the main PRG size unchanged.
# Phase C.3b / Phase 1.5 split: P-384 overlay IMAGES + labels for
# harness-time use only. The production PRG does NOT link
# nistcurves-p384-{sha384,curve}.a — these are smoke-test infrastructure.
# A future Phase 3 / Phase 4a harness will load both .bins into REU at
# test time, then DMA them into the live slot via two new swap entry
# points (crypto_swap_to_p384_sha384 / crypto_swap_to_p384_curve);
# the existing crypto_swap_to_p384 entry point is now stale -- see the
# comment block at the top of src/crypto/shared/crypto_swap.s.
#
# All four outputs (two .bins + two labels files) are produced by a
# single script invocation; the rule lists all four targets so make
# only runs the script once even when several are stale.
#
# Both outputs live below build/; depend on the archive being built first.
build/lib/overlay-p384.bin build/labels-p384.txt: build/lib/nistcurves-p384.a cfg/p384-overlay.cfg tools/integration/build_nistcurves_p384_bin.sh
# Phase 5 Fix D: build/labels.txt is an ORDER-ONLY dependency. The
# overlay-bin script's lookup_label() reads build/labels.txt to resolve
# mul_dma_lo / mul_dma_hi / mul_cached_a / reu_fetch_mul_row to the
# main PRG's runtime addresses (so the curve overlay's fp_mul_384
# reads/writes the right $BA00 / $BB00 / etc. cells). On a clean
# build, build/labels.txt doesn't exist yet when this rule runs and the
# script falls back to $0000 stubs - silently producing an overlay
# image whose fp_mul_384 reads from $0000. Order-only ('|') ensures
# labels.txt exists before the script runs but doesn't trigger an
# overlay rebuild on every main-PRG link.
build/lib/overlay-p384-sha384.bin build/lib/overlay-p384-curve.bin build/labels-p384-sha384.txt build/labels-p384-curve.txt: \
build/lib/nistcurves-p384-sha384.a build/lib/nistcurves-p384-curve.a \
cfg/p384-overlay-sha384.cfg cfg/p384-overlay-curve.cfg \
tools/integration/build_nistcurves_p384_bin.sh \
| build/labels.txt
bash tools/integration/build_nistcurves_p384_bin.sh

.PHONY: p384-overlay
p384-overlay: build/lib/overlay-p384.bin build/labels-p384.txt
p384-overlay: build/lib/overlay-p384-sha384.bin build/lib/overlay-p384-curve.bin \
build/labels-p384-sha384.txt build/labels-p384-curve.txt

# W3: P-256 verify overlay .bin (library-ingestion architecture).
# Mirrors the P-384 overlay .bin rule: depends on the P-256 sibling
# archive (build/lib/nistcurves-p256.a, already a default PRG dep) +
# the standalone overlay cfg. Order-only dep on build/labels.txt for
# the lookup_label() fallback (same pattern as P-384 — see Fix D
# comment block above).
build/lib/nistcurves-p256-verify.bin build/labels-p256-verify.txt: \
build/lib/nistcurves-p256.a \
cfg/p256-overlay-verify.cfg \
tools/integration/build_nistcurves_p256_bin.sh \
| build/labels.txt
bash tools/integration/build_nistcurves_p256_bin.sh

.PHONY: p256-overlay
p256-overlay: build/lib/nistcurves-p256-verify.bin build/labels-p256-verify.txt

# Phase 5 Fix C: regenerate the P-384 overlay-resident symbol equates
# (build/p384_overlay_equates.inc) from the overlay labels files so the
# TLS-side dispatcher (src/crypto/ecdsa_verify_384.s) picks up address
# changes via .include, with .assert pins catching drift. Whenever
# either labels file is rebuilt, the .inc regenerates and the
# dispatcher .o is forced to rebuild.
build/p384_overlay_equates.inc: build/labels-p384-sha384.txt build/labels-p384-curve.txt \
tools/integration/gen_p384_overlay_equates.sh
bash tools/integration/gen_p384_overlay_equates.sh \
build/labels-p384-sha384.txt build/labels-p384-curve.txt $@

# The dispatcher .o now depends on the generated equates file (via
# .include) AND on the overlay .bin files (PRG_DEPS already lists those
# under USE_OVERLAY_P384_EMBED). Phase 5 Fix D: gate the .inc dep on
# USE_OVERLAY_P384_EMBED so the bootstrap rule for $(LABELS) (which
# sub-makes with USE_OVERLAY_P384_EMBED=0) can skip rebuilding the .inc
# from labels-p384-* (those depend on overlay-bins which depend on
# $(LABELS) -- cycle). The bootstrap pre-creates a placeholder .inc
# before sub-making.
ifeq ($(USE_OVERLAY_P384_EMBED),1)
build/crypto/ecdsa_verify_384.o: build/p384_overlay_equates.inc
endif

# Build ip65 object libraries from the submodule. Only needed if the ip65
# submodule changes; the prebuilt blob is committed to ip65-build/.
Expand Down
Loading