Skip to content

fix: hold string claims and exp to REQ-COMMON-19 / REQ-COMMON-19D - #3

Merged
xgreenx merged 1 commit into
feat/ceremony-circuitsfrom
fix/jwt-email-req-common-19-19d
Aug 21, 2026
Merged

xgreenx merged 1 commit into
feat/ceremony-circuitsfrom
fix/jwt-email-req-common-19-19d

Conversation

@xgreenx

@xgreenx xgreenx commented Aug 21, 2026

Copy link
Copy Markdown
Contributor

Closes out the two findings from the review of #1 — both pre-existing on
main, both defense-in-depth misses in circuits/jwt_email/src/main.nr.
Targets the feat/ceremony-circuits branch so it lands as part of #1's
history; the branch is #1's head plus this one commit.

REQ-COMMON-19 — trailing structural byte on string claims

The spec requires the circuit to "assert the full "field":" delimiter at
that offset, the value bytes, the closing quote, and the following
structural byte
fixed by the profile". Only email_verified and exp
asserted their trailing byte; the five string claims — email, nonce,
sub, iss, aud — stopped at the closing quote, so a claim-shaped
substring inside a longer signed string value would have satisfied the
match, with JSON escaping of attacker-typed content the only thing in the
way.

Every claim now asserts the byte after its match is , or } through one
shared assert_structural() (the two existing inline checks fold into it),
and the section-9 offset bounds each grow by one byte so the trailing byte
itself must sit inside the authenticated payload length per REQ-COMMON-19B —
without that, the new assertion could be satisfied from prover-controlled
zero padding.

REQ-COMMON-19D — canonical exp

The spec pins integers to canonical 0|[1-9][0-9]* and explicitly lists
leading-zero among the rejects. The digit-run check accepted any digits, so
"exp":0123… was a second signed encoding of the same u64. A multi-digit
exp may no longer begin with '0'; the lone "0" remains legal.

Tests

Four new tests (jwt_email 3 → 7, repo 24 → 28): a claim-shaped substring
whose apparent closing quote is followed by ordinary string content fails
with the new assertion after passing every pre-existing check, and a
leading-zero exp fails; companion positive tests pin , / }
continuations and the two canonical exp shapes (ten-digit timestamp,
lone "0").

Artifact impact (pinned toolchain: nargo 1.0.0-beta.20, bb 5.0.0-nightly.20260324)

before (#1 head) after
jwt_email gates 179,367 179,413 (+46, 0.03 %)
jwt_email vk_hash 0x24db903f…88a5a69f 0x1596b429…2af7a27c
bearer-link / dyaka-noir-token unchanged byte-identical

The README's recorded jwt_email vk_hash is updated accordingly (the
2026-08-12 reproducibility note now dates its hash and records the current
one), and the stale "jwt_email has no tests" comment in ci.yml is corrected.
nargo fmt --check, nargo test (28/28) and scripts/build.sh all pass
locally under the pinned toolchain.

🤖 Generated with Claude Code

Two spec-compliance gaps found in review of #1, both pre-existing on main.

REQ-COMMON-19 requires a string claim's match to cover the closing quote
AND the following structural byte. Only email_verified and exp asserted
their trailing byte; email, nonce, sub, iss and aud stopped at the closing
quote, so a claim-shaped substring inside a longer signed string value
would have matched -- JSON escaping of attacker-typed content was the only
thing in the way. Every claim now ends at `,` or `}` via one shared
assert_structural(), and the section-9 bounds grow by one byte so the
trailing byte itself must lie inside the authenticated payload length
(REQ-COMMON-19B), not in prover-controlled zero padding.

REQ-COMMON-19D pins integers to canonical 0|[1-9][0-9]* and lists leading
zeros among the rejects; the exp digit-run check accepted them, so a
leading-zero rendering was a second signed encoding of the same u64. A
multi-digit exp may no longer start with '0'; the lone "0" stays legal.

Negative tests cover both: a claim-shaped substring whose apparent closing
quote is followed by ordinary string content now fails, as does a
leading-zero exp; companion positive tests pin the accepted shapes.

The added constraints move jwt_email from 179,367 to 179,413 gates (+46,
0.03 %) and change its vk_hash from 0x24db903f...88a5a69f to
0x1596b429...2af7a27c; the on-chain verifier regenerates with the next
release. bearer-link and dyaka-noir-token artifacts are byte-identical.

Assisted-by: Claude Fable 5
Signed-off-by: xgreenx <xgreenx9999@gmail.com>
@xgreenx
xgreenx merged commit effeb69 into feat/ceremony-circuits Aug 21, 2026
3 checks passed
Sign up for free to 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