Skip to content

fix(contract): §8.0 ownership expectation is profile-dependent (unblocks onchip builds) - #100

Closed
JC-000 wants to merge 1 commit into
masterfrom
fix/onchip-shared-primitives-assert
Closed

fix(contract): §8.0 ownership expectation is profile-dependent (unblocks onchip builds)#100
JC-000 wants to merge 1 commit into
masterfrom
fix/onchip-shared-primitives-assert

Conversation

@JC-000

Copy link
Copy Markdown
Owner

Unblocks the release. Both onchip variants — half the release matrix — fail to link at master.

Root cause

Measured with od65 on the two archives we actually build:

nistcurves-p256.a (REU) SHARED_PRIMITIVES = $0007
nistcurves-p256-onchip.a (onchip) SHARED_PRIMITIVES = $0005

$0007 → $0005 is the reu_mul bit leaving both masks under -D FP_ONCHIP_MUL, which upstream's CHANGELOG documents for that row. The onchip profile has no REU multiply path, so owning nothing there is correct — this is upstream behaving properly, not drift. The assert hardcoded $0007, measured at the v0.6.0 pin when both profiles still agreed; the masks split upstream since.

Credit: root-caused by the packaging and certs lanes, who found it via make package and declined to fix it in someone else's file.

The assert is not weakened

Both branches verified by negative control:

controlexpectationresult
onchip fed the old $0007should failfails the onchip link
REU fed $0001should failfails the REU link

Also: the error text was a red herring

It told the reader to "re-derive the archive member drops in tools/integration/build_nistcurves_p256.sh". Nothing about the surgery changed, and following that costs an afternoon — it did. The message now names the profile split, gives both expected values, and says to touch the wrapper only if which primitives ship has changed.

An assert that fires correctly but misdirects is half a safety net. Worth fixing at the same time as the value.

Verified from clean

make 47,105 B
make BACKEND=uci 62,977 B
make USE_NISTCURVES_ONCHIP=1 47,105 B
make BACKEND=uci USE_NISTCURVES_ONCHIP=1 62,977 B
make BACKEND=uci USE_NISTCURVES_ONCHIP_COMB=1 62,977 B
ECDSA KAT 6/6 (incl. 3 negative CAVP vectors)

🤖 Generated with Claude Code

Both onchip variants — half the release matrix — failed to link at the
v0.9.1 pin:
ld65: Error: src/lib_contract_asserts.s(166): libs/nistcurves
shared-primitive ownership claim moved
Root cause (od65 on the two archives we build): REU reports
SHARED_PRIMITIVES = $0007, onchip reports $0005. That is the reu_mul bit
correctly leaving both masks under -D FP_ONCHIP_MUL, which upstream's
CHANGELOG documents for that row — the profile has no REU multiply path,
so owning nothing there is right. The assert hardcoded $0007, a value
measured at v0.6.0 when both profiles still agreed; the masks split
upstream since.
The expectation is now derived per profile. The assert is NOT weakened:
both branches verified by negative control — feeding onchip the old
$0007 fails the onchip link, and feeding REU $0001 fails the REU link.
Also rewrites the error text, which sent the reader to re-derive archive
member drops in build_nistcurves_p256.sh. That is the wrong remedy here
(nothing about the surgery changed) and it cost real time. It now names
the profile split, gives both expected values, and says to re-derive the
wrapper only if which primitives SHIP has changed.
Verified from clean, all five build configurations:
make 47,105 B
make BACKEND=uci 62,977 B
make USE_NISTCURVES_ONCHIP=1 47,105 B
make BACKEND=uci USE_NISTCURVES_ONCHIP=1 62,977 B
make BACKEND=uci USE_NISTCURVES_ONCHIP_COMB=1 62,977 B
ECDSA KAT 6/6 including the three negative CAVP vectors.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@JC-000

Copy link
Copy Markdown
OwnerAuthor

Closing in favour of #99, which fixes the same defect better.

Both derive the §8.0 expectation per profile. #99 is preferable on two counts:

  1. Per-arm messages. Mine emitted one combined message covering both profiles; fix(contract): SHARED_PRIMITIVES is profile-dependent — unblock both onchip variants #99 gives each arm its own, naming the profile, its expected value, and whichlib_manifest to read. The reader sees guidance for the build they are actually running rather than having to work out which half applies — which matters given the original message's misdirection is what cost an afternoon.

  2. It verified the archive member drops rather than assuming them. I asserted the surgery was unaffected; fix(contract): SHARED_PRIMITIVES is profile-dependent — unblock both onchip variants #99 measured it — provider tables from the link maps showing every §8 primitive body comes from c64-https, the ct_mul_8x8 deferral working as designed, and od65 --dump-imports proving the duplicate reu_fetch_mul_row under onchip is imported by nobody, so the two definitions never compete. That closes the one silent-win candidate, and it is why fix(contract): SHARED_PRIMITIVES is profile-dependent — unblock both onchip variants #99's comment can state the drops need no re-derivation as a measurement rather than a hope.

#99 also traces the split to upstream v0.8.0 (c64-nist-curves#78) rather than v0.9.x, and confirms make package completes 4/4 — the gate the release actually needs.

No code from this PR is lost; #99 supersedes it entirely.

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@JC-000