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

add script to compute precomputed curves, test with precomputed #1

Merged
merged 23 commits into from
Sep 6, 2019

Conversation

mvayngrib
Copy link
Collaborator

@mvayngrib mvayngrib commented Jul 29, 2019

current master is forked from elliptic@6.4.1, renamed to @exodus/elliptic

the goal is to be able to sacrifice bundle size for performance by electing to use precomputed curves from the root project, e.g.:

const elliptic = require('elliptic');
elliptic.usePrecomputed({
  // require only the ones you need
  p256: require('elliptic/lib/elliptic/precomputed/p256'),
});

also, the validation in the PresetCurve is expensive and unnecessary to do at runtime for pre-defined curves

@mvayngrib mvayngrib added enhancement New feature or request performance labels Jul 29, 2019
@mvayngrib mvayngrib self-assigned this Jul 29, 2019
@mvayngrib mvayngrib requested a review from ChALkeR July 29, 2019 22:43
lib/elliptic/curves.js Outdated Show resolved Hide resolved
@mvayngrib mvayngrib requested a review from kklash July 29, 2019 23:35
lib/elliptic/curves.js Outdated Show resolved Hide resolved
Copy link

@ChALkeR ChALkeR left a comment

Choose a reason for hiding this comment

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

Could there be a test that all precomputed curves match with non-precomputed ones?
Similar to precompute.js, but for verification only and automated during tests.

@kklash
Copy link

kklash commented Jul 30, 2019

Agreed with @ChALkeR, that seems like a must-have opportunity for a unit test

@mvayngrib
Copy link
Collaborator Author

@kklash @ChALkeR see scripts for unit:precomputed. It runs the same tests with precomputed curves. You can also delete the contents of the precomputed/ dir and re-gen them with ./scripts/precompute.js and see that the git diff is empty

@mvayngrib
Copy link
Collaborator Author

Could there be a test that all precomputed curves match with non-precomputed ones?

@ChALkeR in case i misunderstood, in which way did you mean for them to match?

@kklash
Copy link

kklash commented Jul 30, 2019

in case i misunderstood, in which way did you mean for them to match?

I imagine he means that if you run regular old elliptic with no precomputed curves, and generate a p256 curve, for example, that curve's JSON object should exactly match the precomputed p256.json object. I assume you could check using some kind of deep equality comparison function.

@mvayngrib
Copy link
Collaborator Author

@kklash ok, i'll see if i can add some kind of deep equality check to this test tomorrow: https://github.com/ExodusMovement/elliptic/pull/1/files#diff-eb6a8b288bf31a87c6e73e3e18055362R32

@mvayngrib
Copy link
Collaborator Author

@ChALkeR did i understand you correctly with this test? 83d7b7c

@mvayngrib
Copy link
Collaborator Author

@ChALkeR @kklash is anything still missing from the PR?

@mvayngrib
Copy link
Collaborator Author

mvayngrib commented Aug 5, 2019

increased timeout for test

can i remove support for node < 4 and the coveralls test so we don't waste time on them? Or do we want to setup coveralls here?

the failing build for reference: https://travis-ci.com/ExodusMovement/elliptic/builds/121961197

Copy link

@ChALkeR ChALkeR left a comment

Choose a reason for hiding this comment

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

The checks removed in options.skipValidation block should probably be extracted into a testcase, to make sure that all hardcoded curves do not fail that check. I don't think those are present in tests?
I.e.

assert(this.g.validate(), 'Invalid curve');
assert(this.g.mul(this.n).isInfinity(), 'Invalid curve, G*N != O');

As for older Node.js versions (0.10, 0.12) support -- those fail due to new syntax usage,
so we should either use older syntax to support those, or just drop those from support and test matrix.
I would suggest removing those, those reached EOL a long time ago.

@mvayngrib
Copy link
Collaborator Author

The checks removed in options.skipValidation block should probably be extracted into a testcase

good catch! pushed a test

Copy link

@kklash kklash left a comment

Choose a reason for hiding this comment

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

utACK

Copy link

@ChALkeR ChALkeR left a comment

Choose a reason for hiding this comment

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

utACK.

README.md Outdated Show resolved Hide resolved
Copy link

@gutenye gutenye left a comment

Choose a reason for hiding this comment

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

utACK

Copy link

@Sekhmet Sekhmet left a comment

Choose a reason for hiding this comment

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

tACK

Tested:

  • generating curves using the script.

@unidwell
Copy link

unidwell commented Aug 13, 2019

TLDR: Using precomputations does not work for multiple reasons. But, ecliptic library works as before only without precomputations. Will review again when fixed.

Simple proof

Default case, precomputed is calculated on the fly. It displays true.

var ec = elliptic.ec('p256');
console.log('isPrecomputed:', ec.g._hasDoubles(new BN(1)));

usePrecomputed does not work; it displays false.

elliptic.usePrecomputed({
  p256: require('../lib/elliptic/precomputed/p256');
});

var ec = elliptic.ec('p256');
console.log('isPrecomputed:', ec.g._hasDoubles(new BN(1)));

Explanation

It does not work, because toJSON is not matched somewhere with fromJSON. We have:

curves.forEach(({ name, curve }) => {
  const precomputed = curve.g.toJSON()
  fs.writeFileSync(getCurvePath(name), prettify(precomputed))
})

The EC point's toJSON creates a transformed JSON. We were unlucky the following did not break when curves are being loaded:

names.forEach(function(name) {
  if (!curves[name].g.precomputed) {
    curves[name].g.precomputed = precomputed[name];
  }
});

Possible solution

We patch elliptic/curve/index.js EC constructor like this (new option fromJSON):

function EC(options, fromJSON) {
  if (!(this instanceof EC))
    return new EC(options, fromJSON);

  // Shortcut `elliptic.ec(curve-name)`
  if (typeof options === 'string') {
    assert(elliptic.curves.hasOwnProperty(options), 'Unknown curve ' + options);

    options = elliptic.curves[options];
  }

  // Shortcut for `elliptic.ec(elliptic.curves.curveName)`
  if (options instanceof elliptic.curves.PresetCurve)
    options = { curve: options };

  this.curve = options.curve.curve;
  this.n = this.curve.n;
  this.nh = this.n.ushrn(1);
  this.g = this.curve.g;

  // Point on curve
  this.g = options.curve.g;
  if (fromJSON) {
    this.g = options.curve.curve.pointFromJSON(fromJSON)
  }
  else {
    this.g.precompute(options.curve.n.bitLength() + 1);
  }

  // Hash for function for DRBG
  this.hash = options.hash || options.curve.hash;
}

This will make the following example work correctly. It displays true:

var ec = elliptic.ec('p256', require('../lib/elliptic/precomputed/p256'));
console.log('isPrecomputed:', ec.g._hasDoubles(new BN(1)));

If we need complete compatibility with existing libs, it should be possible to monkey patch EC, so that elliptic.ec('p256') returns elliptic.ec('p256', require('../lib/elliptic/precomputed/p256'))

Unanswered questions

  • Currently only operations with EC point g are accelerated (the original library and our library). Not sure if that is necessary. A console.log in _hasDoubles can show, that for instance, multiplication could benefit two times, but precomputed is successfully used only once. Precomputations are probably still WIP in original lib.

@mvayngrib
Copy link
Collaborator Author

rebased on top of 6.4.1

@ChALkeR
Copy link

ChALkeR commented Sep 3, 2019

7cffa3b was ignored with the rebase?
Do we need those files in the package?
Upd: ah, only lib/ is packaged, sorry.

Another question -- hmac-drbg is moved to a separate module upstream, is that expected?
Just to make sure that this doesn't affect this PR.

ChALkeR
ChALkeR previously requested changes Sep 4, 2019
Copy link

@ChALkeR ChALkeR left a comment

Choose a reason for hiding this comment

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

secp256k1 precomputed curve should also be compared with computed during tests.
It looks reproducible with a simple change like if (name === 'secp256k1') computed = computed[2], but that's probably not a good way there (see below).

Currently, modifying secp256k1 precomputed curve file in a certain way still keeps the tests passing, that should not be the case.


Also: why is it split into a different *.js file instead of a json one?

Just to filter it out from e.g. tests based on the filename? Perhaps explicitly giving it a different suffix or a separate directory would be a better way to indicate that it uses a different format from all the other ones, than filtering based on .js/.json filename difference.

@ChALkeR ChALkeR dismissed their stale review September 4, 2019 00:36

secp256k1 is precomputed upstream

Copy link

@ChALkeR ChALkeR left a comment

Choose a reason for hiding this comment

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

Ok, I dismissed my prior review because, as @mvayngrib pointed out, secp256k1 is precomputed upstream and not introduced here. Thanks for explanation!

I do not have any specific concerns with the code anymore, but I would still recommend adding a test for secp256k1 precomputation upd: nevermind about that.

@mvayngrib
Copy link
Collaborator Author

mvayngrib commented Sep 5, 2019

@feri42 @roccomuso @unidwell do you guys want to take another look, or can we merge this?

@unidwell
Copy link

unidwell commented Sep 5, 2019

@mvayngrib Checked also changes since rebase, looks good.

@sonaye sonaye merged commit 91fb36e into master Sep 6, 2019
mvayngrib added a commit that referenced this pull request Aug 8, 2020
* add precomputed curves

* test precomputed curves

* skip validation for pre-defined curves

* add .vscode to .gitignore

* rm template literal to support earlier node.js versions

* yes, but actually use precomputed

* add use-precomputed-test

* reset require cache per test file

* fix typo

* embed skipValidation in options obj

* add test to check precomputed matches computed

* Update test/use-precomputed-test.js

Co-Authored-By: Сковорода Никита Андреевич <chalkerx@gmail.com>

* increase timeout for test

* fix node 0.10, 0.12 support

* add test to validate preset curves

* rm support for node 0.10, 0.11, 0.12

* fix links in readme

* rm coveralls from test suite

* fix use-precomputed

* fix use-precomputed test

* add breaking toJSON test

* fix Point.prototype.toJSON for short curves

* recompute short curves
ChALkeR pushed a commit that referenced this pull request Feb 11, 2021
* add precomputed curves

* test precomputed curves

* skip validation for pre-defined curves

* add .vscode to .gitignore

* rm template literal to support earlier node.js versions

* yes, but actually use precomputed

* add use-precomputed-test

* reset require cache per test file

* fix typo

* embed skipValidation in options obj

* add test to check precomputed matches computed

* Update test/use-precomputed-test.js

Co-Authored-By: Сковорода Никита Андреевич <chalkerx@gmail.com>

* increase timeout for test

* fix node 0.10, 0.12 support

* add test to validate preset curves

* rm support for node 0.10, 0.11, 0.12

* fix links in readme

* rm coveralls from test suite

* fix use-precomputed

* fix use-precomputed test

* add breaking toJSON test

* fix Point.prototype.toJSON for short curves

* recompute short curves
ChALkeR added a commit that referenced this pull request Mar 29, 2021
add script to compute precomputed curves, test with precomputed (#1) - rebased onto 6.5.4 + fixes
sparten11740 pushed a commit that referenced this pull request Nov 18, 2024
* add precomputed curves

* test precomputed curves

* skip validation for pre-defined curves

* add .vscode to .gitignore

* rm template literal to support earlier node.js versions

* yes, but actually use precomputed

* add use-precomputed-test

* reset require cache per test file

* fix typo

* embed skipValidation in options obj

* add test to check precomputed matches computed

* Update test/use-precomputed-test.js

Co-Authored-By: Сковорода Никита Андреевич <chalkerx@gmail.com>

* increase timeout for test

* fix node 0.10, 0.12 support

* add test to validate preset curves

* rm support for node 0.10, 0.11, 0.12

* fix links in readme

* rm coveralls from test suite

* fix use-precomputed

* fix use-precomputed test

* add breaking toJSON test

* fix Point.prototype.toJSON for short curves

* recompute short curves
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request performance
Projects
None yet
Development

Successfully merging this pull request may close these issues.

7 participants