-
Notifications
You must be signed in to change notification settings - Fork 149
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Fix tests panic in debug #764
Conversation
Codecov Report
Additional details and impacted files@@ Coverage Diff @@
## master #764 +/- ##
==========================================
+ Coverage 85.05% 85.07% +0.01%
==========================================
Files 57 57
Lines 4363 4327 -36
==========================================
- Hits 3711 3681 -30
+ Misses 652 646 -6
... and 3 files with indirect coverage changes Continue to review full report in Codecov by Sentry.
|
84a1163
to
773d1fd
Compare
773d1fd
to
280837b
Compare
By repeatedly running the setup, the public parametesr where unnecessarily recreated which slowed down the tests.
280837b
to
8a35ca3
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good overall! A comment regarding the correct change on enforcing range checks of even values
src/composer.rs
Outdated
@@ -129,7 +129,7 @@ pub trait Composer: Sized + Index<Witness, Output = BlsScalar> { | |||
) -> Witness { | |||
// the bits are iterated as chunks of two; hence, we require an even | |||
// number | |||
debug_assert_eq!(num_bits & 1, 0); | |||
assert_eq!(num_bits & 1, 0, "number of bits must be even"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not sure if it makes sense to add production panic to check circuit development consistency. I'd rather keep it as debug_assert_eq
and have tests checking for such case
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I agree that it's weird to deliberately panic in production, but I think in this case it makes sense since the alternative would be that the circuit would produce an incorrect proof. The other alternative I see is to return an error but that means changing the function signature.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have the same feeling on panicking like this, but more because it signals that we should be erroring rather than panicking. The library should validate user input against what it expects.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There is an important distinction tho: the validation is static and should be performed at compilation time.
Meaning: when we create a circuit implementation, we create it for a static type (i.e. impl Circuit for Foo
). It means it could be a waste to move such check to runtime (i.e. make the function fallible & Err
).
If we move everything to static time, then it probably makes more sense. In short: if the function receives a constant, we can just assert
it and it would fail at compile time if the user attempts to create a circuit with wrong bits boundaries:
fn append_logic_component<BITS: usize>(
&mut self,
a: Witness,
b: Witness,
is_component_xor: bool,
) -> Witness {
assert_eq!(BITS & 1, 0, "some msg");
The code above will not compile for invalid bits.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In fact, the problem above probably applies elsewhere. We should probably use more static stuff for other components instead of running test checks. Probably is_component_xor
should also be a constant.
TLDR; components should receive only witnesses as arguments. Everything else is a constant
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I pushed a version with the range and logic components erroring on uneven bits.
But generally I think we all agree that the circuit description should not depend on the circuit struct input. This is in line with our earlier discussion of remodeling the Circuit
trait in general.
For now though I think throwing an error at compilation time when the bits are uneven seems like a good solution to me.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We can also circumvent any misuse if we let the user pass the amount of bit-pairs instead of bits. In the components themselves we multiply the bit-pairs by 2 and can therefore always be sure the total amount of bits is dividable by two.
It would be more cognitive overhead on the circuit creator but would make sure the components can not be misused without the need to panic or error
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I did an attempt on my above proposal combined with @vlopes11 suggestion of making the logic and range components generic over the bit (bit-halves in this case).
@vlopes11 and @ureeves please check it out under the branch: mocello/763_fix_debug_panic_bit_pairs and let me know whether you like that one or the latest changes on this branch more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I very much like the direction of "making illegal state unrepresentable". Comes with tons of benefits. I vote for the bit_pairs
branch that you suggested.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I also like the solution with the BIT_PAIRS
most.
Pushed to the branch, please have a final look and approve (if you approve that is ;) )
a56c77e
to
5eae14a
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The instinct to want to actually panic on this makes sense, but I think it makes more sense to error in this situation. Here's the book on when to panic.
I'm open to being persuaded otherwise though.
src/composer.rs
Outdated
@@ -129,7 +129,7 @@ pub trait Composer: Sized + Index<Witness, Output = BlsScalar> { | |||
) -> Witness { | |||
// the bits are iterated as chunks of two; hence, we require an even | |||
// number | |||
debug_assert_eq!(num_bits & 1, 0); | |||
assert_eq!(num_bits & 1, 0, "number of bits must be even"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have the same feeling on panicking like this, but more because it signals that we should be erroring rather than panicking. The library should validate user input against what it expects.
61c0470
to
3cf75ca
Compare
With the introduction of the const generic `BIT_PAIRS` it is now impossible for the user to create an invalid circuit and removes the need to panic or error.
3cf75ca
to
0721229
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
@@ -50,8 +50,10 @@ impl Circuit for TestCircuit { | |||
composer.append_gate(constraint); | |||
|
|||
// Check that a and b are in range | |||
composer.component_range(a, 6); | |||
composer.component_range(b, 5); | |||
const HALF_SIX: usize = 3; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
what's the reason for that?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The range (and logic) component is now generic over a constant BIT_PAIRS
. This was done so that the user has no way to construct an invalid circuit (internally we group the bits in pairs which made circuits over an uneven number of bits invalid).
In the case of the above example, we chose 3
for the generic BIT_PAIRS
, which will result in a circuit that checks whether the witness is encoded in 6 bits or less.
To make that connection between 3 and 6 clear I chose the name HALF_SIX
.
Resolves: #763