Skip to content

chore(libs): nistcurves v0.9.1 -> v0.10.1, x25519 v0.10.0 -> v0.11.0 (lib-contract phase-3 wave) - #113

Merged
JC-000 merged 2 commits into
masterfrom
chore/wave-tag-bump
Aug 15, 2026
Merged

chore(libs): nistcurves v0.9.1 -> v0.10.1, x25519 v0.10.0 -> v0.11.0 (lib-contract phase-3 wave)#113
JC-000 merged 2 commits into
masterfrom
chore/wave-tag-bump

Conversation

@JC-000

Copy link
Copy Markdown
Owner

Closes#112.

submodulewasnow
libs/nistcurvesv0.9.1 f9701e1v0.10.11edd634
libs/x25519v0.10.0 68ae0efv0.11.0e9af04e

v0.10.0 of nistcurves was skipped as the issue instructs — it ships content
self-reporting as 0.10.1 and is documented-as-superseded.

Both REU-profile PRGs are byte-identical across the bump. For the shipped
default this is a pure export-surface change. Getting there needed four
consumer-side migrations, and one of them fails silently.


The four migrations

1. -D zp_ptr2=$3d-D nistcurves_zp_ptr2=$3d
(tools/integration/build_nistcurves_p256.sh)

The §6.5 window made the four general-purpose scratch slots canonically
nistcurves_zp_{tmp1,tmp2,ptr1,ptr2} and kept the bare names as aliases — but
the alias assignment is not .ifndef-guarded:

.ifndef nistcurves_zp_ptr2 nistcurves_zp_ptr2 =$fd.endifzp_ptr2 = nistcurves_zp_ptr2 ; <- not guarded

so the old spelling stopped being an override and became
zp_config.s(56): Error: Symbol 'zp_ptr2' is already defined. Loud, for once —
this class of mistake is normally runtime memory corruption several layers from
its cause. The od65 post-check was retargeted to the canonical name, because the
bare one disappears under -D LIB_NO_BARE_EXPORTS=1 and a guard that can go
vacuous under a build-tightening flag is worse than no guard.

2. LIB_ABI_VERSION 1 → 2 (src/lib_contract_asserts.s)

The assert fired as designed. The re-check it demands is now written into the
file so the next person can audit the audit instead of repeating it. Method:
git diff v0.9.1 v0.10.1 -- src/ filtered to export lines, intersected with
every import of c64-https's own objects (od65 over build/*.o,
build/crypto/**, build/net/**, excluding build/lib staging).

Removed unconditionally: LIB_SHARED_REU_MUL_{BANK,OFFSET,BANKS_USED} — the
three unprefixed §8.2 consumer-input equates. c64-https imports zero of
them, and could not usefully have: every §8.2 consumer defines the same three,
which is exactly why exporting them produced Duplicate external identifier in
any two-library link. Everything else in the wave is additive at the default
gate. The surface we actually consume is unchanged at four symbols: ec_base_x,
ec_gx256, ec_scalar_mul_var, ecdsa_verify_256.

3. Four §6.5 canonical aliases (src/crypto/shared/mul_tables.s)

The library's objects now reference nistcurves_mul_{dma_lo,dma_hi,cached_a,src2_buf}.
Upstream keeps the bare spellings as aliases insidedata_shared.o — which is
precisely the member our wrapper drops, because c64-https owns those buffers.
Without the aliases:

Unresolved external 'nistcurves_mul_cached_a' referenced in:
src/fp256.s(188) ... (likewise _dma_hi, _dma_lo, _src2_buf)

They live in mul_tables.s rather than beside a definition, because src/data.s
declares the buffers only under .ifndef USE_X25519_SIBLING and the sibling's
data module declares them otherwise — importing the bare name binds to whichever
provider the link selected, with no duplication and no gating.

4. poly_prod_lo/hi ownership flip under USE_NISTCURVES_ONCHIP — the one
that fails silently

Upstream moved those two bytes outside the SHARED_CT_MUL_8X8 gate
(contract v0.9.1 adopter-private-buffer rule: fp_sqr's diagonal path writes
them with no ct_mul_8x8 involved). The wrapper's glue TU could no longer
.import them:

mul_8x8.s(223): Error: Symbol 'poly_prod_lo' is already an import

The obvious fix — delete the import — links cleanly and produces wrong
crypto.
og_common does jsr ct_mul_8x8, which under SHARED_CT_MUL_8X8
resolves to our body in poly1305.s, and then reads the product back out of
poly_prod_lo/hi. Writer and reader must address the same two bytes. With two
disjoint pairs, og_common reads two zeros for every product and every
on-chip-generated multiply row is wrong, with no diagnostic anywhere. So
poly1305.s now imports the sibling's pair under that profile instead of
defining its own.

Guarded behaviourally: test_ecdsa_kat_oracle.pyon an onchip build is what
catches it. A REU build does not link mul_8x8_onchip.o at all and passes
regardless — that asymmetry is now recorded in CLAUDE.md.

§8.0 masks re-derived, not carried forward

od65 on the built archives, per profile:

profileSHARED_PRIMITIVESSHARED_CONSUMESREU_BANKS_USED
REU (lib_manifest_p256verify.o)$0007$0007passes & $C0 = 0
onchip (lib_manifest_p256verify_onchip.o)$0005$0005$0000

Both unchanged from v0.9.1, so no assert edit was needed there. No footprint or
RESIDENT_BYTES constant is asserted in this repo, so the issue's per-archive
caveat had nothing to bite.


USE_X25519_SIBLING=1 links under UCI now

README.md and CLAUDE.md both documented this as failing on both backends
with ld65: Error: Duplicate external identifier: 'reu_mul_tables_init'.
Reproduced at the old pins first, then diagnosed:

Both libraries ship a SPEC §8.2 reu_mul provider. Under the sibling flag
src/boot.simportsreu_mul_init (the sibling owns the table), ld65 pulls
nistcurves' reu_mul_init.o to satisfy it because nistcurves-p256.a precedes
x25519.a on the link line, and then the sibling's provider arrives anyway via
reu_clear_wide. Note the near miss: had ld65 resolved rather than errored,
reu_mul_init would have bound to nistcurves' table builder rather than the
sibling's — a different routine writing through a different buffer set.

c64-https is the §8.0 APP_OWNED case for that primitive, so the fix is one
line: drop reu_mul_init.o alongside the mul_8x8.o / data_shared.o drops
already in the wrapper. That is the archive-surgery spelling of
-D SHARED_REU_MUL_INIT, which the wrapper cannot pass because upstream builds
every module with one recipe.

make clean && make BACKEND=uci USE_X25519_SIBLING=1 62,977 B 86889422...
make clean && make USE_X25519_SIBLING=1 # ip65
Segment 'X25519_RODATA' overflows memory area 'CRYPTO_OVERLAY' by 3584 bytes

ip65's failure has moved from a symbol collision to a fit problem: its
overlay slot is 4,212 B against UCI's 7,680 B. That is a cfg restructure, not a
flag.

Proven inert for what ships: both REU PRGs are byte-identical with and without
the drop. The flag stays OFF by default — flipping it is a separate decision
that wants a hardware handshake behind it. README.md and CLAUDE.md are corrected.

tools/test_x25519.py could not run against a sibling build at all

It aborted at FATAL: 'fe_copy' label not found before launching VICE: its nine
fe_* groups drive in-treesrc/crypto/fe25519.s internals, which a sibling
link does not contain. So the sibling had zero runnable coverage — a bad thing to
discover only after deciding to flip a default.

The fe_* requirement is now conditional on the routine family being present.
Detection is by total absence of the family, never one probe label, and
partial presence hard-fails rather than guessing — silently downgrading to two
vectors is how a broken link passes as a green run. (fe_src1/2/dst are ZP
equates present in every link and are excluded from the probe set for that
reason.) The verdict distinguishes the two possible skips, since --fast drops
the only end-to-end coverage while a sibling build keeps it.

The sibling passes both RFC 7748 vectors, including vector 2 — peer u with
bit 255 set, the vector that catches upstream #64.

-D LIB_NO_BARE_EXPORTS=1 (SPEC §6.5) — evaluated, not adopted

Measured rather than argued:

  • It does not touch the symbol that actually collided.
    reu_mul_tables_init is a §8.2 canonical entry point, not a bare manifest
    equate; it is gated by SHARED_REU_MUL_INIT alone.
  • Adopting it would break the onchip profile: mul_8x8.s:64 gates the
    sqtab_lo/sqtab_hi exports behind it, and src/crypto/poly1305.s:14
    imports both. It would also force the ABI import to the prefixed name.

Cost real, benefit zero at this pin. Recorded rather than done.

CONTRACT_DEFINES / CONTRACT_ZP_DEFINES

The risk the issue names is absent here: we do not patch library makefiles.
The wrapper rebuilds zp_config_*.o post-hoc with the overrides and od65-verifies
the emitted values.

v0.10.x's CONTRACT_ZP_DEFINES does now reach the per-variant zp_config rules
(libs/nistcurves/Makefile:296), and would let the rebuild + member-discovery +
variant-gate case block collapse to one make flag. Deliberately not folded in
here
: it replaces the mechanism on the highest-consequence path in the wrapper,
the current one is measured-good, and this PR already carries four migrations.
Worth a follow-up issue.


Evidence

All at these pins, make clean between every one.

$ make clean && make # ip65
d522e68469b8fc09709f34e64fd5573a0a72465349374a26257194bd5ed96cca 47105
$ make clean && make BACKEND=uci
66e37037deb9b295d3594a50b2bacfe95d09bb7e62f3dfc401c51b03c2461fed 62977
$ make clean && make USE_NISTCURVES_ONCHIP=1
b181ec0862c2680e1ac59717a4e474d31c04d7f885d01c13f8304e7762e742a6 47105
$ make clean && make BACKEND=uci USE_NISTCURVES_ONCHIP=1
118241e975563a26d9ca69a8bc8607d7d0ec2ae259fa7f7d3e1744c0b6f13df9 62977
$ make clean && make BACKEND=uci USE_NISTCURVES_ONCHIP_COMB=1
211ad1bd841b65f473d5cbf18860c4097f14254a51ed3edb465372df202a075d 62977

PRG hashes, old pins vs new

buildbytesv0.9.1 / v0.10.0v0.10.1 / v0.11.0
ip65 REU47,105d522e684…d522e684…identical
uci REU62,97766e37037…66e37037…identical
ip65 onchip47,10513268587…b181ec08…moved
uci onchip62,977518ee446…118241e9…moved
uci onchip+comb62,97729828653…211ad1bd…moved

Old-pin figures were measured in this worktree by reverting the submodules and
stashing the source changes, not quoted from memory. The onchip rows move only
because migration 4 relocated two bytes out of CRYPTO_BSS. The released
v0.2.0 artifacts were built at the old pins, so those PRG hashes are superseded

— whether to cut a follow-up release is the supervisor's call, not mine.

Tests

$ python3 tools/test_ecdsa_kat_oracle.py # UCI REU
Passed: 6/6 [+] ALL 6 VECTORS PASSED (3 valid accepted, 3 invalid rejected)
$ python3 tools/test_ecdsa_kat_oracle.py # UCI ONCHIP — migration 4
Passed: 6/6 [+] ALL 6 VECTORS PASSED (3 valid accepted, 3 invalid rejected)
$ python3 tools/test_x509.py
Passed: 11/11 [+] X.509/ECDSA: ALL 11 TESTS PASSED
$ python3 tools/test_x25519.py # UCI REU, in-tree
RESULTS: 73/73 passed, 0/73 failed
$ python3 tools/test_x25519.py # UCI ONCHIP
RESULTS: 73/73 passed, 0/73 failed
$ python3 tools/test_x25519.py # UCI + USE_X25519_SIBLING=1
RESULTS: 12/12 passed, 0/12 failed -- 9 group(s) SKIPPED: fe_copy/zero/one,
fe_add, fe_sub, fe_add/sub inverse, fe_mul, fe_sqr, fe_mul_a24, fe_cswap, fe_inv

The in-tree 73/73 was re-run after the test_x25519.py edits — the default
path is unregressed and skips nothing.

Packaging

$ make package PACKAGE_PYTHON=.../.venv/bin/python3
[package] PRG matrix complete (4 variants).
[package] disk images complete. # 6 D64s
[package] wrote dist/c64-https-listener.py # 22130 bytes
[package] wrote dist/MANIFEST.txt

4/4 variants result=OK, no INCOMPLETE block, build-info.txt records
libs/nistcurves … v0.10.1 and libs/x25519 … v0.11.0 with git_dirty=no. Run
twice (once before the commit, once after); every PRG hash reproduced.

make package-verify was not run — it needs VICE boots per D64 on top of a full
rebuild, and every hash it would compare is already double-produced above.

Hardware

No hardware e2e was run. Everything above is VICE and link-time. The
U64E-side questions this bump could plausibly disturb — handshake wall-clock on
the onchip profile, and whether the sibling build completes a real handshake —
are both open and both want the device.

The c64-lib-contract phase-3 namespace wave tags. Closes#112.
Both REU-profile PRGs are byte-identical across the bump
(ip65 47,105 B d522e684..., UCI 62,977 B 66e37037...), so for the
shipped default this is a pure export-surface change. Four consumer-side
migrations were needed to get there, and one of them would have been
silent.
1. ZP override renamed. The §6.5 window made the four general-purpose
scratch slots canonically nistcurves_zp_{tmp1,tmp2,ptr1,ptr2} and left
the bare names as aliases -- but the alias ASSIGNMENT is not
.ifndef-guarded, so `-D zp_ptr2=$3d` stopped overriding and started
erroring (`Symbol 'zp_ptr2' is already defined`). Loud, for once.
The od65 post-check now reads the canonical name, since the bare one
vanishes under -D LIB_NO_BARE_EXPORTS=1 and a guard that can go
vacuous under a build-tightening flag is worse than none.
2. LIB_ABI_VERSION 1 -> 2, with the re-check recorded in the file rather
than just performed. Removed unconditionally: the three bare
LIB_SHARED_REU_MUL_{BANK,OFFSET,BANKS_USED} §8.2 *input* equates.
c64-https imports zero of them (od65 import dump n export dump). The
surface we actually consume is unchanged at four symbols: ec_base_x,
ec_gx256, ec_scalar_mul_var, ecdsa_verify_256.
3. Four §6.5 canonical aliases added in src/crypto/shared/mul_tables.s.
The library's objects now reference nistcurves_mul_{dma_lo,dma_hi,
cached_a,src2_buf}; the bare aliases live in data_shared.o, which our
wrapper drops because c64-https owns those buffers. Without the
aliases: four unresolved externals out of src/fp256.s.
4. poly_prod_lo/hi ownership flips under USE_NISTCURVES_ONCHIP. Upstream
moved them OUTSIDE the SHARED_CT_MUL_8X8 gate (contract v0.9.1
adopter-private-buffer rule), so the wrapper's glue TU can no longer
import them and poly1305.s imports the sibling's pair instead. These
two bytes are a rendezvous: og_common does `jsr ct_mul_8x8` -- our
body -- and reads the product back out of them. Dropping the glue's
import WITHOUT the consumer-side change links cleanly with two
disjoint pairs, and every on-chip-generated multiply row is then
zeros. Guarded behaviourally by test_ecdsa_kat_oracle.py on an onchip
build; the REU build does not link mul_8x8_onchip.o and passes either
way.
§8.0 masks re-derived with od65 on the built archives rather than
carried forward: REU $0007, onchip $0005, both unchanged.
USE_X25519_SIBLING=1 now LINKS under UCI. The
`ld65: Error: Duplicate external identifier: 'reu_mul_tables_init'`
that README.md and CLAUDE.md both documented as unconditional came from
both libraries shipping a SPEC §8.2 reu_mul provider: under the sibling
flag boot.s *imports* reu_mul_init, ld65 pulls nistcurves' member to
satisfy it (its archive precedes x25519.a), and the sibling's provider
arrives anyway via reu_clear_wide. c64-https is the §8.0 APP_OWNED case
for that primitive, so the fix is to drop reu_mul_init.o alongside the
mul_8x8.o / data_shared.o drops already in the wrapper -- inert for the
shipped builds, which stay byte-identical with and without it. ip65 now
fails later and differently: X25519_RODATA overflows CRYPTO_OVERLAY by
3,584 B, a fit problem, not a collision. The flag stays OFF by default.
test_x25519.py could not run against a sibling build at all -- it aborted
at `FATAL: 'fe_copy' label not found` before launching VICE, because its
nine fe_* groups test in-tree fe25519 internals a sibling link does not
contain. The fe_* requirement is now conditional on the routine family
being present, detected by total absence and hard-failing on partial
presence; the RFC 7748 end-to-end vectors run on either build. The
sibling passes both, including vector 2 (peer u with bit 255 set), which
is the vector that catches upstream #64.
Evidence, all at these pins:
make clean && make 47,105 B d522e684
make clean && make BACKEND=uci 62,977 B 66e37037
make clean && make USE_NISTCURVES_ONCHIP=1 47,105 B b181ec08
make clean && make BACKEND=uci USE_NISTCURVES_ONCHIP=1
62,977 B 118241e9
make clean && make BACKEND=uci USE_NISTCURVES_ONCHIP_COMB=1
62,977 B 211ad1bd
test_ecdsa_kat_oracle.py 6/6 (UCI REU) incl. 3 negative CAVP
test_ecdsa_kat_oracle.py 6/6 (UCI onchip)
test_x509.py 11/11
test_x25519.py 73/73 (in-tree), 12/12 + 9 named skips (sibling)
make package 4/4 variants, 6 D64s, listener
No hardware e2e was run.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
… regression
Archaeology from the deferred-followups lane, re-verified here before
landing. #102's 'the sibling links' evidence was honest on its own
branch: at 76d876c the nistcurves pin was still v0.6.0, and the two
bumps were parallel branches neither of which could see the other.
One clause tightened rather than pasted. The contributed wording said
v0.6.0 'does not export reu_mul_tables_init at all'; it does, at
src/main.s:254. What is true — and is the actual mechanism — is that
main.o is excluded from every lib-* archive target, and c64-https links
archives only. Upstream #81 moved the provider into reu_mul_init.s so it
would ship to consumers, which is what put it in our link at v0.9.1. A
claim a reader can disprove with one grep is worse than no claim.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@JC-000
JC-000 merged commit a6cf205 into masterAug 15, 2026
JC-000 added a commit that referenced this pull request Aug 15, 2026
…st measurement
Two deferred follow-ups, both left with reasons recorded by earlier lanes.
PR #111 renamed tests/test_*.py -> tests/rig_*.py because those files wear
pytest's discovery convention while collecting zero tests, so a bare `pytest`
overstates coverage. It explicitly deferred the identical problem in
tools/uci/, whose blast radius runs through CLAUDE.md. This is that change:
six scripts renamed, following #111's precedent exactly.
`norecursedirs` already closed the default-invocation path, but the rename is
what holds from an arbitrary working directory, since `testpaths` only applies
at the rootdir. Both halves are now pinned by the guard rather than one.
tools/test_pytest_boundary.py grows a RIG_DIRS tuple covering both directories
and a new test_norecursedirs_covers_every_rig_dir. Probed in both directions:
a stray tools/uci/test_*.py fails test_rig_dirs_hold_no_pytest_named_files, and
dropping tools/uci from norecursedirs fails the new check. Bare `pytest` is now
31 passed / exit 0; `pytest tests/` and `pytest tools/uci/` both exit 5 with an
explanation naming the right README.
New tools/uci/README.md mirrors tests/README.md. Reference sweep covers
CLAUDE.md, README.md, conftest.py, pytest.ini, tests/README.md, both phase_f
docs, tools/https_e2e/, tools/package/listener/, and the cross-invocations
(rig_https_print_body and rig_https_local_p384 both delegate to
rig_https_local; import-checked after the rename). Zero references exist in
c64-test-harness or any other sibling c64-* repo, and no open issue or PR in
the org names any of the six.
README was audited claim-by-claim in #104; CLAUDE.md never was. Every item
below was confirmed by running a command, not by reading:
- The ip65 blob section contradicted itself and the Makefile. It claimed
`ip65-blob` is phony with "no rule connecting the two" and that a fresh
clone dies at the `.incbin`. Measured: deleting the blob and running plain
`make` rebuilds it byte-identically (6,951 B, cf1a5ff7...) and links the
usual 47,105 B PRG. The real fresh-clone blocker is the missing ip65 .lib
archives, which fail at the blob's ld65 step. `make ip65-blob` is not a
required step. Fixed here and in README.
- "the committed blob" / `touch ip65-build/ip65-c64.bin` advice: the blob is
gitignored, so on a fresh clone there is nothing to touch.
- Fence macro: 17 bytes per site, not 14 (counted from the macro body).
26 sites, not 24 — 11 write + 14 read + 1 pre-loop settle at net.s:199.
- uci_drain_resp/uci_drain_status: 22 call sites in net.s, not 13. All 22
still `bcs` out, so that half was right.
- CIA1 TOD read order is HOUR -> TENTHS; MIN and SEC are never read and have
no equate in uci_cmd.s.
- UCI memory table: NET_CODE is $2000-$3B65 and NET_BSS_TAIL $3B66-$41FF
(cfg grew NET_CODE by $40 for the C64U WiFi iface-fallback loop).
UCI_BSS_REGION is size 0, so quoting a 512 B span contradicted its own
label and overlapped NET_BSS_TAIL.
- src/exports.s no longer exports ip65_init/ip65_process; those moved to
src/net/ip65/exports.s. Named the real backend-agnostic set instead.
- KEEP_DEBUG_ON_PASS is the env var; UCI_DEBUG_KEEP_ON_PASS is only the
Python variable name, so the documented spelling did nothing.
- rig_https_local_p384.py defaults to 90 minutes (5400 s), not 30.
- C64_SKIP_BUILD: 15 scripts, not 14 (ran the recipe the file itself quotes).
- EMBED_P256_OVERLAY's stated mutual exclusions have no $(error) guard: one
is a silent auto-disable, the other is unguarded. Only the
USE_NISTCURVES_ONCHIP exclusions are hard errors.
- "All in-tree VICE-driven tests go through default_vice_config()" is false:
8 suites do, 15 other files still build ViceConfig directly — including
run_all_tests.py, which hand-spells the REU flags.
- Smoke-test list is 8 entries, not 7, and the 97/97 total predates
test_finished_verify.py joining it.
- pytest counts 30 -> 31; src/boot.s:107-114 -> 110-117.
Wall-clock figures are labelled rather than re-measured, per instruction: a
pin-vs-commit table resolves 2ceb5b1 / f0127a0 / cb6eab4 to libs/nistcurves
v0.6.0 (verified with git ls-tree), every table states the pin it was taken
at, and "at HEAD" captions that no longer refer to HEAD are gone. No hardware
was used and no benchmark was re-run.
Deliberately NOT included: the x25519 sibling failure. It is measured and
understood (both backends exit 2 on a duplicate reu_mul_tables_init export,
not the overflow CLAUDE.md records), but PR #113 rewrites the same spans and
fixes the underlying collision, so the prose belongs there. Details handed to
that lane. docs/library-ingestion-architecture.md's two stale references are
owned and taken by the contract lane.
Python and docs only — no .s, no .cfg, no Makefile, so no PRG changes.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
JC-000 added a commit that referenced this pull request Aug 15, 2026
…e and limits
Closes the gap the previous commits left open. I had declined to write in
a v0.9.1 figure because I could not corroborate one from the repo. It
exists -- it lives in the release-prep session's logs rather than in the
tree, which is why no amount of grepping here would have found it. The
coordinator supplied all three points with per-row provenance.
48 MHz UCI, REU profile, U64E at 10.43.23.81, handshake + GET against the
local listener, measured C64-side from run_prg, all PASS with server-side
evidence:
libs/nistcurves c64-side vs v0.6.0
v0.6.0 80.8 s --
v0.9.1 82.1 s +1.6%
v0.10.1 82.4 s +2.0%
Recorded with the two caveats that matter more than the numbers, because
three fresh datapoints in a file full of v0.6.0 tables is exactly the kind
of thing that gets read as a refresh:
- n=1 per row. The +0.4% v0.9.1 -> v0.10.1 step is indistinguishable
from run-to-run variation and is explicitly not presented as a
measured effect.
- This is ONE point of the sweep. Every other clock (1/8/16/20 MHz),
every onchip and comb row, and every ip65 and C64U figure is still
v0.6.0-era. The section header, the U64E sweep table and the
packaging validation record all now say so in place.
The +1.6% at v0.9.1 is consistent in sign and size with the FIPS 186-5
public-key validation gate v0.7.0 added -- an on-curve check on a point
taken from an attacker-supplied certificate, so it is a regression worth
paying rather than one to chase.
Provenance is stated inline (bench/summary.txt, rel_e2e_uci48.log,
e2e_wave.log) together with the fact that those logs are not in this repo,
so a future reader knows the rows are not reproducible from a clean
checkout and should re-run bench_ecdsa_u64e.py to confirm them.
Independent corroboration of the v0.9.1 -> v0.10.1 "no timing change
expected" claim: rebasing onto #113 moved the pins to nistcurves v0.10.1 /
x25519 v0.11.0, and both PRGs hash exactly as they did at v0.9.1 --
ip65 d522e684... (47,105 B), UCI 66e37037... (62,977 B).
Rebased onto merged master (a6cf205). One conflict, in README's
USE_X25519_SIBLING known-issue bullet: resolved in favour of #113's
version, which is measured at the new pins and belongs to that lane.
Pin-vs-commit table extended with the a6cf205 row.
Evidence bar re-run at the new pins, not carried over:
make clean && make -> exit 0, 47,105 B, d522e684...
make clean && make BACKEND=uci -> exit 0, 62,977 B, 66e37037...
python3 tools/test_ecdsa_kat_oracle.py -> 6/6 (3 valid, 3 invalid CAVP)
python3 tools/test_x509.py -> 11/11
Boundary guard and pytest count unchanged by the rebase: 5 checks pass,
bare pytest 31 passed exit 0.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
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.

Bump libs/nistcurves → v0.10.1 and libs/x25519 → v0.11.0: pinned pair carries the lib-contract #82/#83 collisions at tags

1 participant

@JC-000