├── dist
└── .gitkeep
├── .gitignore
├── .npmignore
├── lib
├── elliptic
│ ├── curve
│ │ ├── index.js
│ │ ├── mont.js
│ │ ├── base.js
│ │ ├── edwards.js
│ │ └── short.js
│ ├── eddsa
│ │ ├── signature.js
│ │ ├── key.js
│ │ └── index.js
│ ├── utils.js
│ ├── ec
│ │ ├── signature.js
│ │ ├── key.js
│ │ └── index.js
│ ├── curves.js
│ └── precomputed
│ │ └── secp256k1.js
└── elliptic.js
├── test
├── index.js
├── api-test.js
├── ecdh-test.js
├── unittests.html
├── ed25519-test.js
├── curve-test.js
└── ecdsa-test.js
├── .codeclimate.yml
├── benchmarks
├── package.json
└── index.js
├── .travis.yml
├── .jscsrc
├── package.json
├── Gruntfile.js
├── .jshintrc
└── README.md
/dist/.gitkeep:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | test/lib/
2 | node_modules/
3 | coverage/
4 | npm-debug.log
5 | 1.js
6 | v8.log
7 |
--------------------------------------------------------------------------------
/.npmignore:
--------------------------------------------------------------------------------
1 | dist/
2 | test/lib/
3 | node_modules/
4 | coverage/
5 | npm-debug.log
6 | 1.js
7 | v8.log
8 |
--------------------------------------------------------------------------------
/lib/elliptic/curve/index.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var curve = exports;
4 |
5 | curve.base = require('./base');
6 | curve.short = require('./short');
7 | curve.mont = require('./mont');
8 | curve.edwards = require('./edwards');
9 |
--------------------------------------------------------------------------------
/test/index.js:
--------------------------------------------------------------------------------
1 | describe('Test specs', function () {
2 | require('./api-test.js');
3 | require('./curve-test.js');
4 | require('./ecdh-test.js');
5 | require('./ecdsa-test.js');
6 | require('./ed25519-test.js');
7 | });
8 |
--------------------------------------------------------------------------------
/.codeclimate.yml:
--------------------------------------------------------------------------------
1 | ---
2 | engines:
3 | duplication:
4 | enabled: true
5 | config:
6 | languages:
7 | - javascript
8 | eslint:
9 | enabled: true
10 | fixme:
11 | enabled: true
12 | ratings:
13 | paths:
14 | - "lib/**/*"
15 |
--------------------------------------------------------------------------------
/lib/elliptic.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var elliptic = exports;
4 |
5 | elliptic.version = require('../package.json').version;
6 | elliptic.utils = require('./elliptic/utils');
7 | elliptic.rand = require('brorand');
8 | elliptic.curve = require('./elliptic/curve');
9 | elliptic.curves = require('./elliptic/curves');
10 |
11 | // Protocols
12 | elliptic.ec = require('./elliptic/ec');
13 | elliptic.eddsa = require('./elliptic/eddsa');
14 |
--------------------------------------------------------------------------------
/test/api-test.js:
--------------------------------------------------------------------------------
1 | var assert = require('assert');
2 | var elliptic = require('../');
3 |
4 | describe('EC API', function() {
5 | it('should instantiate with valid curve (secp256k1)', function() {
6 | var ec = new elliptic.ec('secp256k1');
7 |
8 | assert(ec);
9 | assert(typeof ec === 'object');
10 | });
11 |
12 | it('should throw error with invalid curve', function() {
13 | assert.throws(function() {
14 | var ec = new elliptic.ec('nonexistent-curve');
15 | }, Error);
16 | });
17 | });
18 |
--------------------------------------------------------------------------------
/benchmarks/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "bn.js-benchmark",
3 | "version": "0.0.0",
4 | "description": "",
5 | "main": "index.js",
6 | "scripts": {
7 | "test": "echo \"Error: no test specified\" && exit 1"
8 | },
9 | "author": "",
10 | "license": "MIT",
11 | "dependencies": {
12 | "benchmark": "^1.0.0",
13 | "eccjs": "^0.3.1",
14 | "ecdsa": "^0.6.0",
15 | "eckey": "^0.8.0",
16 | "hash.js": "^0.3.2",
17 | "jodid25519": "git://github.com/meganz/jodid25519.git",
18 | "secp256k1": "~0.0.13",
19 | "sjcl": "^1.0.1"
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/test/ecdh-test.js:
--------------------------------------------------------------------------------
1 | var assert = require('assert');
2 | var elliptic = require('../');
3 | var hash = require('hash.js');
4 |
5 | describe('ECDH', function() {
6 | function test(name) {
7 | it('should work with ' + name + ' curve', function() {
8 | var ecdh = new elliptic.ec(name);
9 | var s1 = ecdh.genKeyPair();
10 | var s2 = ecdh.genKeyPair();
11 | var sh1 = s1.derive(s2.getPublic());
12 | var sh2 = s2.derive(s1.getPublic());
13 |
14 | assert.equal(sh1.toString(16), sh2.toString(16));
15 |
16 | var sh1 = s1.derive(ecdh.keyFromPublic(s2.getPublic('hex'), 'hex')
17 | .getPublic());
18 | var sh2 = s2.derive(ecdh.keyFromPublic(s1.getPublic('hex'), 'hex')
19 | .getPublic());
20 | assert.equal(sh1.toString(16), sh2.toString(16));
21 | });
22 | }
23 |
24 | test('curve25519');
25 | test('ed25519');
26 | test('secp256k1');
27 | });
28 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | sudo: false
2 | os:
3 | - linux
4 | language: node_js
5 | node_js:
6 | - "0.10"
7 | - "0.11"
8 | - "0.12"
9 | - "4"
10 | - "5"
11 | env:
12 | global:
13 | - secure: ewqsRnX7z3+g6q+mM6peRPhuTlTlkJIRmVG/Ya9AcDXEb7as49KDTdqfMcOu7+FxF50ehqla+TRRCLRPOcVkWqs72OVUXEsjRASp9jQwpQGl+g/vZhyTMwlM2ENEkyiFQtobI1hYKgVW1ogftkc6vm7ywvoyTrFp/leVJBrTuHk=
14 | - secure: UcurJwykdbpUrAsrMox4BfiSGOWDIcI8ytBdxgK2vOC2biZJmkFXG4WfB6X2PwNvK4hx0z2s+VhxNVQRwtyl9mqyeAoAWjTpDg+NOoBgTu6Bacsobg29m65tD4x4Qc6iSmylRnfdb04Iob4rsnNNLZbIbERv3j3PFJMENUD3acQ=
15 | - secure: S8vAesx9V9o0/cJRmENJ76JrzSPLo8mtKAfDVHgcVG7Okfl7ANs+0cW1BtjZjBR63uQKJSmQEYC6N9eQlnNhCjeM7KXtFEbtD76OxvAABj4Sr9pIY06KUYLvBaGdYNmyT0WMIAaRN8SzY2uZEUaxMHmiEd1yOw6qQYBMCjbx0xg=
16 | matrix:
17 | - TEST_SUITE='npm run unit'
18 | matrix:
19 | include:
20 | - node_js: "4"
21 | env: TEST_SUITE='npm run lint'
22 | - node_js: "4"
23 | env: TEST_SUITE='grunt coveralls'
24 | - node_js: "4"
25 | env: TEST_SUITE='grunt saucelabs'
26 | allow_failures:
27 | - env: TEST_SUITE='grunt saucelabs'
28 | fast_finish: true
29 | cache:
30 | directories:
31 | - node_modules
32 | before_script:
33 | - npm install -g grunt-cli
34 | script:
35 | - $TEST_SUITE
36 |
--------------------------------------------------------------------------------
/test/unittests.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | scrypt-async Unit Tests
6 |
7 |
8 |
9 |
10 |
11 |
15 |
16 |
38 |
39 |
40 |
--------------------------------------------------------------------------------
/.jscsrc:
--------------------------------------------------------------------------------
1 | {
2 | "disallowKeywordsOnNewLine": [ "else" ],
3 | "disallowMixedSpacesAndTabs": true,
4 | "disallowMultipleLineStrings": true,
5 | "disallowMultipleVarDecl": true,
6 | "disallowNewlineBeforeBlockStatements": true,
7 | "disallowQuotedKeysInObjects": true,
8 | "disallowSpaceAfterObjectKeys": true,
9 | "disallowSpaceAfterPrefixUnaryOperators": true,
10 | "disallowSpaceBeforePostfixUnaryOperators": true,
11 | "disallowSpacesInCallExpression": true,
12 | "disallowTrailingComma": true,
13 | "disallowTrailingWhitespace": true,
14 | "disallowYodaConditions": true,
15 |
16 | "requireCommaBeforeLineBreak": true,
17 | "requireOperatorBeforeLineBreak": true,
18 | "requireSpaceAfterBinaryOperators": true,
19 | "requireSpaceAfterKeywords": [ "if", "for", "while", "else", "try", "catch" ],
20 | "requireSpaceAfterLineComment": true,
21 | "requireSpaceBeforeBinaryOperators": true,
22 | "requireSpaceBeforeBlockStatements": true,
23 | "requireSpaceBeforeKeywords": [ "else", "catch" ],
24 | "requireSpaceBeforeObjectValues": true,
25 | "requireSpaceBetweenArguments": true,
26 | "requireSpacesInAnonymousFunctionExpression": {
27 | "beforeOpeningCurlyBrace": true
28 | },
29 | "requireSpacesInFunctionDeclaration": {
30 | "beforeOpeningCurlyBrace": true
31 | },
32 | "requireSpacesInFunctionExpression": {
33 | "beforeOpeningCurlyBrace": true
34 | },
35 | "requireSpacesInConditionalExpression": true,
36 | "requireSpacesInForStatement": true,
37 | "requireSpacesInsideArrayBrackets": "all",
38 | "requireSpacesInsideObjectBrackets": "all",
39 | "requireDotNotation": true,
40 |
41 | "maximumLineLength": 80,
42 | "validateIndentation": 2,
43 | "validateLineBreaks": "LF",
44 | "validateParameterSeparator": ", ",
45 | "validateQuoteMarks": "'"
46 | }
47 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "elliptic",
3 | "version": "6.4.0",
4 | "description": "EC cryptography",
5 | "main": "lib/elliptic.js",
6 | "files": [
7 | "lib"
8 | ],
9 | "scripts": {
10 | "jscs": "jscs benchmarks/*.js lib/*.js lib/**/*.js lib/**/**/*.js test/index.js",
11 | "jshint": "jscs benchmarks/*.js lib/*.js lib/**/*.js lib/**/**/*.js test/index.js",
12 | "lint": "npm run jscs && npm run jshint",
13 | "unit": "istanbul test _mocha --reporter=spec test/index.js",
14 | "test": "npm run lint && npm run unit",
15 | "version": "grunt dist && git add dist/"
16 | },
17 | "repository": {
18 | "type": "git",
19 | "url": "git@github.com:indutny/elliptic"
20 | },
21 | "keywords": [
22 | "EC",
23 | "Elliptic",
24 | "curve",
25 | "Cryptography"
26 | ],
27 | "author": "Fedor Indutny ",
28 | "license": "MIT",
29 | "bugs": {
30 | "url": "https://github.com/indutny/elliptic/issues"
31 | },
32 | "homepage": "https://github.com/indutny/elliptic",
33 | "devDependencies": {
34 | "brfs": "^1.4.3",
35 | "coveralls": "^2.11.3",
36 | "grunt": "^0.4.5",
37 | "grunt-browserify": "^5.0.0",
38 | "grunt-cli": "^1.2.0",
39 | "grunt-contrib-connect": "^1.0.0",
40 | "grunt-contrib-copy": "^1.0.0",
41 | "grunt-contrib-uglify": "^1.0.1",
42 | "grunt-mocha-istanbul": "^3.0.1",
43 | "grunt-saucelabs": "^8.6.2",
44 | "istanbul": "^0.4.2",
45 | "jscs": "^2.9.0",
46 | "jshint": "^2.6.0",
47 | "mocha": "^2.1.0"
48 | },
49 | "dependencies": {
50 | "bn.js": "^4.4.0",
51 | "brorand": "^1.0.1",
52 | "hash.js": "^1.0.0",
53 | "hmac-drbg": "^1.0.0",
54 | "inherits": "^2.0.1",
55 | "minimalistic-assert": "^1.0.0",
56 | "minimalistic-crypto-utils": "^1.0.0"
57 | }
58 | }
59 |
--------------------------------------------------------------------------------
/lib/elliptic/eddsa/signature.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var BN = require('bn.js');
4 | var elliptic = require('../../elliptic');
5 | var utils = elliptic.utils;
6 | var assert = utils.assert;
7 | var cachedProperty = utils.cachedProperty;
8 | var parseBytes = utils.parseBytes;
9 |
10 | /**
11 | * @param {EDDSA} eddsa - eddsa instance
12 | * @param {Array|Object} sig -
13 | * @param {Array|Point} [sig.R] - R point as Point or bytes
14 | * @param {Array|bn} [sig.S] - S scalar as bn or bytes
15 | * @param {Array} [sig.Rencoded] - R point encoded
16 | * @param {Array} [sig.Sencoded] - S scalar encoded
17 | */
18 | function Signature(eddsa, sig) {
19 | this.eddsa = eddsa;
20 |
21 | if (typeof sig !== 'object')
22 | sig = parseBytes(sig);
23 |
24 | if (Array.isArray(sig)) {
25 | sig = {
26 | R: sig.slice(0, eddsa.encodingLength),
27 | S: sig.slice(eddsa.encodingLength)
28 | };
29 | }
30 |
31 | assert(sig.R && sig.S, 'Signature without R or S');
32 |
33 | if (eddsa.isPoint(sig.R))
34 | this._R = sig.R;
35 | if (sig.S instanceof BN)
36 | this._S = sig.S;
37 |
38 | this._Rencoded = Array.isArray(sig.R) ? sig.R : sig.Rencoded;
39 | this._Sencoded = Array.isArray(sig.S) ? sig.S : sig.Sencoded;
40 | }
41 |
42 | cachedProperty(Signature, 'S', function S() {
43 | return this.eddsa.decodeInt(this.Sencoded());
44 | });
45 |
46 | cachedProperty(Signature, 'R', function R() {
47 | return this.eddsa.decodePoint(this.Rencoded());
48 | });
49 |
50 | cachedProperty(Signature, 'Rencoded', function Rencoded() {
51 | return this.eddsa.encodePoint(this.R());
52 | });
53 |
54 | cachedProperty(Signature, 'Sencoded', function Sencoded() {
55 | return this.eddsa.encodeInt(this.S());
56 | });
57 |
58 | Signature.prototype.toBytes = function toBytes() {
59 | return this.Rencoded().concat(this.Sencoded());
60 | };
61 |
62 | Signature.prototype.toHex = function toHex() {
63 | return utils.encode(this.toBytes(), 'hex').toUpperCase();
64 | };
65 |
66 | module.exports = Signature;
67 |
--------------------------------------------------------------------------------
/lib/elliptic/eddsa/key.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var elliptic = require('../../elliptic');
4 | var utils = elliptic.utils;
5 | var assert = utils.assert;
6 | var parseBytes = utils.parseBytes;
7 | var cachedProperty = utils.cachedProperty;
8 |
9 | /**
10 | * @param {EDDSA} eddsa - instance
11 | * @param {Object} params - public/private key parameters
12 | *
13 | * @param {Array} [params.secret] - secret seed bytes
14 | * @param {Point} [params.pub] - public key point (aka `A` in eddsa terms)
15 | * @param {Array} [params.pub] - public key point encoded as bytes
16 | *
17 | */
18 | function KeyPair(eddsa, params) {
19 | this.eddsa = eddsa;
20 | this._secret = parseBytes(params.secret);
21 | if (eddsa.isPoint(params.pub))
22 | this._pub = params.pub;
23 | else
24 | this._pubBytes = parseBytes(params.pub);
25 | }
26 |
27 | KeyPair.fromPublic = function fromPublic(eddsa, pub) {
28 | if (pub instanceof KeyPair)
29 | return pub;
30 | return new KeyPair(eddsa, { pub: pub });
31 | };
32 |
33 | KeyPair.fromSecret = function fromSecret(eddsa, secret) {
34 | if (secret instanceof KeyPair)
35 | return secret;
36 | return new KeyPair(eddsa, { secret: secret });
37 | };
38 |
39 | KeyPair.prototype.secret = function secret() {
40 | return this._secret;
41 | };
42 |
43 | cachedProperty(KeyPair, 'pubBytes', function pubBytes() {
44 | return this.eddsa.encodePoint(this.pub());
45 | });
46 |
47 | cachedProperty(KeyPair, 'pub', function pub() {
48 | if (this._pubBytes)
49 | return this.eddsa.decodePoint(this._pubBytes);
50 | return this.eddsa.g.mul(this.priv());
51 | });
52 |
53 | cachedProperty(KeyPair, 'privBytes', function privBytes() {
54 | var eddsa = this.eddsa;
55 | var hash = this.hash();
56 | var lastIx = eddsa.encodingLength - 1;
57 |
58 | var a = hash.slice(0, eddsa.encodingLength);
59 | a[0] &= 248;
60 | a[lastIx] &= 127;
61 | a[lastIx] |= 64;
62 |
63 | return a;
64 | });
65 |
66 | cachedProperty(KeyPair, 'priv', function priv() {
67 | return this.eddsa.decodeInt(this.privBytes());
68 | });
69 |
70 | cachedProperty(KeyPair, 'hash', function hash() {
71 | return this.eddsa.hash().update(this.secret()).digest();
72 | });
73 |
74 | cachedProperty(KeyPair, 'messagePrefix', function messagePrefix() {
75 | return this.hash().slice(this.eddsa.encodingLength);
76 | });
77 |
78 | KeyPair.prototype.sign = function sign(message) {
79 | assert(this._secret, 'KeyPair can only verify');
80 | return this.eddsa.sign(message, this);
81 | };
82 |
83 | KeyPair.prototype.verify = function verify(message, sig) {
84 | return this.eddsa.verify(message, sig, this);
85 | };
86 |
87 | KeyPair.prototype.getSecret = function getSecret(enc) {
88 | assert(this._secret, 'KeyPair is public only');
89 | return utils.encode(this.secret(), enc);
90 | };
91 |
92 | KeyPair.prototype.getPublic = function getPublic(enc) {
93 | return utils.encode(this.pubBytes(), enc);
94 | };
95 |
96 | module.exports = KeyPair;
97 |
--------------------------------------------------------------------------------
/lib/elliptic/utils.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var utils = exports;
4 | var BN = require('bn.js');
5 | var minAssert = require('minimalistic-assert');
6 | var minUtils = require('minimalistic-crypto-utils');
7 |
8 | utils.assert = minAssert;
9 | utils.toArray = minUtils.toArray;
10 | utils.zero2 = minUtils.zero2;
11 | utils.toHex = minUtils.toHex;
12 | utils.encode = minUtils.encode;
13 |
14 | // Represent num in a w-NAF form
15 | function getNAF(num, w) {
16 | var naf = [];
17 | var ws = 1 << (w + 1);
18 | var k = num.clone();
19 | while (k.cmpn(1) >= 0) {
20 | var z;
21 | if (k.isOdd()) {
22 | var mod = k.andln(ws - 1);
23 | if (mod > (ws >> 1) - 1)
24 | z = (ws >> 1) - mod;
25 | else
26 | z = mod;
27 | k.isubn(z);
28 | } else {
29 | z = 0;
30 | }
31 | naf.push(z);
32 |
33 | // Optimization, shift by word if possible
34 | var shift = (k.cmpn(0) !== 0 && k.andln(ws - 1) === 0) ? (w + 1) : 1;
35 | for (var i = 1; i < shift; i++)
36 | naf.push(0);
37 | k.iushrn(shift);
38 | }
39 |
40 | return naf;
41 | }
42 | utils.getNAF = getNAF;
43 |
44 | // Represent k1, k2 in a Joint Sparse Form
45 | function getJSF(k1, k2) {
46 | var jsf = [
47 | [],
48 | []
49 | ];
50 |
51 | k1 = k1.clone();
52 | k2 = k2.clone();
53 | var d1 = 0;
54 | var d2 = 0;
55 | while (k1.cmpn(-d1) > 0 || k2.cmpn(-d2) > 0) {
56 |
57 | // First phase
58 | var m14 = (k1.andln(3) + d1) & 3;
59 | var m24 = (k2.andln(3) + d2) & 3;
60 | if (m14 === 3)
61 | m14 = -1;
62 | if (m24 === 3)
63 | m24 = -1;
64 | var u1;
65 | if ((m14 & 1) === 0) {
66 | u1 = 0;
67 | } else {
68 | var m8 = (k1.andln(7) + d1) & 7;
69 | if ((m8 === 3 || m8 === 5) && m24 === 2)
70 | u1 = -m14;
71 | else
72 | u1 = m14;
73 | }
74 | jsf[0].push(u1);
75 |
76 | var u2;
77 | if ((m24 & 1) === 0) {
78 | u2 = 0;
79 | } else {
80 | var m8 = (k2.andln(7) + d2) & 7;
81 | if ((m8 === 3 || m8 === 5) && m14 === 2)
82 | u2 = -m24;
83 | else
84 | u2 = m24;
85 | }
86 | jsf[1].push(u2);
87 |
88 | // Second phase
89 | if (2 * d1 === u1 + 1)
90 | d1 = 1 - d1;
91 | if (2 * d2 === u2 + 1)
92 | d2 = 1 - d2;
93 | k1.iushrn(1);
94 | k2.iushrn(1);
95 | }
96 |
97 | return jsf;
98 | }
99 | utils.getJSF = getJSF;
100 |
101 | function cachedProperty(obj, name, computer) {
102 | var key = '_' + name;
103 | obj.prototype[name] = function cachedProperty() {
104 | return this[key] !== undefined ? this[key] :
105 | this[key] = computer.call(this);
106 | };
107 | }
108 | utils.cachedProperty = cachedProperty;
109 |
110 | function parseBytes(bytes) {
111 | return typeof bytes === 'string' ? utils.toArray(bytes, 'hex') :
112 | bytes;
113 | }
114 | utils.parseBytes = parseBytes;
115 |
116 | function intFromLE(bytes) {
117 | return new BN(bytes, 'hex', 'le');
118 | }
119 | utils.intFromLE = intFromLE;
120 |
121 |
--------------------------------------------------------------------------------
/lib/elliptic/ec/signature.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var BN = require('bn.js');
4 |
5 | var elliptic = require('../../elliptic');
6 | var utils = elliptic.utils;
7 | var assert = utils.assert;
8 |
9 | function Signature(options, enc) {
10 | if (options instanceof Signature)
11 | return options;
12 |
13 | if (this._importDER(options, enc))
14 | return;
15 |
16 | assert(options.r && options.s, 'Signature without r or s');
17 | this.r = new BN(options.r, 16);
18 | this.s = new BN(options.s, 16);
19 | if (options.recoveryParam === undefined)
20 | this.recoveryParam = null;
21 | else
22 | this.recoveryParam = options.recoveryParam;
23 | }
24 | module.exports = Signature;
25 |
26 | function Position() {
27 | this.place = 0;
28 | }
29 |
30 | function getLength(buf, p) {
31 | var initial = buf[p.place++];
32 | if (!(initial & 0x80)) {
33 | return initial;
34 | }
35 | var octetLen = initial & 0xf;
36 | var val = 0;
37 | for (var i = 0, off = p.place; i < octetLen; i++, off++) {
38 | val <<= 8;
39 | val |= buf[off];
40 | }
41 | p.place = off;
42 | return val;
43 | }
44 |
45 | function rmPadding(buf) {
46 | var i = 0;
47 | var len = buf.length - 1;
48 | while (!buf[i] && !(buf[i + 1] & 0x80) && i < len) {
49 | i++;
50 | }
51 | if (i === 0) {
52 | return buf;
53 | }
54 | return buf.slice(i);
55 | }
56 |
57 | Signature.prototype._importDER = function _importDER(data, enc) {
58 | data = utils.toArray(data, enc);
59 | var p = new Position();
60 | if (data[p.place++] !== 0x30) {
61 | return false;
62 | }
63 | var len = getLength(data, p);
64 | if ((len + p.place) !== data.length) {
65 | return false;
66 | }
67 | if (data[p.place++] !== 0x02) {
68 | return false;
69 | }
70 | var rlen = getLength(data, p);
71 | var r = data.slice(p.place, rlen + p.place);
72 | p.place += rlen;
73 | if (data[p.place++] !== 0x02) {
74 | return false;
75 | }
76 | var slen = getLength(data, p);
77 | if (data.length !== slen + p.place) {
78 | return false;
79 | }
80 | var s = data.slice(p.place, slen + p.place);
81 | if (r[0] === 0 && (r[1] & 0x80)) {
82 | r = r.slice(1);
83 | }
84 | if (s[0] === 0 && (s[1] & 0x80)) {
85 | s = s.slice(1);
86 | }
87 |
88 | this.r = new BN(r);
89 | this.s = new BN(s);
90 | this.recoveryParam = null;
91 |
92 | return true;
93 | };
94 |
95 | function constructLength(arr, len) {
96 | if (len < 0x80) {
97 | arr.push(len);
98 | return;
99 | }
100 | var octets = 1 + (Math.log(len) / Math.LN2 >>> 3);
101 | arr.push(octets | 0x80);
102 | while (--octets) {
103 | arr.push((len >>> (octets << 3)) & 0xff);
104 | }
105 | arr.push(len);
106 | }
107 |
108 | Signature.prototype.toDER = function toDER(enc) {
109 | var r = this.r.toArray();
110 | var s = this.s.toArray();
111 |
112 | // Pad values
113 | if (r[0] & 0x80)
114 | r = [ 0 ].concat(r);
115 | // Pad values
116 | if (s[0] & 0x80)
117 | s = [ 0 ].concat(s);
118 |
119 | r = rmPadding(r);
120 | s = rmPadding(s);
121 |
122 | while (!s[0] && !(s[1] & 0x80)) {
123 | s = s.slice(1);
124 | }
125 | var arr = [ 0x02 ];
126 | constructLength(arr, r.length);
127 | arr = arr.concat(r);
128 | arr.push(0x02);
129 | constructLength(arr, s.length);
130 | var backHalf = arr.concat(s);
131 | var res = [ 0x30 ];
132 | constructLength(res, backHalf.length);
133 | res = res.concat(backHalf);
134 | return utils.encode(res, enc);
135 | };
136 |
--------------------------------------------------------------------------------
/lib/elliptic/ec/key.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var BN = require('bn.js');
4 | var elliptic = require('../../elliptic');
5 | var utils = elliptic.utils;
6 | var assert = utils.assert;
7 |
8 | function KeyPair(ec, options) {
9 | this.ec = ec;
10 | this.priv = null;
11 | this.pub = null;
12 |
13 | // KeyPair(ec, { priv: ..., pub: ... })
14 | if (options.priv)
15 | this._importPrivate(options.priv, options.privEnc);
16 | if (options.pub)
17 | this._importPublic(options.pub, options.pubEnc);
18 | }
19 | module.exports = KeyPair;
20 |
21 | KeyPair.fromPublic = function fromPublic(ec, pub, enc) {
22 | if (pub instanceof KeyPair)
23 | return pub;
24 |
25 | return new KeyPair(ec, {
26 | pub: pub,
27 | pubEnc: enc
28 | });
29 | };
30 |
31 | KeyPair.fromPrivate = function fromPrivate(ec, priv, enc) {
32 | if (priv instanceof KeyPair)
33 | return priv;
34 |
35 | return new KeyPair(ec, {
36 | priv: priv,
37 | privEnc: enc
38 | });
39 | };
40 |
41 | KeyPair.prototype.validate = function validate() {
42 | var pub = this.getPublic();
43 |
44 | if (pub.isInfinity())
45 | return { result: false, reason: 'Invalid public key' };
46 | if (!pub.validate())
47 | return { result: false, reason: 'Public key is not a point' };
48 | if (!pub.mul(this.ec.curve.n).isInfinity())
49 | return { result: false, reason: 'Public key * N != O' };
50 |
51 | return { result: true, reason: null };
52 | };
53 |
54 | KeyPair.prototype.getPublic = function getPublic(compact, enc) {
55 | // compact is optional argument
56 | if (typeof compact === 'string') {
57 | enc = compact;
58 | compact = null;
59 | }
60 |
61 | if (!this.pub)
62 | this.pub = this.ec.g.mul(this.priv);
63 |
64 | if (!enc)
65 | return this.pub;
66 |
67 | return this.pub.encode(enc, compact);
68 | };
69 |
70 | KeyPair.prototype.getPrivate = function getPrivate(enc) {
71 | if (enc === 'hex')
72 | return this.priv.toString(16, 2);
73 | else
74 | return this.priv;
75 | };
76 |
77 | KeyPair.prototype._importPrivate = function _importPrivate(key, enc) {
78 | this.priv = new BN(key, enc || 16);
79 |
80 | // Ensure that the priv won't be bigger than n, otherwise we may fail
81 | // in fixed multiplication method
82 | this.priv = this.priv.umod(this.ec.curve.n);
83 | };
84 |
85 | KeyPair.prototype._importPublic = function _importPublic(key, enc) {
86 | if (key.x || key.y) {
87 | // Montgomery points only have an `x` coordinate.
88 | // Weierstrass/Edwards points on the other hand have both `x` and
89 | // `y` coordinates.
90 | if (this.ec.curve.type === 'mont') {
91 | assert(key.x, 'Need x coordinate');
92 | } else if (this.ec.curve.type === 'short' ||
93 | this.ec.curve.type === 'edwards') {
94 | assert(key.x && key.y, 'Need both x and y coordinate');
95 | }
96 | this.pub = this.ec.curve.point(key.x, key.y);
97 | return;
98 | }
99 | this.pub = this.ec.curve.decodePoint(key, enc);
100 | };
101 |
102 | // ECDH
103 | KeyPair.prototype.derive = function derive(pub) {
104 | return pub.mul(this.priv).getX();
105 | };
106 |
107 | // ECDSA
108 | KeyPair.prototype.sign = function sign(msg, enc, options) {
109 | return this.ec.sign(msg, this, enc, options);
110 | };
111 |
112 | KeyPair.prototype.verify = function verify(msg, signature) {
113 | return this.ec.verify(msg, signature, this);
114 | };
115 |
116 | KeyPair.prototype.inspect = function inspect() {
117 | return '';
119 | };
120 |
--------------------------------------------------------------------------------
/lib/elliptic/eddsa/index.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var hash = require('hash.js');
4 | var elliptic = require('../../elliptic');
5 | var utils = elliptic.utils;
6 | var assert = utils.assert;
7 | var parseBytes = utils.parseBytes;
8 | var KeyPair = require('./key');
9 | var Signature = require('./signature');
10 |
11 | function EDDSA(curve) {
12 | assert(curve === 'ed25519', 'only tested with ed25519 so far');
13 |
14 | if (!(this instanceof EDDSA))
15 | return new EDDSA(curve);
16 |
17 | var curve = elliptic.curves[curve].curve;
18 | this.curve = curve;
19 | this.g = curve.g;
20 | this.g.precompute(curve.n.bitLength() + 1);
21 |
22 | this.pointClass = curve.point().constructor;
23 | this.encodingLength = Math.ceil(curve.n.bitLength() / 8);
24 | this.hash = hash.sha512;
25 | }
26 |
27 | module.exports = EDDSA;
28 |
29 | /**
30 | * @param {Array|String} message - message bytes
31 | * @param {Array|String|KeyPair} secret - secret bytes or a keypair
32 | * @returns {Signature} - signature
33 | */
34 | EDDSA.prototype.sign = function sign(message, secret) {
35 | message = parseBytes(message);
36 | var key = this.keyFromSecret(secret);
37 | var r = this.hashInt(key.messagePrefix(), message);
38 | var R = this.g.mul(r);
39 | var Rencoded = this.encodePoint(R);
40 | var s_ = this.hashInt(Rencoded, key.pubBytes(), message)
41 | .mul(key.priv());
42 | var S = r.add(s_).umod(this.curve.n);
43 | return this.makeSignature({ R: R, S: S, Rencoded: Rencoded });
44 | };
45 |
46 | /**
47 | * @param {Array} message - message bytes
48 | * @param {Array|String|Signature} sig - sig bytes
49 | * @param {Array|String|Point|KeyPair} pub - public key
50 | * @returns {Boolean} - true if public key matches sig of message
51 | */
52 | EDDSA.prototype.verify = function verify(message, sig, pub) {
53 | message = parseBytes(message);
54 | sig = this.makeSignature(sig);
55 | var key = this.keyFromPublic(pub);
56 | var h = this.hashInt(sig.Rencoded(), key.pubBytes(), message);
57 | var SG = this.g.mul(sig.S());
58 | var RplusAh = sig.R().add(key.pub().mul(h));
59 | return RplusAh.eq(SG);
60 | };
61 |
62 | EDDSA.prototype.hashInt = function hashInt() {
63 | var hash = this.hash();
64 | for (var i = 0; i < arguments.length; i++)
65 | hash.update(arguments[i]);
66 | return utils.intFromLE(hash.digest()).umod(this.curve.n);
67 | };
68 |
69 | EDDSA.prototype.keyFromPublic = function keyFromPublic(pub) {
70 | return KeyPair.fromPublic(this, pub);
71 | };
72 |
73 | EDDSA.prototype.keyFromSecret = function keyFromSecret(secret) {
74 | return KeyPair.fromSecret(this, secret);
75 | };
76 |
77 | EDDSA.prototype.makeSignature = function makeSignature(sig) {
78 | if (sig instanceof Signature)
79 | return sig;
80 | return new Signature(this, sig);
81 | };
82 |
83 | /**
84 | * * https://tools.ietf.org/html/draft-josefsson-eddsa-ed25519-03#section-5.2
85 | *
86 | * EDDSA defines methods for encoding and decoding points and integers. These are
87 | * helper convenience methods, that pass along to utility functions implied
88 | * parameters.
89 | *
90 | */
91 | EDDSA.prototype.encodePoint = function encodePoint(point) {
92 | var enc = point.getY().toArray('le', this.encodingLength);
93 | enc[this.encodingLength - 1] |= point.getX().isOdd() ? 0x80 : 0;
94 | return enc;
95 | };
96 |
97 | EDDSA.prototype.decodePoint = function decodePoint(bytes) {
98 | bytes = utils.parseBytes(bytes);
99 |
100 | var lastIx = bytes.length - 1;
101 | var normed = bytes.slice(0, lastIx).concat(bytes[lastIx] & ~0x80);
102 | var xIsOdd = (bytes[lastIx] & 0x80) !== 0;
103 |
104 | var y = utils.intFromLE(normed);
105 | return this.curve.pointFromY(y, xIsOdd);
106 | };
107 |
108 | EDDSA.prototype.encodeInt = function encodeInt(num) {
109 | return num.toArray('le', this.encodingLength);
110 | };
111 |
112 | EDDSA.prototype.decodeInt = function decodeInt(bytes) {
113 | return utils.intFromLE(bytes);
114 | };
115 |
116 | EDDSA.prototype.isPoint = function isPoint(val) {
117 | return val instanceof this.pointClass;
118 | };
119 |
--------------------------------------------------------------------------------
/benchmarks/index.js:
--------------------------------------------------------------------------------
1 | var assert = require('assert');
2 | var benchmark = require('benchmark');
3 | var crypto = require('crypto');
4 | var hash = require('hash.js');
5 | var elliptic = require('../');
6 | var eccjs = require('eccjs');
7 | var jodid = require('./deps/jodid');
8 | var ecdsa = require('ecdsa');
9 | var ECKey = require('eckey');
10 | var secp256k1 = require('secp256k1');
11 |
12 | var benchmarks = [];
13 | var maxTime = 10;
14 |
15 | function add(op, obj) {
16 | benchmarks.push({
17 | name: op,
18 | start: function start() {
19 | var suite = new benchmark.Suite;
20 |
21 | console.log('Benchmarking: ' + op);
22 | Object.keys(obj).forEach(function(key) {
23 | suite.add(key + '#' + op, obj[key], { maxTime: maxTime })
24 | });
25 |
26 | suite
27 | .on('cycle', function(event) {
28 | console.log(String(event.target));
29 | })
30 | .on('complete', function() {
31 | console.log('------------------------');
32 | console.log('Fastest is ' + this.filter('fastest').pluck('name'));
33 | })
34 | .run();
35 | console.log('========================');
36 | }
37 | });
38 | }
39 |
40 | function start() {
41 | var re = process.argv[2] ? new RegExp(process.argv[2], 'i') : /./;
42 |
43 | benchmarks.filter(function(b) {
44 | return re.test(b.name);
45 | }).forEach(function(b) {
46 | b.start();
47 | });
48 | }
49 |
50 | var str = 'big benchmark against elliptic';
51 |
52 | var m1 = hash.sha256().update(str).digest();
53 | var c1 = elliptic.ec(elliptic.curves.secp256k1);
54 | var k1 = c1.genKeyPair();
55 | var s1 = c1.sign(m1, k1);
56 | var ok = '-----BEGIN EC PARAMETERS-----\n' +
57 | 'BgUrgQQACg==\n' +
58 | '-----END EC PARAMETERS-----\n' +
59 | '-----BEGIN EC PRIVATE KEY-----\n' +
60 | 'MHQCAQEEIEWQfsvf8TdY+F2ziHut3Fl+LVdCHAQBLxeKn3v79M1LoAcGBSuBBAAK\n' +
61 | 'oUQDQgAEM7DB6MG6T5nGSwougzGIXVypXb81EerftCyqTc7v/rjmLobz5ZJHGALh\n' +
62 | 'ne+0Gdz5ZytFHQCTkUlU85Mz8SPjWg==\n' +
63 | '-----END EC PRIVATE KEY-----';
64 | assert(c1.verify(m1, s1, k1));
65 |
66 | var m2 = eccjs.sjcl.hash.sha256.hash('big benchmark against elliptic');
67 | var c2 = eccjs.sjcl.ecc.curves.k256;
68 | var k2 = eccjs.sjcl.ecc.ecdsa.generateKeys(c2, 0);
69 | var s2 = k2.sec.sign(m2, 0);
70 | assert(k2.pub.verify(m2, s2));
71 |
72 | var m3 = crypto.createHash('sha256').update(str).digest();
73 | var k3 = new ECKey(crypto.randomBytes(32));
74 | var s3 = ecdsa.sign(m3, k3.privateKey);
75 | assert(ecdsa.verify(m3, s3, k3.publicKey));
76 |
77 | var m4 = crypto.createHash('sha256').update(str).digest();
78 | var k4priv = crypto.randomBytes(32);
79 | var k4pub = secp256k1.createPublicKey(k4priv);
80 | var s4 = secp256k1.sign(k4priv, m4);
81 | assert(secp256k1.verify(k4pub, m4, s4) > 0);
82 |
83 | add('sign', {
84 | elliptic: function() {
85 | c1.sign(m1, k1);
86 | },
87 | sjcl: function() {
88 | k2.sec.sign(m2, 0);
89 | },
90 | openssl: function() {
91 | crypto.createSign('RSA-SHA256').update(str).sign(ok);
92 | },
93 | ecdsa: function() {
94 | ecdsa.sign(m3, k3.privateKey);
95 | },
96 | secp256k1: function() {
97 | secp256k1.sign(k4priv, m4);
98 | }
99 | });
100 |
101 | var os1 = crypto.createSign('RSA-SHA256').update(str).sign(ok);
102 | var opk = '-----BEGIN PUBLIC KEY-----\n' +
103 | 'MFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEM7DB6MG6T5nGSwougzGIXVypXb81Eerf\n' +
104 | 'tCyqTc7v/rjmLobz5ZJHGALhne+0Gdz5ZytFHQCTkUlU85Mz8SPjWg==\n' +
105 | '-----END PUBLIC KEY-----';
106 | add('verify', {
107 | elliptic: function() {
108 | c1.verify(m1, s1, k1);
109 | },
110 | sjcl: function() {
111 | k2.pub.verify(m2, s2);
112 | },
113 | openssl: function() {
114 | crypto.createVerify('RSA-SHA256').update(str).verify(opk, os1);
115 | },
116 | ecdsa: function() {
117 | ecdsa.verify(m3, s3, k3.publicKey);
118 | },
119 | secp256k1: function() {
120 | secp256k1.verify(k4pub, m4, s4);
121 | }
122 | });
123 |
124 | add('gen', {
125 | elliptic: function() {
126 | c1.genKeyPair().getPublic();
127 | },
128 | sjcl: function() {
129 | eccjs.sjcl.ecc.ecdsa.generateKeys(c2, 0);
130 | }
131 | });
132 |
133 | add('ecdh', {
134 | elliptic: function() {
135 | c1.genKeyPair().derive(k1.getPublic());
136 | }
137 | });
138 |
139 | var cu1 = elliptic.ec('curve25519');
140 | var ku1 = cu1.genKeyPair();
141 | var kp2 = jodid.eddsa.genKeySeed();
142 |
143 | add('curve25519', {
144 | elliptic: function() {
145 | var s = ku1.derive(cu1.genKeyPair().getPublic());
146 | },
147 | jodid: function() {
148 | var s = jodid.dh.computeKey(kp2,
149 | jodid.dh.publicKey(jodid.eddsa.genKeySeed()));
150 | }
151 | });
152 |
153 | start();
154 |
--------------------------------------------------------------------------------
/test/ed25519-test.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var assert = require('assert');
4 | var elliptic = require('../');
5 | var utils = elliptic.utils;
6 | var toArray = elliptic.utils.toArray;
7 | var eddsa = elliptic.eddsa;
8 |
9 | function toHex(arr) {
10 | return elliptic.utils.toHex(arr).toUpperCase();
11 | }
12 |
13 | var MAX_PROGRAMMATIC = process.env.CI ? Infinity : 50;
14 |
15 | describe('ed25519 derivations', function() {
16 | var expectedTests = 256;
17 | var ed25519;
18 | var derivations;
19 |
20 | before(function() {
21 | ed25519 = new eddsa('ed25519');
22 | derivations = require('./fixtures/derivation-fixtures');
23 | assert.equal(derivations.length, expectedTests);
24 | });
25 |
26 | function testFactory(i) {
27 | it('can compute correct a and A for secret: ' + i, function() {
28 | var test = derivations[i];
29 | var secret = utils.toArray(test.secret_hex, 'hex');
30 | var key = ed25519.keyFromSecret(secret);
31 | assert.equal(toHex(key.privBytes()), test.a_hex);
32 | var xRecovered = toHex(ed25519.encodeInt(
33 | ed25519.decodePoint(key.pubBytes()).getX()));
34 | assert.equal(xRecovered, test.A_P.x);
35 | assert.equal(toHex(key.pubBytes()), test.A_hex);
36 | });
37 | }
38 |
39 | for (var i = 0; i < Math.min(expectedTests, MAX_PROGRAMMATIC); i++)
40 | testFactory(i);
41 | });
42 |
43 | describe('sign.input ed25519 test vectors', function() {
44 | var expectedTests = 1024;
45 | var ed25519;
46 | var lines;
47 |
48 | before(function(done) {
49 | ed25519 = new eddsa('ed25519');
50 | require('fs').readFile(__dirname + '/fixtures/sign.input', function(err, f) {
51 | lines = f.toString().split('\n');
52 | assert.equal(lines.length, expectedTests + 1 /*blank line*/);
53 | done();
54 | });
55 | });
56 |
57 | function testFactory(i) {
58 | it('vector ' + i, function() {
59 | var split = lines[i].toUpperCase().split(':');
60 | var key = ed25519.keyFromSecret(split[0].slice(0, 64));
61 | var expectedPk = split[0].slice(64);
62 |
63 | assert.equal(toHex(key.pubBytes()), expectedPk);
64 |
65 | var msg = toArray(split[2], 'hex');
66 | var sig = key.sign(msg).toHex();
67 | var sigR = sig.slice(0, 64);
68 | var sigS = sig.slice(64);
69 |
70 | assert.equal(sigR, split[3].slice(0, 64));
71 | assert.equal(sigS, split[3].slice(64, 128));
72 | assert(key.verify(msg, sig));
73 |
74 | var forged = msg.length === 0 ? [ 0x78 ] /*ord('x')*/:
75 | msg.slice(0, msg.length - 1).concat(
76 | (msg[(msg.length - 1)] + 1) % 256);
77 |
78 | assert.equal(msg.length || 1, forged.length);
79 | assert(!key.verify(forged, sig));
80 | });
81 | }
82 | for (var i = 0; i < Math.min(expectedTests, MAX_PROGRAMMATIC); i++)
83 | testFactory(i);
84 | });
85 |
86 | describe('EDDSA(\'ed25519\')', function() {
87 | var ed25519;
88 |
89 | before(function() {
90 | ed25519 = new eddsa('ed25519');
91 | });
92 |
93 | it('has encodingLength of 32', function() {
94 | assert.equal(32, ed25519.encodingLength);
95 | });
96 |
97 | it('can sign/verify messages', function() {
98 | var secret = toArray(new Array(65).join('0'), 'hex');
99 | assert(secret.length === 32);
100 | var msg = [ 0xB, 0xE, 0xE, 0xF ];
101 | var key = ed25519.keyFromSecret(secret);
102 | var sig = key.sign(msg).toHex();
103 |
104 | var R = '8F1B9A7FDB22BCD2C15D4695B1CE2B063CBFAEC9B00BE360427BAC9533943F6C';
105 | var S = '5F0B380FD7F2E43B70AB2FA29F6C6E3FFC1012710E174786814012324BF19B0C';
106 |
107 | assert.equal(sig.slice(0, 64), R);
108 | assert.equal(sig.slice(64), S);
109 |
110 | assert(key.verify(msg, sig));
111 | });
112 |
113 | describe('KeyPair', function() {
114 | var pair;
115 | var secret = '00000000000000000000000000000000' +
116 | '00000000000000000000000000000000';
117 |
118 | before(function() {
119 | pair = ed25519.keyFromSecret(secret);
120 | });
121 |
122 | it('can be created with keyFromSecret/keyFromPublic', function() {
123 | var pubKey = ed25519.keyFromPublic(toHex(pair.pubBytes()));
124 | assert(pubKey.pub() instanceof ed25519.pointClass);
125 | assert(pubKey.pub().eq(pair.pub()));
126 | });
127 | it('#getSecret returns bytes with optional encoding', function() {
128 | assert(Array.isArray(pair.getSecret()));
129 | assert(pair.getSecret('hex') === secret);
130 | });
131 | it('#getPub returns bytes with optional encoding', function() {
132 | assert(Array.isArray(pair.getPublic()));
133 | assert.equal(pair.getPublic('hex'),
134 | '3b6a27bcceb6a42d62a3a8d02a6f0d73653215771de243a63ac048a18b59da29');
135 | });
136 | });
137 | });
138 |
--------------------------------------------------------------------------------
/lib/elliptic/curve/mont.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var curve = require('../curve');
4 | var BN = require('bn.js');
5 | var inherits = require('inherits');
6 | var Base = curve.base;
7 |
8 | var elliptic = require('../../elliptic');
9 | var utils = elliptic.utils;
10 |
11 | function MontCurve(conf) {
12 | Base.call(this, 'mont', conf);
13 |
14 | this.a = new BN(conf.a, 16).toRed(this.red);
15 | this.b = new BN(conf.b, 16).toRed(this.red);
16 | this.i4 = new BN(4).toRed(this.red).redInvm();
17 | this.two = new BN(2).toRed(this.red);
18 | this.a24 = this.i4.redMul(this.a.redAdd(this.two));
19 | }
20 | inherits(MontCurve, Base);
21 | module.exports = MontCurve;
22 |
23 | MontCurve.prototype.validate = function validate(point) {
24 | var x = point.normalize().x;
25 | var x2 = x.redSqr();
26 | var rhs = x2.redMul(x).redAdd(x2.redMul(this.a)).redAdd(x);
27 | var y = rhs.redSqrt();
28 |
29 | return y.redSqr().cmp(rhs) === 0;
30 | };
31 |
32 | function Point(curve, x, z) {
33 | Base.BasePoint.call(this, curve, 'projective');
34 | if (x === null && z === null) {
35 | this.x = this.curve.one;
36 | this.z = this.curve.zero;
37 | } else {
38 | this.x = new BN(x, 16);
39 | this.z = new BN(z, 16);
40 | if (!this.x.red)
41 | this.x = this.x.toRed(this.curve.red);
42 | if (!this.z.red)
43 | this.z = this.z.toRed(this.curve.red);
44 | }
45 | }
46 | inherits(Point, Base.BasePoint);
47 |
48 | MontCurve.prototype.decodePoint = function decodePoint(bytes, enc) {
49 | return this.point(utils.toArray(bytes, enc), 1);
50 | };
51 |
52 | MontCurve.prototype.point = function point(x, z) {
53 | return new Point(this, x, z);
54 | };
55 |
56 | MontCurve.prototype.pointFromJSON = function pointFromJSON(obj) {
57 | return Point.fromJSON(this, obj);
58 | };
59 |
60 | Point.prototype.precompute = function precompute() {
61 | // No-op
62 | };
63 |
64 | Point.prototype._encode = function _encode() {
65 | return this.getX().toArray('be', this.curve.p.byteLength());
66 | };
67 |
68 | Point.fromJSON = function fromJSON(curve, obj) {
69 | return new Point(curve, obj[0], obj[1] || curve.one);
70 | };
71 |
72 | Point.prototype.inspect = function inspect() {
73 | if (this.isInfinity())
74 | return '';
75 | return '';
77 | };
78 |
79 | Point.prototype.isInfinity = function isInfinity() {
80 | // XXX This code assumes that zero is always zero in red
81 | return this.z.cmpn(0) === 0;
82 | };
83 |
84 | Point.prototype.dbl = function dbl() {
85 | // http://hyperelliptic.org/EFD/g1p/auto-montgom-xz.html#doubling-dbl-1987-m-3
86 | // 2M + 2S + 4A
87 |
88 | // A = X1 + Z1
89 | var a = this.x.redAdd(this.z);
90 | // AA = A^2
91 | var aa = a.redSqr();
92 | // B = X1 - Z1
93 | var b = this.x.redSub(this.z);
94 | // BB = B^2
95 | var bb = b.redSqr();
96 | // C = AA - BB
97 | var c = aa.redSub(bb);
98 | // X3 = AA * BB
99 | var nx = aa.redMul(bb);
100 | // Z3 = C * (BB + A24 * C)
101 | var nz = c.redMul(bb.redAdd(this.curve.a24.redMul(c)));
102 | return this.curve.point(nx, nz);
103 | };
104 |
105 | Point.prototype.add = function add() {
106 | throw new Error('Not supported on Montgomery curve');
107 | };
108 |
109 | Point.prototype.diffAdd = function diffAdd(p, diff) {
110 | // http://hyperelliptic.org/EFD/g1p/auto-montgom-xz.html#diffadd-dadd-1987-m-3
111 | // 4M + 2S + 6A
112 |
113 | // A = X2 + Z2
114 | var a = this.x.redAdd(this.z);
115 | // B = X2 - Z2
116 | var b = this.x.redSub(this.z);
117 | // C = X3 + Z3
118 | var c = p.x.redAdd(p.z);
119 | // D = X3 - Z3
120 | var d = p.x.redSub(p.z);
121 | // DA = D * A
122 | var da = d.redMul(a);
123 | // CB = C * B
124 | var cb = c.redMul(b);
125 | // X5 = Z1 * (DA + CB)^2
126 | var nx = diff.z.redMul(da.redAdd(cb).redSqr());
127 | // Z5 = X1 * (DA - CB)^2
128 | var nz = diff.x.redMul(da.redISub(cb).redSqr());
129 | return this.curve.point(nx, nz);
130 | };
131 |
132 | Point.prototype.mul = function mul(k) {
133 | var t = k.clone();
134 | var a = this; // (N / 2) * Q + Q
135 | var b = this.curve.point(null, null); // (N / 2) * Q
136 | var c = this; // Q
137 |
138 | for (var bits = []; t.cmpn(0) !== 0; t.iushrn(1))
139 | bits.push(t.andln(1));
140 |
141 | for (var i = bits.length - 1; i >= 0; i--) {
142 | if (bits[i] === 0) {
143 | // N * Q + Q = ((N / 2) * Q + Q)) + (N / 2) * Q
144 | a = a.diffAdd(b, c);
145 | // N * Q = 2 * ((N / 2) * Q + Q))
146 | b = b.dbl();
147 | } else {
148 | // N * Q = ((N / 2) * Q + Q) + ((N / 2) * Q)
149 | b = a.diffAdd(b, c);
150 | // N * Q + Q = 2 * ((N / 2) * Q + Q)
151 | a = a.dbl();
152 | }
153 | }
154 | return b;
155 | };
156 |
157 | Point.prototype.mulAdd = function mulAdd() {
158 | throw new Error('Not supported on Montgomery curve');
159 | };
160 |
161 | Point.prototype.jumlAdd = function jumlAdd() {
162 | throw new Error('Not supported on Montgomery curve');
163 | };
164 |
165 | Point.prototype.eq = function eq(other) {
166 | return this.getX().cmp(other.getX()) === 0;
167 | };
168 |
169 | Point.prototype.normalize = function normalize() {
170 | this.x = this.x.redMul(this.z.redInvm());
171 | this.z = this.curve.one;
172 | return this;
173 | };
174 |
175 | Point.prototype.getX = function getX() {
176 | // Normalize coordinates
177 | this.normalize();
178 |
179 | return this.x.fromRed();
180 | };
181 |
--------------------------------------------------------------------------------
/Gruntfile.js:
--------------------------------------------------------------------------------
1 | module.exports = function(grunt) {
2 | grunt.initConfig({
3 | browserify: {
4 | unittests: {
5 | files: {
6 | 'test/lib/unittests-bundle.js': [ 'test/index.js']
7 | },
8 | options: {
9 | transform: ['brfs']
10 | }
11 | },
12 | dist: {
13 | files: {
14 | 'dist/elliptic.js': [ 'lib/elliptic.js' ]
15 | },
16 | options: {
17 | browserifyOptions: {
18 | standalone: 'elliptic'
19 | }
20 | }
21 | }
22 | },
23 | connect: {
24 | server: {
25 | options: {
26 | port: 3000,
27 | base: './test'
28 | }
29 | }
30 | },
31 | copy: {
32 | test: {
33 | expand: true,
34 | flatten: true,
35 | cwd: 'node_modules/',
36 | src: ['mocha/mocha.css', 'mocha/mocha.js'],
37 | dest: 'test/lib/'
38 | }
39 | },
40 | mocha_istanbul: {
41 | coverage: {
42 | src: ['test'],
43 | options: {
44 | coverage: false,
45 | timeout: 6000,
46 | reportFormats: ['cobertura','lcovonly']
47 | }
48 | },
49 | coveralls: {
50 | src: ['test'],
51 | options: {
52 | coverage: true,
53 | timeout: 6000,
54 | reportFormats: ['cobertura','lcovonly']
55 | }
56 | }
57 | },
58 | 'saucelabs-mocha': {
59 | all: {
60 | options: {
61 | username: process.env.SAUCE_USERNAME,
62 | key: process.env.SAUCE_ACCESS_KEY,
63 | urls: ['http://127.0.0.1:3000/unittests.html'],
64 | build: process.env.TRAVIS_JOB_ID,
65 | testname: 'Sauce Unit Test for ellipticjs',
66 | browsers: [
67 | {
68 | browserName: "safari",
69 | platform: "OS X 10.11",
70 | version: "9"
71 | },
72 | {
73 | browserName: "safari",
74 | platform: "OS X 10.10",
75 | version: "8"
76 | },
77 | {
78 | browserName: "microsoftedge",
79 | version: "13.10586",
80 | platform: "Windows 10"
81 | },
82 | {
83 | browserName: "internet explorer",
84 | version: "11",
85 | platform: "Windows 8.1"
86 | },
87 | {
88 | browserName: "internet explorer",
89 | version: "10",
90 | platform: "Windows 8"
91 | },
92 | {
93 | browserName: "internet explorer",
94 | version: "9",
95 | platform: "Windows 7"
96 | },
97 | {
98 | browserName: "internet explorer",
99 | version: "8",
100 | platform: "Windows 7"
101 | },
102 | {
103 | browserName: "android",
104 | platform: "Linux",
105 | version: "5.1"
106 | },
107 | {
108 | browserName: "android",
109 | platform: "Linux",
110 | version: "4.4"
111 | },
112 | {
113 | browserName: "iphone",
114 | platform: "OS X 10.10",
115 | version: "7.1"
116 | },
117 | {
118 | browserName: "iphone",
119 | platform: "OS X 10.10",
120 | version: "9.2"
121 | },
122 | {
123 | browserName: "chrome",
124 | platform: "Linux",
125 | version: "38"
126 | },
127 | {
128 | browserName: "chrome",
129 | platform: "Linux",
130 | version: "47"
131 | },
132 | {
133 | browserName: "chrome",
134 | platform: "Linux",
135 | version: "beta"
136 | },
137 | {
138 | browserName: "firefox",
139 | platform: "Linux",
140 | version: "38"
141 | },
142 | {
143 | browserName: "firefox",
144 | platform: "Linux",
145 | version: "43"
146 | },
147 | {
148 | browserName: "firefox",
149 | platform: "Linux",
150 | version: "beta"
151 | }
152 | ],
153 | public: "public",
154 | maxRetries: 3,
155 | throttled: 2,
156 | pollInterval: 4000,
157 | statusCheckAttempts: 200
158 | }
159 | },
160 | },
161 | uglify: {
162 | dist: {
163 | files: {
164 | 'dist/elliptic.min.js' : [ 'dist/elliptic.js' ]
165 | }
166 | }
167 | }
168 | });
169 |
170 | grunt.loadNpmTasks('grunt-browserify');
171 | grunt.loadNpmTasks('grunt-contrib-connect');
172 | grunt.loadNpmTasks('grunt-contrib-copy');
173 | grunt.loadNpmTasks('grunt-contrib-uglify');
174 | grunt.loadNpmTasks('grunt-mocha-istanbul');
175 | grunt.loadNpmTasks('grunt-saucelabs');
176 |
177 | grunt.event.on('coverage', function(lcov, done){
178 | require('coveralls').handleInput(lcov, function(err){
179 | if (err) {
180 | return done(err);
181 | }
182 | done();
183 | });
184 | });
185 |
186 | grunt.registerTask('dist', ['browserify', 'uglify']);
187 | grunt.registerTask('coverage', ['browserify', 'copy:test', 'mocha_istanbul:coverage']);
188 | grunt.registerTask('coveralls', ['browserify', 'copy:test', 'mocha_istanbul:coveralls']);
189 | grunt.registerTask('saucelabs', ['browserify', 'copy:test', 'connect', 'saucelabs-mocha']);
190 | };
191 |
--------------------------------------------------------------------------------
/.jshintrc:
--------------------------------------------------------------------------------
1 | {
2 | // JSHint Default Configuration File (as on JSHint website)
3 | // See http://jshint.com/docs/ for more details
4 |
5 | "maxerr" : 50, // {int} Maximum error before stopping
6 |
7 | // Enforcing
8 | "bitwise" : false, // true: Prohibit bitwise operators (&, |, ^, etc.)
9 | "camelcase" : true, // true: Identifiers must be in camelCase
10 | "curly" : false, // true: Require {} for every new block or scope
11 | "eqeqeq" : true, // true: Require triple equals (===) for comparison
12 | "forin" : true, // true: Require filtering for..in loops with obj.hasOwnProperty()
13 | "freeze" : true, // true: prohibits overwriting prototypes of native objects such as Array, Date etc.
14 | "immed" : false, // true: Require immediate invocations to be wrapped in parens e.g. `(function () { } ());`
15 | "indent" : 2, // {int} Number of spaces to use for indentation
16 | "latedef" : true, // true: Require variables/functions to be defined before being used
17 | "newcap" : true, // true: Require capitalization of all constructor functions e.g. `new F()`
18 | "noarg" : true, // true: Prohibit use of `arguments.caller` and `arguments.callee`
19 | "noempty" : false, // true: Prohibit use of empty blocks
20 | "nonbsp" : true, // true: Prohibit "non-breaking whitespace" characters.
21 | "nonew" : false, // true: Prohibit use of constructors for side-effects (without assignment)
22 | "plusplus" : false, // true: Prohibit use of `++` & `--`
23 | "quotmark" : "single", // Quotation mark consistency:
24 | // false : do nothing (default)
25 | // true : ensure whatever is used is consistent
26 | // "single" : require single quotes
27 | // "double" : require double quotes
28 | "undef" : true, // true: Require all non-global variables to be declared (prevents global leaks)
29 | "unused" : true, // true: Require all defined variables be used
30 | "strict" : true, // true: Requires all functions run in ES5 Strict Mode
31 | "maxparams" : false, // {int} Max number of formal params allowed per function
32 | "maxdepth" : 4, // {int} Max depth of nested blocks (within functions)
33 | "maxstatements" : false, // {int} Max number statements per function
34 | "maxcomplexity" : false, // {int} Max cyclomatic complexity per function
35 | "maxlen" : false, // {int} Max number of characters per line
36 |
37 | // Relaxing
38 | "asi" : false, // true: Tolerate Automatic Semicolon Insertion (no semicolons)
39 | "boss" : false, // true: Tolerate assignments where comparisons would be expected
40 | "debug" : false, // true: Allow debugger statements e.g. browser breakpoints.
41 | "eqnull" : false, // true: Tolerate use of `== null`
42 | "es5" : false, // true: Allow ES5 syntax (ex: getters and setters)
43 | "esnext" : false, // true: Allow ES.next (ES6) syntax (ex: `const`)
44 | "moz" : false, // true: Allow Mozilla specific syntax (extends and overrides esnext features)
45 | // (ex: `for each`, multiple try/catch, function expression…)
46 | "evil" : false, // true: Tolerate use of `eval` and `new Function()`
47 | "expr" : false, // true: Tolerate `ExpressionStatement` as Programs
48 | "funcscope" : false, // true: Tolerate defining variables inside control statements
49 | "globalstrict" : false, // true: Allow global "use strict" (also enables 'strict')
50 | "iterator" : false, // true: Tolerate using the `__iterator__` property
51 | "lastsemic" : false, // true: Tolerate omitting a semicolon for the last statement of a 1-line block
52 | "laxbreak" : false, // true: Tolerate possibly unsafe line breakings
53 | "laxcomma" : false, // true: Tolerate comma-first style coding
54 | "loopfunc" : false, // true: Tolerate functions being defined in loops
55 | "multistr" : false, // true: Tolerate multi-line strings
56 | "noyield" : false, // true: Tolerate generator functions with no yield statement in them.
57 | "notypeof" : false, // true: Tolerate invalid typeof operator values
58 | "proto" : false, // true: Tolerate using the `__proto__` property
59 | "scripturl" : false, // true: Tolerate script-targeted URLs
60 | "shadow" : true, // true: Allows re-define variables later in code e.g. `var x=1; x=2;`
61 | "sub" : false, // true: Tolerate using `[]` notation when it can still be expressed in dot notation
62 | "supernew" : false, // true: Tolerate `new function () { ... };` and `new Object;`
63 | "validthis" : false, // true: Tolerate using this in a non-constructor function
64 |
65 | // Environments
66 | "browser" : true, // Web Browser (window, document, etc)
67 | "browserify" : true, // Browserify (node.js code in the browser)
68 | "couch" : false, // CouchDB
69 | "devel" : true, // Development/debugging (alert, confirm, etc)
70 | "dojo" : false, // Dojo Toolkit
71 | "jasmine" : false, // Jasmine
72 | "jquery" : false, // jQuery
73 | "mocha" : true, // Mocha
74 | "mootools" : false, // MooTools
75 | "node" : true, // Node.js
76 | "nonstandard" : false, // Widely adopted globals (escape, unescape, etc)
77 | "prototypejs" : false, // Prototype and Scriptaculous
78 | "qunit" : false, // QUnit
79 | "rhino" : false, // Rhino
80 | "shelljs" : false, // ShellJS
81 | "worker" : false, // Web Workers
82 | "wsh" : false, // Windows Scripting Host
83 | "yui" : false, // Yahoo User Interface
84 |
85 | // Custom Globals
86 | "globals" : {
87 | "module": true
88 | } // additional predefined global variables
89 | }
90 |
--------------------------------------------------------------------------------
/lib/elliptic/curves.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var curves = exports;
4 |
5 | var hash = require('hash.js');
6 | var elliptic = require('../elliptic');
7 |
8 | var assert = elliptic.utils.assert;
9 |
10 | function PresetCurve(options) {
11 | if (options.type === 'short')
12 | this.curve = new elliptic.curve.short(options);
13 | else if (options.type === 'edwards')
14 | this.curve = new elliptic.curve.edwards(options);
15 | else
16 | this.curve = new elliptic.curve.mont(options);
17 | this.g = this.curve.g;
18 | this.n = this.curve.n;
19 | this.hash = options.hash;
20 |
21 | assert(this.g.validate(), 'Invalid curve');
22 | assert(this.g.mul(this.n).isInfinity(), 'Invalid curve, G*N != O');
23 | }
24 | curves.PresetCurve = PresetCurve;
25 |
26 | function defineCurve(name, options) {
27 | Object.defineProperty(curves, name, {
28 | configurable: true,
29 | enumerable: true,
30 | get: function() {
31 | var curve = new PresetCurve(options);
32 | Object.defineProperty(curves, name, {
33 | configurable: true,
34 | enumerable: true,
35 | value: curve
36 | });
37 | return curve;
38 | }
39 | });
40 | }
41 |
42 | defineCurve('p192', {
43 | type: 'short',
44 | prime: 'p192',
45 | p: 'ffffffff ffffffff ffffffff fffffffe ffffffff ffffffff',
46 | a: 'ffffffff ffffffff ffffffff fffffffe ffffffff fffffffc',
47 | b: '64210519 e59c80e7 0fa7e9ab 72243049 feb8deec c146b9b1',
48 | n: 'ffffffff ffffffff ffffffff 99def836 146bc9b1 b4d22831',
49 | hash: hash.sha256,
50 | gRed: false,
51 | g: [
52 | '188da80e b03090f6 7cbf20eb 43a18800 f4ff0afd 82ff1012',
53 | '07192b95 ffc8da78 631011ed 6b24cdd5 73f977a1 1e794811'
54 | ]
55 | });
56 |
57 | defineCurve('p224', {
58 | type: 'short',
59 | prime: 'p224',
60 | p: 'ffffffff ffffffff ffffffff ffffffff 00000000 00000000 00000001',
61 | a: 'ffffffff ffffffff ffffffff fffffffe ffffffff ffffffff fffffffe',
62 | b: 'b4050a85 0c04b3ab f5413256 5044b0b7 d7bfd8ba 270b3943 2355ffb4',
63 | n: 'ffffffff ffffffff ffffffff ffff16a2 e0b8f03e 13dd2945 5c5c2a3d',
64 | hash: hash.sha256,
65 | gRed: false,
66 | g: [
67 | 'b70e0cbd 6bb4bf7f 321390b9 4a03c1d3 56c21122 343280d6 115c1d21',
68 | 'bd376388 b5f723fb 4c22dfe6 cd4375a0 5a074764 44d58199 85007e34'
69 | ]
70 | });
71 |
72 | defineCurve('p256', {
73 | type: 'short',
74 | prime: null,
75 | p: 'ffffffff 00000001 00000000 00000000 00000000 ffffffff ffffffff ffffffff',
76 | a: 'ffffffff 00000001 00000000 00000000 00000000 ffffffff ffffffff fffffffc',
77 | b: '5ac635d8 aa3a93e7 b3ebbd55 769886bc 651d06b0 cc53b0f6 3bce3c3e 27d2604b',
78 | n: 'ffffffff 00000000 ffffffff ffffffff bce6faad a7179e84 f3b9cac2 fc632551',
79 | hash: hash.sha256,
80 | gRed: false,
81 | g: [
82 | '6b17d1f2 e12c4247 f8bce6e5 63a440f2 77037d81 2deb33a0 f4a13945 d898c296',
83 | '4fe342e2 fe1a7f9b 8ee7eb4a 7c0f9e16 2bce3357 6b315ece cbb64068 37bf51f5'
84 | ]
85 | });
86 |
87 | defineCurve('p384', {
88 | type: 'short',
89 | prime: null,
90 | p: 'ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ' +
91 | 'fffffffe ffffffff 00000000 00000000 ffffffff',
92 | a: 'ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ' +
93 | 'fffffffe ffffffff 00000000 00000000 fffffffc',
94 | b: 'b3312fa7 e23ee7e4 988e056b e3f82d19 181d9c6e fe814112 0314088f ' +
95 | '5013875a c656398d 8a2ed19d 2a85c8ed d3ec2aef',
96 | n: 'ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff c7634d81 ' +
97 | 'f4372ddf 581a0db2 48b0a77a ecec196a ccc52973',
98 | hash: hash.sha384,
99 | gRed: false,
100 | g: [
101 | 'aa87ca22 be8b0537 8eb1c71e f320ad74 6e1d3b62 8ba79b98 59f741e0 82542a38 ' +
102 | '5502f25d bf55296c 3a545e38 72760ab7',
103 | '3617de4a 96262c6f 5d9e98bf 9292dc29 f8f41dbd 289a147c e9da3113 b5f0b8c0 ' +
104 | '0a60b1ce 1d7e819d 7a431d7c 90ea0e5f'
105 | ]
106 | });
107 |
108 | defineCurve('p521', {
109 | type: 'short',
110 | prime: null,
111 | p: '000001ff ffffffff ffffffff ffffffff ffffffff ffffffff ' +
112 | 'ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ' +
113 | 'ffffffff ffffffff ffffffff ffffffff ffffffff',
114 | a: '000001ff ffffffff ffffffff ffffffff ffffffff ffffffff ' +
115 | 'ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ' +
116 | 'ffffffff ffffffff ffffffff ffffffff fffffffc',
117 | b: '00000051 953eb961 8e1c9a1f 929a21a0 b68540ee a2da725b ' +
118 | '99b315f3 b8b48991 8ef109e1 56193951 ec7e937b 1652c0bd ' +
119 | '3bb1bf07 3573df88 3d2c34f1 ef451fd4 6b503f00',
120 | n: '000001ff ffffffff ffffffff ffffffff ffffffff ffffffff ' +
121 | 'ffffffff ffffffff fffffffa 51868783 bf2f966b 7fcc0148 ' +
122 | 'f709a5d0 3bb5c9b8 899c47ae bb6fb71e 91386409',
123 | hash: hash.sha512,
124 | gRed: false,
125 | g: [
126 | '000000c6 858e06b7 0404e9cd 9e3ecb66 2395b442 9c648139 ' +
127 | '053fb521 f828af60 6b4d3dba a14b5e77 efe75928 fe1dc127 ' +
128 | 'a2ffa8de 3348b3c1 856a429b f97e7e31 c2e5bd66',
129 | '00000118 39296a78 9a3bc004 5c8a5fb4 2c7d1bd9 98f54449 ' +
130 | '579b4468 17afbd17 273e662c 97ee7299 5ef42640 c550b901 ' +
131 | '3fad0761 353c7086 a272c240 88be9476 9fd16650'
132 | ]
133 | });
134 |
135 | defineCurve('curve25519', {
136 | type: 'mont',
137 | prime: 'p25519',
138 | p: '7fffffffffffffff ffffffffffffffff ffffffffffffffff ffffffffffffffed',
139 | a: '76d06',
140 | b: '1',
141 | n: '1000000000000000 0000000000000000 14def9dea2f79cd6 5812631a5cf5d3ed',
142 | hash: hash.sha256,
143 | gRed: false,
144 | g: [
145 | '9'
146 | ]
147 | });
148 |
149 | defineCurve('ed25519', {
150 | type: 'edwards',
151 | prime: 'p25519',
152 | p: '7fffffffffffffff ffffffffffffffff ffffffffffffffff ffffffffffffffed',
153 | a: '-1',
154 | c: '1',
155 | // -121665 * (121666^(-1)) (mod P)
156 | d: '52036cee2b6ffe73 8cc740797779e898 00700a4d4141d8ab 75eb4dca135978a3',
157 | n: '1000000000000000 0000000000000000 14def9dea2f79cd6 5812631a5cf5d3ed',
158 | hash: hash.sha256,
159 | gRed: false,
160 | g: [
161 | '216936d3cd6e53fec0a4e231fdd6dc5c692cc7609525a7b2c9562d608f25d51a',
162 |
163 | // 4/5
164 | '6666666666666666666666666666666666666666666666666666666666666658'
165 | ]
166 | });
167 |
168 | var pre;
169 | try {
170 | pre = require('./precomputed/secp256k1');
171 | } catch (e) {
172 | pre = undefined;
173 | }
174 |
175 | defineCurve('secp256k1', {
176 | type: 'short',
177 | prime: 'k256',
178 | p: 'ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff fffffffe fffffc2f',
179 | a: '0',
180 | b: '7',
181 | n: 'ffffffff ffffffff ffffffff fffffffe baaedce6 af48a03b bfd25e8c d0364141',
182 | h: '1',
183 | hash: hash.sha256,
184 |
185 | // Precomputed endomorphism
186 | beta: '7ae96a2b657c07106e64479eac3434e99cf0497512f58995c1396c28719501ee',
187 | lambda: '5363ad4cc05c30e0a5261c028812645a122e22ea20816678df02967c1b23bd72',
188 | basis: [
189 | {
190 | a: '3086d221a7d46bcde86c90e49284eb15',
191 | b: '-e4437ed6010e88286f547fa90abfe4c3'
192 | },
193 | {
194 | a: '114ca50f7a8e2f3f657c1108d9d44cfd8',
195 | b: '3086d221a7d46bcde86c90e49284eb15'
196 | }
197 | ],
198 |
199 | gRed: false,
200 | g: [
201 | '79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798',
202 | '483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8',
203 | pre
204 | ]
205 | });
206 |
--------------------------------------------------------------------------------
/lib/elliptic/ec/index.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var BN = require('bn.js');
4 | var HmacDRBG = require('hmac-drbg');
5 | var elliptic = require('../../elliptic');
6 | var utils = elliptic.utils;
7 | var assert = utils.assert;
8 |
9 | var KeyPair = require('./key');
10 | var Signature = require('./signature');
11 |
12 | function EC(options) {
13 | if (!(this instanceof EC))
14 | return new EC(options);
15 |
16 | // Shortcut `elliptic.ec(curve-name)`
17 | if (typeof options === 'string') {
18 | assert(elliptic.curves.hasOwnProperty(options), 'Unknown curve ' + options);
19 |
20 | options = elliptic.curves[options];
21 | }
22 |
23 | // Shortcut for `elliptic.ec(elliptic.curves.curveName)`
24 | if (options instanceof elliptic.curves.PresetCurve)
25 | options = { curve: options };
26 |
27 | this.curve = options.curve.curve;
28 | this.n = this.curve.n;
29 | this.nh = this.n.ushrn(1);
30 | this.g = this.curve.g;
31 |
32 | // Point on curve
33 | this.g = options.curve.g;
34 | this.g.precompute(options.curve.n.bitLength() + 1);
35 |
36 | // Hash for function for DRBG
37 | this.hash = options.hash || options.curve.hash;
38 | }
39 | module.exports = EC;
40 |
41 | EC.prototype.keyPair = function keyPair(options) {
42 | return new KeyPair(this, options);
43 | };
44 |
45 | EC.prototype.keyFromPrivate = function keyFromPrivate(priv, enc) {
46 | return KeyPair.fromPrivate(this, priv, enc);
47 | };
48 |
49 | EC.prototype.keyFromPublic = function keyFromPublic(pub, enc) {
50 | return KeyPair.fromPublic(this, pub, enc);
51 | };
52 |
53 | EC.prototype.genKeyPair = function genKeyPair(options) {
54 | if (!options)
55 | options = {};
56 |
57 | // Instantiate Hmac_DRBG
58 | var drbg = new HmacDRBG({
59 | hash: this.hash,
60 | pers: options.pers,
61 | persEnc: options.persEnc || 'utf8',
62 | entropy: options.entropy || elliptic.rand(this.hash.hmacStrength),
63 | entropyEnc: options.entropy && options.entropyEnc || 'utf8',
64 | nonce: this.n.toArray()
65 | });
66 |
67 | var bytes = this.n.byteLength();
68 | var ns2 = this.n.sub(new BN(2));
69 | do {
70 | var priv = new BN(drbg.generate(bytes));
71 | if (priv.cmp(ns2) > 0)
72 | continue;
73 |
74 | priv.iaddn(1);
75 | return this.keyFromPrivate(priv);
76 | } while (true);
77 | };
78 |
79 | EC.prototype._truncateToN = function truncateToN(msg, truncOnly) {
80 | var delta = msg.byteLength() * 8 - this.n.bitLength();
81 | if (delta > 0)
82 | msg = msg.ushrn(delta);
83 | if (!truncOnly && msg.cmp(this.n) >= 0)
84 | return msg.sub(this.n);
85 | else
86 | return msg;
87 | };
88 |
89 | EC.prototype.sign = function sign(msg, key, enc, options) {
90 | if (typeof enc === 'object') {
91 | options = enc;
92 | enc = null;
93 | }
94 | if (!options)
95 | options = {};
96 |
97 | key = this.keyFromPrivate(key, enc);
98 | msg = this._truncateToN(new BN(msg, 16));
99 |
100 | // Zero-extend key to provide enough entropy
101 | var bytes = this.n.byteLength();
102 | var bkey = key.getPrivate().toArray('be', bytes);
103 |
104 | // Zero-extend nonce to have the same byte size as N
105 | var nonce = msg.toArray('be', bytes);
106 |
107 | // Instantiate Hmac_DRBG
108 | var drbg = new HmacDRBG({
109 | hash: this.hash,
110 | entropy: bkey,
111 | nonce: nonce,
112 | pers: options.pers,
113 | persEnc: options.persEnc || 'utf8'
114 | });
115 |
116 | // Number of bytes to generate
117 | var ns1 = this.n.sub(new BN(1));
118 |
119 | for (var iter = 0; true; iter++) {
120 | var k = options.k ?
121 | options.k(iter) :
122 | new BN(drbg.generate(this.n.byteLength()));
123 | k = this._truncateToN(k, true);
124 | if (k.cmpn(1) <= 0 || k.cmp(ns1) >= 0)
125 | continue;
126 |
127 | var kp = this.g.mul(k);
128 | if (kp.isInfinity())
129 | continue;
130 |
131 | var kpX = kp.getX();
132 | var r = kpX.umod(this.n);
133 | if (r.cmpn(0) === 0)
134 | continue;
135 |
136 | var s = k.invm(this.n).mul(r.mul(key.getPrivate()).iadd(msg));
137 | s = s.umod(this.n);
138 | if (s.cmpn(0) === 0)
139 | continue;
140 |
141 | var recoveryParam = (kp.getY().isOdd() ? 1 : 0) |
142 | (kpX.cmp(r) !== 0 ? 2 : 0);
143 |
144 | // Use complement of `s`, if it is > `n / 2`
145 | if (options.canonical && s.cmp(this.nh) > 0) {
146 | s = this.n.sub(s);
147 | recoveryParam ^= 1;
148 | }
149 |
150 | return new Signature({ r: r, s: s, recoveryParam: recoveryParam });
151 | }
152 | };
153 |
154 | EC.prototype.verify = function verify(msg, signature, key, enc) {
155 | msg = this._truncateToN(new BN(msg, 16));
156 | key = this.keyFromPublic(key, enc);
157 | signature = new Signature(signature, 'hex');
158 |
159 | // Perform primitive values validation
160 | var r = signature.r;
161 | var s = signature.s;
162 | if (r.cmpn(1) < 0 || r.cmp(this.n) >= 0)
163 | return false;
164 | if (s.cmpn(1) < 0 || s.cmp(this.n) >= 0)
165 | return false;
166 |
167 | // Validate signature
168 | var sinv = s.invm(this.n);
169 | var u1 = sinv.mul(msg).umod(this.n);
170 | var u2 = sinv.mul(r).umod(this.n);
171 |
172 | if (!this.curve._maxwellTrick) {
173 | var p = this.g.mulAdd(u1, key.getPublic(), u2);
174 | if (p.isInfinity())
175 | return false;
176 |
177 | return p.getX().umod(this.n).cmp(r) === 0;
178 | }
179 |
180 | // NOTE: Greg Maxwell's trick, inspired by:
181 | // https://git.io/vad3K
182 |
183 | var p = this.g.jmulAdd(u1, key.getPublic(), u2);
184 | if (p.isInfinity())
185 | return false;
186 |
187 | // Compare `p.x` of Jacobian point with `r`,
188 | // this will do `p.x == r * p.z^2` instead of multiplying `p.x` by the
189 | // inverse of `p.z^2`
190 | return p.eqXToP(r);
191 | };
192 |
193 | EC.prototype.recoverPubKey = function(msg, signature, j, enc) {
194 | assert((3 & j) === j, 'The recovery param is more than two bits');
195 | signature = new Signature(signature, enc);
196 |
197 | var n = this.n;
198 | var e = new BN(msg);
199 | var r = signature.r;
200 | var s = signature.s;
201 |
202 | // A set LSB signifies that the y-coordinate is odd
203 | var isYOdd = j & 1;
204 | var isSecondKey = j >> 1;
205 | if (r.cmp(this.curve.p.umod(this.curve.n)) >= 0 && isSecondKey)
206 | throw new Error('Unable to find sencond key candinate');
207 |
208 | // 1.1. Let x = r + jn.
209 | if (isSecondKey)
210 | r = this.curve.pointFromX(r.add(this.curve.n), isYOdd);
211 | else
212 | r = this.curve.pointFromX(r, isYOdd);
213 |
214 | var rInv = signature.r.invm(n);
215 | var s1 = n.sub(e).mul(rInv).umod(n);
216 | var s2 = s.mul(rInv).umod(n);
217 |
218 | // 1.6.1 Compute Q = r^-1 (sR - eG)
219 | // Q = r^-1 (sR + -eG)
220 | return this.g.mulAdd(s1, r, s2);
221 | };
222 |
223 | EC.prototype.getKeyRecoveryParam = function(e, signature, Q, enc) {
224 | signature = new Signature(signature, enc);
225 | if (signature.recoveryParam !== null)
226 | return signature.recoveryParam;
227 |
228 | for (var i = 0; i < 4; i++) {
229 | var Qprime;
230 | try {
231 | Qprime = this.recoverPubKey(e, signature, i);
232 | } catch (e) {
233 | continue;
234 | }
235 |
236 | if (Qprime.eq(Q))
237 | return i;
238 | }
239 | throw new Error('Unable to find valid recovery factor');
240 | };
241 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Elliptic [](http://travis-ci.org/indutny/elliptic) [](https://coveralls.io/github/indutny/elliptic?branch=master) [](https://codeclimate.com/github/indutny/elliptic)
2 |
3 | [](https://saucelabs.com/u/gh-indutny-elliptic)
4 |
5 | Fast elliptic-curve cryptography in a plain javascript implementation.
6 |
7 | NOTE: Please take a look at http://safecurves.cr.yp.to/ before choosing a curve
8 | for your cryptography operations.
9 |
10 | ## Incentive
11 |
12 | ECC is much slower than regular RSA cryptography, the JS implementations are
13 | even more slower.
14 |
15 | ## Benchmarks
16 |
17 | ```bash
18 | $ node benchmarks/index.js
19 | Benchmarking: sign
20 | elliptic#sign x 262 ops/sec ±0.51% (177 runs sampled)
21 | eccjs#sign x 55.91 ops/sec ±0.90% (144 runs sampled)
22 | ------------------------
23 | Fastest is elliptic#sign
24 | ========================
25 | Benchmarking: verify
26 | elliptic#verify x 113 ops/sec ±0.50% (166 runs sampled)
27 | eccjs#verify x 48.56 ops/sec ±0.36% (125 runs sampled)
28 | ------------------------
29 | Fastest is elliptic#verify
30 | ========================
31 | Benchmarking: gen
32 | elliptic#gen x 294 ops/sec ±0.43% (176 runs sampled)
33 | eccjs#gen x 62.25 ops/sec ±0.63% (129 runs sampled)
34 | ------------------------
35 | Fastest is elliptic#gen
36 | ========================
37 | Benchmarking: ecdh
38 | elliptic#ecdh x 136 ops/sec ±0.85% (156 runs sampled)
39 | ------------------------
40 | Fastest is elliptic#ecdh
41 | ========================
42 | ```
43 |
44 | ## API
45 |
46 | ### ECDSA
47 |
48 | ```javascript
49 | var EC = require('elliptic').ec;
50 |
51 | // Create and initialize EC context
52 | // (better do it once and reuse it)
53 | var ec = new EC('secp256k1');
54 |
55 | // Generate keys
56 | var key = ec.genKeyPair();
57 |
58 | // Sign the message's hash (input must be an array, or a hex-string)
59 | var msgHash = [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ];
60 | var signature = key.sign(msgHash);
61 |
62 | // Export DER encoded signature in Array
63 | var derSign = signature.toDER();
64 |
65 | // Verify signature
66 | console.log(key.verify(msgHash, derSign));
67 |
68 | // CHECK WITH NO PRIVATE KEY
69 |
70 | var pubPoint = key.getPublic();
71 | var x = pubPoint.getX();
72 | var y = pubPoint.getY();
73 |
74 | // Public Key MUST be either:
75 | // 1) '04' + hex string of x + hex string of y; or
76 | // 2) object with two hex string properties (x and y); or
77 | // 3) object with two buffer properties (x and y)
78 | var pub = pubPoint.encode('hex'); // case 1
79 | var pub = { x: x.toString('hex'), y: y.toString('hex') }; // case 2
80 | var pub = { x: x.toBuffer(), y: y.toBuffer() }; // case 3
81 | var pub = { x: x.toArrayLike(Buffer), y: y.toArrayLike(Buffer) }; // case 3
82 |
83 | // Import public key
84 | var key = ec.keyFromPublic(pub, 'hex');
85 |
86 | // Signature MUST be either:
87 | // 1) DER-encoded signature as hex-string; or
88 | // 2) DER-encoded signature as buffer; or
89 | // 3) object with two hex-string properties (r and s); or
90 | // 4) object with two buffer properties (r and s)
91 |
92 | var signature = '3046022100...'; // case 1
93 | var signature = new Buffer('...'); // case 2
94 | var signature = { r: 'b1fc...', s: '9c42...' }; // case 3
95 |
96 | // Verify signature
97 | console.log(key.verify(msgHash, signature));
98 | ```
99 |
100 | ### EdDSA
101 |
102 | ```javascript
103 | var EdDSA = require('elliptic').eddsa;
104 |
105 | // Create and initialize EdDSA context
106 | // (better do it once and reuse it)
107 | var ec = new EdDSA('ed25519');
108 |
109 | // Create key pair from secret
110 | var key = ec.keyFromSecret('693e3c...'); // hex string, array or Buffer
111 |
112 | // Sign the message's hash (input must be an array, or a hex-string)
113 | var msgHash = [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ];
114 | var signature = key.sign(msgHash).toHex();
115 |
116 | // Verify signature
117 | console.log(key.verify(msgHash, signature));
118 |
119 | // CHECK WITH NO PRIVATE KEY
120 |
121 | // Import public key
122 | var pub = '0a1af638...';
123 | var key = ec.keyFromPublic(pub, 'hex');
124 |
125 | // Verify signature
126 | var signature = '70bed1...';
127 | console.log(key.verify(msgHash, signature));
128 | ```
129 |
130 | ### ECDH
131 |
132 | ```javascript
133 | var EC = require('elliptic').ec;
134 | var ec = new EC('curve25519');
135 |
136 | // Generate keys
137 | var key1 = ec.genKeyPair();
138 | var key2 = ec.genKeyPair();
139 |
140 | var shared1 = key1.derive(key2.getPublic());
141 | var shared2 = key2.derive(key1.getPublic());
142 |
143 | console.log('Both shared secrets are BN instances');
144 | console.log(shared1.toString(16));
145 | console.log(shared2.toString(16));
146 | ```
147 |
148 | three and more members:
149 | ```javascript
150 | var EC = require('elliptic').ec;
151 | var ec = new EC('curve25519');
152 |
153 | var A = ec.genKeyPair();
154 | var B = ec.genKeyPair();
155 | var C = ec.genKeyPair();
156 |
157 | var AB = A.getPublic().mul(B.getPrivate())
158 | var BC = B.getPublic().mul(C.getPrivate())
159 | var CA = C.getPublic().mul(A.getPrivate())
160 |
161 | var ABC = AB.mul(C.getPrivate())
162 | var BCA = BC.mul(A.getPrivate())
163 | var CAB = CA.mul(B.getPrivate())
164 |
165 | console.log(ABC.getX().toString(16))
166 | console.log(BCA.getX().toString(16))
167 | console.log(CAB.getX().toString(16))
168 | ```
169 |
170 | NOTE: `.derive()` returns a [BN][1] instance.
171 |
172 | ## Supported curves
173 |
174 | Elliptic.js support following curve types:
175 |
176 | * Short Weierstrass
177 | * Montgomery
178 | * Edwards
179 | * Twisted Edwards
180 |
181 | Following curve 'presets' are embedded into the library:
182 |
183 | * `secp256k1`
184 | * `p192`
185 | * `p224`
186 | * `p256`
187 | * `p384`
188 | * `p521`
189 | * `curve25519`
190 | * `ed25519`
191 |
192 | NOTE: That `curve25519` could not be used for ECDSA, use `ed25519` instead.
193 |
194 | ### Implementation details
195 |
196 | ECDSA is using deterministic `k` value generation as per [RFC6979][0]. Most of
197 | the curve operations are performed on non-affine coordinates (either projective
198 | or extended), various windowing techniques are used for different cases.
199 |
200 | All operations are performed in reduction context using [bn.js][1], hashing is
201 | provided by [hash.js][2]
202 |
203 | ### Related projects
204 |
205 | * [eccrypto][3]: isomorphic implementation of ECDSA, ECDH and ECIES for both
206 | browserify and node (uses `elliptic` for browser and [secp256k1-node][4] for
207 | node)
208 |
209 | #### LICENSE
210 |
211 | This software is licensed under the MIT License.
212 |
213 | Copyright Fedor Indutny, 2014.
214 |
215 | Permission is hereby granted, free of charge, to any person obtaining a
216 | copy of this software and associated documentation files (the
217 | "Software"), to deal in the Software without restriction, including
218 | without limitation the rights to use, copy, modify, merge, publish,
219 | distribute, sublicense, and/or sell copies of the Software, and to permit
220 | persons to whom the Software is furnished to do so, subject to the
221 | following conditions:
222 |
223 | The above copyright notice and this permission notice shall be included
224 | in all copies or substantial portions of the Software.
225 |
226 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
227 | OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
228 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
229 | NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
230 | DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
231 | OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
232 | USE OR OTHER DEALINGS IN THE SOFTWARE.
233 |
234 | [0]: http://tools.ietf.org/html/rfc6979
235 | [1]: https://github.com/indutny/bn.js
236 | [2]: https://github.com/indutny/hash.js
237 | [3]: https://github.com/bitchan/eccrypto
238 | [4]: https://github.com/wanderer/secp256k1-node
239 |
--------------------------------------------------------------------------------
/test/curve-test.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var assert = require('assert');
4 | var BN = require('bn.js');
5 | var elliptic = require('../');
6 |
7 | describe('Curve', function() {
8 | it('should work with example curve', function() {
9 | var curve = new elliptic.curve.short({
10 | p: '1d',
11 | a: '4',
12 | b: '14'
13 | });
14 |
15 | var p = curve.point('18', '16');
16 | assert(p.validate());
17 | assert(p.dbl().validate());
18 | assert(p.dbl().add(p).validate());
19 | assert(p.dbl().add(p.dbl()).validate());
20 | assert(p.dbl().add(p.dbl()).eq(p.add(p).add(p).add(p)));
21 | });
22 |
23 | it('should work with secp112k1', function() {
24 | var curve = new elliptic.curve.short({
25 | p: 'db7c 2abf62e3 5e668076 bead208b',
26 | a: 'db7c 2abf62e3 5e668076 bead2088',
27 | b: '659e f8ba0439 16eede89 11702b22'
28 | });
29 |
30 | var p = curve.point(
31 | '0948 7239995a 5ee76b55 f9c2f098',
32 | 'a89c e5af8724 c0a23e0e 0ff77500');
33 | assert(p.validate());
34 | assert(p.dbl().validate());
35 | });
36 |
37 | it('should work with secp256k1', function() {
38 | var curve = new elliptic.curve.short({
39 | p: 'ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff fffffffe ' +
40 | 'fffffc2f',
41 | a: '0',
42 | b: '7',
43 | n: 'ffffffff ffffffff ffffffff fffffffe ' +
44 | 'baaedce6 af48a03b bfd25e8c d0364141',
45 | g: [
46 | '79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798',
47 | '483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8'
48 | ]
49 | });
50 |
51 | var p = curve.point(
52 | '79be667e f9dcbbac 55a06295 ce870b07 029bfcdb 2dce28d9 59f2815b 16f81798',
53 | '483ada77 26a3c465 5da4fbfc 0e1108a8 fd17b448 a6855419 9c47d08f fb10d4b8'
54 | );
55 | assert(p.validate());
56 | assert(p.dbl().validate());
57 | assert(p.toJ().dbl().toP().validate());
58 | assert(p.mul(new BN('79be667e f9dcbbac 55a06295 ce870b07', 16)).validate());
59 |
60 | var j = p.toJ();
61 | assert(j.trpl().eq(j.dbl().add(j)));
62 |
63 | // Endomorphism test
64 | assert(curve.endo);
65 | assert.equal(
66 | curve.endo.beta.fromRed().toString(16),
67 | '7ae96a2b657c07106e64479eac3434e99cf0497512f58995c1396c28719501ee');
68 | assert.equal(
69 | curve.endo.lambda.toString(16),
70 | '5363ad4cc05c30e0a5261c028812645a122e22ea20816678df02967c1b23bd72');
71 |
72 | var k = new BN('1234567890123456789012345678901234', 16);
73 | var split = curve._endoSplit(k);
74 |
75 | var testK = split.k1.add(split.k2.mul(curve.endo.lambda)).umod(curve.n);
76 | assert.equal(testK.toString(16), k.toString(16));
77 | });
78 |
79 | it('should compute this problematic secp256k1 multiplication', function() {
80 | var curve = elliptic.curves.secp256k1.curve;
81 | var g1 = curve.g; // precomputed g
82 | assert(g1.precomputed);
83 | var g2 = curve.point(g1.getX(), g1.getY()); // not precomputed g
84 | assert(!g2.precomputed);
85 | var a = new BN(
86 | '6d1229a6b24c2e775c062870ad26bc261051e0198c67203167273c7c62538846', 16);
87 | var p1 = g1.mul(a);
88 | var p2 = g2.mul(a);
89 | assert(p1.eq(p2));
90 | });
91 |
92 | it('should not use fixed NAF when k is too large', function() {
93 | var curve = elliptic.curves.secp256k1.curve;
94 | var g1 = curve.g; // precomputed g
95 | assert(g1.precomputed);
96 | var g2 = curve.point(g1.getX(), g1.getY()); // not precomputed g
97 | assert(!g2.precomputed);
98 |
99 | var a = new BN(
100 | '6d1229a6b24c2e775c062870ad26bc26' +
101 | '1051e0198c67203167273c7c6253884612345678',
102 | 16);
103 | var p1 = g1.mul(a);
104 | var p2 = g2.mul(a);
105 | assert(p1.eq(p2));
106 | });
107 |
108 | it('should not fail on secp256k1 regression', function() {
109 | var curve = elliptic.curves.secp256k1.curve;
110 | var k1 = new BN(
111 | '32efeba414cd0c830aed727749e816a01c471831536fd2fce28c56b54f5a3bb1', 16);
112 | var k2 = new BN(
113 | '5f2e49b5d64e53f9811545434706cde4de528af97bfd49fde1f6cf792ee37a8c', 16);
114 |
115 | var p1 = curve.g.mul(k1);
116 | var p2 = curve.g.mul(k2);
117 |
118 | // 2 + 2 + 1 = 2 + 1 + 2
119 | var two = p2.dbl();
120 | var five = two.dbl().add(p2);
121 | var three = two.add(p2);
122 | var maybeFive = three.add(two);
123 |
124 | assert(maybeFive.eq(five));
125 |
126 | p1 = p1.mul(k2);
127 | p2 = p2.mul(k1);
128 |
129 | assert(p1.validate());
130 | assert(p2.validate());
131 | assert(p1.eq(p2));
132 | });
133 |
134 | it('should correctly double the affine point on secp256k1', function() {
135 | var bad = {
136 | x: '026a2073b1ef6fab47ace18e60e728a05180a82755bbcec9a0abc08ad9f7a3d4',
137 | y: '9cd8cb48c3281596139f147c1364a3ede88d3f310fdb0eb98c924e599ca1b3c9',
138 | z: 'd78587ad45e4102f48b54b5d85598296e069ce6085002e169c6bad78ddc6d9bd'
139 | };
140 |
141 | var good = {
142 | x: 'e7789226739ac2eb3c7ccb2a9a910066beeed86cdb4e0f8a7fee8eeb29dc7016',
143 | y: '4b76b191fd6d47d07828ea965e275b76d0e3e0196cd5056d38384fbb819f9fcb',
144 | z: 'cbf8d99056618ba132d6145b904eee1ce566e0feedb9595139c45f84e90cfa7d'
145 | };
146 |
147 | var curve = elliptic.curves.secp256k1.curve;
148 | bad = curve.jpoint(bad.x, bad.y, bad.z);
149 | good = curve.jpoint(good.x, good.y, good.z);
150 |
151 | // They are the same points
152 | assert(bad.add(good.neg()).isInfinity());
153 |
154 | // But doubling borks them out
155 | assert(bad.dbl().add(good.dbl().neg()).isInfinity());
156 | });
157 |
158 | it('should store precomputed values correctly on negation', function() {
159 | var curve = elliptic.curves.secp256k1.curve;
160 | var p = curve.g.mul('2');
161 | p.precompute();
162 | var neg = p.neg(true);
163 | var neg2 = neg.neg(true);
164 | assert(p.eq(neg2));
165 | });
166 | });
167 |
168 | describe('Point codec', function () {
169 | function makeShortTest(definition) {
170 | var curve = elliptic.curves.secp256k1.curve;
171 |
172 | return function() {
173 | var co = definition.coordinates;
174 | var p = curve.point(co.x, co.y);
175 |
176 | // Encodes as expected
177 | assert.equal(p.encode('hex'), definition.encoded);
178 | assert.equal(p.encodeCompressed('hex'), definition.compactEncoded);
179 |
180 | // Decodes as expected
181 | assert(curve.decodePoint(definition.encoded, 'hex').eq(p));
182 | assert(curve.decodePoint(definition.compactEncoded, 'hex').eq(p));
183 | assert(curve.decodePoint(definition.hybrid, 'hex').eq(p));
184 | };
185 | }
186 |
187 | function makeMontTest(definition) {
188 | var curve = elliptic.curves.curve25519.curve;
189 |
190 | return function() {
191 | var co = definition.coordinates;
192 | var p = curve.point(co.x, co.z);
193 | var encoded = p.encode('hex');
194 | var decoded = curve.decodePoint(encoded, 'hex');
195 | assert(decoded.eq(p));
196 | assert.equal(encoded, definition.encoded);
197 | };
198 | }
199 |
200 | var shortPointEvenY = {
201 | coordinates: {
202 | x: '79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798',
203 | y: '483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8'
204 | },
205 | compactEncoded:
206 | '02' +
207 | '79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798',
208 | encoded:
209 | '04' +
210 | '79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798' +
211 | '483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8',
212 | hybrid:
213 | '06' +
214 | '79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798' +
215 | '483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8'
216 | };
217 |
218 | var shortPointOddY = {
219 | coordinates: {
220 | x: 'fff97bd5755eeea420453a14355235d382f6472f8568a18b2f057a1460297556',
221 | y: 'ae12777aacfbb620f3be96017f45c560de80f0f6518fe4a03c870c36b075f297'
222 | },
223 | compactEncoded:
224 | '03' +
225 | 'fff97bd5755eeea420453a14355235d382f6472f8568a18b2f057a1460297556',
226 | encoded:
227 | '04' +
228 | 'fff97bd5755eeea420453a14355235d382f6472f8568a18b2f057a1460297556' +
229 | 'ae12777aacfbb620f3be96017f45c560de80f0f6518fe4a03c870c36b075f297',
230 | hybrid:
231 | '07' +
232 | 'fff97bd5755eeea420453a14355235d382f6472f8568a18b2f057a1460297556' +
233 | 'ae12777aacfbb620f3be96017f45c560de80f0f6518fe4a03c870c36b075f297'
234 | };
235 |
236 | it('should throw when trying to decode random bytes', function() {
237 | assert.throws(function() {
238 | elliptic.curves.secp256k1.curve.decodePoint(
239 | '05' +
240 | '79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798');
241 | });
242 | });
243 |
244 | it('should be able to encode/decode a short curve point with even Y',
245 | makeShortTest(shortPointEvenY));
246 |
247 | it('should be able to encode/decode a short curve point with odd Y',
248 | makeShortTest(shortPointOddY));
249 |
250 | it('should be able to encode/decode a mont curve point', makeMontTest({
251 | coordinates: {
252 | // curve25519.curve.g.mul(new BN('6')).getX().toString(16, 2)
253 | x: '26954ccdc99ebf34f8f1dde5e6bb080685fec73640494c28f9fe0bfa8c794531',
254 | z: '1'
255 | },
256 | encoded:
257 | '26954ccdc99ebf34f8f1dde5e6bb080685fec73640494c28f9fe0bfa8c794531'
258 | }));
259 | });
260 |
--------------------------------------------------------------------------------
/lib/elliptic/curve/base.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var BN = require('bn.js');
4 | var elliptic = require('../../elliptic');
5 | var utils = elliptic.utils;
6 | var getNAF = utils.getNAF;
7 | var getJSF = utils.getJSF;
8 | var assert = utils.assert;
9 |
10 | function BaseCurve(type, conf) {
11 | this.type = type;
12 | this.p = new BN(conf.p, 16);
13 |
14 | // Use Montgomery, when there is no fast reduction for the prime
15 | this.red = conf.prime ? BN.red(conf.prime) : BN.mont(this.p);
16 |
17 | // Useful for many curves
18 | this.zero = new BN(0).toRed(this.red);
19 | this.one = new BN(1).toRed(this.red);
20 | this.two = new BN(2).toRed(this.red);
21 |
22 | // Curve configuration, optional
23 | this.n = conf.n && new BN(conf.n, 16);
24 | this.g = conf.g && this.pointFromJSON(conf.g, conf.gRed);
25 |
26 | // Temporary arrays
27 | this._wnafT1 = new Array(4);
28 | this._wnafT2 = new Array(4);
29 | this._wnafT3 = new Array(4);
30 | this._wnafT4 = new Array(4);
31 |
32 | // Generalized Greg Maxwell's trick
33 | var adjustCount = this.n && this.p.div(this.n);
34 | if (!adjustCount || adjustCount.cmpn(100) > 0) {
35 | this.redN = null;
36 | } else {
37 | this._maxwellTrick = true;
38 | this.redN = this.n.toRed(this.red);
39 | }
40 | }
41 | module.exports = BaseCurve;
42 |
43 | BaseCurve.prototype.point = function point() {
44 | throw new Error('Not implemented');
45 | };
46 |
47 | BaseCurve.prototype.validate = function validate() {
48 | throw new Error('Not implemented');
49 | };
50 |
51 | BaseCurve.prototype._fixedNafMul = function _fixedNafMul(p, k) {
52 | assert(p.precomputed);
53 | var doubles = p._getDoubles();
54 |
55 | var naf = getNAF(k, 1);
56 | var I = (1 << (doubles.step + 1)) - (doubles.step % 2 === 0 ? 2 : 1);
57 | I /= 3;
58 |
59 | // Translate into more windowed form
60 | var repr = [];
61 | for (var j = 0; j < naf.length; j += doubles.step) {
62 | var nafW = 0;
63 | for (var k = j + doubles.step - 1; k >= j; k--)
64 | nafW = (nafW << 1) + naf[k];
65 | repr.push(nafW);
66 | }
67 |
68 | var a = this.jpoint(null, null, null);
69 | var b = this.jpoint(null, null, null);
70 | for (var i = I; i > 0; i--) {
71 | for (var j = 0; j < repr.length; j++) {
72 | var nafW = repr[j];
73 | if (nafW === i)
74 | b = b.mixedAdd(doubles.points[j]);
75 | else if (nafW === -i)
76 | b = b.mixedAdd(doubles.points[j].neg());
77 | }
78 | a = a.add(b);
79 | }
80 | return a.toP();
81 | };
82 |
83 | BaseCurve.prototype._wnafMul = function _wnafMul(p, k) {
84 | var w = 4;
85 |
86 | // Precompute window
87 | var nafPoints = p._getNAFPoints(w);
88 | w = nafPoints.wnd;
89 | var wnd = nafPoints.points;
90 |
91 | // Get NAF form
92 | var naf = getNAF(k, w);
93 |
94 | // Add `this`*(N+1) for every w-NAF index
95 | var acc = this.jpoint(null, null, null);
96 | for (var i = naf.length - 1; i >= 0; i--) {
97 | // Count zeroes
98 | for (var k = 0; i >= 0 && naf[i] === 0; i--)
99 | k++;
100 | if (i >= 0)
101 | k++;
102 | acc = acc.dblp(k);
103 |
104 | if (i < 0)
105 | break;
106 | var z = naf[i];
107 | assert(z !== 0);
108 | if (p.type === 'affine') {
109 | // J +- P
110 | if (z > 0)
111 | acc = acc.mixedAdd(wnd[(z - 1) >> 1]);
112 | else
113 | acc = acc.mixedAdd(wnd[(-z - 1) >> 1].neg());
114 | } else {
115 | // J +- J
116 | if (z > 0)
117 | acc = acc.add(wnd[(z - 1) >> 1]);
118 | else
119 | acc = acc.add(wnd[(-z - 1) >> 1].neg());
120 | }
121 | }
122 | return p.type === 'affine' ? acc.toP() : acc;
123 | };
124 |
125 | BaseCurve.prototype._wnafMulAdd = function _wnafMulAdd(defW,
126 | points,
127 | coeffs,
128 | len,
129 | jacobianResult) {
130 | var wndWidth = this._wnafT1;
131 | var wnd = this._wnafT2;
132 | var naf = this._wnafT3;
133 |
134 | // Fill all arrays
135 | var max = 0;
136 | for (var i = 0; i < len; i++) {
137 | var p = points[i];
138 | var nafPoints = p._getNAFPoints(defW);
139 | wndWidth[i] = nafPoints.wnd;
140 | wnd[i] = nafPoints.points;
141 | }
142 |
143 | // Comb small window NAFs
144 | for (var i = len - 1; i >= 1; i -= 2) {
145 | var a = i - 1;
146 | var b = i;
147 | if (wndWidth[a] !== 1 || wndWidth[b] !== 1) {
148 | naf[a] = getNAF(coeffs[a], wndWidth[a]);
149 | naf[b] = getNAF(coeffs[b], wndWidth[b]);
150 | max = Math.max(naf[a].length, max);
151 | max = Math.max(naf[b].length, max);
152 | continue;
153 | }
154 |
155 | var comb = [
156 | points[a], /* 1 */
157 | null, /* 3 */
158 | null, /* 5 */
159 | points[b] /* 7 */
160 | ];
161 |
162 | // Try to avoid Projective points, if possible
163 | if (points[a].y.cmp(points[b].y) === 0) {
164 | comb[1] = points[a].add(points[b]);
165 | comb[2] = points[a].toJ().mixedAdd(points[b].neg());
166 | } else if (points[a].y.cmp(points[b].y.redNeg()) === 0) {
167 | comb[1] = points[a].toJ().mixedAdd(points[b]);
168 | comb[2] = points[a].add(points[b].neg());
169 | } else {
170 | comb[1] = points[a].toJ().mixedAdd(points[b]);
171 | comb[2] = points[a].toJ().mixedAdd(points[b].neg());
172 | }
173 |
174 | var index = [
175 | -3, /* -1 -1 */
176 | -1, /* -1 0 */
177 | -5, /* -1 1 */
178 | -7, /* 0 -1 */
179 | 0, /* 0 0 */
180 | 7, /* 0 1 */
181 | 5, /* 1 -1 */
182 | 1, /* 1 0 */
183 | 3 /* 1 1 */
184 | ];
185 |
186 | var jsf = getJSF(coeffs[a], coeffs[b]);
187 | max = Math.max(jsf[0].length, max);
188 | naf[a] = new Array(max);
189 | naf[b] = new Array(max);
190 | for (var j = 0; j < max; j++) {
191 | var ja = jsf[0][j] | 0;
192 | var jb = jsf[1][j] | 0;
193 |
194 | naf[a][j] = index[(ja + 1) * 3 + (jb + 1)];
195 | naf[b][j] = 0;
196 | wnd[a] = comb;
197 | }
198 | }
199 |
200 | var acc = this.jpoint(null, null, null);
201 | var tmp = this._wnafT4;
202 | for (var i = max; i >= 0; i--) {
203 | var k = 0;
204 |
205 | while (i >= 0) {
206 | var zero = true;
207 | for (var j = 0; j < len; j++) {
208 | tmp[j] = naf[j][i] | 0;
209 | if (tmp[j] !== 0)
210 | zero = false;
211 | }
212 | if (!zero)
213 | break;
214 | k++;
215 | i--;
216 | }
217 | if (i >= 0)
218 | k++;
219 | acc = acc.dblp(k);
220 | if (i < 0)
221 | break;
222 |
223 | for (var j = 0; j < len; j++) {
224 | var z = tmp[j];
225 | var p;
226 | if (z === 0)
227 | continue;
228 | else if (z > 0)
229 | p = wnd[j][(z - 1) >> 1];
230 | else if (z < 0)
231 | p = wnd[j][(-z - 1) >> 1].neg();
232 |
233 | if (p.type === 'affine')
234 | acc = acc.mixedAdd(p);
235 | else
236 | acc = acc.add(p);
237 | }
238 | }
239 | // Zeroify references
240 | for (var i = 0; i < len; i++)
241 | wnd[i] = null;
242 |
243 | if (jacobianResult)
244 | return acc;
245 | else
246 | return acc.toP();
247 | };
248 |
249 | function BasePoint(curve, type) {
250 | this.curve = curve;
251 | this.type = type;
252 | this.precomputed = null;
253 | }
254 | BaseCurve.BasePoint = BasePoint;
255 |
256 | BasePoint.prototype.eq = function eq(/*other*/) {
257 | throw new Error('Not implemented');
258 | };
259 |
260 | BasePoint.prototype.validate = function validate() {
261 | return this.curve.validate(this);
262 | };
263 |
264 | BaseCurve.prototype.decodePoint = function decodePoint(bytes, enc) {
265 | bytes = utils.toArray(bytes, enc);
266 |
267 | var len = this.p.byteLength();
268 |
269 | // uncompressed, hybrid-odd, hybrid-even
270 | if ((bytes[0] === 0x04 || bytes[0] === 0x06 || bytes[0] === 0x07) &&
271 | bytes.length - 1 === 2 * len) {
272 | if (bytes[0] === 0x06)
273 | assert(bytes[bytes.length - 1] % 2 === 0);
274 | else if (bytes[0] === 0x07)
275 | assert(bytes[bytes.length - 1] % 2 === 1);
276 |
277 | var res = this.point(bytes.slice(1, 1 + len),
278 | bytes.slice(1 + len, 1 + 2 * len));
279 |
280 | return res;
281 | } else if ((bytes[0] === 0x02 || bytes[0] === 0x03) &&
282 | bytes.length - 1 === len) {
283 | return this.pointFromX(bytes.slice(1, 1 + len), bytes[0] === 0x03);
284 | }
285 | throw new Error('Unknown point format');
286 | };
287 |
288 | BasePoint.prototype.encodeCompressed = function encodeCompressed(enc) {
289 | return this.encode(enc, true);
290 | };
291 |
292 | BasePoint.prototype._encode = function _encode(compact) {
293 | var len = this.curve.p.byteLength();
294 | var x = this.getX().toArray('be', len);
295 |
296 | if (compact)
297 | return [ this.getY().isEven() ? 0x02 : 0x03 ].concat(x);
298 |
299 | return [ 0x04 ].concat(x, this.getY().toArray('be', len)) ;
300 | };
301 |
302 | BasePoint.prototype.encode = function encode(enc, compact) {
303 | return utils.encode(this._encode(compact), enc);
304 | };
305 |
306 | BasePoint.prototype.precompute = function precompute(power) {
307 | if (this.precomputed)
308 | return this;
309 |
310 | var precomputed = {
311 | doubles: null,
312 | naf: null,
313 | beta: null
314 | };
315 | precomputed.naf = this._getNAFPoints(8);
316 | precomputed.doubles = this._getDoubles(4, power);
317 | precomputed.beta = this._getBeta();
318 | this.precomputed = precomputed;
319 |
320 | return this;
321 | };
322 |
323 | BasePoint.prototype._hasDoubles = function _hasDoubles(k) {
324 | if (!this.precomputed)
325 | return false;
326 |
327 | var doubles = this.precomputed.doubles;
328 | if (!doubles)
329 | return false;
330 |
331 | return doubles.points.length >= Math.ceil((k.bitLength() + 1) / doubles.step);
332 | };
333 |
334 | BasePoint.prototype._getDoubles = function _getDoubles(step, power) {
335 | if (this.precomputed && this.precomputed.doubles)
336 | return this.precomputed.doubles;
337 |
338 | var doubles = [ this ];
339 | var acc = this;
340 | for (var i = 0; i < power; i += step) {
341 | for (var j = 0; j < step; j++)
342 | acc = acc.dbl();
343 | doubles.push(acc);
344 | }
345 | return {
346 | step: step,
347 | points: doubles
348 | };
349 | };
350 |
351 | BasePoint.prototype._getNAFPoints = function _getNAFPoints(wnd) {
352 | if (this.precomputed && this.precomputed.naf)
353 | return this.precomputed.naf;
354 |
355 | var res = [ this ];
356 | var max = (1 << wnd) - 1;
357 | var dbl = max === 1 ? null : this.dbl();
358 | for (var i = 1; i < max; i++)
359 | res[i] = res[i - 1].add(dbl);
360 | return {
361 | wnd: wnd,
362 | points: res
363 | };
364 | };
365 |
366 | BasePoint.prototype._getBeta = function _getBeta() {
367 | return null;
368 | };
369 |
370 | BasePoint.prototype.dblp = function dblp(k) {
371 | var r = this;
372 | for (var i = 0; i < k; i++)
373 | r = r.dbl();
374 | return r;
375 | };
376 |
--------------------------------------------------------------------------------
/lib/elliptic/curve/edwards.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var curve = require('../curve');
4 | var elliptic = require('../../elliptic');
5 | var BN = require('bn.js');
6 | var inherits = require('inherits');
7 | var Base = curve.base;
8 |
9 | var assert = elliptic.utils.assert;
10 |
11 | function EdwardsCurve(conf) {
12 | // NOTE: Important as we are creating point in Base.call()
13 | this.twisted = (conf.a | 0) !== 1;
14 | this.mOneA = this.twisted && (conf.a | 0) === -1;
15 | this.extended = this.mOneA;
16 |
17 | Base.call(this, 'edwards', conf);
18 |
19 | this.a = new BN(conf.a, 16).umod(this.red.m);
20 | this.a = this.a.toRed(this.red);
21 | this.c = new BN(conf.c, 16).toRed(this.red);
22 | this.c2 = this.c.redSqr();
23 | this.d = new BN(conf.d, 16).toRed(this.red);
24 | this.dd = this.d.redAdd(this.d);
25 |
26 | assert(!this.twisted || this.c.fromRed().cmpn(1) === 0);
27 | this.oneC = (conf.c | 0) === 1;
28 | }
29 | inherits(EdwardsCurve, Base);
30 | module.exports = EdwardsCurve;
31 |
32 | EdwardsCurve.prototype._mulA = function _mulA(num) {
33 | if (this.mOneA)
34 | return num.redNeg();
35 | else
36 | return this.a.redMul(num);
37 | };
38 |
39 | EdwardsCurve.prototype._mulC = function _mulC(num) {
40 | if (this.oneC)
41 | return num;
42 | else
43 | return this.c.redMul(num);
44 | };
45 |
46 | // Just for compatibility with Short curve
47 | EdwardsCurve.prototype.jpoint = function jpoint(x, y, z, t) {
48 | return this.point(x, y, z, t);
49 | };
50 |
51 | EdwardsCurve.prototype.pointFromX = function pointFromX(x, odd) {
52 | x = new BN(x, 16);
53 | if (!x.red)
54 | x = x.toRed(this.red);
55 |
56 | var x2 = x.redSqr();
57 | var rhs = this.c2.redSub(this.a.redMul(x2));
58 | var lhs = this.one.redSub(this.c2.redMul(this.d).redMul(x2));
59 |
60 | var y2 = rhs.redMul(lhs.redInvm());
61 | var y = y2.redSqrt();
62 | if (y.redSqr().redSub(y2).cmp(this.zero) !== 0)
63 | throw new Error('invalid point');
64 |
65 | var isOdd = y.fromRed().isOdd();
66 | if (odd && !isOdd || !odd && isOdd)
67 | y = y.redNeg();
68 |
69 | return this.point(x, y);
70 | };
71 |
72 | EdwardsCurve.prototype.pointFromY = function pointFromY(y, odd) {
73 | y = new BN(y, 16);
74 | if (!y.red)
75 | y = y.toRed(this.red);
76 |
77 | // x^2 = (y^2 - 1) / (d y^2 + 1)
78 | var y2 = y.redSqr();
79 | var lhs = y2.redSub(this.one);
80 | var rhs = y2.redMul(this.d).redAdd(this.one);
81 | var x2 = lhs.redMul(rhs.redInvm());
82 |
83 | if (x2.cmp(this.zero) === 0) {
84 | if (odd)
85 | throw new Error('invalid point');
86 | else
87 | return this.point(this.zero, y);
88 | }
89 |
90 | var x = x2.redSqrt();
91 | if (x.redSqr().redSub(x2).cmp(this.zero) !== 0)
92 | throw new Error('invalid point');
93 |
94 | if (x.isOdd() !== odd)
95 | x = x.redNeg();
96 |
97 | return this.point(x, y);
98 | };
99 |
100 | EdwardsCurve.prototype.validate = function validate(point) {
101 | if (point.isInfinity())
102 | return true;
103 |
104 | // Curve: A * X^2 + Y^2 = C^2 * (1 + D * X^2 * Y^2)
105 | point.normalize();
106 |
107 | var x2 = point.x.redSqr();
108 | var y2 = point.y.redSqr();
109 | var lhs = x2.redMul(this.a).redAdd(y2);
110 | var rhs = this.c2.redMul(this.one.redAdd(this.d.redMul(x2).redMul(y2)));
111 |
112 | return lhs.cmp(rhs) === 0;
113 | };
114 |
115 | function Point(curve, x, y, z, t) {
116 | Base.BasePoint.call(this, curve, 'projective');
117 | if (x === null && y === null && z === null) {
118 | this.x = this.curve.zero;
119 | this.y = this.curve.one;
120 | this.z = this.curve.one;
121 | this.t = this.curve.zero;
122 | this.zOne = true;
123 | } else {
124 | this.x = new BN(x, 16);
125 | this.y = new BN(y, 16);
126 | this.z = z ? new BN(z, 16) : this.curve.one;
127 | this.t = t && new BN(t, 16);
128 | if (!this.x.red)
129 | this.x = this.x.toRed(this.curve.red);
130 | if (!this.y.red)
131 | this.y = this.y.toRed(this.curve.red);
132 | if (!this.z.red)
133 | this.z = this.z.toRed(this.curve.red);
134 | if (this.t && !this.t.red)
135 | this.t = this.t.toRed(this.curve.red);
136 | this.zOne = this.z === this.curve.one;
137 |
138 | // Use extended coordinates
139 | if (this.curve.extended && !this.t) {
140 | this.t = this.x.redMul(this.y);
141 | if (!this.zOne)
142 | this.t = this.t.redMul(this.z.redInvm());
143 | }
144 | }
145 | }
146 | inherits(Point, Base.BasePoint);
147 |
148 | EdwardsCurve.prototype.pointFromJSON = function pointFromJSON(obj) {
149 | return Point.fromJSON(this, obj);
150 | };
151 |
152 | EdwardsCurve.prototype.point = function point(x, y, z, t) {
153 | return new Point(this, x, y, z, t);
154 | };
155 |
156 | Point.fromJSON = function fromJSON(curve, obj) {
157 | return new Point(curve, obj[0], obj[1], obj[2]);
158 | };
159 |
160 | Point.prototype.inspect = function inspect() {
161 | if (this.isInfinity())
162 | return '';
163 | return '';
166 | };
167 |
168 | Point.prototype.isInfinity = function isInfinity() {
169 | // XXX This code assumes that zero is always zero in red
170 | return this.x.cmpn(0) === 0 &&
171 | this.y.cmp(this.z) === 0;
172 | };
173 |
174 | Point.prototype._extDbl = function _extDbl() {
175 | // hyperelliptic.org/EFD/g1p/auto-twisted-extended-1.html
176 | // #doubling-dbl-2008-hwcd
177 | // 4M + 4S
178 |
179 | // A = X1^2
180 | var a = this.x.redSqr();
181 | // B = Y1^2
182 | var b = this.y.redSqr();
183 | // C = 2 * Z1^2
184 | var c = this.z.redSqr();
185 | c = c.redIAdd(c);
186 | // D = a * A
187 | var d = this.curve._mulA(a);
188 | // E = (X1 + Y1)^2 - A - B
189 | var e = this.x.redAdd(this.y).redSqr().redISub(a).redISub(b);
190 | // G = D + B
191 | var g = d.redAdd(b);
192 | // F = G - C
193 | var f = g.redSub(c);
194 | // H = D - B
195 | var h = d.redSub(b);
196 | // X3 = E * F
197 | var nx = e.redMul(f);
198 | // Y3 = G * H
199 | var ny = g.redMul(h);
200 | // T3 = E * H
201 | var nt = e.redMul(h);
202 | // Z3 = F * G
203 | var nz = f.redMul(g);
204 | return this.curve.point(nx, ny, nz, nt);
205 | };
206 |
207 | Point.prototype._projDbl = function _projDbl() {
208 | // hyperelliptic.org/EFD/g1p/auto-twisted-projective.html
209 | // #doubling-dbl-2008-bbjlp
210 | // #doubling-dbl-2007-bl
211 | // and others
212 | // Generally 3M + 4S or 2M + 4S
213 |
214 | // B = (X1 + Y1)^2
215 | var b = this.x.redAdd(this.y).redSqr();
216 | // C = X1^2
217 | var c = this.x.redSqr();
218 | // D = Y1^2
219 | var d = this.y.redSqr();
220 |
221 | var nx;
222 | var ny;
223 | var nz;
224 | if (this.curve.twisted) {
225 | // E = a * C
226 | var e = this.curve._mulA(c);
227 | // F = E + D
228 | var f = e.redAdd(d);
229 | if (this.zOne) {
230 | // X3 = (B - C - D) * (F - 2)
231 | nx = b.redSub(c).redSub(d).redMul(f.redSub(this.curve.two));
232 | // Y3 = F * (E - D)
233 | ny = f.redMul(e.redSub(d));
234 | // Z3 = F^2 - 2 * F
235 | nz = f.redSqr().redSub(f).redSub(f);
236 | } else {
237 | // H = Z1^2
238 | var h = this.z.redSqr();
239 | // J = F - 2 * H
240 | var j = f.redSub(h).redISub(h);
241 | // X3 = (B-C-D)*J
242 | nx = b.redSub(c).redISub(d).redMul(j);
243 | // Y3 = F * (E - D)
244 | ny = f.redMul(e.redSub(d));
245 | // Z3 = F * J
246 | nz = f.redMul(j);
247 | }
248 | } else {
249 | // E = C + D
250 | var e = c.redAdd(d);
251 | // H = (c * Z1)^2
252 | var h = this.curve._mulC(this.c.redMul(this.z)).redSqr();
253 | // J = E - 2 * H
254 | var j = e.redSub(h).redSub(h);
255 | // X3 = c * (B - E) * J
256 | nx = this.curve._mulC(b.redISub(e)).redMul(j);
257 | // Y3 = c * E * (C - D)
258 | ny = this.curve._mulC(e).redMul(c.redISub(d));
259 | // Z3 = E * J
260 | nz = e.redMul(j);
261 | }
262 | return this.curve.point(nx, ny, nz);
263 | };
264 |
265 | Point.prototype.dbl = function dbl() {
266 | if (this.isInfinity())
267 | return this;
268 |
269 | // Double in extended coordinates
270 | if (this.curve.extended)
271 | return this._extDbl();
272 | else
273 | return this._projDbl();
274 | };
275 |
276 | Point.prototype._extAdd = function _extAdd(p) {
277 | // hyperelliptic.org/EFD/g1p/auto-twisted-extended-1.html
278 | // #addition-add-2008-hwcd-3
279 | // 8M
280 |
281 | // A = (Y1 - X1) * (Y2 - X2)
282 | var a = this.y.redSub(this.x).redMul(p.y.redSub(p.x));
283 | // B = (Y1 + X1) * (Y2 + X2)
284 | var b = this.y.redAdd(this.x).redMul(p.y.redAdd(p.x));
285 | // C = T1 * k * T2
286 | var c = this.t.redMul(this.curve.dd).redMul(p.t);
287 | // D = Z1 * 2 * Z2
288 | var d = this.z.redMul(p.z.redAdd(p.z));
289 | // E = B - A
290 | var e = b.redSub(a);
291 | // F = D - C
292 | var f = d.redSub(c);
293 | // G = D + C
294 | var g = d.redAdd(c);
295 | // H = B + A
296 | var h = b.redAdd(a);
297 | // X3 = E * F
298 | var nx = e.redMul(f);
299 | // Y3 = G * H
300 | var ny = g.redMul(h);
301 | // T3 = E * H
302 | var nt = e.redMul(h);
303 | // Z3 = F * G
304 | var nz = f.redMul(g);
305 | return this.curve.point(nx, ny, nz, nt);
306 | };
307 |
308 | Point.prototype._projAdd = function _projAdd(p) {
309 | // hyperelliptic.org/EFD/g1p/auto-twisted-projective.html
310 | // #addition-add-2008-bbjlp
311 | // #addition-add-2007-bl
312 | // 10M + 1S
313 |
314 | // A = Z1 * Z2
315 | var a = this.z.redMul(p.z);
316 | // B = A^2
317 | var b = a.redSqr();
318 | // C = X1 * X2
319 | var c = this.x.redMul(p.x);
320 | // D = Y1 * Y2
321 | var d = this.y.redMul(p.y);
322 | // E = d * C * D
323 | var e = this.curve.d.redMul(c).redMul(d);
324 | // F = B - E
325 | var f = b.redSub(e);
326 | // G = B + E
327 | var g = b.redAdd(e);
328 | // X3 = A * F * ((X1 + Y1) * (X2 + Y2) - C - D)
329 | var tmp = this.x.redAdd(this.y).redMul(p.x.redAdd(p.y)).redISub(c).redISub(d);
330 | var nx = a.redMul(f).redMul(tmp);
331 | var ny;
332 | var nz;
333 | if (this.curve.twisted) {
334 | // Y3 = A * G * (D - a * C)
335 | ny = a.redMul(g).redMul(d.redSub(this.curve._mulA(c)));
336 | // Z3 = F * G
337 | nz = f.redMul(g);
338 | } else {
339 | // Y3 = A * G * (D - C)
340 | ny = a.redMul(g).redMul(d.redSub(c));
341 | // Z3 = c * F * G
342 | nz = this.curve._mulC(f).redMul(g);
343 | }
344 | return this.curve.point(nx, ny, nz);
345 | };
346 |
347 | Point.prototype.add = function add(p) {
348 | if (this.isInfinity())
349 | return p;
350 | if (p.isInfinity())
351 | return this;
352 |
353 | if (this.curve.extended)
354 | return this._extAdd(p);
355 | else
356 | return this._projAdd(p);
357 | };
358 |
359 | Point.prototype.mul = function mul(k) {
360 | if (this._hasDoubles(k))
361 | return this.curve._fixedNafMul(this, k);
362 | else
363 | return this.curve._wnafMul(this, k);
364 | };
365 |
366 | Point.prototype.mulAdd = function mulAdd(k1, p, k2) {
367 | return this.curve._wnafMulAdd(1, [ this, p ], [ k1, k2 ], 2, false);
368 | };
369 |
370 | Point.prototype.jmulAdd = function jmulAdd(k1, p, k2) {
371 | return this.curve._wnafMulAdd(1, [ this, p ], [ k1, k2 ], 2, true);
372 | };
373 |
374 | Point.prototype.normalize = function normalize() {
375 | if (this.zOne)
376 | return this;
377 |
378 | // Normalize coordinates
379 | var zi = this.z.redInvm();
380 | this.x = this.x.redMul(zi);
381 | this.y = this.y.redMul(zi);
382 | if (this.t)
383 | this.t = this.t.redMul(zi);
384 | this.z = this.curve.one;
385 | this.zOne = true;
386 | return this;
387 | };
388 |
389 | Point.prototype.neg = function neg() {
390 | return this.curve.point(this.x.redNeg(),
391 | this.y,
392 | this.z,
393 | this.t && this.t.redNeg());
394 | };
395 |
396 | Point.prototype.getX = function getX() {
397 | this.normalize();
398 | return this.x.fromRed();
399 | };
400 |
401 | Point.prototype.getY = function getY() {
402 | this.normalize();
403 | return this.y.fromRed();
404 | };
405 |
406 | Point.prototype.eq = function eq(other) {
407 | return this === other ||
408 | this.getX().cmp(other.getX()) === 0 &&
409 | this.getY().cmp(other.getY()) === 0;
410 | };
411 |
412 | Point.prototype.eqXToP = function eqXToP(x) {
413 | var rx = x.toRed(this.curve.red).redMul(this.z);
414 | if (this.x.cmp(rx) === 0)
415 | return true;
416 |
417 | var xc = x.clone();
418 | var t = this.curve.redN.redMul(this.z);
419 | for (;;) {
420 | xc.iadd(this.curve.n);
421 | if (xc.cmp(this.curve.p) >= 0)
422 | return false;
423 |
424 | rx.redIAdd(t);
425 | if (this.x.cmp(rx) === 0)
426 | return true;
427 | }
428 | };
429 |
430 | // Compatibility with BaseCurve
431 | Point.prototype.toP = Point.prototype.normalize;
432 | Point.prototype.mixedAdd = Point.prototype.add;
433 |
--------------------------------------------------------------------------------
/test/ecdsa-test.js:
--------------------------------------------------------------------------------
1 | var assert = require('assert');
2 | var elliptic = require('../');
3 | var Signature = require('../lib/elliptic/ec/signature')
4 | var BN = require('bn.js');
5 | var hash = require('hash.js');
6 |
7 | var entropy = [
8 | 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
9 | 21, 22, 23, 24, 25
10 | ];
11 |
12 | var msg = 'deadbeef';
13 |
14 | describe('ECDSA', function() {
15 | function test(name) {
16 | describe('curve ' + name, function() {
17 | var curve;
18 | var ecdsa;
19 |
20 | beforeEach(function() {
21 | curve = elliptic.curves[name];
22 | assert(curve);
23 |
24 | ecdsa = new elliptic.ec(curve);
25 | keys = ecdsa.genKeyPair({
26 | entropy: entropy
27 | });
28 | });
29 |
30 | it('should generate proper key pair', function() {
31 | var keylen = 64;
32 | if (name === 'p384') {
33 | keylen = 96;
34 | } else if (name === 'p521') {
35 | keylen = 132
36 | }
37 | // Get keys out of pair
38 | assert(keys.getPublic().x && keys.getPublic().y);
39 | assert(keys.getPrivate().length > 0);
40 | assert.equal(keys.getPrivate('hex').length, keylen);
41 | assert(keys.getPublic('hex').length > 0);
42 | assert(keys.getPrivate('hex').length > 0);
43 | assert(keys.validate().result);
44 | });
45 |
46 | it('should sign and verify', function() {
47 | var signature = ecdsa.sign(msg, keys);
48 | assert(ecdsa.verify(msg, signature, keys), 'Normal verify');
49 | });
50 |
51 | it('should sign and verify using key\'s methods', function() {
52 | var signature = keys.sign(msg);
53 | assert(keys.verify(msg, signature), 'On-key verify');
54 | });
55 |
56 | it('should load private key from the hex value', function() {
57 | var copy = ecdsa.keyFromPrivate(keys.getPrivate('hex'), 'hex');
58 | var signature = ecdsa.sign(msg, copy);
59 | assert(ecdsa.verify(msg, signature, copy), 'hex-private verify');
60 | });
61 |
62 | it('should have `signature.s <= keys.ec.nh`', function() {
63 | // key.sign(msg, options)
64 | var sign = keys.sign('hello', { canonical: true });
65 | assert(sign.s.cmp(keys.ec.nh) <= 0);
66 | });
67 |
68 | it('should support `options.k`', function() {
69 | var sign = keys.sign(msg, {
70 | k: function(iter) {
71 | assert(iter >= 0);
72 | return new BN(1358);
73 | }
74 | });
75 | assert(ecdsa.verify(msg, sign, keys), 'custom-k verify');
76 | });
77 |
78 | it('should have another signature with pers', function () {
79 | var sign1 = keys.sign(msg);
80 | var sign2 = keys.sign(msg, { pers: '1234', persEnc: 'hex' });
81 | assert.notEqual(sign1.r.toArray().concat(sign1.s.toArray()),
82 | sign2.r.toArray().concat(sign2.s.toArray()));
83 | });
84 |
85 | it('should load public key from compact hex value', function() {
86 | var pub = keys.getPublic(true, 'hex');
87 | var copy = ecdsa.keyFromPublic(pub, 'hex');
88 | assert.equal(copy.getPublic(true, 'hex'), pub);
89 | });
90 |
91 | it('should load public key from hex value', function() {
92 | var pub = keys.getPublic('hex');
93 | var copy = ecdsa.keyFromPublic(pub, 'hex');
94 | assert.equal(copy.getPublic('hex'), pub);
95 | });
96 |
97 | it('should support hex DER encoding of signatures', function() {
98 | var signature = ecdsa.sign(msg, keys);
99 | var dsign = signature.toDER('hex');
100 | assert(ecdsa.verify(msg, dsign, keys), 'hex-DER encoded verify');
101 | });
102 |
103 | it('should support DER encoding of signatures', function() {
104 | var signature = ecdsa.sign(msg, keys);
105 | var dsign = signature.toDER();
106 | assert(ecdsa.verify(msg, dsign, keys), 'DER encoded verify');
107 | });
108 |
109 | it('should not verify signature with wrong public key', function() {
110 | var signature = ecdsa.sign(msg, keys);
111 |
112 | var wrong = ecdsa.genKeyPair();
113 | assert(!ecdsa.verify(msg, signature, wrong), 'Wrong key verify');
114 | });
115 |
116 | it('should not verify signature with wrong private key', function() {
117 | var signature = ecdsa.sign(msg, keys);
118 |
119 | var wrong = ecdsa.keyFromPrivate(keys.getPrivate('hex') +
120 | keys.getPrivate('hex'));
121 | assert(!ecdsa.verify(msg, signature, wrong), 'Wrong key verify');
122 | });
123 | });
124 | }
125 | test('secp256k1');
126 | test('ed25519');
127 | test('p256');
128 | test('p384');
129 | test('p521');
130 |
131 | describe('RFC6979 vector', function() {
132 | function test(opt) {
133 | opt.cases.forEach(function(c) {
134 | var ecdsa = elliptic.ec({
135 | curve: opt.curve,
136 | hash: c.hash
137 | });
138 | var descr = 'should not fail on "' + opt.name + '" ' +
139 | 'and hash ' + c.hash.name + ' on "' + c.message + '"';
140 | it(descr, function() {
141 | var dgst = c.hash().update(c.message).digest();
142 | var sign = ecdsa.sign(dgst, opt.key);
143 | assert.equal(sign.r.toString(16), c.r);
144 | assert.equal(sign.s.toString(16), c.s);
145 | assert.ok(ecdsa.keyFromPublic(opt.pub).validate().result,
146 | 'Invalid public key');
147 | assert.ok(ecdsa.verify(dgst, sign, opt.pub),
148 | 'Invalid signature');
149 | });
150 | });
151 | }
152 |
153 | test({
154 | name: 'ECDSA, 192 Bits (Prime Field)',
155 | curve: elliptic.curves.p192,
156 | key: '6fab034934e4c0fc9ae67f5b5659a9d7d1fefd187ee09fd4',
157 | pub: {
158 | x: 'ac2c77f529f91689fea0ea5efec7f210d8eea0b9e047ed56',
159 | y: '3bc723e57670bd4887ebc732c523063d0a7c957bc97c1c43'
160 | },
161 | cases: [
162 | {
163 | message: 'sample',
164 | hash: hash.sha224,
165 | r: 'a1f00dad97aeec91c95585f36200c65f3c01812aa60378f5',
166 | s: 'e07ec1304c7c6c9debbe980b9692668f81d4de7922a0f97a'
167 | },
168 | {
169 | message: 'sample',
170 | hash: hash.sha256,
171 | r: '4b0b8ce98a92866a2820e20aa6b75b56382e0f9bfd5ecb55',
172 | s: 'ccdb006926ea9565cbadc840829d8c384e06de1f1e381b85'
173 | },
174 | {
175 | message: 'test',
176 | hash: hash.sha224,
177 | r: '6945a1c1d1b2206b8145548f633bb61cef04891baf26ed34',
178 | s: 'b7fb7fdfc339c0b9bd61a9f5a8eaf9be58fc5cba2cb15293'
179 | },
180 | {
181 | message: 'test',
182 | hash: hash.sha256,
183 | r: '3a718bd8b4926c3b52ee6bbe67ef79b18cb6eb62b1ad97ae',
184 | s: '5662e6848a4a19b1f1ae2f72acd4b8bbe50f1eac65d9124f'
185 | }
186 | ]
187 | });
188 |
189 | test({
190 | name: 'ECDSA, 224 Bits (Prime Field)',
191 | curve: elliptic.curves.p224,
192 | key: 'f220266e1105bfe3083e03ec7a3a654651f45e37167e88600bf257c1',
193 | pub: {
194 | x: '00cf08da5ad719e42707fa431292dea11244d64fc51610d94b130d6c',
195 | y: 'eeab6f3debe455e3dbf85416f7030cbd94f34f2d6f232c69f3c1385a'
196 | },
197 | cases: [
198 | {
199 | message: 'sample',
200 | hash: hash.sha224,
201 | r: '1cdfe6662dde1e4a1ec4cdedf6a1f5a2fb7fbd9145c12113e6abfd3e',
202 | s: 'a6694fd7718a21053f225d3f46197ca699d45006c06f871808f43ebc'
203 | },
204 | {
205 | message: 'sample',
206 | hash: hash.sha256,
207 | r: '61aa3da010e8e8406c656bc477a7a7189895e7e840cdfe8ff42307ba',
208 | s: 'bc814050dab5d23770879494f9e0a680dc1af7161991bde692b10101'
209 | },
210 | {
211 | message: 'test',
212 | hash: hash.sha224,
213 | r: 'c441ce8e261ded634e4cf84910e4c5d1d22c5cf3b732bb204dbef019',
214 | s: '902f42847a63bdc5f6046ada114953120f99442d76510150f372a3f4'
215 | },
216 | {
217 | message: 'test',
218 | hash: hash.sha256,
219 | r: 'ad04dde87b84747a243a631ea47a1ba6d1faa059149ad2440de6fba6',
220 | s: '178d49b1ae90e3d8b629be3db5683915f4e8c99fdf6e666cf37adcfd'
221 | }
222 | ]
223 | });
224 |
225 | test({
226 | name: 'ECDSA, 256 Bits (Prime Field)',
227 | curve: elliptic.curves.p256,
228 | key: 'c9afa9d845ba75166b5c215767b1d6934e50c3db36e89b127b8a622b120f6721',
229 | pub: {
230 | x: '60fed4ba255a9d31c961eb74c6356d68c049b8923b61fa6ce669622e60f29fb6',
231 | y: '7903fe1008b8bc99a41ae9e95628bc64f2f1b20c2d7e9f5177a3c294d4462299'
232 | },
233 | cases: [
234 | {
235 | message: 'sample',
236 | hash: hash.sha224,
237 | r: '53b2fff5d1752b2c689df257c04c40a587fababb3f6fc2702f1343af7ca9aa3f',
238 | s: 'b9afb64fdc03dc1a131c7d2386d11e349f070aa432a4acc918bea988bf75c74c'
239 | },
240 | {
241 | message: 'sample',
242 | hash: hash.sha256,
243 | r: 'efd48b2aacb6a8fd1140dd9cd45e81d69d2c877b56aaf991c34d0ea84eaf3716',
244 | s: 'f7cb1c942d657c41d436c7a1b6e29f65f3e900dbb9aff4064dc4ab2f843acda8'
245 | },
246 | {
247 | message: 'test',
248 | hash: hash.sha224,
249 | r: 'c37edb6f0ae79d47c3c27e962fa269bb4f441770357e114ee511f662ec34a692',
250 | s: 'c820053a05791e521fcaad6042d40aea1d6b1a540138558f47d0719800e18f2d'
251 | },
252 | {
253 | message: 'test',
254 | hash: hash.sha256,
255 | r: 'f1abb023518351cd71d881567b1ea663ed3efcf6c5132b354f28d3b0b7d38367',
256 | s: '19f4113742a2b14bd25926b49c649155f267e60d3814b4c0cc84250e46f0083'
257 | }
258 | ]
259 | });
260 |
261 | test({
262 | name: 'ECDSA, 384 Bits (Prime Field)',
263 | curve: elliptic.curves.p384,
264 | key: '6b9d3dad2e1b8c1c05b19875b6659f4de23c3b667bf297ba9aa4774078713' +
265 | '7d896d5724e4c70a825f872c9ea60d2edf5',
266 | pub: {
267 | x: 'ec3a4e415b4e19a4568618029f427fa5da9a8bc4ae92e02e06aae5286b30' +
268 | '0c64def8f0ea9055866064a254515480bc13',
269 | y: '8015d9b72d7d57244ea8ef9ac0c621896708a59367f9dfb9f54ca84b3f' +
270 | '1c9db1288b231c3ae0d4fe7344fd2533264720'
271 | },
272 | cases: [
273 | {
274 | message: 'sample',
275 | hash: hash.sha224,
276 | r: '42356e76b55a6d9b4631c865445dbe54e056d3b3431766d05092447' +
277 | '93c3f9366450f76ee3de43f5a125333a6be060122',
278 | s: '9da0c81787064021e78df658f2fbb0b042bf304665db721f077a429' +
279 | '8b095e4834c082c03d83028efbf93a3c23940ca8d'
280 | },
281 | {
282 | message: 'sample',
283 | hash: hash.sha384,
284 | r: '94edbb92a5ecb8aad4736e56c691916b3f88140666ce9fa73d6' +
285 | '4c4ea95ad133c81a648152e44acf96e36dd1e80fabe46',
286 | s: '99ef4aeb15f178cea1fe40db2603138f130e740a19624526203b' +
287 | '6351d0a3a94fa329c145786e679e7b82c71a38628ac8'
288 | },
289 | {
290 | message: 'test',
291 | hash: hash.sha384,
292 | r: '8203b63d3c853e8d77227fb377bcf7b7b772e97892a80f36a' +
293 | 'b775d509d7a5feb0542a7f0812998da8f1dd3ca3cf023db',
294 | s: 'ddd0760448d42d8a43af45af836fce4de8be06b485e9b61b827c2f13' +
295 | '173923e06a739f040649a667bf3b828246baa5a5'
296 | }
297 | ]
298 | });
299 |
300 | test({
301 | name: 'ECDSA, 521 Bits (Prime Field)',
302 | curve: elliptic.curves.p521,
303 | key: '0fad06daa62ba3b25d2fb40133da757205de67f5bb0018fee8c86e1b68c7e75' +
304 | 'caa896eb32f1f47c70855836a6d16fcc1466f6d8fbec67db89ec0c08b0e996b' +
305 | '83538',
306 | pub: {
307 | x: '1894550d0785932e00eaa23b694f213f8c3121f86dc97a04e5a7167db4e5bcd3' +
308 | '71123d46e45db6b5d5370a7f20fb633155d38ffa16d2bd761dcac474b9a2f502' +
309 | '3a4',
310 | y: '0493101c962cd4d2fddf782285e64584139c2f91b47f87ff82354d6630f746a2' +
311 | '8a0db25741b5b34a828008b22acc23f924faafbd4d33f81ea66956dfeaa2bfdfcf5'
312 | },
313 | cases: [
314 | {
315 | message: 'sample',
316 | hash: hash.sha384,
317 | r: '1ea842a0e17d2de4f92c15315c63ddf72685c18195c2bb95e572b9c5136ca4' +
318 | 'b4b576ad712a52be9730627d16054ba40cc0b8d3ff035b12ae75168397f5' +
319 | 'd50c67451',
320 | s: '1f21a3cee066e1961025fb048bd5fe2b7924d0cd797babe0a83b66f1e35ee' +
321 | 'af5fde143fa85dc394a7dee766523393784484bdf3e00114a1c857cde1aa2' +
322 | '03db65d61'
323 | },
324 | {
325 | message: 'sample',
326 | hash: hash.sha512,
327 | r: 'c328fafcbd79dd77850370c46325d987cb525569fb63c5d3bc53950e6d4c5f1' +
328 | '74e25a1ee9017b5d450606add152b534931d7d4e8455cc91f9b15bf05ec36e3' +
329 | '77fa',
330 | s: '617cce7cf5064806c467f678d3b4080d6f1cc50af26ca209417308281b68af2' +
331 | '82623eaa63e5b5c0723d8b8c37ff0777b1a20f8ccb1dccc43997f1ee0e44da4' +
332 | 'a67a'
333 | },
334 | {
335 | message: 'test',
336 | hash: hash.sha512,
337 | r: '13e99020abf5cee7525d16b69b229652ab6bdf2affcaef38773b4b7d087' +
338 | '25f10cdb93482fdcc54edcee91eca4166b2a7c6265ef0ce2bd7051b7cef945' +
339 | 'babd47ee6d',
340 | s: '1fbd0013c674aa79cb39849527916ce301c66ea7ce8b80682786ad60f98' +
341 | 'f7e78a19ca69eff5c57400e3b3a0ad66ce0978214d13baf4e9ac60752f7b15' +
342 | '5e2de4dce3'
343 | }
344 | ]
345 | });
346 | });
347 |
348 | describe('Maxwell\'s trick', function() {
349 | var p256 = elliptic.curves.p256;
350 | assert(p256);
351 | var p384 = elliptic.curves.p384;
352 | assert(p384);
353 |
354 | var msg =
355 | 'e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855';
356 |
357 | var vectors = [
358 | {
359 | curve: p256,
360 | pub: '041548fc88953e06cd34d4b300804c5322cb48c24aaaa4d0' +
361 | '7a541b0f0ccfeedeb0ae4991b90519ea405588bdf699f5e6' +
362 | 'd0c6b2d5217a5c16e8371062737aa1dae1',
363 | message: msg,
364 | sig: '3006020106020104',
365 | result: true
366 | },
367 | {
368 | curve: p256,
369 | pub: '04ad8f60e4ec1ebdb6a260b559cb55b1e9d2c5ddd43a41a2' +
370 | 'd11b0741ef2567d84e166737664104ebbc337af3d861d352' +
371 | '4cfbc761c12edae974a0759750c8324f9a',
372 | message: msg,
373 | sig: '3006020106020104',
374 | result: true
375 | },
376 | {
377 | curve: p256,
378 | pub: '0445bd879143a64af5746e2e82aa65fd2ea07bba4e355940' +
379 | '95a981b59984dacb219d59697387ac721b1f1eccf4b11f43' +
380 | 'ddc39e8367147abab3084142ed3ea170e4',
381 | message: msg,
382 | sig: '301502104319055358e8617b0c46353d039cdaae020104',
383 | result: true
384 | },
385 | {
386 | curve: p256,
387 | pub: '040feb5df4cc78b35ec9c180cc0de5842f75f088b4845697' +
388 | '8ffa98e716d94883e1e6500b2a1f6c1d9d493428d7ae7d9a' +
389 | '8a560fff30a3d14aa160be0c5e7edcd887',
390 | message: msg,
391 | sig: '301502104319055358e8617b0c46353d039cdaae020104',
392 | result: false
393 | },
394 | {
395 | curve: p384,
396 | pub: '0425e299eea9927b39fa92417705391bf17e8110b4615e9e' +
397 | 'b5da471b57be0c30e7d89dbdc3e5da4eae029b300344d385' +
398 | '1548b59ed8be668813905105e673319d59d32f574e180568' +
399 | '463c6186864888f6c0b67b304441f82aab031279e48f047c31',
400 | message: msg,
401 | sig: '3006020103020104',
402 | result: true
403 | },
404 | {
405 | curve: p384,
406 | pub: '04a328f65c22307188b4af65779c1d2ec821c6748c6bd8dc' +
407 | '0e6a008135f048f832df501f7f3f79966b03d5bef2f187ec' +
408 | '34d85f6a934af465656fb4eea8dd9176ab80fbb4a27a649f' +
409 | '526a7dfe616091b78d293552bc093dfde9b31cae69d51d3afb',
410 | message: msg,
411 | sig: '3006020103020104',
412 | result: true
413 | },
414 | {
415 | curve: p384,
416 | pub: '04242e8585eaa7a28cc6062cab4c9c5fd536f46b17be1728' +
417 | '288a2cda5951df4941aed1d712defda023d10aca1c5ee014' +
418 | '43e8beacd821f7efa27847418ab95ce2c514b2b6b395ee73' +
419 | '417c83dbcad631421f360d84d64658c98a62d685b220f5aad4',
420 | message: msg,
421 | sig: '301d0218389cb27e0bc8d21fa7e5f24cb74f58851313e696333ad68e020104',
422 | result: true
423 | },
424 | {
425 | curve: p384,
426 | pub: '04cdf865dd743fe1c23757ec5e65fd5e4038b472ded2af26' +
427 | '1e3d8343c595c8b69147df46379c7ca40e60e80170d34a11' +
428 | '88dbb2b6f7d3934c23d2f78cfb0db3f3219959fad63c9b61' +
429 | '2ef2f20d679777b84192ce86e781c14b1bbb77eacd6e0520e2',
430 | message: msg,
431 | sig: '301d0218389cb27e0bc8d21fa7e5f24cb74f58851313e696333ad68e020104',
432 | result: false
433 | }
434 | ];
435 |
436 | vectors.forEach(function(vector, i) {
437 | it('should pass on vector#' + i, function() {
438 | var ecdsa = new elliptic.ec(vector.curve);
439 | var key = ecdsa.keyFromPublic(vector.pub, 'hex');
440 | var msg = vector.message;
441 | var sig = vector.sig;
442 |
443 | var actual = ecdsa.verify(msg, sig, key);
444 | assert.equal(actual, vector.result);
445 | });
446 | });
447 | });
448 |
449 | it('should deterministically generate private key', function() {
450 | var curve = elliptic.curves.secp256k1;
451 | assert(curve);
452 |
453 | var ecdsa = new elliptic.ec(curve);
454 | var keys = ecdsa.genKeyPair({
455 | pers: 'my.pers.string',
456 | entropy: hash.sha256().update('hello world').digest()
457 | });
458 | assert.equal(
459 | keys.getPrivate('hex'),
460 | '6160edb2b218b7f1394b9ca8eb65a72831032a1f2f3dc2d99291c2f7950ed887');
461 | });
462 |
463 | it('should recover the public key from a signature', function() {
464 | var ec = new elliptic.ec('secp256k1');
465 | var key = ec.genKeyPair();
466 | var msg = [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ];
467 | var signature = key.sign(msg);
468 | var recid = ec.getKeyRecoveryParam(msg, signature, key.getPublic());
469 | var r = ec.recoverPubKey(msg, signature, recid);
470 | assert(key.getPublic().eq(r), 'the keys should match');
471 | });
472 |
473 | it('should fail to recover key when no quadratic residue available',
474 | function() {
475 | var ec = new elliptic.ec('secp256k1');
476 |
477 | var message =
478 | 'f75c6b18a72fabc0f0b888c3da58e004f0af1fe14f7ca5d8c897fe164925d5e9';
479 |
480 | assert.throws(function() {
481 | ecdsa.recoverPubKey(message, {
482 | r: 'fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364140',
483 | s: '8887321be575c8095f789dd4c743dfe42c1820f9231f98a962b210e3ac2452a3'
484 | }, 0);
485 | });
486 | });
487 |
488 | describe('Signature', function () {
489 | it('recoveryParam is 0', function () {
490 | var sig = new Signature({ r: '00', s: '00', recoveryParam: 0 });
491 | assert.equal(sig.recoveryParam, 0);
492 | });
493 |
494 | it('recoveryParam is 1', function () {
495 | var sig = new Signature({ r: '00', s: '00', recoveryParam: 1 });
496 | assert.equal(sig.recoveryParam, 1);
497 | });
498 | });
499 | });
500 |
--------------------------------------------------------------------------------
/lib/elliptic/curve/short.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var curve = require('../curve');
4 | var elliptic = require('../../elliptic');
5 | var BN = require('bn.js');
6 | var inherits = require('inherits');
7 | var Base = curve.base;
8 |
9 | var assert = elliptic.utils.assert;
10 |
11 | function ShortCurve(conf) {
12 | Base.call(this, 'short', conf);
13 |
14 | this.a = new BN(conf.a, 16).toRed(this.red);
15 | this.b = new BN(conf.b, 16).toRed(this.red);
16 | this.tinv = this.two.redInvm();
17 |
18 | this.zeroA = this.a.fromRed().cmpn(0) === 0;
19 | this.threeA = this.a.fromRed().sub(this.p).cmpn(-3) === 0;
20 |
21 | // If the curve is endomorphic, precalculate beta and lambda
22 | this.endo = this._getEndomorphism(conf);
23 | this._endoWnafT1 = new Array(4);
24 | this._endoWnafT2 = new Array(4);
25 | }
26 | inherits(ShortCurve, Base);
27 | module.exports = ShortCurve;
28 |
29 | ShortCurve.prototype._getEndomorphism = function _getEndomorphism(conf) {
30 | // No efficient endomorphism
31 | if (!this.zeroA || !this.g || !this.n || this.p.modn(3) !== 1)
32 | return;
33 |
34 | // Compute beta and lambda, that lambda * P = (beta * Px; Py)
35 | var beta;
36 | var lambda;
37 | if (conf.beta) {
38 | beta = new BN(conf.beta, 16).toRed(this.red);
39 | } else {
40 | var betas = this._getEndoRoots(this.p);
41 | // Choose the smallest beta
42 | beta = betas[0].cmp(betas[1]) < 0 ? betas[0] : betas[1];
43 | beta = beta.toRed(this.red);
44 | }
45 | if (conf.lambda) {
46 | lambda = new BN(conf.lambda, 16);
47 | } else {
48 | // Choose the lambda that is matching selected beta
49 | var lambdas = this._getEndoRoots(this.n);
50 | if (this.g.mul(lambdas[0]).x.cmp(this.g.x.redMul(beta)) === 0) {
51 | lambda = lambdas[0];
52 | } else {
53 | lambda = lambdas[1];
54 | assert(this.g.mul(lambda).x.cmp(this.g.x.redMul(beta)) === 0);
55 | }
56 | }
57 |
58 | // Get basis vectors, used for balanced length-two representation
59 | var basis;
60 | if (conf.basis) {
61 | basis = conf.basis.map(function(vec) {
62 | return {
63 | a: new BN(vec.a, 16),
64 | b: new BN(vec.b, 16)
65 | };
66 | });
67 | } else {
68 | basis = this._getEndoBasis(lambda);
69 | }
70 |
71 | return {
72 | beta: beta,
73 | lambda: lambda,
74 | basis: basis
75 | };
76 | };
77 |
78 | ShortCurve.prototype._getEndoRoots = function _getEndoRoots(num) {
79 | // Find roots of for x^2 + x + 1 in F
80 | // Root = (-1 +- Sqrt(-3)) / 2
81 | //
82 | var red = num === this.p ? this.red : BN.mont(num);
83 | var tinv = new BN(2).toRed(red).redInvm();
84 | var ntinv = tinv.redNeg();
85 |
86 | var s = new BN(3).toRed(red).redNeg().redSqrt().redMul(tinv);
87 |
88 | var l1 = ntinv.redAdd(s).fromRed();
89 | var l2 = ntinv.redSub(s).fromRed();
90 | return [ l1, l2 ];
91 | };
92 |
93 | ShortCurve.prototype._getEndoBasis = function _getEndoBasis(lambda) {
94 | // aprxSqrt >= sqrt(this.n)
95 | var aprxSqrt = this.n.ushrn(Math.floor(this.n.bitLength() / 2));
96 |
97 | // 3.74
98 | // Run EGCD, until r(L + 1) < aprxSqrt
99 | var u = lambda;
100 | var v = this.n.clone();
101 | var x1 = new BN(1);
102 | var y1 = new BN(0);
103 | var x2 = new BN(0);
104 | var y2 = new BN(1);
105 |
106 | // NOTE: all vectors are roots of: a + b * lambda = 0 (mod n)
107 | var a0;
108 | var b0;
109 | // First vector
110 | var a1;
111 | var b1;
112 | // Second vector
113 | var a2;
114 | var b2;
115 |
116 | var prevR;
117 | var i = 0;
118 | var r;
119 | var x;
120 | while (u.cmpn(0) !== 0) {
121 | var q = v.div(u);
122 | r = v.sub(q.mul(u));
123 | x = x2.sub(q.mul(x1));
124 | var y = y2.sub(q.mul(y1));
125 |
126 | if (!a1 && r.cmp(aprxSqrt) < 0) {
127 | a0 = prevR.neg();
128 | b0 = x1;
129 | a1 = r.neg();
130 | b1 = x;
131 | } else if (a1 && ++i === 2) {
132 | break;
133 | }
134 | prevR = r;
135 |
136 | v = u;
137 | u = r;
138 | x2 = x1;
139 | x1 = x;
140 | y2 = y1;
141 | y1 = y;
142 | }
143 | a2 = r.neg();
144 | b2 = x;
145 |
146 | var len1 = a1.sqr().add(b1.sqr());
147 | var len2 = a2.sqr().add(b2.sqr());
148 | if (len2.cmp(len1) >= 0) {
149 | a2 = a0;
150 | b2 = b0;
151 | }
152 |
153 | // Normalize signs
154 | if (a1.negative) {
155 | a1 = a1.neg();
156 | b1 = b1.neg();
157 | }
158 | if (a2.negative) {
159 | a2 = a2.neg();
160 | b2 = b2.neg();
161 | }
162 |
163 | return [
164 | { a: a1, b: b1 },
165 | { a: a2, b: b2 }
166 | ];
167 | };
168 |
169 | ShortCurve.prototype._endoSplit = function _endoSplit(k) {
170 | var basis = this.endo.basis;
171 | var v1 = basis[0];
172 | var v2 = basis[1];
173 |
174 | var c1 = v2.b.mul(k).divRound(this.n);
175 | var c2 = v1.b.neg().mul(k).divRound(this.n);
176 |
177 | var p1 = c1.mul(v1.a);
178 | var p2 = c2.mul(v2.a);
179 | var q1 = c1.mul(v1.b);
180 | var q2 = c2.mul(v2.b);
181 |
182 | // Calculate answer
183 | var k1 = k.sub(p1).sub(p2);
184 | var k2 = q1.add(q2).neg();
185 | return { k1: k1, k2: k2 };
186 | };
187 |
188 | ShortCurve.prototype.pointFromX = function pointFromX(x, odd) {
189 | x = new BN(x, 16);
190 | if (!x.red)
191 | x = x.toRed(this.red);
192 |
193 | var y2 = x.redSqr().redMul(x).redIAdd(x.redMul(this.a)).redIAdd(this.b);
194 | var y = y2.redSqrt();
195 | if (y.redSqr().redSub(y2).cmp(this.zero) !== 0)
196 | throw new Error('invalid point');
197 |
198 | // XXX Is there any way to tell if the number is odd without converting it
199 | // to non-red form?
200 | var isOdd = y.fromRed().isOdd();
201 | if (odd && !isOdd || !odd && isOdd)
202 | y = y.redNeg();
203 |
204 | return this.point(x, y);
205 | };
206 |
207 | ShortCurve.prototype.validate = function validate(point) {
208 | if (point.inf)
209 | return true;
210 |
211 | var x = point.x;
212 | var y = point.y;
213 |
214 | var ax = this.a.redMul(x);
215 | var rhs = x.redSqr().redMul(x).redIAdd(ax).redIAdd(this.b);
216 | return y.redSqr().redISub(rhs).cmpn(0) === 0;
217 | };
218 |
219 | ShortCurve.prototype._endoWnafMulAdd =
220 | function _endoWnafMulAdd(points, coeffs, jacobianResult) {
221 | var npoints = this._endoWnafT1;
222 | var ncoeffs = this._endoWnafT2;
223 | for (var i = 0; i < points.length; i++) {
224 | var split = this._endoSplit(coeffs[i]);
225 | var p = points[i];
226 | var beta = p._getBeta();
227 |
228 | if (split.k1.negative) {
229 | split.k1.ineg();
230 | p = p.neg(true);
231 | }
232 | if (split.k2.negative) {
233 | split.k2.ineg();
234 | beta = beta.neg(true);
235 | }
236 |
237 | npoints[i * 2] = p;
238 | npoints[i * 2 + 1] = beta;
239 | ncoeffs[i * 2] = split.k1;
240 | ncoeffs[i * 2 + 1] = split.k2;
241 | }
242 | var res = this._wnafMulAdd(1, npoints, ncoeffs, i * 2, jacobianResult);
243 |
244 | // Clean-up references to points and coefficients
245 | for (var j = 0; j < i * 2; j++) {
246 | npoints[j] = null;
247 | ncoeffs[j] = null;
248 | }
249 | return res;
250 | };
251 |
252 | function Point(curve, x, y, isRed) {
253 | Base.BasePoint.call(this, curve, 'affine');
254 | if (x === null && y === null) {
255 | this.x = null;
256 | this.y = null;
257 | this.inf = true;
258 | } else {
259 | this.x = new BN(x, 16);
260 | this.y = new BN(y, 16);
261 | // Force redgomery representation when loading from JSON
262 | if (isRed) {
263 | this.x.forceRed(this.curve.red);
264 | this.y.forceRed(this.curve.red);
265 | }
266 | if (!this.x.red)
267 | this.x = this.x.toRed(this.curve.red);
268 | if (!this.y.red)
269 | this.y = this.y.toRed(this.curve.red);
270 | this.inf = false;
271 | }
272 | }
273 | inherits(Point, Base.BasePoint);
274 |
275 | ShortCurve.prototype.point = function point(x, y, isRed) {
276 | return new Point(this, x, y, isRed);
277 | };
278 |
279 | ShortCurve.prototype.pointFromJSON = function pointFromJSON(obj, red) {
280 | return Point.fromJSON(this, obj, red);
281 | };
282 |
283 | Point.prototype._getBeta = function _getBeta() {
284 | if (!this.curve.endo)
285 | return;
286 |
287 | var pre = this.precomputed;
288 | if (pre && pre.beta)
289 | return pre.beta;
290 |
291 | var beta = this.curve.point(this.x.redMul(this.curve.endo.beta), this.y);
292 | if (pre) {
293 | var curve = this.curve;
294 | var endoMul = function(p) {
295 | return curve.point(p.x.redMul(curve.endo.beta), p.y);
296 | };
297 | pre.beta = beta;
298 | beta.precomputed = {
299 | beta: null,
300 | naf: pre.naf && {
301 | wnd: pre.naf.wnd,
302 | points: pre.naf.points.map(endoMul)
303 | },
304 | doubles: pre.doubles && {
305 | step: pre.doubles.step,
306 | points: pre.doubles.points.map(endoMul)
307 | }
308 | };
309 | }
310 | return beta;
311 | };
312 |
313 | Point.prototype.toJSON = function toJSON() {
314 | if (!this.precomputed)
315 | return [ this.x, this.y ];
316 |
317 | return [ this.x, this.y, this.precomputed && {
318 | doubles: this.precomputed.doubles && {
319 | step: this.precomputed.doubles.step,
320 | points: this.precomputed.doubles.points.slice(1)
321 | },
322 | naf: this.precomputed.naf && {
323 | wnd: this.precomputed.naf.wnd,
324 | points: this.precomputed.naf.points.slice(1)
325 | }
326 | } ];
327 | };
328 |
329 | Point.fromJSON = function fromJSON(curve, obj, red) {
330 | if (typeof obj === 'string')
331 | obj = JSON.parse(obj);
332 | var res = curve.point(obj[0], obj[1], red);
333 | if (!obj[2])
334 | return res;
335 |
336 | function obj2point(obj) {
337 | return curve.point(obj[0], obj[1], red);
338 | }
339 |
340 | var pre = obj[2];
341 | res.precomputed = {
342 | beta: null,
343 | doubles: pre.doubles && {
344 | step: pre.doubles.step,
345 | points: [ res ].concat(pre.doubles.points.map(obj2point))
346 | },
347 | naf: pre.naf && {
348 | wnd: pre.naf.wnd,
349 | points: [ res ].concat(pre.naf.points.map(obj2point))
350 | }
351 | };
352 | return res;
353 | };
354 |
355 | Point.prototype.inspect = function inspect() {
356 | if (this.isInfinity())
357 | return '';
358 | return '';
360 | };
361 |
362 | Point.prototype.isInfinity = function isInfinity() {
363 | return this.inf;
364 | };
365 |
366 | Point.prototype.add = function add(p) {
367 | // O + P = P
368 | if (this.inf)
369 | return p;
370 |
371 | // P + O = P
372 | if (p.inf)
373 | return this;
374 |
375 | // P + P = 2P
376 | if (this.eq(p))
377 | return this.dbl();
378 |
379 | // P + (-P) = O
380 | if (this.neg().eq(p))
381 | return this.curve.point(null, null);
382 |
383 | // P + Q = O
384 | if (this.x.cmp(p.x) === 0)
385 | return this.curve.point(null, null);
386 |
387 | var c = this.y.redSub(p.y);
388 | if (c.cmpn(0) !== 0)
389 | c = c.redMul(this.x.redSub(p.x).redInvm());
390 | var nx = c.redSqr().redISub(this.x).redISub(p.x);
391 | var ny = c.redMul(this.x.redSub(nx)).redISub(this.y);
392 | return this.curve.point(nx, ny);
393 | };
394 |
395 | Point.prototype.dbl = function dbl() {
396 | if (this.inf)
397 | return this;
398 |
399 | // 2P = O
400 | var ys1 = this.y.redAdd(this.y);
401 | if (ys1.cmpn(0) === 0)
402 | return this.curve.point(null, null);
403 |
404 | var a = this.curve.a;
405 |
406 | var x2 = this.x.redSqr();
407 | var dyinv = ys1.redInvm();
408 | var c = x2.redAdd(x2).redIAdd(x2).redIAdd(a).redMul(dyinv);
409 |
410 | var nx = c.redSqr().redISub(this.x.redAdd(this.x));
411 | var ny = c.redMul(this.x.redSub(nx)).redISub(this.y);
412 | return this.curve.point(nx, ny);
413 | };
414 |
415 | Point.prototype.getX = function getX() {
416 | return this.x.fromRed();
417 | };
418 |
419 | Point.prototype.getY = function getY() {
420 | return this.y.fromRed();
421 | };
422 |
423 | Point.prototype.mul = function mul(k) {
424 | k = new BN(k, 16);
425 |
426 | if (this._hasDoubles(k))
427 | return this.curve._fixedNafMul(this, k);
428 | else if (this.curve.endo)
429 | return this.curve._endoWnafMulAdd([ this ], [ k ]);
430 | else
431 | return this.curve._wnafMul(this, k);
432 | };
433 |
434 | Point.prototype.mulAdd = function mulAdd(k1, p2, k2) {
435 | var points = [ this, p2 ];
436 | var coeffs = [ k1, k2 ];
437 | if (this.curve.endo)
438 | return this.curve._endoWnafMulAdd(points, coeffs);
439 | else
440 | return this.curve._wnafMulAdd(1, points, coeffs, 2);
441 | };
442 |
443 | Point.prototype.jmulAdd = function jmulAdd(k1, p2, k2) {
444 | var points = [ this, p2 ];
445 | var coeffs = [ k1, k2 ];
446 | if (this.curve.endo)
447 | return this.curve._endoWnafMulAdd(points, coeffs, true);
448 | else
449 | return this.curve._wnafMulAdd(1, points, coeffs, 2, true);
450 | };
451 |
452 | Point.prototype.eq = function eq(p) {
453 | return this === p ||
454 | this.inf === p.inf &&
455 | (this.inf || this.x.cmp(p.x) === 0 && this.y.cmp(p.y) === 0);
456 | };
457 |
458 | Point.prototype.neg = function neg(_precompute) {
459 | if (this.inf)
460 | return this;
461 |
462 | var res = this.curve.point(this.x, this.y.redNeg());
463 | if (_precompute && this.precomputed) {
464 | var pre = this.precomputed;
465 | var negate = function(p) {
466 | return p.neg();
467 | };
468 | res.precomputed = {
469 | naf: pre.naf && {
470 | wnd: pre.naf.wnd,
471 | points: pre.naf.points.map(negate)
472 | },
473 | doubles: pre.doubles && {
474 | step: pre.doubles.step,
475 | points: pre.doubles.points.map(negate)
476 | }
477 | };
478 | }
479 | return res;
480 | };
481 |
482 | Point.prototype.toJ = function toJ() {
483 | if (this.inf)
484 | return this.curve.jpoint(null, null, null);
485 |
486 | var res = this.curve.jpoint(this.x, this.y, this.curve.one);
487 | return res;
488 | };
489 |
490 | function JPoint(curve, x, y, z) {
491 | Base.BasePoint.call(this, curve, 'jacobian');
492 | if (x === null && y === null && z === null) {
493 | this.x = this.curve.one;
494 | this.y = this.curve.one;
495 | this.z = new BN(0);
496 | } else {
497 | this.x = new BN(x, 16);
498 | this.y = new BN(y, 16);
499 | this.z = new BN(z, 16);
500 | }
501 | if (!this.x.red)
502 | this.x = this.x.toRed(this.curve.red);
503 | if (!this.y.red)
504 | this.y = this.y.toRed(this.curve.red);
505 | if (!this.z.red)
506 | this.z = this.z.toRed(this.curve.red);
507 |
508 | this.zOne = this.z === this.curve.one;
509 | }
510 | inherits(JPoint, Base.BasePoint);
511 |
512 | ShortCurve.prototype.jpoint = function jpoint(x, y, z) {
513 | return new JPoint(this, x, y, z);
514 | };
515 |
516 | JPoint.prototype.toP = function toP() {
517 | if (this.isInfinity())
518 | return this.curve.point(null, null);
519 |
520 | var zinv = this.z.redInvm();
521 | var zinv2 = zinv.redSqr();
522 | var ax = this.x.redMul(zinv2);
523 | var ay = this.y.redMul(zinv2).redMul(zinv);
524 |
525 | return this.curve.point(ax, ay);
526 | };
527 |
528 | JPoint.prototype.neg = function neg() {
529 | return this.curve.jpoint(this.x, this.y.redNeg(), this.z);
530 | };
531 |
532 | JPoint.prototype.add = function add(p) {
533 | // O + P = P
534 | if (this.isInfinity())
535 | return p;
536 |
537 | // P + O = P
538 | if (p.isInfinity())
539 | return this;
540 |
541 | // 12M + 4S + 7A
542 | var pz2 = p.z.redSqr();
543 | var z2 = this.z.redSqr();
544 | var u1 = this.x.redMul(pz2);
545 | var u2 = p.x.redMul(z2);
546 | var s1 = this.y.redMul(pz2.redMul(p.z));
547 | var s2 = p.y.redMul(z2.redMul(this.z));
548 |
549 | var h = u1.redSub(u2);
550 | var r = s1.redSub(s2);
551 | if (h.cmpn(0) === 0) {
552 | if (r.cmpn(0) !== 0)
553 | return this.curve.jpoint(null, null, null);
554 | else
555 | return this.dbl();
556 | }
557 |
558 | var h2 = h.redSqr();
559 | var h3 = h2.redMul(h);
560 | var v = u1.redMul(h2);
561 |
562 | var nx = r.redSqr().redIAdd(h3).redISub(v).redISub(v);
563 | var ny = r.redMul(v.redISub(nx)).redISub(s1.redMul(h3));
564 | var nz = this.z.redMul(p.z).redMul(h);
565 |
566 | return this.curve.jpoint(nx, ny, nz);
567 | };
568 |
569 | JPoint.prototype.mixedAdd = function mixedAdd(p) {
570 | // O + P = P
571 | if (this.isInfinity())
572 | return p.toJ();
573 |
574 | // P + O = P
575 | if (p.isInfinity())
576 | return this;
577 |
578 | // 8M + 3S + 7A
579 | var z2 = this.z.redSqr();
580 | var u1 = this.x;
581 | var u2 = p.x.redMul(z2);
582 | var s1 = this.y;
583 | var s2 = p.y.redMul(z2).redMul(this.z);
584 |
585 | var h = u1.redSub(u2);
586 | var r = s1.redSub(s2);
587 | if (h.cmpn(0) === 0) {
588 | if (r.cmpn(0) !== 0)
589 | return this.curve.jpoint(null, null, null);
590 | else
591 | return this.dbl();
592 | }
593 |
594 | var h2 = h.redSqr();
595 | var h3 = h2.redMul(h);
596 | var v = u1.redMul(h2);
597 |
598 | var nx = r.redSqr().redIAdd(h3).redISub(v).redISub(v);
599 | var ny = r.redMul(v.redISub(nx)).redISub(s1.redMul(h3));
600 | var nz = this.z.redMul(h);
601 |
602 | return this.curve.jpoint(nx, ny, nz);
603 | };
604 |
605 | JPoint.prototype.dblp = function dblp(pow) {
606 | if (pow === 0)
607 | return this;
608 | if (this.isInfinity())
609 | return this;
610 | if (!pow)
611 | return this.dbl();
612 |
613 | if (this.curve.zeroA || this.curve.threeA) {
614 | var r = this;
615 | for (var i = 0; i < pow; i++)
616 | r = r.dbl();
617 | return r;
618 | }
619 |
620 | // 1M + 2S + 1A + N * (4S + 5M + 8A)
621 | // N = 1 => 6M + 6S + 9A
622 | var a = this.curve.a;
623 | var tinv = this.curve.tinv;
624 |
625 | var jx = this.x;
626 | var jy = this.y;
627 | var jz = this.z;
628 | var jz4 = jz.redSqr().redSqr();
629 |
630 | // Reuse results
631 | var jyd = jy.redAdd(jy);
632 | for (var i = 0; i < pow; i++) {
633 | var jx2 = jx.redSqr();
634 | var jyd2 = jyd.redSqr();
635 | var jyd4 = jyd2.redSqr();
636 | var c = jx2.redAdd(jx2).redIAdd(jx2).redIAdd(a.redMul(jz4));
637 |
638 | var t1 = jx.redMul(jyd2);
639 | var nx = c.redSqr().redISub(t1.redAdd(t1));
640 | var t2 = t1.redISub(nx);
641 | var dny = c.redMul(t2);
642 | dny = dny.redIAdd(dny).redISub(jyd4);
643 | var nz = jyd.redMul(jz);
644 | if (i + 1 < pow)
645 | jz4 = jz4.redMul(jyd4);
646 |
647 | jx = nx;
648 | jz = nz;
649 | jyd = dny;
650 | }
651 |
652 | return this.curve.jpoint(jx, jyd.redMul(tinv), jz);
653 | };
654 |
655 | JPoint.prototype.dbl = function dbl() {
656 | if (this.isInfinity())
657 | return this;
658 |
659 | if (this.curve.zeroA)
660 | return this._zeroDbl();
661 | else if (this.curve.threeA)
662 | return this._threeDbl();
663 | else
664 | return this._dbl();
665 | };
666 |
667 | JPoint.prototype._zeroDbl = function _zeroDbl() {
668 | var nx;
669 | var ny;
670 | var nz;
671 | // Z = 1
672 | if (this.zOne) {
673 | // hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html
674 | // #doubling-mdbl-2007-bl
675 | // 1M + 5S + 14A
676 |
677 | // XX = X1^2
678 | var xx = this.x.redSqr();
679 | // YY = Y1^2
680 | var yy = this.y.redSqr();
681 | // YYYY = YY^2
682 | var yyyy = yy.redSqr();
683 | // S = 2 * ((X1 + YY)^2 - XX - YYYY)
684 | var s = this.x.redAdd(yy).redSqr().redISub(xx).redISub(yyyy);
685 | s = s.redIAdd(s);
686 | // M = 3 * XX + a; a = 0
687 | var m = xx.redAdd(xx).redIAdd(xx);
688 | // T = M ^ 2 - 2*S
689 | var t = m.redSqr().redISub(s).redISub(s);
690 |
691 | // 8 * YYYY
692 | var yyyy8 = yyyy.redIAdd(yyyy);
693 | yyyy8 = yyyy8.redIAdd(yyyy8);
694 | yyyy8 = yyyy8.redIAdd(yyyy8);
695 |
696 | // X3 = T
697 | nx = t;
698 | // Y3 = M * (S - T) - 8 * YYYY
699 | ny = m.redMul(s.redISub(t)).redISub(yyyy8);
700 | // Z3 = 2*Y1
701 | nz = this.y.redAdd(this.y);
702 | } else {
703 | // hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html
704 | // #doubling-dbl-2009-l
705 | // 2M + 5S + 13A
706 |
707 | // A = X1^2
708 | var a = this.x.redSqr();
709 | // B = Y1^2
710 | var b = this.y.redSqr();
711 | // C = B^2
712 | var c = b.redSqr();
713 | // D = 2 * ((X1 + B)^2 - A - C)
714 | var d = this.x.redAdd(b).redSqr().redISub(a).redISub(c);
715 | d = d.redIAdd(d);
716 | // E = 3 * A
717 | var e = a.redAdd(a).redIAdd(a);
718 | // F = E^2
719 | var f = e.redSqr();
720 |
721 | // 8 * C
722 | var c8 = c.redIAdd(c);
723 | c8 = c8.redIAdd(c8);
724 | c8 = c8.redIAdd(c8);
725 |
726 | // X3 = F - 2 * D
727 | nx = f.redISub(d).redISub(d);
728 | // Y3 = E * (D - X3) - 8 * C
729 | ny = e.redMul(d.redISub(nx)).redISub(c8);
730 | // Z3 = 2 * Y1 * Z1
731 | nz = this.y.redMul(this.z);
732 | nz = nz.redIAdd(nz);
733 | }
734 |
735 | return this.curve.jpoint(nx, ny, nz);
736 | };
737 |
738 | JPoint.prototype._threeDbl = function _threeDbl() {
739 | var nx;
740 | var ny;
741 | var nz;
742 | // Z = 1
743 | if (this.zOne) {
744 | // hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-3.html
745 | // #doubling-mdbl-2007-bl
746 | // 1M + 5S + 15A
747 |
748 | // XX = X1^2
749 | var xx = this.x.redSqr();
750 | // YY = Y1^2
751 | var yy = this.y.redSqr();
752 | // YYYY = YY^2
753 | var yyyy = yy.redSqr();
754 | // S = 2 * ((X1 + YY)^2 - XX - YYYY)
755 | var s = this.x.redAdd(yy).redSqr().redISub(xx).redISub(yyyy);
756 | s = s.redIAdd(s);
757 | // M = 3 * XX + a
758 | var m = xx.redAdd(xx).redIAdd(xx).redIAdd(this.curve.a);
759 | // T = M^2 - 2 * S
760 | var t = m.redSqr().redISub(s).redISub(s);
761 | // X3 = T
762 | nx = t;
763 | // Y3 = M * (S - T) - 8 * YYYY
764 | var yyyy8 = yyyy.redIAdd(yyyy);
765 | yyyy8 = yyyy8.redIAdd(yyyy8);
766 | yyyy8 = yyyy8.redIAdd(yyyy8);
767 | ny = m.redMul(s.redISub(t)).redISub(yyyy8);
768 | // Z3 = 2 * Y1
769 | nz = this.y.redAdd(this.y);
770 | } else {
771 | // hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-3.html#doubling-dbl-2001-b
772 | // 3M + 5S
773 |
774 | // delta = Z1^2
775 | var delta = this.z.redSqr();
776 | // gamma = Y1^2
777 | var gamma = this.y.redSqr();
778 | // beta = X1 * gamma
779 | var beta = this.x.redMul(gamma);
780 | // alpha = 3 * (X1 - delta) * (X1 + delta)
781 | var alpha = this.x.redSub(delta).redMul(this.x.redAdd(delta));
782 | alpha = alpha.redAdd(alpha).redIAdd(alpha);
783 | // X3 = alpha^2 - 8 * beta
784 | var beta4 = beta.redIAdd(beta);
785 | beta4 = beta4.redIAdd(beta4);
786 | var beta8 = beta4.redAdd(beta4);
787 | nx = alpha.redSqr().redISub(beta8);
788 | // Z3 = (Y1 + Z1)^2 - gamma - delta
789 | nz = this.y.redAdd(this.z).redSqr().redISub(gamma).redISub(delta);
790 | // Y3 = alpha * (4 * beta - X3) - 8 * gamma^2
791 | var ggamma8 = gamma.redSqr();
792 | ggamma8 = ggamma8.redIAdd(ggamma8);
793 | ggamma8 = ggamma8.redIAdd(ggamma8);
794 | ggamma8 = ggamma8.redIAdd(ggamma8);
795 | ny = alpha.redMul(beta4.redISub(nx)).redISub(ggamma8);
796 | }
797 |
798 | return this.curve.jpoint(nx, ny, nz);
799 | };
800 |
801 | JPoint.prototype._dbl = function _dbl() {
802 | var a = this.curve.a;
803 |
804 | // 4M + 6S + 10A
805 | var jx = this.x;
806 | var jy = this.y;
807 | var jz = this.z;
808 | var jz4 = jz.redSqr().redSqr();
809 |
810 | var jx2 = jx.redSqr();
811 | var jy2 = jy.redSqr();
812 |
813 | var c = jx2.redAdd(jx2).redIAdd(jx2).redIAdd(a.redMul(jz4));
814 |
815 | var jxd4 = jx.redAdd(jx);
816 | jxd4 = jxd4.redIAdd(jxd4);
817 | var t1 = jxd4.redMul(jy2);
818 | var nx = c.redSqr().redISub(t1.redAdd(t1));
819 | var t2 = t1.redISub(nx);
820 |
821 | var jyd8 = jy2.redSqr();
822 | jyd8 = jyd8.redIAdd(jyd8);
823 | jyd8 = jyd8.redIAdd(jyd8);
824 | jyd8 = jyd8.redIAdd(jyd8);
825 | var ny = c.redMul(t2).redISub(jyd8);
826 | var nz = jy.redAdd(jy).redMul(jz);
827 |
828 | return this.curve.jpoint(nx, ny, nz);
829 | };
830 |
831 | JPoint.prototype.trpl = function trpl() {
832 | if (!this.curve.zeroA)
833 | return this.dbl().add(this);
834 |
835 | // hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html#tripling-tpl-2007-bl
836 | // 5M + 10S + ...
837 |
838 | // XX = X1^2
839 | var xx = this.x.redSqr();
840 | // YY = Y1^2
841 | var yy = this.y.redSqr();
842 | // ZZ = Z1^2
843 | var zz = this.z.redSqr();
844 | // YYYY = YY^2
845 | var yyyy = yy.redSqr();
846 | // M = 3 * XX + a * ZZ2; a = 0
847 | var m = xx.redAdd(xx).redIAdd(xx);
848 | // MM = M^2
849 | var mm = m.redSqr();
850 | // E = 6 * ((X1 + YY)^2 - XX - YYYY) - MM
851 | var e = this.x.redAdd(yy).redSqr().redISub(xx).redISub(yyyy);
852 | e = e.redIAdd(e);
853 | e = e.redAdd(e).redIAdd(e);
854 | e = e.redISub(mm);
855 | // EE = E^2
856 | var ee = e.redSqr();
857 | // T = 16*YYYY
858 | var t = yyyy.redIAdd(yyyy);
859 | t = t.redIAdd(t);
860 | t = t.redIAdd(t);
861 | t = t.redIAdd(t);
862 | // U = (M + E)^2 - MM - EE - T
863 | var u = m.redIAdd(e).redSqr().redISub(mm).redISub(ee).redISub(t);
864 | // X3 = 4 * (X1 * EE - 4 * YY * U)
865 | var yyu4 = yy.redMul(u);
866 | yyu4 = yyu4.redIAdd(yyu4);
867 | yyu4 = yyu4.redIAdd(yyu4);
868 | var nx = this.x.redMul(ee).redISub(yyu4);
869 | nx = nx.redIAdd(nx);
870 | nx = nx.redIAdd(nx);
871 | // Y3 = 8 * Y1 * (U * (T - U) - E * EE)
872 | var ny = this.y.redMul(u.redMul(t.redISub(u)).redISub(e.redMul(ee)));
873 | ny = ny.redIAdd(ny);
874 | ny = ny.redIAdd(ny);
875 | ny = ny.redIAdd(ny);
876 | // Z3 = (Z1 + E)^2 - ZZ - EE
877 | var nz = this.z.redAdd(e).redSqr().redISub(zz).redISub(ee);
878 |
879 | return this.curve.jpoint(nx, ny, nz);
880 | };
881 |
882 | JPoint.prototype.mul = function mul(k, kbase) {
883 | k = new BN(k, kbase);
884 |
885 | return this.curve._wnafMul(this, k);
886 | };
887 |
888 | JPoint.prototype.eq = function eq(p) {
889 | if (p.type === 'affine')
890 | return this.eq(p.toJ());
891 |
892 | if (this === p)
893 | return true;
894 |
895 | // x1 * z2^2 == x2 * z1^2
896 | var z2 = this.z.redSqr();
897 | var pz2 = p.z.redSqr();
898 | if (this.x.redMul(pz2).redISub(p.x.redMul(z2)).cmpn(0) !== 0)
899 | return false;
900 |
901 | // y1 * z2^3 == y2 * z1^3
902 | var z3 = z2.redMul(this.z);
903 | var pz3 = pz2.redMul(p.z);
904 | return this.y.redMul(pz3).redISub(p.y.redMul(z3)).cmpn(0) === 0;
905 | };
906 |
907 | JPoint.prototype.eqXToP = function eqXToP(x) {
908 | var zs = this.z.redSqr();
909 | var rx = x.toRed(this.curve.red).redMul(zs);
910 | if (this.x.cmp(rx) === 0)
911 | return true;
912 |
913 | var xc = x.clone();
914 | var t = this.curve.redN.redMul(zs);
915 | for (;;) {
916 | xc.iadd(this.curve.n);
917 | if (xc.cmp(this.curve.p) >= 0)
918 | return false;
919 |
920 | rx.redIAdd(t);
921 | if (this.x.cmp(rx) === 0)
922 | return true;
923 | }
924 | };
925 |
926 | JPoint.prototype.inspect = function inspect() {
927 | if (this.isInfinity())
928 | return '';
929 | return '';
932 | };
933 |
934 | JPoint.prototype.isInfinity = function isInfinity() {
935 | // XXX This code assumes that zero is always zero in red
936 | return this.z.cmpn(0) === 0;
937 | };
938 |
--------------------------------------------------------------------------------
/lib/elliptic/precomputed/secp256k1.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | doubles: {
3 | step: 4,
4 | points: [
5 | [
6 | 'e60fce93b59e9ec53011aabc21c23e97b2a31369b87a5ae9c44ee89e2a6dec0a',
7 | 'f7e3507399e595929db99f34f57937101296891e44d23f0be1f32cce69616821'
8 | ],
9 | [
10 | '8282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508',
11 | '11f8a8098557dfe45e8256e830b60ace62d613ac2f7b17bed31b6eaff6e26caf'
12 | ],
13 | [
14 | '175e159f728b865a72f99cc6c6fc846de0b93833fd2222ed73fce5b551e5b739',
15 | 'd3506e0d9e3c79eba4ef97a51ff71f5eacb5955add24345c6efa6ffee9fed695'
16 | ],
17 | [
18 | '363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640',
19 | '4e273adfc732221953b445397f3363145b9a89008199ecb62003c7f3bee9de9'
20 | ],
21 | [
22 | '8b4b5f165df3c2be8c6244b5b745638843e4a781a15bcd1b69f79a55dffdf80c',
23 | '4aad0a6f68d308b4b3fbd7813ab0da04f9e336546162ee56b3eff0c65fd4fd36'
24 | ],
25 | [
26 | '723cbaa6e5db996d6bf771c00bd548c7b700dbffa6c0e77bcb6115925232fcda',
27 | '96e867b5595cc498a921137488824d6e2660a0653779494801dc069d9eb39f5f'
28 | ],
29 | [
30 | 'eebfa4d493bebf98ba5feec812c2d3b50947961237a919839a533eca0e7dd7fa',
31 | '5d9a8ca3970ef0f269ee7edaf178089d9ae4cdc3a711f712ddfd4fdae1de8999'
32 | ],
33 | [
34 | '100f44da696e71672791d0a09b7bde459f1215a29b3c03bfefd7835b39a48db0',
35 | 'cdd9e13192a00b772ec8f3300c090666b7ff4a18ff5195ac0fbd5cd62bc65a09'
36 | ],
37 | [
38 | 'e1031be262c7ed1b1dc9227a4a04c017a77f8d4464f3b3852c8acde6e534fd2d',
39 | '9d7061928940405e6bb6a4176597535af292dd419e1ced79a44f18f29456a00d'
40 | ],
41 | [
42 | 'feea6cae46d55b530ac2839f143bd7ec5cf8b266a41d6af52d5e688d9094696d',
43 | 'e57c6b6c97dce1bab06e4e12bf3ecd5c981c8957cc41442d3155debf18090088'
44 | ],
45 | [
46 | 'da67a91d91049cdcb367be4be6ffca3cfeed657d808583de33fa978bc1ec6cb1',
47 | '9bacaa35481642bc41f463f7ec9780e5dec7adc508f740a17e9ea8e27a68be1d'
48 | ],
49 | [
50 | '53904faa0b334cdda6e000935ef22151ec08d0f7bb11069f57545ccc1a37b7c0',
51 | '5bc087d0bc80106d88c9eccac20d3c1c13999981e14434699dcb096b022771c8'
52 | ],
53 | [
54 | '8e7bcd0bd35983a7719cca7764ca906779b53a043a9b8bcaeff959f43ad86047',
55 | '10b7770b2a3da4b3940310420ca9514579e88e2e47fd68b3ea10047e8460372a'
56 | ],
57 | [
58 | '385eed34c1cdff21e6d0818689b81bde71a7f4f18397e6690a841e1599c43862',
59 | '283bebc3e8ea23f56701de19e9ebf4576b304eec2086dc8cc0458fe5542e5453'
60 | ],
61 | [
62 | '6f9d9b803ecf191637c73a4413dfa180fddf84a5947fbc9c606ed86c3fac3a7',
63 | '7c80c68e603059ba69b8e2a30e45c4d47ea4dd2f5c281002d86890603a842160'
64 | ],
65 | [
66 | '3322d401243c4e2582a2147c104d6ecbf774d163db0f5e5313b7e0e742d0e6bd',
67 | '56e70797e9664ef5bfb019bc4ddaf9b72805f63ea2873af624f3a2e96c28b2a0'
68 | ],
69 | [
70 | '85672c7d2de0b7da2bd1770d89665868741b3f9af7643397721d74d28134ab83',
71 | '7c481b9b5b43b2eb6374049bfa62c2e5e77f17fcc5298f44c8e3094f790313a6'
72 | ],
73 | [
74 | '948bf809b1988a46b06c9f1919413b10f9226c60f668832ffd959af60c82a0a',
75 | '53a562856dcb6646dc6b74c5d1c3418c6d4dff08c97cd2bed4cb7f88d8c8e589'
76 | ],
77 | [
78 | '6260ce7f461801c34f067ce0f02873a8f1b0e44dfc69752accecd819f38fd8e8',
79 | 'bc2da82b6fa5b571a7f09049776a1ef7ecd292238051c198c1a84e95b2b4ae17'
80 | ],
81 | [
82 | 'e5037de0afc1d8d43d8348414bbf4103043ec8f575bfdc432953cc8d2037fa2d',
83 | '4571534baa94d3b5f9f98d09fb990bddbd5f5b03ec481f10e0e5dc841d755bda'
84 | ],
85 | [
86 | 'e06372b0f4a207adf5ea905e8f1771b4e7e8dbd1c6a6c5b725866a0ae4fce725',
87 | '7a908974bce18cfe12a27bb2ad5a488cd7484a7787104870b27034f94eee31dd'
88 | ],
89 | [
90 | '213c7a715cd5d45358d0bbf9dc0ce02204b10bdde2a3f58540ad6908d0559754',
91 | '4b6dad0b5ae462507013ad06245ba190bb4850f5f36a7eeddff2c27534b458f2'
92 | ],
93 | [
94 | '4e7c272a7af4b34e8dbb9352a5419a87e2838c70adc62cddf0cc3a3b08fbd53c',
95 | '17749c766c9d0b18e16fd09f6def681b530b9614bff7dd33e0b3941817dcaae6'
96 | ],
97 | [
98 | 'fea74e3dbe778b1b10f238ad61686aa5c76e3db2be43057632427e2840fb27b6',
99 | '6e0568db9b0b13297cf674deccb6af93126b596b973f7b77701d3db7f23cb96f'
100 | ],
101 | [
102 | '76e64113f677cf0e10a2570d599968d31544e179b760432952c02a4417bdde39',
103 | 'c90ddf8dee4e95cf577066d70681f0d35e2a33d2b56d2032b4b1752d1901ac01'
104 | ],
105 | [
106 | 'c738c56b03b2abe1e8281baa743f8f9a8f7cc643df26cbee3ab150242bcbb891',
107 | '893fb578951ad2537f718f2eacbfbbbb82314eef7880cfe917e735d9699a84c3'
108 | ],
109 | [
110 | 'd895626548b65b81e264c7637c972877d1d72e5f3a925014372e9f6588f6c14b',
111 | 'febfaa38f2bc7eae728ec60818c340eb03428d632bb067e179363ed75d7d991f'
112 | ],
113 | [
114 | 'b8da94032a957518eb0f6433571e8761ceffc73693e84edd49150a564f676e03',
115 | '2804dfa44805a1e4d7c99cc9762808b092cc584d95ff3b511488e4e74efdf6e7'
116 | ],
117 | [
118 | 'e80fea14441fb33a7d8adab9475d7fab2019effb5156a792f1a11778e3c0df5d',
119 | 'eed1de7f638e00771e89768ca3ca94472d155e80af322ea9fcb4291b6ac9ec78'
120 | ],
121 | [
122 | 'a301697bdfcd704313ba48e51d567543f2a182031efd6915ddc07bbcc4e16070',
123 | '7370f91cfb67e4f5081809fa25d40f9b1735dbf7c0a11a130c0d1a041e177ea1'
124 | ],
125 | [
126 | '90ad85b389d6b936463f9d0512678de208cc330b11307fffab7ac63e3fb04ed4',
127 | 'e507a3620a38261affdcbd9427222b839aefabe1582894d991d4d48cb6ef150'
128 | ],
129 | [
130 | '8f68b9d2f63b5f339239c1ad981f162ee88c5678723ea3351b7b444c9ec4c0da',
131 | '662a9f2dba063986de1d90c2b6be215dbbea2cfe95510bfdf23cbf79501fff82'
132 | ],
133 | [
134 | 'e4f3fb0176af85d65ff99ff9198c36091f48e86503681e3e6686fd5053231e11',
135 | '1e63633ad0ef4f1c1661a6d0ea02b7286cc7e74ec951d1c9822c38576feb73bc'
136 | ],
137 | [
138 | '8c00fa9b18ebf331eb961537a45a4266c7034f2f0d4e1d0716fb6eae20eae29e',
139 | 'efa47267fea521a1a9dc343a3736c974c2fadafa81e36c54e7d2a4c66702414b'
140 | ],
141 | [
142 | 'e7a26ce69dd4829f3e10cec0a9e98ed3143d084f308b92c0997fddfc60cb3e41',
143 | '2a758e300fa7984b471b006a1aafbb18d0a6b2c0420e83e20e8a9421cf2cfd51'
144 | ],
145 | [
146 | 'b6459e0ee3662ec8d23540c223bcbdc571cbcb967d79424f3cf29eb3de6b80ef',
147 | '67c876d06f3e06de1dadf16e5661db3c4b3ae6d48e35b2ff30bf0b61a71ba45'
148 | ],
149 | [
150 | 'd68a80c8280bb840793234aa118f06231d6f1fc67e73c5a5deda0f5b496943e8',
151 | 'db8ba9fff4b586d00c4b1f9177b0e28b5b0e7b8f7845295a294c84266b133120'
152 | ],
153 | [
154 | '324aed7df65c804252dc0270907a30b09612aeb973449cea4095980fc28d3d5d',
155 | '648a365774b61f2ff130c0c35aec1f4f19213b0c7e332843967224af96ab7c84'
156 | ],
157 | [
158 | '4df9c14919cde61f6d51dfdbe5fee5dceec4143ba8d1ca888e8bd373fd054c96',
159 | '35ec51092d8728050974c23a1d85d4b5d506cdc288490192ebac06cad10d5d'
160 | ],
161 | [
162 | '9c3919a84a474870faed8a9c1cc66021523489054d7f0308cbfc99c8ac1f98cd',
163 | 'ddb84f0f4a4ddd57584f044bf260e641905326f76c64c8e6be7e5e03d4fc599d'
164 | ],
165 | [
166 | '6057170b1dd12fdf8de05f281d8e06bb91e1493a8b91d4cc5a21382120a959e5',
167 | '9a1af0b26a6a4807add9a2daf71df262465152bc3ee24c65e899be932385a2a8'
168 | ],
169 | [
170 | 'a576df8e23a08411421439a4518da31880cef0fba7d4df12b1a6973eecb94266',
171 | '40a6bf20e76640b2c92b97afe58cd82c432e10a7f514d9f3ee8be11ae1b28ec8'
172 | ],
173 | [
174 | '7778a78c28dec3e30a05fe9629de8c38bb30d1f5cf9a3a208f763889be58ad71',
175 | '34626d9ab5a5b22ff7098e12f2ff580087b38411ff24ac563b513fc1fd9f43ac'
176 | ],
177 | [
178 | '928955ee637a84463729fd30e7afd2ed5f96274e5ad7e5cb09eda9c06d903ac',
179 | 'c25621003d3f42a827b78a13093a95eeac3d26efa8a8d83fc5180e935bcd091f'
180 | ],
181 | [
182 | '85d0fef3ec6db109399064f3a0e3b2855645b4a907ad354527aae75163d82751',
183 | '1f03648413a38c0be29d496e582cf5663e8751e96877331582c237a24eb1f962'
184 | ],
185 | [
186 | 'ff2b0dce97eece97c1c9b6041798b85dfdfb6d8882da20308f5404824526087e',
187 | '493d13fef524ba188af4c4dc54d07936c7b7ed6fb90e2ceb2c951e01f0c29907'
188 | ],
189 | [
190 | '827fbbe4b1e880ea9ed2b2e6301b212b57f1ee148cd6dd28780e5e2cf856e241',
191 | 'c60f9c923c727b0b71bef2c67d1d12687ff7a63186903166d605b68baec293ec'
192 | ],
193 | [
194 | 'eaa649f21f51bdbae7be4ae34ce6e5217a58fdce7f47f9aa7f3b58fa2120e2b3',
195 | 'be3279ed5bbbb03ac69a80f89879aa5a01a6b965f13f7e59d47a5305ba5ad93d'
196 | ],
197 | [
198 | 'e4a42d43c5cf169d9391df6decf42ee541b6d8f0c9a137401e23632dda34d24f',
199 | '4d9f92e716d1c73526fc99ccfb8ad34ce886eedfa8d8e4f13a7f7131deba9414'
200 | ],
201 | [
202 | '1ec80fef360cbdd954160fadab352b6b92b53576a88fea4947173b9d4300bf19',
203 | 'aeefe93756b5340d2f3a4958a7abbf5e0146e77f6295a07b671cdc1cc107cefd'
204 | ],
205 | [
206 | '146a778c04670c2f91b00af4680dfa8bce3490717d58ba889ddb5928366642be',
207 | 'b318e0ec3354028add669827f9d4b2870aaa971d2f7e5ed1d0b297483d83efd0'
208 | ],
209 | [
210 | 'fa50c0f61d22e5f07e3acebb1aa07b128d0012209a28b9776d76a8793180eef9',
211 | '6b84c6922397eba9b72cd2872281a68a5e683293a57a213b38cd8d7d3f4f2811'
212 | ],
213 | [
214 | 'da1d61d0ca721a11b1a5bf6b7d88e8421a288ab5d5bba5220e53d32b5f067ec2',
215 | '8157f55a7c99306c79c0766161c91e2966a73899d279b48a655fba0f1ad836f1'
216 | ],
217 | [
218 | 'a8e282ff0c9706907215ff98e8fd416615311de0446f1e062a73b0610d064e13',
219 | '7f97355b8db81c09abfb7f3c5b2515888b679a3e50dd6bd6cef7c73111f4cc0c'
220 | ],
221 | [
222 | '174a53b9c9a285872d39e56e6913cab15d59b1fa512508c022f382de8319497c',
223 | 'ccc9dc37abfc9c1657b4155f2c47f9e6646b3a1d8cb9854383da13ac079afa73'
224 | ],
225 | [
226 | '959396981943785c3d3e57edf5018cdbe039e730e4918b3d884fdff09475b7ba',
227 | '2e7e552888c331dd8ba0386a4b9cd6849c653f64c8709385e9b8abf87524f2fd'
228 | ],
229 | [
230 | 'd2a63a50ae401e56d645a1153b109a8fcca0a43d561fba2dbb51340c9d82b151',
231 | 'e82d86fb6443fcb7565aee58b2948220a70f750af484ca52d4142174dcf89405'
232 | ],
233 | [
234 | '64587e2335471eb890ee7896d7cfdc866bacbdbd3839317b3436f9b45617e073',
235 | 'd99fcdd5bf6902e2ae96dd6447c299a185b90a39133aeab358299e5e9faf6589'
236 | ],
237 | [
238 | '8481bde0e4e4d885b3a546d3e549de042f0aa6cea250e7fd358d6c86dd45e458',
239 | '38ee7b8cba5404dd84a25bf39cecb2ca900a79c42b262e556d64b1b59779057e'
240 | ],
241 | [
242 | '13464a57a78102aa62b6979ae817f4637ffcfed3c4b1ce30bcd6303f6caf666b',
243 | '69be159004614580ef7e433453ccb0ca48f300a81d0942e13f495a907f6ecc27'
244 | ],
245 | [
246 | 'bc4a9df5b713fe2e9aef430bcc1dc97a0cd9ccede2f28588cada3a0d2d83f366',
247 | 'd3a81ca6e785c06383937adf4b798caa6e8a9fbfa547b16d758d666581f33c1'
248 | ],
249 | [
250 | '8c28a97bf8298bc0d23d8c749452a32e694b65e30a9472a3954ab30fe5324caa',
251 | '40a30463a3305193378fedf31f7cc0eb7ae784f0451cb9459e71dc73cbef9482'
252 | ],
253 | [
254 | '8ea9666139527a8c1dd94ce4f071fd23c8b350c5a4bb33748c4ba111faccae0',
255 | '620efabbc8ee2782e24e7c0cfb95c5d735b783be9cf0f8e955af34a30e62b945'
256 | ],
257 | [
258 | 'dd3625faef5ba06074669716bbd3788d89bdde815959968092f76cc4eb9a9787',
259 | '7a188fa3520e30d461da2501045731ca941461982883395937f68d00c644a573'
260 | ],
261 | [
262 | 'f710d79d9eb962297e4f6232b40e8f7feb2bc63814614d692c12de752408221e',
263 | 'ea98e67232d3b3295d3b535532115ccac8612c721851617526ae47a9c77bfc82'
264 | ]
265 | ]
266 | },
267 | naf: {
268 | wnd: 7,
269 | points: [
270 | [
271 | 'f9308a019258c31049344f85f89d5229b531c845836f99b08601f113bce036f9',
272 | '388f7b0f632de8140fe337e62a37f3566500a99934c2231b6cb9fd7584b8e672'
273 | ],
274 | [
275 | '2f8bde4d1a07209355b4a7250a5c5128e88b84bddc619ab7cba8d569b240efe4',
276 | 'd8ac222636e5e3d6d4dba9dda6c9c426f788271bab0d6840dca87d3aa6ac62d6'
277 | ],
278 | [
279 | '5cbdf0646e5db4eaa398f365f2ea7a0e3d419b7e0330e39ce92bddedcac4f9bc',
280 | '6aebca40ba255960a3178d6d861a54dba813d0b813fde7b5a5082628087264da'
281 | ],
282 | [
283 | 'acd484e2f0c7f65309ad178a9f559abde09796974c57e714c35f110dfc27ccbe',
284 | 'cc338921b0a7d9fd64380971763b61e9add888a4375f8e0f05cc262ac64f9c37'
285 | ],
286 | [
287 | '774ae7f858a9411e5ef4246b70c65aac5649980be5c17891bbec17895da008cb',
288 | 'd984a032eb6b5e190243dd56d7b7b365372db1e2dff9d6a8301d74c9c953c61b'
289 | ],
290 | [
291 | 'f28773c2d975288bc7d1d205c3748651b075fbc6610e58cddeeddf8f19405aa8',
292 | 'ab0902e8d880a89758212eb65cdaf473a1a06da521fa91f29b5cb52db03ed81'
293 | ],
294 | [
295 | 'd7924d4f7d43ea965a465ae3095ff41131e5946f3c85f79e44adbcf8e27e080e',
296 | '581e2872a86c72a683842ec228cc6defea40af2bd896d3a5c504dc9ff6a26b58'
297 | ],
298 | [
299 | 'defdea4cdb677750a420fee807eacf21eb9898ae79b9768766e4faa04a2d4a34',
300 | '4211ab0694635168e997b0ead2a93daeced1f4a04a95c0f6cfb199f69e56eb77'
301 | ],
302 | [
303 | '2b4ea0a797a443d293ef5cff444f4979f06acfebd7e86d277475656138385b6c',
304 | '85e89bc037945d93b343083b5a1c86131a01f60c50269763b570c854e5c09b7a'
305 | ],
306 | [
307 | '352bbf4a4cdd12564f93fa332ce333301d9ad40271f8107181340aef25be59d5',
308 | '321eb4075348f534d59c18259dda3e1f4a1b3b2e71b1039c67bd3d8bcf81998c'
309 | ],
310 | [
311 | '2fa2104d6b38d11b0230010559879124e42ab8dfeff5ff29dc9cdadd4ecacc3f',
312 | '2de1068295dd865b64569335bd5dd80181d70ecfc882648423ba76b532b7d67'
313 | ],
314 | [
315 | '9248279b09b4d68dab21a9b066edda83263c3d84e09572e269ca0cd7f5453714',
316 | '73016f7bf234aade5d1aa71bdea2b1ff3fc0de2a887912ffe54a32ce97cb3402'
317 | ],
318 | [
319 | 'daed4f2be3a8bf278e70132fb0beb7522f570e144bf615c07e996d443dee8729',
320 | 'a69dce4a7d6c98e8d4a1aca87ef8d7003f83c230f3afa726ab40e52290be1c55'
321 | ],
322 | [
323 | 'c44d12c7065d812e8acf28d7cbb19f9011ecd9e9fdf281b0e6a3b5e87d22e7db',
324 | '2119a460ce326cdc76c45926c982fdac0e106e861edf61c5a039063f0e0e6482'
325 | ],
326 | [
327 | '6a245bf6dc698504c89a20cfded60853152b695336c28063b61c65cbd269e6b4',
328 | 'e022cf42c2bd4a708b3f5126f16a24ad8b33ba48d0423b6efd5e6348100d8a82'
329 | ],
330 | [
331 | '1697ffa6fd9de627c077e3d2fe541084ce13300b0bec1146f95ae57f0d0bd6a5',
332 | 'b9c398f186806f5d27561506e4557433a2cf15009e498ae7adee9d63d01b2396'
333 | ],
334 | [
335 | '605bdb019981718b986d0f07e834cb0d9deb8360ffb7f61df982345ef27a7479',
336 | '2972d2de4f8d20681a78d93ec96fe23c26bfae84fb14db43b01e1e9056b8c49'
337 | ],
338 | [
339 | '62d14dab4150bf497402fdc45a215e10dcb01c354959b10cfe31c7e9d87ff33d',
340 | '80fc06bd8cc5b01098088a1950eed0db01aa132967ab472235f5642483b25eaf'
341 | ],
342 | [
343 | '80c60ad0040f27dade5b4b06c408e56b2c50e9f56b9b8b425e555c2f86308b6f',
344 | '1c38303f1cc5c30f26e66bad7fe72f70a65eed4cbe7024eb1aa01f56430bd57a'
345 | ],
346 | [
347 | '7a9375ad6167ad54aa74c6348cc54d344cc5dc9487d847049d5eabb0fa03c8fb',
348 | 'd0e3fa9eca8726909559e0d79269046bdc59ea10c70ce2b02d499ec224dc7f7'
349 | ],
350 | [
351 | 'd528ecd9b696b54c907a9ed045447a79bb408ec39b68df504bb51f459bc3ffc9',
352 | 'eecf41253136e5f99966f21881fd656ebc4345405c520dbc063465b521409933'
353 | ],
354 | [
355 | '49370a4b5f43412ea25f514e8ecdad05266115e4a7ecb1387231808f8b45963',
356 | '758f3f41afd6ed428b3081b0512fd62a54c3f3afbb5b6764b653052a12949c9a'
357 | ],
358 | [
359 | '77f230936ee88cbbd73df930d64702ef881d811e0e1498e2f1c13eb1fc345d74',
360 | '958ef42a7886b6400a08266e9ba1b37896c95330d97077cbbe8eb3c7671c60d6'
361 | ],
362 | [
363 | 'f2dac991cc4ce4b9ea44887e5c7c0bce58c80074ab9d4dbaeb28531b7739f530',
364 | 'e0dedc9b3b2f8dad4da1f32dec2531df9eb5fbeb0598e4fd1a117dba703a3c37'
365 | ],
366 | [
367 | '463b3d9f662621fb1b4be8fbbe2520125a216cdfc9dae3debcba4850c690d45b',
368 | '5ed430d78c296c3543114306dd8622d7c622e27c970a1de31cb377b01af7307e'
369 | ],
370 | [
371 | 'f16f804244e46e2a09232d4aff3b59976b98fac14328a2d1a32496b49998f247',
372 | 'cedabd9b82203f7e13d206fcdf4e33d92a6c53c26e5cce26d6579962c4e31df6'
373 | ],
374 | [
375 | 'caf754272dc84563b0352b7a14311af55d245315ace27c65369e15f7151d41d1',
376 | 'cb474660ef35f5f2a41b643fa5e460575f4fa9b7962232a5c32f908318a04476'
377 | ],
378 | [
379 | '2600ca4b282cb986f85d0f1709979d8b44a09c07cb86d7c124497bc86f082120',
380 | '4119b88753c15bd6a693b03fcddbb45d5ac6be74ab5f0ef44b0be9475a7e4b40'
381 | ],
382 | [
383 | '7635ca72d7e8432c338ec53cd12220bc01c48685e24f7dc8c602a7746998e435',
384 | '91b649609489d613d1d5e590f78e6d74ecfc061d57048bad9e76f302c5b9c61'
385 | ],
386 | [
387 | '754e3239f325570cdbbf4a87deee8a66b7f2b33479d468fbc1a50743bf56cc18',
388 | '673fb86e5bda30fb3cd0ed304ea49a023ee33d0197a695d0c5d98093c536683'
389 | ],
390 | [
391 | 'e3e6bd1071a1e96aff57859c82d570f0330800661d1c952f9fe2694691d9b9e8',
392 | '59c9e0bba394e76f40c0aa58379a3cb6a5a2283993e90c4167002af4920e37f5'
393 | ],
394 | [
395 | '186b483d056a033826ae73d88f732985c4ccb1f32ba35f4b4cc47fdcf04aa6eb',
396 | '3b952d32c67cf77e2e17446e204180ab21fb8090895138b4a4a797f86e80888b'
397 | ],
398 | [
399 | 'df9d70a6b9876ce544c98561f4be4f725442e6d2b737d9c91a8321724ce0963f',
400 | '55eb2dafd84d6ccd5f862b785dc39d4ab157222720ef9da217b8c45cf2ba2417'
401 | ],
402 | [
403 | '5edd5cc23c51e87a497ca815d5dce0f8ab52554f849ed8995de64c5f34ce7143',
404 | 'efae9c8dbc14130661e8cec030c89ad0c13c66c0d17a2905cdc706ab7399a868'
405 | ],
406 | [
407 | '290798c2b6476830da12fe02287e9e777aa3fba1c355b17a722d362f84614fba',
408 | 'e38da76dcd440621988d00bcf79af25d5b29c094db2a23146d003afd41943e7a'
409 | ],
410 | [
411 | 'af3c423a95d9f5b3054754efa150ac39cd29552fe360257362dfdecef4053b45',
412 | 'f98a3fd831eb2b749a93b0e6f35cfb40c8cd5aa667a15581bc2feded498fd9c6'
413 | ],
414 | [
415 | '766dbb24d134e745cccaa28c99bf274906bb66b26dcf98df8d2fed50d884249a',
416 | '744b1152eacbe5e38dcc887980da38b897584a65fa06cedd2c924f97cbac5996'
417 | ],
418 | [
419 | '59dbf46f8c94759ba21277c33784f41645f7b44f6c596a58ce92e666191abe3e',
420 | 'c534ad44175fbc300f4ea6ce648309a042ce739a7919798cd85e216c4a307f6e'
421 | ],
422 | [
423 | 'f13ada95103c4537305e691e74e9a4a8dd647e711a95e73cb62dc6018cfd87b8',
424 | 'e13817b44ee14de663bf4bc808341f326949e21a6a75c2570778419bdaf5733d'
425 | ],
426 | [
427 | '7754b4fa0e8aced06d4167a2c59cca4cda1869c06ebadfb6488550015a88522c',
428 | '30e93e864e669d82224b967c3020b8fa8d1e4e350b6cbcc537a48b57841163a2'
429 | ],
430 | [
431 | '948dcadf5990e048aa3874d46abef9d701858f95de8041d2a6828c99e2262519',
432 | 'e491a42537f6e597d5d28a3224b1bc25df9154efbd2ef1d2cbba2cae5347d57e'
433 | ],
434 | [
435 | '7962414450c76c1689c7b48f8202ec37fb224cf5ac0bfa1570328a8a3d7c77ab',
436 | '100b610ec4ffb4760d5c1fc133ef6f6b12507a051f04ac5760afa5b29db83437'
437 | ],
438 | [
439 | '3514087834964b54b15b160644d915485a16977225b8847bb0dd085137ec47ca',
440 | 'ef0afbb2056205448e1652c48e8127fc6039e77c15c2378b7e7d15a0de293311'
441 | ],
442 | [
443 | 'd3cc30ad6b483e4bc79ce2c9dd8bc54993e947eb8df787b442943d3f7b527eaf',
444 | '8b378a22d827278d89c5e9be8f9508ae3c2ad46290358630afb34db04eede0a4'
445 | ],
446 | [
447 | '1624d84780732860ce1c78fcbfefe08b2b29823db913f6493975ba0ff4847610',
448 | '68651cf9b6da903e0914448c6cd9d4ca896878f5282be4c8cc06e2a404078575'
449 | ],
450 | [
451 | '733ce80da955a8a26902c95633e62a985192474b5af207da6df7b4fd5fc61cd4',
452 | 'f5435a2bd2badf7d485a4d8b8db9fcce3e1ef8e0201e4578c54673bc1dc5ea1d'
453 | ],
454 | [
455 | '15d9441254945064cf1a1c33bbd3b49f8966c5092171e699ef258dfab81c045c',
456 | 'd56eb30b69463e7234f5137b73b84177434800bacebfc685fc37bbe9efe4070d'
457 | ],
458 | [
459 | 'a1d0fcf2ec9de675b612136e5ce70d271c21417c9d2b8aaaac138599d0717940',
460 | 'edd77f50bcb5a3cab2e90737309667f2641462a54070f3d519212d39c197a629'
461 | ],
462 | [
463 | 'e22fbe15c0af8ccc5780c0735f84dbe9a790badee8245c06c7ca37331cb36980',
464 | 'a855babad5cd60c88b430a69f53a1a7a38289154964799be43d06d77d31da06'
465 | ],
466 | [
467 | '311091dd9860e8e20ee13473c1155f5f69635e394704eaa74009452246cfa9b3',
468 | '66db656f87d1f04fffd1f04788c06830871ec5a64feee685bd80f0b1286d8374'
469 | ],
470 | [
471 | '34c1fd04d301be89b31c0442d3e6ac24883928b45a9340781867d4232ec2dbdf',
472 | '9414685e97b1b5954bd46f730174136d57f1ceeb487443dc5321857ba73abee'
473 | ],
474 | [
475 | 'f219ea5d6b54701c1c14de5b557eb42a8d13f3abbcd08affcc2a5e6b049b8d63',
476 | '4cb95957e83d40b0f73af4544cccf6b1f4b08d3c07b27fb8d8c2962a400766d1'
477 | ],
478 | [
479 | 'd7b8740f74a8fbaab1f683db8f45de26543a5490bca627087236912469a0b448',
480 | 'fa77968128d9c92ee1010f337ad4717eff15db5ed3c049b3411e0315eaa4593b'
481 | ],
482 | [
483 | '32d31c222f8f6f0ef86f7c98d3a3335ead5bcd32abdd94289fe4d3091aa824bf',
484 | '5f3032f5892156e39ccd3d7915b9e1da2e6dac9e6f26e961118d14b8462e1661'
485 | ],
486 | [
487 | '7461f371914ab32671045a155d9831ea8793d77cd59592c4340f86cbc18347b5',
488 | '8ec0ba238b96bec0cbdddcae0aa442542eee1ff50c986ea6b39847b3cc092ff6'
489 | ],
490 | [
491 | 'ee079adb1df1860074356a25aa38206a6d716b2c3e67453d287698bad7b2b2d6',
492 | '8dc2412aafe3be5c4c5f37e0ecc5f9f6a446989af04c4e25ebaac479ec1c8c1e'
493 | ],
494 | [
495 | '16ec93e447ec83f0467b18302ee620f7e65de331874c9dc72bfd8616ba9da6b5',
496 | '5e4631150e62fb40d0e8c2a7ca5804a39d58186a50e497139626778e25b0674d'
497 | ],
498 | [
499 | 'eaa5f980c245f6f038978290afa70b6bd8855897f98b6aa485b96065d537bd99',
500 | 'f65f5d3e292c2e0819a528391c994624d784869d7e6ea67fb18041024edc07dc'
501 | ],
502 | [
503 | '78c9407544ac132692ee1910a02439958ae04877151342ea96c4b6b35a49f51',
504 | 'f3e0319169eb9b85d5404795539a5e68fa1fbd583c064d2462b675f194a3ddb4'
505 | ],
506 | [
507 | '494f4be219a1a77016dcd838431aea0001cdc8ae7a6fc688726578d9702857a5',
508 | '42242a969283a5f339ba7f075e36ba2af925ce30d767ed6e55f4b031880d562c'
509 | ],
510 | [
511 | 'a598a8030da6d86c6bc7f2f5144ea549d28211ea58faa70ebf4c1e665c1fe9b5',
512 | '204b5d6f84822c307e4b4a7140737aec23fc63b65b35f86a10026dbd2d864e6b'
513 | ],
514 | [
515 | 'c41916365abb2b5d09192f5f2dbeafec208f020f12570a184dbadc3e58595997',
516 | '4f14351d0087efa49d245b328984989d5caf9450f34bfc0ed16e96b58fa9913'
517 | ],
518 | [
519 | '841d6063a586fa475a724604da03bc5b92a2e0d2e0a36acfe4c73a5514742881',
520 | '73867f59c0659e81904f9a1c7543698e62562d6744c169ce7a36de01a8d6154'
521 | ],
522 | [
523 | '5e95bb399a6971d376026947f89bde2f282b33810928be4ded112ac4d70e20d5',
524 | '39f23f366809085beebfc71181313775a99c9aed7d8ba38b161384c746012865'
525 | ],
526 | [
527 | '36e4641a53948fd476c39f8a99fd974e5ec07564b5315d8bf99471bca0ef2f66',
528 | 'd2424b1b1abe4eb8164227b085c9aa9456ea13493fd563e06fd51cf5694c78fc'
529 | ],
530 | [
531 | '336581ea7bfbbb290c191a2f507a41cf5643842170e914faeab27c2c579f726',
532 | 'ead12168595fe1be99252129b6e56b3391f7ab1410cd1e0ef3dcdcabd2fda224'
533 | ],
534 | [
535 | '8ab89816dadfd6b6a1f2634fcf00ec8403781025ed6890c4849742706bd43ede',
536 | '6fdcef09f2f6d0a044e654aef624136f503d459c3e89845858a47a9129cdd24e'
537 | ],
538 | [
539 | '1e33f1a746c9c5778133344d9299fcaa20b0938e8acff2544bb40284b8c5fb94',
540 | '60660257dd11b3aa9c8ed618d24edff2306d320f1d03010e33a7d2057f3b3b6'
541 | ],
542 | [
543 | '85b7c1dcb3cec1b7ee7f30ded79dd20a0ed1f4cc18cbcfcfa410361fd8f08f31',
544 | '3d98a9cdd026dd43f39048f25a8847f4fcafad1895d7a633c6fed3c35e999511'
545 | ],
546 | [
547 | '29df9fbd8d9e46509275f4b125d6d45d7fbe9a3b878a7af872a2800661ac5f51',
548 | 'b4c4fe99c775a606e2d8862179139ffda61dc861c019e55cd2876eb2a27d84b'
549 | ],
550 | [
551 | 'a0b1cae06b0a847a3fea6e671aaf8adfdfe58ca2f768105c8082b2e449fce252',
552 | 'ae434102edde0958ec4b19d917a6a28e6b72da1834aff0e650f049503a296cf2'
553 | ],
554 | [
555 | '4e8ceafb9b3e9a136dc7ff67e840295b499dfb3b2133e4ba113f2e4c0e121e5',
556 | 'cf2174118c8b6d7a4b48f6d534ce5c79422c086a63460502b827ce62a326683c'
557 | ],
558 | [
559 | 'd24a44e047e19b6f5afb81c7ca2f69080a5076689a010919f42725c2b789a33b',
560 | '6fb8d5591b466f8fc63db50f1c0f1c69013f996887b8244d2cdec417afea8fa3'
561 | ],
562 | [
563 | 'ea01606a7a6c9cdd249fdfcfacb99584001edd28abbab77b5104e98e8e3b35d4',
564 | '322af4908c7312b0cfbfe369f7a7b3cdb7d4494bc2823700cfd652188a3ea98d'
565 | ],
566 | [
567 | 'af8addbf2b661c8a6c6328655eb96651252007d8c5ea31be4ad196de8ce2131f',
568 | '6749e67c029b85f52a034eafd096836b2520818680e26ac8f3dfbcdb71749700'
569 | ],
570 | [
571 | 'e3ae1974566ca06cc516d47e0fb165a674a3dabcfca15e722f0e3450f45889',
572 | '2aeabe7e4531510116217f07bf4d07300de97e4874f81f533420a72eeb0bd6a4'
573 | ],
574 | [
575 | '591ee355313d99721cf6993ffed1e3e301993ff3ed258802075ea8ced397e246',
576 | 'b0ea558a113c30bea60fc4775460c7901ff0b053d25ca2bdeee98f1a4be5d196'
577 | ],
578 | [
579 | '11396d55fda54c49f19aa97318d8da61fa8584e47b084945077cf03255b52984',
580 | '998c74a8cd45ac01289d5833a7beb4744ff536b01b257be4c5767bea93ea57a4'
581 | ],
582 | [
583 | '3c5d2a1ba39c5a1790000738c9e0c40b8dcdfd5468754b6405540157e017aa7a',
584 | 'b2284279995a34e2f9d4de7396fc18b80f9b8b9fdd270f6661f79ca4c81bd257'
585 | ],
586 | [
587 | 'cc8704b8a60a0defa3a99a7299f2e9c3fbc395afb04ac078425ef8a1793cc030',
588 | 'bdd46039feed17881d1e0862db347f8cf395b74fc4bcdc4e940b74e3ac1f1b13'
589 | ],
590 | [
591 | 'c533e4f7ea8555aacd9777ac5cad29b97dd4defccc53ee7ea204119b2889b197',
592 | '6f0a256bc5efdf429a2fb6242f1a43a2d9b925bb4a4b3a26bb8e0f45eb596096'
593 | ],
594 | [
595 | 'c14f8f2ccb27d6f109f6d08d03cc96a69ba8c34eec07bbcf566d48e33da6593',
596 | 'c359d6923bb398f7fd4473e16fe1c28475b740dd098075e6c0e8649113dc3a38'
597 | ],
598 | [
599 | 'a6cbc3046bc6a450bac24789fa17115a4c9739ed75f8f21ce441f72e0b90e6ef',
600 | '21ae7f4680e889bb130619e2c0f95a360ceb573c70603139862afd617fa9b9f'
601 | ],
602 | [
603 | '347d6d9a02c48927ebfb86c1359b1caf130a3c0267d11ce6344b39f99d43cc38',
604 | '60ea7f61a353524d1c987f6ecec92f086d565ab687870cb12689ff1e31c74448'
605 | ],
606 | [
607 | 'da6545d2181db8d983f7dcb375ef5866d47c67b1bf31c8cf855ef7437b72656a',
608 | '49b96715ab6878a79e78f07ce5680c5d6673051b4935bd897fea824b77dc208a'
609 | ],
610 | [
611 | 'c40747cc9d012cb1a13b8148309c6de7ec25d6945d657146b9d5994b8feb1111',
612 | '5ca560753be2a12fc6de6caf2cb489565db936156b9514e1bb5e83037e0fa2d4'
613 | ],
614 | [
615 | '4e42c8ec82c99798ccf3a610be870e78338c7f713348bd34c8203ef4037f3502',
616 | '7571d74ee5e0fb92a7a8b33a07783341a5492144cc54bcc40a94473693606437'
617 | ],
618 | [
619 | '3775ab7089bc6af823aba2e1af70b236d251cadb0c86743287522a1b3b0dedea',
620 | 'be52d107bcfa09d8bcb9736a828cfa7fac8db17bf7a76a2c42ad961409018cf7'
621 | ],
622 | [
623 | 'cee31cbf7e34ec379d94fb814d3d775ad954595d1314ba8846959e3e82f74e26',
624 | '8fd64a14c06b589c26b947ae2bcf6bfa0149ef0be14ed4d80f448a01c43b1c6d'
625 | ],
626 | [
627 | 'b4f9eaea09b6917619f6ea6a4eb5464efddb58fd45b1ebefcdc1a01d08b47986',
628 | '39e5c9925b5a54b07433a4f18c61726f8bb131c012ca542eb24a8ac07200682a'
629 | ],
630 | [
631 | 'd4263dfc3d2df923a0179a48966d30ce84e2515afc3dccc1b77907792ebcc60e',
632 | '62dfaf07a0f78feb30e30d6295853ce189e127760ad6cf7fae164e122a208d54'
633 | ],
634 | [
635 | '48457524820fa65a4f8d35eb6930857c0032acc0a4a2de422233eeda897612c4',
636 | '25a748ab367979d98733c38a1fa1c2e7dc6cc07db2d60a9ae7a76aaa49bd0f77'
637 | ],
638 | [
639 | 'dfeeef1881101f2cb11644f3a2afdfc2045e19919152923f367a1767c11cceda',
640 | 'ecfb7056cf1de042f9420bab396793c0c390bde74b4bbdff16a83ae09a9a7517'
641 | ],
642 | [
643 | '6d7ef6b17543f8373c573f44e1f389835d89bcbc6062ced36c82df83b8fae859',
644 | 'cd450ec335438986dfefa10c57fea9bcc521a0959b2d80bbf74b190dca712d10'
645 | ],
646 | [
647 | 'e75605d59102a5a2684500d3b991f2e3f3c88b93225547035af25af66e04541f',
648 | 'f5c54754a8f71ee540b9b48728473e314f729ac5308b06938360990e2bfad125'
649 | ],
650 | [
651 | 'eb98660f4c4dfaa06a2be453d5020bc99a0c2e60abe388457dd43fefb1ed620c',
652 | '6cb9a8876d9cb8520609af3add26cd20a0a7cd8a9411131ce85f44100099223e'
653 | ],
654 | [
655 | '13e87b027d8514d35939f2e6892b19922154596941888336dc3563e3b8dba942',
656 | 'fef5a3c68059a6dec5d624114bf1e91aac2b9da568d6abeb2570d55646b8adf1'
657 | ],
658 | [
659 | 'ee163026e9fd6fe017c38f06a5be6fc125424b371ce2708e7bf4491691e5764a',
660 | '1acb250f255dd61c43d94ccc670d0f58f49ae3fa15b96623e5430da0ad6c62b2'
661 | ],
662 | [
663 | 'b268f5ef9ad51e4d78de3a750c2dc89b1e626d43505867999932e5db33af3d80',
664 | '5f310d4b3c99b9ebb19f77d41c1dee018cf0d34fd4191614003e945a1216e423'
665 | ],
666 | [
667 | 'ff07f3118a9df035e9fad85eb6c7bfe42b02f01ca99ceea3bf7ffdba93c4750d',
668 | '438136d603e858a3a5c440c38eccbaddc1d2942114e2eddd4740d098ced1f0d8'
669 | ],
670 | [
671 | '8d8b9855c7c052a34146fd20ffb658bea4b9f69e0d825ebec16e8c3ce2b526a1',
672 | 'cdb559eedc2d79f926baf44fb84ea4d44bcf50fee51d7ceb30e2e7f463036758'
673 | ],
674 | [
675 | '52db0b5384dfbf05bfa9d472d7ae26dfe4b851ceca91b1eba54263180da32b63',
676 | 'c3b997d050ee5d423ebaf66a6db9f57b3180c902875679de924b69d84a7b375'
677 | ],
678 | [
679 | 'e62f9490d3d51da6395efd24e80919cc7d0f29c3f3fa48c6fff543becbd43352',
680 | '6d89ad7ba4876b0b22c2ca280c682862f342c8591f1daf5170e07bfd9ccafa7d'
681 | ],
682 | [
683 | '7f30ea2476b399b4957509c88f77d0191afa2ff5cb7b14fd6d8e7d65aaab1193',
684 | 'ca5ef7d4b231c94c3b15389a5f6311e9daff7bb67b103e9880ef4bff637acaec'
685 | ],
686 | [
687 | '5098ff1e1d9f14fb46a210fada6c903fef0fb7b4a1dd1d9ac60a0361800b7a00',
688 | '9731141d81fc8f8084d37c6e7542006b3ee1b40d60dfe5362a5b132fd17ddc0'
689 | ],
690 | [
691 | '32b78c7de9ee512a72895be6b9cbefa6e2f3c4ccce445c96b9f2c81e2778ad58',
692 | 'ee1849f513df71e32efc3896ee28260c73bb80547ae2275ba497237794c8753c'
693 | ],
694 | [
695 | 'e2cb74fddc8e9fbcd076eef2a7c72b0ce37d50f08269dfc074b581550547a4f7',
696 | 'd3aa2ed71c9dd2247a62df062736eb0baddea9e36122d2be8641abcb005cc4a4'
697 | ],
698 | [
699 | '8438447566d4d7bedadc299496ab357426009a35f235cb141be0d99cd10ae3a8',
700 | 'c4e1020916980a4da5d01ac5e6ad330734ef0d7906631c4f2390426b2edd791f'
701 | ],
702 | [
703 | '4162d488b89402039b584c6fc6c308870587d9c46f660b878ab65c82c711d67e',
704 | '67163e903236289f776f22c25fb8a3afc1732f2b84b4e95dbda47ae5a0852649'
705 | ],
706 | [
707 | '3fad3fa84caf0f34f0f89bfd2dcf54fc175d767aec3e50684f3ba4a4bf5f683d',
708 | 'cd1bc7cb6cc407bb2f0ca647c718a730cf71872e7d0d2a53fa20efcdfe61826'
709 | ],
710 | [
711 | '674f2600a3007a00568c1a7ce05d0816c1fb84bf1370798f1c69532faeb1a86b',
712 | '299d21f9413f33b3edf43b257004580b70db57da0b182259e09eecc69e0d38a5'
713 | ],
714 | [
715 | 'd32f4da54ade74abb81b815ad1fb3b263d82d6c692714bcff87d29bd5ee9f08f',
716 | 'f9429e738b8e53b968e99016c059707782e14f4535359d582fc416910b3eea87'
717 | ],
718 | [
719 | '30e4e670435385556e593657135845d36fbb6931f72b08cb1ed954f1e3ce3ff6',
720 | '462f9bce619898638499350113bbc9b10a878d35da70740dc695a559eb88db7b'
721 | ],
722 | [
723 | 'be2062003c51cc3004682904330e4dee7f3dcd10b01e580bf1971b04d4cad297',
724 | '62188bc49d61e5428573d48a74e1c655b1c61090905682a0d5558ed72dccb9bc'
725 | ],
726 | [
727 | '93144423ace3451ed29e0fb9ac2af211cb6e84a601df5993c419859fff5df04a',
728 | '7c10dfb164c3425f5c71a3f9d7992038f1065224f72bb9d1d902a6d13037b47c'
729 | ],
730 | [
731 | 'b015f8044f5fcbdcf21ca26d6c34fb8197829205c7b7d2a7cb66418c157b112c',
732 | 'ab8c1e086d04e813744a655b2df8d5f83b3cdc6faa3088c1d3aea1454e3a1d5f'
733 | ],
734 | [
735 | 'd5e9e1da649d97d89e4868117a465a3a4f8a18de57a140d36b3f2af341a21b52',
736 | '4cb04437f391ed73111a13cc1d4dd0db1693465c2240480d8955e8592f27447a'
737 | ],
738 | [
739 | 'd3ae41047dd7ca065dbf8ed77b992439983005cd72e16d6f996a5316d36966bb',
740 | 'bd1aeb21ad22ebb22a10f0303417c6d964f8cdd7df0aca614b10dc14d125ac46'
741 | ],
742 | [
743 | '463e2763d885f958fc66cdd22800f0a487197d0a82e377b49f80af87c897b065',
744 | 'bfefacdb0e5d0fd7df3a311a94de062b26b80c61fbc97508b79992671ef7ca7f'
745 | ],
746 | [
747 | '7985fdfd127c0567c6f53ec1bb63ec3158e597c40bfe747c83cddfc910641917',
748 | '603c12daf3d9862ef2b25fe1de289aed24ed291e0ec6708703a5bd567f32ed03'
749 | ],
750 | [
751 | '74a1ad6b5f76e39db2dd249410eac7f99e74c59cb83d2d0ed5ff1543da7703e9',
752 | 'cc6157ef18c9c63cd6193d83631bbea0093e0968942e8c33d5737fd790e0db08'
753 | ],
754 | [
755 | '30682a50703375f602d416664ba19b7fc9bab42c72747463a71d0896b22f6da3',
756 | '553e04f6b018b4fa6c8f39e7f311d3176290d0e0f19ca73f17714d9977a22ff8'
757 | ],
758 | [
759 | '9e2158f0d7c0d5f26c3791efefa79597654e7a2b2464f52b1ee6c1347769ef57',
760 | '712fcdd1b9053f09003a3481fa7762e9ffd7c8ef35a38509e2fbf2629008373'
761 | ],
762 | [
763 | '176e26989a43c9cfeba4029c202538c28172e566e3c4fce7322857f3be327d66',
764 | 'ed8cc9d04b29eb877d270b4878dc43c19aefd31f4eee09ee7b47834c1fa4b1c3'
765 | ],
766 | [
767 | '75d46efea3771e6e68abb89a13ad747ecf1892393dfc4f1b7004788c50374da8',
768 | '9852390a99507679fd0b86fd2b39a868d7efc22151346e1a3ca4726586a6bed8'
769 | ],
770 | [
771 | '809a20c67d64900ffb698c4c825f6d5f2310fb0451c869345b7319f645605721',
772 | '9e994980d9917e22b76b061927fa04143d096ccc54963e6a5ebfa5f3f8e286c1'
773 | ],
774 | [
775 | '1b38903a43f7f114ed4500b4eac7083fdefece1cf29c63528d563446f972c180',
776 | '4036edc931a60ae889353f77fd53de4a2708b26b6f5da72ad3394119daf408f9'
777 | ]
778 | ]
779 | }
780 | };
781 |
--------------------------------------------------------------------------------