Skip to content
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

Implement BYTE opcode + Code reuse utilities #106

Merged
merged 7 commits into from
Oct 11, 2021

Conversation

Brechtpd
Copy link
Collaborator

@Brechtpd Brechtpd commented Sep 30, 2021

Spec: privacy-scaling-explorations/zkevm-specs#46

Also contains a couple of helper classes and utilities to more easily reuse frequently used code which should also improve readability. Currently these are only used for the BYTE opcode implementation because I'm not sure if people will like this, so let me know what you think.

@Brechtpd Brechtpd changed the title Implement BYTE opcode Implement BYTE opcode + Code reuse utilities Oct 1, 2021
@github-actions github-actions bot added the crate-zkevm-circuits Issues related to the zkevm-circuits workspace member label Oct 4, 2021
@spartucus
Copy link
Contributor

Love this code reuse utilities PR.

Copy link
Collaborator

@ChihChengLiang ChihChengLiang left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM!
The ConstraintBuilder is a life saver! I like it so much! It makes the circuit code so readable and auditable.

Copy link
Collaborator

@miha-stopar miha-stopar left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Really nice work! I like the utilities too! I would only perhaps slightly modify the tests to have the variables which are then passed into ExecutionSteps and Operations (because now changing the value to be tested requires changes in multiple places).

Copy link
Collaborator

@han0110 han0110 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM! Nice work!

Only got one concern about the require_in_set, which might use degree up to set.len(), I am thinking maybe we would like to use lookup with some prebuilt tables for those who has too large set.len() like responsible opcodes, constant gas cost and stack overflow/underflow range.

Would it possible to set some max_degree on ConstraintBuilder to panic when the function makes the degree too high?

@github-actions github-actions bot added the T-opcode Type: opcode-related and focused PR/Issue label Oct 8, 2021
@Brechtpd
Copy link
Collaborator Author

Brechtpd commented Oct 8, 2021

Really nice work! I like the utilities too! I would only perhaps slightly modify the tests to have the variables which are then passed into ExecutionSteps and Operations (because now changing the value to be tested requires changes in multiple places).

I kind of neglected the tests because I hoped to be able to use the tracer test tool for that, but yeah doesn't seem that will be very soon so should have put in a bit more time there regardless. I have updated the test code.

Would it possible to set some max_degree on ConstraintBuilder to panic when the function makes the degree too high?

I have added a check on the set length, because I think that was kind of the main idea of the check. But I wonder how useful that check really is. The expressions that are passed in could be a higher degree already so perhaps better to add a check on the degree of the final expression that is built? Although even that may not really work as expected always because a high degree expression could be passed in as a single element set, which I guess would be a valid use of the function as it could not be done more efficiently with a lookup directly? What do you think?

@han0110
Copy link
Collaborator

han0110 commented Oct 8, 2021

The expressions that are passed in could be a higher degree already so perhaps better to add a check on the degree of the final expression that is built

Ah right, but actually we can peek Expression's degree by its function degree, so maybe we should assert it is less than max_degree in add_expression or some internal function. Then with panic trace we still know which line of code leads to degree too high.

Although even that may not really work as expected always because a high degree expression could be passed in as a single element set, which I guess would be a valid use of the function as it could not be done more efficiently with a lookup directly?

We would definitely want a max_degree on all expressions in the end, cause once the degree exceed next power of 2, then the circuit's capacity also halved. If some verification just requires such high degree, we could probably just add some extra intermediate witness to make it fit in the max_degree. So ConstraintBuilder should always guard the max_degree in my opinion.

@Brechtpd
Copy link
Collaborator Author

Brechtpd commented Oct 9, 2021

The expressions that are passed in could be a higher degree already so perhaps better to add a check on the degree of the final expression that is built

Ah right, but actually we can peek Expression's degree by its function degree, so maybe we should assert it is less than max_degree in add_expression or some internal function. Then with panic trace we still know which line of code leads to degree too high.

Should we do < max_degree or <= max_degree? I did <= max_degree because for some reason that makes more sense to me but I don't know why so let me know what makes the most sense to you. :)

We would definitely want a max_degree on all expressions in the end, cause once the degree exceed next power of 2, then the circuit's capacity also halved. If some verification just requires such high degree, we could probably just add some extra intermediate witness to make it fit in the max_degree. So ConstraintBuilder should always guard the max_degree in my opinion.

I'm assuming we should also guard the degree of expressions used in lookups in the same way? Added those checks but not sure if needed (or these may even need a bit stricter requirements because they may increase in degree in the end, I don't really know how these actually end up being used).

@han0110
Copy link
Collaborator

han0110 commented Oct 9, 2021

<= max_degree makes sense to me :)

I'm assuming we should also guard the degree of expressions used in lookups in the same way.

For sure, cause the lookup currently is composed in a strange way, which might have a high degree of input. I think we probably want a simpler lookup in the future... For example a selector with some advice columns, and when one wants to enable the lookup, it constrain the input in these columns, and also the selector to be enabled. It seems a more reasonable way to construct lookup (we make use of it on much more rows), and then we don't need to worry about lookup's degree anymore.

Regarding to lookup's degree, it also has a required_degree depends on input and table. So if to check lookup's degree, it would be like assert!(expr.degree() + 3 <= self.max_degree) if we assume table has max degree 1 (we might gain extra 1 degree if we disable the zk feature).

BTW, IIUC all of gate or arguments' required degree would be subtracted by one due to divide_by_vanishing_poly, so our DEFAULT_MAX_DEGREE could be 2**n + 1 like 9.

@Brechtpd
Copy link
Collaborator Author

Brechtpd commented Oct 9, 2021

Alright, thanks for the info and help! I think I have added these checks correctly now.

Comment on lines 277 to 290
// More extensive tests (which takes a long time to run, so disabled by default)
/*let test_value =
BigUint::from_bytes_be(&(1u8..33u8).collect::<Vec<u8>>()[..]);
for idx in 0u64..33 {
check_byte_gadget(
test_value.clone(),
idx.into(),
if idx < 32 {
(idx + 1).into()
} else {
0u64.into()
},
);
}*/
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Instead of leaving dead codes here, can we create an issue and put this code snippet there?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Marked the exhaustive test as ignored so it doesn't run by default, but all ignored tests can be run when doing cargo test -- --ignored. Does that sound good to you? No more dead code and the test code is still nicely available next to the other code, and all future slow tests can do the same so there's just one command that can be run to all test these as well.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Brechtpd Yes, that sounds great!

@ChihChengLiang
Copy link
Collaborator

Great work @Brechtpd! I also checked with @miha-stopar and @han0110, they are all good with the updates on feedbacks.

@ChihChengLiang ChihChengLiang merged commit d5a1445 into privacy-scaling-explorations:main Oct 11, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
crate-zkevm-circuits Issues related to the zkevm-circuits workspace member T-opcode Type: opcode-related and focused PR/Issue
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

5 participants