-
Notifications
You must be signed in to change notification settings - Fork 39
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
[ECC chip] Fixed- and variable-base scalar multiplication #111
Conversation
src/circuit/gadget/ecc/chip/mul.rs
Outdated
// Cast from base field into scalar field. | ||
// Assumptions: | ||
// - The witnessed scalar field element fits into the base field. | ||
// - The scalar field order is larger than the base field order. |
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.
It would help a bit if we had ways to (statically) assert these kinds of things.
Originally posted by @ebfull in #107 (comment)
src/circuit/gadget/ecc/chip.rs
Outdated
fn witness_scalar_var( | ||
&self, | ||
_layouter: &mut impl Layouter<C::Base>, | ||
_value: Option<C::Base>, | ||
layouter: &mut impl Layouter<C::Base>, | ||
value: Option<C::Base>, |
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 should point out in the docs for EccInstructions::witness_scalar_var
that this API only accepts scalars that fit inside the base field:
- If
C::Base
fits insideC::Scalar
(e.g. if the application curve is Pallas), this API restricts the range of scalars that can be operated on (but all scalars it accepts would be canonical). - If
C::Scalar
fits insideC::Base
(e.g. if the application curve is Vesta), this API would technically allow non-canonical scalars.
Originally posted by @str4d in #107 (comment)
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.
Yes, the correctness argument would need to be re-checked if it were applied to Vesta.
Codecov Report
@@ Coverage Diff @@
## main #111 +/- ##
==========================================
+ Coverage 83.94% 86.71% +2.77%
==========================================
Files 53 64 +11
Lines 4659 6407 +1748
==========================================
+ Hits 3911 5556 +1645
- Misses 748 851 +103
Continue to review full report at Codecov.
|
These will be updated or restored in #111.
These will be updated or restored in #111.
ac2950b
to
4eb2eac
Compare
These will be updated or restored in #111.
5b74277
to
7341996
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.
Found some easy performance wins!
} | ||
OrchardFixedBases::Full(base) => { | ||
assert_eq!(NUM_WINDOWS, constants::NUM_WINDOWS); | ||
let base: OrchardFixedBase = base.into(); |
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.
This .into()
is doing a lot of heavy lifting during proving:
These constants are only used inside assign_fixed
calls, so we should not be computing them at all during proving. I would recommend moving this entire match base
into a closure, and then evaluating the closure the first time we call the || Ok(lagrange_coeffs[window].0[k])
closure below.
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.
Why aren't we building the constants in a lazy_static?
Co-authored-by: Daira Hopwood <daira@jacaranda.org> Co-authored-by: Jack Grigg <jack@electriccoin.co>
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.
utACK ae4e54d. Test circuit LGTM other than the unnecessary double-assignment of base_field_fixed_mul
.
[EDIT: Removed old chip layout as I can't seem to hide review comments. See below for latest.]
…mul. Co-authored-by: Jack Grigg <jack@electriccoin.co>
Previously, we were multiplying the expression by 0, which led it to always evaluate to true.
Verify that this constraint fails when the witnessed value is out of range.
le_bytes.iter().fold(Vec::new(), |mut bitstring, byte| { | ||
let bits = (0..8) | ||
.map(|shift| (byte >> shift) % 2 == 1) | ||
.collect::<Vec<_>>(); | ||
bitstring.extend_from_slice(&bits); | ||
bitstring | ||
}) |
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.
This should probably be a utility function. (Does not block.)
|
||
#[allow(clippy::type_complexity)] | ||
#[allow(non_snake_case)] | ||
#[allow(clippy::too_many_arguments)] |
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.
Opinion: the default threshold of at most 7 arguments to avoid this lint is silly. We should raise that globally (say to 9).
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.
re-utACK b696163
mut layouter: impl Layouter<pallas::Base>, | ||
base: FixedPoint<pallas::Affine, EccChip>, | ||
base_val: pallas::Affine, | ||
) -> Result<(), 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.
Why do these tests seem to be duplicated here and in mul_fixed/full_width.rs
?
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.
They're duplicated because the mul_fixed()
and mul_fixed_base_field_elem()
are both usable with the same set of fixed points. Perhaps we could abstract these tests out?
Edit:
Actually, for the purposes of Orchard, mul_fixed_base_field_elem()
should only ever be used with the NullifierK
base. We should introduce another FixedPointBaseField
enum to separate these two APIs.
I'll do this in #145 (#145 (comment)).
|
||
// There is a single canonical sequence of window values for which a doubling occurs on the last step: | ||
// 1333333333333333333334 in octal. | ||
// [0xB6DB_6DB6_DB6D_B6DC] B |
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.
Test this value with both signs.
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.
Since these tests are refactored in #145, I have noted this comment there and will address it in that PR: https://github.com/zcash/orchard/pull/145/files#r670057072
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.
utACK with minor comments.
Co-authored-by: Daira Hopwood <daira@jacaranda.org>
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.
re-utACK 425ee6e. Test chip LGTM.
// into usize for convenient indexing into `u`-values | ||
fn windows_usize(&self) -> Vec<Option<usize>> { | ||
self.windows_field() | ||
.iter() | ||
.map(|window| { | ||
if let Some(window) = window { | ||
let window = window.to_bytes()[0] as usize; | ||
let window = window.get_lower_32() as usize; |
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.
@daira left a comment inside the get_lower_32()
impls:
// TODO: don't reduce, just hash the Montgomery form. (Requires rebuilding perfect hash table.)
We'll need to take care over there to ensure we don't alter this API, now that we are relying on it outside the perfect hash table.
Closes #38.