Repository navigation
Retire the P-384 lane; only P-256 is verified (incl. L5) - #294
Merged
Merged
Conversation
JC-000
added a commit
that referenced
this pull request
Oct 12, 2026
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Everything below already assembled into every shipped image while only
an ENABLE_P384_VERIFY build could use it. Each is gated, not deleted, so
the armed link keeps all of it (CLAUDE.md: that link is the only thing
that keeps ecdsa_verify_384.s honest):
src/data.s ecdsa_pubkey_{x,y}_384 (96 B BSS) and their exports
src/tls_cert.s the P-384 curve-OID check, the 48 B pubkey copies, and
the CertificateVerify 0x0503 short-circuit
src/boot.s reu_p384_overlay_init: label, export and boot call,
under crypto_swap.s's own gate (KEEP_CRYPTO_SWAP /
ENABLE_P384_VERIFY / either overlay embed); it was an
RTS without the P-384 embed anyway
Behaviour, unarmed: a P-384 leaf is now refused AT Certificate (the scan
finds no supported key, C=1) instead of being extracted as curve 1 and
refused at CertificateVerify; a 0x0503 CertificateVerify is refused in
the handler without routing curve_id = 1 into the dispatcher. Same
verdict, earlier, with less code; ecdsa_curve_id can no longer be 1.
Freed (tools/measure_margins.py --build), every profile:
code ip65 CRYPTO_OVERLAY 45 -> 144 (+99), ip65-onchip 11 -> 110;
uci NET_CODE 176 -> 275 (+99), uci-onchip 184 -> 283,
uci-comb 176 -> 275, uci-onchip-store 184 -> 283,
uci-comb-store 38 -> 137, comb demo 38 -> 137
LOADER +4 B everywhere (the jsr and the rts)
BSS 96 B: ip65's hole below TABLES_BSS 71 -> 167; on UCI the gap
below X25519_TABLES ($B100, page-aligned) 14 -> 110 -- alignment
padding, not tail, on both
Armed builds fail exactly as on master (NET_CODE overflow 327/319/327 B
on uci/onchip/comb, ip65 CRYPTO_OVERLAY 63/97 B -- the same bytes, so the
gates restore everything). That link was already broken at 75dd519;
KEEP_CRYPTO_SWAP=1 and uci-m3 link.
tools/test_tls_p384_negotiation.py: [1b] is build-aware (armed =
ecdsa_verify_384_tls linked, which tracks the flag on master and here);
new [1c] runs a P-384 leaf, SAN matching tls_hostname so only the curve
can refuse it, through the live x509_extract_pubkey.
L5 ip65 23b843bc..., uci-onchip d5202b48...: [1a][1b][1c] PASS
master tls_cert.s/data.s, uci-onchip 60678588...: [1b] FAIL
(curve_id = 1), [1c] FAIL (C=0: leaf extracted as P-384)
test_p384_overlay_hazard.py PASS on both (C=1, 0/7680 overlay bytes
changed). test_cert_pin.py 44 PASS.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…n ([1d]) Review finding: the previous commit said a P-384 leaf is refused AT Certificate. That holds for a plain P-384 leaf only. x509_extract_pubkey scans for the first supported curve OID rather than parsing the TBS, so with the P-384 OID gated out a P-384 leaf that also carries a P-256 SPKI byte pattern later (inside an unknown extension, say) gets C=0 with that trailing P-256 key extracted -- as RSA leaves already do at 75dd519. CertificateVerify is then checked against the extracted key, one the server chose; the same position as any self-chosen leaf, since nothing validates a chain, and a pin binds to the extracted key. src/tls_cert.s the gate's comment says so tools/test_tls_p384_negotiation.py [1c] docstring narrowed to a PLAIN P-384 leaf; new [1d] (characterisation, not a guarantee): P-384 leaf, SAN = tls_hostname, real P-384 SPKI first, a P-256 SPKI inside an unknown extension (1.3.6.1.4.1.99999.1) after it. Unarmed: C=0, curve 0, the trailing P-256 point extracted. Armed: curve 1. Green: ip65 23b843bc..., uci-onchip d5202b48... (PRGs unchanged: comment only): [1a]-[1d] PASS. Red / characterising: master's tls_cert.s + data.s, uci-onchip 60678588...: [1b] [1c] FAIL as before, [1d] FAIL (C=0 but curve_id=1: master takes the P-384 key first), so the [1d] behaviour is this branch's, now documented. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
ENABLE_P384_VERIFY=1 no longer linked on any of the five profiles at 75dd519 (NET_CODE / CRYPTO_OVERLAY overflows), and no P-384 build target ever completed. The user decided to retire the lane. Removed: src/crypto/ecdsa_verify_384.s, src/crypto/p384_force_link.s, the P-384 arm of ecdsa_verify.s (any non-zero ecdsa_curve_id is now a clean C=1 before the VIC is blanked or the library entered), the L5-gated code in tls_cert.s / data.s / boot.s (P-384 OID check, 48 B copies, 0x0503 short-circuit and cv_sig_scheme -- the handler now accepts 0x0403 only), reu_p384_overlay_init and its stash; the overlay machinery that existed only to page P-384 (and the retired P-256 embed): crypto_swap.s, overlay_ids.inc, p384_overlay_blobs.s, p256_overlay_blobs.s, cfg/p384-overlay-{curve,sha384}.cfg, cfg/p256-overlay-verify.cfg, build_nistcurves_p384{,_bin}.sh, build_nistcurves_p256_bin.sh, gen_p384_overlay_equates.sh, the unused build_nistcurves.sh placeholder, the p384-overlay / p256-overlay make targets, and every cfg's OVERLAY_P256/P384, OVERLAY_BLOB_*, LIB_NISTCURVES_P384_* / SHA384_* routing and OVERLAY_BLOB_CURVE_RAM; src/crypto/shared/reu_layout.inc (no consumer left), the REU banks 6-7 reservation (lib_contract_asserts.s, http.s), so the HTTP body sink's region is now [base, REU end) for any base at or above bank 3; tools/test_p384_overlay_hazard.py, test_p384_symbols.py, test_ecdsa_p384_kat.py, tools/uci/rig_https_local_p384.py, and the skip-contract case that spawned the P-384 KAT. Kept, and why: crypto_swap.s / P-256 overlay plumbing had no importer outside the P-384 path and the already-retired embed, so they went too. Kept: OVERLAY_FILE_PAD (dropping it would stop the UCI PRG zero-filling $C000-$DFFF at load, a separate behaviour change); the listener's P-384 cert profile (the fixture a hardware refusal test would need); test_x509.py's P-384 DER-parse group (x509_parse_cert, test-only knob); ecdsa_curve_id (the pin hook and trust_bundle use it); the dead overlay segment names in tools/uci/_memory_policy.py's blocker list (harmless, harness logic untouched). LIB_NISTCURVES_REU_BANKS_USED keeps an import (asserted < bank 3, the sink floor): the REU preflight reads it from labels.txt. Retired knobs ENABLE_P384_VERIFY, USE_OVERLAY_P384_EMBED, KEEP_CRYPTO_SWAP, EMBED_P256_OVERLAY, USE_OVERLAY_P256_EMBED are a Makefile $(error) for any value (=0 included), like USE_X25519_SIBLING. tools/test_curve_refusal.py replaces test_tls_p384_negotiation.py: [1a] ClientHello offers 0x0403 only; [1b] 0x0503 CertificateVerify refused, curve_id untouched; [1c] P-384, [1e] RSA-2048, [1f] Ed25519 leaves refused (C=1, slots untouched); [1d] P-384 leaf + trailing P-256 pattern characterised. 6/6 on ip65 a0e9dfce, uci-onchip d5fe4a54 (no REU), uci-comb 662d7fd9. ECDSA KAT 6/6 on uci-onchip and uci-comb. Sink: test_reu_body_sink.py / test_http.py retargeted from the bank-6 edge to the REU's end (wrap to bank 0). Red: the new expectations against the old sink code -> 11 failures, all the banks 6-7 cap; green 76/76 on b96e1a4a (comb demo). Freed vs L5 (tools/measure_margins.py --build): ip65 CRYPTO_OVERLAY +17, CRYPTO_RESIDENT +2; every UCI profile NET_CODE +17, CRYPTO_HOT +22. UCI PRG file 62,977 -> 55,297 B (the 7,680 B curve-blob pad). Also green: test_runner_coverage, test_rig_skip_contract + test_skip_policy (37), cold-bank cfg delta, test_pytest_boundary, _sni_precondition --selftest, root pytest (440 + 2 build-state). CLAUDE.md / README: one line each; PR link TBD (not pushed). Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…docs Review findings on d638333. 1. [1b] could not go red. It sent 48 zero bytes and asserted only C=1; ecdsa_parse_der_sig rejects those whatever the scheme, so a handler with no scheme gate passed. [1b] now judges the GATE by tls_recv_sub_progress ($21 after the type check, $22 only once the scheme gate passes): 0x0503, 0x0603, 0x0804 and 0x0003 must stop at $21 with C=1 and ecdsa_curve_id untouched; the 0x0403 control must get past it. Red: the gate's `cmp #$04 / bne` removed from tls_cert.s (ip65 0cdff9ec...) -> 0x0503, 0x0603, 0x0003 reach $23 (C=1 on all of them, which is why the old check passed) -> 5/6. Restored a0e9dfce... -> 6/6; uci-onchip d5fe4a54... -> 6/6. 2. TRUST_STORE builds: x509_extract_pubkey tail-calls the trust hook, which refuses while tp_mode is TP_M_NONE -- the bug L3 had. Every extraction now sets TP_M_FIRST (read from src/trust_policy.inc) first. Shipped onchip-store a3fdc772... (no REU) 6/6 and comb-store 6a5a2993... 6/6. Red: the arming removed, onchip-store -> [1d] C=1, curve 0, trailing key extracted (the hook's refusal) -> 5/6. 3. Runner: run_tests(transport, labels, seed) added, shared by main(); "curve_refusal" is in run_all_tests.SUITE_ORDER with its dispatch arm (valid on the ip65 build the runner makes). test_runner_coverage and test_pytest_boundary pass. 4. Docs: CLAUDE.md's two "every other key or scheme is refused" sentences deduplicated into one, qualified with the [1d] exception; README's "parked as roadmap work" -> retired; src/vic.s no longer names ecdsa_verify_384_tls; "32 or 48" comments in data.s and tls_cert.s -> 32 (P-256 only). PRGs unchanged (comment only). 5. Stale overlay names: tools/rig_scratch_profiles.json regenerated from real links (test_rig_scratch.py --build --write-fixtures, 17/17); the OVERLAY_BLOB_SHA384/P256 and OVERLAY_P256/P384 blockers and the prose that cited them dropped from tools/uci/_memory_policy.py. OVERLAY_FILE_PAD untouched (pending #288). Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Review finding: every refused scheme in [1b] had a high byte != $04, so the gate's low-byte check (`cmp #$03 / beq`) was never exercised; with it replaced by `jmp`, [1b] still passed. Added 0x0401 (rsa_pkcs1_sha256), 0x0402 and 0x04FF, which only the low-byte check refuses. Red: `cmp #$03 / beq :+` -> `jmp :+` in src/tls_cert.s, ip65 73cddfcd... -> 0x0401, 0x0402, 0x04FF reach $23 -> 5/6. Green, restored: ip65 a0e9dfce... 6/6, onchip-store a3fdc772... 6/6 (no REU), comb-store 6a5a2993... 6/6. Also: src/data.s's note about reclaiming the P-384 slots "when ecdsa_verify_384 is re-integrated" now says the lane is retired. Comment only; PRGs unchanged. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
The capture predated #292's P256_SCRATCH_UNION and #290's sha256 roll, so its five PRG hashes and labels were the pre-rebase links. Regenerated with test_rig_scratch.py --build --write-fixtures; --build re-run: matrix PASS, 17/17, hashes uci ed6871b2, uci-onchip eaa43a6a, uci-comb 8f8a0d05, uci-comb-trust 936884e9, uci-comb-demo-trust b66eaf0c. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
JC-000
force-pushed
the
retire/p384-lane
branch
from
October 12, 2026 20:04
3f420f2 to
17654bf
Compare
This was referenced Oct 14, 2026
Merged
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 free
to 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.
Retires the P-384 lane (decision 2026-10-08): only P-256 is verified. Includes layout pass L5.
ecdsa_verify_384,p384_force_link,crypto_swap, overlay ids,reu_layout.inc,OVERLAY_BLOB_CURVE_RAM, the P-384 tests and rig; knobsENABLE_P384_VERIFY/USE_OVERLAY_P384_EMBEDare retired and$(error)-guarded.tools/test_curve_refusal.py6/6, including [1b], which checkstls_recv_sub_progressfor 0x0401/0x0402/0x04FF and was mutated until it could go red. Green after the rebase: ip65c270ae4e…, onchip-store7059930a…(no REU), comb-store936884e9…(REU). (Pre-rebase: ip65a0e9dfce…, onchip-storea3fdc772…, comb-store6a5a2993….)Rebased on
75fe1b4(master with #289-#293). Conflicts, resolved keeping both sides:cfg/c64-https-uci.cfg,-uci-onchip.cfg,-uci-onchip-cold.cfg: uci: union P-256 scratch with cert_buf (+1,312 B), with lifetime proof (L2+L3) #292'sP256_SCRATCH_UNION(LIB_NISTCURVES_P256_BSS on cert_buf,CERT_BUF_BSSpinned at$4200) kept with its comments; the P-384LIB_NISTCURVES_P384_*/SHA384_*header lines and the overlay-embed paragraphs atCERT_BUF_BSSdropped; no duplicateCERT_BUF_BSSline (the retirement's unpinned one is gone, the pinned one stays).tools/uci/README.md: rigs: trust store via the harness storage API; retire _temp_gc.py #293'srig_trust_store.py/rig_trust_policy.pyrows kept, therig_https_local_p384.pyrow dropped.tools/rig_scratch_profiles.jsonregenerated (test_rig_scratch.py --build --write-fixtures), since the capture predated uci: union P-256 scratch with cert_buf (+1,312 B), with lifetime proof (L2+L3) #292/sha256: roll sha256_add_to_hash (-250 B on every profile) (L4) #290.Every profile
tools/measure_margins.py --buildcovers links. PRG sha256 and free bytes vs master75fe1b4(tail free; the PRG file is fixed-size, so it is not the gauge):3caf4526c270ae4ee1ad289d810f115874fc00b85f363110c729761700bdf485b4e4e6fbed6871b24ab553bfeaa43a6a4281d7868f8a0d05375f94807059930a74a7d358936884e9335c481fd499a112(The commit messages below quote +17/+22 "vs L5" and +99 for L5 itself; vs master the two together are the +116.)
Verified after the rebase:
test_curve_refusal.py6/6 on ip65c270ae4e, onchip-store7059930a(C64_VICE_NO_REU=1), comb-store936884e9(REU).test_ecdsa_kat_oracle.py10/10 incl. [3k]-[3n] on onchip-store7059930a(no REU) and comb-store936884e9(REU).test_cold_bank.py117/117;test_rig_scratch.py17/17 and--buildmatrix PASS;test_build_flags_stamp.py17/17;test_runner_coverage.pyPASS;check_upstream_pins.py --strict0 (nistcurves v0.15.0, x25519 v0.16.0).pyteston aBACKEND=ucibuild: 476 passed, 1 failed —test_ip65_hw_checks_unit.py::test_the_build_exports_every_symbol_the_rig_reads, which requires an ip65 build inbuild/; onBACKEND=ip65 USE_NISTCURVES_ONCHIP=1that file is 49/49.boot_check.pyPASS on onchip-store7059930aand comb-store936884e9;rig_https_local.pyPASS (HTTP 200 body, listener decrypted the GET) on uci-onchip+SNI218a337band uci-comb+SNI5800da18.rig_https_local.pydoes NOT pass on a TRUST_STORE build: onchip-store+SNI572b3c76stops at Certificate (tls_last_state=$04), and master's onchip-store+SNI4544a0c2stops at the same point — the trampoline never runstrust_pre, so it is the rig, not this PR.Commits (messages verbatim; each carries its red-green evidence)
8a92147 p384: gate the leftovers nothing reaches without ENABLE_P384_VERIFY
Everything below already assembled into every shipped image while only
an ENABLE_P384_VERIFY build could use it. Each is gated, not deleted, so
the armed link keeps all of it (CLAUDE.md: that link is the only thing
that keeps ecdsa_verify_384.s honest):
src/data.s ecdsa_pubkey_{x,y}_384 (96 B BSS) and their exports
src/tls_cert.s the P-384 curve-OID check, the 48 B pubkey copies, and
the CertificateVerify 0x0503 short-circuit
src/boot.s reu_p384_overlay_init: label, export and boot call,
under crypto_swap.s's own gate (KEEP_CRYPTO_SWAP /
ENABLE_P384_VERIFY / either overlay embed); it was an
RTS without the P-384 embed anyway
Behaviour, unarmed: a P-384 leaf is now refused AT Certificate (the scan
finds no supported key, C=1) instead of being extracted as curve 1 and
refused at CertificateVerify; a 0x0503 CertificateVerify is refused in
the handler without routing curve_id = 1 into the dispatcher. Same
verdict, earlier, with less code; ecdsa_curve_id can no longer be 1.
Freed (tools/measure_margins.py --build), every profile:
code ip65 CRYPTO_OVERLAY 45 -> 144 (+99), ip65-onchip 11 -> 110;
uci NET_CODE 176 -> 275 (+99), uci-onchip 184 -> 283,
uci-comb 176 -> 275, uci-onchip-store 184 -> 283,
uci-comb-store 38 -> 137, comb demo 38 -> 137
LOADER +4 B everywhere (the jsr and the rts)
BSS 96 B: ip65's hole below TABLES_BSS 71 -> 167; on UCI the gap
below X25519_TABLES ($B100, page-aligned) 14 -> 110 -- alignment
padding, not tail, on both
Armed builds fail exactly as on master (NET_CODE overflow 327/319/327 B
on uci/onchip/comb, ip65 CRYPTO_OVERLAY 63/97 B -- the same bytes, so the
gates restore everything). That link was already broken at 75dd519;
KEEP_CRYPTO_SWAP=1 and uci-m3 link.
tools/test_tls_p384_negotiation.py: [1b] is build-aware (armed =
ecdsa_verify_384_tls linked, which tracks the flag on master and here);
new [1c] runs a P-384 leaf, SAN matching tls_hostname so only the curve
can refuse it, through the live x509_extract_pubkey.
L5 ip65 23b843bc..., uci-onchip d5202b48...: [1a][1b][1c] PASS
master tls_cert.s/data.s, uci-onchip 60678588...: [1b] FAIL
(curve_id = 1), [1c] FAIL (C=0: leaf extracted as P-384)
test_p384_overlay_hazard.py PASS on both (C=1, 0/7680 overlay bytes
changed). test_cert_pin.py 44 PASS.
aec540f p384: qualify "refused at Certificate", and characterise the exception ([1d])
Review finding: the previous commit said a P-384 leaf is refused AT
Certificate. That holds for a plain P-384 leaf only. x509_extract_pubkey
scans for the first supported curve OID rather than parsing the TBS, so
with the P-384 OID gated out a P-384 leaf that also carries a P-256 SPKI
byte pattern later (inside an unknown extension, say) gets C=0 with that
trailing P-256 key extracted -- as RSA leaves already do at 75dd519.
CertificateVerify is then checked against the extracted key, one the
server chose; the same position as any self-chosen leaf, since nothing
validates a chain, and a pin binds to the extracted key.
src/tls_cert.s the gate's comment says so
tools/test_tls_p384_negotiation.py [1c] docstring narrowed to a PLAIN
P-384 leaf; new [1d] (characterisation, not a guarantee): P-384 leaf,
SAN = tls_hostname, real P-384 SPKI first, a P-256 SPKI inside an
unknown extension (1.3.6.1.4.1.99999.1) after it. Unarmed: C=0,
curve 0, the trailing P-256 point extracted. Armed: curve 1.
Green: ip65 23b843bc..., uci-onchip d5202b48... (PRGs unchanged: comment
only): [1a]-[1d] PASS.
Red / characterising: master's tls_cert.s + data.s, uci-onchip 60678588...:
[1b] [1c] FAIL as before, [1d] FAIL (C=0 but curve_id=1: master takes the
P-384 key first), so the [1d] behaviour is this branch's, now documented.
eda8bb8 Retire the P-384 lane; only P-256 is verified
ENABLE_P384_VERIFY=1 no longer linked on any of the five profiles at
75dd519 (NET_CODE / CRYPTO_OVERLAY overflows), and no P-384 build target
ever completed. The user decided to retire the lane. Removed:
src/crypto/ecdsa_verify_384.s, src/crypto/p384_force_link.s, the
P-384 arm of ecdsa_verify.s (any non-zero ecdsa_curve_id is now a clean
C=1 before the VIC is blanked or the library entered), the L5-gated
code in tls_cert.s / data.s / boot.s (P-384 OID check, 48 B copies,
0x0503 short-circuit and cv_sig_scheme -- the handler now accepts
0x0403 only), reu_p384_overlay_init and its stash;
the overlay machinery that existed only to page P-384 (and the retired
P-256 embed): crypto_swap.s, overlay_ids.inc, p384_overlay_blobs.s,
p256_overlay_blobs.s, cfg/p384-overlay-{curve,sha384}.cfg,
cfg/p256-overlay-verify.cfg, build_nistcurves_p384{,bin}.sh,
build_nistcurves_p256_bin.sh, gen_p384_overlay_equates.sh, the unused
build_nistcurves.sh placeholder, the p384-overlay / p256-overlay make
targets, and every cfg's OVERLAY_P256/P384, OVERLAY_BLOB,
LIB_NISTCURVES_P384_ / SHA384_* routing and OVERLAY_BLOB_CURVE_RAM;
src/crypto/shared/reu_layout.inc (no consumer left), the REU banks 6-7
reservation (lib_contract_asserts.s, http.s), so the HTTP body sink's
region is now [base, REU end) for any base at or above bank 3;
tools/test_p384_overlay_hazard.py, test_p384_symbols.py,
test_ecdsa_p384_kat.py, tools/uci/rig_https_local_p384.py, and the
skip-contract case that spawned the P-384 KAT.
Kept, and why: crypto_swap.s / P-256 overlay plumbing had no importer
outside the P-384 path and the already-retired embed, so they went too.
Kept: OVERLAY_FILE_PAD (dropping it would stop the UCI PRG zero-filling
$C000-$DFFF at load, a separate behaviour change); the listener's P-384
cert profile (the fixture a hardware refusal test would need);
test_x509.py's P-384 DER-parse group (x509_parse_cert, test-only knob);
ecdsa_curve_id (the pin hook and trust_bundle use it); the dead overlay
segment names in tools/uci/_memory_policy.py's blocker list (harmless,
harness logic untouched). LIB_NISTCURVES_REU_BANKS_USED keeps an import
(asserted < bank 3, the sink floor): the REU preflight reads it from
labels.txt.
Retired knobs ENABLE_P384_VERIFY, USE_OVERLAY_P384_EMBED,
KEEP_CRYPTO_SWAP, EMBED_P256_OVERLAY, USE_OVERLAY_P256_EMBED are a
Makefile $(error) for any value (=0 included), like USE_X25519_SIBLING.
tools/test_curve_refusal.py replaces test_tls_p384_negotiation.py:
[1a] ClientHello offers 0x0403 only; [1b] 0x0503 CertificateVerify
refused, curve_id untouched; [1c] P-384, [1e] RSA-2048, [1f] Ed25519
leaves refused (C=1, slots untouched); [1d] P-384 leaf + trailing P-256
pattern characterised. 6/6 on ip65 a0e9dfce, uci-onchip d5fe4a54
(no REU), uci-comb 662d7fd9. ECDSA KAT 6/6 on uci-onchip and uci-comb.
Sink: test_reu_body_sink.py / test_http.py retargeted from the bank-6
edge to the REU's end (wrap to bank 0). Red: the new expectations
against the old sink code -> 11 failures, all the banks 6-7 cap; green
76/76 on b96e1a4a (comb demo).
Freed vs L5 (tools/measure_margins.py --build): ip65 CRYPTO_OVERLAY +17,
CRYPTO_RESIDENT +2; every UCI profile NET_CODE +17, CRYPTO_HOT +22. UCI
PRG file 62,977 -> 55,297 B (the 7,680 B curve-blob pad).
Also green: test_runner_coverage, test_rig_skip_contract +
test_skip_policy (37), cold-bank cfg delta, test_pytest_boundary,
_sni_precondition --selftest, root pytest (440 + 2 build-state).
CLAUDE.md / README: one line each; PR link TBD (not pushed).
9d0c4ab curve refusal: test the scheme gate itself; run on the store builds; docs
Review findings on d638333.
[1b] could not go red. It sent 48 zero bytes and asserted only C=1;
ecdsa_parse_der_sig rejects those whatever the scheme, so a handler
with no scheme gate passed. [1b] now judges the GATE by
tls_recv_sub_progress ($21 after the type check, $22 only once the
scheme gate passes): 0x0503, 0x0603, 0x0804 and 0x0003 must stop at
$21 with C=1 and ecdsa_curve_id untouched; the 0x0403 control must get
past it. Red: the gate's
cmp #$04 / bneremoved from tls_cert.s(ip65 0cdff9ec...) -> 0x0503, 0x0603, 0x0003 reach $23 (C=1 on all of
them, which is why the old check passed) -> 5/6. Restored a0e9dfce...
-> 6/6; uci-onchip d5fe4a54... -> 6/6.
TRUST_STORE builds: x509_extract_pubkey tail-calls the trust hook,
which refuses while tp_mode is TP_M_NONE -- the bug L3 had. Every
extraction now sets TP_M_FIRST (read from src/trust_policy.inc) first.
Shipped onchip-store a3fdc772... (no REU) 6/6 and comb-store
6a5a2993... 6/6. Red: the arming removed, onchip-store -> [1d] C=1,
curve 0, trailing key extracted (the hook's refusal) -> 5/6.
Runner: run_tests(transport, labels, seed) added, shared by main();
"curve_refusal" is in run_all_tests.SUITE_ORDER with its dispatch arm
(valid on the ip65 build the runner makes). test_runner_coverage and
test_pytest_boundary pass.
Docs: CLAUDE.md's two "every other key or scheme is refused"
sentences deduplicated into one, qualified with the [1d] exception;
README's "parked as roadmap work" -> retired; src/vic.s no longer
names ecdsa_verify_384_tls; "32 or 48" comments in data.s and
tls_cert.s -> 32 (P-256 only). PRGs unchanged (comment only).
Stale overlay names: tools/rig_scratch_profiles.json regenerated from
real links (test_rig_scratch.py --build --write-fixtures, 17/17); the
OVERLAY_BLOB_SHA384/P256 and OVERLAY_P256/P384 blockers and the prose
that cited them dropped from tools/uci/_memory_policy.py.
OVERLAY_FILE_PAD untouched (pending #288).
a32baf3 curve refusal: [1b] also tests the scheme gate's low byte
Review finding: every refused scheme in [1b] had a high byte != $04, so
the gate's low-byte check (
cmp #$03 / beq) was never exercised; with itreplaced by
jmp, [1b] still passed. Added 0x0401 (rsa_pkcs1_sha256),0x0402 and 0x04FF, which only the low-byte check refuses.
Red:
cmp #$03 / beq :+->jmp :+in src/tls_cert.s, ip65 73cddfcd...-> 0x0401, 0x0402, 0x04FF reach $23 -> 5/6.
Green, restored: ip65 a0e9dfce... 6/6, onchip-store a3fdc772... 6/6
(no REU), comb-store 6a5a2993... 6/6.
Also: src/data.s's note about reclaiming the P-384 slots "when
ecdsa_verify_384 is re-integrated" now says the lane is retired. Comment
only; PRGs unchanged.
🤖 Generated with Claude Code