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 pow-by-constant with NAF for FpVar #72

Open
wants to merge 6 commits into
base: master
Choose a base branch
from

Conversation

weikengchen
Copy link
Member

@weikengchen weikengchen commented Jul 4, 2021

Description

Warning: this PR is more complicated than one may expect.

This PR changes FpVar's implementation of pow_by_constant to a special version that uses NAF.

However, there are several subtle issues.

First, for correctness and soundness,

  1. When base = 0, exp != 0, the result should be zero, and the constraint system should be satisfied. This means that one cannot simply use inverse to compute the inverse of the base, as it may create an unsatisfiable constraint.
  2. When base = 0, exp = 0, there should be panic, and the constraint system is guaranteed to be unsatisfied.

Second, for efficiency,

  1. The NAF, which provides low Hamming weight, does not mean that it is the most efficient one. Since NAF may use "-1", we need to compute the inverse of the base. This, however, is costly, because we need to handle the corner case of "0", which incurs three constraints instead of one constraint for computing the inverse of a non-zero base (which will be unsatisfiable when the base is zero).
  2. NAF can be slightly improved with Add the relaxed NAF algebra#302, though we know that there is still a large space for possible implementations.

closes: #55

Note that currently algebra's pow does not panic when base = 0 and exp = 0, which will be handled in a separate PR.

This PR is associated with four tests.

For review, this PR will need some effort, as it appears to be quite complicated.

If you find any good ideas to simplify the code, please propose. The current code is a little bit longer than expected (due to the handling of soundness in respect to the corner cases).


Before we can merge this PR, please make sure that all the following items have been
checked off. If any of the checklist items are not applicable, please leave them but
write a little note why.

  • Targeted PR against correct branch (master)
  • Linked to Github issue with discussion and accepted design OR have an explanation in the PR that describes this work.
  • Wrote unit tests
  • Updated relevant documentation in the code
  • Added a relevant changelog entry to the Pending section in CHANGELOG.md
  • Re-reviewed Files changed in the Github PR explorer

@weikengchen
Copy link
Member Author

The need to support zero bases for a non-zero exp when using NAF has something to do with Poseidon.

It is very possible for Poseidon to be powering "0" to alpha. If alpha has a NAF form that contains "-1", it should not make the constraint system unsatisfiable, which needs the inverse-or-any gadget in this PR.

@weikengchen
Copy link
Member Author

The zero-base zero-pow issue is also discussed in arkworks-rs/algebra#303. If we decide that 0^0 = 1, then this PR can also be simplified somehow (note, only the beginning part).

use ark_ff::biginteger::arithmetic::find_wnaf;

// first check if exp = 0
let mut is_nonzero = false;
Copy link
Member

Choose a reason for hiding this comment

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

Is this something we can move to a function in utils?

Copy link
Member Author

Choose a reason for hiding this comment

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

This is tricky since that the optimization here is very specific to constraints (e.g., count inversion at a cost of 3 constraints).

Comment on lines +827 to +828
let standard_cost =
standard_be_bits.len() + standard_be_bits.iter().filter(|x| **x == true).count();
Copy link
Member

@ValarDragon ValarDragon Jul 7, 2021

Choose a reason for hiding this comment

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

Does it make sense to make a pow_by_const trait, with two impls, but eventually three, naf, standard, and windowed?

Then we can have four methods, pow, pow_r1cs, pow_native_cost, and pow_r1cs_cost?

Copy link
Member

Choose a reason for hiding this comment

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

Or does that seem like a premature abstraction? If so, I at least recommend splitting out the pow and r1cs_cost into separate functions for code readability & reuse in the future.

Copy link
Member Author

Choose a reason for hiding this comment

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

I got the idea. It seems better to have a separate function that simply returns what is the best sequence, and then this function in fp/mod should just execute it.

I agree and will make the change. Let me think about where to put this function since it is naturally r1cs...

(Note: later it might also be used for group elements)

Copy link
Member Author

Choose a reason for hiding this comment

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

Let me try to split it and will keep you posted.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

More efficient powering by constant
2 participants