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

Effective affine precomputation (by Peter Dettman) #210

Merged
merged 2 commits into from
Apr 30, 2015

Conversation

sipa
Copy link
Contributor

@sipa sipa commented Feb 11, 2015

Significantly refactored version of Peter Dettman's effective affine precomputation tricks.

See #174 and #41 for old discussion.

@sipa sipa force-pushed the effective_affine branch 2 times, most recently from 2f2d6d2 to 01c3529 Compare February 12, 2015 07:14
@sipa sipa force-pushed the effective_affine branch 2 times, most recently from 6d972e2 to 7305b6e Compare March 2, 2015 10:52
@sipa
Copy link
Contributor Author

sipa commented Mar 2, 2015

Rebased.

@sipa
Copy link
Contributor Author

sipa commented Mar 3, 2015

This seems to give a 4.5-6.5% speedup for verification (without and with GLV).

@sipa
Copy link
Contributor Author

sipa commented Mar 16, 2015

@gmaxwell @apoelstra: feel like reviewing this?

@apoelstra
Copy link
Contributor

Sure. I will need to do the prereading.

@sipa sipa force-pushed the effective_affine branch from 7305b6e to 9efdf99 Compare March 28, 2015 00:44
@sipa
Copy link
Contributor Author

sipa commented Mar 28, 2015

Rebased.

@sipa sipa force-pushed the effective_affine branch from 9efdf99 to 4365b85 Compare March 29, 2015 21:42
@gmaxwell
Copy link
Contributor

gmaxwell commented Apr 3, 2015

I believe this needs a citation to https://eprint.iacr.org/2008/051 (you should check to see that the technique agrees).

@sipa sipa force-pushed the effective_affine branch from 4365b85 to c52c957 Compare April 11, 2015 08:08
@sipa
Copy link
Contributor Author

sipa commented Apr 11, 2015

Rebased.

@sipa sipa force-pushed the effective_affine branch from c52c957 to 713db62 Compare April 23, 2015 08:22
@sipa
Copy link
Contributor Author

sipa commented Apr 23, 2015

Rebased.

@sipa
Copy link
Contributor Author

sipa commented Apr 23, 2015

@apoelstra Feel free to ask any questions.

@peterdettman
Copy link
Contributor

@apoelstra Happy to answer questions also.

@apoelstra
Copy link
Contributor

Hi guys, sorry for the delay. I've been caught up in schoolwork as I transition departments and haven't had enough spare cycles at once. This weekend is hopeful.

Am I correct that there is an explicit description of the new code in https://eprint.iacr.org/2008/051 (which I haven't read)? Or should I use the algebra and motivations from the Co-Z paper (which I have read in some detail)?

@sipa
Copy link
Contributor Author

sipa commented Apr 24, 2015 via email

@peterdettman
Copy link
Contributor

@apoelstra Further to @sipa's comments, "Co-Z" and "Effective affine" are independent techniques. Possibly that was somewhat obscured during the initial development, but with hindsight and a subsequent refactoring of the code (thanks to @sipa) it is now clear.

I would like to clarify my position on claims of novelty. Since here we wish only to deal with "Effective affine", please also see #211 where I will shortly add a similar statement regarding "Co-Z".

I claim independent discovery of "the effective affine trick", the essence of which is to perform the main ladder of a scalar multiplication on an isomorphism of the original curve, which avoids the cost of an inversion in the field, whilst still admitting the use of mixed addition with precomputed points. There are some minor corollary techniques reflected in the implementation, to wit: i) applying the trick to the pre-computation itself, and ii) applying the trick in the context of a Strauss-Shamir ladder (with one point fixed).

I think it would be premature to claim novelty at this time, for (at least) the following reasons. Although I read quite widely in the relevant literature and know of no previous description or implementation of the technique, I have made only moderate efforts in a directed search. The technique is only a small step away from other commonly-understood techniques. I have not yet directly solicited the opinion of academic researchers, who are likely to have a more complete (e.g. paywalled) and up-to-date view of the literature. Although I have described the techniques on e.g. the IETF CFRG mailing list and in a few private communications, it has never been in the context of establishing novelty. Finally, I have not conducted or requested a prior art search with any patent office.

@sipa
Copy link
Contributor Author

sipa commented Apr 25, 2015 via email

@sipa
Copy link
Contributor Author

sipa commented Apr 25, 2015

The isomorphism involved can be compactly written as:

  • (in affine coordinates): (a,b) + (c,d) = (e,f) <=> (a_t^2,b_t^3) + (c_t^2,d_t^3) = (e_t^2,f_t^3).
  • (in Jacobian coordinates): (a,b,c) + (d,e,f) = (g,h,i) <=> (a,b,c_t) + (d,e,f_t) = (g,h,i*t).

This is used in two different ways:

  • When adding a number of Jacobian points together, which are all known to have the same Z coordinate (called global Z in the source code), one can use the formulae for affine addition (temporarily assuming that global Z coordinate is 1), and then later multiply the result's Z coordinate with the global Z.
  • Addition with a Jacobian point of which the inverse of its Z coordinate is known, can be done using a minor modification to the affine formulae.

@apoelstra
Copy link
Contributor

Awesome, thanks for the summary @peterdettman and for the algebra @sipa. I'll check over the code today (as in now) and tomorrow.

@sipa
Copy link
Contributor Author

sipa commented Apr 27, 2015

@apoelstra In particular, feel free to comment about explanations given in comments (not enough, confusing, ...).

@@ -82,10 +93,10 @@ static void secp256k1_gej_neg(secp256k1_gej_t *r, const secp256k1_gej_t *a);
static int secp256k1_gej_is_infinity(const secp256k1_gej_t *a);

/** Set r equal to the double of a. */
static void secp256k1_gej_double_var(secp256k1_gej_t *r, const secp256k1_gej_t *a);
static void secp256k1_gej_double_var(secp256k1_gej_t *r, const secp256k1_gej_t *a, secp256k1_fe_t *rzr);
Copy link
Contributor

Choose a reason for hiding this comment

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

I think the doccomment needs to be updated to reflect what happens to rzr. ("Is it r.z/a.z or its recipricol?" is not obvious just from the name. I also don't think the behaviour for infinity is obvious since then rzr ought be be "0/0".)

@@ -93,11 +104,14 @@ static void secp256k1_gej_add_ge(secp256k1_gej_t *r, const secp256k1_gej_t *a, c
/** Set r equal to the sum of a and b (with b given in affine coordinates). This is more efficient
than secp256k1_gej_add_var. It is identical to secp256k1_gej_add_ge but without constant-time
guarantee, and b is allowed to be infinity. */
static void secp256k1_gej_add_ge_var(secp256k1_gej_t *r, const secp256k1_gej_t *a, const secp256k1_ge_t *b);
static void secp256k1_gej_add_ge_var(secp256k1_gej_t *r, const secp256k1_gej_t *a, const secp256k1_ge_t *b, secp256k1_fe_t *rzr);
Copy link
Contributor

Choose a reason for hiding this comment

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

and here.

@apoelstra
Copy link
Contributor

Tested ACK. Confirmed that the algebra made sense, comments were sensible, that it was implemented clearly and correctly. Ran unit tests on both commits under valgrind (no leaks or errors) and kcov ("full coverage" as much as that tool can tell), also ran the unit tests for rust-secp256k1 on them.

This is a really elegant and clever improvement. Thanks a ton for your contribution @peterdettman . Sorry all for the delays in my review.

* Make secp256k1_gej_add_var and secp256k1_gej_double return the
  Z ratio to go from a.z to r.z.
* Use these Z ratios to speed up batch point conversion to affine
  coordinates, and to speed up batch conversion of points to a
  common Z coordinate.
* Add a point addition function that takes a point with a known
  Z inverse.
* Due to secp256k1's endomorphism, all additions in the EC
  multiplication code can work on affine coordinate (with an
  implicit common Z coordinate), correcting the Z coordinate of
  the result afterwards.

Refactoring by Pieter Wuille:
* Move more global-z logic into the group code.
* Separate code for computing the odd multiples from the code to bring it
  to either storage or globalz format.
* Rename functions.
* Make all addition operations return Z ratios, and test them.
* Make the zr table format compatible with future batch chaining
  (the first entry in zr becomes the ratio between the input and the
  first output).

Original idea and code by Peter Dettman.
@sipa sipa force-pushed the effective_affine branch from 713db62 to 2d5a186 Compare April 30, 2015 16:27
@sipa
Copy link
Contributor Author

sipa commented Apr 30, 2015

Updated the comments, as requested by @apoelstra.

@sipa
Copy link
Contributor Author

sipa commented Apr 30, 2015

@apoelstra Thanks for the review!

@sipa sipa merged commit 2d5a186 into bitcoin-core:master Apr 30, 2015
sipa added a commit that referenced this pull request Apr 30, 2015
2d5a186 Apply effective-affine trick to precomp (Peter Dettman)
4f9791a Effective affine addition in EC multiplication (Peter Dettman)
@peterdettman
Copy link
Contributor

@apoelstra Thanks for your review, and for your kind words.

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.

4 participants