-
Notifications
You must be signed in to change notification settings - Fork 856
fix modulo soundness due to overflow #999
fix modulo soundness due to overflow #999
Conversation
1fbec15
to
3c9636d
Compare
b9aeb7a
to
545e7d3
Compare
545e7d3
to
4852883
Compare
4852883
to
c570e50
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.
Great fix. LGTM. I added a nitpick.
@@ -49,27 +49,31 @@ impl<F: Field> ModGadget<F> { | |||
1.expr() - lt.expr() - n_is_zero.expr(), | |||
); | |||
|
|||
// Constrain k * n + r no overflow | |||
cb.add_constraint("overflow == 0 for k * n + r", mul_add_words.overflow()); |
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 do you think use require_zero
here for clarity?
c570e50
to
698ed2b
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.
Added some more comments to help understand the soundness bug.
Word::from(2), | ||
Word::from(3), | ||
Word::from(0), | ||
/* magic number (2^256 + 2) / 3, and 2^256 + 2 divisible by 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.
/* magic number (2^256 + 2) / 3, and 2^256 + 2 divisible by 3 */ | |
/* magic number (2^256 + 2) / 3, and 2^256 + 2 is divisible by 3 */ |
@@ -183,6 +194,20 @@ mod tests { | |||
|
|||
#[test] | |||
fn test_mod_n_unexpected_rem() { | |||
// test soundness by manipulating k to make a' = k * n + r and a' >= | |||
// 2^256 lead to overflow and trigger soundness bug: (a' != a) ^ a' ≡ a | |||
// (mod 2^256) |
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.
// (mod 2^256) | |
// (mod 2^256) | |
// Here, the attacker tries to convince you of a false statement `2 % 3 = 0` by showing you `2 = ((2^256 + 2) / 3) * 3 + 0`. In the `MulAddWordsGadget`, `k * n + r = a (modulo 2**256)` would have been a valid statement. But the gadget would have the overflow=1. Since we constrain the overflow to be 0 in the ModGadget, the statement would be invalid in the ModGadget. |
698ed2b
to
992c216
Compare
* fix soundness bug in ecdsa circuit * update parameters * fix: ec_sub_unequal would have panicked for some edge cases (privacy-scaling-explorations#999) * update ecdsa parameters --------- Co-authored-by: Rohit Narurkar <[email protected]>
Fix issue #996
Changes summary
ModGadget
k
so it's able to be unit-test. With k exposing, therefore also move witness generation logic outside.MulModGadget
, op implementationk
tok2
, plus addingk1
, also passingk1
forModGadget
to constrain.MulAddWordsGadget
saturating_sub
to avoid underflow panic during carry calculation.