├── .codeclimate.yml ├── .eslintignore ├── .eslintrc.js ├── .gitignore ├── .npmignore ├── .travis.yml ├── Gruntfile.js ├── README.md ├── benchmarks ├── deps │ ├── jodid.js │ └── secp256k1.js ├── index.js └── package.json ├── dist ├── .gitkeep ├── elliptic.js └── elliptic.min.js ├── lib ├── elliptic.js └── elliptic │ ├── curve │ ├── base.js │ ├── edwards.js │ ├── index.js │ ├── mont.js │ └── short.js │ ├── curves.js │ ├── ec │ ├── index.js │ ├── key.js │ └── signature.js │ ├── eddsa │ ├── index.js │ ├── key.js │ └── signature.js │ ├── precomputed │ └── secp256k1.js │ └── utils.js ├── package-lock.json ├── package.json └── test ├── api-test.js ├── curve-test.js ├── ecdh-test.js ├── ecdsa-test.js ├── ed25519-test.js ├── fixtures ├── derivation-fixtures.js └── sign.input ├── index.js └── unittests.html /.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 | -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | test/lib 2 | -------------------------------------------------------------------------------- /.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | "env": { 3 | "node": true, 4 | "es6": true 5 | }, 6 | "extends": [ 7 | "eslint:recommended", 8 | ], 9 | "globals": { 10 | "Atomics": "readonly", 11 | "SharedArrayBuffer": "readonly", 12 | "BigInt": "readonly", 13 | }, 14 | "parserOptions": { 15 | "ecmaVersion": 2020, 16 | "sourceType": "module", 17 | "ecmaFeatures": { 18 | "jsx": true 19 | } 20 | }, 21 | "rules": { 22 | "indent": [ 23 | "error", 24 | 2 25 | ], 26 | "linebreak-style": [ 27 | "error", 28 | "unix" 29 | ], 30 | "quotes": [ 31 | "error", 32 | "single" 33 | ], 34 | "semi": [ 35 | "error", 36 | "always" 37 | ], 38 | "array-bracket-spacing": [ "error", "always" ], 39 | "brace-style": [ "error" ], 40 | "camelcase": [ "error" ], 41 | "comma-spacing": [ "error" ], 42 | "comma-style": [ "error" ], 43 | "eol-last": [ "error" ], 44 | "func-call-spacing": [ "error" ], 45 | "func-name-matching": [ "error" ], 46 | "no-multiple-empty-lines": [ "error" ], 47 | "no-tabs": [ "error" ], 48 | "no-trailing-spaces": [ "error" ], 49 | "no-whitespace-before-property": [ "error" ], 50 | "object-curly-newline": [ "error" ], 51 | "object-curly-spacing": [ "error", "always" ], 52 | "padded-blocks": [ "error", "never" ], 53 | "quotes": [ "error", "single", { "avoidEscape": true } ], 54 | "semi-spacing": [ "error" ], 55 | "semi-style": [ "error" ], 56 | "space-before-blocks": [ "error" ], 57 | "space-in-parens": [ "error" ], 58 | "space-infix-ops": [ "error" ], 59 | "space-unary-ops": [ "error" ], 60 | "switch-colon-spacing": [ "error" ], 61 | "comma-dangle": [ "error", "always-multiline" ], 62 | }, 63 | "settings": { 64 | "react": { 65 | "version": "detect", 66 | }, 67 | } 68 | }; 69 | -------------------------------------------------------------------------------- /.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 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | sudo: false 2 | os: 3 | - linux 4 | language: node_js 5 | node_js: 6 | - "stable" 7 | env: 8 | global: 9 | - secure: ewqsRnX7z3+g6q+mM6peRPhuTlTlkJIRmVG/Ya9AcDXEb7as49KDTdqfMcOu7+FxF50ehqla+TRRCLRPOcVkWqs72OVUXEsjRASp9jQwpQGl+g/vZhyTMwlM2ENEkyiFQtobI1hYKgVW1ogftkc6vm7ywvoyTrFp/leVJBrTuHk= 10 | - secure: UcurJwykdbpUrAsrMox4BfiSGOWDIcI8ytBdxgK2vOC2biZJmkFXG4WfB6X2PwNvK4hx0z2s+VhxNVQRwtyl9mqyeAoAWjTpDg+NOoBgTu6Bacsobg29m65tD4x4Qc6iSmylRnfdb04Iob4rsnNNLZbIbERv3j3PFJMENUD3acQ= 11 | - secure: S8vAesx9V9o0/cJRmENJ76JrzSPLo8mtKAfDVHgcVG7Okfl7ANs+0cW1BtjZjBR63uQKJSmQEYC6N9eQlnNhCjeM7KXtFEbtD76OxvAABj4Sr9pIY06KUYLvBaGdYNmyT0WMIAaRN8SzY2uZEUaxMHmiEd1yOw6qQYBMCjbx0xg= 12 | matrix: 13 | - TEST_SUITE='npm run unit' 14 | matrix: 15 | include: 16 | - node_js: "stable" 17 | env: TEST_SUITE='npm run lint' 18 | - node_js: "stable" 19 | env: TEST_SUITE='grunt coveralls' 20 | - node_js: "stable" 21 | env: TEST_SUITE='grunt saucelabs' 22 | allow_failures: 23 | - env: TEST_SUITE='grunt saucelabs' 24 | fast_finish: true 25 | cache: 26 | directories: 27 | - node_modules 28 | before_script: 29 | - npm install -g grunt-cli 30 | script: 31 | - $TEST_SUITE 32 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Elliptic [![Build Status](https://secure.travis-ci.org/indutny/elliptic.png)](http://travis-ci.org/indutny/elliptic) [![Coverage Status](https://coveralls.io/repos/indutny/elliptic/badge.svg?branch=master&service=github)](https://coveralls.io/github/indutny/elliptic?branch=master) [![Code Climate](https://codeclimate.com/github/indutny/elliptic/badges/gpa.svg)](https://codeclimate.com/github/indutny/elliptic) 2 | 3 | [![Saucelabs Test Status](https://saucelabs.com/browser-matrix/gh-indutny-elliptic.svg)](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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /dist/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/indutny/elliptic/9b77436a59cc35eccf4ffb848259c8762a492ee7/dist/.gitkeep -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /lib/elliptic/curve/base.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var BN = require('bn.js'); 4 | var utils = require('../utils'); 5 | var getNAF = utils.getNAF; 6 | var getJSF = utils.getJSF; 7 | var assert = utils.assert; 8 | 9 | function BaseCurve(type, conf) { 10 | this.type = type; 11 | this.p = new BN(conf.p, 16); 12 | 13 | // Use Montgomery, when there is no fast reduction for the prime 14 | this.red = conf.prime ? BN.red(conf.prime) : BN.mont(this.p); 15 | 16 | // Useful for many curves 17 | this.zero = new BN(0).toRed(this.red); 18 | this.one = new BN(1).toRed(this.red); 19 | this.two = new BN(2).toRed(this.red); 20 | 21 | // Curve configuration, optional 22 | this.n = conf.n && new BN(conf.n, 16); 23 | this.g = conf.g && this.pointFromJSON(conf.g, conf.gRed); 24 | 25 | // Temporary arrays 26 | this._wnafT1 = new Array(4); 27 | this._wnafT2 = new Array(4); 28 | this._wnafT3 = new Array(4); 29 | this._wnafT4 = new Array(4); 30 | 31 | this._bitLength = this.n ? this.n.bitLength() : 0; 32 | 33 | // Generalized Greg Maxwell's trick 34 | var adjustCount = this.n && this.p.div(this.n); 35 | if (!adjustCount || adjustCount.cmpn(100) > 0) { 36 | this.redN = null; 37 | } else { 38 | this._maxwellTrick = true; 39 | this.redN = this.n.toRed(this.red); 40 | } 41 | } 42 | module.exports = BaseCurve; 43 | 44 | BaseCurve.prototype.point = function point() { 45 | throw new Error('Not implemented'); 46 | }; 47 | 48 | BaseCurve.prototype.validate = function validate() { 49 | throw new Error('Not implemented'); 50 | }; 51 | 52 | BaseCurve.prototype._fixedNafMul = function _fixedNafMul(p, k) { 53 | assert(p.precomputed); 54 | var doubles = p._getDoubles(); 55 | 56 | var naf = getNAF(k, 1, this._bitLength); 57 | var I = (1 << (doubles.step + 1)) - (doubles.step % 2 === 0 ? 2 : 1); 58 | I /= 3; 59 | 60 | // Translate into more windowed form 61 | var repr = []; 62 | var j; 63 | var nafW; 64 | for (j = 0; j < naf.length; j += doubles.step) { 65 | nafW = 0; 66 | for (var l = j + doubles.step - 1; l >= j; l--) 67 | nafW = (nafW << 1) + naf[l]; 68 | repr.push(nafW); 69 | } 70 | 71 | var a = this.jpoint(null, null, null); 72 | var b = this.jpoint(null, null, null); 73 | for (var i = I; i > 0; i--) { 74 | for (j = 0; j < repr.length; j++) { 75 | nafW = repr[j]; 76 | if (nafW === i) 77 | b = b.mixedAdd(doubles.points[j]); 78 | else if (nafW === -i) 79 | b = b.mixedAdd(doubles.points[j].neg()); 80 | } 81 | a = a.add(b); 82 | } 83 | return a.toP(); 84 | }; 85 | 86 | BaseCurve.prototype._wnafMul = function _wnafMul(p, k) { 87 | var w = 4; 88 | 89 | // Precompute window 90 | var nafPoints = p._getNAFPoints(w); 91 | w = nafPoints.wnd; 92 | var wnd = nafPoints.points; 93 | 94 | // Get NAF form 95 | var naf = getNAF(k, w, this._bitLength); 96 | 97 | // Add `this`*(N+1) for every w-NAF index 98 | var acc = this.jpoint(null, null, null); 99 | for (var i = naf.length - 1; i >= 0; i--) { 100 | // Count zeroes 101 | for (var l = 0; i >= 0 && naf[i] === 0; i--) 102 | l++; 103 | if (i >= 0) 104 | l++; 105 | acc = acc.dblp(l); 106 | 107 | if (i < 0) 108 | break; 109 | var z = naf[i]; 110 | assert(z !== 0); 111 | if (p.type === 'affine') { 112 | // J +- P 113 | if (z > 0) 114 | acc = acc.mixedAdd(wnd[(z - 1) >> 1]); 115 | else 116 | acc = acc.mixedAdd(wnd[(-z - 1) >> 1].neg()); 117 | } else { 118 | // J +- J 119 | if (z > 0) 120 | acc = acc.add(wnd[(z - 1) >> 1]); 121 | else 122 | acc = acc.add(wnd[(-z - 1) >> 1].neg()); 123 | } 124 | } 125 | return p.type === 'affine' ? acc.toP() : acc; 126 | }; 127 | 128 | BaseCurve.prototype._wnafMulAdd = function _wnafMulAdd(defW, 129 | points, 130 | coeffs, 131 | len, 132 | jacobianResult) { 133 | var wndWidth = this._wnafT1; 134 | var wnd = this._wnafT2; 135 | var naf = this._wnafT3; 136 | 137 | // Fill all arrays 138 | var max = 0; 139 | var i; 140 | var j; 141 | var p; 142 | for (i = 0; i < len; i++) { 143 | p = points[i]; 144 | var nafPoints = p._getNAFPoints(defW); 145 | wndWidth[i] = nafPoints.wnd; 146 | wnd[i] = nafPoints.points; 147 | } 148 | 149 | // Comb small window NAFs 150 | for (i = len - 1; i >= 1; i -= 2) { 151 | var a = i - 1; 152 | var b = i; 153 | if (wndWidth[a] !== 1 || wndWidth[b] !== 1) { 154 | naf[a] = getNAF(coeffs[a], wndWidth[a], this._bitLength); 155 | naf[b] = getNAF(coeffs[b], wndWidth[b], this._bitLength); 156 | max = Math.max(naf[a].length, max); 157 | max = Math.max(naf[b].length, max); 158 | continue; 159 | } 160 | 161 | var comb = [ 162 | points[a], /* 1 */ 163 | null, /* 3 */ 164 | null, /* 5 */ 165 | points[b], /* 7 */ 166 | ]; 167 | 168 | // Try to avoid Projective points, if possible 169 | if (points[a].y.cmp(points[b].y) === 0) { 170 | comb[1] = points[a].add(points[b]); 171 | comb[2] = points[a].toJ().mixedAdd(points[b].neg()); 172 | } else if (points[a].y.cmp(points[b].y.redNeg()) === 0) { 173 | comb[1] = points[a].toJ().mixedAdd(points[b]); 174 | comb[2] = points[a].add(points[b].neg()); 175 | } else { 176 | comb[1] = points[a].toJ().mixedAdd(points[b]); 177 | comb[2] = points[a].toJ().mixedAdd(points[b].neg()); 178 | } 179 | 180 | var index = [ 181 | -3, /* -1 -1 */ 182 | -1, /* -1 0 */ 183 | -5, /* -1 1 */ 184 | -7, /* 0 -1 */ 185 | 0, /* 0 0 */ 186 | 7, /* 0 1 */ 187 | 5, /* 1 -1 */ 188 | 1, /* 1 0 */ 189 | 3, /* 1 1 */ 190 | ]; 191 | 192 | var jsf = getJSF(coeffs[a], coeffs[b]); 193 | max = Math.max(jsf[0].length, max); 194 | naf[a] = new Array(max); 195 | naf[b] = new Array(max); 196 | for (j = 0; j < max; j++) { 197 | var ja = jsf[0][j] | 0; 198 | var jb = jsf[1][j] | 0; 199 | 200 | naf[a][j] = index[(ja + 1) * 3 + (jb + 1)]; 201 | naf[b][j] = 0; 202 | wnd[a] = comb; 203 | } 204 | } 205 | 206 | var acc = this.jpoint(null, null, null); 207 | var tmp = this._wnafT4; 208 | for (i = max; i >= 0; i--) { 209 | var k = 0; 210 | 211 | while (i >= 0) { 212 | var zero = true; 213 | for (j = 0; j < len; j++) { 214 | tmp[j] = naf[j][i] | 0; 215 | if (tmp[j] !== 0) 216 | zero = false; 217 | } 218 | if (!zero) 219 | break; 220 | k++; 221 | i--; 222 | } 223 | if (i >= 0) 224 | k++; 225 | acc = acc.dblp(k); 226 | if (i < 0) 227 | break; 228 | 229 | for (j = 0; j < len; j++) { 230 | var z = tmp[j]; 231 | p; 232 | if (z === 0) 233 | continue; 234 | else if (z > 0) 235 | p = wnd[j][(z - 1) >> 1]; 236 | else if (z < 0) 237 | p = wnd[j][(-z - 1) >> 1].neg(); 238 | 239 | if (p.type === 'affine') 240 | acc = acc.mixedAdd(p); 241 | else 242 | acc = acc.add(p); 243 | } 244 | } 245 | // Zeroify references 246 | for (i = 0; i < len; i++) 247 | wnd[i] = null; 248 | 249 | if (jacobianResult) 250 | return acc; 251 | else 252 | return acc.toP(); 253 | }; 254 | 255 | function BasePoint(curve, type) { 256 | this.curve = curve; 257 | this.type = type; 258 | this.precomputed = null; 259 | } 260 | BaseCurve.BasePoint = BasePoint; 261 | 262 | BasePoint.prototype.eq = function eq(/*other*/) { 263 | throw new Error('Not implemented'); 264 | }; 265 | 266 | BasePoint.prototype.validate = function validate() { 267 | return this.curve.validate(this); 268 | }; 269 | 270 | BaseCurve.prototype.decodePoint = function decodePoint(bytes, enc) { 271 | bytes = utils.toArray(bytes, enc); 272 | 273 | var len = this.p.byteLength(); 274 | 275 | // uncompressed, hybrid-odd, hybrid-even 276 | if ((bytes[0] === 0x04 || bytes[0] === 0x06 || bytes[0] === 0x07) && 277 | bytes.length - 1 === 2 * len) { 278 | if (bytes[0] === 0x06) 279 | assert(bytes[bytes.length - 1] % 2 === 0); 280 | else if (bytes[0] === 0x07) 281 | assert(bytes[bytes.length - 1] % 2 === 1); 282 | 283 | var res = this.point(bytes.slice(1, 1 + len), 284 | bytes.slice(1 + len, 1 + 2 * len)); 285 | 286 | return res; 287 | } else if ((bytes[0] === 0x02 || bytes[0] === 0x03) && 288 | bytes.length - 1 === len) { 289 | return this.pointFromX(bytes.slice(1, 1 + len), bytes[0] === 0x03); 290 | } 291 | throw new Error('Unknown point format'); 292 | }; 293 | 294 | BasePoint.prototype.encodeCompressed = function encodeCompressed(enc) { 295 | return this.encode(enc, true); 296 | }; 297 | 298 | BasePoint.prototype._encode = function _encode(compact) { 299 | var len = this.curve.p.byteLength(); 300 | var x = this.getX().toArray('be', len); 301 | 302 | if (compact) 303 | return [ this.getY().isEven() ? 0x02 : 0x03 ].concat(x); 304 | 305 | return [ 0x04 ].concat(x, this.getY().toArray('be', len)); 306 | }; 307 | 308 | BasePoint.prototype.encode = function encode(enc, compact) { 309 | return utils.encode(this._encode(compact), enc); 310 | }; 311 | 312 | BasePoint.prototype.precompute = function precompute(power) { 313 | if (this.precomputed) 314 | return this; 315 | 316 | var precomputed = { 317 | doubles: null, 318 | naf: null, 319 | beta: null, 320 | }; 321 | precomputed.naf = this._getNAFPoints(8); 322 | precomputed.doubles = this._getDoubles(4, power); 323 | precomputed.beta = this._getBeta(); 324 | this.precomputed = precomputed; 325 | 326 | return this; 327 | }; 328 | 329 | BasePoint.prototype._hasDoubles = function _hasDoubles(k) { 330 | if (!this.precomputed) 331 | return false; 332 | 333 | var doubles = this.precomputed.doubles; 334 | if (!doubles) 335 | return false; 336 | 337 | return doubles.points.length >= Math.ceil((k.bitLength() + 1) / doubles.step); 338 | }; 339 | 340 | BasePoint.prototype._getDoubles = function _getDoubles(step, power) { 341 | if (this.precomputed && this.precomputed.doubles) 342 | return this.precomputed.doubles; 343 | 344 | var doubles = [ this ]; 345 | var acc = this; 346 | for (var i = 0; i < power; i += step) { 347 | for (var j = 0; j < step; j++) 348 | acc = acc.dbl(); 349 | doubles.push(acc); 350 | } 351 | return { 352 | step: step, 353 | points: doubles, 354 | }; 355 | }; 356 | 357 | BasePoint.prototype._getNAFPoints = function _getNAFPoints(wnd) { 358 | if (this.precomputed && this.precomputed.naf) 359 | return this.precomputed.naf; 360 | 361 | var res = [ this ]; 362 | var max = (1 << wnd) - 1; 363 | var dbl = max === 1 ? null : this.dbl(); 364 | for (var i = 1; i < max; i++) 365 | res[i] = res[i - 1].add(dbl); 366 | return { 367 | wnd: wnd, 368 | points: res, 369 | }; 370 | }; 371 | 372 | BasePoint.prototype._getBeta = function _getBeta() { 373 | return null; 374 | }; 375 | 376 | BasePoint.prototype.dblp = function dblp(k) { 377 | var r = this; 378 | for (var i = 0; i < k; i++) 379 | r = r.dbl(); 380 | return r; 381 | }; 382 | -------------------------------------------------------------------------------- /lib/elliptic/curve/edwards.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var utils = require('../utils'); 4 | var BN = require('bn.js'); 5 | var inherits = require('inherits'); 6 | var Base = require('./base'); 7 | 8 | var assert = utils.assert; 9 | 10 | function EdwardsCurve(conf) { 11 | // NOTE: Important as we are creating point in Base.call() 12 | this.twisted = (conf.a | 0) !== 1; 13 | this.mOneA = this.twisted && (conf.a | 0) === -1; 14 | this.extended = this.mOneA; 15 | 16 | Base.call(this, 'edwards', conf); 17 | 18 | this.a = new BN(conf.a, 16).umod(this.red.m); 19 | this.a = this.a.toRed(this.red); 20 | this.c = new BN(conf.c, 16).toRed(this.red); 21 | this.c2 = this.c.redSqr(); 22 | this.d = new BN(conf.d, 16).toRed(this.red); 23 | this.dd = this.d.redAdd(this.d); 24 | 25 | assert(!this.twisted || this.c.fromRed().cmpn(1) === 0); 26 | this.oneC = (conf.c | 0) === 1; 27 | } 28 | inherits(EdwardsCurve, Base); 29 | module.exports = EdwardsCurve; 30 | 31 | EdwardsCurve.prototype._mulA = function _mulA(num) { 32 | if (this.mOneA) 33 | return num.redNeg(); 34 | else 35 | return this.a.redMul(num); 36 | }; 37 | 38 | EdwardsCurve.prototype._mulC = function _mulC(num) { 39 | if (this.oneC) 40 | return num; 41 | else 42 | return this.c.redMul(num); 43 | }; 44 | 45 | // Just for compatibility with Short curve 46 | EdwardsCurve.prototype.jpoint = function jpoint(x, y, z, t) { 47 | return this.point(x, y, z, t); 48 | }; 49 | 50 | EdwardsCurve.prototype.pointFromX = function pointFromX(x, odd) { 51 | x = new BN(x, 16); 52 | if (!x.red) 53 | x = x.toRed(this.red); 54 | 55 | var x2 = x.redSqr(); 56 | var rhs = this.c2.redSub(this.a.redMul(x2)); 57 | var lhs = this.one.redSub(this.c2.redMul(this.d).redMul(x2)); 58 | 59 | var y2 = rhs.redMul(lhs.redInvm()); 60 | var y = y2.redSqrt(); 61 | if (y.redSqr().redSub(y2).cmp(this.zero) !== 0) 62 | throw new Error('invalid point'); 63 | 64 | var isOdd = y.fromRed().isOdd(); 65 | if (odd && !isOdd || !odd && isOdd) 66 | y = y.redNeg(); 67 | 68 | return this.point(x, y); 69 | }; 70 | 71 | EdwardsCurve.prototype.pointFromY = function pointFromY(y, odd) { 72 | y = new BN(y, 16); 73 | if (!y.red) 74 | y = y.toRed(this.red); 75 | 76 | // x^2 = (y^2 - c^2) / (c^2 d y^2 - a) 77 | var y2 = y.redSqr(); 78 | var lhs = y2.redSub(this.c2); 79 | var rhs = y2.redMul(this.d).redMul(this.c2).redSub(this.a); 80 | var x2 = lhs.redMul(rhs.redInvm()); 81 | 82 | if (x2.cmp(this.zero) === 0) { 83 | if (odd) 84 | throw new Error('invalid point'); 85 | else 86 | return this.point(this.zero, y); 87 | } 88 | 89 | var x = x2.redSqrt(); 90 | if (x.redSqr().redSub(x2).cmp(this.zero) !== 0) 91 | throw new Error('invalid point'); 92 | 93 | if (x.fromRed().isOdd() !== odd) 94 | x = x.redNeg(); 95 | 96 | return this.point(x, y); 97 | }; 98 | 99 | EdwardsCurve.prototype.validate = function validate(point) { 100 | if (point.isInfinity()) 101 | return true; 102 | 103 | // Curve: A * X^2 + Y^2 = C^2 * (1 + D * X^2 * Y^2) 104 | point.normalize(); 105 | 106 | var x2 = point.x.redSqr(); 107 | var y2 = point.y.redSqr(); 108 | var lhs = x2.redMul(this.a).redAdd(y2); 109 | var rhs = this.c2.redMul(this.one.redAdd(this.d.redMul(x2).redMul(y2))); 110 | 111 | return lhs.cmp(rhs) === 0; 112 | }; 113 | 114 | function Point(curve, x, y, z, t) { 115 | Base.BasePoint.call(this, curve, 'projective'); 116 | if (x === null && y === null && z === null) { 117 | this.x = this.curve.zero; 118 | this.y = this.curve.one; 119 | this.z = this.curve.one; 120 | this.t = this.curve.zero; 121 | this.zOne = true; 122 | } else { 123 | this.x = new BN(x, 16); 124 | this.y = new BN(y, 16); 125 | this.z = z ? new BN(z, 16) : this.curve.one; 126 | this.t = t && new BN(t, 16); 127 | if (!this.x.red) 128 | this.x = this.x.toRed(this.curve.red); 129 | if (!this.y.red) 130 | this.y = this.y.toRed(this.curve.red); 131 | if (!this.z.red) 132 | this.z = this.z.toRed(this.curve.red); 133 | if (this.t && !this.t.red) 134 | this.t = this.t.toRed(this.curve.red); 135 | this.zOne = this.z === this.curve.one; 136 | 137 | // Use extended coordinates 138 | if (this.curve.extended && !this.t) { 139 | this.t = this.x.redMul(this.y); 140 | if (!this.zOne) 141 | this.t = this.t.redMul(this.z.redInvm()); 142 | } 143 | } 144 | } 145 | inherits(Point, Base.BasePoint); 146 | 147 | EdwardsCurve.prototype.pointFromJSON = function pointFromJSON(obj) { 148 | return Point.fromJSON(this, obj); 149 | }; 150 | 151 | EdwardsCurve.prototype.point = function point(x, y, z, t) { 152 | return new Point(this, x, y, z, t); 153 | }; 154 | 155 | Point.fromJSON = function fromJSON(curve, obj) { 156 | return new Point(curve, obj[0], obj[1], obj[2]); 157 | }; 158 | 159 | Point.prototype.inspect = function inspect() { 160 | if (this.isInfinity()) 161 | return ''; 162 | return ''; 165 | }; 166 | 167 | Point.prototype.isInfinity = function isInfinity() { 168 | // XXX This code assumes that zero is always zero in red 169 | return this.x.cmpn(0) === 0 && 170 | (this.y.cmp(this.z) === 0 || 171 | (this.zOne && this.y.cmp(this.curve.c) === 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 | var e; 225 | var h; 226 | var j; 227 | if (this.curve.twisted) { 228 | // E = a * C 229 | e = this.curve._mulA(c); 230 | // F = E + D 231 | var f = e.redAdd(d); 232 | if (this.zOne) { 233 | // X3 = (B - C - D) * (F - 2) 234 | nx = b.redSub(c).redSub(d).redMul(f.redSub(this.curve.two)); 235 | // Y3 = F * (E - D) 236 | ny = f.redMul(e.redSub(d)); 237 | // Z3 = F^2 - 2 * F 238 | nz = f.redSqr().redSub(f).redSub(f); 239 | } else { 240 | // H = Z1^2 241 | h = this.z.redSqr(); 242 | // J = F - 2 * H 243 | j = f.redSub(h).redISub(h); 244 | // X3 = (B-C-D)*J 245 | nx = b.redSub(c).redISub(d).redMul(j); 246 | // Y3 = F * (E - D) 247 | ny = f.redMul(e.redSub(d)); 248 | // Z3 = F * J 249 | nz = f.redMul(j); 250 | } 251 | } else { 252 | // E = C + D 253 | e = c.redAdd(d); 254 | // H = (c * Z1)^2 255 | h = this.curve._mulC(this.z).redSqr(); 256 | // J = E - 2 * H 257 | j = e.redSub(h).redSub(h); 258 | // X3 = c * (B - E) * J 259 | nx = this.curve._mulC(b.redISub(e)).redMul(j); 260 | // Y3 = c * E * (C - D) 261 | ny = this.curve._mulC(e).redMul(c.redISub(d)); 262 | // Z3 = E * J 263 | nz = e.redMul(j); 264 | } 265 | return this.curve.point(nx, ny, nz); 266 | }; 267 | 268 | Point.prototype.dbl = function dbl() { 269 | if (this.isInfinity()) 270 | return this; 271 | 272 | // Double in extended coordinates 273 | if (this.curve.extended) 274 | return this._extDbl(); 275 | else 276 | return this._projDbl(); 277 | }; 278 | 279 | Point.prototype._extAdd = function _extAdd(p) { 280 | // hyperelliptic.org/EFD/g1p/auto-twisted-extended-1.html 281 | // #addition-add-2008-hwcd-3 282 | // 8M 283 | 284 | // A = (Y1 - X1) * (Y2 - X2) 285 | var a = this.y.redSub(this.x).redMul(p.y.redSub(p.x)); 286 | // B = (Y1 + X1) * (Y2 + X2) 287 | var b = this.y.redAdd(this.x).redMul(p.y.redAdd(p.x)); 288 | // C = T1 * k * T2 289 | var c = this.t.redMul(this.curve.dd).redMul(p.t); 290 | // D = Z1 * 2 * Z2 291 | var d = this.z.redMul(p.z.redAdd(p.z)); 292 | // E = B - A 293 | var e = b.redSub(a); 294 | // F = D - C 295 | var f = d.redSub(c); 296 | // G = D + C 297 | var g = d.redAdd(c); 298 | // H = B + A 299 | var h = b.redAdd(a); 300 | // X3 = E * F 301 | var nx = e.redMul(f); 302 | // Y3 = G * H 303 | var ny = g.redMul(h); 304 | // T3 = E * H 305 | var nt = e.redMul(h); 306 | // Z3 = F * G 307 | var nz = f.redMul(g); 308 | return this.curve.point(nx, ny, nz, nt); 309 | }; 310 | 311 | Point.prototype._projAdd = function _projAdd(p) { 312 | // hyperelliptic.org/EFD/g1p/auto-twisted-projective.html 313 | // #addition-add-2008-bbjlp 314 | // #addition-add-2007-bl 315 | // 10M + 1S 316 | 317 | // A = Z1 * Z2 318 | var a = this.z.redMul(p.z); 319 | // B = A^2 320 | var b = a.redSqr(); 321 | // C = X1 * X2 322 | var c = this.x.redMul(p.x); 323 | // D = Y1 * Y2 324 | var d = this.y.redMul(p.y); 325 | // E = d * C * D 326 | var e = this.curve.d.redMul(c).redMul(d); 327 | // F = B - E 328 | var f = b.redSub(e); 329 | // G = B + E 330 | var g = b.redAdd(e); 331 | // X3 = A * F * ((X1 + Y1) * (X2 + Y2) - C - D) 332 | var tmp = this.x.redAdd(this.y).redMul(p.x.redAdd(p.y)).redISub(c).redISub(d); 333 | var nx = a.redMul(f).redMul(tmp); 334 | var ny; 335 | var nz; 336 | if (this.curve.twisted) { 337 | // Y3 = A * G * (D - a * C) 338 | ny = a.redMul(g).redMul(d.redSub(this.curve._mulA(c))); 339 | // Z3 = F * G 340 | nz = f.redMul(g); 341 | } else { 342 | // Y3 = A * G * (D - C) 343 | ny = a.redMul(g).redMul(d.redSub(c)); 344 | // Z3 = c * F * G 345 | nz = this.curve._mulC(f).redMul(g); 346 | } 347 | return this.curve.point(nx, ny, nz); 348 | }; 349 | 350 | Point.prototype.add = function add(p) { 351 | if (this.isInfinity()) 352 | return p; 353 | if (p.isInfinity()) 354 | return this; 355 | 356 | if (this.curve.extended) 357 | return this._extAdd(p); 358 | else 359 | return this._projAdd(p); 360 | }; 361 | 362 | Point.prototype.mul = function mul(k) { 363 | if (this._hasDoubles(k)) 364 | return this.curve._fixedNafMul(this, k); 365 | else 366 | return this.curve._wnafMul(this, k); 367 | }; 368 | 369 | Point.prototype.mulAdd = function mulAdd(k1, p, k2) { 370 | return this.curve._wnafMulAdd(1, [ this, p ], [ k1, k2 ], 2, false); 371 | }; 372 | 373 | Point.prototype.jmulAdd = function jmulAdd(k1, p, k2) { 374 | return this.curve._wnafMulAdd(1, [ this, p ], [ k1, k2 ], 2, true); 375 | }; 376 | 377 | Point.prototype.normalize = function normalize() { 378 | if (this.zOne) 379 | return this; 380 | 381 | // Normalize coordinates 382 | var zi = this.z.redInvm(); 383 | this.x = this.x.redMul(zi); 384 | this.y = this.y.redMul(zi); 385 | if (this.t) 386 | this.t = this.t.redMul(zi); 387 | this.z = this.curve.one; 388 | this.zOne = true; 389 | return this; 390 | }; 391 | 392 | Point.prototype.neg = function neg() { 393 | return this.curve.point(this.x.redNeg(), 394 | this.y, 395 | this.z, 396 | this.t && this.t.redNeg()); 397 | }; 398 | 399 | Point.prototype.getX = function getX() { 400 | this.normalize(); 401 | return this.x.fromRed(); 402 | }; 403 | 404 | Point.prototype.getY = function getY() { 405 | this.normalize(); 406 | return this.y.fromRed(); 407 | }; 408 | 409 | Point.prototype.eq = function eq(other) { 410 | return this === other || 411 | this.getX().cmp(other.getX()) === 0 && 412 | this.getY().cmp(other.getY()) === 0; 413 | }; 414 | 415 | Point.prototype.eqXToP = function eqXToP(x) { 416 | var rx = x.toRed(this.curve.red).redMul(this.z); 417 | if (this.x.cmp(rx) === 0) 418 | return true; 419 | 420 | var xc = x.clone(); 421 | var t = this.curve.redN.redMul(this.z); 422 | for (;;) { 423 | xc.iadd(this.curve.n); 424 | if (xc.cmp(this.curve.p) >= 0) 425 | return false; 426 | 427 | rx.redIAdd(t); 428 | if (this.x.cmp(rx) === 0) 429 | return true; 430 | } 431 | }; 432 | 433 | // Compatibility with BaseCurve 434 | Point.prototype.toP = Point.prototype.normalize; 435 | Point.prototype.mixedAdd = Point.prototype.add; 436 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /lib/elliptic/curve/mont.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var BN = require('bn.js'); 4 | var inherits = require('inherits'); 5 | var Base = require('./base'); 6 | 7 | var utils = require('../utils'); 8 | 9 | function MontCurve(conf) { 10 | Base.call(this, 'mont', conf); 11 | 12 | this.a = new BN(conf.a, 16).toRed(this.red); 13 | this.b = new BN(conf.b, 16).toRed(this.red); 14 | this.i4 = new BN(4).toRed(this.red).redInvm(); 15 | this.two = new BN(2).toRed(this.red); 16 | this.a24 = this.i4.redMul(this.a.redAdd(this.two)); 17 | } 18 | inherits(MontCurve, Base); 19 | module.exports = MontCurve; 20 | 21 | MontCurve.prototype.validate = function validate(point) { 22 | var x = point.normalize().x; 23 | var x2 = x.redSqr(); 24 | var rhs = x2.redMul(x).redAdd(x2.redMul(this.a)).redAdd(x); 25 | var y = rhs.redSqrt(); 26 | 27 | return y.redSqr().cmp(rhs) === 0; 28 | }; 29 | 30 | function Point(curve, x, z) { 31 | Base.BasePoint.call(this, curve, 'projective'); 32 | if (x === null && z === null) { 33 | this.x = this.curve.one; 34 | this.z = this.curve.zero; 35 | } else { 36 | this.x = new BN(x, 16); 37 | this.z = new BN(z, 16); 38 | if (!this.x.red) 39 | this.x = this.x.toRed(this.curve.red); 40 | if (!this.z.red) 41 | this.z = this.z.toRed(this.curve.red); 42 | } 43 | } 44 | inherits(Point, Base.BasePoint); 45 | 46 | MontCurve.prototype.decodePoint = function decodePoint(bytes, enc) { 47 | return this.point(utils.toArray(bytes, enc), 1); 48 | }; 49 | 50 | MontCurve.prototype.point = function point(x, z) { 51 | return new Point(this, x, z); 52 | }; 53 | 54 | MontCurve.prototype.pointFromJSON = function pointFromJSON(obj) { 55 | return Point.fromJSON(this, obj); 56 | }; 57 | 58 | Point.prototype.precompute = function precompute() { 59 | // No-op 60 | }; 61 | 62 | Point.prototype._encode = function _encode() { 63 | return this.getX().toArray('be', this.curve.p.byteLength()); 64 | }; 65 | 66 | Point.fromJSON = function fromJSON(curve, obj) { 67 | return new Point(curve, obj[0], obj[1] || curve.one); 68 | }; 69 | 70 | Point.prototype.inspect = function inspect() { 71 | if (this.isInfinity()) 72 | return ''; 73 | return ''; 75 | }; 76 | 77 | Point.prototype.isInfinity = function isInfinity() { 78 | // XXX This code assumes that zero is always zero in red 79 | return this.z.cmpn(0) === 0; 80 | }; 81 | 82 | Point.prototype.dbl = function dbl() { 83 | // http://hyperelliptic.org/EFD/g1p/auto-montgom-xz.html#doubling-dbl-1987-m-3 84 | // 2M + 2S + 4A 85 | 86 | // A = X1 + Z1 87 | var a = this.x.redAdd(this.z); 88 | // AA = A^2 89 | var aa = a.redSqr(); 90 | // B = X1 - Z1 91 | var b = this.x.redSub(this.z); 92 | // BB = B^2 93 | var bb = b.redSqr(); 94 | // C = AA - BB 95 | var c = aa.redSub(bb); 96 | // X3 = AA * BB 97 | var nx = aa.redMul(bb); 98 | // Z3 = C * (BB + A24 * C) 99 | var nz = c.redMul(bb.redAdd(this.curve.a24.redMul(c))); 100 | return this.curve.point(nx, nz); 101 | }; 102 | 103 | Point.prototype.add = function add() { 104 | throw new Error('Not supported on Montgomery curve'); 105 | }; 106 | 107 | Point.prototype.diffAdd = function diffAdd(p, diff) { 108 | // http://hyperelliptic.org/EFD/g1p/auto-montgom-xz.html#diffadd-dadd-1987-m-3 109 | // 4M + 2S + 6A 110 | 111 | // A = X2 + Z2 112 | var a = this.x.redAdd(this.z); 113 | // B = X2 - Z2 114 | var b = this.x.redSub(this.z); 115 | // C = X3 + Z3 116 | var c = p.x.redAdd(p.z); 117 | // D = X3 - Z3 118 | var d = p.x.redSub(p.z); 119 | // DA = D * A 120 | var da = d.redMul(a); 121 | // CB = C * B 122 | var cb = c.redMul(b); 123 | // X5 = Z1 * (DA + CB)^2 124 | var nx = diff.z.redMul(da.redAdd(cb).redSqr()); 125 | // Z5 = X1 * (DA - CB)^2 126 | var nz = diff.x.redMul(da.redISub(cb).redSqr()); 127 | return this.curve.point(nx, nz); 128 | }; 129 | 130 | Point.prototype.mul = function mul(k) { 131 | var t = k.clone(); 132 | var a = this; // (N / 2) * Q + Q 133 | var b = this.curve.point(null, null); // (N / 2) * Q 134 | var c = this; // Q 135 | 136 | for (var bits = []; t.cmpn(0) !== 0; t.iushrn(1)) 137 | bits.push(t.andln(1)); 138 | 139 | for (var i = bits.length - 1; i >= 0; i--) { 140 | if (bits[i] === 0) { 141 | // N * Q + Q = ((N / 2) * Q + Q)) + (N / 2) * Q 142 | a = a.diffAdd(b, c); 143 | // N * Q = 2 * ((N / 2) * Q + Q)) 144 | b = b.dbl(); 145 | } else { 146 | // N * Q = ((N / 2) * Q + Q) + ((N / 2) * Q) 147 | b = a.diffAdd(b, c); 148 | // N * Q + Q = 2 * ((N / 2) * Q + Q) 149 | a = a.dbl(); 150 | } 151 | } 152 | return b; 153 | }; 154 | 155 | Point.prototype.mulAdd = function mulAdd() { 156 | throw new Error('Not supported on Montgomery curve'); 157 | }; 158 | 159 | Point.prototype.jumlAdd = function jumlAdd() { 160 | throw new Error('Not supported on Montgomery curve'); 161 | }; 162 | 163 | Point.prototype.eq = function eq(other) { 164 | return this.getX().cmp(other.getX()) === 0; 165 | }; 166 | 167 | Point.prototype.normalize = function normalize() { 168 | this.x = this.x.redMul(this.z.redInvm()); 169 | this.z = this.curve.one; 170 | return this; 171 | }; 172 | 173 | Point.prototype.getX = function getX() { 174 | // Normalize coordinates 175 | this.normalize(); 176 | 177 | return this.x.fromRed(); 178 | }; 179 | -------------------------------------------------------------------------------- /lib/elliptic/curve/short.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var utils = require('../utils'); 4 | var BN = require('bn.js'); 5 | var inherits = require('inherits'); 6 | var Base = require('./base'); 7 | 8 | var assert = utils.assert; 9 | 10 | function ShortCurve(conf) { 11 | Base.call(this, 'short', conf); 12 | 13 | this.a = new BN(conf.a, 16).toRed(this.red); 14 | this.b = new BN(conf.b, 16).toRed(this.red); 15 | this.tinv = this.two.redInvm(); 16 | 17 | this.zeroA = this.a.fromRed().cmpn(0) === 0; 18 | this.threeA = this.a.fromRed().sub(this.p).cmpn(-3) === 0; 19 | 20 | // If the curve is endomorphic, precalculate beta and lambda 21 | this.endo = this._getEndomorphism(conf); 22 | this._endoWnafT1 = new Array(4); 23 | this._endoWnafT2 = new Array(4); 24 | } 25 | inherits(ShortCurve, Base); 26 | module.exports = ShortCurve; 27 | 28 | ShortCurve.prototype._getEndomorphism = function _getEndomorphism(conf) { 29 | // No efficient endomorphism 30 | if (!this.zeroA || !this.g || !this.n || this.p.modn(3) !== 1) 31 | return; 32 | 33 | // Compute beta and lambda, that lambda * P = (beta * Px; Py) 34 | var beta; 35 | var lambda; 36 | if (conf.beta) { 37 | beta = new BN(conf.beta, 16).toRed(this.red); 38 | } else { 39 | var betas = this._getEndoRoots(this.p); 40 | // Choose the smallest beta 41 | beta = betas[0].cmp(betas[1]) < 0 ? betas[0] : betas[1]; 42 | beta = beta.toRed(this.red); 43 | } 44 | if (conf.lambda) { 45 | lambda = new BN(conf.lambda, 16); 46 | } else { 47 | // Choose the lambda that is matching selected beta 48 | var lambdas = this._getEndoRoots(this.n); 49 | if (this.g.mul(lambdas[0]).x.cmp(this.g.x.redMul(beta)) === 0) { 50 | lambda = lambdas[0]; 51 | } else { 52 | lambda = lambdas[1]; 53 | assert(this.g.mul(lambda).x.cmp(this.g.x.redMul(beta)) === 0); 54 | } 55 | } 56 | 57 | // Get basis vectors, used for balanced length-two representation 58 | var basis; 59 | if (conf.basis) { 60 | basis = conf.basis.map(function(vec) { 61 | return { 62 | a: new BN(vec.a, 16), 63 | b: new BN(vec.b, 16), 64 | }; 65 | }); 66 | } else { 67 | basis = this._getEndoBasis(lambda); 68 | } 69 | 70 | return { 71 | beta: beta, 72 | lambda: lambda, 73 | basis: basis, 74 | }; 75 | }; 76 | 77 | ShortCurve.prototype._getEndoRoots = function _getEndoRoots(num) { 78 | // Find roots of for x^2 + x + 1 in F 79 | // Root = (-1 +- Sqrt(-3)) / 2 80 | // 81 | var red = num === this.p ? this.red : BN.mont(num); 82 | var tinv = new BN(2).toRed(red).redInvm(); 83 | var ntinv = tinv.redNeg(); 84 | 85 | var s = new BN(3).toRed(red).redNeg().redSqrt().redMul(tinv); 86 | 87 | var l1 = ntinv.redAdd(s).fromRed(); 88 | var l2 = ntinv.redSub(s).fromRed(); 89 | return [ l1, l2 ]; 90 | }; 91 | 92 | ShortCurve.prototype._getEndoBasis = function _getEndoBasis(lambda) { 93 | // aprxSqrt >= sqrt(this.n) 94 | var aprxSqrt = this.n.ushrn(Math.floor(this.n.bitLength() / 2)); 95 | 96 | // 3.74 97 | // Run EGCD, until r(L + 1) < aprxSqrt 98 | var u = lambda; 99 | var v = this.n.clone(); 100 | var x1 = new BN(1); 101 | var y1 = new BN(0); 102 | var x2 = new BN(0); 103 | var y2 = new BN(1); 104 | 105 | // NOTE: all vectors are roots of: a + b * lambda = 0 (mod n) 106 | var a0; 107 | var b0; 108 | // First vector 109 | var a1; 110 | var b1; 111 | // Second vector 112 | var a2; 113 | var b2; 114 | 115 | var prevR; 116 | var i = 0; 117 | var r; 118 | var x; 119 | while (u.cmpn(0) !== 0) { 120 | var q = v.div(u); 121 | r = v.sub(q.mul(u)); 122 | x = x2.sub(q.mul(x1)); 123 | var y = y2.sub(q.mul(y1)); 124 | 125 | if (!a1 && r.cmp(aprxSqrt) < 0) { 126 | a0 = prevR.neg(); 127 | b0 = x1; 128 | a1 = r.neg(); 129 | b1 = x; 130 | } else if (a1 && ++i === 2) { 131 | break; 132 | } 133 | prevR = r; 134 | 135 | v = u; 136 | u = r; 137 | x2 = x1; 138 | x1 = x; 139 | y2 = y1; 140 | y1 = y; 141 | } 142 | a2 = r.neg(); 143 | b2 = x; 144 | 145 | var len1 = a1.sqr().add(b1.sqr()); 146 | var len2 = a2.sqr().add(b2.sqr()); 147 | if (len2.cmp(len1) >= 0) { 148 | a2 = a0; 149 | b2 = b0; 150 | } 151 | 152 | // Normalize signs 153 | if (a1.negative) { 154 | a1 = a1.neg(); 155 | b1 = b1.neg(); 156 | } 157 | if (a2.negative) { 158 | a2 = a2.neg(); 159 | b2 = b2.neg(); 160 | } 161 | 162 | return [ 163 | { a: a1, b: b1 }, 164 | { a: a2, b: b2 }, 165 | ]; 166 | }; 167 | 168 | ShortCurve.prototype._endoSplit = function _endoSplit(k) { 169 | var basis = this.endo.basis; 170 | var v1 = basis[0]; 171 | var v2 = basis[1]; 172 | 173 | var c1 = v2.b.mul(k).divRound(this.n); 174 | var c2 = v1.b.neg().mul(k).divRound(this.n); 175 | 176 | var p1 = c1.mul(v1.a); 177 | var p2 = c2.mul(v2.a); 178 | var q1 = c1.mul(v1.b); 179 | var q2 = c2.mul(v2.b); 180 | 181 | // Calculate answer 182 | var k1 = k.sub(p1).sub(p2); 183 | var k2 = q1.add(q2).neg(); 184 | return { k1: k1, k2: k2 }; 185 | }; 186 | 187 | ShortCurve.prototype.pointFromX = function pointFromX(x, odd) { 188 | x = new BN(x, 16); 189 | if (!x.red) 190 | x = x.toRed(this.red); 191 | 192 | var y2 = x.redSqr().redMul(x).redIAdd(x.redMul(this.a)).redIAdd(this.b); 193 | var y = y2.redSqrt(); 194 | if (y.redSqr().redSub(y2).cmp(this.zero) !== 0) 195 | throw new Error('invalid point'); 196 | 197 | // XXX Is there any way to tell if the number is odd without converting it 198 | // to non-red form? 199 | var isOdd = y.fromRed().isOdd(); 200 | if (odd && !isOdd || !odd && isOdd) 201 | y = y.redNeg(); 202 | 203 | return this.point(x, y); 204 | }; 205 | 206 | ShortCurve.prototype.validate = function validate(point) { 207 | if (point.inf) 208 | return true; 209 | 210 | var x = point.x; 211 | var y = point.y; 212 | 213 | var ax = this.a.redMul(x); 214 | var rhs = x.redSqr().redMul(x).redIAdd(ax).redIAdd(this.b); 215 | return y.redSqr().redISub(rhs).cmpn(0) === 0; 216 | }; 217 | 218 | ShortCurve.prototype._endoWnafMulAdd = 219 | function _endoWnafMulAdd(points, coeffs, jacobianResult) { 220 | var npoints = this._endoWnafT1; 221 | var ncoeffs = this._endoWnafT2; 222 | for (var i = 0; i < points.length; i++) { 223 | var split = this._endoSplit(coeffs[i]); 224 | var p = points[i]; 225 | var beta = p._getBeta(); 226 | 227 | if (split.k1.negative) { 228 | split.k1.ineg(); 229 | p = p.neg(true); 230 | } 231 | if (split.k2.negative) { 232 | split.k2.ineg(); 233 | beta = beta.neg(true); 234 | } 235 | 236 | npoints[i * 2] = p; 237 | npoints[i * 2 + 1] = beta; 238 | ncoeffs[i * 2] = split.k1; 239 | ncoeffs[i * 2 + 1] = split.k2; 240 | } 241 | var res = this._wnafMulAdd(1, npoints, ncoeffs, i * 2, jacobianResult); 242 | 243 | // Clean-up references to points and coefficients 244 | for (var j = 0; j < i * 2; j++) { 245 | npoints[j] = null; 246 | ncoeffs[j] = null; 247 | } 248 | return res; 249 | }; 250 | 251 | function Point(curve, x, y, isRed) { 252 | Base.BasePoint.call(this, curve, 'affine'); 253 | if (x === null && y === null) { 254 | this.x = null; 255 | this.y = null; 256 | this.inf = true; 257 | } else { 258 | this.x = new BN(x, 16); 259 | this.y = new BN(y, 16); 260 | // Force redgomery representation when loading from JSON 261 | if (isRed) { 262 | this.x.forceRed(this.curve.red); 263 | this.y.forceRed(this.curve.red); 264 | } 265 | if (!this.x.red) 266 | this.x = this.x.toRed(this.curve.red); 267 | if (!this.y.red) 268 | this.y = this.y.toRed(this.curve.red); 269 | this.inf = false; 270 | } 271 | } 272 | inherits(Point, Base.BasePoint); 273 | 274 | ShortCurve.prototype.point = function point(x, y, isRed) { 275 | return new Point(this, x, y, isRed); 276 | }; 277 | 278 | ShortCurve.prototype.pointFromJSON = function pointFromJSON(obj, red) { 279 | return Point.fromJSON(this, obj, red); 280 | }; 281 | 282 | Point.prototype._getBeta = function _getBeta() { 283 | if (!this.curve.endo) 284 | return; 285 | 286 | var pre = this.precomputed; 287 | if (pre && pre.beta) 288 | return pre.beta; 289 | 290 | var beta = this.curve.point(this.x.redMul(this.curve.endo.beta), this.y); 291 | if (pre) { 292 | var curve = this.curve; 293 | var endoMul = function(p) { 294 | return curve.point(p.x.redMul(curve.endo.beta), p.y); 295 | }; 296 | pre.beta = beta; 297 | beta.precomputed = { 298 | beta: null, 299 | naf: pre.naf && { 300 | wnd: pre.naf.wnd, 301 | points: pre.naf.points.map(endoMul), 302 | }, 303 | doubles: pre.doubles && { 304 | step: pre.doubles.step, 305 | points: pre.doubles.points.map(endoMul), 306 | }, 307 | }; 308 | } 309 | return beta; 310 | }; 311 | 312 | Point.prototype.toJSON = function toJSON() { 313 | if (!this.precomputed) 314 | return [ this.x, this.y ]; 315 | 316 | return [ this.x, this.y, this.precomputed && { 317 | doubles: this.precomputed.doubles && { 318 | step: this.precomputed.doubles.step, 319 | points: this.precomputed.doubles.points.slice(1), 320 | }, 321 | naf: this.precomputed.naf && { 322 | wnd: this.precomputed.naf.wnd, 323 | points: this.precomputed.naf.points.slice(1), 324 | }, 325 | } ]; 326 | }; 327 | 328 | Point.fromJSON = function fromJSON(curve, obj, red) { 329 | if (typeof obj === 'string') 330 | obj = JSON.parse(obj); 331 | var res = curve.point(obj[0], obj[1], red); 332 | if (!obj[2]) 333 | return res; 334 | 335 | function obj2point(obj) { 336 | return curve.point(obj[0], obj[1], red); 337 | } 338 | 339 | var pre = obj[2]; 340 | res.precomputed = { 341 | beta: null, 342 | doubles: pre.doubles && { 343 | step: pre.doubles.step, 344 | points: [ res ].concat(pre.doubles.points.map(obj2point)), 345 | }, 346 | naf: pre.naf && { 347 | wnd: pre.naf.wnd, 348 | points: [ res ].concat(pre.naf.points.map(obj2point)), 349 | }, 350 | }; 351 | return res; 352 | }; 353 | 354 | Point.prototype.inspect = function inspect() { 355 | if (this.isInfinity()) 356 | return ''; 357 | return ''; 359 | }; 360 | 361 | Point.prototype.isInfinity = function isInfinity() { 362 | return this.inf; 363 | }; 364 | 365 | Point.prototype.add = function add(p) { 366 | // O + P = P 367 | if (this.inf) 368 | return p; 369 | 370 | // P + O = P 371 | if (p.inf) 372 | return this; 373 | 374 | // P + P = 2P 375 | if (this.eq(p)) 376 | return this.dbl(); 377 | 378 | // P + (-P) = O 379 | if (this.neg().eq(p)) 380 | return this.curve.point(null, null); 381 | 382 | // P + Q = O 383 | if (this.x.cmp(p.x) === 0) 384 | return this.curve.point(null, null); 385 | 386 | var c = this.y.redSub(p.y); 387 | if (c.cmpn(0) !== 0) 388 | c = c.redMul(this.x.redSub(p.x).redInvm()); 389 | var nx = c.redSqr().redISub(this.x).redISub(p.x); 390 | var ny = c.redMul(this.x.redSub(nx)).redISub(this.y); 391 | return this.curve.point(nx, ny); 392 | }; 393 | 394 | Point.prototype.dbl = function dbl() { 395 | if (this.inf) 396 | return this; 397 | 398 | // 2P = O 399 | var ys1 = this.y.redAdd(this.y); 400 | if (ys1.cmpn(0) === 0) 401 | return this.curve.point(null, null); 402 | 403 | var a = this.curve.a; 404 | 405 | var x2 = this.x.redSqr(); 406 | var dyinv = ys1.redInvm(); 407 | var c = x2.redAdd(x2).redIAdd(x2).redIAdd(a).redMul(dyinv); 408 | 409 | var nx = c.redSqr().redISub(this.x.redAdd(this.x)); 410 | var ny = c.redMul(this.x.redSub(nx)).redISub(this.y); 411 | return this.curve.point(nx, ny); 412 | }; 413 | 414 | Point.prototype.getX = function getX() { 415 | return this.x.fromRed(); 416 | }; 417 | 418 | Point.prototype.getY = function getY() { 419 | return this.y.fromRed(); 420 | }; 421 | 422 | Point.prototype.mul = function mul(k) { 423 | k = new BN(k, 16); 424 | if (this.isInfinity()) 425 | return this; 426 | else 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 | var i; 614 | if (this.curve.zeroA || this.curve.threeA) { 615 | var r = this; 616 | for (i = 0; i < pow; i++) 617 | r = r.dbl(); 618 | return r; 619 | } 620 | 621 | // 1M + 2S + 1A + N * (4S + 5M + 8A) 622 | // N = 1 => 6M + 6S + 9A 623 | var a = this.curve.a; 624 | var tinv = this.curve.tinv; 625 | 626 | var jx = this.x; 627 | var jy = this.y; 628 | var jz = this.z; 629 | var jz4 = jz.redSqr().redSqr(); 630 | 631 | // Reuse results 632 | var jyd = jy.redAdd(jy); 633 | for (i = 0; i < pow; i++) { 634 | var jx2 = jx.redSqr(); 635 | var jyd2 = jyd.redSqr(); 636 | var jyd4 = jyd2.redSqr(); 637 | var c = jx2.redAdd(jx2).redIAdd(jx2).redIAdd(a.redMul(jz4)); 638 | 639 | var t1 = jx.redMul(jyd2); 640 | var nx = c.redSqr().redISub(t1.redAdd(t1)); 641 | var t2 = t1.redISub(nx); 642 | var dny = c.redMul(t2); 643 | dny = dny.redIAdd(dny).redISub(jyd4); 644 | var nz = jyd.redMul(jz); 645 | if (i + 1 < pow) 646 | jz4 = jz4.redMul(jyd4); 647 | 648 | jx = nx; 649 | jz = nz; 650 | jyd = dny; 651 | } 652 | 653 | return this.curve.jpoint(jx, jyd.redMul(tinv), jz); 654 | }; 655 | 656 | JPoint.prototype.dbl = function dbl() { 657 | if (this.isInfinity()) 658 | return this; 659 | 660 | if (this.curve.zeroA) 661 | return this._zeroDbl(); 662 | else if (this.curve.threeA) 663 | return this._threeDbl(); 664 | else 665 | return this._dbl(); 666 | }; 667 | 668 | JPoint.prototype._zeroDbl = function _zeroDbl() { 669 | var nx; 670 | var ny; 671 | var nz; 672 | // Z = 1 673 | if (this.zOne) { 674 | // hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html 675 | // #doubling-mdbl-2007-bl 676 | // 1M + 5S + 14A 677 | 678 | // XX = X1^2 679 | var xx = this.x.redSqr(); 680 | // YY = Y1^2 681 | var yy = this.y.redSqr(); 682 | // YYYY = YY^2 683 | var yyyy = yy.redSqr(); 684 | // S = 2 * ((X1 + YY)^2 - XX - YYYY) 685 | var s = this.x.redAdd(yy).redSqr().redISub(xx).redISub(yyyy); 686 | s = s.redIAdd(s); 687 | // M = 3 * XX + a; a = 0 688 | var m = xx.redAdd(xx).redIAdd(xx); 689 | // T = M ^ 2 - 2*S 690 | var t = m.redSqr().redISub(s).redISub(s); 691 | 692 | // 8 * YYYY 693 | var yyyy8 = yyyy.redIAdd(yyyy); 694 | yyyy8 = yyyy8.redIAdd(yyyy8); 695 | yyyy8 = yyyy8.redIAdd(yyyy8); 696 | 697 | // X3 = T 698 | nx = t; 699 | // Y3 = M * (S - T) - 8 * YYYY 700 | ny = m.redMul(s.redISub(t)).redISub(yyyy8); 701 | // Z3 = 2*Y1 702 | nz = this.y.redAdd(this.y); 703 | } else { 704 | // hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html 705 | // #doubling-dbl-2009-l 706 | // 2M + 5S + 13A 707 | 708 | // A = X1^2 709 | var a = this.x.redSqr(); 710 | // B = Y1^2 711 | var b = this.y.redSqr(); 712 | // C = B^2 713 | var c = b.redSqr(); 714 | // D = 2 * ((X1 + B)^2 - A - C) 715 | var d = this.x.redAdd(b).redSqr().redISub(a).redISub(c); 716 | d = d.redIAdd(d); 717 | // E = 3 * A 718 | var e = a.redAdd(a).redIAdd(a); 719 | // F = E^2 720 | var f = e.redSqr(); 721 | 722 | // 8 * C 723 | var c8 = c.redIAdd(c); 724 | c8 = c8.redIAdd(c8); 725 | c8 = c8.redIAdd(c8); 726 | 727 | // X3 = F - 2 * D 728 | nx = f.redISub(d).redISub(d); 729 | // Y3 = E * (D - X3) - 8 * C 730 | ny = e.redMul(d.redISub(nx)).redISub(c8); 731 | // Z3 = 2 * Y1 * Z1 732 | nz = this.y.redMul(this.z); 733 | nz = nz.redIAdd(nz); 734 | } 735 | 736 | return this.curve.jpoint(nx, ny, nz); 737 | }; 738 | 739 | JPoint.prototype._threeDbl = function _threeDbl() { 740 | var nx; 741 | var ny; 742 | var nz; 743 | // Z = 1 744 | if (this.zOne) { 745 | // hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-3.html 746 | // #doubling-mdbl-2007-bl 747 | // 1M + 5S + 15A 748 | 749 | // XX = X1^2 750 | var xx = this.x.redSqr(); 751 | // YY = Y1^2 752 | var yy = this.y.redSqr(); 753 | // YYYY = YY^2 754 | var yyyy = yy.redSqr(); 755 | // S = 2 * ((X1 + YY)^2 - XX - YYYY) 756 | var s = this.x.redAdd(yy).redSqr().redISub(xx).redISub(yyyy); 757 | s = s.redIAdd(s); 758 | // M = 3 * XX + a 759 | var m = xx.redAdd(xx).redIAdd(xx).redIAdd(this.curve.a); 760 | // T = M^2 - 2 * S 761 | var t = m.redSqr().redISub(s).redISub(s); 762 | // X3 = T 763 | nx = t; 764 | // Y3 = M * (S - T) - 8 * YYYY 765 | var yyyy8 = yyyy.redIAdd(yyyy); 766 | yyyy8 = yyyy8.redIAdd(yyyy8); 767 | yyyy8 = yyyy8.redIAdd(yyyy8); 768 | ny = m.redMul(s.redISub(t)).redISub(yyyy8); 769 | // Z3 = 2 * Y1 770 | nz = this.y.redAdd(this.y); 771 | } else { 772 | // hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-3.html#doubling-dbl-2001-b 773 | // 3M + 5S 774 | 775 | // delta = Z1^2 776 | var delta = this.z.redSqr(); 777 | // gamma = Y1^2 778 | var gamma = this.y.redSqr(); 779 | // beta = X1 * gamma 780 | var beta = this.x.redMul(gamma); 781 | // alpha = 3 * (X1 - delta) * (X1 + delta) 782 | var alpha = this.x.redSub(delta).redMul(this.x.redAdd(delta)); 783 | alpha = alpha.redAdd(alpha).redIAdd(alpha); 784 | // X3 = alpha^2 - 8 * beta 785 | var beta4 = beta.redIAdd(beta); 786 | beta4 = beta4.redIAdd(beta4); 787 | var beta8 = beta4.redAdd(beta4); 788 | nx = alpha.redSqr().redISub(beta8); 789 | // Z3 = (Y1 + Z1)^2 - gamma - delta 790 | nz = this.y.redAdd(this.z).redSqr().redISub(gamma).redISub(delta); 791 | // Y3 = alpha * (4 * beta - X3) - 8 * gamma^2 792 | var ggamma8 = gamma.redSqr(); 793 | ggamma8 = ggamma8.redIAdd(ggamma8); 794 | ggamma8 = ggamma8.redIAdd(ggamma8); 795 | ggamma8 = ggamma8.redIAdd(ggamma8); 796 | ny = alpha.redMul(beta4.redISub(nx)).redISub(ggamma8); 797 | } 798 | 799 | return this.curve.jpoint(nx, ny, nz); 800 | }; 801 | 802 | JPoint.prototype._dbl = function _dbl() { 803 | var a = this.curve.a; 804 | 805 | // 4M + 6S + 10A 806 | var jx = this.x; 807 | var jy = this.y; 808 | var jz = this.z; 809 | var jz4 = jz.redSqr().redSqr(); 810 | 811 | var jx2 = jx.redSqr(); 812 | var jy2 = jy.redSqr(); 813 | 814 | var c = jx2.redAdd(jx2).redIAdd(jx2).redIAdd(a.redMul(jz4)); 815 | 816 | var jxd4 = jx.redAdd(jx); 817 | jxd4 = jxd4.redIAdd(jxd4); 818 | var t1 = jxd4.redMul(jy2); 819 | var nx = c.redSqr().redISub(t1.redAdd(t1)); 820 | var t2 = t1.redISub(nx); 821 | 822 | var jyd8 = jy2.redSqr(); 823 | jyd8 = jyd8.redIAdd(jyd8); 824 | jyd8 = jyd8.redIAdd(jyd8); 825 | jyd8 = jyd8.redIAdd(jyd8); 826 | var ny = c.redMul(t2).redISub(jyd8); 827 | var nz = jy.redAdd(jy).redMul(jz); 828 | 829 | return this.curve.jpoint(nx, ny, nz); 830 | }; 831 | 832 | JPoint.prototype.trpl = function trpl() { 833 | if (!this.curve.zeroA) 834 | return this.dbl().add(this); 835 | 836 | // hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html#tripling-tpl-2007-bl 837 | // 5M + 10S + ... 838 | 839 | // XX = X1^2 840 | var xx = this.x.redSqr(); 841 | // YY = Y1^2 842 | var yy = this.y.redSqr(); 843 | // ZZ = Z1^2 844 | var zz = this.z.redSqr(); 845 | // YYYY = YY^2 846 | var yyyy = yy.redSqr(); 847 | // M = 3 * XX + a * ZZ2; a = 0 848 | var m = xx.redAdd(xx).redIAdd(xx); 849 | // MM = M^2 850 | var mm = m.redSqr(); 851 | // E = 6 * ((X1 + YY)^2 - XX - YYYY) - MM 852 | var e = this.x.redAdd(yy).redSqr().redISub(xx).redISub(yyyy); 853 | e = e.redIAdd(e); 854 | e = e.redAdd(e).redIAdd(e); 855 | e = e.redISub(mm); 856 | // EE = E^2 857 | var ee = e.redSqr(); 858 | // T = 16*YYYY 859 | var t = yyyy.redIAdd(yyyy); 860 | t = t.redIAdd(t); 861 | t = t.redIAdd(t); 862 | t = t.redIAdd(t); 863 | // U = (M + E)^2 - MM - EE - T 864 | var u = m.redIAdd(e).redSqr().redISub(mm).redISub(ee).redISub(t); 865 | // X3 = 4 * (X1 * EE - 4 * YY * U) 866 | var yyu4 = yy.redMul(u); 867 | yyu4 = yyu4.redIAdd(yyu4); 868 | yyu4 = yyu4.redIAdd(yyu4); 869 | var nx = this.x.redMul(ee).redISub(yyu4); 870 | nx = nx.redIAdd(nx); 871 | nx = nx.redIAdd(nx); 872 | // Y3 = 8 * Y1 * (U * (T - U) - E * EE) 873 | var ny = this.y.redMul(u.redMul(t.redISub(u)).redISub(e.redMul(ee))); 874 | ny = ny.redIAdd(ny); 875 | ny = ny.redIAdd(ny); 876 | ny = ny.redIAdd(ny); 877 | // Z3 = (Z1 + E)^2 - ZZ - EE 878 | var nz = this.z.redAdd(e).redSqr().redISub(zz).redISub(ee); 879 | 880 | return this.curve.jpoint(nx, ny, nz); 881 | }; 882 | 883 | JPoint.prototype.mul = function mul(k, kbase) { 884 | k = new BN(k, kbase); 885 | 886 | return this.curve._wnafMul(this, k); 887 | }; 888 | 889 | JPoint.prototype.eq = function eq(p) { 890 | if (p.type === 'affine') 891 | return this.eq(p.toJ()); 892 | 893 | if (this === p) 894 | return true; 895 | 896 | // x1 * z2^2 == x2 * z1^2 897 | var z2 = this.z.redSqr(); 898 | var pz2 = p.z.redSqr(); 899 | if (this.x.redMul(pz2).redISub(p.x.redMul(z2)).cmpn(0) !== 0) 900 | return false; 901 | 902 | // y1 * z2^3 == y2 * z1^3 903 | var z3 = z2.redMul(this.z); 904 | var pz3 = pz2.redMul(p.z); 905 | return this.y.redMul(pz3).redISub(p.y.redMul(z3)).cmpn(0) === 0; 906 | }; 907 | 908 | JPoint.prototype.eqXToP = function eqXToP(x) { 909 | var zs = this.z.redSqr(); 910 | var rx = x.toRed(this.curve.red).redMul(zs); 911 | if (this.x.cmp(rx) === 0) 912 | return true; 913 | 914 | var xc = x.clone(); 915 | var t = this.curve.redN.redMul(zs); 916 | for (;;) { 917 | xc.iadd(this.curve.n); 918 | if (xc.cmp(this.curve.p) >= 0) 919 | return false; 920 | 921 | rx.redIAdd(t); 922 | if (this.x.cmp(rx) === 0) 923 | return true; 924 | } 925 | }; 926 | 927 | JPoint.prototype.inspect = function inspect() { 928 | if (this.isInfinity()) 929 | return ''; 930 | return ''; 933 | }; 934 | 935 | JPoint.prototype.isInfinity = function isInfinity() { 936 | // XXX This code assumes that zero is always zero in red 937 | return this.z.cmpn(0) === 0; 938 | }; 939 | -------------------------------------------------------------------------------- /lib/elliptic/curves.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var curves = exports; 4 | 5 | var hash = require('hash.js'); 6 | var curve = require('./curve'); 7 | var utils = require('./utils'); 8 | 9 | var assert = utils.assert; 10 | 11 | function PresetCurve(options) { 12 | if (options.type === 'short') 13 | this.curve = new curve.short(options); 14 | else if (options.type === 'edwards') 15 | this.curve = new curve.edwards(options); 16 | else 17 | this.curve = new curve.mont(options); 18 | this.g = this.curve.g; 19 | this.n = this.curve.n; 20 | this.hash = options.hash; 21 | 22 | assert(this.g.validate(), 'Invalid curve'); 23 | assert(this.g.mul(this.n).isInfinity(), 'Invalid curve, G*N != O'); 24 | } 25 | curves.PresetCurve = PresetCurve; 26 | 27 | function defineCurve(name, options) { 28 | Object.defineProperty(curves, name, { 29 | configurable: true, 30 | enumerable: true, 31 | get: function() { 32 | var curve = new PresetCurve(options); 33 | Object.defineProperty(curves, name, { 34 | configurable: true, 35 | enumerable: true, 36 | value: curve, 37 | }); 38 | return curve; 39 | }, 40 | }); 41 | } 42 | 43 | defineCurve('p192', { 44 | type: 'short', 45 | prime: 'p192', 46 | p: 'ffffffff ffffffff ffffffff fffffffe ffffffff ffffffff', 47 | a: 'ffffffff ffffffff ffffffff fffffffe ffffffff fffffffc', 48 | b: '64210519 e59c80e7 0fa7e9ab 72243049 feb8deec c146b9b1', 49 | n: 'ffffffff ffffffff ffffffff 99def836 146bc9b1 b4d22831', 50 | hash: hash.sha256, 51 | gRed: false, 52 | g: [ 53 | '188da80e b03090f6 7cbf20eb 43a18800 f4ff0afd 82ff1012', 54 | '07192b95 ffc8da78 631011ed 6b24cdd5 73f977a1 1e794811', 55 | ], 56 | }); 57 | 58 | defineCurve('p224', { 59 | type: 'short', 60 | prime: 'p224', 61 | p: 'ffffffff ffffffff ffffffff ffffffff 00000000 00000000 00000001', 62 | a: 'ffffffff ffffffff ffffffff fffffffe ffffffff ffffffff fffffffe', 63 | b: 'b4050a85 0c04b3ab f5413256 5044b0b7 d7bfd8ba 270b3943 2355ffb4', 64 | n: 'ffffffff ffffffff ffffffff ffff16a2 e0b8f03e 13dd2945 5c5c2a3d', 65 | hash: hash.sha256, 66 | gRed: false, 67 | g: [ 68 | 'b70e0cbd 6bb4bf7f 321390b9 4a03c1d3 56c21122 343280d6 115c1d21', 69 | 'bd376388 b5f723fb 4c22dfe6 cd4375a0 5a074764 44d58199 85007e34', 70 | ], 71 | }); 72 | 73 | defineCurve('p256', { 74 | type: 'short', 75 | prime: null, 76 | p: 'ffffffff 00000001 00000000 00000000 00000000 ffffffff ffffffff ffffffff', 77 | a: 'ffffffff 00000001 00000000 00000000 00000000 ffffffff ffffffff fffffffc', 78 | b: '5ac635d8 aa3a93e7 b3ebbd55 769886bc 651d06b0 cc53b0f6 3bce3c3e 27d2604b', 79 | n: 'ffffffff 00000000 ffffffff ffffffff bce6faad a7179e84 f3b9cac2 fc632551', 80 | hash: hash.sha256, 81 | gRed: false, 82 | g: [ 83 | '6b17d1f2 e12c4247 f8bce6e5 63a440f2 77037d81 2deb33a0 f4a13945 d898c296', 84 | '4fe342e2 fe1a7f9b 8ee7eb4a 7c0f9e16 2bce3357 6b315ece cbb64068 37bf51f5', 85 | ], 86 | }); 87 | 88 | defineCurve('p384', { 89 | type: 'short', 90 | prime: null, 91 | p: 'ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ' + 92 | 'fffffffe ffffffff 00000000 00000000 ffffffff', 93 | a: 'ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ' + 94 | 'fffffffe ffffffff 00000000 00000000 fffffffc', 95 | b: 'b3312fa7 e23ee7e4 988e056b e3f82d19 181d9c6e fe814112 0314088f ' + 96 | '5013875a c656398d 8a2ed19d 2a85c8ed d3ec2aef', 97 | n: 'ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff c7634d81 ' + 98 | 'f4372ddf 581a0db2 48b0a77a ecec196a ccc52973', 99 | hash: hash.sha384, 100 | gRed: false, 101 | g: [ 102 | 'aa87ca22 be8b0537 8eb1c71e f320ad74 6e1d3b62 8ba79b98 59f741e0 82542a38 ' + 103 | '5502f25d bf55296c 3a545e38 72760ab7', 104 | '3617de4a 96262c6f 5d9e98bf 9292dc29 f8f41dbd 289a147c e9da3113 b5f0b8c0 ' + 105 | '0a60b1ce 1d7e819d 7a431d7c 90ea0e5f', 106 | ], 107 | }); 108 | 109 | defineCurve('p521', { 110 | type: 'short', 111 | prime: null, 112 | p: '000001ff ffffffff ffffffff ffffffff ffffffff ffffffff ' + 113 | 'ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ' + 114 | 'ffffffff ffffffff ffffffff ffffffff ffffffff', 115 | a: '000001ff ffffffff ffffffff ffffffff ffffffff ffffffff ' + 116 | 'ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ' + 117 | 'ffffffff ffffffff ffffffff ffffffff fffffffc', 118 | b: '00000051 953eb961 8e1c9a1f 929a21a0 b68540ee a2da725b ' + 119 | '99b315f3 b8b48991 8ef109e1 56193951 ec7e937b 1652c0bd ' + 120 | '3bb1bf07 3573df88 3d2c34f1 ef451fd4 6b503f00', 121 | n: '000001ff ffffffff ffffffff ffffffff ffffffff ffffffff ' + 122 | 'ffffffff ffffffff fffffffa 51868783 bf2f966b 7fcc0148 ' + 123 | 'f709a5d0 3bb5c9b8 899c47ae bb6fb71e 91386409', 124 | hash: hash.sha512, 125 | gRed: false, 126 | g: [ 127 | '000000c6 858e06b7 0404e9cd 9e3ecb66 2395b442 9c648139 ' + 128 | '053fb521 f828af60 6b4d3dba a14b5e77 efe75928 fe1dc127 ' + 129 | 'a2ffa8de 3348b3c1 856a429b f97e7e31 c2e5bd66', 130 | '00000118 39296a78 9a3bc004 5c8a5fb4 2c7d1bd9 98f54449 ' + 131 | '579b4468 17afbd17 273e662c 97ee7299 5ef42640 c550b901 ' + 132 | '3fad0761 353c7086 a272c240 88be9476 9fd16650', 133 | ], 134 | }); 135 | 136 | defineCurve('curve25519', { 137 | type: 'mont', 138 | prime: 'p25519', 139 | p: '7fffffffffffffff ffffffffffffffff ffffffffffffffff ffffffffffffffed', 140 | a: '76d06', 141 | b: '1', 142 | n: '1000000000000000 0000000000000000 14def9dea2f79cd6 5812631a5cf5d3ed', 143 | hash: hash.sha256, 144 | gRed: false, 145 | g: [ 146 | '9', 147 | ], 148 | }); 149 | 150 | defineCurve('ed25519', { 151 | type: 'edwards', 152 | prime: 'p25519', 153 | p: '7fffffffffffffff ffffffffffffffff ffffffffffffffff ffffffffffffffed', 154 | a: '-1', 155 | c: '1', 156 | // -121665 * (121666^(-1)) (mod P) 157 | d: '52036cee2b6ffe73 8cc740797779e898 00700a4d4141d8ab 75eb4dca135978a3', 158 | n: '1000000000000000 0000000000000000 14def9dea2f79cd6 5812631a5cf5d3ed', 159 | hash: hash.sha256, 160 | gRed: false, 161 | g: [ 162 | '216936d3cd6e53fec0a4e231fdd6dc5c692cc7609525a7b2c9562d608f25d51a', 163 | 164 | // 4/5 165 | '6666666666666666666666666666666666666666666666666666666666666658', 166 | ], 167 | }); 168 | 169 | var pre; 170 | try { 171 | pre = require('./precomputed/secp256k1'); 172 | } catch (e) { 173 | pre = undefined; 174 | } 175 | 176 | defineCurve('secp256k1', { 177 | type: 'short', 178 | prime: 'k256', 179 | p: 'ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff fffffffe fffffc2f', 180 | a: '0', 181 | b: '7', 182 | n: 'ffffffff ffffffff ffffffff fffffffe baaedce6 af48a03b bfd25e8c d0364141', 183 | h: '1', 184 | hash: hash.sha256, 185 | 186 | // Precomputed endomorphism 187 | beta: '7ae96a2b657c07106e64479eac3434e99cf0497512f58995c1396c28719501ee', 188 | lambda: '5363ad4cc05c30e0a5261c028812645a122e22ea20816678df02967c1b23bd72', 189 | basis: [ 190 | { 191 | a: '3086d221a7d46bcde86c90e49284eb15', 192 | b: '-e4437ed6010e88286f547fa90abfe4c3', 193 | }, 194 | { 195 | a: '114ca50f7a8e2f3f657c1108d9d44cfd8', 196 | b: '3086d221a7d46bcde86c90e49284eb15', 197 | }, 198 | ], 199 | 200 | gRed: false, 201 | g: [ 202 | '79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798', 203 | '483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8', 204 | pre, 205 | ], 206 | }); 207 | -------------------------------------------------------------------------------- /lib/elliptic/ec/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var BN = require('bn.js'); 4 | var HmacDRBG = require('hmac-drbg'); 5 | var utils = require('../utils'); 6 | var curves = require('../curves'); 7 | var rand = require('brorand'); 8 | var assert = utils.assert; 9 | 10 | var KeyPair = require('./key'); 11 | var Signature = require('./signature'); 12 | 13 | function EC(options) { 14 | if (!(this instanceof EC)) 15 | return new EC(options); 16 | 17 | // Shortcut `elliptic.ec(curve-name)` 18 | if (typeof options === 'string') { 19 | assert(Object.prototype.hasOwnProperty.call(curves, options), 20 | 'Unknown curve ' + options); 21 | 22 | options = curves[options]; 23 | } 24 | 25 | // Shortcut for `elliptic.ec(elliptic.curves.curveName)` 26 | if (options instanceof curves.PresetCurve) 27 | options = { curve: options }; 28 | 29 | this.curve = options.curve.curve; 30 | this.n = this.curve.n; 31 | this.nh = this.n.ushrn(1); 32 | this.g = this.curve.g; 33 | 34 | // Point on curve 35 | this.g = options.curve.g; 36 | this.g.precompute(options.curve.n.bitLength() + 1); 37 | 38 | // Hash for function for DRBG 39 | this.hash = options.hash || options.curve.hash; 40 | } 41 | module.exports = EC; 42 | 43 | EC.prototype.keyPair = function keyPair(options) { 44 | return new KeyPair(this, options); 45 | }; 46 | 47 | EC.prototype.keyFromPrivate = function keyFromPrivate(priv, enc) { 48 | return KeyPair.fromPrivate(this, priv, enc); 49 | }; 50 | 51 | EC.prototype.keyFromPublic = function keyFromPublic(pub, enc) { 52 | return KeyPair.fromPublic(this, pub, enc); 53 | }; 54 | 55 | EC.prototype.genKeyPair = function genKeyPair(options) { 56 | if (!options) 57 | options = {}; 58 | 59 | // Instantiate Hmac_DRBG 60 | var drbg = new HmacDRBG({ 61 | hash: this.hash, 62 | pers: options.pers, 63 | persEnc: options.persEnc || 'utf8', 64 | entropy: options.entropy || rand(this.hash.hmacStrength), 65 | entropyEnc: options.entropy && options.entropyEnc || 'utf8', 66 | nonce: this.n.toArray(), 67 | }); 68 | 69 | var bytes = this.n.byteLength(); 70 | var ns2 = this.n.sub(new BN(2)); 71 | for (;;) { 72 | var priv = new BN(drbg.generate(bytes)); 73 | if (priv.cmp(ns2) > 0) 74 | continue; 75 | 76 | priv.iaddn(1); 77 | return this.keyFromPrivate(priv); 78 | } 79 | }; 80 | 81 | EC.prototype._truncateToN = function _truncateToN(msg, truncOnly, bitLength) { 82 | var byteLength; 83 | if (BN.isBN(msg) || typeof msg === 'number') { 84 | msg = new BN(msg, 16); 85 | byteLength = msg.byteLength(); 86 | } else if (typeof msg === 'object') { 87 | // BN assumes an array-like input and asserts length 88 | byteLength = msg.length; 89 | msg = new BN(msg, 16); 90 | } else { 91 | // BN converts the value to string 92 | var str = msg.toString(); 93 | // HEX encoding 94 | byteLength = (str.length + 1) >>> 1; 95 | msg = new BN(str, 16); 96 | } 97 | // Allow overriding 98 | if (typeof bitLength !== 'number') { 99 | bitLength = byteLength * 8; 100 | } 101 | var delta = bitLength - this.n.bitLength(); 102 | if (delta > 0) 103 | msg = msg.ushrn(delta); 104 | if (!truncOnly && msg.cmp(this.n) >= 0) 105 | return msg.sub(this.n); 106 | else 107 | return msg; 108 | }; 109 | 110 | EC.prototype.sign = function sign(msg, key, enc, options) { 111 | if (typeof enc === 'object') { 112 | options = enc; 113 | enc = null; 114 | } 115 | if (!options) 116 | options = {}; 117 | 118 | if (typeof msg !== 'string' && typeof msg !== 'number' && !BN.isBN(msg)) { 119 | assert(typeof msg === 'object' && msg && typeof msg.length === 'number', 120 | 'Expected message to be an array-like, a hex string, or a BN instance'); 121 | assert((msg.length >>> 0) === msg.length); // non-negative 32-bit integer 122 | for (var i = 0; i < msg.length; i++) assert((msg[i] & 255) === msg[i]); 123 | } 124 | 125 | key = this.keyFromPrivate(key, enc); 126 | msg = this._truncateToN(msg, false, options.msgBitLength); 127 | 128 | // Would fail further checks, but let's make the error message clear 129 | assert(!msg.isNeg(), 'Can not sign a negative message'); 130 | 131 | // Zero-extend key to provide enough entropy 132 | var bytes = this.n.byteLength(); 133 | var bkey = key.getPrivate().toArray('be', bytes); 134 | 135 | // Zero-extend nonce to have the same byte size as N 136 | var nonce = msg.toArray('be', bytes); 137 | 138 | // Recheck nonce to be bijective to msg 139 | assert((new BN(nonce)).eq(msg), 'Can not sign message'); 140 | 141 | // Instantiate Hmac_DRBG 142 | var drbg = new HmacDRBG({ 143 | hash: this.hash, 144 | entropy: bkey, 145 | nonce: nonce, 146 | pers: options.pers, 147 | persEnc: options.persEnc || 'utf8', 148 | }); 149 | 150 | // Number of bytes to generate 151 | var ns1 = this.n.sub(new BN(1)); 152 | 153 | for (var iter = 0; ; iter++) { 154 | var k = options.k ? 155 | options.k(iter) : 156 | new BN(drbg.generate(this.n.byteLength())); 157 | k = this._truncateToN(k, true); 158 | if (k.cmpn(1) <= 0 || k.cmp(ns1) >= 0) 159 | continue; 160 | 161 | var kp = this.g.mul(k); 162 | if (kp.isInfinity()) 163 | continue; 164 | 165 | var kpX = kp.getX(); 166 | var r = kpX.umod(this.n); 167 | if (r.cmpn(0) === 0) 168 | continue; 169 | 170 | var s = k.invm(this.n).mul(r.mul(key.getPrivate()).iadd(msg)); 171 | s = s.umod(this.n); 172 | if (s.cmpn(0) === 0) 173 | continue; 174 | 175 | var recoveryParam = (kp.getY().isOdd() ? 1 : 0) | 176 | (kpX.cmp(r) !== 0 ? 2 : 0); 177 | 178 | // Use complement of `s`, if it is > `n / 2` 179 | if (options.canonical && s.cmp(this.nh) > 0) { 180 | s = this.n.sub(s); 181 | recoveryParam ^= 1; 182 | } 183 | 184 | return new Signature({ r: r, s: s, recoveryParam: recoveryParam }); 185 | } 186 | }; 187 | 188 | EC.prototype.verify = function verify(msg, signature, key, enc, options) { 189 | if (!options) 190 | options = {}; 191 | 192 | msg = this._truncateToN(msg, false, options.msgBitLength); 193 | key = this.keyFromPublic(key, enc); 194 | signature = new Signature(signature, 'hex'); 195 | 196 | // Perform primitive values validation 197 | var r = signature.r; 198 | var s = signature.s; 199 | if (r.cmpn(1) < 0 || r.cmp(this.n) >= 0) 200 | return false; 201 | if (s.cmpn(1) < 0 || s.cmp(this.n) >= 0) 202 | return false; 203 | 204 | // Validate signature 205 | var sinv = s.invm(this.n); 206 | var u1 = sinv.mul(msg).umod(this.n); 207 | var u2 = sinv.mul(r).umod(this.n); 208 | var p; 209 | 210 | if (!this.curve._maxwellTrick) { 211 | p = this.g.mulAdd(u1, key.getPublic(), u2); 212 | if (p.isInfinity()) 213 | return false; 214 | 215 | return p.getX().umod(this.n).cmp(r) === 0; 216 | } 217 | 218 | // NOTE: Greg Maxwell's trick, inspired by: 219 | // https://git.io/vad3K 220 | 221 | p = this.g.jmulAdd(u1, key.getPublic(), u2); 222 | if (p.isInfinity()) 223 | return false; 224 | 225 | // Compare `p.x` of Jacobian point with `r`, 226 | // this will do `p.x == r * p.z^2` instead of multiplying `p.x` by the 227 | // inverse of `p.z^2` 228 | return p.eqXToP(r); 229 | }; 230 | 231 | EC.prototype.recoverPubKey = function(msg, signature, j, enc) { 232 | assert((3 & j) === j, 'The recovery param is more than two bits'); 233 | signature = new Signature(signature, enc); 234 | 235 | var n = this.n; 236 | var e = new BN(msg); 237 | var r = signature.r; 238 | var s = signature.s; 239 | 240 | // A set LSB signifies that the y-coordinate is odd 241 | var isYOdd = j & 1; 242 | var isSecondKey = j >> 1; 243 | if (r.cmp(this.curve.p.umod(this.curve.n)) >= 0 && isSecondKey) 244 | throw new Error('Unable to find sencond key candinate'); 245 | 246 | // 1.1. Let x = r + jn. 247 | if (isSecondKey) 248 | r = this.curve.pointFromX(r.add(this.curve.n), isYOdd); 249 | else 250 | r = this.curve.pointFromX(r, isYOdd); 251 | 252 | var rInv = signature.r.invm(n); 253 | var s1 = n.sub(e).mul(rInv).umod(n); 254 | var s2 = s.mul(rInv).umod(n); 255 | 256 | // 1.6.1 Compute Q = r^-1 (sR - eG) 257 | // Q = r^-1 (sR + -eG) 258 | return this.g.mulAdd(s1, r, s2); 259 | }; 260 | 261 | EC.prototype.getKeyRecoveryParam = function(e, signature, Q, enc) { 262 | signature = new Signature(signature, enc); 263 | if (signature.recoveryParam !== null) 264 | return signature.recoveryParam; 265 | 266 | for (var i = 0; i < 4; i++) { 267 | var Qprime; 268 | try { 269 | Qprime = this.recoverPubKey(e, signature, i); 270 | } catch (e) { 271 | continue; 272 | } 273 | 274 | if (Qprime.eq(Q)) 275 | return i; 276 | } 277 | throw new Error('Unable to find valid recovery factor'); 278 | }; 279 | -------------------------------------------------------------------------------- /lib/elliptic/ec/key.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var BN = require('bn.js'); 4 | var utils = require('../utils'); 5 | var assert = utils.assert; 6 | 7 | function KeyPair(ec, options) { 8 | this.ec = ec; 9 | this.priv = null; 10 | this.pub = null; 11 | 12 | // KeyPair(ec, { priv: ..., pub: ... }) 13 | if (options.priv) 14 | this._importPrivate(options.priv, options.privEnc); 15 | if (options.pub) 16 | this._importPublic(options.pub, options.pubEnc); 17 | } 18 | module.exports = KeyPair; 19 | 20 | KeyPair.fromPublic = function fromPublic(ec, pub, enc) { 21 | if (pub instanceof KeyPair) 22 | return pub; 23 | 24 | return new KeyPair(ec, { 25 | pub: pub, 26 | pubEnc: enc, 27 | }); 28 | }; 29 | 30 | KeyPair.fromPrivate = function fromPrivate(ec, priv, enc) { 31 | if (priv instanceof KeyPair) 32 | return priv; 33 | 34 | return new KeyPair(ec, { 35 | priv: priv, 36 | privEnc: enc, 37 | }); 38 | }; 39 | 40 | KeyPair.prototype.validate = function validate() { 41 | var pub = this.getPublic(); 42 | 43 | if (pub.isInfinity()) 44 | return { result: false, reason: 'Invalid public key' }; 45 | if (!pub.validate()) 46 | return { result: false, reason: 'Public key is not a point' }; 47 | if (!pub.mul(this.ec.curve.n).isInfinity()) 48 | return { result: false, reason: 'Public key * N != O' }; 49 | 50 | return { result: true, reason: null }; 51 | }; 52 | 53 | KeyPair.prototype.getPublic = function getPublic(compact, enc) { 54 | // compact is optional argument 55 | if (typeof compact === 'string') { 56 | enc = compact; 57 | compact = null; 58 | } 59 | 60 | if (!this.pub) 61 | this.pub = this.ec.g.mul(this.priv); 62 | 63 | if (!enc) 64 | return this.pub; 65 | 66 | return this.pub.encode(enc, compact); 67 | }; 68 | 69 | KeyPair.prototype.getPrivate = function getPrivate(enc) { 70 | if (enc === 'hex') 71 | return this.priv.toString(16, 2); 72 | else 73 | return this.priv; 74 | }; 75 | 76 | KeyPair.prototype._importPrivate = function _importPrivate(key, enc) { 77 | this.priv = new BN(key, enc || 16); 78 | 79 | // Ensure that the priv won't be bigger than n, otherwise we may fail 80 | // in fixed multiplication method 81 | this.priv = this.priv.umod(this.ec.curve.n); 82 | }; 83 | 84 | KeyPair.prototype._importPublic = function _importPublic(key, enc) { 85 | if (key.x || key.y) { 86 | // Montgomery points only have an `x` coordinate. 87 | // Weierstrass/Edwards points on the other hand have both `x` and 88 | // `y` coordinates. 89 | if (this.ec.curve.type === 'mont') { 90 | assert(key.x, 'Need x coordinate'); 91 | } else if (this.ec.curve.type === 'short' || 92 | this.ec.curve.type === 'edwards') { 93 | assert(key.x && key.y, 'Need both x and y coordinate'); 94 | } 95 | this.pub = this.ec.curve.point(key.x, key.y); 96 | return; 97 | } 98 | this.pub = this.ec.curve.decodePoint(key, enc); 99 | }; 100 | 101 | // ECDH 102 | KeyPair.prototype.derive = function derive(pub) { 103 | if(!pub.validate()) { 104 | assert(pub.validate(), 'public point not validated'); 105 | } 106 | return pub.mul(this.priv).getX(); 107 | }; 108 | 109 | // ECDSA 110 | KeyPair.prototype.sign = function sign(msg, enc, options) { 111 | return this.ec.sign(msg, this, enc, options); 112 | }; 113 | 114 | KeyPair.prototype.verify = function verify(msg, signature, options) { 115 | return this.ec.verify(msg, signature, this, undefined, options); 116 | }; 117 | 118 | KeyPair.prototype.inspect = function inspect() { 119 | return ''; 121 | }; 122 | -------------------------------------------------------------------------------- /lib/elliptic/ec/signature.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var BN = require('bn.js'); 4 | 5 | var utils = require('../utils'); 6 | var assert = utils.assert; 7 | 8 | function Signature(options, enc) { 9 | if (options instanceof Signature) 10 | return options; 11 | 12 | if (this._importDER(options, enc)) 13 | return; 14 | 15 | assert(options.r && options.s, 'Signature without r or s'); 16 | this.r = new BN(options.r, 16); 17 | this.s = new BN(options.s, 16); 18 | if (options.recoveryParam === undefined) 19 | this.recoveryParam = null; 20 | else 21 | this.recoveryParam = options.recoveryParam; 22 | } 23 | module.exports = Signature; 24 | 25 | function Position() { 26 | this.place = 0; 27 | } 28 | 29 | function getLength(buf, p) { 30 | var initial = buf[p.place++]; 31 | if (!(initial & 0x80)) { 32 | return initial; 33 | } 34 | var octetLen = initial & 0xf; 35 | 36 | // Indefinite length or overflow 37 | if (octetLen === 0 || octetLen > 4) { 38 | return false; 39 | } 40 | 41 | if(buf[p.place] === 0x00) { 42 | return false; 43 | } 44 | 45 | var val = 0; 46 | for (var i = 0, off = p.place; i < octetLen; i++, off++) { 47 | val <<= 8; 48 | val |= buf[off]; 49 | val >>>= 0; 50 | } 51 | 52 | // Leading zeroes 53 | if (val <= 0x7f) { 54 | return false; 55 | } 56 | 57 | p.place = off; 58 | return val; 59 | } 60 | 61 | function rmPadding(buf) { 62 | var i = 0; 63 | var len = buf.length - 1; 64 | while (!buf[i] && !(buf[i + 1] & 0x80) && i < len) { 65 | i++; 66 | } 67 | if (i === 0) { 68 | return buf; 69 | } 70 | return buf.slice(i); 71 | } 72 | 73 | Signature.prototype._importDER = function _importDER(data, enc) { 74 | data = utils.toArray(data, enc); 75 | var p = new Position(); 76 | if (data[p.place++] !== 0x30) { 77 | return false; 78 | } 79 | var len = getLength(data, p); 80 | if (len === false) { 81 | return false; 82 | } 83 | if ((len + p.place) !== data.length) { 84 | return false; 85 | } 86 | if (data[p.place++] !== 0x02) { 87 | return false; 88 | } 89 | var rlen = getLength(data, p); 90 | if (rlen === false) { 91 | return false; 92 | } 93 | if ((data[p.place] & 128) !== 0) { 94 | return false; 95 | } 96 | var r = data.slice(p.place, rlen + p.place); 97 | p.place += rlen; 98 | if (data[p.place++] !== 0x02) { 99 | return false; 100 | } 101 | var slen = getLength(data, p); 102 | if (slen === false) { 103 | return false; 104 | } 105 | if (data.length !== slen + p.place) { 106 | return false; 107 | } 108 | if ((data[p.place] & 128) !== 0) { 109 | return false; 110 | } 111 | var s = data.slice(p.place, slen + p.place); 112 | if (r[0] === 0) { 113 | if (r[1] & 0x80) { 114 | r = r.slice(1); 115 | } else { 116 | // Leading zeroes 117 | return false; 118 | } 119 | } 120 | if (s[0] === 0) { 121 | if (s[1] & 0x80) { 122 | s = s.slice(1); 123 | } else { 124 | // Leading zeroes 125 | return false; 126 | } 127 | } 128 | 129 | this.r = new BN(r); 130 | this.s = new BN(s); 131 | this.recoveryParam = null; 132 | 133 | return true; 134 | }; 135 | 136 | function constructLength(arr, len) { 137 | if (len < 0x80) { 138 | arr.push(len); 139 | return; 140 | } 141 | var octets = 1 + (Math.log(len) / Math.LN2 >>> 3); 142 | arr.push(octets | 0x80); 143 | while (--octets) { 144 | arr.push((len >>> (octets << 3)) & 0xff); 145 | } 146 | arr.push(len); 147 | } 148 | 149 | Signature.prototype.toDER = function toDER(enc) { 150 | var r = this.r.toArray(); 151 | var s = this.s.toArray(); 152 | 153 | // Pad values 154 | if (r[0] & 0x80) 155 | r = [ 0 ].concat(r); 156 | // Pad values 157 | if (s[0] & 0x80) 158 | s = [ 0 ].concat(s); 159 | 160 | r = rmPadding(r); 161 | s = rmPadding(s); 162 | 163 | while (!s[0] && !(s[1] & 0x80)) { 164 | s = s.slice(1); 165 | } 166 | var arr = [ 0x02 ]; 167 | constructLength(arr, r.length); 168 | arr = arr.concat(r); 169 | arr.push(0x02); 170 | constructLength(arr, s.length); 171 | var backHalf = arr.concat(s); 172 | var res = [ 0x30 ]; 173 | constructLength(res, backHalf.length); 174 | res = res.concat(backHalf); 175 | return utils.encode(res, enc); 176 | }; 177 | -------------------------------------------------------------------------------- /lib/elliptic/eddsa/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var hash = require('hash.js'); 4 | var curves = require('../curves'); 5 | var utils = require('../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 | curve = 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 | if (sig.S().gte(sig.eddsa.curve.n) || sig.S().isNeg()) { 56 | return false; 57 | } 58 | var key = this.keyFromPublic(pub); 59 | var h = this.hashInt(sig.Rencoded(), key.pubBytes(), message); 60 | var SG = this.g.mul(sig.S()); 61 | var RplusAh = sig.R().add(key.pub().mul(h)); 62 | return RplusAh.eq(SG); 63 | }; 64 | 65 | EDDSA.prototype.hashInt = function hashInt() { 66 | var hash = this.hash(); 67 | for (var i = 0; i < arguments.length; i++) 68 | hash.update(arguments[i]); 69 | return utils.intFromLE(hash.digest()).umod(this.curve.n); 70 | }; 71 | 72 | EDDSA.prototype.keyFromPublic = function keyFromPublic(pub) { 73 | return KeyPair.fromPublic(this, pub); 74 | }; 75 | 76 | EDDSA.prototype.keyFromSecret = function keyFromSecret(secret) { 77 | return KeyPair.fromSecret(this, secret); 78 | }; 79 | 80 | EDDSA.prototype.makeSignature = function makeSignature(sig) { 81 | if (sig instanceof Signature) 82 | return sig; 83 | return new Signature(this, sig); 84 | }; 85 | 86 | /** 87 | * * https://tools.ietf.org/html/draft-josefsson-eddsa-ed25519-03#section-5.2 88 | * 89 | * EDDSA defines methods for encoding and decoding points and integers. These are 90 | * helper convenience methods, that pass along to utility functions implied 91 | * parameters. 92 | * 93 | */ 94 | EDDSA.prototype.encodePoint = function encodePoint(point) { 95 | var enc = point.getY().toArray('le', this.encodingLength); 96 | enc[this.encodingLength - 1] |= point.getX().isOdd() ? 0x80 : 0; 97 | return enc; 98 | }; 99 | 100 | EDDSA.prototype.decodePoint = function decodePoint(bytes) { 101 | bytes = utils.parseBytes(bytes); 102 | 103 | var lastIx = bytes.length - 1; 104 | var normed = bytes.slice(0, lastIx).concat(bytes[lastIx] & ~0x80); 105 | var xIsOdd = (bytes[lastIx] & 0x80) !== 0; 106 | 107 | var y = utils.intFromLE(normed); 108 | return this.curve.pointFromY(y, xIsOdd); 109 | }; 110 | 111 | EDDSA.prototype.encodeInt = function encodeInt(num) { 112 | return num.toArray('le', this.encodingLength); 113 | }; 114 | 115 | EDDSA.prototype.decodeInt = function decodeInt(bytes) { 116 | return utils.intFromLE(bytes); 117 | }; 118 | 119 | EDDSA.prototype.isPoint = function isPoint(val) { 120 | return val instanceof this.pointClass; 121 | }; 122 | -------------------------------------------------------------------------------- /lib/elliptic/eddsa/key.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var utils = require('../utils'); 4 | var assert = utils.assert; 5 | var parseBytes = utils.parseBytes; 6 | var cachedProperty = utils.cachedProperty; 7 | 8 | /** 9 | * @param {EDDSA} eddsa - instance 10 | * @param {Object} params - public/private key parameters 11 | * 12 | * @param {Array} [params.secret] - secret seed bytes 13 | * @param {Point} [params.pub] - public key point (aka `A` in eddsa terms) 14 | * @param {Array} [params.pub] - public key point encoded as bytes 15 | * 16 | */ 17 | function KeyPair(eddsa, params) { 18 | this.eddsa = eddsa; 19 | this._secret = parseBytes(params.secret); 20 | if (eddsa.isPoint(params.pub)) 21 | this._pub = params.pub; 22 | else 23 | this._pubBytes = parseBytes(params.pub); 24 | } 25 | 26 | KeyPair.fromPublic = function fromPublic(eddsa, pub) { 27 | if (pub instanceof KeyPair) 28 | return pub; 29 | return new KeyPair(eddsa, { pub: pub }); 30 | }; 31 | 32 | KeyPair.fromSecret = function fromSecret(eddsa, secret) { 33 | if (secret instanceof KeyPair) 34 | return secret; 35 | return new KeyPair(eddsa, { secret: secret }); 36 | }; 37 | 38 | KeyPair.prototype.secret = function secret() { 39 | return this._secret; 40 | }; 41 | 42 | cachedProperty(KeyPair, 'pubBytes', function pubBytes() { 43 | return this.eddsa.encodePoint(this.pub()); 44 | }); 45 | 46 | cachedProperty(KeyPair, 'pub', function pub() { 47 | if (this._pubBytes) 48 | return this.eddsa.decodePoint(this._pubBytes); 49 | return this.eddsa.g.mul(this.priv()); 50 | }); 51 | 52 | cachedProperty(KeyPair, 'privBytes', function privBytes() { 53 | var eddsa = this.eddsa; 54 | var hash = this.hash(); 55 | var lastIx = eddsa.encodingLength - 1; 56 | 57 | var a = hash.slice(0, eddsa.encodingLength); 58 | a[0] &= 248; 59 | a[lastIx] &= 127; 60 | a[lastIx] |= 64; 61 | 62 | return a; 63 | }); 64 | 65 | cachedProperty(KeyPair, 'priv', function priv() { 66 | return this.eddsa.decodeInt(this.privBytes()); 67 | }); 68 | 69 | cachedProperty(KeyPair, 'hash', function hash() { 70 | return this.eddsa.hash().update(this.secret()).digest(); 71 | }); 72 | 73 | cachedProperty(KeyPair, 'messagePrefix', function messagePrefix() { 74 | return this.hash().slice(this.eddsa.encodingLength); 75 | }); 76 | 77 | KeyPair.prototype.sign = function sign(message) { 78 | assert(this._secret, 'KeyPair can only verify'); 79 | return this.eddsa.sign(message, this); 80 | }; 81 | 82 | KeyPair.prototype.verify = function verify(message, sig) { 83 | return this.eddsa.verify(message, sig, this); 84 | }; 85 | 86 | KeyPair.prototype.getSecret = function getSecret(enc) { 87 | assert(this._secret, 'KeyPair is public only'); 88 | return utils.encode(this.secret(), enc); 89 | }; 90 | 91 | KeyPair.prototype.getPublic = function getPublic(enc) { 92 | return utils.encode(this.pubBytes(), enc); 93 | }; 94 | 95 | module.exports = KeyPair; 96 | -------------------------------------------------------------------------------- /lib/elliptic/eddsa/signature.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var BN = require('bn.js'); 4 | var utils = require('../utils'); 5 | var assert = utils.assert; 6 | var cachedProperty = utils.cachedProperty; 7 | var parseBytes = utils.parseBytes; 8 | 9 | /** 10 | * @param {EDDSA} eddsa - eddsa instance 11 | * @param {Array|Object} sig - 12 | * @param {Array|Point} [sig.R] - R point as Point or bytes 13 | * @param {Array|bn} [sig.S] - S scalar as bn or bytes 14 | * @param {Array} [sig.Rencoded] - R point encoded 15 | * @param {Array} [sig.Sencoded] - S scalar encoded 16 | */ 17 | function Signature(eddsa, sig) { 18 | this.eddsa = eddsa; 19 | 20 | if (typeof sig !== 'object') 21 | sig = parseBytes(sig); 22 | 23 | if (Array.isArray(sig)) { 24 | assert(sig.length === eddsa.encodingLength * 2, 'Signature has invalid size'); 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/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 | -------------------------------------------------------------------------------- /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, bits) { 16 | var naf = new Array(Math.max(num.bitLength(), bits) + 1); 17 | var i; 18 | for (i = 0; i < naf.length; i += 1) { 19 | naf[i] = 0; 20 | } 21 | 22 | var ws = 1 << (w + 1); 23 | var k = num.clone(); 24 | 25 | for (i = 0; i < naf.length; i++) { 26 | var z; 27 | var mod = k.andln(ws - 1); 28 | if (k.isOdd()) { 29 | if (mod > (ws >> 1) - 1) 30 | z = (ws >> 1) - mod; 31 | else 32 | z = mod; 33 | k.isubn(z); 34 | } else { 35 | z = 0; 36 | } 37 | 38 | naf[i] = z; 39 | k.iushrn(1); 40 | } 41 | 42 | return naf; 43 | } 44 | utils.getNAF = getNAF; 45 | 46 | // Represent k1, k2 in a Joint Sparse Form 47 | function getJSF(k1, k2) { 48 | var jsf = [ 49 | [], 50 | [], 51 | ]; 52 | 53 | k1 = k1.clone(); 54 | k2 = k2.clone(); 55 | var d1 = 0; 56 | var d2 = 0; 57 | var m8; 58 | while (k1.cmpn(-d1) > 0 || k2.cmpn(-d2) > 0) { 59 | // First phase 60 | var m14 = (k1.andln(3) + d1) & 3; 61 | var m24 = (k2.andln(3) + d2) & 3; 62 | if (m14 === 3) 63 | m14 = -1; 64 | if (m24 === 3) 65 | m24 = -1; 66 | var u1; 67 | if ((m14 & 1) === 0) { 68 | u1 = 0; 69 | } else { 70 | m8 = (k1.andln(7) + d1) & 7; 71 | if ((m8 === 3 || m8 === 5) && m24 === 2) 72 | u1 = -m14; 73 | else 74 | u1 = m14; 75 | } 76 | jsf[0].push(u1); 77 | 78 | var u2; 79 | if ((m24 & 1) === 0) { 80 | u2 = 0; 81 | } else { 82 | m8 = (k2.andln(7) + d2) & 7; 83 | if ((m8 === 3 || m8 === 5) && m14 === 2) 84 | u2 = -m24; 85 | else 86 | u2 = m24; 87 | } 88 | jsf[1].push(u2); 89 | 90 | // Second phase 91 | if (2 * d1 === u1 + 1) 92 | d1 = 1 - d1; 93 | if (2 * d2 === u2 + 1) 94 | d2 = 1 - d2; 95 | k1.iushrn(1); 96 | k2.iushrn(1); 97 | } 98 | 99 | return jsf; 100 | } 101 | utils.getJSF = getJSF; 102 | 103 | function cachedProperty(obj, name, computer) { 104 | var key = '_' + name; 105 | obj.prototype[name] = function cachedProperty() { 106 | return this[key] !== undefined ? this[key] : 107 | this[key] = computer.call(this); 108 | }; 109 | } 110 | utils.cachedProperty = cachedProperty; 111 | 112 | function parseBytes(bytes) { 113 | return typeof bytes === 'string' ? utils.toArray(bytes, 'hex') : 114 | bytes; 115 | } 116 | utils.parseBytes = parseBytes; 117 | 118 | function intFromLE(bytes) { 119 | return new BN(bytes, 'hex', 'le'); 120 | } 121 | utils.intFromLE = intFromLE; 122 | 123 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "elliptic", 3 | "version": "6.6.1", 4 | "description": "EC cryptography", 5 | "main": "lib/elliptic.js", 6 | "files": [ 7 | "lib" 8 | ], 9 | "scripts": { 10 | "lint": "eslint lib test", 11 | "lint:fix": "npm run lint -- --fix", 12 | "unit": "istanbul test _mocha --reporter=spec test/index.js", 13 | "test": "npm run lint && npm run unit", 14 | "version": "grunt dist && git add dist/" 15 | }, 16 | "repository": { 17 | "type": "git", 18 | "url": "git@github.com:indutny/elliptic" 19 | }, 20 | "keywords": [ 21 | "EC", 22 | "Elliptic", 23 | "curve", 24 | "Cryptography" 25 | ], 26 | "author": "Fedor Indutny ", 27 | "license": "MIT", 28 | "bugs": { 29 | "url": "https://github.com/indutny/elliptic/issues" 30 | }, 31 | "homepage": "https://github.com/indutny/elliptic", 32 | "devDependencies": { 33 | "brfs": "^2.0.2", 34 | "coveralls": "^3.1.0", 35 | "eslint": "^7.6.0", 36 | "grunt": "^1.2.1", 37 | "grunt-browserify": "^5.3.0", 38 | "grunt-cli": "^1.3.2", 39 | "grunt-contrib-connect": "^3.0.0", 40 | "grunt-contrib-copy": "^1.0.0", 41 | "grunt-contrib-uglify": "^5.0.0", 42 | "grunt-mocha-istanbul": "^5.0.2", 43 | "grunt-saucelabs": "^9.0.1", 44 | "istanbul": "^0.4.5", 45 | "mocha": "^8.0.1" 46 | }, 47 | "dependencies": { 48 | "bn.js": "^4.11.9", 49 | "brorand": "^1.1.0", 50 | "hash.js": "^1.0.0", 51 | "hmac-drbg": "^1.0.1", 52 | "inherits": "^2.0.4", 53 | "minimalistic-assert": "^1.0.1", 54 | "minimalistic-crypto-utils": "^1.0.1" 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /test/api-test.js: -------------------------------------------------------------------------------- 1 | /* eslint-env node, mocha */ 2 | 'use strict'; 3 | 4 | var assert = require('assert'); 5 | var elliptic = require('../'); 6 | 7 | describe('EC API', function() { 8 | it('should instantiate with valid curve (secp256k1)', function() { 9 | var ec = new elliptic.ec('secp256k1'); 10 | 11 | assert(ec); 12 | assert(typeof ec === 'object'); 13 | }); 14 | 15 | it('should throw error with invalid curve', function() { 16 | assert.throws(function() { 17 | new elliptic.ec('nonexistent-curve'); 18 | }, Error); 19 | }); 20 | }); 21 | -------------------------------------------------------------------------------- /test/curve-test.js: -------------------------------------------------------------------------------- 1 | /* eslint-env node, mocha */ 2 | 'use strict'; 3 | 4 | var assert = require('assert'); 5 | var BN = require('bn.js'); 6 | var elliptic = require('../'); 7 | 8 | describe('Curve', function() { 9 | it('should work with example curve', function() { 10 | var curve = new elliptic.curve.short({ 11 | p: '1d', 12 | a: '4', 13 | b: '14', 14 | }); 15 | 16 | var p = curve.point('18', '16'); 17 | assert(p.validate()); 18 | assert(p.dbl().validate()); 19 | assert(p.dbl().add(p).validate()); 20 | assert(p.dbl().add(p.dbl()).validate()); 21 | assert(p.dbl().add(p.dbl()).eq(p.add(p).add(p).add(p))); 22 | }); 23 | 24 | it('should dbl points on edwards curve using proj coordinates', function() { 25 | var curve = new elliptic.curve.edwards({ 26 | p: new BN('97ffffffffffffffffffffffffffffffffffffffffffffffffffffffffff' + 27 | 'ffffffffffffffffffffffffffffffffff3f', 16, 'le'), 28 | q: new BN('19973cfd137ee273272d101b28695e7ce1ee951ef221fbd5ffffffffff' + 29 | 'ffffffffffffffffffffffffffffffffffff0f', 16, 'le'), 30 | r: '8', 31 | a: '1', 32 | c: '1', 33 | // -67254 mod p 34 | d: new BN('e1f8feffffffffffffffffffffffffffffffffffffffffffffffffff' + 35 | 'ffffffffffffffffffffffffffffffffffffff3f', 16, 'le'), 36 | g: [ 37 | new BN('0396f77094ccc0eb985310e8bc7d519311846453b8ba232935640b2b0' + 38 | '340f868ae208d6ee95bf0e59103b2ead08d6f19', 16, 'le'), 39 | new BN('11', 16, 'le'), 40 | ], 41 | }); 42 | 43 | var point = [ 44 | '21fd21b36cbdbe0d77ad8692c25d918774f5d3bc179c4cb0ae3c364bf1bea981d0' + 45 | '2e9f97cc62f20acacf0c553887e5fb', 46 | '29f994329799dba72aa12ceb06312300167b6e18fbed607c63709826c57292cf29' + 47 | 'f5bab4f5c99c739cf107a3833bb553', 48 | ]; 49 | 50 | var double = [ 51 | '0561c8722cf82b2f0d7c36bc72e34539dcbf181e8d98f5244480e79f5b51a4a541' + 52 | '457016c9c0509d49078eb5909a1121', 53 | '05b7812fae9d164ee9249c56a16e29a1ad2cdc6353227074dd96d59df363a0bcb5' + 54 | 'bc67d50b44843ea833156bdc0ac6a2', 55 | ]; 56 | 57 | var p = curve.pointFromJSON(point); 58 | var d = curve.pointFromJSON(double); 59 | assert(p.dbl().eq(d)); 60 | }); 61 | 62 | it('should be able to find a point given y coordinate for all edwards curves', 63 | function() { 64 | var curve = new elliptic.curve.edwards({ 65 | p: new BN('f7' + 66 | 'ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff07', 67 | 16, 'le'), 68 | q: new BN('71' + 69 | 'c966d15fd444893407d3dfc46579f7ffffffffffffffffffffffffffffff01', 70 | 16, 'le'), 71 | r: '4', 72 | a: '1', 73 | // -1174 mod p 74 | d: new BN('61' + 75 | 'fbffffffffffffffffffffffffffffffffffffffffffffffffffffffffff07', 76 | 16, 'le'), 77 | c: '1', 78 | }); 79 | 80 | var target = curve.point( 81 | '05d040ddaa645bf27d2d2f302c5697231425185fd9a410f220ac5c5c7fbeb8a1', 82 | '02f8ca771306cd23e929775177f2c213843a017a6487b2ec5f9b2a3808108ef2', 83 | ); 84 | 85 | var point = curve.pointFromY('02' + 86 | 'f8ca771306cd23e929775177f2c213843a017a6487b2ec5f9b2a3808108ef2'); 87 | assert(point.eq(target)); 88 | }); 89 | 90 | it('should find an odd point given a y coordinate', function() { 91 | var curve = new elliptic.curve.edwards({ 92 | p: '7fffffffffffffff ffffffffffffffff ffffffffffffffff ffffffffffffffed', 93 | a: '-1', 94 | c: '1', 95 | // -121665 * (121666^(-1)) (mod P) 96 | d: '52036cee2b6ffe73 8cc740797779e898 00700a4d4141d8ab 75eb4dca135978a3', 97 | n: '1000000000000000 0000000000000000 14def9dea2f79cd6 5812631a5cf5d3ed', 98 | gRed: false, 99 | g: [ 100 | '216936d3cd6e53fec0a4e231fdd6dc5c692cc7609525a7b2c9562d608f25d51a', 101 | 102 | // 4/5 103 | '6666666666666666666666666666666666666666666666666666666666666658', 104 | ], 105 | }); 106 | 107 | var bytes = new Uint8Array([ 5, 69, 248, 173, 171, 254, 19, 253, 143, 140, 146, 174, 26, 128, 3, 52, 106, 55, 112, 245, 62, 127, 42, 93, 0, 81, 47, 177, 30, 25, 39, 70 ]); 108 | var y = new BN(bytes, 16, 'le'); 109 | var point = curve.pointFromY(y, true); 110 | var target = '2cd591ae3789fd62dc420a152002f79973a387eacecadc6a9a00c1a89488c15d'; 111 | assert.deepStrictEqual(point.getX().toString(16), target); 112 | }); 113 | 114 | it('should work with secp112k1', function() { 115 | var curve = new elliptic.curve.short({ 116 | p: 'db7c 2abf62e3 5e668076 bead208b', 117 | a: 'db7c 2abf62e3 5e668076 bead2088', 118 | b: '659e f8ba0439 16eede89 11702b22', 119 | }); 120 | 121 | var p = curve.point( 122 | '0948 7239995a 5ee76b55 f9c2f098', 123 | 'a89c e5af8724 c0a23e0e 0ff77500'); 124 | assert(p.validate()); 125 | assert(p.dbl().validate()); 126 | }); 127 | 128 | it('should work with secp256k1', function() { 129 | var curve = new elliptic.curve.short({ 130 | p: 'ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff fffffffe ' + 131 | 'fffffc2f', 132 | a: '0', 133 | b: '7', 134 | n: 'ffffffff ffffffff ffffffff fffffffe ' + 135 | 'baaedce6 af48a03b bfd25e8c d0364141', 136 | g: [ 137 | '79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798', 138 | '483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8', 139 | ], 140 | }); 141 | 142 | var p = curve.point( 143 | '79be667e f9dcbbac 55a06295 ce870b07 029bfcdb 2dce28d9 59f2815b 16f81798', 144 | '483ada77 26a3c465 5da4fbfc 0e1108a8 fd17b448 a6855419 9c47d08f fb10d4b8', 145 | ); 146 | assert(p.validate()); 147 | assert(p.dbl().validate()); 148 | assert(p.toJ().dbl().toP().validate()); 149 | assert(p.mul(new BN('79be667e f9dcbbac 55a06295 ce870b07', 16)).validate()); 150 | 151 | var j = p.toJ(); 152 | assert(j.trpl().eq(j.dbl().add(j))); 153 | 154 | // Endomorphism test 155 | assert(curve.endo); 156 | assert.equal( 157 | curve.endo.beta.fromRed().toString(16), 158 | '7ae96a2b657c07106e64479eac3434e99cf0497512f58995c1396c28719501ee'); 159 | assert.equal( 160 | curve.endo.lambda.toString(16), 161 | '5363ad4cc05c30e0a5261c028812645a122e22ea20816678df02967c1b23bd72'); 162 | 163 | var k = new BN('1234567890123456789012345678901234', 16); 164 | var split = curve._endoSplit(k); 165 | 166 | var testK = split.k1.add(split.k2.mul(curve.endo.lambda)).umod(curve.n); 167 | assert.equal(testK.toString(16), k.toString(16)); 168 | }); 169 | 170 | it('should compute this problematic secp256k1 multiplication', function() { 171 | var curve = elliptic.curves.secp256k1.curve; 172 | var g1 = curve.g; // precomputed g 173 | assert(g1.precomputed); 174 | var g2 = curve.point(g1.getX(), g1.getY()); // not precomputed g 175 | assert(!g2.precomputed); 176 | var a = new BN( 177 | '6d1229a6b24c2e775c062870ad26bc261051e0198c67203167273c7c62538846', 16); 178 | var p1 = g1.mul(a); 179 | var p2 = g2.mul(a); 180 | assert(p1.eq(p2)); 181 | }); 182 | 183 | it('should not use fixed NAF when k is too large', function() { 184 | var curve = elliptic.curves.secp256k1.curve; 185 | var g1 = curve.g; // precomputed g 186 | assert(g1.precomputed); 187 | var g2 = curve.point(g1.getX(), g1.getY()); // not precomputed g 188 | assert(!g2.precomputed); 189 | 190 | var a = new BN( 191 | '6d1229a6b24c2e775c062870ad26bc26' + 192 | '1051e0198c67203167273c7c6253884612345678', 193 | 16); 194 | var p1 = g1.mul(a); 195 | var p2 = g2.mul(a); 196 | assert(p1.eq(p2)); 197 | }); 198 | 199 | it('should not fail on secp256k1 regression', function() { 200 | var curve = elliptic.curves.secp256k1.curve; 201 | var k1 = new BN( 202 | '32efeba414cd0c830aed727749e816a01c471831536fd2fce28c56b54f5a3bb1', 16); 203 | var k2 = new BN( 204 | '5f2e49b5d64e53f9811545434706cde4de528af97bfd49fde1f6cf792ee37a8c', 16); 205 | 206 | var p1 = curve.g.mul(k1); 207 | var p2 = curve.g.mul(k2); 208 | 209 | // 2 + 2 + 1 = 2 + 1 + 2 210 | var two = p2.dbl(); 211 | var five = two.dbl().add(p2); 212 | var three = two.add(p2); 213 | var maybeFive = three.add(two); 214 | 215 | assert(maybeFive.eq(five)); 216 | 217 | p1 = p1.mul(k2); 218 | p2 = p2.mul(k1); 219 | 220 | assert(p1.validate()); 221 | assert(p2.validate()); 222 | assert(p1.eq(p2)); 223 | }); 224 | 225 | it('should correctly double the affine point on secp256k1', function() { 226 | var bad = { 227 | x: '026a2073b1ef6fab47ace18e60e728a05180a82755bbcec9a0abc08ad9f7a3d4', 228 | y: '9cd8cb48c3281596139f147c1364a3ede88d3f310fdb0eb98c924e599ca1b3c9', 229 | z: 'd78587ad45e4102f48b54b5d85598296e069ce6085002e169c6bad78ddc6d9bd', 230 | }; 231 | 232 | var good = { 233 | x: 'e7789226739ac2eb3c7ccb2a9a910066beeed86cdb4e0f8a7fee8eeb29dc7016', 234 | y: '4b76b191fd6d47d07828ea965e275b76d0e3e0196cd5056d38384fbb819f9fcb', 235 | z: 'cbf8d99056618ba132d6145b904eee1ce566e0feedb9595139c45f84e90cfa7d', 236 | }; 237 | 238 | var curve = elliptic.curves.secp256k1.curve; 239 | bad = curve.jpoint(bad.x, bad.y, bad.z); 240 | good = curve.jpoint(good.x, good.y, good.z); 241 | 242 | // They are the same points 243 | assert(bad.add(good.neg()).isInfinity()); 244 | 245 | // But doubling borks them out 246 | assert(bad.dbl().add(good.dbl().neg()).isInfinity()); 247 | }); 248 | 249 | it('should store precomputed values correctly on negation', function() { 250 | var curve = elliptic.curves.secp256k1.curve; 251 | var p = curve.g.mul('2'); 252 | p.precompute(); 253 | var neg = p.neg(true); 254 | var neg2 = neg.neg(true); 255 | assert(p.eq(neg2)); 256 | }); 257 | 258 | it('should correctly handle scalar multiplication of zero', function() { 259 | var curve = elliptic.curves.secp256k1.curve; 260 | var p1 = curve.g.mul('0'); 261 | var p2 = p1.mul('2'); 262 | assert(p1.eq(p2)); 263 | }); 264 | }); 265 | 266 | describe('Point codec', function () { 267 | function makeShortTest(definition) { 268 | var curve = elliptic.curves.secp256k1.curve; 269 | 270 | return function() { 271 | var co = definition.coordinates; 272 | var p = curve.point(co.x, co.y); 273 | 274 | // Encodes as expected 275 | assert.equal(p.encode('hex'), definition.encoded); 276 | assert.equal(p.encodeCompressed('hex'), definition.compactEncoded); 277 | 278 | // Decodes as expected 279 | assert(curve.decodePoint(definition.encoded, 'hex').eq(p)); 280 | assert(curve.decodePoint(definition.compactEncoded, 'hex').eq(p)); 281 | assert(curve.decodePoint(definition.hybrid, 'hex').eq(p)); 282 | }; 283 | } 284 | 285 | function makeMontTest(definition) { 286 | var curve = elliptic.curves.curve25519.curve; 287 | 288 | return function() { 289 | var co = definition.coordinates; 290 | var p = curve.point(co.x, co.z); 291 | var encoded = p.encode('hex'); 292 | var decoded = curve.decodePoint(encoded, 'hex'); 293 | assert(decoded.eq(p)); 294 | assert.equal(encoded, definition.encoded); 295 | }; 296 | } 297 | 298 | var shortPointEvenY = { 299 | coordinates: { 300 | x: '79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798', 301 | y: '483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8', 302 | }, 303 | compactEncoded: 304 | '02' + 305 | '79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798', 306 | encoded: 307 | '04' + 308 | '79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798' + 309 | '483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8', 310 | hybrid: 311 | '06' + 312 | '79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798' + 313 | '483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8', 314 | }; 315 | 316 | var shortPointOddY = { 317 | coordinates: { 318 | x: 'fff97bd5755eeea420453a14355235d382f6472f8568a18b2f057a1460297556', 319 | y: 'ae12777aacfbb620f3be96017f45c560de80f0f6518fe4a03c870c36b075f297', 320 | }, 321 | compactEncoded: 322 | '03' + 323 | 'fff97bd5755eeea420453a14355235d382f6472f8568a18b2f057a1460297556', 324 | encoded: 325 | '04' + 326 | 'fff97bd5755eeea420453a14355235d382f6472f8568a18b2f057a1460297556' + 327 | 'ae12777aacfbb620f3be96017f45c560de80f0f6518fe4a03c870c36b075f297', 328 | hybrid: 329 | '07' + 330 | 'fff97bd5755eeea420453a14355235d382f6472f8568a18b2f057a1460297556' + 331 | 'ae12777aacfbb620f3be96017f45c560de80f0f6518fe4a03c870c36b075f297', 332 | }; 333 | 334 | it('should throw when trying to decode random bytes', function() { 335 | assert.throws(function() { 336 | elliptic.curves.secp256k1.curve.decodePoint( 337 | '05' + 338 | '79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798'); 339 | }); 340 | }); 341 | 342 | it('should be able to encode/decode a short curve point with even Y', 343 | makeShortTest(shortPointEvenY)); 344 | 345 | it('should be able to encode/decode a short curve point with odd Y', 346 | makeShortTest(shortPointOddY)); 347 | 348 | it('should be able to encode/decode a mont curve point', makeMontTest({ 349 | coordinates: { 350 | // curve25519.curve.g.mul(new BN('6')).getX().toString(16, 2) 351 | x: '26954ccdc99ebf34f8f1dde5e6bb080685fec73640494c28f9fe0bfa8c794531', 352 | z: '1', 353 | }, 354 | encoded: 355 | '26954ccdc99ebf34f8f1dde5e6bb080685fec73640494c28f9fe0bfa8c794531', 356 | })); 357 | }); 358 | -------------------------------------------------------------------------------- /test/ecdh-test.js: -------------------------------------------------------------------------------- 1 | /* eslint-env node, mocha */ 2 | 'use strict'; 3 | 4 | var assert = require('assert'); 5 | var elliptic = require('../'); 6 | 7 | describe('ECDH', function() { 8 | function test(name) { 9 | it('should work with ' + name + ' curve', function() { 10 | var ecdh = new elliptic.ec(name); 11 | var s1 = ecdh.genKeyPair(); 12 | var s2 = ecdh.genKeyPair(); 13 | var sh1 = s1.derive(s2.getPublic()); 14 | var sh2 = s2.derive(s1.getPublic()); 15 | 16 | assert.equal(sh1.toString(16), sh2.toString(16)); 17 | 18 | sh1 = s1.derive(ecdh.keyFromPublic(s2.getPublic('hex'), 'hex') 19 | .getPublic()); 20 | sh2 = s2.derive(ecdh.keyFromPublic(s1.getPublic('hex'), 'hex') 21 | .getPublic()); 22 | assert.equal(sh1.toString(16), sh2.toString(16)); 23 | }); 24 | } 25 | 26 | test('curve25519'); 27 | test('ed25519'); 28 | test('secp256k1'); 29 | }); 30 | 31 | describe('ECDH twist attack', () => { 32 | it('should be able to prevent a twist attack for secp256k1', () => { 33 | var bobEcdh = new elliptic.ec('secp256k1'); 34 | var malloryEcdh = new elliptic.ec('secp256k1'); 35 | var bob = bobEcdh.genKeyPair(); 36 | // This is a bad point that shouldn't be able to be passed to derive. 37 | // If a bad point can be passed it's possible to perform a twist attack. 38 | var mallory = malloryEcdh.keyFromPublic({ x: 14, y: 16 }); 39 | assert.throws(function () { 40 | bob.derive(mallory.getPublic()); 41 | }); 42 | }); 43 | }); 44 | -------------------------------------------------------------------------------- /test/ecdsa-test.js: -------------------------------------------------------------------------------- 1 | /* eslint-env node, mocha */ 2 | 'use strict'; 3 | 4 | var assert = require('assert'); 5 | var elliptic = require('../'); 6 | var Signature = require('../lib/elliptic/ec/signature'); 7 | var BN = require('bn.js'); 8 | var hash = require('hash.js'); 9 | 10 | var entropy = [ 11 | 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 12 | 21, 22, 23, 24, 25, 13 | ]; 14 | 15 | var msg = 'deadbeef'; 16 | 17 | describe('ECDSA', function() { 18 | function test(name) { 19 | describe('curve ' + name, function() { 20 | var curve; 21 | var ecdsa; 22 | var keys; 23 | 24 | beforeEach(function() { 25 | curve = elliptic.curves[name]; 26 | assert(curve); 27 | 28 | ecdsa = new elliptic.ec(curve); 29 | keys = ecdsa.genKeyPair({ 30 | entropy: entropy, 31 | }); 32 | }); 33 | 34 | it('should generate proper key pair', function() { 35 | var keylen = 64; 36 | if (name === 'p384') { 37 | keylen = 96; 38 | } else if (name === 'p521') { 39 | keylen = 132; 40 | } 41 | // Get keys out of pair 42 | assert(keys.getPublic().x && keys.getPublic().y); 43 | assert(keys.getPrivate().length > 0); 44 | assert.equal(keys.getPrivate('hex').length, keylen); 45 | assert(keys.getPublic('hex').length > 0); 46 | assert(keys.getPrivate('hex').length > 0); 47 | assert(keys.validate().result); 48 | }); 49 | 50 | it('should sign and verify', function() { 51 | var signature = ecdsa.sign(msg, keys); 52 | assert(ecdsa.verify(msg, signature, keys), 'Normal verify'); 53 | }); 54 | 55 | it('should sign and verify using key\'s methods', function() { 56 | var signature = keys.sign(msg); 57 | assert(keys.verify(msg, signature), 'On-key verify'); 58 | }); 59 | 60 | it('should load private key from the hex value', function() { 61 | var copy = ecdsa.keyFromPrivate(keys.getPrivate('hex'), 'hex'); 62 | var signature = ecdsa.sign(msg, copy); 63 | assert(ecdsa.verify(msg, signature, copy), 'hex-private verify'); 64 | }); 65 | 66 | it('should have `signature.s <= keys.ec.nh`', function() { 67 | // key.sign(msg, options) 68 | var sign = keys.sign('hello', { canonical: true }); 69 | assert(sign.s.cmp(keys.ec.nh) <= 0); 70 | }); 71 | 72 | it('should support `options.k`', function() { 73 | var sign = keys.sign(msg, { 74 | k: function(iter) { 75 | assert(iter >= 0); 76 | return new BN(1358); 77 | }, 78 | }); 79 | assert(ecdsa.verify(msg, sign, keys), 'custom-k verify'); 80 | }); 81 | 82 | it('should have another signature with pers', function () { 83 | var sign1 = keys.sign(msg); 84 | var sign2 = keys.sign(msg, { pers: '1234', persEnc: 'hex' }); 85 | assert.notEqual(sign1.r.toArray().concat(sign1.s.toArray()), 86 | sign2.r.toArray().concat(sign2.s.toArray())); 87 | }); 88 | 89 | it('should load public key from compact hex value', function() { 90 | var pub = keys.getPublic(true, 'hex'); 91 | var copy = ecdsa.keyFromPublic(pub, 'hex'); 92 | assert.equal(copy.getPublic(true, 'hex'), pub); 93 | }); 94 | 95 | it('should load public key from hex value', function() { 96 | var pub = keys.getPublic('hex'); 97 | var copy = ecdsa.keyFromPublic(pub, 'hex'); 98 | assert.equal(copy.getPublic('hex'), pub); 99 | }); 100 | 101 | it('should support hex DER encoding of signatures', function() { 102 | var signature = ecdsa.sign(msg, keys); 103 | var dsign = signature.toDER('hex'); 104 | assert(ecdsa.verify(msg, dsign, keys), 'hex-DER encoded verify'); 105 | }); 106 | 107 | it('should support DER encoding of signatures', function() { 108 | var signature = ecdsa.sign(msg, keys); 109 | var dsign = signature.toDER(); 110 | assert(ecdsa.verify(msg, dsign, keys), 'DER encoded verify'); 111 | }); 112 | 113 | it('should not verify signature with wrong public key', function() { 114 | var signature = ecdsa.sign(msg, keys); 115 | 116 | var wrong = ecdsa.genKeyPair(); 117 | assert(!ecdsa.verify(msg, signature, wrong), 'Wrong key verify'); 118 | }); 119 | 120 | it('should not verify signature with wrong private key', function() { 121 | var signature = ecdsa.sign(msg, keys); 122 | 123 | var wrong = ecdsa.keyFromPrivate(keys.getPrivate('hex') + 124 | keys.getPrivate('hex')); 125 | assert(!ecdsa.verify(msg, signature, wrong), 'Wrong key verify'); 126 | }); 127 | }); 128 | } 129 | test('secp256k1'); 130 | test('ed25519'); 131 | test('p256'); 132 | test('p384'); 133 | test('p521'); 134 | 135 | describe('RFC6979 vector', function() { 136 | function test(opt) { 137 | opt.cases.forEach(function(c) { 138 | var ecdsa = elliptic.ec({ 139 | curve: opt.curve, 140 | hash: c.hash, 141 | }); 142 | var descr = 'should not fail on "' + opt.name + '" ' + 143 | 'and hash ' + c.hash.name + ' on "' + c.message + '"'; 144 | it(descr, function() { 145 | var dgst = c.hash().update(c.message).digest(); 146 | var sign = ecdsa.sign(dgst, opt.key); 147 | assert.equal(sign.r.toString(16), c.r); 148 | assert.equal(sign.s.toString(16), c.s); 149 | assert.ok(ecdsa.keyFromPublic(opt.pub).validate().result, 150 | 'Invalid public key'); 151 | assert.ok(ecdsa.verify(dgst, sign, opt.pub), 152 | 'Invalid signature'); 153 | }); 154 | }); 155 | } 156 | 157 | test({ 158 | name: 'ECDSA, 192 Bits (Prime Field)', 159 | curve: elliptic.curves.p192, 160 | key: '6fab034934e4c0fc9ae67f5b5659a9d7d1fefd187ee09fd4', 161 | pub: { 162 | x: 'ac2c77f529f91689fea0ea5efec7f210d8eea0b9e047ed56', 163 | y: '3bc723e57670bd4887ebc732c523063d0a7c957bc97c1c43', 164 | }, 165 | cases: [ 166 | { 167 | message: 'sample', 168 | hash: hash.sha224, 169 | r: 'a1f00dad97aeec91c95585f36200c65f3c01812aa60378f5', 170 | s: 'e07ec1304c7c6c9debbe980b9692668f81d4de7922a0f97a', 171 | }, 172 | { 173 | message: 'sample', 174 | hash: hash.sha256, 175 | r: '4b0b8ce98a92866a2820e20aa6b75b56382e0f9bfd5ecb55', 176 | s: 'ccdb006926ea9565cbadc840829d8c384e06de1f1e381b85', 177 | }, 178 | { 179 | message: 'test', 180 | hash: hash.sha224, 181 | r: '6945a1c1d1b2206b8145548f633bb61cef04891baf26ed34', 182 | s: 'b7fb7fdfc339c0b9bd61a9f5a8eaf9be58fc5cba2cb15293', 183 | }, 184 | { 185 | message: 'test', 186 | hash: hash.sha256, 187 | r: '3a718bd8b4926c3b52ee6bbe67ef79b18cb6eb62b1ad97ae', 188 | s: '5662e6848a4a19b1f1ae2f72acd4b8bbe50f1eac65d9124f', 189 | }, 190 | ], 191 | }); 192 | 193 | test({ 194 | name: 'ECDSA, 224 Bits (Prime Field)', 195 | curve: elliptic.curves.p224, 196 | key: 'f220266e1105bfe3083e03ec7a3a654651f45e37167e88600bf257c1', 197 | pub: { 198 | x: '00cf08da5ad719e42707fa431292dea11244d64fc51610d94b130d6c', 199 | y: 'eeab6f3debe455e3dbf85416f7030cbd94f34f2d6f232c69f3c1385a', 200 | }, 201 | cases: [ 202 | { 203 | message: 'sample', 204 | hash: hash.sha224, 205 | r: '1cdfe6662dde1e4a1ec4cdedf6a1f5a2fb7fbd9145c12113e6abfd3e', 206 | s: 'a6694fd7718a21053f225d3f46197ca699d45006c06f871808f43ebc', 207 | }, 208 | { 209 | message: 'sample', 210 | hash: hash.sha256, 211 | r: '61aa3da010e8e8406c656bc477a7a7189895e7e840cdfe8ff42307ba', 212 | s: 'bc814050dab5d23770879494f9e0a680dc1af7161991bde692b10101', 213 | }, 214 | { 215 | message: 'test', 216 | hash: hash.sha224, 217 | r: 'c441ce8e261ded634e4cf84910e4c5d1d22c5cf3b732bb204dbef019', 218 | s: '902f42847a63bdc5f6046ada114953120f99442d76510150f372a3f4', 219 | }, 220 | { 221 | message: 'test', 222 | hash: hash.sha256, 223 | r: 'ad04dde87b84747a243a631ea47a1ba6d1faa059149ad2440de6fba6', 224 | s: '178d49b1ae90e3d8b629be3db5683915f4e8c99fdf6e666cf37adcfd', 225 | }, 226 | ], 227 | }); 228 | 229 | test({ 230 | name: 'ECDSA, 256 Bits (Prime Field)', 231 | curve: elliptic.curves.p256, 232 | key: 'c9afa9d845ba75166b5c215767b1d6934e50c3db36e89b127b8a622b120f6721', 233 | pub: { 234 | x: '60fed4ba255a9d31c961eb74c6356d68c049b8923b61fa6ce669622e60f29fb6', 235 | y: '7903fe1008b8bc99a41ae9e95628bc64f2f1b20c2d7e9f5177a3c294d4462299', 236 | }, 237 | cases: [ 238 | { 239 | message: 'sample', 240 | hash: hash.sha224, 241 | r: '53b2fff5d1752b2c689df257c04c40a587fababb3f6fc2702f1343af7ca9aa3f', 242 | s: 'b9afb64fdc03dc1a131c7d2386d11e349f070aa432a4acc918bea988bf75c74c', 243 | }, 244 | { 245 | message: 'sample', 246 | hash: hash.sha256, 247 | r: 'efd48b2aacb6a8fd1140dd9cd45e81d69d2c877b56aaf991c34d0ea84eaf3716', 248 | s: 'f7cb1c942d657c41d436c7a1b6e29f65f3e900dbb9aff4064dc4ab2f843acda8', 249 | }, 250 | { 251 | message: 'test', 252 | hash: hash.sha224, 253 | r: 'c37edb6f0ae79d47c3c27e962fa269bb4f441770357e114ee511f662ec34a692', 254 | s: 'c820053a05791e521fcaad6042d40aea1d6b1a540138558f47d0719800e18f2d', 255 | }, 256 | { 257 | message: 'test', 258 | hash: hash.sha256, 259 | r: 'f1abb023518351cd71d881567b1ea663ed3efcf6c5132b354f28d3b0b7d38367', 260 | s: '19f4113742a2b14bd25926b49c649155f267e60d3814b4c0cc84250e46f0083', 261 | }, 262 | ], 263 | }); 264 | 265 | test({ 266 | name: 'ECDSA, 384 Bits (Prime Field)', 267 | curve: elliptic.curves.p384, 268 | key: '6b9d3dad2e1b8c1c05b19875b6659f4de23c3b667bf297ba9aa4774078713' + 269 | '7d896d5724e4c70a825f872c9ea60d2edf5', 270 | pub: { 271 | x: 'ec3a4e415b4e19a4568618029f427fa5da9a8bc4ae92e02e06aae5286b30' + 272 | '0c64def8f0ea9055866064a254515480bc13', 273 | y: '8015d9b72d7d57244ea8ef9ac0c621896708a59367f9dfb9f54ca84b3f' + 274 | '1c9db1288b231c3ae0d4fe7344fd2533264720', 275 | }, 276 | cases: [ 277 | { 278 | message: 'sample', 279 | hash: hash.sha224, 280 | r: '42356e76b55a6d9b4631c865445dbe54e056d3b3431766d05092447' + 281 | '93c3f9366450f76ee3de43f5a125333a6be060122', 282 | s: '9da0c81787064021e78df658f2fbb0b042bf304665db721f077a429' + 283 | '8b095e4834c082c03d83028efbf93a3c23940ca8d', 284 | }, 285 | { 286 | message: 'sample', 287 | hash: hash.sha384, 288 | r: '94edbb92a5ecb8aad4736e56c691916b3f88140666ce9fa73d6' + 289 | '4c4ea95ad133c81a648152e44acf96e36dd1e80fabe46', 290 | s: '99ef4aeb15f178cea1fe40db2603138f130e740a19624526203b' + 291 | '6351d0a3a94fa329c145786e679e7b82c71a38628ac8', 292 | }, 293 | { 294 | message: 'test', 295 | hash: hash.sha384, 296 | r: '8203b63d3c853e8d77227fb377bcf7b7b772e97892a80f36a' + 297 | 'b775d509d7a5feb0542a7f0812998da8f1dd3ca3cf023db', 298 | s: 'ddd0760448d42d8a43af45af836fce4de8be06b485e9b61b827c2f13' + 299 | '173923e06a739f040649a667bf3b828246baa5a5', 300 | }, 301 | ], 302 | }); 303 | 304 | test({ 305 | name: 'ECDSA, 521 Bits (Prime Field)', 306 | curve: elliptic.curves.p521, 307 | key: '0fad06daa62ba3b25d2fb40133da757205de67f5bb0018fee8c86e1b68c7e75' + 308 | 'caa896eb32f1f47c70855836a6d16fcc1466f6d8fbec67db89ec0c08b0e996b' + 309 | '83538', 310 | pub: { 311 | x: '1894550d0785932e00eaa23b694f213f8c3121f86dc97a04e5a7167db4e5bcd3' + 312 | '71123d46e45db6b5d5370a7f20fb633155d38ffa16d2bd761dcac474b9a2f502' + 313 | '3a4', 314 | y: '0493101c962cd4d2fddf782285e64584139c2f91b47f87ff82354d6630f746a2' + 315 | '8a0db25741b5b34a828008b22acc23f924faafbd4d33f81ea66956dfeaa2bfdfcf5', 316 | }, 317 | cases: [ 318 | { 319 | message: 'sample', 320 | hash: hash.sha384, 321 | r: '1ea842a0e17d2de4f92c15315c63ddf72685c18195c2bb95e572b9c5136ca4' + 322 | 'b4b576ad712a52be9730627d16054ba40cc0b8d3ff035b12ae75168397f5' + 323 | 'd50c67451', 324 | s: '1f21a3cee066e1961025fb048bd5fe2b7924d0cd797babe0a83b66f1e35ee' + 325 | 'af5fde143fa85dc394a7dee766523393784484bdf3e00114a1c857cde1aa2' + 326 | '03db65d61', 327 | }, 328 | { 329 | message: 'sample', 330 | hash: hash.sha512, 331 | r: 'c328fafcbd79dd77850370c46325d987cb525569fb63c5d3bc53950e6d4c5f1' + 332 | '74e25a1ee9017b5d450606add152b534931d7d4e8455cc91f9b15bf05ec36e3' + 333 | '77fa', 334 | s: '617cce7cf5064806c467f678d3b4080d6f1cc50af26ca209417308281b68af2' + 335 | '82623eaa63e5b5c0723d8b8c37ff0777b1a20f8ccb1dccc43997f1ee0e44da4' + 336 | 'a67a', 337 | }, 338 | { 339 | message: 'test', 340 | hash: hash.sha512, 341 | r: '13e99020abf5cee7525d16b69b229652ab6bdf2affcaef38773b4b7d087' + 342 | '25f10cdb93482fdcc54edcee91eca4166b2a7c6265ef0ce2bd7051b7cef945' + 343 | 'babd47ee6d', 344 | s: '1fbd0013c674aa79cb39849527916ce301c66ea7ce8b80682786ad60f98' + 345 | 'f7e78a19ca69eff5c57400e3b3a0ad66ce0978214d13baf4e9ac60752f7b15' + 346 | '5e2de4dce3', 347 | }, 348 | ], 349 | }); 350 | }); 351 | 352 | describe('Maxwell\'s trick', function() { 353 | var p256 = elliptic.curves.p256; 354 | assert(p256); 355 | var p384 = elliptic.curves.p384; 356 | assert(p384); 357 | 358 | var msg = 359 | 'e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855'; 360 | 361 | var vectors = [ 362 | { 363 | curve: p256, 364 | pub: '041548fc88953e06cd34d4b300804c5322cb48c24aaaa4d0' + 365 | '7a541b0f0ccfeedeb0ae4991b90519ea405588bdf699f5e6' + 366 | 'd0c6b2d5217a5c16e8371062737aa1dae1', 367 | message: msg, 368 | sig: '3006020106020104', 369 | result: true, 370 | }, 371 | { 372 | curve: p256, 373 | pub: '04ad8f60e4ec1ebdb6a260b559cb55b1e9d2c5ddd43a41a2' + 374 | 'd11b0741ef2567d84e166737664104ebbc337af3d861d352' + 375 | '4cfbc761c12edae974a0759750c8324f9a', 376 | message: msg, 377 | sig: '3006020106020104', 378 | result: true, 379 | }, 380 | { 381 | curve: p256, 382 | pub: '0445bd879143a64af5746e2e82aa65fd2ea07bba4e355940' + 383 | '95a981b59984dacb219d59697387ac721b1f1eccf4b11f43' + 384 | 'ddc39e8367147abab3084142ed3ea170e4', 385 | message: msg, 386 | sig: '301502104319055358e8617b0c46353d039cdaae020104', 387 | result: true, 388 | }, 389 | { 390 | curve: p256, 391 | pub: '040feb5df4cc78b35ec9c180cc0de5842f75f088b4845697' + 392 | '8ffa98e716d94883e1e6500b2a1f6c1d9d493428d7ae7d9a' + 393 | '8a560fff30a3d14aa160be0c5e7edcd887', 394 | message: msg, 395 | sig: '301502104319055358e8617b0c46353d039cdaae020104', 396 | result: false, 397 | }, 398 | { 399 | curve: p384, 400 | pub: '0425e299eea9927b39fa92417705391bf17e8110b4615e9e' + 401 | 'b5da471b57be0c30e7d89dbdc3e5da4eae029b300344d385' + 402 | '1548b59ed8be668813905105e673319d59d32f574e180568' + 403 | '463c6186864888f6c0b67b304441f82aab031279e48f047c31', 404 | message: msg, 405 | sig: '3006020103020104', 406 | result: true, 407 | }, 408 | { 409 | curve: p384, 410 | pub: '04a328f65c22307188b4af65779c1d2ec821c6748c6bd8dc' + 411 | '0e6a008135f048f832df501f7f3f79966b03d5bef2f187ec' + 412 | '34d85f6a934af465656fb4eea8dd9176ab80fbb4a27a649f' + 413 | '526a7dfe616091b78d293552bc093dfde9b31cae69d51d3afb', 414 | message: msg, 415 | sig: '3006020103020104', 416 | result: true, 417 | }, 418 | { 419 | curve: p384, 420 | pub: '04242e8585eaa7a28cc6062cab4c9c5fd536f46b17be1728' + 421 | '288a2cda5951df4941aed1d712defda023d10aca1c5ee014' + 422 | '43e8beacd821f7efa27847418ab95ce2c514b2b6b395ee73' + 423 | '417c83dbcad631421f360d84d64658c98a62d685b220f5aad4', 424 | message: msg, 425 | sig: '301d0218389cb27e0bc8d21fa7e5f24cb74f58851313e696333ad68e020104', 426 | result: true, 427 | }, 428 | { 429 | curve: p384, 430 | pub: '04cdf865dd743fe1c23757ec5e65fd5e4038b472ded2af26' + 431 | '1e3d8343c595c8b69147df46379c7ca40e60e80170d34a11' + 432 | '88dbb2b6f7d3934c23d2f78cfb0db3f3219959fad63c9b61' + 433 | '2ef2f20d679777b84192ce86e781c14b1bbb77eacd6e0520e2', 434 | message: msg, 435 | sig: '301d0218389cb27e0bc8d21fa7e5f24cb74f58851313e696333ad68e020104', 436 | result: false, 437 | }, 438 | ]; 439 | 440 | vectors.forEach(function(vector, i) { 441 | it('should pass on vector#' + i, function() { 442 | var ecdsa = new elliptic.ec(vector.curve); 443 | var key = ecdsa.keyFromPublic(vector.pub, 'hex'); 444 | var msg = vector.message; 445 | var sig = vector.sig; 446 | 447 | var actual = ecdsa.verify(msg, sig, key); 448 | assert.equal(actual, vector.result); 449 | }); 450 | }); 451 | }); 452 | 453 | it('should deterministically generate private key', function() { 454 | var curve = elliptic.curves.secp256k1; 455 | assert(curve); 456 | 457 | var ecdsa = new elliptic.ec(curve); 458 | var keys = ecdsa.genKeyPair({ 459 | pers: 'my.pers.string', 460 | entropy: hash.sha256().update('hello world').digest(), 461 | }); 462 | assert.equal( 463 | keys.getPrivate('hex'), 464 | '6160edb2b218b7f1394b9ca8eb65a72831032a1f2f3dc2d99291c2f7950ed887'); 465 | }); 466 | 467 | it('should recover the public key from a signature', function() { 468 | var ec = new elliptic.ec('secp256k1'); 469 | var key = ec.genKeyPair(); 470 | var msg = [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ]; 471 | var signature = key.sign(msg); 472 | var recid = ec.getKeyRecoveryParam(msg, signature, key.getPublic()); 473 | var r = ec.recoverPubKey(msg, signature, recid); 474 | assert(key.getPublic().eq(r), 'the keys should match'); 475 | }); 476 | 477 | it('should fail to recover key when no quadratic residue available', 478 | function() { 479 | var ec = new elliptic.ec('secp256k1'); 480 | 481 | var message = 482 | 'f75c6b18a72fabc0f0b888c3da58e004f0af1fe14f7ca5d8c897fe164925d5e9'; 483 | 484 | assert.throws(function() { 485 | ec.recoverPubKey(message, { 486 | r: 'fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364140', 487 | s: '8887321be575c8095f789dd4c743dfe42c1820f9231f98a962b210e3ac2452a3', 488 | }, 0); 489 | }); 490 | }); 491 | 492 | it('Wycheproof special hash case with hex', function() { 493 | var curve = new elliptic.ec('p192'); 494 | var msg = 495 | '00000000690ed426ccf17803ebe2bd0884bcd58a1bb5e7477ead3645f356e7a9'; 496 | var sig = '303502186f20676c0d04fc40ea55d5702f798355787363a9' + 497 | '1e97a7e50219009d1c8c171b2b02e7d791c204c17cea4cf5' + 498 | '56a2034288885b'; 499 | var pub = '04cd35a0b18eeb8fcd87ff019780012828745f046e785deb' + 500 | 'a28150de1be6cb4376523006beff30ff09b4049125ced29723'; 501 | var pubKey = curve.keyFromPublic(pub, 'hex'); 502 | assert(pubKey.verify(msg, sig) === true); 503 | }); 504 | 505 | it('Wycheproof special hash case with Array', function() { 506 | var curve = new elliptic.ec('p192'); 507 | var msg = [ 508 | 0x00, 0x00, 0x00, 0x00, 0x69, 0x0e, 0xd4, 0x26, 0xcc, 0xf1, 0x78, 509 | 0x03, 0xeb, 0xe2, 0xbd, 0x08, 0x84, 0xbc, 0xd5, 0x8a, 0x1b, 0xb5, 510 | 0xe7, 0x47, 0x7e, 0xad, 0x36, 0x45, 0xf3, 0x56, 0xe7, 0xa9, 511 | ]; 512 | var sig = '303502186f20676c0d04fc40ea55d5702f798355787363a9' + 513 | '1e97a7e50219009d1c8c171b2b02e7d791c204c17cea4cf5' + 514 | '56a2034288885b'; 515 | var pub = '04cd35a0b18eeb8fcd87ff019780012828745f046e785deb' + 516 | 'a28150de1be6cb4376523006beff30ff09b4049125ced29723'; 517 | var pubKey = curve.keyFromPublic(pub, 'hex'); 518 | assert(pubKey.verify(msg, sig) === true); 519 | }); 520 | 521 | it('Wycheproof special hash case with BN', function() { 522 | var curve = new elliptic.ec('p192'); 523 | var msg = new BN( 524 | '00000000690ed426ccf17803ebe2bd0884bcd58a1bb5e7477ead3645f356e7a9', 525 | 16, 526 | ); 527 | var sig = '303502186f20676c0d04fc40ea55d5702f798355787363a9' + 528 | '1e97a7e50219009d1c8c171b2b02e7d791c204c17cea4cf5' + 529 | '56a2034288885b'; 530 | var pub = '04cd35a0b18eeb8fcd87ff019780012828745f046e785deb' + 531 | 'a28150de1be6cb4376523006beff30ff09b4049125ced29723'; 532 | var pubKey = curve.keyFromPublic(pub, 'hex'); 533 | assert(pubKey.verify(msg, sig, { msgBitLength: 32 * 8 }) === true); 534 | }); 535 | 536 | describe('Signature', function () { 537 | it('recoveryParam is 0', function () { 538 | var sig = new Signature({ r: '00', s: '00', recoveryParam: 0 }); 539 | assert.equal(sig.recoveryParam, 0); 540 | }); 541 | 542 | it('recoveryParam is 1', function () { 543 | var sig = new Signature({ r: '00', s: '00', recoveryParam: 1 }); 544 | assert.equal(sig.recoveryParam, 1); 545 | }); 546 | }); 547 | }); 548 | -------------------------------------------------------------------------------- /test/ed25519-test.js: -------------------------------------------------------------------------------- 1 | /* eslint-env node, mocha */ 2 | 'use strict'; 3 | 4 | var assert = require('assert'); 5 | var elliptic = require('../'); 6 | var utils = elliptic.utils; 7 | var toArray = elliptic.utils.toArray; 8 | var eddsa = elliptic.eddsa; 9 | 10 | function toHex(arr) { 11 | return elliptic.utils.toHex(arr).toUpperCase(); 12 | } 13 | 14 | var MAX_PROGRAMMATIC = process.env.CI ? Infinity : 50; 15 | 16 | describe('ed25519 derivations', function() { 17 | var expectedTests = 256; 18 | var ed25519; 19 | var derivations; 20 | 21 | before(function() { 22 | ed25519 = new eddsa('ed25519'); 23 | derivations = require('./fixtures/derivation-fixtures'); 24 | assert.equal(derivations.length, expectedTests); 25 | }); 26 | 27 | function testFactory(i) { 28 | it('can compute correct a and A for secret: ' + i, function() { 29 | var test = derivations[i]; 30 | var secret = utils.toArray(test.secret_hex, 'hex'); 31 | var key = ed25519.keyFromSecret(secret); 32 | assert.equal(toHex(key.privBytes()), test.a_hex); 33 | var xRecovered = toHex(ed25519.encodeInt( 34 | ed25519.decodePoint(key.pubBytes()).getX())); 35 | assert.equal(xRecovered, test.A_P.x); 36 | assert.equal(toHex(key.pubBytes()), test.A_hex); 37 | }); 38 | } 39 | 40 | for (var i = 0; i < Math.min(expectedTests, MAX_PROGRAMMATIC); i++) 41 | testFactory(i); 42 | }); 43 | 44 | describe('sign.input ed25519 test vectors', function() { 45 | var expectedTests = 1024; 46 | var ed25519; 47 | var lines; 48 | 49 | before(function(done) { 50 | ed25519 = new eddsa('ed25519'); 51 | require('fs').readFile(__dirname + '/fixtures/sign.input', function(err, f) { 52 | lines = f.toString().split('\n'); 53 | assert.equal(lines.length, expectedTests + 1 /*blank line*/); 54 | done(); 55 | }); 56 | }); 57 | 58 | function testFactory(i) { 59 | it('vector ' + i, function() { 60 | var split = lines[i].toUpperCase().split(':'); 61 | var key = ed25519.keyFromSecret(split[0].slice(0, 64)); 62 | var expectedPk = split[0].slice(64); 63 | 64 | assert.equal(toHex(key.pubBytes()), expectedPk); 65 | 66 | var msg = toArray(split[2], 'hex'); 67 | var sig = key.sign(msg).toHex(); 68 | var sigR = sig.slice(0, 64); 69 | var sigS = sig.slice(64); 70 | 71 | assert.equal(sigR, split[3].slice(0, 64)); 72 | assert.equal(sigS, split[3].slice(64, 128)); 73 | assert(key.verify(msg, sig)); 74 | 75 | var forged = msg.length === 0 ? [ 0x78 ] /*ord('x')*/: 76 | msg.slice(0, msg.length - 1).concat( 77 | (msg[(msg.length - 1)] + 1) % 256); 78 | 79 | assert.equal(msg.length || 1, forged.length); 80 | assert(!key.verify(forged, sig)); 81 | }); 82 | } 83 | for (var i = 0; i < Math.min(expectedTests, MAX_PROGRAMMATIC); i++) 84 | testFactory(i); 85 | }); 86 | 87 | describe('EDDSA(\'ed25519\')', function() { 88 | var ed25519; 89 | 90 | before(function() { 91 | ed25519 = new eddsa('ed25519'); 92 | }); 93 | 94 | it('has encodingLength of 32', function() { 95 | assert.equal(32, ed25519.encodingLength); 96 | }); 97 | 98 | it('can sign/verify messages', function() { 99 | var secret = toArray(new Array(65).join('0'), 'hex'); 100 | assert(secret.length === 32); 101 | var msg = [ 0xB, 0xE, 0xE, 0xF ]; 102 | var key = ed25519.keyFromSecret(secret); 103 | var sig = key.sign(msg).toHex(); 104 | 105 | var R = '8F1B9A7FDB22BCD2C15D4695B1CE2B063CBFAEC9B00BE360427BAC9533943F6C'; 106 | var S = '5F0B380FD7F2E43B70AB2FA29F6C6E3FFC1012710E174786814012324BF19B0C'; 107 | 108 | assert.equal(sig.slice(0, 64), R); 109 | assert.equal(sig.slice(64), S); 110 | 111 | assert(key.verify(msg, sig)); 112 | }); 113 | 114 | describe('KeyPair', function() { 115 | var pair; 116 | var secret = '00000000000000000000000000000000' + 117 | '00000000000000000000000000000000'; 118 | 119 | before(function() { 120 | pair = ed25519.keyFromSecret(secret); 121 | }); 122 | 123 | it('can be created with keyFromSecret/keyFromPublic', function() { 124 | var pubKey = ed25519.keyFromPublic(toHex(pair.pubBytes())); 125 | assert(pubKey.pub() instanceof ed25519.pointClass); 126 | assert(pubKey.pub().eq(pair.pub())); 127 | }); 128 | it('#getSecret returns bytes with optional encoding', function() { 129 | assert(Array.isArray(pair.getSecret())); 130 | assert(pair.getSecret('hex') === secret); 131 | }); 132 | it('#getPub returns bytes with optional encoding', function() { 133 | assert(Array.isArray(pair.getPublic())); 134 | assert.equal(pair.getPublic('hex'), 135 | '3b6a27bcceb6a42d62a3a8d02a6f0d73653215771de243a63ac048a18b59da29'); 136 | }); 137 | }); 138 | }); 139 | -------------------------------------------------------------------------------- /test/index.js: -------------------------------------------------------------------------------- 1 | /* eslint-env node, mocha */ 2 | 'use strict'; 3 | 4 | describe('Test specs', function () { 5 | require('./api-test.js'); 6 | require('./curve-test.js'); 7 | require('./ecdh-test.js'); 8 | require('./ecdsa-test.js'); 9 | require('./ed25519-test.js'); 10 | }); 11 | -------------------------------------------------------------------------------- /test/unittests.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | scrypt-async Unit Tests 6 | 7 | 8 | 9 |
10 | 11 | 15 | 16 | 38 | 39 | 40 | --------------------------------------------------------------------------------