feat(crypto): c64-nist-curves P-256 ECDSA integration + Phase C infra - #31
Merged
Conversation
…ripts Adds tools/integration/ helpers that downstream integration-phase agents will call. Also pre-seeds the allowlists of the three sibling crypto repos (c64-x25519, c64-ChaCha20-Poly1305, c64-nist-curves) so cross-repo agent dispatches no longer stall on bash-approval prompts. New scripts: - allowlist_preseed.sh / _merge_allow.py — merge allow + deny patterns into each sibling's .claude/settings.local.json (dedupe against existing; preserve order; append new at the end). - worktree_up.sh / worktree_merge.sh — wrap git worktree add and --no-ff merge-with-tests for Phase C parallel work. - build_x25519.sh / build_chacha20poly1305.sh / build_nistcurves.sh — stub placeholders; Phase C agents fill them in. - run_vice_suite.sh — one-arg wrapper around tools/run_all_tests.py honoring C64_SKIP_BUILD. - run_u64_suite.sh — intentional refuse-to-run; U64E runs must be dispatched via a live Phase F agent per feedback_never_inline_u64e. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Adds shared crypto infrastructure (zp_canon.inc, reu_layout.inc, crypto_swap.s, mul_tables.s, crypto_init.s stub, zp_define.mk) that Phases C.1-.3 will populate with the sibling libs. cfg reshaped for the REU-overlay design per plan: - UCI: CRYPTO_RESIDENT \$6000-\$BFFF (24 KB), CRYPTO_OVERLAY \$4100-\$5FFF (7.5 KB) active. - ip65: CRYPTO_RESIDENT \$6000-\$BFFF (24 KB). CRYPTO_OVERLAY deferred until Phase C.1 lands an overlay image — ip65 can't shrink CRYPTO_RESIDENT below 24 KB without Profile B + sibling CODE savings that don't exist yet. No sibling libs linked yet; in-tree src/crypto/*.s unchanged. Both backends build; run_all_tests.py --skip-slow passes. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Adds libs/x25519/ submodule (pinned to cd9a663) + integration build script tools/integration/build_x25519.sh that splits the c64-x25519 sibling sources into three segments when assembled into build/lib/x25519.a: OVERLAY_X25519 runtime code (fe25519/x25519/mul_8x8 body) loaded at boot into the CRYPTO_OVERLAY slot ($4200-$5FFF under UCI). Actual size 3484 B of the 7680 B budget (45%). CRYPTO_INIT_CODE boot-only routines (x25519_reu_mul_init, x25519_sqtab_init) placed in the pre-SQTAB half of CRYPTO_RESIDENT so they survive overlay swaps. DATA sibling's page-aligned RW buffers and constant lookup tables, placed below $A000. Under BACKEND=uci the Makefile filters out src/crypto/x25519.s + src/crypto/fe25519.s, defines USE_X25519_SIBLING, and links build/lib/x25519.a. ip65 continues using the in-tree sources until Phase C.2 frees enough CRYPTO_RESIDENT headroom. cfg/c64-https-uci.cfg splits CRYPTO_RESIDENT around a 1 KB hole at $7800-$7BFF reserved for the sibling's hardcoded sqtab_lo/hi tables (built at boot by `x25519_sqtab_init`). New DATA + CRYPTO_INIT_CODE segments flow into the split halves. src/crypto/shared/crypto_init.s now drives x25519_sqtab_init + x25519_reu_mul_init + crypto_overlay_stash_x25519 (DMAs the overlay image from $4200 to REU bank 2 offset $0100 so future P-256 / P-384 swaps can restore it). reu_layout.inc bumps overlay offsets to $0100 to dodge the 64-byte zero buffer at bank 2 offset $0000 used by `reu_clear_wide`. src/crypto/x25519_aliases.s aliases the legacy `fe_*` names to the sibling's `fe25519_*` exports for test-harness compatibility. fe_mul and fe_sqr are trampolines that append fe25519_reduce_final because the sibling intentionally skips final reduction in mul/sqr. Verification: - `make BACKEND=uci` clean build, OVERLAY_X25519 = 3484 B (≤ 8192 B). - CRYPTO_RESIDENT total fill 98.2% (23126 / 23552 B). - `make BACKEND=ip65` clean build, no regression. - `BACKEND=uci python3 tools/test_x25519.py` — 71/71 pass. - `BACKEND=ip65 python3 tools/test_x25519.py` — 71/71 pass (baseline). - `python3 tools/test_entropy.py` under ip65 — 7/7 pass. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Rescopes Phase C.2: the original ccp sibling integration overflows CRYPTO_RESIDENT by ~20 KB (measurement, not estimate) and is abandoned — in-tree chacha20/poly1305/aead/word32 stay permanently. Instead, reorganize memory to open headroom for Phase C.3: - New CRYPTO_AUX_CODE segment for SHA-256, HMAC-DRBG, ecdsa_verify dispatcher (always-resident, addressable from anywhere). - CRYPTO_AUX_CODE + TLS_CODE now load into NET_CODE (LOADER_OVERFLOW neighborhood) under UCI. Under ip65, only the CRYPTO_AUX_CODE rename happens — it still loads into CRYPTO_RESIDENT because ip65's NET_CODE is already 88% full with the ip65 blob and cannot absorb either TLS_CODE (~1.8 KB) or CRYPTO_AUX_CODE (~3.1 KB). UCI fill deltas: - NET_CODE: 23.4% → 83.3% (absorbed 1.8 KB TLS_CODE + 3.1 KB CRYPTO_AUX_CODE) - CRYPTO_RESIDENT ($6000-$77FF, 6 KB): 100% → 70.8% (TLS_CODE left; ~1.8 KB reclaimed) - CRYPTO_RESIDENT_2 ($7C00-$BFFF, 17 KB): 97.8% → 80.1% (~3.1 KB reclaimed) ip65 fill deltas: unchanged (CRYPTO_AUX_CODE routes to CRYPTO_RESIDENT, same region as before). Backend divergence documented in both cfg files. No test regressions: 251/253 passing on both backends (the 2 chacha20/poly1305 failures pre-date this commit and are unrelated). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Adds the libs/nistcurves/ submodule (pinned at 1e72e6c) and the build plumbing for a narrow P-384 integration under BACKEND=uci: - build/lib/nistcurves-p384.a emits OVERLAY_P384 containing ONLY the three variable-base primitives that TLS would consume: ec_point_double_384, ec_point_add_384, ec_jacobian_to_affine_384 plus their fp384/mod384 helpers. Fixed-base ec_scalar_mul_384 + ec_precompute_384 and the Lim-Lee anchor tables are sed-stripped from the sibling sources since they're unused here and would bloat the overlay. Size: 5,879 B (≤ 7,680 B ceiling). - src/crypto/p384_force_link.s forces ld65 to pull the archive members via a 6-byte reference table in CRYPTO_AUX_CODE. - tools/test_p384_symbols.py exercises the primitives against NIST P-384 reference values computed from the generator (2G, 3G, 17G, Jacobian->affine). P-256 ECDSA stays in-tree under both backends pending upstream work on variable-base scalar-mult and big-endian I/O (JC-000/c64-nist-curves#17). The USE_NISTCURVES_P384 Makefile gate is present but commented: with both OVERLAY_X25519 (3.4 KB) and OVERLAY_P384 (5.7 KB) active, ld65 stacks them sequentially in CRYPTO_OVERLAY ($4200-$5FFF, 7.5 KB) and overflows by 1.6 KB. Architecturally max(x25519,p384)=5.7 KB fits the slot, but the cfg needs `run=CRYPTO_OVERLAY, load=<staging>` for one overlay plus a contiguous file-backed staging region to hold the displaced image. That restructure exceeds Phase C.3's stop-on-overflow hard rule and is deferred pending supervisor OK. Uncomment the two CA65FLAGS/SIBLING_LIB_ARCHIVES lines in Makefile once the cfg is extended to enable the integration end-to-end. ip65 and UCI builds both succeed with the gate commented (p384_force_link.s is inert when USE_NISTCURVES_P384 is undefined). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Previous Phase C.3 landed a P-384 archive but couldn't link it alongside x25519 due to ld65's load= segment concatenation (two segments with load=CRYPTO_OVERLAY stack rather than overlay). New approach: P-384 is smoke-test-only, so keep it out of the production PRG entirely. A new cfg/p384-overlay.cfg + build script tools/integration/build_nistcurves_p384_bin.sh link the archive standalone to extract: build/lib/overlay-p384.bin (8 KB raw OVERLAY_P384 image, padded with $00) build/labels-p384.txt (VICE labels for P-384 symbols + DATA buffers at $C000-$C635 inside TCP_BUF) Makefile target `p384-overlay` produces both; the main PRG build under BACKEND=uci is unchanged (production PRG still does NOT link nistcurves-p384.a — the USE_NISTCURVES_P384 gate stays commented). Production PRG size: 47105 B before and after. tools/test_p384_symbols.py now: - Skips cleanly under BACKEND=ip65. - Uploads the 8 KB image to REU bank 2 offset $4100 in two 4 KB halves staged via TCP_BUF ($C000-$CFFF — networking is off), using a 55-byte SEI/LDA/STA trampoline injected at $0340 that reads DMA params from $0380. - Calls crypto_swap_to_p384 — REU→$4200 DMA, then restores REU registers ($DF02/$DF03=$6600, $DF07/$DF08=512, $DF0A=0) to the "mul-row FETCH config" that x25519's reu_fetch_mul_row expects (fp_mul_384 / fp_sqr_384 only overwrite $DF05 / $DF06 / $DF01). - Exercises ec_point_double_384 / ec_point_add_384 / ec_jacobian_to_affine_384 against NIST P-384 generator vectors. Known issue: fp_mul_384 verifies correctly (2*3=6 smoke-tested) but fp_sqr_384 hangs on any nonzero input in this standalone link, causing ec_point_double_384 (which calls ec_sqrp_384 -> fp_sqr_384) to time out on Test 1. The test infrastructure (overlay upload, swap, REU restore, ZP/fp_src wiring, readback) is verified working via the fp_mul_384 path; the root cause of the fp_sqr hang has not been identified yet — full details in the module docstring. Build artifacts: - Main UCI PRG: 47105 B (unchanged). - overlay-p384.bin: 8192 B. - labels-p384.txt: 96 entries covering ec_point_double_384, ec_point_add_384, ec_jacobian_to_affine_384, fp_* helpers, ec384_p1/p2/p3 buffers, ec384_affine_x/y, etc. - x25519 non-regression: tools/test_x25519.py passes 71/71.
Boot-only sanity check that crypto_init seeds: - Shared sqtab tables (sqtab_lo, sqtab_hi at $7800/$7A00) - x25519 REU mul-row stash (row 42 spot-check via DMA pull-back to C64 $C000) - x25519 overlay correctly paged into live slot at $4200-$5FFF, with idempotent re-swap Narrowed from the original plan: ccp Shoup + nist-curves P-256/P-384 precompute samples were dropped because those integrations were deferred (Profile A ccp too large; P-256 blocked on upstream variable-base scalar-mult; P-384 is external-image-only). UCI runs the three checks; ip65 skips cleanly (no sibling libs). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Phase F surfaced two unit-test failures under both backends: test_crypto.py and test_http.py were FATAL on `cc20_data_ptr` and `zp_ptr` lookups, cascading to a later failure on `cc20_remain`. All three symbols are equates in src/constants.inc without any `.export` directive, so they never reached build/labels.txt and Labels.from_file() couldn't resolve them. Promote the three here in src/exports.s, following the same pattern Phase C.1 used for fe_src1/fe_src2/fe_dst. Baseline improvement: run_all_tests.py --skip-slow goes from 251/253 to 253/253 under ip65. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Phase C.1 added REU_OVERLAY_{X25519,P256,P384} labels at offsets
$020100/$022100/$024100. ld65 emits these as "al XXXXXX .name" (no
"C:" prefix) because they're outside the 16-bit C64 code space.
The hand-rolled _load_labels() parsers in tools/uci/test_https_local.py
and tools/uci/bench_ecdsa_u64e.py crashed with ValueError on these
lines (split(":", 1) on "022100" returns a 1-element list).
Skip non-C lines — the UCI harness scripts only need CPU addresses
and the REU offsets aren't useful for them anyway.
Upstream c64-test-harness Labels.from_file() got the proper fix
in JC-000/c64-test-harness#62 (0.12.3) — parses both forms into
one map. A follow-up can migrate these scripts to use the upstream
parser once Labels grows a public iteration API.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>Replaces the 8-line hand-rolled parser with a single Labels.from_file() call in both tools/uci/test_https_local.py and tools/uci/bench_ecdsa_u64e.py. This is now possible because the upstream Labels class gained: - JC-000/c64-test-harness#62: parse non-C-prefixed label lines ("al XXXXXX .name") for REU offsets and other >16-bit addresses. - JC-000/c64-test-harness#64: implement collections.abc.Mapping so dict(labels), .items(), .keys(), .values(), iteration all work. Behavioral change: _load_labels() now returns REU_OVERLAY_* entries too (1183 labels vs ~1180 before). Callers looking up by name are unaffected; any code iterating over every label gets three extra keys that it didn't previously see. No such iteration callers exist in either script today. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
libs/nistcurves 1e72e6c → dfdfb59 picks up: - PR #19 (JC-000/c64-nist-curves): variable-base ec_scalar_mul_var for both P-256 and P-384, fp_mod_mul_n / fp_mod_mul_n_384, packaged ecdsa_verify_256 / ecdsa_verify_384 (160/240-byte BE structs, C=0 valid / C=1 invalid), fp_reverse32/48 BE↔LE helpers. Closes issue #17. - PR #20: reu_fetch_mul_row relocated from main.s into mul_8x8.s so standalone-overlay links (like c64-https) reach it. Closes issue #18 (fp_sqr_384 hang). Also switch libs/x25519 and libs/nistcurves .gitmodules URLs from local file paths to HTTPS — recent git releases reject "file://" transports for submodule fetches (CVE-2022-39253 mitigation), which was blocking `git submodule update --remote`. Integration of the new ECDSA API lands in a follow-up phase. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Root-cause investigation under BACKEND=uci. Progressive `tls_last_state` probing (reverted) bisected the hang to the `jsr x25519_scalarmult` call inside `tls_ecdh_generate_keypair`: $82 reached (pre tls_ecdh_generate_keypair) $91 reached (post privkey-copy) $92/$93 reached (post fe25519_copy + pre clamp) $94 reached (pre x25519_scalarmult) $9E never seen (post return) x25519_scalarmult in isolation (tools/test_x25519.py) still passes, so the defect is stateful: something in the boot or early-handshake path corrupts state between x25519's init and its first TLS invocation. Three leads documented (ZP overlap from legacy sqtab_init at src/boot.s:211, REU register state, IRQ racing ZP) plus a small recommended experiment: gate the legacy sqtab_init call the same way reu_mul_init is already gated under USE_X25519_SIBLING. No functional code changes — diagnostic instrumentation was reverted after capturing the bisection. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Phase F validation showed x25519_scalarmult hangs deterministically
in TLS context under BACKEND=uci at 48 MHz — scalarmult enters and
never returns (tls_last_state=$94 pre-jsr, never reaches $9E post).
Standalone tools/test_x25519.py passes 71/71, so the defect is
stateful / context-dependent.
Rolling back libs/x25519 submodule + overlay machinery while
keeping the rest of Phase C (shared infra in Phase C.0, aux code
relocation in C.2, P-384 external smoke test in C.3b, submodule
URL fix, Labels migration). In-tree src/crypto/{fe25519,x25519}.s
return as the active x25519 implementation under both backends.
Specific changes:
- Remove -D USE_X25519_SIBLING=1 and the build/lib/x25519.a rule
from Makefile; drop the x25519.s + fe25519.s filter-out.
- cfg/c64-https-uci.cfg: revert CRYPTO_RESIDENT to a single
contiguous $6000-$BFFF region; drop the $7800-$7BFF sqtab hole,
CRYPTO_RESIDENT_2 split, X25519_SQTAB region, OVERLAY_X25519
segment, and DATA segment declarations. CRYPTO_OVERLAY region
stays for the external P-384 smoke test.
- cfg/c64-https-ip65.cfg: drop the OVERLAY_X25519 placeholder.
- src/crypto/shared/crypto_init.s: simplify back to a single
mul_tables_init dispatch, drop the .ifdef USE_X25519_SIBLING
branch (REU mul init + overlay stash).
- src/crypto/shared/crypto_swap.s: drop crypto_swap_to_x25519
(remaining dispatcher serves the P-384 external smoke test only).
- src/crypto/shared/reu_layout.inc: drop REU_OVERLAY_X25519 equate.
- src/boot.s: drop all .ifndef USE_X25519_SIBLING guards — reu_mul_init,
the REU table inits, and their BSS come back unconditionally.
- src/data.s: drop all .ifndef USE_X25519_SIBLING guards — fe_p,
x25_basepoint, mul38_lo/hi_tab, mul_dma_lo/hi, sqtab_lo/hi,
fe_tmp1..4, x25_scalar/u/result/ladder state, mul_cached_a/_src2_buf
come back unconditionally.
- src/crypto/poly1305.s: drop .ifndef guard around poly_prod_lo/hi,
mul_8x8 exports (these are back in-tree).
- src/crypto/x25519_aliases.s: delete (alias layer no longer needed).
- tools/integration/build_x25519.sh: delete (sibling overlay builder).
- tools/test_crypto_init.py: delete (Phase E regression test
was overlay-specific; shared sqtab coverage is retained in
tools/test_crypto.py).
- libs/x25519/ submodule + .gitmodules entry: remove.
Verification:
- make BACKEND=ip65: clean build.
- make BACKEND=uci: clean build.
- C64_SKIP_BUILD=1 python3 tools/run_all_tests.py --skip-slow: 253/253.
Filed upstream follow-up: JC-000/c64-x25519#33.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>Replaces in-tree ecdsa_{points,fp,mod,curve}.s with the sibling's
ecdsa_verify_256 (JC-000/c64-nist-curves PR #19 — variable-base
scalar-mult, mod-order multiply, packaged ECDSA verify, BE-struct I/O
with fp_reverse32 helper).
src/crypto/ecdsa_verify.s collapses from the ~673 B in-tree verifier
body into a ~234 B thin TLS dispatcher that banks ROM out, dispatches
on ecdsa_curve_id (P-384 still stubbed), hands the 160-byte packed
r|s|h|Qx|Qy BE struct to ecdsa_verify_256, and forwards its C flag.
src/data.s lays ecdsa_sig_r/s + ecdsa_hash + ecdsa_pubkey_x/y out as
five contiguous 32-byte BE fields so the dispatcher can pass
ecdsa_sig_r as the struct base with no explicit pack step.
Sibling code lives in CRYPTO_CODE (fp256 + mod256 + points256 +
ecdsa256), CRYPTO_RODATA (curve256 constants), and CRYPTO_BSS (data
buffers). ~7.3 KB of always-resident code + ~1.3 KB of BSS; no overlay
mechanism. The dispatcher provides an ec_scalar_mul shim that
redirects u1*G (which the sibling's ecdsa_verify_256 dispatches to a
Lim-Lee 8-way fixed-base comb) to ec_scalar_mul_var with G pre-loaded
as the base point, avoiding the 16 KB REU bank-2 precompute table that
the comb would otherwise need at boot.
Shared mul infrastructure (mul_cached_a, mul_src2_buf, mul_dma_lo/hi,
sqtab_lo/hi, mul_8x8, reu_fetch_mul_row, poly_prod_lo/hi) is reused
from the in-tree src/data.s + src/crypto/poly1305.s + src/boot.s; the
sibling's copies are excluded from the archive to avoid collisions.
src/data.s grows mul_src2_buf from 32 to 35 bytes so the sibling
fp256's 4x-unrolled mul over-read into j=32..34 reads zeros. REU DMA
register equates (reu_reu_hi/bank/command) are promoted to linker-
visible exports via src/exports.s so fp256's .import resolves.
Memory-fit work: the sibling + dispatcher pushed CRYPTO_RESIDENT over
its 24 KB budget under BOTH backends. Under UCI we added a new
CRYPTO_AUX_CODE2 segment (carrying only hmac_drbg) alongside the
existing CRYPTO_AUX_CODE; both route to NET_CODE under UCI so Phase
C.2's aux-code-in-NET_CODE arrangement is preserved. Under ip65
NET_BSS is split into the blob-owned $4000-$4F8B region and a
NET_BSS_TAIL slack region at $4F8C-$5FFF ($1074 B); TLS_CODE +
sha256's CRYPTO_AUX_CODE relocate there while hmac_drbg's
CRYPTO_AUX_CODE2 rides the NET_CODE tail. BSS reclaim: removed six
now-dead ecdsa scratch buffers (ecdsa_verify_tmp, ev_u1/u2/point_save
and their P-384 twins, ~432 B) from src/data.s and pruned unused
sibling result registers (fp_r1/r2/r3 + fp_tmp2/3/4 + fp_inv_iter,
~194 B) from data_p256_raw.s.
Validated:
- run_all_tests.py --skip-slow: 253/253
- test_x509.py (ECDSA full sweep): 11/11, valid P-256 verify
under VICE warp in ~30 s
- tools/uci/test_https_local.py on U64E at 48 MHz: PASS, body
"HELLO FROM TLS SERVER" decrypted, handshake progress=0x03 →
progress=0x05 sentinel in 81.9 s wall-clock (~3 s under the
82 s Phase F ECDSA bench baseline)
In-tree ecdsa_{curve,fp,mod,points}.s remain on disk but are filtered
out of CRYPTO_SRCS_ALL in the Makefile; Phase G will delete them.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>Captured before Phase C.4 landed. Explains why trace.bin couldn't pinpoint the x25519 hang loop (~48:1 undersampling at 48 MHz). Retained for future diagnosis attempts on JC-000/c64-x25519#33. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Phase C.4 stopped linking the in-tree P-256 primitives
(ecdsa_{curve,fp,mod,points}.s) in favour of the sibling
c64-nist-curves integration via build/lib/nistcurves-p256.a.
The files remained on disk for reference but have been unused
since 06bf475. Delete them now, along with the legacy ACME-era
P-384 .asm stubs (ecdsa_*_384.asm) which were never assembled
under ca65.
The corresponding Makefile filter-out list becomes a no-op and
is simplified back to a plain wildcard.
Verified: both `make BACKEND=ip65` and `make BACKEND=uci` build
clean after deletion.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>- Crypto ABI: point P-256 at libs/nistcurves sibling via ecdsa_verify_256 / ec_scalar_mul_var; note X25519 stays in-tree pending JC-000/c64-x25519#33; note ChaCha20-Poly1305 stays in-tree permanently. - MEMORY requirements: REU banks 0-1 no longer used by shipped build (x25519 overlay rolled back); banks 4-7 reserved for P-384 external overlay smoke test. Note crypto_init currently bootstraps mul_tables_init only. - P-384 entry: sibling primitives buildable via `make p384-overlay` (Phase C.3b), but the target has a pre-existing unresolved- symbol bug (ec_base384_x/y in points384_raw.s); TLS-level P-384 verify still stubbed. - End-to-end HTTPS status: handshake wall-clock now 81.9 s on U64E 48 MHz under the sibling P-256 path. - Summary of recent fixes: add bullet 11 for Phase C.4 (06bf475). - Known issues: add X25519 overlay deferred (#33) and `make p384-overlay` unresolved-symbol bug. - ECDSA benchmark: note 81.9 s handshake wall-clock post-Phase-C.4; speedup path becomes a libs/nistcurves submodule bump. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for freeto join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
End of the crypto-integration series. Replaces the in-tree hand-port of
ECDSA P-256 with the sibling `libs/nistcurves` implementation, plus
the shared REU-overlay / cfg / init plumbing that supports dropping
in additional optimised sibling libraries through the Crypto ABI.
What shipped
scripts for the integration agents.
overlay swap dispatcher, `crypto_init` orchestrator, canonical ZP
map, shared sqtab stub, REU-overlay cfg rework.
`LOADER_OVERFLOW` segment riding the tail of `NET_CODE` under
both backends.
as build artifacts.
overlay image (not linked into the main PRG).
ECDSA replaces the in-tree P-256 primitives under BOTH backends.
`src/crypto/ecdsa_verify.s` rewritten as a thin TLS-facing
dispatcher over `ecdsa_verify_256`.
narrowed to the Montgomery ladder; trace-capture under-sampling
analysis recorded for future diagnosis.
CLAUDE.md + memory updated to reflect end state.
What was deferred
rolled back in `b133ac7` after `x25519_scalarmult` hung
deterministically inside the Montgomery ladder under BACKEND=uci
at 48 MHz (standalone tests pass 71/71; hang is stateful). Retry
against the v0.3.0 tag failed the same way. Tracked upstream at
c64-x25519#33. In-tree `src/crypto/x25519.s` + `src/crypto/fe25519.s`
remain the active implementation.
via the external overlay image, but the `make p384-overlay` target
has a pre-existing unresolved-symbol bug (`ec_base384_x/y` in
`points384_raw.s`, not exported by the current sibling build).
TLS-level P-384 verify remains stubbed (see `project_p384_stubbed`).
Not a Phase C regression — fix before wiring P-384 into the TLS path.
Test results
(down from ~110 s pre-integration). Full flow: CH → SH → EE →
Cert → CertVerify (sibling ECDSA) → SF → CF → app keys → HTTP GET
→ `HELLO FROM TLS SERVER` body decrypted. Validated during Phase C.4.
after the Phase G orphan-file deletion.
Upstream references
Labels migration).
Known issues
but still exceeds typical real-world handshake windows (10-30 s).
Further speedups land via submodule bump through the Crypto ABI.
Test plan
Co-Authored-By: Claude Opus 4.7 (1M context) noreply@anthropic.com
Originally posted by @JC-000 on 2026-04-21