Repository navigation
S11: let AliasCheck grant a unique tag, and make Sign require it - #153
Draft
OBrezhniev wants to merge 1 commit into
Draft
OBrezhniev wants to merge 1 commit into
OBrezhniev wants to merge 1 commit into
Conversation
OBrezhniev
force-pushed
the
fix/aliascheck-unique-tag
branch
from
September 29, 2026 18:39
e0b7cb7 to
d73ccf8
Compare
OBrezhniev
force-pushed
the
fix/circomlib_buses_review
branch
from
September 29, 2026 18:39
b85175e to
7198ad7
Compare
Sign() promises 0 when in <= p \ 2, but it computes on bits, and a
maxbits()-bit vector does not determine a field element: for x below
2**maxbits() - p, the bits of x and of x + p both satisfy the linear
constraint of Num2Bits(maxbits())(x). Through test/circuits/sign_test.circom
the bits of 1 gave sign 0 and the bits of 1 + p gave sign 1, so a prover
free to choose the decomposition flipped the sign. The library's own uses
in pointbits.circom were safe only because they run AliasCheck first, a
discipline nothing required.
The tag system could not express the property: AliasCheck was the only
checker with no output, so "these bits are alias free" could not travel
with the signals, and unique existed only on the BinaryNumber bus.
AliasCheck now returns its input tagged {binary, unique}; Num2Bits_strict
routes its bits through the check and grants the same; Sign requires it.
No new constraints anywhere: the check that existed is now also a grant.
Bits2Num_strict keeps its internal check and interface.
Callers of Sign must now alias check, which they must for correctness in
any case. sign_test.circom does; its cases for q and for 2**254 - 1,
which are not field elements, are now rejected instead of returning a
sign, and the bits of 1 + q are rejected rather than read as negative.
The bare AliasCheck()(...) statements in binnum_test.circom become
_ <== AliasCheck()(...) since the template now has an output.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01D1w729xzwemQigkf3PCisD
OBrezhniev
force-pushed
the
fix/aliascheck-unique-tag
branch
from
September 29, 2026 20:08
d73ccf8 to
e6bcc0e
Compare
OBrezhniev
force-pushed
the
fix/circomlib_buses_review
branch
from
September 29, 2026 20:08
7198ad7 to
d5f158d
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Stacked on #149 (
fix/circomlib_buses_review); this PR shows only its own commits. Independent of the other stacked PRs unless stated. Full suite passes on the branch.Signcomputed on bits without an alias check, so the bits of 1 gave sign 0 and the bits of 1+p gave sign 1 for the same field element.AliasCheckwas the only checker with no output, so the property could not be expressed. No new constraints in the library.Let AliasCheck grant a unique tag, and make Sign require it
Sign() promises 0 when in <= p \ 2, but it computes on bits, and a
maxbits()-bit vector does not determine a field element: for x below
2**maxbits() - p, the bits of x and of x + p both satisfy the linear
constraint of Num2Bits(maxbits())(x). Through test/circuits/sign_test.circom
the bits of 1 gave sign 0 and the bits of 1 + p gave sign 1, so a prover
free to choose the decomposition flipped the sign. The library's own uses
in pointbits.circom were safe only because they run AliasCheck first, a
discipline nothing required.
The tag system could not express the property: AliasCheck was the only
checker with no output, so "these bits are alias free" could not travel
with the signals, and unique existed only on the BinaryNumber bus.
AliasCheck now returns its input tagged {binary, unique}; Num2Bits_strict
routes its bits through the check and grants the same; Sign requires it.
No new constraints anywhere: the check that existed is now also a grant.
Bits2Num_strict keeps its internal check and interface.
Callers of Sign must now alias check, which they must for correctness in
any case. sign_test.circom does; its cases for q and for 2**254 - 1,
which are not field elements, are now rejected instead of returning a
sign, and the bits of 1 + q are rejected rather than read as negative.
The bare AliasCheck()(...) statements in binnum_test.circom become
_ <== AliasCheck()(...) since the template now has an output.
🤖 Generated with Claude Code
https://claude.ai/code/session_01D1w729xzwemQigkf3PCisD