diff --git a/CLAUDE.md b/CLAUDE.md index 68df3dd..a3d8202 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -194,7 +194,7 @@ buffers in the crypto BSS — see per-module headers for details): SHA-256 (in-tree; no sibling) sha256_init, sha256_update, sha256_final - ECDSA P-256 (`libs/nistcurves@v0.6.0` sibling, + ECDSA P-256 (`libs/nistcurves@v0.9.1` sibling, c64-lib-contract SPEC §1-§8.1 aligned) ecdsa_verify_256 — TLS dispatcher in src/crypto/ecdsa_verify.s packs the BE struct + calls the sibling entry @@ -203,11 +203,26 @@ buffers in the crypto BSS — see per-module headers for details): archive built via `make -C libs/nistcurves lib-p256-verify` — see `tools/integration/build_nistcurves_p256.sh` for the wrapper.) + **From v0.7.0 the sibling validates the public key at entry** + (FIPS 186-5 §3.3: `Qx,Qy ∈ [0,p-1]` plus on-curve + `Qy² ≡ Qx³ − 3Qx + b (mod p)`, C=1 returned before any scalar + multiplication). This matters to c64-https specifically: the `Q` + handed to `ecdsa_verify_256` comes straight from an + attacker-supplied certificate via `src/tls_cert.s` → + `ecdsa_pubkey_x/y`, and c64-https performs no range or on-curve + check of its own. `src/crypto/ecdsa_verify.s` therefore carries a + link-time `.assert LIB_NISTCURVES_VERSION_MINOR >= 9` so a silent + downgrade below that pin is a loud `ld65: Error` rather than a + quietly reopened gap — every KAT vector we own has a well-formed + public key, so the tests would not notice. The assert costs zero + PRG bytes (hashes identical with and without it) and, from v0.9.0, + zero ld65 warnings, since the version equates are exported `:abs`. + P-384 is *stubbed at the TLS layer* (see `project_p384_stubbed` memory note). The sibling `libs/nistcurves` P-384 primitives were meant to be buildable as an external overlay image (Phase C.3b, `make -p384-overlay`) but every P-384 build target is broken at the v0.6.0 -pin — see "Known issues" for the current failure chain. Fix the build +p384-overlay`) but no P-384 build target has ever completed — see +"Known issues" for the current failure chain. Fix the build before wiring P-384 into the TLS path. MEMORY requirements for a drop-in sibling library (see "Memory layout" @@ -812,25 +827,76 @@ Five latent bugs and three new ones were cleared to get here: #32 and #45 were closed as stale; file fresh issues against this chain when P-384 enablement resumes. TLS-level P-384 verify remains stubbed regardless (see `project_p384_stubbed`). - - **A `libs/nistcurves` bump to v0.7.0/v0.8.0 does not link under - UCI** (measured 2026-08-13). `LIB_NISTCURVES_P256_RODATA` - overflows `CRYPTO_HOT` by **207 B**, because CRYPTO_HOT is - already *one byte* from full at the v0.6.0 pin (`build/ - c64-https.map`: rodata `009E1F..009FFE`, region ends `$9FFF`) and - v0.7.0's FIPS 186-5 §3.3 public-key validation gate adds +512 B. - ip65 links fine at v0.8.0, and both `tools/test_ecdsa_kat_oracle.py` - (3/3) and `tools/test_x509.py` (11/11) pass there — so the blocker - is placement, not function. A link-verified remedy exists (route - `cfg/c64-https-uci.cfg` `LIB_NISTCURVES_P256_RODATA` to the - otherwise-unused `CRYPTO_OVERLAY`; v0.8.0 UCI then links at the - same 62,977 B with 7,200 B of the slot still free) but it has had - no hardware run and it changes what `tools/uci/_memory_policy.py` - sees at $4200-$5FFF, so it needs a UCI e2e before it ships. The - bump is worth taking eventually: the gate validates the - attacker-supplied certificate public key that `src/tls_cert.s` - feeds to `ecdsa_verify_256`, which c64-https does not check - itself. No export was renamed or removed in v0.7.0/v0.8.0 — - `LIB_ABI_VERSION` is still 0. + The v0.9.1 bump briefly moved this failure *earlier* — upstream + #90's per-variant manifests renamed `lib_manifest.o` / + `zp_config.o` to `lib_manifest_sha384.o` / `zp_config_p384verify.o` + etc., which the wrapper's hardcoded archive list could not find. + Both P-384 wrappers now **discover** those member names instead, so + the chain again stops exactly at the SHA-384 `OVERLAY_REGION` + overflow above — verified, same 1536 B, at the v0.9.1 pin. + - **Sibling-archive member names are DISCOVERED, never hardcoded — + and this is load-bearing.** Upstream v0.9.0 gave each of its nine + archives its own per-variant `zp_config_*.o` / + `lib_manifest_*.o` / `precalc_manifest_*.o`. + `tools/integration/build_nistcurves_p256.sh` rebuilds the ZP object + with c64-https's slot overrides (`zp_ptr2 = $3d`, + `fp_mul_i = $39`, `fp_mul_j = $3a`) and then re-archives strictly by + `ar65 t upstream.a`. Writing that rebuild to a hardcoded + `zp_config.o`, as it did before the v0.9.1 bump, means the override + object is **silently dropped** and the upstream-default member + archived in its place — restoring `zp_ptr2 = $fd` (collides with + c64-https `zp_temp`/`zp_count` during cert parsing) and + `fp_mul_i/j = $2c/$2d` (inside the fe25519 claim `$2c-$37`). There + is no link error for this; it is runtime memory corruption several + layers from its cause. The wrappers now fail loudly on an absent, + ambiguous or unrecognised member name, apply the matching upstream + `-D` variant gate (it selects which slots get `.exportzp`), and + **post-check the emitted object with `od65`** so the override is + proven rather than assumed. Verify from the link if you ever doubt + it: `build/labels.txt` must show `fp_mul_i=$39`, `fp_mul_j=$3A`, + `zp_ptr2=$3D`. + - **The v0.7.0/v0.8.0 UCI `CRYPTO_HOT` overflow is RESOLVED at + v0.9.1 — and no cfg change was needed.** Recorded here because the + obvious remedy was nearly taken and would have been the wrong + trade. The failure was real: `LIB_NISTCURVES_P256_RODATA` overflowed + `CRYPTO_HOT` by **207 B** at v0.7.0/v0.8.0, because CRYPTO_HOT sat + *one byte* from full at the v0.6.0 pin (rodata `009E1F..009FFE`, + region ends `$9FFF`) and v0.7.0's validation gate adds +208 B of + **code**. 1 − 208 = −207. Exact. + + v0.9.0 then deleted 288 B of dead RFC 6979 self-test vectors from + `curve256.o` (upstream #91) — an object our archive ships — and the + rodata half of the pressure went away: + + segment v0.6.0 v0.9.1 delta + LIB_..._P256_CODE $1FB4 (8116) $2084 (8324) +208 + LIB_..._P256_RODATA $01E0 (480) $00C0 (192) -288 + LIB_..._P256_BSS $0520 (1312) $0520 (1312) 0 + + UCI CRYPTO_HOT last byte used: $9FFE -> $9FAE (**81 B free**) + + So the shelved remedy (routing `LIB_NISTCURVES_P256_RODATA` to + `CRYPTO_OVERLAY`) was **not adopted**: `CRYPTO_OVERLAY` stays + entirely free, the three mutually exclusive flags that contend for + it keep exactly the contention they had, and + `tools/uci/_memory_policy.py` sees an unchanged `$4200-$5FFF`. + Both cfgs are byte-identical across this bump. Note the corollary + for the next bump: **81 B is the whole margin**, and 288 B of it + was a one-off recovery of dead weight that cannot be recovered + twice. + + v0.9.0 is an ABI break upstream (`LIB_ABI_VERSION` 0 → 1, 17 + exports removed). Measured against our tree rather than assumed: + dumping every export of the staged archive at both pins and every + import of c64-https's own objects, **31** symbols left the archive + (upstream's 17 plus 14 more that the new per-variant + `zp_config_p256verify.o` / `precalc_manifest_p256verify.o` narrow + away) and the intersection with what c64-https imports is + **empty**. The whole library surface we consume is four symbols: + `ec_base_x`, `ec_gx256`, `ec_scalar_mul_var`, `ecdsa_verify_256`. + The removed ZP slots could not have bitten us either way — + c64-https contains zero `.importzp` directives and defines every + slot locally in `src/constants.inc` / `src/crypto/shared/zp_canon.inc`. - **VICE harness gotcha**: any test that exercises sibling `libs/nistcurves` P-256 primitives (`fp_mul`, `fp_inv`, `ec_scalar_mul_var`, `ecdsa_verify_256`, ...) MUST launch VICE with @@ -878,13 +944,23 @@ list. With `-reu` enabled, `tools/test_x509.py` 3c PASSes cleanly in ~60 s wall-clock under VICE warp. Under the then-current `libs/nistcurves@v0.3.0` pin (post-PR #55, -c64-lib-contract-aligned; the pin is v0.6.0 today) the U64E 48 MHz +c64-lib-contract-aligned) the U64E 48 MHz handshake measured **82.1 s** end-to-end (verified 2026-05-20 against the local listener; the prior v0.2.0 measurement was 86.7 s, and the pre-Phase-C.4 in-tree path was -~110 s). The pin has since moved to **v0.6.0** — the tables below are -the current numbers; the v0.3.0 row is kept only as the REU-profile -baseline. +~110 s). + +**Every wall-clock figure below was measured at the v0.6.0 pin; the +pin is now v0.9.1 and none of them has been re-measured.** Treat them +as the v0.6.0 baseline, not as HEAD. The expected drift is small but +its sign is known: v0.7.0's public-key validation gate adds 2 `fp_cmp` ++ 3 mod-p muls + 4 mod-p add/subs to every verify, which is noise +against a multi-second scalar multiplication, and nothing else in +v0.7.0-v0.9.1 touches a hot path (the rest is manifest equates, dead +data removal and export hygiene). So expect a small *regression*, not +a speedup, and do not quote these rows as v0.9.1 numbers until someone +re-runs `bench_ecdsa_u64e.py` on hardware. The v0.3.0 row is kept only +as the REU-profile baseline. On the **C64 Ultimate** (10.53.21.158, see "C64 Ultimate notes"), measured 2026-07-19 with the INNER=217 fence and boot-at-speed flow: @@ -1345,8 +1421,14 @@ Tight regions (post-W1): commit `7cb59f7` before upstream v0.4.0, so it has been inside our v0.6.0 pin all along and is not available as future headroom. `LIB_NISTCURVES_P256_BSS` measures $0520 (1,312 B) at v0.6.0 and - is unchanged at v0.8.0, so the union's cap is not threatened by a - bump. + is **unchanged through v0.9.1** (re-measured at the bump), so the + union's cap is not threatened. The segment is genuinely + uninitialised — `libs/nistcurves/src/data_p256.s` is 32 `.res` + directives with no `.byte`/`.word` — which is what makes our + `type = bss` declaration safe under c64-lib-contract §4, where a + `rw`→`bss` flip would drop initialised bytes with no ld65 + diagnostic at all. Re-check that if `data_p256.s` ever grows a + literal. - **CRYPTO_OVERLAY** under UCI doubles as P-384 SHA-384/curve overlay paging slot, the W3 P-256 overlay embed slot, AND the USE_X25519_SIBLING=1 X25519 sibling rodata + BSS slot. Mutually diff --git a/libs/nistcurves b/libs/nistcurves index 00d2626..f9701e1 160000 --- a/libs/nistcurves +++ b/libs/nistcurves @@ -1 +1 @@ -Subproject commit 00d2626ceb6b9179c7885b82a6ebcd27f62fd571 +Subproject commit f9701e1d35c664d494139db4cc7d7a3f62bd3c50 diff --git a/src/crypto/ecdsa_verify.s b/src/crypto/ecdsa_verify.s index 641558b..7402598 100644 --- a/src/crypto/ecdsa_verify.s +++ b/src/crypto/ecdsa_verify.s @@ -27,6 +27,29 @@ .import ec_gx256, ec_gy256 .import ec_base_x, ec_base_y +; --- c64-lib-contract §1/§5: sibling version floor, checked at link time --- +; Two things depend on the pin being >= v0.9.0 and NEITHER fails loudly by +; itself, which is why this assert exists rather than a comment: +; +; - v0.7.0's FIPS 186-5 §3.3 public-key validation gate. The Q packed +; below reaches `ecdsa_verify_256` straight out of an attacker-supplied +; certificate (src/tls_cert.s -> ecdsa_pubkey_x/y) and c64-https performs +; no range or on-curve check of its own. Silently dropping back to a +; pre-v0.7.0 archive would reopen that gap with every test still green, +; because our KAT vectors all carry well-formed public keys. +; +; - v0.9.0's per-variant `zp_config_.o`, which +; tools/integration/build_nistcurves_p256.sh locates by name in order to +; re-apply c64-https's ZP overrides. Against an older archive that lookup +; changes shape. +; +; From v0.9.0 the version equates are exported `:abs` (upstream #95/#96), so +; importing them here costs no `ld65: Warning: Address size mismatch`. +.import LIB_NISTCURVES_VERSION_MAJOR +.import LIB_NISTCURVES_VERSION_MINOR +.assert LIB_NISTCURVES_VERSION_MAJOR = 0, lderror, "libs/nistcurves: expected MAJOR 0" +.assert LIB_NISTCURVES_VERSION_MINOR >= 9, lderror, "libs/nistcurves: pin is older than v0.9.0" + ; --- Phase 4a: P-384 TLS dispatcher (src/crypto/ecdsa_verify_384.s) --- .import ecdsa_verify_384_tls diff --git a/src/lib_contract_asserts.s b/src/lib_contract_asserts.s index 7f65aee..bd49e5f 100644 --- a/src/lib_contract_asserts.s +++ b/src/lib_contract_asserts.s @@ -132,7 +132,7 @@ APP_OWNED = LIB_SHARED_PRIMITIVES_SQTAB | LIB_SHARED_PRIMITIVES_REU_MUL | LIB_SH ; working: re-check the integration against the new export surface, then ; update the expected value on the next line — do not delete the assert. .import LIB_ABI_VERSION -.assert LIB_ABI_VERSION = 0, lderror, "libs/nistcurves: exported-surface generation changed (LIB_ABI_VERSION != 0) — re-check the integration, then bump the expected value in src/lib_contract_asserts.s" +.assert LIB_ABI_VERSION = 1, lderror, "libs/nistcurves: exported-surface generation changed (LIB_ABI_VERSION != 1) — re-check the integration, then bump the expected value in src/lib_contract_asserts.s" ; ===================================================================== diff --git a/tools/integration/build_nistcurves_p256.sh b/tools/integration/build_nistcurves_p256.sh index 0b5b9b3..488179d 100755 --- a/tools/integration/build_nistcurves_p256.sh +++ b/tools/integration/build_nistcurves_p256.sh @@ -11,11 +11,14 @@ # `make -C libs/nistcurves`, then performs adjustments before placing the # result at the location the top-level Makefile expects: # -# 1. Rebuild `zp_config.o` with c64-https's ZP-slot overrides (the upstream -# defaults collide with c64-https's canonical map on three slots: -# zp_ptr2, fp_mul_i, fp_mul_j). The library's zp_config.s `.ifndef`- -# guards every slot, so an override-built version replaces the -# upstream default cleanly. +# 1. Rebuild the archive's `zp_config*.o` member with c64-https's ZP-slot +# overrides (the upstream defaults collide with c64-https's canonical map +# on three slots: zp_ptr2, fp_mul_i, fp_mul_j). The library's zp_config.s +# `.ifndef`-guards every slot, so an override-built version replaces the +# upstream default cleanly. The member name is DISCOVERED from the +# archive, not hardcoded — upstream v0.9.0 gave each archive its own +# per-variant object (`zp_config_p256verify.o`), and a hardcoded name +# would drop the overrides silently. Post-checked with od65. # # 2. Drop `mul_8x8[_onchip].o` (REU profile) and `data_shared.o` (both # profiles) from the archive. c64-https's in-tree @@ -116,15 +119,63 @@ mkdir -p "$STAGING" "$OUT_DIR" cp "$UPSTREAM_ARCHIVE" "$STAGING/upstream.a" (cd "$STAGING" && "$AR65" x upstream.a $( "$AR65" t upstream.a )) -# --- 3. Rebuild zp_config.o with c64-https overrides --- +# --- 3. Rebuild the archive's zp_config member with c64-https overrides --- +# The member NAME is discovered, never hardcoded. Upstream v0.9.0 (issue #90) +# gave each of the nine archives its own per-variant ZP object, so +# `nistcurves-p256-verify.a` ships `zp_config_p256verify.o` and only the FULL +# archive still ships a plain `zp_config.o`. Step 5 re-archives strictly by +# `ar65 t upstream.a`, so writing to a hardcoded `zp_config.o` here would have +# been SILENTLY DROPPED from the output and the upstream-default object +# archived in its place — reinstating exactly the ZP collisions these +# overrides exist to prevent (zp_ptr2 $fd vs c64-https zp_temp/zp_count during +# cert parsing; fp_mul_i/j $2c/$2d inside the fe25519 claim $2c-$37). That is +# memory corruption at runtime, not a link error, so it must fail loudly here. +ZP_MEMBER="" +for m in $( "$AR65" t "$STAGING/upstream.a" ); do + case "$m" in zp_config*.o) + [ -z "$ZP_MEMBER" ] || { echo "ERROR: upstream archive has more than one zp_config member ($ZP_MEMBER, $m) — teach this script which one to override" >&2; exit 1; } + ZP_MEMBER="$m" ;; + esac +done +[ -n "$ZP_MEMBER" ] || { echo "ERROR: no zp_config*.o member in $UPSTREAM_ARCHIVE — upstream layout changed; the c64-https ZP overrides would be silently lost" >&2; exit 1; } + +# The variant gate decides which slots the object .exportzp's (zp_config.s +# lines ~132-141), so it must match what upstream built the member with. +case "$ZP_MEMBER" in + zp_config.o) ZP_VARIANT_DEFINE=() ;; + zp_config_p256verify.o) ZP_VARIANT_DEFINE=('-D' 'LIB_P256_VERIFY_ONLY') ;; + zp_config_p384verify.o) ZP_VARIANT_DEFINE=('-D' 'LIB_P384_VERIFY_ONLY') ;; + zp_config_p384curve.o) ZP_VARIANT_DEFINE=('-D' 'LIB_P384_CURVE_ONLY') ;; + zp_config_sha384.o) ZP_VARIANT_DEFINE=('-D' 'LIB_SHA384_ONLY') ;; + *) echo "ERROR: unrecognised zp_config member '$ZP_MEMBER' — add its upstream -D gate to this case block" >&2; exit 1 ;; +esac + +echo "[p256/$PROFILE] rebuilding $ZP_MEMBER with c64-https ZP overrides..." "$CA65" \ --cpu 6502 \ -g \ -I "$LIB_SRC" \ + "${ZP_VARIANT_DEFINE[@]+"${ZP_VARIANT_DEFINE[@]}"}" \ "${ZP_OVERRIDES[@]}" \ - -o "$STAGING/zp_config.o" \ + -o "$STAGING/$ZP_MEMBER" \ "$LIB_SRC/zp_config.s" +# 3b. Prove the overrides actually landed in the object that gets archived. +# A ZP collision here is silent at link time and only shows up as corrupted +# cert parsing at runtime, so assert the values rather than trusting the -D. +check_zp_slot() { + local name="$1" want="$2" got + got=$("${OD65:-od65}" --dump-exports "$STAGING/$ZP_MEMBER" \ + | awk -v n="\"$name\"" '$1=="Name:" && $2==n {f=1; next} f && $1=="Value:" {gsub(/[()]/,"",$3); print $3; exit}') + if [ "$got" != "$want" ]; then + echo "ERROR: $ZP_MEMBER exports $name = ${got:-}, expected $want (c64-https ZP override did not take)" >&2 + exit 1 + fi +} +check_zp_slot zp_ptr2 61 # $3d +check_zp_slot fp_mul_i 57 # $39 +check_zp_slot fp_mul_j 58 # $3a + # --- 4. Drop conflicting members / rebuild the onchip mul object --- rm -f "$STAGING/mul_8x8.o" "$STAGING/data_shared.o" # 4b. onchip-comb: the full onchip archive carries both curves + SHA-384 + diff --git a/tools/integration/build_nistcurves_p384.sh b/tools/integration/build_nistcurves_p384.sh index b9a043d..6a9eed4 100755 --- a/tools/integration/build_nistcurves_p384.sh +++ b/tools/integration/build_nistcurves_p384.sh @@ -107,18 +107,78 @@ cp "$UPSTREAM_CURVE_ARCHIVE" "$STAGING/curve/upstream.a" (cd "$STAGING/sha" && "$AR65" x upstream.a $( "$AR65" t upstream.a )) (cd "$STAGING/curve" && "$AR65" x upstream.a $( "$AR65" t upstream.a )) -# --- 3. Rebuild zp_config.o with c64-https overrides (shared by both archives) --- -"$CA65" \ - --cpu 6502 \ - -g \ - -I "$LIB_SRC" \ - "${ZP_OVERRIDES[@]}" \ - -o "$STAGING/zp_config.o" \ - "$LIB_SRC/zp_config.s" +# --- 3. Rebuild each archive's zp_config member with c64-https overrides --- +# Member names are DISCOVERED, never hardcoded. Upstream v0.9.0 (issue #90) +# gave every archive its own per-variant manifest + ZP objects, so +# `zp_config.o` / `lib_manifest.o` no longer exist in these archives — +# they are `zp_config_sha384.o` / `lib_manifest_p384verify.o` and friends. +# Hardcoding the old names made this script die at the ar65 staging step. +# +# The variant gate matters twice over: it selects which slots the object +# `.exportzp`s, and the SHA-384 variant deliberately exports only the four +# sha_* slots — so the c64-https overrides below are a legitimate no-op there +# and the post-check must tolerate their absence rather than demand them. +find_member() { + # find_member -> echoes the single matching member + local dir="$1" glob="$2" hit="" m + for m in $( "$AR65" t "$dir/upstream.a" ); do + case "$m" in $glob) + [ -z "$hit" ] || { echo "ERROR: $dir/upstream.a has >1 member matching '$glob' ($hit, $m)" >&2; exit 1; } + hit="$m" ;; + esac + done + [ -n "$hit" ] || { echo "ERROR: no member matching '$glob' in $dir/upstream.a — upstream layout changed" >&2; exit 1; } + echo "$hit" +} + +zp_variant_define() { + case "$1" in + zp_config.o) ;; + zp_config_p256verify.o) echo '-D LIB_P256_VERIFY_ONLY' ;; + zp_config_p384verify.o) echo '-D LIB_P384_VERIFY_ONLY' ;; + zp_config_p384curve.o) echo '-D LIB_P384_CURVE_ONLY' ;; + zp_config_sha384.o) echo '-D LIB_SHA384_ONLY' ;; + *) echo "ERROR: unrecognised zp_config member '$1' — add its upstream -D gate" >&2; exit 1 ;; + esac +} + +# Present ⇒ must carry the c64-https value. Absent ⇒ this variant does not +# export the slot, which is fine. A wrong value is silent memory corruption +# at runtime, never a link error, so it has to be caught here. +check_zp_slot_if_present() { + local obj="$1" name="$2" want="$3" got + got=$("${OD65:-od65}" --dump-exports "$obj" \ + | awk -v n="\"$name\"" '$1=="Name:" && $2==n {f=1; next} f && $1=="Value:" {gsub(/[()]/,"",$3); print $3; exit}') + [ -z "$got" ] && return 0 + if [ "$got" != "$want" ]; then + echo "ERROR: $(basename "$obj") exports $name = $got, expected $want (c64-https ZP override did not take)" >&2 + exit 1 + fi +} + +for tree in sha curve; do + zp_member="$(find_member "$STAGING/$tree" 'zp_config*.o')" + echo "[p384] rebuilding $tree/$zp_member with c64-https ZP overrides..." + # shellcheck disable=SC2046 # deliberate word-split of the -D pair + "$CA65" \ + --cpu 6502 \ + -g \ + -I "$LIB_SRC" \ + $(zp_variant_define "$zp_member") \ + "${ZP_OVERRIDES[@]}" \ + -o "$STAGING/$tree/$zp_member" \ + "$LIB_SRC/zp_config.s" + check_zp_slot_if_present "$STAGING/$tree/$zp_member" zp_ptr2 61 # $3d + check_zp_slot_if_present "$STAGING/$tree/$zp_member" fp_mul_i 57 # $39 + check_zp_slot_if_present "$STAGING/$tree/$zp_member" fp_mul_j 58 # $3a +done -# Distribute the overridden zp_config.o into both staging trees. -cp "$STAGING/zp_config.o" "$STAGING/sha/zp_config.o" -cp "$STAGING/zp_config.o" "$STAGING/curve/zp_config.o" +SHA_ZP="$(find_member "$STAGING/sha" 'zp_config*.o')" +CURVE_ZP="$(find_member "$STAGING/curve" 'zp_config*.o')" +SHA_MANIFEST="$(find_member "$STAGING/sha" 'lib_manifest*.o')" +CURVE_MANIFEST="$(find_member "$STAGING/curve" 'lib_manifest*.o')" +SHA_PRECALC="$(find_member "$STAGING/sha" 'precalc_manifest*.o')" +CURVE_PRECALC="$(find_member "$STAGING/curve" 'precalc_manifest*.o')" # --- 4. Drop conflicting members from the curve archive --- # Same reasoning as P-256: mul_8x8.o + data_shared.o collide with @@ -184,8 +244,9 @@ SHIM_EOF rm -f "$ARCHIVE_SHA" "$AR65" a "$ARCHIVE_SHA" \ "$STAGING/sha/lib_version.o" \ - "$STAGING/sha/lib_manifest.o" \ - "$STAGING/sha/zp_config.o" \ + "$STAGING/sha/$SHA_MANIFEST" \ + "$STAGING/sha/$SHA_PRECALC" \ + "$STAGING/sha/$SHA_ZP" \ "$STAGING/sha/sha384.o" \ "$STAGING/sha/data_sha.o" @@ -195,8 +256,9 @@ rm -f "$ARCHIVE_SHA" rm -f "$ARCHIVE_CURVE" "$AR65" a "$ARCHIVE_CURVE" \ "$STAGING/curve/lib_version.o" \ - "$STAGING/curve/lib_manifest.o" \ - "$STAGING/curve/zp_config.o" \ + "$STAGING/curve/$CURVE_MANIFEST" \ + "$STAGING/curve/$CURVE_PRECALC" \ + "$STAGING/curve/$CURVE_ZP" \ "$STAGING/curve/constants.o" \ "$STAGING/curve/reu_config.o" \ "$STAGING/curve/fp384.o" \ @@ -210,7 +272,7 @@ rm -f "$ARCHIVE_CURVE" # --- 7. Per-source byte counts --- { echo "# nistcurves-p384-sha384.a per-source byte counts (ca65 .o file sizes)" - for src in lib_version lib_manifest zp_config sha384 data_sha; do + for src in lib_version "${SHA_MANIFEST%.o}" "${SHA_PRECALC%.o}" "${SHA_ZP%.o}" sha384 data_sha; do if [ -f "$STAGING/sha/$src.o" ]; then bytes=$(wc -c < "$STAGING/sha/$src.o") printf '%-32s %d bytes (.o)\n' "$src" "$bytes" @@ -220,7 +282,7 @@ rm -f "$ARCHIVE_CURVE" { echo "# nistcurves-p384-curve.a per-source byte counts (ca65 .o file sizes)" - for src in lib_version lib_manifest zp_config constants reu_config \ + for src in lib_version "${CURVE_MANIFEST%.o}" "${CURVE_PRECALC%.o}" "${CURVE_ZP%.o}" constants reu_config \ fp384 mod384 curve384 points384_core ecdsa384_nocomb \ ec_scalar_mul_384_shim data_p384; do if [ -f "$STAGING/curve/$src.o" ]; then