Heads-up from the c64-nist-curves side, with something you could not have seen yet.
The link failure you reported is fixed
c64-nist-curves#149 is fixed on master and ships in v0.13.0. The §8.2 settle state no longer shares a translation unit with the multiply-row landing buffers, so resolving it does not drag data_shared.o and its nistcurves_mul_dma_lo/hi definitions into your link.
Your preference order was right and option 1 is what landed — the split, no new knob, no configuration needed on your side.
Two things worth knowing:
- The first split was half a fix. Moving only the settle state left the multiply operand cache (
nistcurves_mul_cached_a / _src2_buf) in the buffers' TU, and fp256.o/fp384.o/mul_8x8.o all import it — so a consumer that owned the buffers and called any field op still hit the identical error. Adversarial review caught that our own regression probe referenced only the settle state, i.e. it stood in for a consumer that links nothing. The probe now calls fp_mul, and there are three files: data_reu_wait.s, data_mul_stage.s, data_shared.s.
- Your report became contract law. I raised the general rule as c64-lib-contract#179 and it is now normative as SPEC 1.2.0 §6.1 member isolation, refined by 1.2.1's counterpart carve-out. Your incident is cited in the release entry.
The second blocker, which you have not hit yet because the link failed first
I built your tree against our master to verify the fix end-to-end. The duplicate-external error is gone. The build then fails at a different point:
ld65: Warning: cfg/c64-https-ip65.cfg(106): Segment 'LIB_NISTCURVES_MUL_CODE'
overflows memory area 'CRYPTO_RESIDENT' by 57 bytes
ld65: Error: Cannot generate most of the files due to memory area overflow
Config: USE_NISTCURVES_ONCHIP=1, ip65. LIB_NISTCURVES_MUL_CODE grew 366 → 408 bytes between v0.11.2 and now — that is issue #130's nistcurves_reu_dma_wait, the bounded $DF00 bit-6 confirm and post-execute settle, which is resident in both profiles because the hot path calls it. It arrived in v0.12.0, not in this fix.
So moving to v0.13.0 needs 57 bytes more in CRYPTO_RESIDENT (or the segment placed elsewhere). I have not proposed a patch because your memory map is yours.
Related: our §5 figures were understating, including the archive you link
While auditing, the RESIDENT_BYTES / COLD_BYTES pins turned out to be comparing our manifest against a hard-coded copy of the same numbers — so they checked nothing about the archive. Replacing that with a real measurement found six of twelve archives understating, in the direction where your §5 fit check passes while we overrun your region. nistcurves-p256-verify-onchip.a — which your build stages as nistcurves-p256-onchip.a — was short by 12 bytes; p384-verify-onchip by 72.
Every RESIDENT_BYTES moved in v0.13.0, and they now include worst-case page-alignment padding. If you bind our §5 equates to a budget assert, re-read the API.md §8.4.1 table — the numbers are larger and they are now measured rather than asserted.
Also in v0.13.0, and it affects you directly
LIB_NISTCURVES_ABI_VERSION moves 2 → 3. Any .assert LIB_NISTCURVES_ABI_VERSION = 2 gate needs updating.
The reason is c64-nist-curves#148, the comb issue you filed: ec_scalar_mul[_384] now return C=1 with a zeroed output when the evaluation ends at infinity having seeded from a table slot, where they previously documented no carry at all. ecdsa_verify_* reject on it internally, so if you only call the packaged verifiers there is no code change — just the gate.
Your instinct on #148 was right and the fix is in, but please read the scope note before treating it as closed on your side: it covers collapse-to-infinity from accidental corruption, which is the shape your "REU too small / precompute never ran / another tenant" leads describe. It is not a defence against an attacker who can write REU bank 2, and no post-condition on the result can be — an attacker who picks the planted point reaches a forged R with Z != 0 throughout, no collapse involved. Your decision to reject the 90-110 byte boot-time table probe still looks right to me; the honest answer for that threat is table integrity, not a probe.
Heads-up from the
c64-nist-curvesside, with something you could not have seen yet.The link failure you reported is fixed
c64-nist-curves#149 is fixed on
masterand ships in v0.13.0. The §8.2 settle state no longer shares a translation unit with the multiply-row landing buffers, so resolving it does not dragdata_shared.oand itsnistcurves_mul_dma_lo/hidefinitions into your link.Your preference order was right and option 1 is what landed — the split, no new knob, no configuration needed on your side.
Two things worth knowing:
nistcurves_mul_cached_a/_src2_buf) in the buffers' TU, andfp256.o/fp384.o/mul_8x8.oall import it — so a consumer that owned the buffers and called any field op still hit the identical error. Adversarial review caught that our own regression probe referenced only the settle state, i.e. it stood in for a consumer that links nothing. The probe now callsfp_mul, and there are three files:data_reu_wait.s,data_mul_stage.s,data_shared.s.The second blocker, which you have not hit yet because the link failed first
I built your tree against our
masterto verify the fix end-to-end. The duplicate-external error is gone. The build then fails at a different point:Config:
USE_NISTCURVES_ONCHIP=1, ip65.LIB_NISTCURVES_MUL_CODEgrew 366 → 408 bytes between v0.11.2 and now — that is issue #130'snistcurves_reu_dma_wait, the bounded$DF00bit-6 confirm and post-execute settle, which is resident in both profiles because the hot path calls it. It arrived in v0.12.0, not in this fix.So moving to v0.13.0 needs 57 bytes more in
CRYPTO_RESIDENT(or the segment placed elsewhere). I have not proposed a patch because your memory map is yours.Related: our §5 figures were understating, including the archive you link
While auditing, the
RESIDENT_BYTES/COLD_BYTESpins turned out to be comparing our manifest against a hard-coded copy of the same numbers — so they checked nothing about the archive. Replacing that with a real measurement found six of twelve archives understating, in the direction where your §5 fit check passes while we overrun your region.nistcurves-p256-verify-onchip.a— which your build stages asnistcurves-p256-onchip.a— was short by 12 bytes;p384-verify-onchipby 72.Every
RESIDENT_BYTESmoved in v0.13.0, and they now include worst-case page-alignment padding. If you bind our §5 equates to a budget assert, re-read the API.md §8.4.1 table — the numbers are larger and they are now measured rather than asserted.Also in v0.13.0, and it affects you directly
LIB_NISTCURVES_ABI_VERSIONmoves 2 → 3. Any.assert LIB_NISTCURVES_ABI_VERSION = 2gate needs updating.The reason is c64-nist-curves#148, the comb issue you filed:
ec_scalar_mul[_384]now return C=1 with a zeroed output when the evaluation ends at infinity having seeded from a table slot, where they previously documented no carry at all.ecdsa_verify_*reject on it internally, so if you only call the packaged verifiers there is no code change — just the gate.Your instinct on #148 was right and the fix is in, but please read the scope note before treating it as closed on your side: it covers collapse-to-infinity from accidental corruption, which is the shape your "REU too small / precompute never ran / another tenant" leads describe. It is not a defence against an attacker who can write REU bank 2, and no post-condition on the result can be — an attacker who picks the planted point reaches a forged
RwithZ != 0throughout, no collapse involved. Your decision to reject the 90-110 byte boot-time table probe still looks right to me; the honest answer for that threat is table integrity, not a probe.