Opcode SHL#157
Conversation
icemelon
left a comment
There was a problem hiding this comment.
one high level idea. is it possible to swap the a & b in the SHR and SHL to reuse most part of the constraints? e.g.
SHR: a >> shift = b
SHL: a << shift = b <=> b >> shift = a
Yes. I think it makes sense. Will give a try. Thanks. |
I don't think this is correct. E.g. for |
|
Updated to merge both opcode |
| "overflow == 0 for opcode DIV, MOD and SHR", | ||
| (is_div.clone() + is_mod.clone() + is_shr.clone()) * mul_add_words.overflow(), | ||
| ); | ||
|
|
There was a problem hiding this comment.
I think you're still missing the power of 2 lookup conditions for SHL and SHR?
You can check that pop2 < 256 by checking that the value fits into the first byte with by constraining that RLC(pop2) == pop2.cells[0] btw.
There was a problem hiding this comment.
It seems that there is no need to lookup Pow2 table. Since I calculated divisor = 1 << shf0 (if shf0 < 256) in function assign_exec_step directly (not sperated to low and high bytes). What do you think?
And I added another contraint to check pop1 == pop1.cells[0] for opcode SHL and SHR. Thanks.
cb.require_zero(
"pop1 == pop1.cells[0] when divisor != 0 for opcode SHL and SHR",
(is_shl.clone() + is_shr.clone())
* (1.expr() - divisor_is_zero.expr())
* (pop1.expr() - pop1.cells[0].expr()),
);
There was a problem hiding this comment.
we definately need to add the lookup constraint here.
My model is that configure adds the constraints for the circuit and assign_exec_step generates a witness that satisfies those constraints. If you don't have enough constraints, then there can be multiple witnesses that satisfy them. In this case, without the lookup constraint, replacing line 177 with 5.expr() or many other expressions could still allow the constraints to all be satisfied.
and sperate the word array to `quotient`, `divisor`, `remiander` and
`dividend`.
| "overflow == 0 for opcode DIV, MOD and SHR", | ||
| (is_div.clone() + is_mod.clone() + is_shr.clone()) * mul_add_words.overflow(), | ||
| ); | ||
|
|
There was a problem hiding this comment.
we definately need to add the lookup constraint here.
My model is that configure adds the constraints for the circuit and assign_exec_step generates a witness that satisfies those constraints. If you don't have enough constraints, then there can be multiple witnesses that satisfy them. In this case, without the lookup constraint, replacing line 177 with 5.expr() or many other expressions could still allow the constraints to all be satisfied.
|
Hi @z2trillion , according to code review, I sperated And I added two constraints to lookup Could you help review the code again? Thanks a lot. |
| pop1: util::Word<F>, | ||
| /// For opcode SHL and SHR, it is `shift[0]` if `shift[0]` is less than 128, | ||
| /// and 0 otherwise. | ||
| shf_lo: Cell<F>, |
There was a problem hiding this comment.
Lookups can have up to three values in them:
pub(crate) enum Lookup<F> {
/// Lookup to fixed table, which contains serveral pre-built tables such as
/// range tables or bitwise tables.
Fixed {
/// Tag to specify which table to lookup.
tag: Expression<F>,
/// Values that must satisfy the pre-built relationship.
values: [Expression<F>; 3],
},
...
I think a more direct (and easier to understand) approach would be to have
values = [
input,
if input < 128 {1 << input} else {0},
if input < 128 {0} else {1 << (input -128)}
]
You can then directly lookup up shift_hi and shift_lo without needing to use the divisor_lo_is_zero and divisor_hi_is_zero gadgets.
There was a problem hiding this comment.
Updated Pow2 table and fixed to lookup (shf0, divisor_lo, divisor_hi) in this table.
Hi @z2trillion , please have review again when you have time. Thanks.
|
Thanks for code review. Moved to upstream privacy-ethereum#578. |
Spec: scroll-tech/zkevm-specs#43
Summary
Integrate both opcode
SHLandSHRintomul_div_mod(rename tomul_div_mod_shl_shr).Consider
SHLasMUL(a * (1 << shift) = b) andSHRasDIV(a // (1 << shift) = b).