@@ -291,12 +291,14 @@ Both moduli (`p` and `n`) are prime, so any nonzero element has a *unique* inver
291291 most cause a revert (wasted gas), never a false accept. (A non-canonical hint such
292292 as ` inv + m ` also passes the check and is harmless, since every use reduces mod ` m ` .)
293293
294- The equivalence anchor for this argument is that with hints ** disabled** the code is
295- identical to the upstream verifier; the hinted branches only * substitute a
296- pre-verified value* for the same inverse the original computes.
294+ The equivalence anchor for this argument is that, aside from rejecting non-canonical
295+ public key coordinates, the hints-disabled code follows the upstream verifier; the
296+ hinted branches only * substitute a pre-verified value* for the same inverse the original
297+ computes.
297298
298299### What a failed verification does
299- - With hints ** disabled** , behavior is identical to the original verifier.
300+ - With hints ** disabled** , behavior is identical to the original verifier except that
301+ non-canonical public key coordinates are rejected.
300302- A * well-formed but invalid* signature consumes its full hint stream and the verify
301303 returns ` false ` normally.
302304- A signature that fails an ** early** guard (scalar bounds or the on-curve check)
@@ -471,17 +473,19 @@ The off-chain↔on-chain hint equivalence is checked under an FFI test (it shell
471473the generator and compares streams byte-for-byte), so the generator and the contract
472474can never silently diverge.
473475
474- ** For auditors.** The entire trust delta versus the upstream library is the two
475- ` if (hintsEnabled) ` branches shown in the appendix; the soundness argument is in §4
476- (* Why this is sound* ). Reviewers should confirm:
476+ ** For auditors.** The main trust delta versus the upstream library is the two
477+ ` if (hintsEnabled) ` branches shown in the appendix; this repo also tightens public-key
478+ coordinate bounds to reject non-canonical field encodings. The hinting soundness
479+ argument is in §4 (* Why this is sound* ). Reviewers should confirm:
477480
4784811 . every supplied inverse is constrained by ` b · inv ≡ 1 ` in the correct modulus
479482 ** before** it is used;
4804832 . point inverses use the field prime ` p ` and scalar inverses use the group order ` n ` ,
481484 with no crossover;
4824853 . the underflow and surplus guards together force the hint count to match exactly
483486 (no truncated or leftover hints);
484- 4 . the hints-disabled path is byte-identical to the upstream verifier; and
487+ 4 . the hints-disabled path differs from upstream only by the stricter public-key
488+ coordinate bounds; and
4854895 . the curve parameters (` p ` , ` n ` , ` G ` , ` a ` , ` b ` , low-` s ` bound) are correct.
486490
487491## 10. Caveats and notes
@@ -494,9 +498,10 @@ can never silently diverge.
494498 ` x_R mod n == r ` , exactly as the upstream library, including its handling of the
495499 negligible (~ 2⁻¹⁹⁰) case where the recovered x-coordinate lies in ` [n, p) ` . Hinting
496500 does not alter this.
497- - ** Audit boundary.** Only the two inversion branches are new cryptographic code; the
498- rest of the verifier is the upstream library unchanged, and the certificate parser,
499- cache, and CBOR/COSE handling are the pre-existing validator logic.
501+ - ** Audit boundary.** The hinted inversion branches are the primary new cryptographic
502+ code; this repo also tightens public-key coordinate bounds versus upstream. The
503+ certificate parser, cache, and CBOR/COSE handling are the pre-existing validator
504+ logic.
500505- ** The generator is liveness-critical, not trust-critical.** A bug in the off-chain
501506 hint generator can only cause a revert (every value is re-checked on-chain), never a
502507 false accept — but correct hints are required to verify at all, so the generator
@@ -551,12 +556,11 @@ The hinted verifier is the upstream `ECDSA384` verifier from
551556` dl-solarity/solidity-lib ` , vendored into this repo at ` src/vendor/ECDSA384.sol ` (see
552557` src/vendor/README.md ` for provenance and the exact upstream diff in
553558` src/vendor/ECDSA384.hinted.patch ` ) with ** one operation — modular inversion — made
554- hint-aware in two places** . Everything else (the Strauss–Shamir ladder, precompute
555- table, on-curve check, scalar bounds, final ` x_R == r ` ) is unchanged. When hints are
556- disabled the code follows the original path, so the unhinted path is the equivalence
557- anchor.
559+ hint-aware in two places** , plus stricter public-key coordinate bounds. Everything else
560+ (the Strauss–Shamir ladder, precompute table, scalar bounds, final ` x_R == r ` ) is
561+ unchanged.
558562
559- The entire trust delta is these two ` if (hintsEnabled) ` branches.
563+ The hinting trust delta is these two ` if (hintsEnabled) ` branches.
560564
561565** Point arithmetic — inverses mod ` p ` ** (` moddivAssign ` ):
562566
@@ -613,12 +617,15 @@ no-truncation guard:
613617+ }
614618```
615619
620+ The public-key on-curve guard is also tightened to reject non-canonical coordinates
621+ ` >= p ` , not only coordinates equal to ` p ` .
622+
616623The remaining changes are ** plumbing** , not logic, and none can affect the
617624accept/reject decision:
618625
619626- a few words of scratch memory holding the hint stream pointer, length, cursor, and
620627 an enabled flag (` initCall ` / ` initCallWithHints ` );
621- - the ` verify ` entrypoint split into ` verify ` (no hints, identical to the original )
628+ - the ` verify ` entrypoint split into ` verify ` (no hints)
622629 and ` verifyWithHints ` , which adds the surplus guard
623630 ` require(consumed == length, "unused inverse hints") ` .
624631
0 commit comments