Skip to content

EC2m LD ladder - #6690

Closed
romen wants to merge 8 commits into
openssl:masterfrom
romen:nt_ec2m_smpl_ladder
Closed

romen wants to merge 8 commits into
openssl:masterfrom
romen:nt_ec2m_smpl_ladder

Conversation

@romen

@romen romen commented Jul 10, 2018 •

Copy link
Copy Markdown
Member

TL;DR

PR #6009 and #6070 unified the code path for EC point multiplication for prime and binary curves, introducing several SCA defenses.
For binary curves the impact on performance of the security improvements was very high (as reported in some GitHub issues, e.g., #6396 ).

This PR aims at improving the existing ec_mul_consttime (now renamed to a more fitting ec_scalar_mul_ladder) function introducing hooks that an EC_METHOD could use to provide specialized, and faster, implementations.

We then provide such a specialized implementation that applies to binary curves, bringing the performance of cryptosystems built on top of such curves reasonably close to the performance level of 1.1.1-pre3 (before most of the new SCA countermeasures were applied).

In most instances (see the detailed table below) the new implementation is more than 10x times faster than current master.

The new implementation is still (reasonably) slower than 1.1.1-pre3, but:

  • latest master includes other changes to the GF2 arithmetic not immediately related to this PR (e.g., 0dae8ba , b336ce5 , ... );
  • latest master includes also other SCA countermeasures which have an impact on performance (see, e.g., ec/ecdsa_ossl.c: revert blinding in ECDSA signature. #6664 );
  • 1.1.1-pre3 is leaky in, e.g., bit length for keygen and derive;
  • 1.1.1-pre3 has no bug attack or DPA mitigations.

This PR only affects binary curves, but the scaffold introduced by the first commit opens the way for improving in a similar way also prime curves, which also suffered a slowdown as a consequence of the recent SCA hardening process, although minor in comparison to the effect on binary curves.

Co-authored by @sohhas and @bbbrumley .

Benchmark table

The following table presents the CPU cycles average computed over 1000 runs per operation.

The benchmarks were executed on Intel Core i7-6700 CPU, running at 3.40GHz, with Turbo Boost disabled, no frequency scaling and on a single core reserved only for the execution of the benchmark, while the rest of the system was mostly idle.

Curve/Operation pre3 master LD_ladder LD / pre3 LD / master
sect163r2
evp_pkey_keygen 675 105 7 415 437 809 969 1.20 0.11
evp_pkey_derive 647 086 7 396 699 791 018 1.22 0.11
evp_digestsign 716 298 7 586 516 914 920 1.28 0.12
evp_digestverify 1 331 206 5 370 424 1 638 221 1.23 0.31
sect233r1
evp_pkey_keygen 863 484 14 307 333 980 921 1.14 0.07
evp_pkey_derive 835 200 14 266 140 973 475 1.17 0.07
evp_digestsign 944 166 14 435 245 1 155 727 1.22 0.08
evp_digestverify 1 736 499 10 185 112 2 016 280 1.16 0.20
sect283r1
evp_pkey_keygen 1 513 133 22 023 374 1 742 583 1.15 0.08
evp_pkey_derive 1 479 988 21 978 168 1 732 546 1.17 0.08
evp_digestsign 1 625 851 22 238 791 1 972 981 1.21 0.09
evp_digestverify 3 054 693 15 508 890 3 592 322 1.18 0.23
sect571r1
evp_pkey_keygen 5 601 491 106 207 308 6 328 737 1.13 0.06
evp_pkey_derive 5 525 044 106 119 035 6 320 248 1.14 0.06
evp_digestsign 6 014 458 106 691 078 7 118 188 1.18 0.07
evp_digestverify 11 368 181 73 156 913 13 180 169 1.16 0.18

Commits breakout

Remove stale SM2 error codes

Run make update ERROR_REBUILD=-rebuild to remove some stale error codes for SM2 (which is now using its own submodule for error codes, i.e., SM2_*).

I filtered out copyright bumps for other unmodified headers.

EC point multiplication: add ladder scaffold for specialized Montgomery ladder implementations

PR #6009 and #6070 replaced the default EC point multiplication path for prime and binary curves with a unified Montgomery ladder implementation with various timing attack defenses (for the common paths when a secret scalar is feed to the point multiplication).
The newly introduced default implementation directly used EC_POINT_add/dbl in the main loop.

The scaffolding introduced by this commit allows EC_METHODs to define a specialized ladder_step function to improve performances by taking advantage of efficient formulas for differential addition-and-doubling and different coordinate systems.

  • ladder_pre is executed before the main loop of the ladder: by default it copies the input point P into S, and doubles it into R.
    Specialized implementations could, e.g., use this hook to transition to different coordinate systems before copying and doubling;
  • ladder_step is the core of the Montgomery ladder loop: by default it computes S := R+S; R := 2R;, but specific implementations could, e.g., implement a more efficient formula for differential addition-and-doubling;
  • ladder_post is executed after the Montgomery ladder loop: by default it's a noop, but specialized implementations could, e.g., use this hook to transition back from the coordinate system used for optimizing the differential addition-and-doubling or recover the y coordinate of the result point.

This commit also renames ec_mul_consttime to ec_scalar_mul_ladder, as it better corresponds to what this function does: nothing can be truly said about the constant-timeness of the overall execution of this function, given that the underlying operations are not necessarily constant-time themselves.
What this implementation ensures is that the same fixed sequence of operations is executed for each scalar multiplication (for a given EC_GROUP), with no dependency on the value of the input scalar.

[test] test some important ladder corner cases and catch corner cases better and earlier

Self explicative, you might consider squashing this commit with the previous one; I decided to keep it separate as it is technically independent from any other change in this PR and because it was authored by @bbbrumley alone.

EC2M Lopez-Dahab ladder implementation

This commit uses the new ladder scaffold to implement a specialized ladder step based on differential addition-and-doubling in mixed Lopez-Dahab projective coordinates, modified to independently blind the operands.

The arithmetic in ladder_pre, ladder_step and ladder_post is auto generated with tooling:

  • see, e.g., "Guide to ECC" Alg 3.40 for reference about the ladder_pre implementation;
  • see https://www.hyperelliptic.org/EFD/g12o/auto-code/shortw/xz/ladder/mladd-2003-s.op3 for the differential addition-and-doubling formulas implemented in ladder_step;
  • see, e.g., "Fast Multiplication on Elliptic Curves over GF(2**m) without Precomputation" (Lopez and Dahab, CHES 1999) Appendix Alg Mxy for the ladder_post implementation to recover the (x,y) result in affine coordinates.

EC2M Lopez-Dahab ladder: use it also for ECDSA verify

By default ec_scalar_mul_ladder (which uses the Lopez-Dahab ladder implementation) is used only for (k * Generator) or (k * VariablePoint).
ECDSA verification uses (a * Generator + b * VariablePoint): this commit forces the use of ec_scalar_mul_ladder also for the ECDSA verification path, while using the default wNAF implementation for any other case.

With this commit ec_scalar_mul_ladder loses the static attribute, and is added to ec_lcl.h so EC_METHODs can directly use it.

While working on a new custom EC_POINTs_mul implementation, I realized that many checks (e.g. all the points being compatible with the given EC_GROUP, creating a temporary BN_CTX if ctx == NULL, check for the corner case scalar == NULL && num == 0) were duplicated again and again in every single implementation (and actually some implementations lacked some of the tests).
I thought that it makes way more sense for those checks that are independent from the actual implementation and should always be done, to be moved in the EC_POINTs_mul wrapper: so this commit also includes these changes.

Again this is technically independent from the parent commit, but you might consider squashing it with the parent: without this ECDSA verification using binary curves does not benefit from the performance boost brought by the new implementation.

Checklist

  • documentation is added or updated
  • tests are added or updated
  • make commits atomic (running make update) once we receive feedback
  • rename ec_mul_consttime to ec_scalar_mul_ladder
  • rebase and squash
  • add group->order and group->cofactor checks in ec_scalar_mul_ladder
  • get feedback on the "Remove stale SM2 error codes" commit

Comment thread crypto/ec/ec_err.c Outdated

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

I'm not sure why make update wants to remove SM2 stuff, should this have been removed in a previous PR?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

@richsalz am I doing something wrong here? Should I use something more specific to update the error codes, rather than a full make update to avoid removing this SM2 stuff?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I'm not sure what's happening. Maybe you're not on the current master? Curious.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

I am on latest master, but apparently it's "dirty" and apparently make update does not remove superfluous unused error codes unless new error codes are detected:

~/repos/openssl >>> git log -1
commit 03a5e5ae6304c75f611d3613bedf2019524ff0d6 (HEAD -> master, upstream/master)
Author: Patrick Steuer <patrick.steuer@de.ibm.com>
Date:   Thu Jul 12 13:19:07 2018 -0400

    Fix undefined behavior in s390x aes-gcm/ccm

    Reviewed-by: Rich Salz <rsalz@openssl.org>
    Reviewed-by: Andy Polyakov <appro@openssl.org>
~/repos/openssl >>> ack EC_F_PKEY_SM2_CTRL
crypto/ec/ec_err.c
264:    {ERR_PACK(ERR_LIB_EC, EC_F_PKEY_SM2_CTRL, 0), "pkey_sm2_ctrl"},
265:    {ERR_PACK(ERR_LIB_EC, EC_F_PKEY_SM2_CTRL_STR, 0), "pkey_sm2_ctrl_str"},

include/openssl/ecerr.h
186:#  define EC_F_PKEY_SM2_CTRL                               284
187:#  define EC_F_PKEY_SM2_CTRL_STR                           285

EC_F_PKEY_SM2_CTRL is one of the error codes that gets removed on my make update step, and as you can see there is no function currently using it: the SM2 functions now are using their own "submodule", e.g., SM2_F_PKEY_SM2_CTRL.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Fixed following @dot-asm advice!

@romen
romen force-pushed the nt_ec2m_smpl_ladder branch from f57a97b to 562ded8 Compare July 12, 2018 09:45
@romen

romen commented Jul 12, 2018

Copy link
Copy Markdown
Member Author

I just rebased on master after improving the "EC2M LD ladder: use it also for ECDSA verify" commit, hardening it against weird arguments that could be passed in but are not currently covered by testing.

I actually moved most of those checks to the EC_POINTs_mul wrapper, as they are actually independent from the specific implementation and should always be executed.

/cc @bbbrumley (that gave me the original input for the latest changes) for feedback on 063e3d9

@romen

romen commented Jul 12, 2018

Copy link
Copy Markdown
Member Author

Ping @richsalz for an opinion about moving the checks to the wrapper (and if that should actually be ported to 1.1.0 as well) and possibly also on how OMC would prefer the commits to be organized.

I know @mattcaswell is on holiday, does anyone else from the committers care to give feedback on this? Maybe @dot-asm ?

@richsalz

Copy link
Copy Markdown
Contributor

I'm not worried about how the commits are organized, although others might be. Moving the checks to the wrapper, and out of the internal functions is reasonable if those aren't part of the public API.

@richsalz

Copy link
Copy Markdown
Contributor

@davidben or @dot-asm any feedback?

Comment thread crypto/ec/ec2_smpl.c Outdated

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I'd like to suggest to add a space here, to align it with group, to denote the fact that they are in same expression.

Comment thread crypto/ec/ec2_smpl.c Outdated

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Same as above.

Comment thread crypto/ec/ec_lib.c Outdated

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Explicit new_ctx != NULL is preferred nowadays.

Comment thread crypto/ec/ecp_nistp224.c Outdated

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

In such case you can remove new_ctx altogether. This comment applies even below.

Comment thread crypto/ec/ec2_smpl.c Outdated

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

EC_POINT_free checks for NULL, no need to do it here.

@dot-asm

dot-asm commented Jul 13, 2018

Copy link
Copy Markdown
Contributor

The fact that some of errors are removed is no mystery. They are actually unreferenced, and should be removed. Note that they start with EC_F_PKEY, while all actual codes are SM2_F_PKEY. So right thing to do would be to run make update [ERROR_REBUILD=-rebuild] prior suggested modifications. "Right thing" in sense that there would be separate commit that removes unreferenced values, so that every commit would be about one thing, not two. It can be done in two ways. I can create separate request that removes them, and you can re-base later. Or you can re-master this request by injecting separate commit that removes the values in question.

@romen

romen commented Jul 13, 2018 •

Copy link
Copy Markdown
Member Author

@dot-asm I saw your comment only now, after replying to @richsalz above with the same answer.

It can be done in two ways. I can create separate request that removes them, and you can re-base later. Or you can re-master this request by injecting separate commit that removes the values in question.

I will do a rebase now, with a commit to remove the old unused ones, followed by our new commits, making them "atomic" so that each of them will include only its own make update.

Thanks!

(I'll now temporarily mark this PR as WIP and ping you again when it's ready for review!)

@romen romen changed the title EC2m LD ladder WIP: EC2m LD ladder Jul 13, 2018
Comment thread crypto/ec/ec_lcl.h Outdated

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Formatting nit, two lines are one space too short.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

thanks for catching this! I will fix both of them during the rebase!

Comment thread crypto/ec/ec_lcl.h Outdated

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Formatting nit. Two lines are one space too short.

@romen
romen force-pushed the nt_ec2m_smpl_ladder branch from 0f9ed0d to 84e3bdd Compare July 13, 2018 09:19
@romen romen changed the title WIP: EC2m LD ladder EC2m LD ladder Jul 13, 2018
@romen

romen commented Jul 13, 2018

Copy link
Copy Markdown
Member Author

@dot-asm @davidben @richsalz @mattcaswell

Out of WIP now:

  • cleaned up stale SM2 error codes (see dc77411976c1a3217c3e9ed80220672fbb5bb599 msg please, I had to make decisions, I hope they were the right ones!)
  • fixed reported formatting nits
  • cleaned up stale new_ctx pointers
  • EC_POINT_free() and BN_CTX_free() can be called with NULL argument
  • made commits "atomic" (i.e., each one includes its own make update pass, so each point in the PR git history can be successfully compiled and passes tests)
  • rebased on latest master

Thanks everyone for the feedback so far!

Comment thread crypto/ec/ec_lcl.h Outdated

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Formatting nit, two lines are one space too long.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Fixed!

Comment thread crypto/ec/ec2_smpl.c Outdated

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Even though it's kind of obvious from the context I'd like to see "LD" expanded. Even elsewhere.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

I fixed this in the code, it might be useful to rewrite the message for commit 84e3bdd722cc0, e.g.:

EC2M Lopez-Dahab ladder: use it also for ECDSA verify

By default `ec_mul_consttime` (which uses the ladder implementation) is
used only for k*Generator or k*GenericPoint.
ECDSA verification uses a*Generator+b*GenericPoint: this commit
forces the use of `ec_mul_consttime` (and the Lopez-Dahab ladder) also
for the ECDSA verification path, while using the default wNAF
implementation for any other case.

With this commit ec_mul_consttime loses the static attribute, and is
added to ec_lcl.h so EC_METHODs can directly use it.

While working on a new custom EC_POINTs_mul implementation, I realized
that many checks (e.g. all the points being compatible with the given
group, creating ctx if NULL, scalar==NULL && num==0) were duplicated
again and again in every single implementation (and actually some
implementations lacked some tests). I thought that it makes way more
sense for those checks that are independent from the actual
implementation and should always be done, to be moved in the
EC_POINTs_mul wrapper: so this commit also includes these changes.

Comment thread crypto/ec/ec2_smpl.c Outdated

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Sytle nit: spaces in front of and after "=" are required; i.e. int ret = 0;

Comment thread crypto/ec/ec2_smpl.c Outdated

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Style nit: space needed after ","

Comment thread crypto/ec/ec_mult.c Outdated

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

There seems to be inconsistency in this function about whether we call ECerr or not.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

The "fixup!" commits below fix the reported formatting nits in the corresponding commits.

I will have now a look at ec_mul_consttime to raise ECerr in the appropriate cases.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

@mattcaswell can you check 6f9fd585222 ?

(I couldn't find more specific reasons than ERR_R_EC_LIB/ERR_R_BN_LIB). Suggestions?

Comment thread test/ectest.c Outdated

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Indentation seems strange here.

Comment thread crypto/ec/ec2_smpl.c Outdated

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

This is side note, which means that no action is actually expected, just think about it. While p != q works, I find it a bit less readable. Because you have to unravel it to scalar being NULL. At the same time replacing it with scalar == NULL doesn't make it perfect either. Maybe [again, this is just for consideration] one can arrange code so that condition would be q != NULL? So that pattern would be

if (q != NULL) EC_POINT_add(group, q, q, p, ctx);
else           q = p;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

On additional thought, it's probably names being so generic that tips me off. For example if q was called say acc[umulator], it wouldn't be a problem. Point is that generic names make you wonder if there is any meaning behind letter. For example you would think of p as "product", and what would be q? And what is connection? With name like acc[umulator] you see directly that it's just a placeholder...

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

bbd0e2b is my attempt at maximizing readability: I clearly and explicitly separated the 3 cases: this comes at the "cost" of duplicating one line of code (ec_mul_consttime(group, r, scalars[0], points[0], ctx)) but I think it is a good tradeoff which does not uglify the code and solves way more problems in readability and upkeep than it creates.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Cool!

Comment thread crypto/ec/ec_lcl.h Outdated

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I for one sense inconsistency in this function naming. Now when it's shared, a better name might be more appropriate. Maybe ec_mul_by_scalar_consttime? Just me? Obviously side note...

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

What about ec_scalarmul_ladder?

I feel a bit of resistance in naming anything "consttime" given that we cannot promise anything about the underlying layer.

@romen romen Jul 13, 2018 •

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Once we agree on the renaming, given that it would require fixing themake update step and rewrite some commit messages, I would do a proper rebase, also squashing the stack of small fixup commits that piled up till now.

But I will have to wait until tomorrow to act upon this.

I totally favor a renaming, for the reason above, let's just agree on a proper name.

@bbbrumley /@mattcaswell would you care to chime in with your opinion on proper names?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

What about ec_scalarmul_ladder?

Great! Except maybe ec_scalar_mul_ladder? Just pick either :-)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

maybe ec_scalar_mul_ladder

+1

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

ec_scalar_mul_ladder works for me.

@romen romen changed the title EC2m LD ladder WIP: EC2m LD ladder Jul 13, 2018
@mattcaswell mattcaswell added this to the 1.1.1 milestone Jul 13, 2018
Run `make update ERROR_REBUILD=-rebuild` to remove some stale error
codes for SM2 (which is now using its own submodule for error codes,
i.e., `SM2_*`).

I filtered out copyright bumps for other unmodified headers, and also
the following diff (as both files are internal and should never be
included in C++ source):

```diff
diff --git a/crypto/include/internal/sm2err.h b/crypto/include/internal/sm2err.h
index f32d26c..9a7e2b6 100644
--- a/crypto/include/internal/sm2err.h
+++ b/crypto/include/internal/sm2err.h
@@ -15,6 +15,9 @@

 # ifndef OPENSSL_NO_SM2

+#  ifdef  __cplusplus
+extern "C"
+#  endif
 int ERR_load_SM2_strings(void);

 /*
diff --git a/include/internal/dsoerr.h b/include/internal/dsoerr.h
index ac6bdcd..a54a185 100644
--- a/include/internal/dsoerr.h
+++ b/include/internal/dsoerr.h
@@ -15,6 +15,9 @@

 # ifndef OPENSSL_NO_DSO

+#  ifdef  __cplusplus
+extern "C"
+#  endif
 int ERR_load_DSO_strings(void);

 /*
```
@romen
romen force-pushed the nt_ec2m_smpl_ladder branch from 6f9fd58 to 3e0abd5 Compare July 13, 2018 22:45
for specialized Montgomery ladder implementations

PR openssl#6009 and openssl#6070 replaced the default EC point multiplication path for
prime and binary curves with a unified Montgomery ladder implementation
with various timing attack defenses (for the common paths when a secret
scalar is feed to the point multiplication).
The newly introduced default implementation directly used
EC_POINT_add/dbl in the main loop.

The scaffolding introduced by this commit allows EC_METHODs to define a
specialized `ladder_step` function to improve performances by taking
advantage of efficient formulas for differential addition-and-doubling
and different coordinate systems.

- `ladder_pre` is executed before the main loop of the ladder: by
  default it copies the input point P into S, and doubles it into R.
  Specialized implementations could, e.g., use this hook to transition
  to different coordinate systems before copying and doubling;
- `ladder_step` is the core of the Montgomery ladder loop: by default it
  computes `S := R+S; R := 2R;`, but specific implementations could,
  e.g., implement a more efficient formula for differential
  addition-and-doubling;
- `ladder_post` is executed after the Montgomery ladder loop: by default
  it's a noop, but specialized implementations could, e.g., use this
  hook to transition back from the coordinate system used for optimizing
  the differential addition-and-doubling or recover the y coordinate of
  the result point.

This commit also renames `ec_mul_consttime` to `ec_scalar_mul_ladder`,
as it better corresponds to what this function does: nothing can be
truly said about the constant-timeness of the overall execution of this
function, given that the underlying operations are not necessarily
constant-time themselves.
What this implementation ensures is that the same fixed sequence of
operations is executed for each scalar multiplication (for a given
EC_GROUP), with no dependency on the value of the input scalar.

Co-authored-by: Sohaib ul Hassan <soh.19.hassan@gmail.com>
Co-authored-by: Billy Brumley <bbrumley@gmail.com>
@dot-asm

dot-asm commented Jul 14, 2018 •

Copy link
Copy Markdown
Contributor

Run make update ERROR_REBUILD=-rebuild ... I filtered out copyright bumps for other unmodified headers, and also the following diff (as both files are internal and should never be included in C++ source)

As for copyright bumps, I'd say it's appropriate. As for pair of extern "C", one could just as well leave them. Because they are auto-generated, and the script will keep re-adding them, because it makes no difference between public and private headers. One can argue that script should be fixed, but couple of extern "C" in private headers is really no biggie, and one can just as well tolerate them. Let's put it this way. If it's not much trouble to re-add those extern "C", do so. And if you feel that it's rather a distraction in the context of this request, do nothing. Script might get fixed at later point [or not].

@romen

romen commented Jul 14, 2018

Copy link
Copy Markdown
Member Author

So 243fb25 adds the group->order and group->cofactor checks.

Re @bbbrumley :

Edit: but really seems like a separate PR to me.

I think it is appropriate to have the checks (and documentation) added where ec_scalar_mul_ladder is made accessible to other internal functions, so I went ahead and included it in this PR.

@dot-asm : 99ae74e adds back the extern C, I just tried it and everything autosquashes without problems. The extended part of the commit message for 40d87a1 should be purged before the final merge.

@romen romen changed the title WIP: EC2m LD ladder EC2m LD ladder Jul 14, 2018
@romen

romen commented Jul 14, 2018

Copy link
Copy Markdown
Member Author

Out of WIP now.

Comment thread crypto/ec/ec2_smpl.c
* order or cofactor set to 0.
*/
if (num > 1 || BN_is_zero(group->order) || BN_is_zero(group->cofactor))
return ec_wNAF_mul(group, r, scalar, num, points, scalars, ctx);

@dot-asm dot-asm Jul 14, 2018 •

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

On side note one can find it confusing that ec_wNAF_mul calls ec_scalar_mul_ladder with inverse conditions. In other words except for scalar != NULL && num==1 case one can simply call ec_wNAF_mul. This makes you wonder if it would be appropriate to implement the additional scalar != NULL && num==1 in ec_wNAF_mul. In which case this method can be simply omitted, right?

@romen romen Jul 14, 2018 •

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

If I understand correctly, you are suggesting to handle the (scalar != NULL && num==1) in ec_wNAF_mul() calling ec_scalar_mul_ladder: the problem with that is that for other implementations ec_scalar_mul_ladder can be slower than the regular "non-const-time" path.

Double multiplication is basically only used by ECDSA verification right now, where all the inputs are public, so a fast and insecure implementation could be used, rather than ec_scalar_mul_ladder.

What we really would need is refactor the EC_METHOD API to ditch/deprecate the unified EC_POINTs_mul (which makes a sense from a mathematical point of view, but is not really the way the 3 different scalar multiplication cases are used by cryptosystems) in favor of 3 different function pointers for fixed_point_mul, variable_point_mul, double_point_mul.
Right now we have wrappers that are forcing the 3 different operations into the unified EC_POINTs_mul path, and then in ec_scalar_mul_ladder we split them again.
In some cases, a specific double_point_mul could almost half the current execution cost of the verification step, as we could use formulas (e.g., derived from Shamir's trick) that avoid doing 2 distinct scalar multiplications and then 1 addition, and share as much computation as possible.
But this must wait for the next major release development cycle!

Does this answer your comment, or did I completely misunderstand what you meant?

Edit: grammar, formatting

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

the problem with that is that for other implementations ec_scalar_mul_ladder can be slower

Fair enough. Then how about

if (scalar == NULL || num != 1 || order == 0 || cofactor == 0)
    return ec_wNAF_mul()
/* scalar != NULL && num == 1 is faster with ec_scalar_mul_ladder here [and now] */
...

Just keep in mind that this is side note, so "how about" is really just a question, it's not a suggestion. Point is not larger than order != 0 && cofactor !=0 case in ec_wNAF_mul being partial duplicate of the code below this line. [Off topic, this kind of asks for question if ec_wNAF_mul is actually suitable name.]

@romen romen Jul 14, 2018 •

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

I think this change would hinder readability and mask intent: what we want to convey is that binary non-degenerate curves (i.e., have a order and cardinality that makes sense, given that mathematically speaking 0 is not really an option for either value) use ec_scalar_mul_ladder for the 3 cases, any other crazyness that can be fed through the EC_POINTs_mul API is basically uncharted territory and not cryptographically relevant, so we will let the default wNAF implementation handle it.

It's true that, currently, we could let ec_wNAF_mul handle every case but the double scalar multiplication, and it would work, depending on the fact that that function will itself call the ec_scalar_mul_ladder for the fixed and variable point.
But I think that relying on the fact that currently something called ec_wNAF_mul is hijacked to perform a completely different code path in specific cases is even worse than duplicating the checks!

Re: renaming ec_wNAF_mul

I would argue that it would make sense to have in ec_mult.c something like ec_points_mul_default working as a wrapper distinguishing the two single point multiplication cases (for which ec_scalar_mul_ladder is then called) from the truly multi-point multiplication case (for which ec_wNAF_mul is called).
But I would leave this to a separate PR.

Even better, in a separate PR I would rather start a transition to 3 separate function pointers in EC_METHOD for the fixed/variable/double point multiplication, and let the EC_POINTs_mul wrapper do something like:

/* All kinds of checks on not NULL args, every point_is_compat, etc. */

if (group->meth->points_mul)
    /* you're on your own, probably will have to replicate most of the checks below */ 
    return group->meth->points_mul(...);

degenerate = BN_is_zero(group->order) || BN_is_zero(group->cofactor);

if (scalar != NULL && num == 0)
    if (group->meth->fixed_scalar_mul)
        /* you still have to handle degenerate cases */
        return group->meth->fixed_scalar_mul(...);
    else if (!degenerate)
        return ec_scalar_mul_ladder(...);

if (scalar == NULL && num == 1)
    if (group->meth->variable_scalar_mul)
        /* you still have to handle degenerate cases */
        return group->meth->variable_scalar_mul(...);
    else if (!degenerate)
        return ec_scalar_mul_ladder(...);

if (scalar != NULL && num == 1 && group->meth->double_scalar_mul)
    /* you still have to handle degenerate cases */
    return group->meth->double_scalar_mul(...);

/* HIC SUNT DRACONES */
return ec_wNAF_mul(...);

Until something similar exists, I don't think we can avoid specific EC_POINTs_mul implementations to repeat the checks for the 3 cases.
And the existence of the degenerate case will also probably mean that most non-default implementations of the 3 scalar_mul variants will need to repeat the check for degenerate cases.

Edit: Reword a bit and fixed a lot of typos....

@dot-asm dot-asm added the approval: review pending This pull request needs review by a committer label Jul 14, 2018
@richsalz

Copy link
Copy Markdown
Contributor

This looks good to me, but I'll not approve until/unless @mattcaswell says that his concerns have been addressed.

@mattcaswell mattcaswell added approval: done This pull request has the required number of approvals and removed approval: review pending This pull request needs review by a committer labels Jul 16, 2018
@mattcaswell

Copy link
Copy Markdown
Member

I will merge shortly

@romen

romen commented Jul 16, 2018

Copy link
Copy Markdown
Member Author

Thanks @mattcaswell! It might have gotten lost in the conversation, but during rebase the msg for the first commit is in need of editing!

@mattcaswell

Copy link
Copy Markdown
Member

Thanks @mattcaswell! It might have gotten lost in the conversation, but during rebase the msg for the first commit is in need of editing!

Yes..I spotted that, thanks.

@mattcaswell

Copy link
Copy Markdown
Member

Pushed! Thanks!

levitte pushed a commit that referenced this pull request Jul 16, 2018
Run `make update ERROR_REBUILD=-rebuild` to remove some stale error
codes for SM2 (which is now using its own submodule for error codes,
i.e., `SM2_*`).

Reviewed-by: Andy Polyakov <appro@openssl.org>
Reviewed-by: Matt Caswell <matt@openssl.org>
(Merged from #6690)
levitte pushed a commit that referenced this pull request Jul 16, 2018
for specialized Montgomery ladder implementations

PR #6009 and #6070 replaced the default EC point multiplication path for
prime and binary curves with a unified Montgomery ladder implementation
with various timing attack defenses (for the common paths when a secret
scalar is feed to the point multiplication).
The newly introduced default implementation directly used
EC_POINT_add/dbl in the main loop.

The scaffolding introduced by this commit allows EC_METHODs to define a
specialized `ladder_step` function to improve performances by taking
advantage of efficient formulas for differential addition-and-doubling
and different coordinate systems.

- `ladder_pre` is executed before the main loop of the ladder: by
  default it copies the input point P into S, and doubles it into R.
  Specialized implementations could, e.g., use this hook to transition
  to different coordinate systems before copying and doubling;
- `ladder_step` is the core of the Montgomery ladder loop: by default it
  computes `S := R+S; R := 2R;`, but specific implementations could,
  e.g., implement a more efficient formula for differential
  addition-and-doubling;
- `ladder_post` is executed after the Montgomery ladder loop: by default
  it's a noop, but specialized implementations could, e.g., use this
  hook to transition back from the coordinate system used for optimizing
  the differential addition-and-doubling or recover the y coordinate of
  the result point.

This commit also renames `ec_mul_consttime` to `ec_scalar_mul_ladder`,
as it better corresponds to what this function does: nothing can be
truly said about the constant-timeness of the overall execution of this
function, given that the underlying operations are not necessarily
constant-time themselves.
What this implementation ensures is that the same fixed sequence of
operations is executed for each scalar multiplication (for a given
EC_GROUP), with no dependency on the value of the input scalar.

Co-authored-by: Sohaib ul Hassan <soh.19.hassan@gmail.com>
Co-authored-by: Billy Brumley <bbrumley@gmail.com>

Reviewed-by: Andy Polyakov <appro@openssl.org>
Reviewed-by: Matt Caswell <matt@openssl.org>
(Merged from #6690)
levitte pushed a commit that referenced this pull request Jul 16, 2018
and catch corner cases better and earlier

Reviewed-by: Andy Polyakov <appro@openssl.org>
Reviewed-by: Matt Caswell <matt@openssl.org>
(Merged from #6690)
levitte pushed a commit that referenced this pull request Jul 16, 2018
This commit uses the new ladder scaffold to implement a specialized
ladder step based on differential addition-and-doubling in mixed
Lopez-Dahab projective coordinates, modified to independently blind the
operands.

The arithmetic in `ladder_pre`, `ladder_step` and `ladder_post` is
auto generated with tooling:
- see, e.g., "Guide to ECC" Alg 3.40 for reference about the
  `ladder_pre` implementation;
- see https://www.hyperelliptic.org/EFD/g12o/auto-code/shortw/xz/ladder/mladd-2003-s.op3
  for the differential addition-and-doubling formulas implemented in
  `ladder_step`;
- see, e.g., "Fast Multiplication on Elliptic Curves over GF(2**m)
  without Precomputation" (Lopez and Dahab, CHES 1999) Appendix Alg Mxy
  for the `ladder_post` implementation to recover the `(x,y)` result in
  affine coordinates.

Co-authored-by: Billy Brumley <bbrumley@gmail.com>
Co-authored-by: Sohaib ul Hassan <soh.19.hassan@gmail.com>

Reviewed-by: Andy Polyakov <appro@openssl.org>
Reviewed-by: Matt Caswell <matt@openssl.org>
(Merged from #6690)
levitte pushed a commit that referenced this pull request Jul 16, 2018
By default `ec_scalar_mul_ladder` (which uses the Lopez-Dahab ladder
implementation) is used only for (k * Generator) or (k * VariablePoint).
ECDSA verification uses (a * Generator + b * VariablePoint): this commit
forces the use of `ec_scalar_mul_ladder` also for the ECDSA verification
path, while using the default wNAF implementation for any other case.

With this commit `ec_scalar_mul_ladder` loses the static attribute, and
is added to ec_lcl.h so EC_METHODs can directly use it.

While working on a new custom EC_POINTs_mul implementation, I realized
that many checks (e.g. all the points being compatible with the given
EC_GROUP, creating a temporary BN_CTX if `ctx == NULL`, check for the
corner case `scalar == NULL && num == 0`) were duplicated again and
again in every single implementation (and actually some
implementations lacked some of the tests).
I thought that it makes way more sense for those checks that are
independent from the actual implementation and should always be done, to
be moved in the EC_POINTs_mul wrapper: so this commit also includes
these changes.

Reviewed-by: Andy Polyakov <appro@openssl.org>
Reviewed-by: Matt Caswell <matt@openssl.org>
(Merged from #6690)
@romen romen mentioned this pull request Jul 24, 2018
1 task done
romen added a commit to romen/openssl that referenced this pull request Jul 26, 2018
This commit leverages the Montgomery ladder scaffold introduced in openssl#6690
(alongside a specialized Lopez-Dahab ladder for binary curves) to
provide a specialized differential addition-and-double implementation to
speedup prime curves, while keeping all the features of
`ec_scalar_mul_ladder` against SCA attacks.

The arithmetic in ladder_pre, ladder_step and ladder_post is auto
generated with tooling, from the following formulae:

- `ladder_pre`: Formula 3 for doubling from Izu-Takagi "A fast parallel
  elliptic curve multiplication resistant against side channel attacks",
  as described at
  https://hyperelliptic.org/EFD/g1p/auto-shortw-xz.html#doubling-dbl-2002-it-2
- `ladder_step`: differential addition-and-doubling Eq. (8) and (10)
  from Izu-Takagi "A fast parallel elliptic curve multiplication
  resistant against side channel attacks", as described at
  https://hyperelliptic.org/EFD/g1p/auto-shortw-xz.html#ladder-ladd-2002-it-3
- `ladder_post`: y-coordinate recovery using Eq. (8) from Brier-Joye
  "Weierstrass Elliptic Curves and Side-Channel Attacks", modified to
  work in projective coordinates.

Co-authored-by: Nicola Tuveri <nic.tuv@gmail.com>
levitte pushed a commit that referenced this pull request Jul 26, 2018
This commit leverages the Montgomery ladder scaffold introduced in #6690
(alongside a specialized Lopez-Dahab ladder for binary curves) to
provide a specialized differential addition-and-double implementation to
speedup prime curves, while keeping all the features of
`ec_scalar_mul_ladder` against SCA attacks.

The arithmetic in ladder_pre, ladder_step and ladder_post is auto
generated with tooling, from the following formulae:

- `ladder_pre`: Formula 3 for doubling from Izu-Takagi "A fast parallel
  elliptic curve multiplication resistant against side channel attacks",
  as described at
  https://hyperelliptic.org/EFD/g1p/auto-shortw-xz.html#doubling-dbl-2002-it-2
- `ladder_step`: differential addition-and-doubling Eq. (8) and (10)
  from Izu-Takagi "A fast parallel elliptic curve multiplication
  resistant against side channel attacks", as described at
  https://hyperelliptic.org/EFD/g1p/auto-shortw-xz.html#ladder-ladd-2002-it-3
- `ladder_post`: y-coordinate recovery using Eq. (8) from Brier-Joye
  "Weierstrass Elliptic Curves and Side-Channel Attacks", modified to
  work in projective coordinates.

Co-authored-by: Nicola Tuveri <nic.tuv@gmail.com>

Reviewed-by: Andy Polyakov <appro@openssl.org>
Reviewed-by: Rich Salz <rsalz@openssl.org>
(Merged from #6772)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

approval: done This pull request has the required number of approvals

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants