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

Refactor MSM: Use VariableBaseMSM trait #425

Merged
merged 22 commits into from
Jun 30, 2022

Conversation

mmagician
Copy link
Member

Description

I believe this PR should address the comments from #423 and offer more flexible interface.
closes: #411


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 Adapted 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

@mmagician mmagician requested a review from Pratyush June 3, 2022 12:06
@@ -170,7 +172,7 @@ impl<P: Parameters> Add<Self> for GroupAffine<P> {
impl<'a, P: Parameters> AddAssign<&'a Self> for GroupAffine<P> {
fn add_assign(&mut self, other: &'a Self) {
let mut s_proj = GroupProjective::from(*self);
s_proj.add_assign_mixed(other);
ProjectiveCurve::add_assign_mixed(&mut s_proj, other);
Copy link
Member

Choose a reason for hiding this comment

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

Did this break? i.e. does s_proj.add_assign_mixed(other) no longer work?

Copy link
Member Author

Choose a reason for hiding this comment

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

That's needed for disambiguation, since we have two traits that define that method

@Pratyush
Copy link
Member

Pratyush commented Jun 3, 2022

Ah I see that we need to put the double_in_place there, as it's used by the default algorithm. Ideally we don't duplicate these method definitions, since whenever you import the VariableBaseMSM trait, you'll automatically need to do the transformation s.double_in_place() -> ProjectiveCurve::double_in_place(&mut s).

I have a couple of ideas to fix this, but the cleanest way would be to do the refactor from #294 =/

@mmaker
Copy link
Member

mmaker commented Jun 9, 2022

EDITED: @mmagician thanks a lot for the pull request! I have a few edits that are available in https://github.com/mmaker/arkworks-algebra/tree/fix/425 and I think will overall improve the quality of this new API.

I'd also much rather keep fancy unicode out of the documentation and add latex support for properly explaining things. I'll add this in a separate pull reuqest.
What do you think? @Pratyush ?

The default, user-friendly way is to multiply group elements by elements
in the scalar field. In an attempt to add some ergonomics,
I'm using the same template but for scalars and adding a big fat warning
that no checks is performed on the size.

The function that acts immediately on the bigints can also be called
explicitly if the caller knows that the same scalar vectors will be used
multiple times. Note that copying that vector only buys a few ms per
MSM of 2^20 elements or more.
The extra function `msm_bigint` also allows to perform  optimizations
on `msm` before the call to `msm_bigint`: instead of
normalizing into `BigInt`s with `u64` we can move to `i32` and use half the
number of buckets in Pippenger, exploiting group addition,
using the representation in buckets as [-w/2 + 1, w/2] instead of [0, w-1].

Use the frontend API `VariableBaseMSM::msm` in tests when possible.

Change (again) defaults for VariableBaseMSM not to panic.

After asking around, looks like most people assume that there is no bound
check (e.g. when committing to a vector or a polynomial). I'm therefore
reverting the change on the bound check
@mmagician
Copy link
Member Author

@mmaker Thanks a lot, I agree that your edits make the API better! Do you want to make a PR to my branch with these changes?

@Pratyush Sure, duplicated method names aren't ideal, but I think that using fully qualified syntax isn't so bad? While the user has to be more explicit, the code stays easy to read. Ultimately, I agree though that having a Group trait like in #294 would automatically allow VariableBaseMSM to extend Group and inherit the necessary methods.

@mmaker mmaker mentioned this pull request Jun 14, 2022
@mmaker
Copy link
Member

mmaker commented Jun 15, 2022

@mmagician done!

@mmaker
Copy link
Member

mmaker commented Jun 15, 2022

@mmagician thanks! maybe this pull request is not anymore a "Draft"?
@Pratyush maybe you concern can be deferred to #294 ?

@mmagician
Copy link
Member Author

I was actually thinking of doing the same for FixedMSM, hence I left it as a draft to get feedback before tackling it.

@mmaker
Copy link
Member

mmaker commented Jun 17, 2022

@mmagician understood -- any chance they could be separated into two different pull requests? I feel like that is another battle and I'm interested in getting this more ergonomic trait available in master sooner than later

@mmagician
Copy link
Member Author

@mmaker For sure, as far as I'm concerned there's no issue in separating it. We just need to convince @Pratyush to accept the duplicated method name ;)

@mmagician mmagician marked this pull request as ready for review June 17, 2022 08:38

type Scalar = <Self as ProjectiveCurve>::ScalarField;

fn double_in_place(&mut self) -> &mut Self {
Copy link
Member

Choose a reason for hiding this comment

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

May be let's rename this to _double_in_place and put it behind a #[doc(hidden)], so that we can avoid having to disambiguate everywhere.

ProjectiveCurve::double_in_place(self)
}

fn add_assign_mixed(&mut self, other: &Self::MSMBase) {
Copy link
Member

Choose a reason for hiding this comment

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

Ditto for this.

Comment on lines 86 to 88
C: ProjectiveCurve,
I: IntoIterator,
I::Item: Borrow<C::ScalarField>,
Copy link
Member

Choose a reason for hiding this comment

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

Does this more generic bound but us much? the IntoIterator I can understand (but we will want to fix it to be conditionally IntoParallelIterator, or call par_bridge() on it.)

However, the Borrow one doesn't seem as useful, IMO

Copy link
Member

@mmaker mmaker Jun 21, 2022

Choose a reason for hiding this comment

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

mmmmh, I was trying to emulate @oleganza in curve25519-dalek: https://github.com/dalek-cryptography/curve25519-dalek/blob/main/src/backend/serial/scalar_mul/pippenger.rs.
Looking at https://github.com/search?q=optional_multiscalar_mul&type=code there's a bunch of repos that use .iter().chain() or iter::once (which can avoid copying the scalars if we support Borrow<C::ScalarField>). I'm however happy to move this into a separate pull request, this can be a different discussion.

Copy link
Member

Choose a reason for hiding this comment

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

@mmagician, @Pratyush: with a % git checkout master -- ec/src/msm/fixed_base.rs we are all good with the new VariableBaseMSM API, only the Changelog might need minor edits.

Copy link
Member

Choose a reason for hiding this comment

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

The impl in curve25519-dalek is not parallelized, which is why they're fine with Iterator. In our case, since we have parallelization, and because iterators are lazy, if you do iter().chain(), the chain() call will be evalauted many times. For more complex iterators this can be an issue.

Copy link
Member

@mmaker mmaker Jun 22, 2022

Choose a reason for hiding this comment

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

This response is not related to Borrow, is it?
To reply about iterators: we still have to copy them in order to make them bigints

Copy link
Member

Choose a reason for hiding this comment

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

@mmaker So is the suggestion to provide an Iterator-based API for MSMs with Scalars, while providing the standard slice-based API for MSMs with bigints?

mmaker added a commit to mmaker/arkworks-algebra that referenced this pull request Jun 21, 2022
Prefix `add_assign_mixed` and `double_in_place` with underscore and
hide from documentation.
mmaker and others added 4 commits June 21, 2022 16:51
Prefix `add_assign_mixed` and `double_in_place` with underscore and
hide from documentation.
@mmagician
Copy link
Member Author

@mmaker I've cherry-picked your previous commit and also checked out the fixed-base file from master. Thanks for that!

@mmagician mmagician requested a review from Pratyush June 21, 2022 15:05
.collect::<Vec<_>>();
let g = (0..SAMPLES)
.map(|_| G::Projective::rand(&mut rng))
.collect::<Vec<_>>();
let g = <G::Projective as ProjectiveCurve>::batch_normalization_into_affine(&g);

let naive = naive_var_base_msm(g.as_slice(), v.as_slice());
let fast = VariableBase::msm(g.as_slice(), v.as_slice());
let fast = <G::Projective as VariableBaseMSM>::msm(g.as_slice(), v.as_slice());
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
let fast = <G::Projective as VariableBaseMSM>::msm(g.as_slice(), v.as_slice());
let fast = VariableBaseMSM::msm(g.as_slice(), v.as_slice());

Should still work, right?

Copy link
Member Author

Choose a reason for hiding this comment

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

No, error[E0282]: type annotations needed. We can be explicit about the type of fast, though:

let fast: G::Projective = VariableBaseMSM::msm(g.as_slice(), v.as_slice());

@@ -48,7 +54,7 @@ pub fn test_chunked_pippenger<G: AffineCurve>() {
.collect::<Vec<_>>();
let g = <G::Projective as ProjectiveCurve>::batch_normalization_into_affine(&g);

let arkworks = VariableBase::msm(g.as_slice(), v.as_slice());
let arkworks = <G::Projective as VariableBaseMSM>::msm_bigint(g.as_slice(), v.as_slice());
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
let arkworks = <G::Projective as VariableBaseMSM>::msm_bigint(g.as_slice(), v.as_slice());
let arkworks = VariableBaseMSM::msm_bigint(g.as_slice(), v.as_slice());

@@ -76,7 +86,7 @@ pub fn test_hashmap_pippenger<G: AffineCurve>() {
.collect::<Vec<_>>();
let g = <G::Projective as ProjectiveCurve>::batch_normalization_into_affine(&g);

let arkworks = VariableBase::msm(g.as_slice(), v.as_slice());
let arkworks = <G::Projective as VariableBaseMSM>::msm_bigint(g.as_slice(), v.as_slice());
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
let arkworks = <G::Projective as VariableBaseMSM>::msm_bigint(g.as_slice(), v.as_slice());
let arkworks = VariableBaseMSM::msm_bigint(g.as_slice(), v.as_slice());

@mmaker
Copy link
Member

mmaker commented Jun 23, 2022 via email

CHANGELOG.md Outdated Show resolved Hide resolved
Copy link
Member

@mmaker mmaker left a comment

Choose a reason for hiding this comment

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

The documentation has now wrong links:

  --> ec/src/msm/variable_base/mod.rs:39:24
   |
39 |     /// Multiply the [`ScalarField::BigInt`] elements in `scalars` with the
   |                        ^^^^^^^^^^^^^^^^^^^ no item named `ScalarField` in scope
   |
   = note: `#[warn(rustdoc::broken_intra_doc_links)]` on by default

warning: unresolved link to `VariableBase::msm`
  --> ec/src/msm/variable_base/mod.rs:60:22
   |
60 |     /// Reference: [`VariableBase::msm`]
   |                      ^^^^^^^^^^^^^^^^^ no item named `VariableBase` in scope

@mmagician I fixed those in mmaker@42e733a or mmagician@42e733a.

@mmaker
Copy link
Member

mmaker commented Jun 28, 2022

@mmagician can you remove FixedBase from the title of the pull request?

@mmagician mmagician changed the title Refactor MSM: Use {Fixed,Variable}BaseMSM traits Refactor MSM: Use VariableBaseMSM trait Jun 28, 2022
@Pratyush Pratyush merged commit 2c5c803 into arkworks-rs:master Jun 30, 2022
@mmagician mmagician deleted the msm-refactor-2 branch December 9, 2022 14:57
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.

Polymorphic MSM interface
3 participants