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

[ECC chip] Fixed- and variable-base scalar multiplication #111

Merged
merged 40 commits into from
Jul 15, 2021
Merged

Conversation

therealyingtong
Copy link
Contributor

@therealyingtong therealyingtong commented Jun 10, 2021

Closes #38.

Comment on lines 354 to 357
// 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.
Copy link
Contributor Author

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/witness_scalar_fixed/short.rs Outdated Show resolved Hide resolved
Comment on lines 240 to 253
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>,
Copy link
Contributor Author

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 inside C::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 inside C::Base (e.g. if the application curve is Vesta), this API would technically allow non-canonical scalars.

Originally posted by @str4d in #107 (comment)

Copy link
Contributor

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.

src/circuit/gadget/ecc/chip.rs Outdated Show resolved Hide resolved
src/circuit/gadget/ecc/chip/mul.rs Outdated Show resolved Hide resolved
@codecov-commenter
Copy link

codecov-commenter commented Jun 10, 2021

Codecov Report

Merging #111 (425ee6e) into main (21b77d6) will increase coverage by 2.77%.
The diff coverage is 86.95%.

Impacted file tree graph

@@            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     
Impacted Files Coverage Δ
src/spec.rs 97.64% <ø> (ø)
src/circuit/gadget/ecc/chip/mul/overflow.rs 80.17% <80.17%> (ø)
...rcuit/gadget/ecc/chip/mul_fixed/base_field_elem.rs 81.51% <81.51%> (ø)
src/circuit/gadget/sinsemilla.rs 80.00% <83.33%> (-0.54%) ⬇️
src/circuit/gadget/ecc/chip.rs 86.66% <84.28%> (+8.72%) ⬆️
src/circuit/gadget/ecc/chip/mul.rs 84.95% <84.95%> (ø)
src/circuit/gadget/ecc/chip/mul/complete.rs 85.13% <85.13%> (ø)
...gadget/ecc/chip/witness_scalar_fixed/full_width.rs 85.71% <85.71%> (ø)
src/constants/load.rs 82.55% <85.71%> (+82.55%) ⬆️
src/circuit/gadget/ecc/chip/mul_fixed.rs 86.69% <86.69%> (ø)
... and 28 more

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 21b77d6...425ee6e. Read the comment docs.

therealyingtong added a commit that referenced this pull request Jun 11, 2021
@therealyingtong therealyingtong marked this pull request as draft June 11, 2021 22:42
@therealyingtong therealyingtong changed the title [ECC chip] Fixed- and variable-base scalar multiplication [WIP] [ECC chip] Fixed- and variable-base scalar multiplication Jun 11, 2021
therealyingtong added a commit that referenced this pull request Jun 12, 2021
therealyingtong added a commit that referenced this pull request Jun 12, 2021
@therealyingtong therealyingtong force-pushed the ecc-chip branch 2 times, most recently from 5b74277 to 7341996 Compare June 13, 2021 13:28
@str4d str4d mentioned this pull request Jun 13, 2021
@therealyingtong therealyingtong changed the title [WIP] [ECC chip] Fixed- and variable-base scalar multiplication [ECC chip] Fixed- and variable-base scalar multiplication Jun 14, 2021
@therealyingtong therealyingtong changed the base branch from ecc-chip to base-ecc-mul June 14, 2021 11:37
@therealyingtong therealyingtong marked this pull request as ready for review June 14, 2021 11:39
@str4d str4d added this to the Core Sprint 2021-22 milestone Jun 14, 2021
@therealyingtong therealyingtong changed the base branch from base-ecc-mul to main June 14, 2021 17:00
Copy link
Contributor

@str4d str4d left a 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();
Copy link
Contributor

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:
image

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.

Copy link
Contributor

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?

src/circuit/gadget/ecc/chip/mul_fixed.rs Outdated Show resolved Hide resolved
src/circuit/gadget/ecc/chip/mul_fixed.rs Outdated Show resolved Hide resolved
src/circuit/gadget/ecc/chip/mul_fixed.rs Outdated Show resolved Hide resolved
src/circuit/gadget/ecc/chip/mul_fixed.rs Outdated Show resolved Hide resolved
Co-authored-by: Daira Hopwood <daira@jacaranda.org>
Co-authored-by: Jack Grigg <jack@electriccoin.co>
Copy link
Contributor

@str4d str4d left a 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.]

src/circuit/gadget/ecc/chip/mul_fixed/base_field_elem.rs Outdated Show resolved Hide resolved
src/circuit/gadget/ecc/chip/mul_fixed/base_field_elem.rs Outdated Show resolved Hide resolved
src/circuit/gadget/ecc/chip/mul_fixed/base_field_elem.rs Outdated Show resolved Hide resolved
therealyingtong and others added 3 commits July 9, 2021 10:23
…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.
Comment on lines +421 to +427
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
})
Copy link
Contributor

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)]
Copy link
Contributor

@daira daira Jul 14, 2021

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).

Copy link
Contributor

@str4d str4d left a comment

Choose a reason for hiding this comment

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

re-utACK b696163

src/circuit/gadget/ecc/chip/mul.rs Show resolved Hide resolved
mut layouter: impl Layouter<pallas::Base>,
base: FixedPoint<pallas::Affine, EccChip>,
base_val: pallas::Affine,
) -> Result<(), Error> {
Copy link
Contributor

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?

Copy link
Contributor Author

@therealyingtong therealyingtong Jul 15, 2021

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
Copy link
Contributor

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.

Copy link
Contributor Author

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

Copy link
Contributor

@daira daira left a 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>
Copy link
Contributor

@str4d str4d left a 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.

ecc-chip-layout

// 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;
Copy link
Contributor

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.

@str4d str4d dismissed ebfull’s stale review July 15, 2021 10:16

Comments resolved.

@str4d str4d merged commit cc3e1ad into main Jul 15, 2021
@str4d str4d deleted the ecc-mul branch July 15, 2021 10:16
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.

Implement generic ECC gadget
6 participants