From 0e1039e8bf361dabcc394b79cb94318af97bfd93 Mon Sep 17 00:00:00 2001 From: JC-000 <3798556+JC-000@users.noreply.github.com> Date: Wed, 6 May 2026 18:18:11 -0500 Subject: [PATCH 1/3] fix(build): use BSD-compatible sed -i '' for macOS portability GNU sed accepts `sed -i '...'`; BSD sed (macOS default) treats the pattern as the backup-suffix and consumes the next argument as the filename, which breaks the build. Switching to `sed -i ''` is portable across both. Affects the ld65 label rewrite in the Makefile and 12 inline edits in build_nistcurves_p256.sh. Co-Authored-By: Claude Opus 4.7 (1M context) --- Makefile | 2 +- tools/integration/build_nistcurves_p256.sh | 26 +++++++++++----------- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/Makefile b/Makefile index 68e3cd4..a33f858 100644 --- a/Makefile +++ b/Makefile @@ -109,7 +109,7 @@ $(PRG): $(PRG_DEPS) $(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) + sed -i '' 's/^al 00\([0-9a-fA-F]\{4\}\) /al C:\1 /' $(LABELS) link: $(PRG) diff --git a/tools/integration/build_nistcurves_p256.sh b/tools/integration/build_nistcurves_p256.sh index d0e2e73..4e72faa 100755 --- a/tools/integration/build_nistcurves_p256.sh +++ b/tools/integration/build_nistcurves_p256.sh @@ -102,22 +102,22 @@ cp "$LIB_SRC"/ecdsa256.s "$STAGING/ecdsa256_raw.s" # helpers + anchor base-address table + cm_* / sm256_* state vars # Keeps ec_point_double (line 60-410), ec_point_add (411-761), # ec_scalar_mul_var (1459-1609), ec_jacobian_to_affine (1610-end). -sed -i '762,1458d' "$STAGING/points256_raw.s" +sed -i '' '762,1458d' "$STAGING/points256_raw.s" # Strip exports + imports that only the removed bodies used. -sed -i '/^\.export ec_precompute_256, ec_scalar_mul, ec_scalar_mul_var$/c\ +sed -i '' '/^\.export ec_precompute_256, ec_scalar_mul, ec_scalar_mul_var$/c\ .export ec_scalar_mul_var' "$STAGING/points256_raw.s" # Anchor + Lim-Lee state imports -sed -i '/^\.import ec_aff2g_256_x, ec_aff2g_256_y$/d' "$STAGING/points256_raw.s" -sed -i '/^\.import ec_anchor[1-8]_x, ec_anchor[1-8]_x, ec_anchor[1-8]_x, ec_anchor[1-8]_x$/d' "$STAGING/points256_raw.s" -sed -i '/^\.import ec_anchor[1-8]_y, ec_anchor[1-8]_y, ec_anchor[1-8]_y, ec_anchor[1-8]_y$/d' "$STAGING/points256_raw.s" -sed -i '/^\.import ec_anchor.*$/d' "$STAGING/points256_raw.s" -sed -i '/^\.import cm_k, mul_dma_lo$/d' "$STAGING/points256_raw.s" -sed -i '/^\.import ec_sc_byte, ec_sc_mask$/d' "$STAGING/points256_raw.s" +sed -i '' '/^\.import ec_aff2g_256_x, ec_aff2g_256_y$/d' "$STAGING/points256_raw.s" +sed -i '' '/^\.import ec_anchor[1-8]_x, ec_anchor[1-8]_x, ec_anchor[1-8]_x, ec_anchor[1-8]_x$/d' "$STAGING/points256_raw.s" +sed -i '' '/^\.import ec_anchor[1-8]_y, ec_anchor[1-8]_y, ec_anchor[1-8]_y, ec_anchor[1-8]_y$/d' "$STAGING/points256_raw.s" +sed -i '' '/^\.import ec_anchor.*$/d' "$STAGING/points256_raw.s" +sed -i '' '/^\.import cm_k, mul_dma_lo$/d' "$STAGING/points256_raw.s" +sed -i '' '/^\.import ec_sc_byte, ec_sc_mask$/d' "$STAGING/points256_raw.s" # REU DMA register imports (only used by stripped REU anchor helpers) -sed -i '/^\.import reu_c64_lo, reu_c64_hi, reu_reu_lo, reu_reu_hi$/d' "$STAGING/points256_raw.s" -sed -i '/^\.import reu_reu_bank, reu_len_lo, reu_len_hi$/d' "$STAGING/points256_raw.s" -sed -i '/^\.import reu_addr_ctrl, reu_command$/d' "$STAGING/points256_raw.s" +sed -i '' '/^\.import reu_c64_lo, reu_c64_hi, reu_reu_lo, reu_reu_hi$/d' "$STAGING/points256_raw.s" +sed -i '' '/^\.import reu_reu_bank, reu_len_lo, reu_len_hi$/d' "$STAGING/points256_raw.s" +sed -i '' '/^\.import reu_addr_ctrl, reu_command$/d' "$STAGING/points256_raw.s" # ec_mulp / ec_sqrp are used by all three retained bodies - keep. # fp_tmp1 is used by ec_scalar_mul_var - keep. @@ -292,7 +292,7 @@ DATA_EOF # The sibling uses `.segment "CODE"`, which under c64-https's cfg is the # LOADER region ($0801-$1FFF). We want this code in CRYPTO_RESIDENT. for src in fp256_raw mod256_raw points256_raw ecdsa256_raw; do - sed -i 's/^\.segment "CODE"/.segment "CRYPTO_CODE"/' "$STAGING/$src.s" + sed -i '' 's/^\.segment "CODE"/.segment "CRYPTO_CODE"/' "$STAGING/$src.s" done # --- Route DATA segment in data_p256_raw.s to CRYPTO_BSS. --- @@ -300,7 +300,7 @@ done # only contains `.res` (zero-init) declarations, so CRYPTO_BSS is the # right home. Don't accidentally match anything inside a string or # comment: the data_p256_raw.s we emit has exactly one such directive. -sed -i 's/^\.segment "DATA"$/.segment "CRYPTO_BSS"/' "$STAGING/data_p256_raw.s" +sed -i '' 's/^\.segment "DATA"$/.segment "CRYPTO_BSS"/' "$STAGING/data_p256_raw.s" # Sanity: no leftover `.segment "CODE"` hunks outside the expected # pattern (the raw files should only have one CODE segment each). From c593f0ec389ff73231bb2c1425554651ce681037 Mon Sep 17 00:00:00 2001 From: JC-000 <3798556+JC-000@users.noreply.github.com> Date: Wed, 6 May 2026 18:18:25 -0500 Subject: [PATCH 2/3] chore(deps): declare cryptography in requirements.txt The Python test scripts under tools/ use the `cryptography` package for cert generation, ECDSA test vectors, and AEAD reference checks, but no project manifest declared it. Add a minimal requirements.txt listing it; c64_test_harness is installed separately per the build instructions. Co-Authored-By: Claude Opus 4.7 (1M context) --- requirements.txt | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 requirements.txt diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..56dce83 --- /dev/null +++ b/requirements.txt @@ -0,0 +1,2 @@ +# c64_test_harness is installed separately per the build instructions: `pip install -e ../c64-test-harness`. +cryptography From c800df503fefa4446fce2c6b10ba582c60680a70 Mon Sep 17 00:00:00 2001 From: JC-000 <3798556+JC-000@users.noreply.github.com> Date: Wed, 6 May 2026 18:18:45 -0500 Subject: [PATCH 3/3] docs: note ECDSA-verify regression in Known issues MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ecdsa_verify (P-256) rejects a known-good signature from the RFC test vector — surfaced 2026-05-06 by tools/test_x509.py group 3 subtest 3c once the BSD-sed portability fixes unblocked the macOS build. Tampered signatures (3d) are still correctly rejected and inputs are staged correctly, so the bug is in the verify path itself. Affects TLS CertificateVerify; ECDHE/X25519 handshake is unaffected. Co-Authored-By: Claude Opus 4.7 (1M context) --- CLAUDE.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/CLAUDE.md b/CLAUDE.md index 75806e1..8ffcc2a 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -326,6 +326,16 @@ Five latent bugs and three new ones were cleared to get here: regression — the target has never built cleanly — but should be fixed before P-384 is actually wired into the TLS path. TLS-level P-384 verify remains stubbed regardless (see `project_p384_stubbed`). + - `ecdsa_verify` (P-256) rejects a known-good signature. Surfaced + 2026-05-06 by `tools/test_x509.py` group 3 subtest 3c + ("ECDSA verify: valid signature (C=0)") on macOS once the BSD-sed + portability fixes unblocked the build. The C64 returns C=1 (invalid) + after ~60 s on a Python-pre-verified valid P-256 signature; tampered + signatures (subtest 3d) are correctly rejected, and all five input + buffers (hash, r, s, Qx, Qy) were confirmed Match=True in C64 memory + before the call, so the bug is in the verify path, not input + staging. Used by TLS handshake CertificateVerify; ECDHE/X25519 + handshake is unaffected. ### ECDSA P-256 verify wall-clock