├── .gitignore ├── .jscsrc ├── .jshintrc ├── .travis.yml ├── CONTRIBUTING.md ├── Gruntfile.js ├── LICENSE ├── README.md ├── build ├── components_concat.js ├── curve25519_compiled.js ├── curve25519_concat.js ├── dcodeIO.js ├── protoText.js ├── protobufs_concat.js ├── test_lib.js └── test_main.js ├── dist └── libsignal.js ├── native ├── curve25519-donna.c └── ed25519 │ ├── additions │ ├── compare.c │ ├── compare.h │ ├── curve_sigs.c │ ├── curve_sigs.h │ ├── sha512.c │ ├── sha512.h │ └── sign_modified.c │ ├── api.h │ ├── base.h │ ├── base2.h │ ├── d.h │ ├── d2.h │ ├── fe.h │ ├── fe_0.c │ ├── fe_1.c │ ├── fe_add.c │ ├── fe_cmov.c │ ├── fe_copy.c │ ├── fe_frombytes.c │ ├── fe_invert.c │ ├── fe_isnegative.c │ ├── fe_isnonzero.c │ ├── fe_mul.c │ ├── fe_neg.c │ ├── fe_pow22523.c │ ├── fe_sq.c │ ├── fe_sq2.c │ ├── fe_sub.c │ ├── fe_tobytes.c │ ├── ge.h │ ├── ge_add.c │ ├── ge_add.h │ ├── ge_double_scalarmult.c │ ├── ge_frombytes.c │ ├── ge_madd.c │ ├── ge_madd.h │ ├── ge_msub.c │ ├── ge_msub.h │ ├── ge_p1p1_to_p2.c │ ├── ge_p1p1_to_p3.c │ ├── ge_p2_0.c │ ├── ge_p2_dbl.c │ ├── ge_p2_dbl.h │ ├── ge_p3_0.c │ ├── ge_p3_dbl.c │ ├── ge_p3_to_cached.c │ ├── ge_p3_to_p2.c │ ├── ge_p3_tobytes.c │ ├── ge_precomp_0.c │ ├── ge_scalarmult_base.c │ ├── ge_sub.c │ ├── ge_sub.h │ ├── ge_tobytes.c │ ├── main │ └── main.c │ ├── nacl_includes │ ├── crypto_hash_sha512.h │ ├── crypto_int32.h │ ├── crypto_int64.h │ ├── crypto_sign.h │ ├── crypto_sign_edwards25519sha512batch.h │ ├── crypto_uint32.h │ ├── crypto_uint64.h │ └── crypto_verify_32.h │ ├── open.c │ ├── pow22523.h │ ├── pow225521.h │ ├── sc.h │ ├── sc_muladd.c │ ├── sc_reduce.c │ ├── sha512 │ ├── LICENSE.txt │ ├── md_helper.c │ ├── sha2big.c │ ├── sph_sha2.h │ └── sph_types.h │ ├── sign.c │ └── sqrtm1.h ├── package.json ├── protos └── WhisperTextProtocol.proto ├── src ├── BaseKeyType.js ├── ChainType.js ├── Curve.js ├── KeyHelper.js ├── NumericFingerprint.js ├── SessionBuilder.js ├── SessionCipher.js ├── SessionLock.js ├── SessionRecord.js ├── SignalProtocolAddress.js ├── crypto.js ├── curve25519_worker.js ├── curve25519_worker_manager.js ├── curve25519_wrapper.js ├── curve_work_routine.js ├── helpers.js ├── main.js ├── main_window.js ├── node_polyfills.js └── protobufs.js └── test ├── IdentityKeyStore_test.js ├── InMemorySignalProtocolStore.js ├── IntegrationTest.js ├── KeyHelperTest.js ├── NumericFingerprintTest.js ├── PreKeyStore_test.js ├── SessionBuilderTest.js ├── SessionCipherTest.js ├── SessionStore_test.js ├── SignalProtocolAddressTest.js ├── SignalProtocolStore_test.js ├── SignedPreKeyStore_test.js ├── _test.js ├── crypto_test.js ├── helpers_test.js ├── index.html ├── long-plaintext.json ├── main.js ├── protos ├── temp_helpers.js ├── test_helpers.js └── testvectors.js /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | -------------------------------------------------------------------------------- /.jscsrc: -------------------------------------------------------------------------------- 1 | { 2 | "disallowMixedSpacesAndTabs": true, 3 | "disallowTrailingWhitespace": true, 4 | "disallowNewlineBeforeBlockStatements": true, 5 | "requireCommaBeforeLineBreak": true, 6 | "requireSemicolons": true, 7 | "requireSpaceBeforeBlockStatements": true, 8 | "disallowSpacesInNamedFunctionExpression": { 9 | "beforeOpeningRoundBrace": true 10 | }, 11 | "requireSpacesInNamedFunctionExpression": { 12 | "beforeOpeningCurlyBrace": true 13 | }, 14 | "requireCurlyBraces": [ 15 | "if", 16 | "else", 17 | "for", 18 | "while", 19 | "do", 20 | "try", 21 | "catch" 22 | ], 23 | "requireSpaceAfterKeywords": [ 24 | "if", 25 | "else", 26 | "for", 27 | "while", 28 | "case", 29 | "try", 30 | "typeof", 31 | "return" 32 | ] 33 | } 34 | -------------------------------------------------------------------------------- /.jshintrc: -------------------------------------------------------------------------------- 1 | { 2 | "maxerr" : 50, 3 | "bitwise" : false, 4 | "camelcase" : false, 5 | "curly" : false, 6 | "eqeqeq" : false, 7 | "forin" : false, 8 | "freeze" : false, 9 | "immed" : false, 10 | "indent" : 4, 11 | "latedef" : false, 12 | "newcap" : false, 13 | "noarg" : false, 14 | "noempty" : false, 15 | "nonbsp" : false, 16 | "nonew" : false, 17 | "plusplus" : false, 18 | "quotmark" : false, 19 | "undef" : false, 20 | "unused" : false, 21 | "strict" : false, 22 | "maxparams" : false, 23 | "maxdepth" : false, 24 | "maxstatements" : false, 25 | "maxcomplexity" : false, 26 | "maxlen" : false, 27 | "asi" : false, 28 | "boss" : false, 29 | "debug" : false, 30 | "eqnull" : false, 31 | "es5" : false, 32 | "esnext" : false, 33 | "moz" : false, 34 | "evil" : false, 35 | "expr" : false, 36 | "funcscope" : false, 37 | "globalstrict" : false, 38 | "iterator" : false, 39 | "lastsemic" : false, 40 | "laxbreak" : false, 41 | "laxcomma" : false, 42 | "loopfunc" : false, 43 | "multistr" : false, 44 | "noyield" : false, 45 | "notypeof" : false, 46 | "proto" : true, 47 | "scripturl" : false, 48 | "shadow" : false, 49 | "sub" : false, 50 | "supernew" : false, 51 | "validthis" : false, 52 | "browser" : true, 53 | "browserify" : false, 54 | "couch" : false, 55 | "devel" : false, 56 | "dojo" : false, 57 | "jasmine" : false, 58 | "jquery" : false, 59 | "mocha" : false, 60 | "mootools" : false, 61 | "node" : false, 62 | "nonstandard" : false, 63 | "prototypejs" : false, 64 | "qunit" : false, 65 | "rhino" : false, 66 | "shelljs" : false, 67 | "worker" : false, 68 | "wsh" : false, 69 | "yui" : false, 70 | "node" : true, 71 | "globals" : { 72 | "Promise" : true 73 | } 74 | } -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | dist: trusty 3 | node_js: 4 | - "6" 5 | - "5" 6 | # - "4" 7 | install: 8 | - npm install 9 | script: 10 | - grunt mochaTest 11 | # env: 12 | # - CXX=clang 13 | # addons: 14 | # apt: 15 | # sources: 16 | # - ubuntu-toolchain-r-test 17 | # - llvm-toolchain-precise-3.6 18 | # packages: 19 | # - g++-4.8 20 | # - llvm-3.6 21 | # - libstdc++-4.9-dev 22 | # - llvm-3.6-dev 23 | # - clang-3.6 24 | 25 | # compiler: clang 26 | # os: 27 | # - linux 28 | # - osx 29 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing 2 | 3 | Thank you for contributing! 4 | 5 | 6 | ## Getting started 7 | 8 | To compile curve25519 from C souce files in `/native`, install 9 | [emscripten](https://kripken.github.io/emscripten-site/docs/getting_started/downloads.html). 10 | Theen, build all the assets with 11 | 12 | ``` 13 | grunt build 14 | ``` 15 | 16 | ## Code structure 17 | 18 | The source is organized like this: 19 | 20 | ``` 21 | /dist # Distributables 22 | /build # Intermediate build files 23 | /src # JS source files 24 | /native # C source files for curve25519 25 | /protos # Protobuf definitions 26 | /test # Tests 27 | ``` 28 | 29 | The main app entrypoint is `src/main.js`. This is what the caller would require in node, or bundle in browserify (though see note below, Node/browser polyfills). 30 | 31 | The main test entrypoint is `test/main.js`. 32 | `test/index.html` compiles everything we need for our tests in the browser. 33 | 34 | ## Testing 35 | 36 | You can run these by serving the project root and visiting /test (e.g. http://localhost:8000/test). 37 | 38 | For the full CI experience, you will need an account with 39 | [Sauce Labs](https://saucelabs.com). Get your username and API key, 40 | then set the appropriate envirionment variables to run the tests: 41 | 42 | ```sh 43 | SAUCE_USERNAME="your-sauce-username" SAUCE_ACCESS_KEY="your-sauce-key" grunt test 44 | ``` 45 | ## Browser requirements 46 | 47 | This implementation currently depends on the presence of the following 48 | types/interfaces, which are available in most modern browsers. 49 | 50 | * [ArrayBuffer](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/ArrayBuffer) 51 | * [TypedArray](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/TypedArray) 52 | * [Promise](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise) 53 | * [WebCrypto](https://developer.mozilla.org/en-US/docs/Web/API/Crypto) with support for: 54 | - AES-CBC 55 | - HMAC SHA-256 56 | 57 | 58 | ## Node/browser polyfills 59 | 60 | There are 2 node polyfills for browser stuff, one in `src/crypto.js` and one in `src/curve25519_worker_manager.js` 61 | Just search the source for: 62 | 63 | ```js 64 | // BROWSER POLYFILL 65 | ``` 66 | 67 | to see where they are used. 68 | 69 | The file with *all* the polyfills is `src/node_polyfills.js` 70 | 71 | We ignore this file when we do our browserify build for testing. 72 | 73 | **NOTE/QUESTION**. 74 | Ignoring the polyfill in our test browserify build certainly makes the tests pass, but a caller who downloads the stuff from npm, tries to `require` our package and browserify it for themelves, will be in for a nasty surprise. Lots of native gunk will show up in their browserify errors, and they will probably be confused and walk away. So, how should we make the browser-side require more seamless? Can we have people require a browserified build we produce? 75 | 76 | 77 | ## TODO 78 | - [X] Integrate native test into grunt test routine 79 | - [X] Get tests running back in browser 80 | - [X] Builds results for node + browser matrix 81 | - [X] Test on more platforms (browser) 82 | - [ ] Test on mobile platforms 83 | - [ ] Capture + fix native bundling issue (pre-bundle?) 84 | - [ ] NPM publish 85 | - [X] Relatedly, make sure callers don't need emscripten! 86 | -------------------------------------------------------------------------------- /Gruntfile.js: -------------------------------------------------------------------------------- 1 | var child_process = require('child_process'); 2 | var util = require('util'); 3 | 4 | // browserify should ignore the native polyfills 5 | var browserifyOpts = { 6 | exclude: ['src/node_polyfills.js'] 7 | }; 8 | 9 | module.exports = function(grunt) { 10 | 'use strict'; 11 | 12 | grunt.initConfig({ 13 | pkg: grunt.file.readJSON('package.json'), 14 | browserify: { 15 | legacy: { 16 | src: 'src/main_window.js', 17 | dest: 'dist/libsignal.js', 18 | options: browserifyOpts 19 | }, 20 | test: { 21 | src: 'test/main.js', 22 | dest: 'build/test_main.js', 23 | options: browserifyOpts 24 | } 25 | }, 26 | concat: { 27 | components: { 28 | src: [ 29 | 'node_modules/long/dist/long.js', 30 | 'node_modules/bytebuffer/dist/ByteBufferAB.js', 31 | 'node_modules/protobufjs/dist/protobuf.js' 32 | ], 33 | dest: 'build/dcodeIO.js' 34 | }, 35 | curve25519: { 36 | src: [ 37 | 'build/curve25519_compiled.js', 38 | ], 39 | dest: 'build/curve25519_concat.js', 40 | // Append this to the build for browser require compatibility 41 | // via https://github.com/nfroidure/ttf2woff2/blob/master/jssrc/post.js 42 | options: { 43 | footer: "module.exports = Module;\nModule.inspect = function() { return '[Module]'; };" 44 | } 45 | }, 46 | protos: { 47 | src: [ 48 | 'protos/WhisperTextProtocol.proto' 49 | ], 50 | dest: 'build/protoText.js', 51 | options: { 52 | banner: 'var Internal = Internal || {};\n\nInternal.protoText = function() {\n\tvar protoText = {};\n\n', 53 | footer: '\n\treturn protoText;\n}();', 54 | process: function(src, file) { 55 | var res = "\tprotoText['" + file + "'] = \n"; 56 | var lines = src.match(/[^\r\n]+/g); 57 | for (var i in lines) { 58 | res += "\t\t'" + lines[i] + "\\n' +\n"; 59 | } 60 | return res + "''\t;\n"; 61 | } 62 | } 63 | }, 64 | protos_concat: { 65 | src: [ 66 | 'build/protoText.js', 67 | 'src/protobufs.js', 68 | ], 69 | dest: 'build/protobufs_concat.js' 70 | }, 71 | 72 | test: { 73 | src: [ 74 | 'node_modules/mocha/mocha.js', 75 | 'node_modules/chai/chai.js', 76 | 'node_modules/jquery/dist/jquery.js', 77 | 'node_modules/blanket/dist/mocha/blanket_mocha.js', 78 | 'test/_test.js' 79 | ], 80 | dest: 'build/test_lib.js' 81 | } 82 | }, 83 | compile: { 84 | curve25519_compiled: { 85 | src_files: [ 86 | 'native/ed25519/additions/*.c', 87 | 'native/curve25519-donna.c', 88 | 'native/ed25519/*.c', 89 | 'native/ed25519/sha512/sha2big.c' 90 | ], 91 | methods: [ 92 | 'curve25519_donna', 93 | 'curve25519_sign', 94 | 'curve25519_verify', 95 | 'crypto_sign_ed25519_ref10_ge_scalarmult_base', 96 | 'sph_sha512_init', 97 | 'malloc' 98 | ] 99 | } 100 | }, 101 | 102 | jshint: { 103 | files: [ 104 | 'Gruntfile.js', 105 | 'src/**/*.js' 106 | ], // TODO add 'test/**/*.js' 107 | options: { jshintrc: '.jshintrc' }, 108 | }, 109 | jscs: { 110 | all: { 111 | src: [ 112 | 'Gruntfile.js', 113 | 'src/**/*.js' 114 | ] 115 | } 116 | }, 117 | // watch: { 118 | // jshint: { 119 | // files: ['<%= jshint.files %>', '.jshintrc'], 120 | // tasks: ['jshint'] 121 | // }, 122 | // libsignalprotocol: { 123 | // files: ['<%= concat.libsignalprotocol.src %>'], 124 | // tasks: ['concat:libsignalprotocol'] 125 | // }, 126 | // protos: { 127 | // files: ['<%= concat.protos.src %>'], 128 | // tasks: ['concat:protos_concat'] 129 | // }, 130 | // protos_concat: { 131 | // files: ['<%= concat.protos_concat.src %>'], 132 | // tasks: ['concat:protos_concat'] 133 | // } 134 | // }, 135 | 136 | connect: { 137 | server: { 138 | options: { 139 | base: '.', 140 | port: 9998 141 | } 142 | } 143 | }, 144 | mochaTest: { 145 | test: { 146 | options: { 147 | reporter: 'spec', 148 | // captureFile: 'results.txt', // Optionally capture the reporter output to a file 149 | // quiet: true, // Optionally suppress output to standard out (defaults to false) 150 | // clearRequireCache: false, // Optionally clear the require cache before running tests (defaults to false) 151 | // noFail: false // Optionally set to not fail on failed tests (will still fail on other errors) 152 | }, 153 | src: ['test/main.js'] 154 | } 155 | }, 156 | 'saucelabs-mocha': { 157 | all: { 158 | options: { 159 | urls: ['http://127.0.0.1:9998/test/index.html'], 160 | build: process.env.TRAVIS_JOB_ID || Date.now(), 161 | public: 'public', 162 | browsers: [ 163 | { platform: 'linux', browserName: 'chrome', version: '48' }, 164 | { platform: 'os x 10.11', browsername: 'chrome', version: '54.0' }, 165 | { platform: 'Windows 10', browserName: 'chrome', version:'54.0' }, 166 | { platform: 'linux', browserName: 'firefox', version: '45' }, 167 | { platform: 'OS X 10.11', browserName: 'firefox', version: '50.0' }, 168 | { platform: 'Windows 10', browserName: 'firefox', version:'50.0' }, 169 | // { platform: 'OS X 10.11', browserName: 'safari', version: '10.0' }, 170 | ], 171 | testname: 'libsignal-protocol tests', 172 | 'max-duration': 300, 173 | statusCheckAttempts: 200 174 | } 175 | } 176 | } 177 | }); 178 | 179 | Object.keys(grunt.config.get('pkg').devDependencies).forEach(function(key) { 180 | if (/^grunt(?!(-cli)?$)/.test(key)) { // ignore grunt and grunt-cli 181 | grunt.loadNpmTasks(key); 182 | } 183 | }); 184 | 185 | grunt.registerMultiTask('compile', 'Compile the C libraries with emscripten.', function() { 186 | var callback = this.async(); 187 | var outfile = 'build/' + this.target + '.js'; 188 | 189 | var exported_functions = this.data.methods.map(function(name) { 190 | return "'_" + name + "'"; 191 | }); 192 | var flags = [ 193 | '-O1', 194 | '-Qunused-arguments', 195 | '-o', outfile, 196 | '-Inative/ed25519/nacl_includes -Inative/ed25519 -Inative/ed25519/sha512', 197 | '-s', "EXPORTED_FUNCTIONS=\"[" + exported_functions.join(',') + "]\""]; 198 | var command = [].concat('emcc', this.data.src_files, flags).join(' '); 199 | grunt.log.writeln('Compiling via emscripten to ' + outfile); 200 | 201 | var exitCode = 0; 202 | grunt.verbose.subhead(command); 203 | grunt.verbose.writeln(util.format('Expecting exit code %d', exitCode)); 204 | 205 | var child = child_process.exec(command); 206 | child.stdout.on('data', function (d) { grunt.log.write(d); }); 207 | child.stderr.on('data', function (d) { grunt.log.error(d); }); 208 | child.on('exit', function(code) { 209 | if (code !== exitCode) { 210 | grunt.log.error(util.format('Exited with code: %d.', code)); 211 | return callback(false); 212 | } 213 | 214 | grunt.verbose.ok(util.format('Exited with code: %d.', code)); 215 | callback(true); 216 | }); 217 | }); 218 | 219 | // grunt.registerTask('dev', ['connect', 'watch']); 220 | grunt.registerTask('test', ['jshint', 'jscs', 'build', 'mochaTest', 'connect', 'saucelabs-mocha']); 221 | grunt.registerTask('build', ['compile', 'concat', 'browserify']); 222 | grunt.registerTask('default', ['build', 'test']); 223 | 224 | }; 225 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # signal-protocol 2 | 3 | [![Build Status](https://travis-ci.org/elsehow/signal-protocol.svg?branch=master)](https://travis-ci.org/elsehow/signal-protocol) 4 | [![Dependencies](https://david-dm.org/elsehow/signal-protocol/status.svg)](https://david-dm.org/elsehow/signal-protocol) 5 | [![DevDependencies](https://david-dm.org/elsehow/signal-protocol/dev-status.svg)](https://david-dm.org/elsehow/signal-protocol?type=dev) 6 | 7 | [![Sauce Test Status](https://saucelabs.com/browser-matrix/elsehow.svg)](https://saucelabs.com/u/elsehow) 8 | 9 | 10 | A ratcheting forward secrecy protocol that works in synchronous and 11 | asynchronous messaging environments. 12 | 13 | # THIS MODULE IS DEPRICATED 14 | 15 | I recommend you use [@wireapp/proteus](https://www.npmjs.com/package/@wireapp/proteus). 16 | 17 | *All code in this repository is FOR RESEARCH PURPOSES ONLY!* 18 | 19 | --- 20 | 21 | This repository is forked from WhisperSystem's own [libsignal-protocol-javascript](https://github.com/WhisperSystems/libsignal-protocol-javascript) by **[@liliakai](https://github.com/liliakai)**, modified to support node and the browser. I use [node-webcrypto-ossl](https://github.com/PeculiarVentures/node-webcrypto-ossl) as a drop-in native replacement for WebCrypto API. 22 | 23 | **WARNING: This code has NOT been reviewed by an experienced cryptographer. IT IS FOR RESEARCH ONLY!!!!!** 24 | 25 | You can read more about the signal protocol 26 | (formerly /axolotl/ for its self-healing abilities) 27 | [here](https://whispersystems.org/blog/advanced-ratcheting/). 28 | 29 | ## Install 30 | 31 | ```sh 32 | npm install signal-protocol 33 | ``` 34 | 35 | ## Usage 36 | 37 | There are two ways to use this package. 38 | 39 | You can require with your front-end bundler of choice (e.g. browserify, webpack): 40 | 41 | ```js 42 | var signal = require('signal-protocol') 43 | ``` 44 | 45 | **IMPT NOTE!!!** If you intend to call this from the browser, have your bundler exclude `src/node_polyfills.js`. You won't need that file for your browser bundles, and it could crash your bundler. (Even at best, it will add tons of useless junk to your bundled js file). 46 | 47 | Or, you can include the prebundled `dist/libsignal.js` in your HTML file. 48 | 49 | The following steps will walk you through the lifecycle of the signal protocol 50 | 51 | ### Generate an indentity + PreKeys 52 | 53 | This protocol uses a concept called 'PreKeys'. A PreKey is an ECPublicKey and 54 | an associated unique ID which are stored together by a server. PreKeys can also 55 | be signed. 56 | 57 | At install time, clients generate a single signed PreKey, as well as a large 58 | list of unsigned PreKeys, and transmit all of them to the server. 59 | 60 | ```js 61 | var signal = require('signal-protocol') 62 | var KeyHelper = signal.KeyHelper; 63 | 64 | var registrationId = KeyHelper.generateRegistrationId(); 65 | // Store registrationId somewhere durable and safe. 66 | 67 | KeyHelper.generateIdentityKeyPair().then(function(identityKeyPair) { 68 | // keyPair -> { pubKey: ArrayBuffer, privKey: ArrayBuffer } 69 | // Store identityKeyPair somewhere durable and safe. 70 | }); 71 | 72 | KeyHelper.generatePreKey(keyId).then(function(preKey) { 73 | store.storePreKey(preKey.keyId, preKey.keyPair); 74 | }); 75 | 76 | KeyHelper.generateSignedPreKey(identityKeyPair, keyId).then(function(signedPreKey) { 77 | store.storeSignedPreKey(signedPreKey.keyId, signedPreKey.keyPair); 78 | }); 79 | 80 | // Register preKeys and signedPreKey with the server 81 | ``` 82 | 83 | ### Build a session 84 | 85 | Signal Protocol is session-oriented. Clients establish a "session," which is 86 | then used for all subsequent encrypt/decrypt operations. There is no need to 87 | ever tear down a session once one has been established. 88 | 89 | Sessions are established in one of two ways: 90 | 91 | 1. PreKeyBundles. A client that wishes to send a message to a recipient can 92 | establish a session by retrieving a PreKeyBundle for that recipient from the 93 | server. 94 | 1. PreKeySignalMessages. A client can receive a PreKeySignalMessage from a 95 | recipient and use it to establish a session. 96 | 97 | #### A note on state 98 | 99 | An established session encapsulates a lot of state between two clients. That 100 | state is maintained in durable records which need to be kept for the life of 101 | the session. 102 | 103 | State is kept in the following places: 104 | 105 | * Identity State. Clients will need to maintain the state of their own identity 106 | key pair, as well as identity keys received from other clients. 107 | * PreKey State. Clients will need to maintain the state of their generated 108 | PreKeys. 109 | * Signed PreKey States. Clients will need to maintain the state of their signed 110 | PreKeys. 111 | * Session State. Clients will need to maintain the state of the sessions they 112 | have established. 113 | 114 | A signal client needs to implement a storage interface that will manage 115 | loading and storing of identity, prekeys, signed prekeys, and session state. 116 | See `test/InMemorySignalProtocolStore.js` for an example. 117 | 118 | #### Building a session 119 | 120 | Once your storage interface is implemented, building a session is fairly straightforward: 121 | 122 | ```js 123 | var store = new MySignalProtocolStore(); 124 | var address = new signal.SignalProtocolAddress(recipientId, deviceId); 125 | 126 | // Instantiate a SessionBuilder for a remote recipientId + deviceId tuple. 127 | var sessionBuilder = new signal.SessionBuilder(store, address); 128 | 129 | // Process a prekey fetched from the server. Returns a promise that resolves 130 | // once a session is created and saved in the store, or rejects if the 131 | // identityKey differs from a previously seen identity for this address. 132 | var promise = sessionBuilder.processPreKey({ 133 | registrationId: , 134 | identityKey: , 135 | signedPreKey: { 136 | keyId : , 137 | publicKey : , 138 | signature : 139 | }, 140 | preKey: { 141 | keyId : , 142 | publicKey : 143 | } 144 | }); 145 | 146 | promise.then(function onsuccess() { 147 | // encrypt messages 148 | }); 149 | 150 | promise.catch(function onerror(error) { 151 | // handle identity key conflict 152 | }); 153 | ``` 154 | 155 | 156 | ### Encrypting 157 | 158 | Once you have a session established with an address, you can encrypt messages 159 | using SessionCipher. 160 | 161 | ```js 162 | var plaintext = "Hello world"; 163 | var sessionCipher = new signal.SessionCipher(store, address); 164 | sessionCipher.encrypt(plaintext).then(function(ciphertext) { 165 | // ciphertext -> { type: , body: } 166 | handle(ciphertext.type, ciphertext.body); 167 | }); 168 | ``` 169 | 170 | ### Decrypting 171 | 172 | Ciphertexts come in two flavors: WhisperMessage and PreKeyWhisperMessage. 173 | 174 | ```js 175 | var address = new signal.SignalProtocolAddress(recipientId, deviceId); 176 | var sessionCipher = new signal.SessionCipher(store, address); 177 | 178 | // Decrypt a PreKeyWhisperMessage by first establishing a new session. 179 | // Returns a promise that resolves when the message is decrypted or 180 | // rejects if the identityKey differs from a previously seen identity for this 181 | // address. 182 | sessionCipher.decryptPreKeyWhisperMessage(ciphertext).then(function(plaintext) { 183 | // handle plaintext ArrayBuffer 184 | }).catch(function(error) { 185 | // handle identity key conflict 186 | }); 187 | 188 | // Decrypt a normal message using an existing session 189 | var sessionCipher = new signal.SessionCipher(store, address); 190 | sessionCipher.decryptWhisperMessage(ciphertext).then(function(plaintext) { 191 | // handle plaintext ArrayBuffer 192 | }); 193 | ``` 194 | 195 | ## Cryptography Notice 196 | 197 | A number of nations restrict the use or export of cryptography. If you are potentially subject to such restrictions you should seek competent professional legal advice before attempting to develop or distribute cryptographic code. 198 | 199 | ## License 200 | 201 | I (elsehow) release copyright to 202 | Copyright 2015-2016 Open Whisper Systems 203 | under the GPLv3: http://www.gnu.org/licenses/gpl-3.0.html 204 | -------------------------------------------------------------------------------- /build/protoText.js: -------------------------------------------------------------------------------- 1 | var Internal = Internal || {}; 2 | 3 | Internal.protoText = function() { 4 | var protoText = {}; 5 | 6 | protoText['protos/WhisperTextProtocol.proto'] = 7 | 'package textsecure;\n' + 8 | 'option java_package = "org.whispersystems.libsignal.protocol";\n' + 9 | 'option java_outer_classname = "WhisperProtos";\n' + 10 | 'message WhisperMessage {\n' + 11 | ' optional bytes ephemeralKey = 1;\n' + 12 | ' optional uint32 counter = 2;\n' + 13 | ' optional uint32 previousCounter = 3;\n' + 14 | ' optional bytes ciphertext = 4; // PushMessageContent\n' + 15 | '}\n' + 16 | 'message PreKeyWhisperMessage {\n' + 17 | ' optional uint32 registrationId = 5;\n' + 18 | ' optional uint32 preKeyId = 1;\n' + 19 | ' optional uint32 signedPreKeyId = 6;\n' + 20 | ' optional bytes baseKey = 2;\n' + 21 | ' optional bytes identityKey = 3;\n' + 22 | ' optional bytes message = 4; // WhisperMessage\n' + 23 | '}\n' + 24 | 'message KeyExchangeMessage {\n' + 25 | ' optional uint32 id = 1;\n' + 26 | ' optional bytes baseKey = 2;\n' + 27 | ' optional bytes ephemeralKey = 3;\n' + 28 | ' optional bytes identityKey = 4;\n' + 29 | ' optional bytes baseKeySignature = 5;\n' + 30 | '}\n' + 31 | '' ; 32 | 33 | return protoText; 34 | }(); -------------------------------------------------------------------------------- /build/protobufs_concat.js: -------------------------------------------------------------------------------- 1 | var Internal = Internal || {}; 2 | 3 | Internal.protoText = function() { 4 | var protoText = {}; 5 | 6 | protoText['protos/WhisperTextProtocol.proto'] = 7 | 'package textsecure;\n' + 8 | 'option java_package = "org.whispersystems.libsignal.protocol";\n' + 9 | 'option java_outer_classname = "WhisperProtos";\n' + 10 | 'message WhisperMessage {\n' + 11 | ' optional bytes ephemeralKey = 1;\n' + 12 | ' optional uint32 counter = 2;\n' + 13 | ' optional uint32 previousCounter = 3;\n' + 14 | ' optional bytes ciphertext = 4; // PushMessageContent\n' + 15 | '}\n' + 16 | 'message PreKeyWhisperMessage {\n' + 17 | ' optional uint32 registrationId = 5;\n' + 18 | ' optional uint32 preKeyId = 1;\n' + 19 | ' optional uint32 signedPreKeyId = 6;\n' + 20 | ' optional bytes baseKey = 2;\n' + 21 | ' optional bytes identityKey = 3;\n' + 22 | ' optional bytes message = 4; // WhisperMessage\n' + 23 | '}\n' + 24 | 'message KeyExchangeMessage {\n' + 25 | ' optional uint32 id = 1;\n' + 26 | ' optional bytes baseKey = 2;\n' + 27 | ' optional bytes ephemeralKey = 3;\n' + 28 | ' optional bytes identityKey = 4;\n' + 29 | ' optional bytes baseKeySignature = 5;\n' + 30 | '}\n' + 31 | '' ; 32 | 33 | return protoText; 34 | }(); 35 | /* vim: ts=4:sw=4 */ 36 | 37 | // this is concatinated after ../protos/WhisperTextProtocol.proto 38 | // Internal.protoText is getting passed in from that file 39 | // (see the Gruntfile's `protos_concat` routine) 40 | // here we export the loaded protobuf, an object 41 | // { WhisperMessage, PreKeyWhisperMessage } 42 | module.exports = function protobuf() { 43 | 'use strict'; 44 | var dcodeIO = require('../build/dcodeIO.js'); 45 | // var protobufjs = require('protobufjs') 46 | 47 | function loadProtoBufs(filename) { 48 | return dcodeIO.loadProto(Internal.protoText['protos/' + filename]).build('textsecure'); 49 | } 50 | 51 | var protocolMessages = loadProtoBufs('WhisperTextProtocol.proto'); 52 | 53 | return { 54 | WhisperMessage : protocolMessages.WhisperMessage, 55 | PreKeyWhisperMessage : protocolMessages.PreKeyWhisperMessage 56 | }; 57 | }(); 58 | -------------------------------------------------------------------------------- /native/ed25519/additions/compare.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "compare.h" 3 | 4 | /* Const-time comparison from SUPERCOP, but here it's only used for 5 | signature verification, so doesn't need to be const-time. But 6 | copied the nacl version anyways. */ 7 | int crypto_verify_32_ref(const unsigned char *x, const unsigned char *y) 8 | { 9 | unsigned int differentbits = 0; 10 | #define F(i) differentbits |= x[i] ^ y[i]; 11 | F(0) 12 | F(1) 13 | F(2) 14 | F(3) 15 | F(4) 16 | F(5) 17 | F(6) 18 | F(7) 19 | F(8) 20 | F(9) 21 | F(10) 22 | F(11) 23 | F(12) 24 | F(13) 25 | F(14) 26 | F(15) 27 | F(16) 28 | F(17) 29 | F(18) 30 | F(19) 31 | F(20) 32 | F(21) 33 | F(22) 34 | F(23) 35 | F(24) 36 | F(25) 37 | F(26) 38 | F(27) 39 | F(28) 40 | F(29) 41 | F(30) 42 | F(31) 43 | return (1 & ((differentbits - 1) >> 8)) - 1; 44 | } 45 | -------------------------------------------------------------------------------- /native/ed25519/additions/compare.h: -------------------------------------------------------------------------------- 1 | #ifndef __COMPARE_H__ 2 | #define __COMPARE_H__ 3 | 4 | int crypto_verify_32_ref(const unsigned char *b1, const unsigned char *b2); 5 | 6 | #endif 7 | -------------------------------------------------------------------------------- /native/ed25519/additions/curve_sigs.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "ge.h" 3 | #include "curve_sigs.h" 4 | #include "crypto_sign.h" 5 | 6 | void curve25519_keygen(unsigned char* curve25519_pubkey_out, 7 | unsigned char* curve25519_privkey_in) 8 | { 9 | ge_p3 ed_pubkey_point; /* Ed25519 pubkey point */ 10 | unsigned char ed_pubkey[32]; /* privkey followed by pubkey */ 11 | fe ed_y, one, ed_y_plus_one, one_minus_ed_y, inv_one_minus_ed_y; 12 | fe mont_x; 13 | 14 | /* Perform a fixed-base multiplication of the Edwards base point, 15 | (which is efficient due to precalculated tables), then convert 16 | to the Curve25519 montgomery-format public key. In particular, 17 | convert Curve25519's "montgomery" x-coordinate into an Ed25519 18 | "edwards" y-coordinate: 19 | 20 | mont_x = (ed_y +1 1) / (1 - ed_y) 21 | */ 22 | 23 | ge_scalarmult_base(&ed_pubkey_point, curve25519_privkey_in); 24 | ge_p3_tobytes(ed_pubkey, &ed_pubkey_point); 25 | ed_pubkey[31] = ed_pubkey[31] & 0x7F; /* Mask off sign bit */ 26 | fe_frombytes(ed_y, ed_pubkey); 27 | 28 | fe_1(one); 29 | fe_add(ed_y_plus_one, ed_y, one); 30 | fe_sub(one_minus_ed_y, one, ed_y); 31 | fe_invert(inv_one_minus_ed_y, one_minus_ed_y); 32 | fe_mul(mont_x, ed_y_plus_one, inv_one_minus_ed_y); 33 | fe_tobytes(curve25519_pubkey_out, mont_x); 34 | } 35 | 36 | void curve25519_sign(unsigned char* signature_out, 37 | unsigned char* curve25519_privkey, 38 | unsigned char* msg, unsigned long msg_len) 39 | { 40 | ge_p3 ed_pubkey_point; /* Ed25519 pubkey point */ 41 | unsigned char ed_keypair[64]; /* privkey followed by pubkey */ 42 | unsigned char sigbuf[msg_len + 64]; /* working buffer */ 43 | unsigned long long sigbuf_out_len = 0; 44 | unsigned char sign_bit = 0; 45 | 46 | /* Convert the Curve25519 privkey to an Ed25519 keypair */ 47 | memmove(ed_keypair, curve25519_privkey, 32); 48 | ge_scalarmult_base(&ed_pubkey_point, curve25519_privkey); 49 | ge_p3_tobytes(ed_keypair + 32, &ed_pubkey_point); 50 | sign_bit = ed_keypair[63] & 0x80; 51 | 52 | /* Perform an Ed25519 signature with explicit private key */ 53 | crypto_sign_modified(sigbuf, &sigbuf_out_len, msg, msg_len, ed_keypair); 54 | memmove(signature_out, sigbuf, 64); 55 | 56 | /* Encode the sign bit into signature (in unused high bit of S) */ 57 | signature_out[63] |= sign_bit; 58 | } 59 | 60 | int curve25519_verify(unsigned char* signature, 61 | unsigned char* curve25519_pubkey, 62 | unsigned char* msg, unsigned long msg_len) 63 | { 64 | fe mont_x, mont_x_minus_one, mont_x_plus_one, inv_mont_x_plus_one; 65 | fe one; 66 | fe ed_y; 67 | unsigned char ed_pubkey[32]; 68 | unsigned long long some_retval; 69 | unsigned char verifybuf[msg_len + 64]; /* working buffer */ 70 | unsigned char verifybuf2[msg_len + 64]; /* working buffer #2 */ 71 | 72 | /* Convert the Curve25519 public key into an Ed25519 public key. In 73 | particular, convert Curve25519's "montgomery" x-coordinate into an 74 | Ed25519 "edwards" y-coordinate: 75 | 76 | ed_y = (mont_x - 1) / (mont_x + 1) 77 | 78 | Then move the sign bit into the pubkey from the signature. 79 | */ 80 | fe_frombytes(mont_x, curve25519_pubkey); 81 | fe_1(one); 82 | fe_sub(mont_x_minus_one, mont_x, one); 83 | fe_add(mont_x_plus_one, mont_x, one); 84 | fe_invert(inv_mont_x_plus_one, mont_x_plus_one); 85 | fe_mul(ed_y, mont_x_minus_one, inv_mont_x_plus_one); 86 | fe_tobytes(ed_pubkey, ed_y); 87 | 88 | /* Copy the sign bit, and remove it from signature */ 89 | ed_pubkey[31] |= (signature[63] & 0x80); 90 | signature[63] &= 0x7F; 91 | 92 | memmove(verifybuf, signature, 64); 93 | memmove(verifybuf+64, msg, msg_len); 94 | 95 | /* Then perform a normal Ed25519 verification, return 0 on success */ 96 | return crypto_sign_open(verifybuf2, &some_retval, verifybuf, 64 + msg_len, ed_pubkey); 97 | } 98 | -------------------------------------------------------------------------------- /native/ed25519/additions/curve_sigs.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef __CURVE_SIGS_H__ 3 | #define __CURVE_SIGS_H__ 4 | 5 | #ifdef __cplusplus 6 | extern "C" { 7 | #endif 8 | 9 | void curve25519_keygen(unsigned char* curve25519_pubkey_out, 10 | unsigned char* curve25519_privkey_in); 11 | 12 | void curve25519_sign(unsigned char* signature_out, 13 | unsigned char* curve25519_privkey, 14 | unsigned char* msg, unsigned long msg_len); 15 | 16 | /* returns 0 on success */ 17 | int curve25519_verify(unsigned char* signature, 18 | unsigned char* curve25519_pubkey, 19 | unsigned char* msg, unsigned long msg_len); 20 | 21 | /* helper function - modified version of crypto_sign() to use 22 | explicit private key */ 23 | int crypto_sign_modified( 24 | unsigned char *sm,unsigned long long *smlen, 25 | const unsigned char *m,unsigned long long mlen, 26 | const unsigned char *sk 27 | ); 28 | 29 | #ifdef __cplusplus 30 | } 31 | #endif 32 | 33 | #endif 34 | -------------------------------------------------------------------------------- /native/ed25519/additions/sha512.c: -------------------------------------------------------------------------------- 1 | #include "sha512.h" 2 | #include "sph_sha2.h" 3 | 4 | int crypto_hash_sha512_ref(unsigned char *output ,const unsigned char *input, 5 | unsigned long long len) 6 | { 7 | sph_sha512_context ctx; 8 | sph_sha512_init(&ctx); 9 | sph_sha512(&ctx, input, len); 10 | sph_sha512_close(&ctx, output); 11 | return 0; 12 | } 13 | 14 | -------------------------------------------------------------------------------- /native/ed25519/additions/sha512.h: -------------------------------------------------------------------------------- 1 | #ifndef __SHA512_H__ 2 | #define __SHA512_H__ 3 | 4 | #include "sha512.h" 5 | #include "sph_sha2.h" 6 | 7 | int crypto_hash_sha512_ref(unsigned char *output ,const unsigned char *input, 8 | unsigned long long len); 9 | 10 | #endif 11 | -------------------------------------------------------------------------------- /native/ed25519/additions/sign_modified.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "crypto_sign.h" 3 | #include "crypto_hash_sha512.h" 4 | #include "ge.h" 5 | #include "sc.h" 6 | 7 | /* NEW: Compare to pristine crypto_sign() 8 | Uses explicit private key for nonce derivation and as scalar, 9 | instead of deriving both from a master key. 10 | */ 11 | int crypto_sign_modified( 12 | unsigned char *sm,unsigned long long *smlen, 13 | const unsigned char *m,unsigned long long mlen, 14 | const unsigned char *sk 15 | ) 16 | { 17 | unsigned char pk[32]; 18 | //unsigned char az[64]; 19 | unsigned char nonce[64]; 20 | unsigned char hram[64]; 21 | ge_p3 R; 22 | 23 | memmove(pk,sk + 32,32); 24 | 25 | *smlen = mlen + 64; 26 | memmove(sm + 64,m,mlen); 27 | memmove(sm + 32,sk,32); /* NEW: Use privkey directly for nonce derivation */ 28 | crypto_hash_sha512(nonce,sm + 32,mlen + 32); 29 | memmove(sm + 32,pk,32); 30 | 31 | sc_reduce(nonce); 32 | ge_scalarmult_base(&R,nonce); 33 | ge_p3_tobytes(sm,&R); 34 | 35 | crypto_hash_sha512(hram,sm,mlen + 64); 36 | sc_reduce(hram); 37 | sc_muladd(sm + 32,hram,sk,nonce); /* NEW: Use privkey directly */ 38 | 39 | return 0; 40 | } 41 | -------------------------------------------------------------------------------- /native/ed25519/api.h: -------------------------------------------------------------------------------- 1 | #define CRYPTO_SECRETKEYBYTES 64 2 | #define CRYPTO_PUBLICKEYBYTES 32 3 | #define CRYPTO_BYTES 64 4 | #define CRYPTO_DETERMINISTIC 1 5 | -------------------------------------------------------------------------------- /native/ed25519/base2.h: -------------------------------------------------------------------------------- 1 | { 2 | { 25967493,-14356035,29566456,3660896,-12694345,4014787,27544626,-11754271,-6079156,2047605 }, 3 | { -12545711,934262,-2722910,3049990,-727428,9406986,12720692,5043384,19500929,-15469378 }, 4 | { -8738181,4489570,9688441,-14785194,10184609,-12363380,29287919,11864899,-24514362,-4438546 }, 5 | }, 6 | { 7 | { 15636291,-9688557,24204773,-7912398,616977,-16685262,27787600,-14772189,28944400,-1550024 }, 8 | { 16568933,4717097,-11556148,-1102322,15682896,-11807043,16354577,-11775962,7689662,11199574 }, 9 | { 30464156,-5976125,-11779434,-15670865,23220365,15915852,7512774,10017326,-17749093,-9920357 }, 10 | }, 11 | { 12 | { 10861363,11473154,27284546,1981175,-30064349,12577861,32867885,14515107,-15438304,10819380 }, 13 | { 4708026,6336745,20377586,9066809,-11272109,6594696,-25653668,12483688,-12668491,5581306 }, 14 | { 19563160,16186464,-29386857,4097519,10237984,-4348115,28542350,13850243,-23678021,-15815942 }, 15 | }, 16 | { 17 | { 5153746,9909285,1723747,-2777874,30523605,5516873,19480852,5230134,-23952439,-15175766 }, 18 | { -30269007,-3463509,7665486,10083793,28475525,1649722,20654025,16520125,30598449,7715701 }, 19 | { 28881845,14381568,9657904,3680757,-20181635,7843316,-31400660,1370708,29794553,-1409300 }, 20 | }, 21 | { 22 | { -22518993,-6692182,14201702,-8745502,-23510406,8844726,18474211,-1361450,-13062696,13821877 }, 23 | { -6455177,-7839871,3374702,-4740862,-27098617,-10571707,31655028,-7212327,18853322,-14220951 }, 24 | { 4566830,-12963868,-28974889,-12240689,-7602672,-2830569,-8514358,-10431137,2207753,-3209784 }, 25 | }, 26 | { 27 | { -25154831,-4185821,29681144,7868801,-6854661,-9423865,-12437364,-663000,-31111463,-16132436 }, 28 | { 25576264,-2703214,7349804,-11814844,16472782,9300885,3844789,15725684,171356,6466918 }, 29 | { 23103977,13316479,9739013,-16149481,817875,-15038942,8965339,-14088058,-30714912,16193877 }, 30 | }, 31 | { 32 | { -33521811,3180713,-2394130,14003687,-16903474,-16270840,17238398,4729455,-18074513,9256800 }, 33 | { -25182317,-4174131,32336398,5036987,-21236817,11360617,22616405,9761698,-19827198,630305 }, 34 | { -13720693,2639453,-24237460,-7406481,9494427,-5774029,-6554551,-15960994,-2449256,-14291300 }, 35 | }, 36 | { 37 | { -3151181,-5046075,9282714,6866145,-31907062,-863023,-18940575,15033784,25105118,-7894876 }, 38 | { -24326370,15950226,-31801215,-14592823,-11662737,-5090925,1573892,-2625887,2198790,-15804619 }, 39 | { -3099351,10324967,-2241613,7453183,-5446979,-2735503,-13812022,-16236442,-32461234,-12290683 }, 40 | }, 41 | -------------------------------------------------------------------------------- /native/ed25519/d.h: -------------------------------------------------------------------------------- 1 | -10913610,13857413,-15372611,6949391,114729,-8787816,-6275908,-3247719,-18696448,-12055116 2 | -------------------------------------------------------------------------------- /native/ed25519/d2.h: -------------------------------------------------------------------------------- 1 | -21827239,-5839606,-30745221,13898782,229458,15978800,-12551817,-6495438,29715968,9444199 2 | -------------------------------------------------------------------------------- /native/ed25519/fe.h: -------------------------------------------------------------------------------- 1 | #ifndef FE_H 2 | #define FE_H 3 | 4 | #include "crypto_int32.h" 5 | 6 | typedef crypto_int32 fe[10]; 7 | 8 | /* 9 | fe means field element. 10 | Here the field is \Z/(2^255-19). 11 | An element t, entries t[0]...t[9], represents the integer 12 | t[0]+2^26 t[1]+2^51 t[2]+2^77 t[3]+2^102 t[4]+...+2^230 t[9]. 13 | Bounds on each t[i] vary depending on context. 14 | */ 15 | 16 | #define fe_frombytes crypto_sign_ed25519_ref10_fe_frombytes 17 | #define fe_tobytes crypto_sign_ed25519_ref10_fe_tobytes 18 | #define fe_copy crypto_sign_ed25519_ref10_fe_copy 19 | #define fe_isnonzero crypto_sign_ed25519_ref10_fe_isnonzero 20 | #define fe_isnegative crypto_sign_ed25519_ref10_fe_isnegative 21 | #define fe_0 crypto_sign_ed25519_ref10_fe_0 22 | #define fe_1 crypto_sign_ed25519_ref10_fe_1 23 | #define fe_cswap crypto_sign_ed25519_ref10_fe_cswap 24 | #define fe_cmov crypto_sign_ed25519_ref10_fe_cmov 25 | #define fe_add crypto_sign_ed25519_ref10_fe_add 26 | #define fe_sub crypto_sign_ed25519_ref10_fe_sub 27 | #define fe_neg crypto_sign_ed25519_ref10_fe_neg 28 | #define fe_mul crypto_sign_ed25519_ref10_fe_mul 29 | #define fe_sq crypto_sign_ed25519_ref10_fe_sq 30 | #define fe_sq2 crypto_sign_ed25519_ref10_fe_sq2 31 | #define fe_mul121666 crypto_sign_ed25519_ref10_fe_mul121666 32 | #define fe_invert crypto_sign_ed25519_ref10_fe_invert 33 | #define fe_pow22523 crypto_sign_ed25519_ref10_fe_pow22523 34 | 35 | extern void fe_frombytes(fe,const unsigned char *); 36 | extern void fe_tobytes(unsigned char *,const fe); 37 | 38 | extern void fe_copy(fe,const fe); 39 | extern int fe_isnonzero(const fe); 40 | extern int fe_isnegative(const fe); 41 | extern void fe_0(fe); 42 | extern void fe_1(fe); 43 | extern void fe_cswap(fe,fe,unsigned int); 44 | extern void fe_cmov(fe,const fe,unsigned int); 45 | 46 | extern void fe_add(fe,const fe,const fe); 47 | extern void fe_sub(fe,const fe,const fe); 48 | extern void fe_neg(fe,const fe); 49 | extern void fe_mul(fe,const fe,const fe); 50 | extern void fe_sq(fe,const fe); 51 | extern void fe_sq2(fe,const fe); 52 | extern void fe_mul121666(fe,const fe); 53 | extern void fe_invert(fe,const fe); 54 | extern void fe_pow22523(fe,const fe); 55 | 56 | #endif 57 | -------------------------------------------------------------------------------- /native/ed25519/fe_0.c: -------------------------------------------------------------------------------- 1 | #include "fe.h" 2 | 3 | /* 4 | h = 0 5 | */ 6 | 7 | void fe_0(fe h) 8 | { 9 | h[0] = 0; 10 | h[1] = 0; 11 | h[2] = 0; 12 | h[3] = 0; 13 | h[4] = 0; 14 | h[5] = 0; 15 | h[6] = 0; 16 | h[7] = 0; 17 | h[8] = 0; 18 | h[9] = 0; 19 | } 20 | -------------------------------------------------------------------------------- /native/ed25519/fe_1.c: -------------------------------------------------------------------------------- 1 | #include "fe.h" 2 | 3 | /* 4 | h = 1 5 | */ 6 | 7 | void fe_1(fe h) 8 | { 9 | h[0] = 1; 10 | h[1] = 0; 11 | h[2] = 0; 12 | h[3] = 0; 13 | h[4] = 0; 14 | h[5] = 0; 15 | h[6] = 0; 16 | h[7] = 0; 17 | h[8] = 0; 18 | h[9] = 0; 19 | } 20 | -------------------------------------------------------------------------------- /native/ed25519/fe_add.c: -------------------------------------------------------------------------------- 1 | #include "fe.h" 2 | 3 | /* 4 | h = f + g 5 | Can overlap h with f or g. 6 | 7 | Preconditions: 8 | |f| bounded by 1.1*2^25,1.1*2^24,1.1*2^25,1.1*2^24,etc. 9 | |g| bounded by 1.1*2^25,1.1*2^24,1.1*2^25,1.1*2^24,etc. 10 | 11 | Postconditions: 12 | |h| bounded by 1.1*2^26,1.1*2^25,1.1*2^26,1.1*2^25,etc. 13 | */ 14 | 15 | void fe_add(fe h,const fe f,const fe g) 16 | { 17 | crypto_int32 f0 = f[0]; 18 | crypto_int32 f1 = f[1]; 19 | crypto_int32 f2 = f[2]; 20 | crypto_int32 f3 = f[3]; 21 | crypto_int32 f4 = f[4]; 22 | crypto_int32 f5 = f[5]; 23 | crypto_int32 f6 = f[6]; 24 | crypto_int32 f7 = f[7]; 25 | crypto_int32 f8 = f[8]; 26 | crypto_int32 f9 = f[9]; 27 | crypto_int32 g0 = g[0]; 28 | crypto_int32 g1 = g[1]; 29 | crypto_int32 g2 = g[2]; 30 | crypto_int32 g3 = g[3]; 31 | crypto_int32 g4 = g[4]; 32 | crypto_int32 g5 = g[5]; 33 | crypto_int32 g6 = g[6]; 34 | crypto_int32 g7 = g[7]; 35 | crypto_int32 g8 = g[8]; 36 | crypto_int32 g9 = g[9]; 37 | crypto_int32 h0 = f0 + g0; 38 | crypto_int32 h1 = f1 + g1; 39 | crypto_int32 h2 = f2 + g2; 40 | crypto_int32 h3 = f3 + g3; 41 | crypto_int32 h4 = f4 + g4; 42 | crypto_int32 h5 = f5 + g5; 43 | crypto_int32 h6 = f6 + g6; 44 | crypto_int32 h7 = f7 + g7; 45 | crypto_int32 h8 = f8 + g8; 46 | crypto_int32 h9 = f9 + g9; 47 | h[0] = h0; 48 | h[1] = h1; 49 | h[2] = h2; 50 | h[3] = h3; 51 | h[4] = h4; 52 | h[5] = h5; 53 | h[6] = h6; 54 | h[7] = h7; 55 | h[8] = h8; 56 | h[9] = h9; 57 | } 58 | -------------------------------------------------------------------------------- /native/ed25519/fe_cmov.c: -------------------------------------------------------------------------------- 1 | #include "fe.h" 2 | 3 | /* 4 | Replace (f,g) with (g,g) if b == 1; 5 | replace (f,g) with (f,g) if b == 0. 6 | 7 | Preconditions: b in {0,1}. 8 | */ 9 | 10 | void fe_cmov(fe f,const fe g,unsigned int b) 11 | { 12 | crypto_int32 f0 = f[0]; 13 | crypto_int32 f1 = f[1]; 14 | crypto_int32 f2 = f[2]; 15 | crypto_int32 f3 = f[3]; 16 | crypto_int32 f4 = f[4]; 17 | crypto_int32 f5 = f[5]; 18 | crypto_int32 f6 = f[6]; 19 | crypto_int32 f7 = f[7]; 20 | crypto_int32 f8 = f[8]; 21 | crypto_int32 f9 = f[9]; 22 | crypto_int32 g0 = g[0]; 23 | crypto_int32 g1 = g[1]; 24 | crypto_int32 g2 = g[2]; 25 | crypto_int32 g3 = g[3]; 26 | crypto_int32 g4 = g[4]; 27 | crypto_int32 g5 = g[5]; 28 | crypto_int32 g6 = g[6]; 29 | crypto_int32 g7 = g[7]; 30 | crypto_int32 g8 = g[8]; 31 | crypto_int32 g9 = g[9]; 32 | crypto_int32 x0 = f0 ^ g0; 33 | crypto_int32 x1 = f1 ^ g1; 34 | crypto_int32 x2 = f2 ^ g2; 35 | crypto_int32 x3 = f3 ^ g3; 36 | crypto_int32 x4 = f4 ^ g4; 37 | crypto_int32 x5 = f5 ^ g5; 38 | crypto_int32 x6 = f6 ^ g6; 39 | crypto_int32 x7 = f7 ^ g7; 40 | crypto_int32 x8 = f8 ^ g8; 41 | crypto_int32 x9 = f9 ^ g9; 42 | b = -b; 43 | x0 &= b; 44 | x1 &= b; 45 | x2 &= b; 46 | x3 &= b; 47 | x4 &= b; 48 | x5 &= b; 49 | x6 &= b; 50 | x7 &= b; 51 | x8 &= b; 52 | x9 &= b; 53 | f[0] = f0 ^ x0; 54 | f[1] = f1 ^ x1; 55 | f[2] = f2 ^ x2; 56 | f[3] = f3 ^ x3; 57 | f[4] = f4 ^ x4; 58 | f[5] = f5 ^ x5; 59 | f[6] = f6 ^ x6; 60 | f[7] = f7 ^ x7; 61 | f[8] = f8 ^ x8; 62 | f[9] = f9 ^ x9; 63 | } 64 | -------------------------------------------------------------------------------- /native/ed25519/fe_copy.c: -------------------------------------------------------------------------------- 1 | #include "fe.h" 2 | 3 | /* 4 | h = f 5 | */ 6 | 7 | void fe_copy(fe h,const fe f) 8 | { 9 | crypto_int32 f0 = f[0]; 10 | crypto_int32 f1 = f[1]; 11 | crypto_int32 f2 = f[2]; 12 | crypto_int32 f3 = f[3]; 13 | crypto_int32 f4 = f[4]; 14 | crypto_int32 f5 = f[5]; 15 | crypto_int32 f6 = f[6]; 16 | crypto_int32 f7 = f[7]; 17 | crypto_int32 f8 = f[8]; 18 | crypto_int32 f9 = f[9]; 19 | h[0] = f0; 20 | h[1] = f1; 21 | h[2] = f2; 22 | h[3] = f3; 23 | h[4] = f4; 24 | h[5] = f5; 25 | h[6] = f6; 26 | h[7] = f7; 27 | h[8] = f8; 28 | h[9] = f9; 29 | } 30 | -------------------------------------------------------------------------------- /native/ed25519/fe_frombytes.c: -------------------------------------------------------------------------------- 1 | #include "fe.h" 2 | #include "crypto_int64.h" 3 | #include "crypto_uint64.h" 4 | 5 | static crypto_uint64 load_3(const unsigned char *in) 6 | { 7 | crypto_uint64 result; 8 | result = (crypto_uint64) in[0]; 9 | result |= ((crypto_uint64) in[1]) << 8; 10 | result |= ((crypto_uint64) in[2]) << 16; 11 | return result; 12 | } 13 | 14 | static crypto_uint64 load_4(const unsigned char *in) 15 | { 16 | crypto_uint64 result; 17 | result = (crypto_uint64) in[0]; 18 | result |= ((crypto_uint64) in[1]) << 8; 19 | result |= ((crypto_uint64) in[2]) << 16; 20 | result |= ((crypto_uint64) in[3]) << 24; 21 | return result; 22 | } 23 | 24 | /* 25 | Ignores top bit of h. 26 | */ 27 | 28 | void fe_frombytes(fe h,const unsigned char *s) 29 | { 30 | crypto_int64 h0 = load_4(s); 31 | crypto_int64 h1 = load_3(s + 4) << 6; 32 | crypto_int64 h2 = load_3(s + 7) << 5; 33 | crypto_int64 h3 = load_3(s + 10) << 3; 34 | crypto_int64 h4 = load_3(s + 13) << 2; 35 | crypto_int64 h5 = load_4(s + 16); 36 | crypto_int64 h6 = load_3(s + 20) << 7; 37 | crypto_int64 h7 = load_3(s + 23) << 5; 38 | crypto_int64 h8 = load_3(s + 26) << 4; 39 | crypto_int64 h9 = (load_3(s + 29) & 8388607) << 2; 40 | crypto_int64 carry0; 41 | crypto_int64 carry1; 42 | crypto_int64 carry2; 43 | crypto_int64 carry3; 44 | crypto_int64 carry4; 45 | crypto_int64 carry5; 46 | crypto_int64 carry6; 47 | crypto_int64 carry7; 48 | crypto_int64 carry8; 49 | crypto_int64 carry9; 50 | 51 | carry9 = (h9 + (crypto_int64) (1<<24)) >> 25; h0 += carry9 * 19; h9 -= carry9 << 25; 52 | carry1 = (h1 + (crypto_int64) (1<<24)) >> 25; h2 += carry1; h1 -= carry1 << 25; 53 | carry3 = (h3 + (crypto_int64) (1<<24)) >> 25; h4 += carry3; h3 -= carry3 << 25; 54 | carry5 = (h5 + (crypto_int64) (1<<24)) >> 25; h6 += carry5; h5 -= carry5 << 25; 55 | carry7 = (h7 + (crypto_int64) (1<<24)) >> 25; h8 += carry7; h7 -= carry7 << 25; 56 | 57 | carry0 = (h0 + (crypto_int64) (1<<25)) >> 26; h1 += carry0; h0 -= carry0 << 26; 58 | carry2 = (h2 + (crypto_int64) (1<<25)) >> 26; h3 += carry2; h2 -= carry2 << 26; 59 | carry4 = (h4 + (crypto_int64) (1<<25)) >> 26; h5 += carry4; h4 -= carry4 << 26; 60 | carry6 = (h6 + (crypto_int64) (1<<25)) >> 26; h7 += carry6; h6 -= carry6 << 26; 61 | carry8 = (h8 + (crypto_int64) (1<<25)) >> 26; h9 += carry8; h8 -= carry8 << 26; 62 | 63 | h[0] = h0; 64 | h[1] = h1; 65 | h[2] = h2; 66 | h[3] = h3; 67 | h[4] = h4; 68 | h[5] = h5; 69 | h[6] = h6; 70 | h[7] = h7; 71 | h[8] = h8; 72 | h[9] = h9; 73 | } 74 | -------------------------------------------------------------------------------- /native/ed25519/fe_invert.c: -------------------------------------------------------------------------------- 1 | #include "fe.h" 2 | 3 | void fe_invert(fe out,const fe z) 4 | { 5 | fe t0; 6 | fe t1; 7 | fe t2; 8 | fe t3; 9 | int i; 10 | 11 | #include "pow225521.h" 12 | 13 | return; 14 | } 15 | -------------------------------------------------------------------------------- /native/ed25519/fe_isnegative.c: -------------------------------------------------------------------------------- 1 | #include "fe.h" 2 | 3 | /* 4 | return 1 if f is in {1,3,5,...,q-2} 5 | return 0 if f is in {0,2,4,...,q-1} 6 | 7 | Preconditions: 8 | |f| bounded by 1.1*2^26,1.1*2^25,1.1*2^26,1.1*2^25,etc. 9 | */ 10 | 11 | int fe_isnegative(const fe f) 12 | { 13 | unsigned char s[32]; 14 | fe_tobytes(s,f); 15 | return s[0] & 1; 16 | } 17 | -------------------------------------------------------------------------------- /native/ed25519/fe_isnonzero.c: -------------------------------------------------------------------------------- 1 | #include "fe.h" 2 | #include "crypto_verify_32.h" 3 | 4 | /* 5 | return 1 if f == 0 6 | return 0 if f != 0 7 | 8 | Preconditions: 9 | |f| bounded by 1.1*2^26,1.1*2^25,1.1*2^26,1.1*2^25,etc. 10 | */ 11 | 12 | static const unsigned char zero[32]; 13 | 14 | int fe_isnonzero(const fe f) 15 | { 16 | unsigned char s[32]; 17 | fe_tobytes(s,f); 18 | return crypto_verify_32(s,zero); 19 | } 20 | -------------------------------------------------------------------------------- /native/ed25519/fe_neg.c: -------------------------------------------------------------------------------- 1 | #include "fe.h" 2 | 3 | /* 4 | h = -f 5 | 6 | Preconditions: 7 | |f| bounded by 1.1*2^25,1.1*2^24,1.1*2^25,1.1*2^24,etc. 8 | 9 | Postconditions: 10 | |h| bounded by 1.1*2^25,1.1*2^24,1.1*2^25,1.1*2^24,etc. 11 | */ 12 | 13 | void fe_neg(fe h,const fe f) 14 | { 15 | crypto_int32 f0 = f[0]; 16 | crypto_int32 f1 = f[1]; 17 | crypto_int32 f2 = f[2]; 18 | crypto_int32 f3 = f[3]; 19 | crypto_int32 f4 = f[4]; 20 | crypto_int32 f5 = f[5]; 21 | crypto_int32 f6 = f[6]; 22 | crypto_int32 f7 = f[7]; 23 | crypto_int32 f8 = f[8]; 24 | crypto_int32 f9 = f[9]; 25 | crypto_int32 h0 = -f0; 26 | crypto_int32 h1 = -f1; 27 | crypto_int32 h2 = -f2; 28 | crypto_int32 h3 = -f3; 29 | crypto_int32 h4 = -f4; 30 | crypto_int32 h5 = -f5; 31 | crypto_int32 h6 = -f6; 32 | crypto_int32 h7 = -f7; 33 | crypto_int32 h8 = -f8; 34 | crypto_int32 h9 = -f9; 35 | h[0] = h0; 36 | h[1] = h1; 37 | h[2] = h2; 38 | h[3] = h3; 39 | h[4] = h4; 40 | h[5] = h5; 41 | h[6] = h6; 42 | h[7] = h7; 43 | h[8] = h8; 44 | h[9] = h9; 45 | } 46 | -------------------------------------------------------------------------------- /native/ed25519/fe_pow22523.c: -------------------------------------------------------------------------------- 1 | #include "fe.h" 2 | 3 | void fe_pow22523(fe out,const fe z) 4 | { 5 | fe t0; 6 | fe t1; 7 | fe t2; 8 | int i; 9 | 10 | #include "pow22523.h" 11 | 12 | return; 13 | } 14 | -------------------------------------------------------------------------------- /native/ed25519/fe_sq.c: -------------------------------------------------------------------------------- 1 | #include "fe.h" 2 | #include "crypto_int64.h" 3 | 4 | /* 5 | h = f * f 6 | Can overlap h with f. 7 | 8 | Preconditions: 9 | |f| bounded by 1.65*2^26,1.65*2^25,1.65*2^26,1.65*2^25,etc. 10 | 11 | Postconditions: 12 | |h| bounded by 1.01*2^25,1.01*2^24,1.01*2^25,1.01*2^24,etc. 13 | */ 14 | 15 | /* 16 | See fe_mul.c for discussion of implementation strategy. 17 | */ 18 | 19 | void fe_sq(fe h,const fe f) 20 | { 21 | crypto_int32 f0 = f[0]; 22 | crypto_int32 f1 = f[1]; 23 | crypto_int32 f2 = f[2]; 24 | crypto_int32 f3 = f[3]; 25 | crypto_int32 f4 = f[4]; 26 | crypto_int32 f5 = f[5]; 27 | crypto_int32 f6 = f[6]; 28 | crypto_int32 f7 = f[7]; 29 | crypto_int32 f8 = f[8]; 30 | crypto_int32 f9 = f[9]; 31 | crypto_int32 f0_2 = 2 * f0; 32 | crypto_int32 f1_2 = 2 * f1; 33 | crypto_int32 f2_2 = 2 * f2; 34 | crypto_int32 f3_2 = 2 * f3; 35 | crypto_int32 f4_2 = 2 * f4; 36 | crypto_int32 f5_2 = 2 * f5; 37 | crypto_int32 f6_2 = 2 * f6; 38 | crypto_int32 f7_2 = 2 * f7; 39 | crypto_int32 f5_38 = 38 * f5; /* 1.959375*2^30 */ 40 | crypto_int32 f6_19 = 19 * f6; /* 1.959375*2^30 */ 41 | crypto_int32 f7_38 = 38 * f7; /* 1.959375*2^30 */ 42 | crypto_int32 f8_19 = 19 * f8; /* 1.959375*2^30 */ 43 | crypto_int32 f9_38 = 38 * f9; /* 1.959375*2^30 */ 44 | crypto_int64 f0f0 = f0 * (crypto_int64) f0; 45 | crypto_int64 f0f1_2 = f0_2 * (crypto_int64) f1; 46 | crypto_int64 f0f2_2 = f0_2 * (crypto_int64) f2; 47 | crypto_int64 f0f3_2 = f0_2 * (crypto_int64) f3; 48 | crypto_int64 f0f4_2 = f0_2 * (crypto_int64) f4; 49 | crypto_int64 f0f5_2 = f0_2 * (crypto_int64) f5; 50 | crypto_int64 f0f6_2 = f0_2 * (crypto_int64) f6; 51 | crypto_int64 f0f7_2 = f0_2 * (crypto_int64) f7; 52 | crypto_int64 f0f8_2 = f0_2 * (crypto_int64) f8; 53 | crypto_int64 f0f9_2 = f0_2 * (crypto_int64) f9; 54 | crypto_int64 f1f1_2 = f1_2 * (crypto_int64) f1; 55 | crypto_int64 f1f2_2 = f1_2 * (crypto_int64) f2; 56 | crypto_int64 f1f3_4 = f1_2 * (crypto_int64) f3_2; 57 | crypto_int64 f1f4_2 = f1_2 * (crypto_int64) f4; 58 | crypto_int64 f1f5_4 = f1_2 * (crypto_int64) f5_2; 59 | crypto_int64 f1f6_2 = f1_2 * (crypto_int64) f6; 60 | crypto_int64 f1f7_4 = f1_2 * (crypto_int64) f7_2; 61 | crypto_int64 f1f8_2 = f1_2 * (crypto_int64) f8; 62 | crypto_int64 f1f9_76 = f1_2 * (crypto_int64) f9_38; 63 | crypto_int64 f2f2 = f2 * (crypto_int64) f2; 64 | crypto_int64 f2f3_2 = f2_2 * (crypto_int64) f3; 65 | crypto_int64 f2f4_2 = f2_2 * (crypto_int64) f4; 66 | crypto_int64 f2f5_2 = f2_2 * (crypto_int64) f5; 67 | crypto_int64 f2f6_2 = f2_2 * (crypto_int64) f6; 68 | crypto_int64 f2f7_2 = f2_2 * (crypto_int64) f7; 69 | crypto_int64 f2f8_38 = f2_2 * (crypto_int64) f8_19; 70 | crypto_int64 f2f9_38 = f2 * (crypto_int64) f9_38; 71 | crypto_int64 f3f3_2 = f3_2 * (crypto_int64) f3; 72 | crypto_int64 f3f4_2 = f3_2 * (crypto_int64) f4; 73 | crypto_int64 f3f5_4 = f3_2 * (crypto_int64) f5_2; 74 | crypto_int64 f3f6_2 = f3_2 * (crypto_int64) f6; 75 | crypto_int64 f3f7_76 = f3_2 * (crypto_int64) f7_38; 76 | crypto_int64 f3f8_38 = f3_2 * (crypto_int64) f8_19; 77 | crypto_int64 f3f9_76 = f3_2 * (crypto_int64) f9_38; 78 | crypto_int64 f4f4 = f4 * (crypto_int64) f4; 79 | crypto_int64 f4f5_2 = f4_2 * (crypto_int64) f5; 80 | crypto_int64 f4f6_38 = f4_2 * (crypto_int64) f6_19; 81 | crypto_int64 f4f7_38 = f4 * (crypto_int64) f7_38; 82 | crypto_int64 f4f8_38 = f4_2 * (crypto_int64) f8_19; 83 | crypto_int64 f4f9_38 = f4 * (crypto_int64) f9_38; 84 | crypto_int64 f5f5_38 = f5 * (crypto_int64) f5_38; 85 | crypto_int64 f5f6_38 = f5_2 * (crypto_int64) f6_19; 86 | crypto_int64 f5f7_76 = f5_2 * (crypto_int64) f7_38; 87 | crypto_int64 f5f8_38 = f5_2 * (crypto_int64) f8_19; 88 | crypto_int64 f5f9_76 = f5_2 * (crypto_int64) f9_38; 89 | crypto_int64 f6f6_19 = f6 * (crypto_int64) f6_19; 90 | crypto_int64 f6f7_38 = f6 * (crypto_int64) f7_38; 91 | crypto_int64 f6f8_38 = f6_2 * (crypto_int64) f8_19; 92 | crypto_int64 f6f9_38 = f6 * (crypto_int64) f9_38; 93 | crypto_int64 f7f7_38 = f7 * (crypto_int64) f7_38; 94 | crypto_int64 f7f8_38 = f7_2 * (crypto_int64) f8_19; 95 | crypto_int64 f7f9_76 = f7_2 * (crypto_int64) f9_38; 96 | crypto_int64 f8f8_19 = f8 * (crypto_int64) f8_19; 97 | crypto_int64 f8f9_38 = f8 * (crypto_int64) f9_38; 98 | crypto_int64 f9f9_38 = f9 * (crypto_int64) f9_38; 99 | crypto_int64 h0 = f0f0 +f1f9_76+f2f8_38+f3f7_76+f4f6_38+f5f5_38; 100 | crypto_int64 h1 = f0f1_2+f2f9_38+f3f8_38+f4f7_38+f5f6_38; 101 | crypto_int64 h2 = f0f2_2+f1f1_2 +f3f9_76+f4f8_38+f5f7_76+f6f6_19; 102 | crypto_int64 h3 = f0f3_2+f1f2_2 +f4f9_38+f5f8_38+f6f7_38; 103 | crypto_int64 h4 = f0f4_2+f1f3_4 +f2f2 +f5f9_76+f6f8_38+f7f7_38; 104 | crypto_int64 h5 = f0f5_2+f1f4_2 +f2f3_2 +f6f9_38+f7f8_38; 105 | crypto_int64 h6 = f0f6_2+f1f5_4 +f2f4_2 +f3f3_2 +f7f9_76+f8f8_19; 106 | crypto_int64 h7 = f0f7_2+f1f6_2 +f2f5_2 +f3f4_2 +f8f9_38; 107 | crypto_int64 h8 = f0f8_2+f1f7_4 +f2f6_2 +f3f5_4 +f4f4 +f9f9_38; 108 | crypto_int64 h9 = f0f9_2+f1f8_2 +f2f7_2 +f3f6_2 +f4f5_2; 109 | crypto_int64 carry0; 110 | crypto_int64 carry1; 111 | crypto_int64 carry2; 112 | crypto_int64 carry3; 113 | crypto_int64 carry4; 114 | crypto_int64 carry5; 115 | crypto_int64 carry6; 116 | crypto_int64 carry7; 117 | crypto_int64 carry8; 118 | crypto_int64 carry9; 119 | 120 | carry0 = (h0 + (crypto_int64) (1<<25)) >> 26; h1 += carry0; h0 -= carry0 << 26; 121 | carry4 = (h4 + (crypto_int64) (1<<25)) >> 26; h5 += carry4; h4 -= carry4 << 26; 122 | 123 | carry1 = (h1 + (crypto_int64) (1<<24)) >> 25; h2 += carry1; h1 -= carry1 << 25; 124 | carry5 = (h5 + (crypto_int64) (1<<24)) >> 25; h6 += carry5; h5 -= carry5 << 25; 125 | 126 | carry2 = (h2 + (crypto_int64) (1<<25)) >> 26; h3 += carry2; h2 -= carry2 << 26; 127 | carry6 = (h6 + (crypto_int64) (1<<25)) >> 26; h7 += carry6; h6 -= carry6 << 26; 128 | 129 | carry3 = (h3 + (crypto_int64) (1<<24)) >> 25; h4 += carry3; h3 -= carry3 << 25; 130 | carry7 = (h7 + (crypto_int64) (1<<24)) >> 25; h8 += carry7; h7 -= carry7 << 25; 131 | 132 | carry4 = (h4 + (crypto_int64) (1<<25)) >> 26; h5 += carry4; h4 -= carry4 << 26; 133 | carry8 = (h8 + (crypto_int64) (1<<25)) >> 26; h9 += carry8; h8 -= carry8 << 26; 134 | 135 | carry9 = (h9 + (crypto_int64) (1<<24)) >> 25; h0 += carry9 * 19; h9 -= carry9 << 25; 136 | 137 | carry0 = (h0 + (crypto_int64) (1<<25)) >> 26; h1 += carry0; h0 -= carry0 << 26; 138 | 139 | h[0] = h0; 140 | h[1] = h1; 141 | h[2] = h2; 142 | h[3] = h3; 143 | h[4] = h4; 144 | h[5] = h5; 145 | h[6] = h6; 146 | h[7] = h7; 147 | h[8] = h8; 148 | h[9] = h9; 149 | } 150 | -------------------------------------------------------------------------------- /native/ed25519/fe_sq2.c: -------------------------------------------------------------------------------- 1 | #include "fe.h" 2 | #include "crypto_int64.h" 3 | 4 | /* 5 | h = 2 * f * f 6 | Can overlap h with f. 7 | 8 | Preconditions: 9 | |f| bounded by 1.65*2^26,1.65*2^25,1.65*2^26,1.65*2^25,etc. 10 | 11 | Postconditions: 12 | |h| bounded by 1.01*2^25,1.01*2^24,1.01*2^25,1.01*2^24,etc. 13 | */ 14 | 15 | /* 16 | See fe_mul.c for discussion of implementation strategy. 17 | */ 18 | 19 | void fe_sq2(fe h,const fe f) 20 | { 21 | crypto_int32 f0 = f[0]; 22 | crypto_int32 f1 = f[1]; 23 | crypto_int32 f2 = f[2]; 24 | crypto_int32 f3 = f[3]; 25 | crypto_int32 f4 = f[4]; 26 | crypto_int32 f5 = f[5]; 27 | crypto_int32 f6 = f[6]; 28 | crypto_int32 f7 = f[7]; 29 | crypto_int32 f8 = f[8]; 30 | crypto_int32 f9 = f[9]; 31 | crypto_int32 f0_2 = 2 * f0; 32 | crypto_int32 f1_2 = 2 * f1; 33 | crypto_int32 f2_2 = 2 * f2; 34 | crypto_int32 f3_2 = 2 * f3; 35 | crypto_int32 f4_2 = 2 * f4; 36 | crypto_int32 f5_2 = 2 * f5; 37 | crypto_int32 f6_2 = 2 * f6; 38 | crypto_int32 f7_2 = 2 * f7; 39 | crypto_int32 f5_38 = 38 * f5; /* 1.959375*2^30 */ 40 | crypto_int32 f6_19 = 19 * f6; /* 1.959375*2^30 */ 41 | crypto_int32 f7_38 = 38 * f7; /* 1.959375*2^30 */ 42 | crypto_int32 f8_19 = 19 * f8; /* 1.959375*2^30 */ 43 | crypto_int32 f9_38 = 38 * f9; /* 1.959375*2^30 */ 44 | crypto_int64 f0f0 = f0 * (crypto_int64) f0; 45 | crypto_int64 f0f1_2 = f0_2 * (crypto_int64) f1; 46 | crypto_int64 f0f2_2 = f0_2 * (crypto_int64) f2; 47 | crypto_int64 f0f3_2 = f0_2 * (crypto_int64) f3; 48 | crypto_int64 f0f4_2 = f0_2 * (crypto_int64) f4; 49 | crypto_int64 f0f5_2 = f0_2 * (crypto_int64) f5; 50 | crypto_int64 f0f6_2 = f0_2 * (crypto_int64) f6; 51 | crypto_int64 f0f7_2 = f0_2 * (crypto_int64) f7; 52 | crypto_int64 f0f8_2 = f0_2 * (crypto_int64) f8; 53 | crypto_int64 f0f9_2 = f0_2 * (crypto_int64) f9; 54 | crypto_int64 f1f1_2 = f1_2 * (crypto_int64) f1; 55 | crypto_int64 f1f2_2 = f1_2 * (crypto_int64) f2; 56 | crypto_int64 f1f3_4 = f1_2 * (crypto_int64) f3_2; 57 | crypto_int64 f1f4_2 = f1_2 * (crypto_int64) f4; 58 | crypto_int64 f1f5_4 = f1_2 * (crypto_int64) f5_2; 59 | crypto_int64 f1f6_2 = f1_2 * (crypto_int64) f6; 60 | crypto_int64 f1f7_4 = f1_2 * (crypto_int64) f7_2; 61 | crypto_int64 f1f8_2 = f1_2 * (crypto_int64) f8; 62 | crypto_int64 f1f9_76 = f1_2 * (crypto_int64) f9_38; 63 | crypto_int64 f2f2 = f2 * (crypto_int64) f2; 64 | crypto_int64 f2f3_2 = f2_2 * (crypto_int64) f3; 65 | crypto_int64 f2f4_2 = f2_2 * (crypto_int64) f4; 66 | crypto_int64 f2f5_2 = f2_2 * (crypto_int64) f5; 67 | crypto_int64 f2f6_2 = f2_2 * (crypto_int64) f6; 68 | crypto_int64 f2f7_2 = f2_2 * (crypto_int64) f7; 69 | crypto_int64 f2f8_38 = f2_2 * (crypto_int64) f8_19; 70 | crypto_int64 f2f9_38 = f2 * (crypto_int64) f9_38; 71 | crypto_int64 f3f3_2 = f3_2 * (crypto_int64) f3; 72 | crypto_int64 f3f4_2 = f3_2 * (crypto_int64) f4; 73 | crypto_int64 f3f5_4 = f3_2 * (crypto_int64) f5_2; 74 | crypto_int64 f3f6_2 = f3_2 * (crypto_int64) f6; 75 | crypto_int64 f3f7_76 = f3_2 * (crypto_int64) f7_38; 76 | crypto_int64 f3f8_38 = f3_2 * (crypto_int64) f8_19; 77 | crypto_int64 f3f9_76 = f3_2 * (crypto_int64) f9_38; 78 | crypto_int64 f4f4 = f4 * (crypto_int64) f4; 79 | crypto_int64 f4f5_2 = f4_2 * (crypto_int64) f5; 80 | crypto_int64 f4f6_38 = f4_2 * (crypto_int64) f6_19; 81 | crypto_int64 f4f7_38 = f4 * (crypto_int64) f7_38; 82 | crypto_int64 f4f8_38 = f4_2 * (crypto_int64) f8_19; 83 | crypto_int64 f4f9_38 = f4 * (crypto_int64) f9_38; 84 | crypto_int64 f5f5_38 = f5 * (crypto_int64) f5_38; 85 | crypto_int64 f5f6_38 = f5_2 * (crypto_int64) f6_19; 86 | crypto_int64 f5f7_76 = f5_2 * (crypto_int64) f7_38; 87 | crypto_int64 f5f8_38 = f5_2 * (crypto_int64) f8_19; 88 | crypto_int64 f5f9_76 = f5_2 * (crypto_int64) f9_38; 89 | crypto_int64 f6f6_19 = f6 * (crypto_int64) f6_19; 90 | crypto_int64 f6f7_38 = f6 * (crypto_int64) f7_38; 91 | crypto_int64 f6f8_38 = f6_2 * (crypto_int64) f8_19; 92 | crypto_int64 f6f9_38 = f6 * (crypto_int64) f9_38; 93 | crypto_int64 f7f7_38 = f7 * (crypto_int64) f7_38; 94 | crypto_int64 f7f8_38 = f7_2 * (crypto_int64) f8_19; 95 | crypto_int64 f7f9_76 = f7_2 * (crypto_int64) f9_38; 96 | crypto_int64 f8f8_19 = f8 * (crypto_int64) f8_19; 97 | crypto_int64 f8f9_38 = f8 * (crypto_int64) f9_38; 98 | crypto_int64 f9f9_38 = f9 * (crypto_int64) f9_38; 99 | crypto_int64 h0 = f0f0 +f1f9_76+f2f8_38+f3f7_76+f4f6_38+f5f5_38; 100 | crypto_int64 h1 = f0f1_2+f2f9_38+f3f8_38+f4f7_38+f5f6_38; 101 | crypto_int64 h2 = f0f2_2+f1f1_2 +f3f9_76+f4f8_38+f5f7_76+f6f6_19; 102 | crypto_int64 h3 = f0f3_2+f1f2_2 +f4f9_38+f5f8_38+f6f7_38; 103 | crypto_int64 h4 = f0f4_2+f1f3_4 +f2f2 +f5f9_76+f6f8_38+f7f7_38; 104 | crypto_int64 h5 = f0f5_2+f1f4_2 +f2f3_2 +f6f9_38+f7f8_38; 105 | crypto_int64 h6 = f0f6_2+f1f5_4 +f2f4_2 +f3f3_2 +f7f9_76+f8f8_19; 106 | crypto_int64 h7 = f0f7_2+f1f6_2 +f2f5_2 +f3f4_2 +f8f9_38; 107 | crypto_int64 h8 = f0f8_2+f1f7_4 +f2f6_2 +f3f5_4 +f4f4 +f9f9_38; 108 | crypto_int64 h9 = f0f9_2+f1f8_2 +f2f7_2 +f3f6_2 +f4f5_2; 109 | crypto_int64 carry0; 110 | crypto_int64 carry1; 111 | crypto_int64 carry2; 112 | crypto_int64 carry3; 113 | crypto_int64 carry4; 114 | crypto_int64 carry5; 115 | crypto_int64 carry6; 116 | crypto_int64 carry7; 117 | crypto_int64 carry8; 118 | crypto_int64 carry9; 119 | 120 | h0 += h0; 121 | h1 += h1; 122 | h2 += h2; 123 | h3 += h3; 124 | h4 += h4; 125 | h5 += h5; 126 | h6 += h6; 127 | h7 += h7; 128 | h8 += h8; 129 | h9 += h9; 130 | 131 | carry0 = (h0 + (crypto_int64) (1<<25)) >> 26; h1 += carry0; h0 -= carry0 << 26; 132 | carry4 = (h4 + (crypto_int64) (1<<25)) >> 26; h5 += carry4; h4 -= carry4 << 26; 133 | 134 | carry1 = (h1 + (crypto_int64) (1<<24)) >> 25; h2 += carry1; h1 -= carry1 << 25; 135 | carry5 = (h5 + (crypto_int64) (1<<24)) >> 25; h6 += carry5; h5 -= carry5 << 25; 136 | 137 | carry2 = (h2 + (crypto_int64) (1<<25)) >> 26; h3 += carry2; h2 -= carry2 << 26; 138 | carry6 = (h6 + (crypto_int64) (1<<25)) >> 26; h7 += carry6; h6 -= carry6 << 26; 139 | 140 | carry3 = (h3 + (crypto_int64) (1<<24)) >> 25; h4 += carry3; h3 -= carry3 << 25; 141 | carry7 = (h7 + (crypto_int64) (1<<24)) >> 25; h8 += carry7; h7 -= carry7 << 25; 142 | 143 | carry4 = (h4 + (crypto_int64) (1<<25)) >> 26; h5 += carry4; h4 -= carry4 << 26; 144 | carry8 = (h8 + (crypto_int64) (1<<25)) >> 26; h9 += carry8; h8 -= carry8 << 26; 145 | 146 | carry9 = (h9 + (crypto_int64) (1<<24)) >> 25; h0 += carry9 * 19; h9 -= carry9 << 25; 147 | 148 | carry0 = (h0 + (crypto_int64) (1<<25)) >> 26; h1 += carry0; h0 -= carry0 << 26; 149 | 150 | h[0] = h0; 151 | h[1] = h1; 152 | h[2] = h2; 153 | h[3] = h3; 154 | h[4] = h4; 155 | h[5] = h5; 156 | h[6] = h6; 157 | h[7] = h7; 158 | h[8] = h8; 159 | h[9] = h9; 160 | } 161 | -------------------------------------------------------------------------------- /native/ed25519/fe_sub.c: -------------------------------------------------------------------------------- 1 | #include "fe.h" 2 | 3 | /* 4 | h = f - g 5 | Can overlap h with f or g. 6 | 7 | Preconditions: 8 | |f| bounded by 1.1*2^25,1.1*2^24,1.1*2^25,1.1*2^24,etc. 9 | |g| bounded by 1.1*2^25,1.1*2^24,1.1*2^25,1.1*2^24,etc. 10 | 11 | Postconditions: 12 | |h| bounded by 1.1*2^26,1.1*2^25,1.1*2^26,1.1*2^25,etc. 13 | */ 14 | 15 | void fe_sub(fe h,const fe f,const fe g) 16 | { 17 | crypto_int32 f0 = f[0]; 18 | crypto_int32 f1 = f[1]; 19 | crypto_int32 f2 = f[2]; 20 | crypto_int32 f3 = f[3]; 21 | crypto_int32 f4 = f[4]; 22 | crypto_int32 f5 = f[5]; 23 | crypto_int32 f6 = f[6]; 24 | crypto_int32 f7 = f[7]; 25 | crypto_int32 f8 = f[8]; 26 | crypto_int32 f9 = f[9]; 27 | crypto_int32 g0 = g[0]; 28 | crypto_int32 g1 = g[1]; 29 | crypto_int32 g2 = g[2]; 30 | crypto_int32 g3 = g[3]; 31 | crypto_int32 g4 = g[4]; 32 | crypto_int32 g5 = g[5]; 33 | crypto_int32 g6 = g[6]; 34 | crypto_int32 g7 = g[7]; 35 | crypto_int32 g8 = g[8]; 36 | crypto_int32 g9 = g[9]; 37 | crypto_int32 h0 = f0 - g0; 38 | crypto_int32 h1 = f1 - g1; 39 | crypto_int32 h2 = f2 - g2; 40 | crypto_int32 h3 = f3 - g3; 41 | crypto_int32 h4 = f4 - g4; 42 | crypto_int32 h5 = f5 - g5; 43 | crypto_int32 h6 = f6 - g6; 44 | crypto_int32 h7 = f7 - g7; 45 | crypto_int32 h8 = f8 - g8; 46 | crypto_int32 h9 = f9 - g9; 47 | h[0] = h0; 48 | h[1] = h1; 49 | h[2] = h2; 50 | h[3] = h3; 51 | h[4] = h4; 52 | h[5] = h5; 53 | h[6] = h6; 54 | h[7] = h7; 55 | h[8] = h8; 56 | h[9] = h9; 57 | } 58 | -------------------------------------------------------------------------------- /native/ed25519/fe_tobytes.c: -------------------------------------------------------------------------------- 1 | #include "fe.h" 2 | 3 | /* 4 | Preconditions: 5 | |h| bounded by 1.1*2^26,1.1*2^25,1.1*2^26,1.1*2^25,etc. 6 | 7 | Write p=2^255-19; q=floor(h/p). 8 | Basic claim: q = floor(2^(-255)(h + 19 2^(-25)h9 + 2^(-1))). 9 | 10 | Proof: 11 | Have |h|<=p so |q|<=1 so |19^2 2^(-255) q|<1/4. 12 | Also have |h-2^230 h9|<2^231 so |19 2^(-255)(h-2^230 h9)|<1/4. 13 | 14 | Write y=2^(-1)-19^2 2^(-255)q-19 2^(-255)(h-2^230 h9). 15 | Then 0> 25; 53 | q = (h0 + q) >> 26; 54 | q = (h1 + q) >> 25; 55 | q = (h2 + q) >> 26; 56 | q = (h3 + q) >> 25; 57 | q = (h4 + q) >> 26; 58 | q = (h5 + q) >> 25; 59 | q = (h6 + q) >> 26; 60 | q = (h7 + q) >> 25; 61 | q = (h8 + q) >> 26; 62 | q = (h9 + q) >> 25; 63 | 64 | /* Goal: Output h-(2^255-19)q, which is between 0 and 2^255-20. */ 65 | h0 += 19 * q; 66 | /* Goal: Output h-2^255 q, which is between 0 and 2^255-20. */ 67 | 68 | carry0 = h0 >> 26; h1 += carry0; h0 -= carry0 << 26; 69 | carry1 = h1 >> 25; h2 += carry1; h1 -= carry1 << 25; 70 | carry2 = h2 >> 26; h3 += carry2; h2 -= carry2 << 26; 71 | carry3 = h3 >> 25; h4 += carry3; h3 -= carry3 << 25; 72 | carry4 = h4 >> 26; h5 += carry4; h4 -= carry4 << 26; 73 | carry5 = h5 >> 25; h6 += carry5; h5 -= carry5 << 25; 74 | carry6 = h6 >> 26; h7 += carry6; h6 -= carry6 << 26; 75 | carry7 = h7 >> 25; h8 += carry7; h7 -= carry7 << 25; 76 | carry8 = h8 >> 26; h9 += carry8; h8 -= carry8 << 26; 77 | carry9 = h9 >> 25; h9 -= carry9 << 25; 78 | /* h10 = carry9 */ 79 | 80 | /* 81 | Goal: Output h0+...+2^255 h10-2^255 q, which is between 0 and 2^255-20. 82 | Have h0+...+2^230 h9 between 0 and 2^255-1; 83 | evidently 2^255 h10-2^255 q = 0. 84 | Goal: Output h0+...+2^230 h9. 85 | */ 86 | 87 | s[0] = h0 >> 0; 88 | s[1] = h0 >> 8; 89 | s[2] = h0 >> 16; 90 | s[3] = (h0 >> 24) | (h1 << 2); 91 | s[4] = h1 >> 6; 92 | s[5] = h1 >> 14; 93 | s[6] = (h1 >> 22) | (h2 << 3); 94 | s[7] = h2 >> 5; 95 | s[8] = h2 >> 13; 96 | s[9] = (h2 >> 21) | (h3 << 5); 97 | s[10] = h3 >> 3; 98 | s[11] = h3 >> 11; 99 | s[12] = (h3 >> 19) | (h4 << 6); 100 | s[13] = h4 >> 2; 101 | s[14] = h4 >> 10; 102 | s[15] = h4 >> 18; 103 | s[16] = h5 >> 0; 104 | s[17] = h5 >> 8; 105 | s[18] = h5 >> 16; 106 | s[19] = (h5 >> 24) | (h6 << 1); 107 | s[20] = h6 >> 7; 108 | s[21] = h6 >> 15; 109 | s[22] = (h6 >> 23) | (h7 << 3); 110 | s[23] = h7 >> 5; 111 | s[24] = h7 >> 13; 112 | s[25] = (h7 >> 21) | (h8 << 4); 113 | s[26] = h8 >> 4; 114 | s[27] = h8 >> 12; 115 | s[28] = (h8 >> 20) | (h9 << 6); 116 | s[29] = h9 >> 2; 117 | s[30] = h9 >> 10; 118 | s[31] = h9 >> 18; 119 | } 120 | -------------------------------------------------------------------------------- /native/ed25519/ge.h: -------------------------------------------------------------------------------- 1 | #ifndef GE_H 2 | #define GE_H 3 | 4 | /* 5 | ge means group element. 6 | 7 | Here the group is the set of pairs (x,y) of field elements (see fe.h) 8 | satisfying -x^2 + y^2 = 1 + d x^2y^2 9 | where d = -121665/121666. 10 | 11 | Representations: 12 | ge_p2 (projective): (X:Y:Z) satisfying x=X/Z, y=Y/Z 13 | ge_p3 (extended): (X:Y:Z:T) satisfying x=X/Z, y=Y/Z, XY=ZT 14 | ge_p1p1 (completed): ((X:Z),(Y:T)) satisfying x=X/Z, y=Y/T 15 | ge_precomp (Duif): (y+x,y-x,2dxy) 16 | */ 17 | 18 | #include "fe.h" 19 | 20 | typedef struct { 21 | fe X; 22 | fe Y; 23 | fe Z; 24 | } ge_p2; 25 | 26 | typedef struct { 27 | fe X; 28 | fe Y; 29 | fe Z; 30 | fe T; 31 | } ge_p3; 32 | 33 | typedef struct { 34 | fe X; 35 | fe Y; 36 | fe Z; 37 | fe T; 38 | } ge_p1p1; 39 | 40 | typedef struct { 41 | fe yplusx; 42 | fe yminusx; 43 | fe xy2d; 44 | } ge_precomp; 45 | 46 | typedef struct { 47 | fe YplusX; 48 | fe YminusX; 49 | fe Z; 50 | fe T2d; 51 | } ge_cached; 52 | 53 | #define ge_frombytes_negate_vartime crypto_sign_ed25519_ref10_ge_frombytes_negate_vartime 54 | #define ge_tobytes crypto_sign_ed25519_ref10_ge_tobytes 55 | #define ge_p3_tobytes crypto_sign_ed25519_ref10_ge_p3_tobytes 56 | 57 | #define ge_p2_0 crypto_sign_ed25519_ref10_ge_p2_0 58 | #define ge_p3_0 crypto_sign_ed25519_ref10_ge_p3_0 59 | #define ge_precomp_0 crypto_sign_ed25519_ref10_ge_precomp_0 60 | #define ge_p3_to_p2 crypto_sign_ed25519_ref10_ge_p3_to_p2 61 | #define ge_p3_to_cached crypto_sign_ed25519_ref10_ge_p3_to_cached 62 | #define ge_p1p1_to_p2 crypto_sign_ed25519_ref10_ge_p1p1_to_p2 63 | #define ge_p1p1_to_p3 crypto_sign_ed25519_ref10_ge_p1p1_to_p3 64 | #define ge_p2_dbl crypto_sign_ed25519_ref10_ge_p2_dbl 65 | #define ge_p3_dbl crypto_sign_ed25519_ref10_ge_p3_dbl 66 | 67 | #define ge_madd crypto_sign_ed25519_ref10_ge_madd 68 | #define ge_msub crypto_sign_ed25519_ref10_ge_msub 69 | #define ge_add crypto_sign_ed25519_ref10_ge_add 70 | #define ge_sub crypto_sign_ed25519_ref10_ge_sub 71 | #define ge_scalarmult_base crypto_sign_ed25519_ref10_ge_scalarmult_base 72 | #define ge_double_scalarmult_vartime crypto_sign_ed25519_ref10_ge_double_scalarmult_vartime 73 | 74 | extern void ge_tobytes(unsigned char *,const ge_p2 *); 75 | extern void ge_p3_tobytes(unsigned char *,const ge_p3 *); 76 | extern int ge_frombytes_negate_vartime(ge_p3 *,const unsigned char *); 77 | 78 | extern void ge_p2_0(ge_p2 *); 79 | extern void ge_p3_0(ge_p3 *); 80 | extern void ge_precomp_0(ge_precomp *); 81 | extern void ge_p3_to_p2(ge_p2 *,const ge_p3 *); 82 | extern void ge_p3_to_cached(ge_cached *,const ge_p3 *); 83 | extern void ge_p1p1_to_p2(ge_p2 *,const ge_p1p1 *); 84 | extern void ge_p1p1_to_p3(ge_p3 *,const ge_p1p1 *); 85 | extern void ge_p2_dbl(ge_p1p1 *,const ge_p2 *); 86 | extern void ge_p3_dbl(ge_p1p1 *,const ge_p3 *); 87 | 88 | extern void ge_madd(ge_p1p1 *,const ge_p3 *,const ge_precomp *); 89 | extern void ge_msub(ge_p1p1 *,const ge_p3 *,const ge_precomp *); 90 | extern void ge_add(ge_p1p1 *,const ge_p3 *,const ge_cached *); 91 | extern void ge_sub(ge_p1p1 *,const ge_p3 *,const ge_cached *); 92 | extern void ge_scalarmult_base(ge_p3 *,const unsigned char *); 93 | extern void ge_double_scalarmult_vartime(ge_p2 *,const unsigned char *,const ge_p3 *,const unsigned char *); 94 | 95 | #endif 96 | -------------------------------------------------------------------------------- /native/ed25519/ge_add.c: -------------------------------------------------------------------------------- 1 | #include "ge.h" 2 | 3 | /* 4 | r = p + q 5 | */ 6 | 7 | void ge_add(ge_p1p1 *r,const ge_p3 *p,const ge_cached *q) 8 | { 9 | fe t0; 10 | #include "ge_add.h" 11 | } 12 | -------------------------------------------------------------------------------- /native/ed25519/ge_add.h: -------------------------------------------------------------------------------- 1 | 2 | /* qhasm: enter ge_add */ 3 | 4 | /* qhasm: fe X1 */ 5 | 6 | /* qhasm: fe Y1 */ 7 | 8 | /* qhasm: fe Z1 */ 9 | 10 | /* qhasm: fe Z2 */ 11 | 12 | /* qhasm: fe T1 */ 13 | 14 | /* qhasm: fe ZZ */ 15 | 16 | /* qhasm: fe YpX2 */ 17 | 18 | /* qhasm: fe YmX2 */ 19 | 20 | /* qhasm: fe T2d2 */ 21 | 22 | /* qhasm: fe X3 */ 23 | 24 | /* qhasm: fe Y3 */ 25 | 26 | /* qhasm: fe Z3 */ 27 | 28 | /* qhasm: fe T3 */ 29 | 30 | /* qhasm: fe YpX1 */ 31 | 32 | /* qhasm: fe YmX1 */ 33 | 34 | /* qhasm: fe A */ 35 | 36 | /* qhasm: fe B */ 37 | 38 | /* qhasm: fe C */ 39 | 40 | /* qhasm: fe D */ 41 | 42 | /* qhasm: YpX1 = Y1+X1 */ 43 | /* asm 1: fe_add(>YpX1=fe#1,YpX1=r->X,Y,X); */ 45 | fe_add(r->X,p->Y,p->X); 46 | 47 | /* qhasm: YmX1 = Y1-X1 */ 48 | /* asm 1: fe_sub(>YmX1=fe#2,YmX1=r->Y,Y,X); */ 50 | fe_sub(r->Y,p->Y,p->X); 51 | 52 | /* qhasm: A = YpX1*YpX2 */ 53 | /* asm 1: fe_mul(>A=fe#3,A=r->Z,X,YplusX); */ 55 | fe_mul(r->Z,r->X,q->YplusX); 56 | 57 | /* qhasm: B = YmX1*YmX2 */ 58 | /* asm 1: fe_mul(>B=fe#2,B=r->Y,Y,YminusX); */ 60 | fe_mul(r->Y,r->Y,q->YminusX); 61 | 62 | /* qhasm: C = T2d2*T1 */ 63 | /* asm 1: fe_mul(>C=fe#4,C=r->T,T2d,T); */ 65 | fe_mul(r->T,q->T2d,p->T); 66 | 67 | /* qhasm: ZZ = Z1*Z2 */ 68 | /* asm 1: fe_mul(>ZZ=fe#1,ZZ=r->X,Z,Z); */ 70 | fe_mul(r->X,p->Z,q->Z); 71 | 72 | /* qhasm: D = 2*ZZ */ 73 | /* asm 1: fe_add(>D=fe#5,D=t0,X,X); */ 75 | fe_add(t0,r->X,r->X); 76 | 77 | /* qhasm: X3 = A-B */ 78 | /* asm 1: fe_sub(>X3=fe#1,X3=r->X,Z,Y); */ 80 | fe_sub(r->X,r->Z,r->Y); 81 | 82 | /* qhasm: Y3 = A+B */ 83 | /* asm 1: fe_add(>Y3=fe#2,Y3=r->Y,Z,Y); */ 85 | fe_add(r->Y,r->Z,r->Y); 86 | 87 | /* qhasm: Z3 = D+C */ 88 | /* asm 1: fe_add(>Z3=fe#3,Z3=r->Z,T); */ 90 | fe_add(r->Z,t0,r->T); 91 | 92 | /* qhasm: T3 = D-C */ 93 | /* asm 1: fe_sub(>T3=fe#4,T3=r->T,T); */ 95 | fe_sub(r->T,t0,r->T); 96 | 97 | /* qhasm: return */ 98 | -------------------------------------------------------------------------------- /native/ed25519/ge_double_scalarmult.c: -------------------------------------------------------------------------------- 1 | #include "ge.h" 2 | 3 | static void slide(signed char *r,const unsigned char *a) 4 | { 5 | int i; 6 | int b; 7 | int k; 8 | 9 | for (i = 0;i < 256;++i) 10 | r[i] = 1 & (a[i >> 3] >> (i & 7)); 11 | 12 | for (i = 0;i < 256;++i) 13 | if (r[i]) { 14 | for (b = 1;b <= 6 && i + b < 256;++b) { 15 | if (r[i + b]) { 16 | if (r[i] + (r[i + b] << b) <= 15) { 17 | r[i] += r[i + b] << b; r[i + b] = 0; 18 | } else if (r[i] - (r[i + b] << b) >= -15) { 19 | r[i] -= r[i + b] << b; 20 | for (k = i + b;k < 256;++k) { 21 | if (!r[k]) { 22 | r[k] = 1; 23 | break; 24 | } 25 | r[k] = 0; 26 | } 27 | } else 28 | break; 29 | } 30 | } 31 | } 32 | 33 | } 34 | 35 | static ge_precomp Bi[8] = { 36 | #include "base2.h" 37 | } ; 38 | 39 | /* 40 | r = a * A + b * B 41 | where a = a[0]+256*a[1]+...+256^31 a[31]. 42 | and b = b[0]+256*b[1]+...+256^31 b[31]. 43 | B is the Ed25519 base point (x,4/5) with x positive. 44 | */ 45 | 46 | void ge_double_scalarmult_vartime(ge_p2 *r,const unsigned char *a,const ge_p3 *A,const unsigned char *b) 47 | { 48 | signed char aslide[256]; 49 | signed char bslide[256]; 50 | ge_cached Ai[8]; /* A,3A,5A,7A,9A,11A,13A,15A */ 51 | ge_p1p1 t; 52 | ge_p3 u; 53 | ge_p3 A2; 54 | int i; 55 | 56 | slide(aslide,a); 57 | slide(bslide,b); 58 | 59 | ge_p3_to_cached(&Ai[0],A); 60 | ge_p3_dbl(&t,A); ge_p1p1_to_p3(&A2,&t); 61 | ge_add(&t,&A2,&Ai[0]); ge_p1p1_to_p3(&u,&t); ge_p3_to_cached(&Ai[1],&u); 62 | ge_add(&t,&A2,&Ai[1]); ge_p1p1_to_p3(&u,&t); ge_p3_to_cached(&Ai[2],&u); 63 | ge_add(&t,&A2,&Ai[2]); ge_p1p1_to_p3(&u,&t); ge_p3_to_cached(&Ai[3],&u); 64 | ge_add(&t,&A2,&Ai[3]); ge_p1p1_to_p3(&u,&t); ge_p3_to_cached(&Ai[4],&u); 65 | ge_add(&t,&A2,&Ai[4]); ge_p1p1_to_p3(&u,&t); ge_p3_to_cached(&Ai[5],&u); 66 | ge_add(&t,&A2,&Ai[5]); ge_p1p1_to_p3(&u,&t); ge_p3_to_cached(&Ai[6],&u); 67 | ge_add(&t,&A2,&Ai[6]); ge_p1p1_to_p3(&u,&t); ge_p3_to_cached(&Ai[7],&u); 68 | 69 | ge_p2_0(r); 70 | 71 | for (i = 255;i >= 0;--i) { 72 | if (aslide[i] || bslide[i]) break; 73 | } 74 | 75 | for (;i >= 0;--i) { 76 | ge_p2_dbl(&t,r); 77 | 78 | if (aslide[i] > 0) { 79 | ge_p1p1_to_p3(&u,&t); 80 | ge_add(&t,&u,&Ai[aslide[i]/2]); 81 | } else if (aslide[i] < 0) { 82 | ge_p1p1_to_p3(&u,&t); 83 | ge_sub(&t,&u,&Ai[(-aslide[i])/2]); 84 | } 85 | 86 | if (bslide[i] > 0) { 87 | ge_p1p1_to_p3(&u,&t); 88 | ge_madd(&t,&u,&Bi[bslide[i]/2]); 89 | } else if (bslide[i] < 0) { 90 | ge_p1p1_to_p3(&u,&t); 91 | ge_msub(&t,&u,&Bi[(-bslide[i])/2]); 92 | } 93 | 94 | ge_p1p1_to_p2(r,&t); 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /native/ed25519/ge_frombytes.c: -------------------------------------------------------------------------------- 1 | #include "ge.h" 2 | 3 | static const fe d = { 4 | #include "d.h" 5 | } ; 6 | 7 | static const fe sqrtm1 = { 8 | #include "sqrtm1.h" 9 | } ; 10 | 11 | int ge_frombytes_negate_vartime(ge_p3 *h,const unsigned char *s) 12 | { 13 | fe u; 14 | fe v; 15 | fe v3; 16 | fe vxx; 17 | fe check; 18 | 19 | fe_frombytes(h->Y,s); 20 | fe_1(h->Z); 21 | fe_sq(u,h->Y); 22 | fe_mul(v,u,d); 23 | fe_sub(u,u,h->Z); /* u = y^2-1 */ 24 | fe_add(v,v,h->Z); /* v = dy^2+1 */ 25 | 26 | fe_sq(v3,v); 27 | fe_mul(v3,v3,v); /* v3 = v^3 */ 28 | fe_sq(h->X,v3); 29 | fe_mul(h->X,h->X,v); 30 | fe_mul(h->X,h->X,u); /* x = uv^7 */ 31 | 32 | fe_pow22523(h->X,h->X); /* x = (uv^7)^((q-5)/8) */ 33 | fe_mul(h->X,h->X,v3); 34 | fe_mul(h->X,h->X,u); /* x = uv^3(uv^7)^((q-5)/8) */ 35 | 36 | fe_sq(vxx,h->X); 37 | fe_mul(vxx,vxx,v); 38 | fe_sub(check,vxx,u); /* vx^2-u */ 39 | if (fe_isnonzero(check)) { 40 | fe_add(check,vxx,u); /* vx^2+u */ 41 | if (fe_isnonzero(check)) return -1; 42 | fe_mul(h->X,h->X,sqrtm1); 43 | } 44 | 45 | if (fe_isnegative(h->X) == (s[31] >> 7)) 46 | fe_neg(h->X,h->X); 47 | 48 | fe_mul(h->T,h->X,h->Y); 49 | return 0; 50 | } 51 | -------------------------------------------------------------------------------- /native/ed25519/ge_madd.c: -------------------------------------------------------------------------------- 1 | #include "ge.h" 2 | 3 | /* 4 | r = p + q 5 | */ 6 | 7 | void ge_madd(ge_p1p1 *r,const ge_p3 *p,const ge_precomp *q) 8 | { 9 | fe t0; 10 | #include "ge_madd.h" 11 | } 12 | -------------------------------------------------------------------------------- /native/ed25519/ge_madd.h: -------------------------------------------------------------------------------- 1 | 2 | /* qhasm: enter ge_madd */ 3 | 4 | /* qhasm: fe X1 */ 5 | 6 | /* qhasm: fe Y1 */ 7 | 8 | /* qhasm: fe Z1 */ 9 | 10 | /* qhasm: fe T1 */ 11 | 12 | /* qhasm: fe ypx2 */ 13 | 14 | /* qhasm: fe ymx2 */ 15 | 16 | /* qhasm: fe xy2d2 */ 17 | 18 | /* qhasm: fe X3 */ 19 | 20 | /* qhasm: fe Y3 */ 21 | 22 | /* qhasm: fe Z3 */ 23 | 24 | /* qhasm: fe T3 */ 25 | 26 | /* qhasm: fe YpX1 */ 27 | 28 | /* qhasm: fe YmX1 */ 29 | 30 | /* qhasm: fe A */ 31 | 32 | /* qhasm: fe B */ 33 | 34 | /* qhasm: fe C */ 35 | 36 | /* qhasm: fe D */ 37 | 38 | /* qhasm: YpX1 = Y1+X1 */ 39 | /* asm 1: fe_add(>YpX1=fe#1,YpX1=r->X,Y,X); */ 41 | fe_add(r->X,p->Y,p->X); 42 | 43 | /* qhasm: YmX1 = Y1-X1 */ 44 | /* asm 1: fe_sub(>YmX1=fe#2,YmX1=r->Y,Y,X); */ 46 | fe_sub(r->Y,p->Y,p->X); 47 | 48 | /* qhasm: A = YpX1*ypx2 */ 49 | /* asm 1: fe_mul(>A=fe#3,A=r->Z,X,yplusx); */ 51 | fe_mul(r->Z,r->X,q->yplusx); 52 | 53 | /* qhasm: B = YmX1*ymx2 */ 54 | /* asm 1: fe_mul(>B=fe#2,B=r->Y,Y,yminusx); */ 56 | fe_mul(r->Y,r->Y,q->yminusx); 57 | 58 | /* qhasm: C = xy2d2*T1 */ 59 | /* asm 1: fe_mul(>C=fe#4,C=r->T,xy2d,T); */ 61 | fe_mul(r->T,q->xy2d,p->T); 62 | 63 | /* qhasm: D = 2*Z1 */ 64 | /* asm 1: fe_add(>D=fe#5,D=t0,Z,Z); */ 66 | fe_add(t0,p->Z,p->Z); 67 | 68 | /* qhasm: X3 = A-B */ 69 | /* asm 1: fe_sub(>X3=fe#1,X3=r->X,Z,Y); */ 71 | fe_sub(r->X,r->Z,r->Y); 72 | 73 | /* qhasm: Y3 = A+B */ 74 | /* asm 1: fe_add(>Y3=fe#2,Y3=r->Y,Z,Y); */ 76 | fe_add(r->Y,r->Z,r->Y); 77 | 78 | /* qhasm: Z3 = D+C */ 79 | /* asm 1: fe_add(>Z3=fe#3,Z3=r->Z,T); */ 81 | fe_add(r->Z,t0,r->T); 82 | 83 | /* qhasm: T3 = D-C */ 84 | /* asm 1: fe_sub(>T3=fe#4,T3=r->T,T); */ 86 | fe_sub(r->T,t0,r->T); 87 | 88 | /* qhasm: return */ 89 | -------------------------------------------------------------------------------- /native/ed25519/ge_msub.c: -------------------------------------------------------------------------------- 1 | #include "ge.h" 2 | 3 | /* 4 | r = p - q 5 | */ 6 | 7 | void ge_msub(ge_p1p1 *r,const ge_p3 *p,const ge_precomp *q) 8 | { 9 | fe t0; 10 | #include "ge_msub.h" 11 | } 12 | -------------------------------------------------------------------------------- /native/ed25519/ge_msub.h: -------------------------------------------------------------------------------- 1 | 2 | /* qhasm: enter ge_msub */ 3 | 4 | /* qhasm: fe X1 */ 5 | 6 | /* qhasm: fe Y1 */ 7 | 8 | /* qhasm: fe Z1 */ 9 | 10 | /* qhasm: fe T1 */ 11 | 12 | /* qhasm: fe ypx2 */ 13 | 14 | /* qhasm: fe ymx2 */ 15 | 16 | /* qhasm: fe xy2d2 */ 17 | 18 | /* qhasm: fe X3 */ 19 | 20 | /* qhasm: fe Y3 */ 21 | 22 | /* qhasm: fe Z3 */ 23 | 24 | /* qhasm: fe T3 */ 25 | 26 | /* qhasm: fe YpX1 */ 27 | 28 | /* qhasm: fe YmX1 */ 29 | 30 | /* qhasm: fe A */ 31 | 32 | /* qhasm: fe B */ 33 | 34 | /* qhasm: fe C */ 35 | 36 | /* qhasm: fe D */ 37 | 38 | /* qhasm: YpX1 = Y1+X1 */ 39 | /* asm 1: fe_add(>YpX1=fe#1,YpX1=r->X,Y,X); */ 41 | fe_add(r->X,p->Y,p->X); 42 | 43 | /* qhasm: YmX1 = Y1-X1 */ 44 | /* asm 1: fe_sub(>YmX1=fe#2,YmX1=r->Y,Y,X); */ 46 | fe_sub(r->Y,p->Y,p->X); 47 | 48 | /* qhasm: A = YpX1*ymx2 */ 49 | /* asm 1: fe_mul(>A=fe#3,A=r->Z,X,yminusx); */ 51 | fe_mul(r->Z,r->X,q->yminusx); 52 | 53 | /* qhasm: B = YmX1*ypx2 */ 54 | /* asm 1: fe_mul(>B=fe#2,B=r->Y,Y,yplusx); */ 56 | fe_mul(r->Y,r->Y,q->yplusx); 57 | 58 | /* qhasm: C = xy2d2*T1 */ 59 | /* asm 1: fe_mul(>C=fe#4,C=r->T,xy2d,T); */ 61 | fe_mul(r->T,q->xy2d,p->T); 62 | 63 | /* qhasm: D = 2*Z1 */ 64 | /* asm 1: fe_add(>D=fe#5,D=t0,Z,Z); */ 66 | fe_add(t0,p->Z,p->Z); 67 | 68 | /* qhasm: X3 = A-B */ 69 | /* asm 1: fe_sub(>X3=fe#1,X3=r->X,Z,Y); */ 71 | fe_sub(r->X,r->Z,r->Y); 72 | 73 | /* qhasm: Y3 = A+B */ 74 | /* asm 1: fe_add(>Y3=fe#2,Y3=r->Y,Z,Y); */ 76 | fe_add(r->Y,r->Z,r->Y); 77 | 78 | /* qhasm: Z3 = D-C */ 79 | /* asm 1: fe_sub(>Z3=fe#3,Z3=r->Z,T); */ 81 | fe_sub(r->Z,t0,r->T); 82 | 83 | /* qhasm: T3 = D+C */ 84 | /* asm 1: fe_add(>T3=fe#4,T3=r->T,T); */ 86 | fe_add(r->T,t0,r->T); 87 | 88 | /* qhasm: return */ 89 | -------------------------------------------------------------------------------- /native/ed25519/ge_p1p1_to_p2.c: -------------------------------------------------------------------------------- 1 | #include "ge.h" 2 | 3 | /* 4 | r = p 5 | */ 6 | 7 | extern void ge_p1p1_to_p2(ge_p2 *r,const ge_p1p1 *p) 8 | { 9 | fe_mul(r->X,p->X,p->T); 10 | fe_mul(r->Y,p->Y,p->Z); 11 | fe_mul(r->Z,p->Z,p->T); 12 | } 13 | -------------------------------------------------------------------------------- /native/ed25519/ge_p1p1_to_p3.c: -------------------------------------------------------------------------------- 1 | #include "ge.h" 2 | 3 | /* 4 | r = p 5 | */ 6 | 7 | extern void ge_p1p1_to_p3(ge_p3 *r,const ge_p1p1 *p) 8 | { 9 | fe_mul(r->X,p->X,p->T); 10 | fe_mul(r->Y,p->Y,p->Z); 11 | fe_mul(r->Z,p->Z,p->T); 12 | fe_mul(r->T,p->X,p->Y); 13 | } 14 | -------------------------------------------------------------------------------- /native/ed25519/ge_p2_0.c: -------------------------------------------------------------------------------- 1 | #include "ge.h" 2 | 3 | void ge_p2_0(ge_p2 *h) 4 | { 5 | fe_0(h->X); 6 | fe_1(h->Y); 7 | fe_1(h->Z); 8 | } 9 | -------------------------------------------------------------------------------- /native/ed25519/ge_p2_dbl.c: -------------------------------------------------------------------------------- 1 | #include "ge.h" 2 | 3 | /* 4 | r = 2 * p 5 | */ 6 | 7 | void ge_p2_dbl(ge_p1p1 *r,const ge_p2 *p) 8 | { 9 | fe t0; 10 | #include "ge_p2_dbl.h" 11 | } 12 | -------------------------------------------------------------------------------- /native/ed25519/ge_p2_dbl.h: -------------------------------------------------------------------------------- 1 | 2 | /* qhasm: enter ge_p2_dbl */ 3 | 4 | /* qhasm: fe X1 */ 5 | 6 | /* qhasm: fe Y1 */ 7 | 8 | /* qhasm: fe Z1 */ 9 | 10 | /* qhasm: fe A */ 11 | 12 | /* qhasm: fe AA */ 13 | 14 | /* qhasm: fe XX */ 15 | 16 | /* qhasm: fe YY */ 17 | 18 | /* qhasm: fe B */ 19 | 20 | /* qhasm: fe X3 */ 21 | 22 | /* qhasm: fe Y3 */ 23 | 24 | /* qhasm: fe Z3 */ 25 | 26 | /* qhasm: fe T3 */ 27 | 28 | /* qhasm: XX=X1^2 */ 29 | /* asm 1: fe_sq(>XX=fe#1,XX=r->X,X); */ 31 | fe_sq(r->X,p->X); 32 | 33 | /* qhasm: YY=Y1^2 */ 34 | /* asm 1: fe_sq(>YY=fe#3,YY=r->Z,Y); */ 36 | fe_sq(r->Z,p->Y); 37 | 38 | /* qhasm: B=2*Z1^2 */ 39 | /* asm 1: fe_sq2(>B=fe#4,B=r->T,Z); */ 41 | fe_sq2(r->T,p->Z); 42 | 43 | /* qhasm: A=X1+Y1 */ 44 | /* asm 1: fe_add(>A=fe#2,A=r->Y,X,Y); */ 46 | fe_add(r->Y,p->X,p->Y); 47 | 48 | /* qhasm: AA=A^2 */ 49 | /* asm 1: fe_sq(>AA=fe#5,AA=t0,Y); */ 51 | fe_sq(t0,r->Y); 52 | 53 | /* qhasm: Y3=YY+XX */ 54 | /* asm 1: fe_add(>Y3=fe#2,Y3=r->Y,Z,X); */ 56 | fe_add(r->Y,r->Z,r->X); 57 | 58 | /* qhasm: Z3=YY-XX */ 59 | /* asm 1: fe_sub(>Z3=fe#3,Z3=r->Z,Z,X); */ 61 | fe_sub(r->Z,r->Z,r->X); 62 | 63 | /* qhasm: X3=AA-Y3 */ 64 | /* asm 1: fe_sub(>X3=fe#1,X3=r->X,Y); */ 66 | fe_sub(r->X,t0,r->Y); 67 | 68 | /* qhasm: T3=B-Z3 */ 69 | /* asm 1: fe_sub(>T3=fe#4,T3=r->T,T,Z); */ 71 | fe_sub(r->T,r->T,r->Z); 72 | 73 | /* qhasm: return */ 74 | -------------------------------------------------------------------------------- /native/ed25519/ge_p3_0.c: -------------------------------------------------------------------------------- 1 | #include "ge.h" 2 | 3 | void ge_p3_0(ge_p3 *h) 4 | { 5 | fe_0(h->X); 6 | fe_1(h->Y); 7 | fe_1(h->Z); 8 | fe_0(h->T); 9 | } 10 | -------------------------------------------------------------------------------- /native/ed25519/ge_p3_dbl.c: -------------------------------------------------------------------------------- 1 | #include "ge.h" 2 | 3 | /* 4 | r = 2 * p 5 | */ 6 | 7 | void ge_p3_dbl(ge_p1p1 *r,const ge_p3 *p) 8 | { 9 | ge_p2 q; 10 | ge_p3_to_p2(&q,p); 11 | ge_p2_dbl(r,&q); 12 | } 13 | -------------------------------------------------------------------------------- /native/ed25519/ge_p3_to_cached.c: -------------------------------------------------------------------------------- 1 | #include "ge.h" 2 | 3 | /* 4 | r = p 5 | */ 6 | 7 | static const fe d2 = { 8 | #include "d2.h" 9 | } ; 10 | 11 | extern void ge_p3_to_cached(ge_cached *r,const ge_p3 *p) 12 | { 13 | fe_add(r->YplusX,p->Y,p->X); 14 | fe_sub(r->YminusX,p->Y,p->X); 15 | fe_copy(r->Z,p->Z); 16 | fe_mul(r->T2d,p->T,d2); 17 | } 18 | -------------------------------------------------------------------------------- /native/ed25519/ge_p3_to_p2.c: -------------------------------------------------------------------------------- 1 | #include "ge.h" 2 | 3 | /* 4 | r = p 5 | */ 6 | 7 | extern void ge_p3_to_p2(ge_p2 *r,const ge_p3 *p) 8 | { 9 | fe_copy(r->X,p->X); 10 | fe_copy(r->Y,p->Y); 11 | fe_copy(r->Z,p->Z); 12 | } 13 | -------------------------------------------------------------------------------- /native/ed25519/ge_p3_tobytes.c: -------------------------------------------------------------------------------- 1 | #include "ge.h" 2 | 3 | void ge_p3_tobytes(unsigned char *s,const ge_p3 *h) 4 | { 5 | fe recip; 6 | fe x; 7 | fe y; 8 | 9 | fe_invert(recip,h->Z); 10 | fe_mul(x,h->X,recip); 11 | fe_mul(y,h->Y,recip); 12 | fe_tobytes(s,y); 13 | s[31] ^= fe_isnegative(x) << 7; 14 | } 15 | -------------------------------------------------------------------------------- /native/ed25519/ge_precomp_0.c: -------------------------------------------------------------------------------- 1 | #include "ge.h" 2 | 3 | void ge_precomp_0(ge_precomp *h) 4 | { 5 | fe_1(h->yplusx); 6 | fe_1(h->yminusx); 7 | fe_0(h->xy2d); 8 | } 9 | -------------------------------------------------------------------------------- /native/ed25519/ge_scalarmult_base.c: -------------------------------------------------------------------------------- 1 | #include "ge.h" 2 | #include "crypto_uint32.h" 3 | 4 | static unsigned char equal(signed char b,signed char c) 5 | { 6 | unsigned char ub = b; 7 | unsigned char uc = c; 8 | unsigned char x = ub ^ uc; /* 0: yes; 1..255: no */ 9 | crypto_uint32 y = x; /* 0: yes; 1..255: no */ 10 | y -= 1; /* 4294967295: yes; 0..254: no */ 11 | y >>= 31; /* 1: yes; 0: no */ 12 | return y; 13 | } 14 | 15 | static unsigned char negative(signed char b) 16 | { 17 | unsigned long long x = b; /* 18446744073709551361..18446744073709551615: yes; 0..255: no */ 18 | x >>= 63; /* 1: yes; 0: no */ 19 | return x; 20 | } 21 | 22 | static void cmov(ge_precomp *t,ge_precomp *u,unsigned char b) 23 | { 24 | fe_cmov(t->yplusx,u->yplusx,b); 25 | fe_cmov(t->yminusx,u->yminusx,b); 26 | fe_cmov(t->xy2d,u->xy2d,b); 27 | } 28 | 29 | /* base[i][j] = (j+1)*256^i*B */ 30 | static ge_precomp base[32][8] = { 31 | #include "base.h" 32 | } ; 33 | 34 | static void select(ge_precomp *t,int pos,signed char b) 35 | { 36 | ge_precomp minust; 37 | unsigned char bnegative = negative(b); 38 | unsigned char babs = b - (((-bnegative) & b) << 1); 39 | 40 | ge_precomp_0(t); 41 | cmov(t,&base[pos][0],equal(babs,1)); 42 | cmov(t,&base[pos][1],equal(babs,2)); 43 | cmov(t,&base[pos][2],equal(babs,3)); 44 | cmov(t,&base[pos][3],equal(babs,4)); 45 | cmov(t,&base[pos][4],equal(babs,5)); 46 | cmov(t,&base[pos][5],equal(babs,6)); 47 | cmov(t,&base[pos][6],equal(babs,7)); 48 | cmov(t,&base[pos][7],equal(babs,8)); 49 | fe_copy(minust.yplusx,t->yminusx); 50 | fe_copy(minust.yminusx,t->yplusx); 51 | fe_neg(minust.xy2d,t->xy2d); 52 | cmov(t,&minust,bnegative); 53 | } 54 | 55 | /* 56 | h = a * B 57 | where a = a[0]+256*a[1]+...+256^31 a[31] 58 | B is the Ed25519 base point (x,4/5) with x positive. 59 | 60 | Preconditions: 61 | a[31] <= 127 62 | */ 63 | 64 | void ge_scalarmult_base(ge_p3 *h,const unsigned char *a) 65 | { 66 | signed char e[64]; 67 | signed char carry; 68 | ge_p1p1 r; 69 | ge_p2 s; 70 | ge_precomp t; 71 | int i; 72 | 73 | for (i = 0;i < 32;++i) { 74 | e[2 * i + 0] = (a[i] >> 0) & 15; 75 | e[2 * i + 1] = (a[i] >> 4) & 15; 76 | } 77 | /* each e[i] is between 0 and 15 */ 78 | /* e[63] is between 0 and 7 */ 79 | 80 | carry = 0; 81 | for (i = 0;i < 63;++i) { 82 | e[i] += carry; 83 | carry = e[i] + 8; 84 | carry >>= 4; 85 | e[i] -= carry << 4; 86 | } 87 | e[63] += carry; 88 | /* each e[i] is between -8 and 8 */ 89 | 90 | ge_p3_0(h); 91 | for (i = 1;i < 64;i += 2) { 92 | select(&t,i / 2,e[i]); 93 | ge_madd(&r,h,&t); ge_p1p1_to_p3(h,&r); 94 | } 95 | 96 | ge_p3_dbl(&r,h); ge_p1p1_to_p2(&s,&r); 97 | ge_p2_dbl(&r,&s); ge_p1p1_to_p2(&s,&r); 98 | ge_p2_dbl(&r,&s); ge_p1p1_to_p2(&s,&r); 99 | ge_p2_dbl(&r,&s); ge_p1p1_to_p3(h,&r); 100 | 101 | for (i = 0;i < 64;i += 2) { 102 | select(&t,i / 2,e[i]); 103 | ge_madd(&r,h,&t); ge_p1p1_to_p3(h,&r); 104 | } 105 | } 106 | -------------------------------------------------------------------------------- /native/ed25519/ge_sub.c: -------------------------------------------------------------------------------- 1 | #include "ge.h" 2 | 3 | /* 4 | r = p - q 5 | */ 6 | 7 | void ge_sub(ge_p1p1 *r,const ge_p3 *p,const ge_cached *q) 8 | { 9 | fe t0; 10 | #include "ge_sub.h" 11 | } 12 | -------------------------------------------------------------------------------- /native/ed25519/ge_sub.h: -------------------------------------------------------------------------------- 1 | 2 | /* qhasm: enter ge_sub */ 3 | 4 | /* qhasm: fe X1 */ 5 | 6 | /* qhasm: fe Y1 */ 7 | 8 | /* qhasm: fe Z1 */ 9 | 10 | /* qhasm: fe Z2 */ 11 | 12 | /* qhasm: fe T1 */ 13 | 14 | /* qhasm: fe ZZ */ 15 | 16 | /* qhasm: fe YpX2 */ 17 | 18 | /* qhasm: fe YmX2 */ 19 | 20 | /* qhasm: fe T2d2 */ 21 | 22 | /* qhasm: fe X3 */ 23 | 24 | /* qhasm: fe Y3 */ 25 | 26 | /* qhasm: fe Z3 */ 27 | 28 | /* qhasm: fe T3 */ 29 | 30 | /* qhasm: fe YpX1 */ 31 | 32 | /* qhasm: fe YmX1 */ 33 | 34 | /* qhasm: fe A */ 35 | 36 | /* qhasm: fe B */ 37 | 38 | /* qhasm: fe C */ 39 | 40 | /* qhasm: fe D */ 41 | 42 | /* qhasm: YpX1 = Y1+X1 */ 43 | /* asm 1: fe_add(>YpX1=fe#1,YpX1=r->X,Y,X); */ 45 | fe_add(r->X,p->Y,p->X); 46 | 47 | /* qhasm: YmX1 = Y1-X1 */ 48 | /* asm 1: fe_sub(>YmX1=fe#2,YmX1=r->Y,Y,X); */ 50 | fe_sub(r->Y,p->Y,p->X); 51 | 52 | /* qhasm: A = YpX1*YmX2 */ 53 | /* asm 1: fe_mul(>A=fe#3,A=r->Z,X,YminusX); */ 55 | fe_mul(r->Z,r->X,q->YminusX); 56 | 57 | /* qhasm: B = YmX1*YpX2 */ 58 | /* asm 1: fe_mul(>B=fe#2,B=r->Y,Y,YplusX); */ 60 | fe_mul(r->Y,r->Y,q->YplusX); 61 | 62 | /* qhasm: C = T2d2*T1 */ 63 | /* asm 1: fe_mul(>C=fe#4,C=r->T,T2d,T); */ 65 | fe_mul(r->T,q->T2d,p->T); 66 | 67 | /* qhasm: ZZ = Z1*Z2 */ 68 | /* asm 1: fe_mul(>ZZ=fe#1,ZZ=r->X,Z,Z); */ 70 | fe_mul(r->X,p->Z,q->Z); 71 | 72 | /* qhasm: D = 2*ZZ */ 73 | /* asm 1: fe_add(>D=fe#5,D=t0,X,X); */ 75 | fe_add(t0,r->X,r->X); 76 | 77 | /* qhasm: X3 = A-B */ 78 | /* asm 1: fe_sub(>X3=fe#1,X3=r->X,Z,Y); */ 80 | fe_sub(r->X,r->Z,r->Y); 81 | 82 | /* qhasm: Y3 = A+B */ 83 | /* asm 1: fe_add(>Y3=fe#2,Y3=r->Y,Z,Y); */ 85 | fe_add(r->Y,r->Z,r->Y); 86 | 87 | /* qhasm: Z3 = D-C */ 88 | /* asm 1: fe_sub(>Z3=fe#3,Z3=r->Z,T); */ 90 | fe_sub(r->Z,t0,r->T); 91 | 92 | /* qhasm: T3 = D+C */ 93 | /* asm 1: fe_add(>T3=fe#4,T3=r->T,T); */ 95 | fe_add(r->T,t0,r->T); 96 | 97 | /* qhasm: return */ 98 | -------------------------------------------------------------------------------- /native/ed25519/ge_tobytes.c: -------------------------------------------------------------------------------- 1 | #include "ge.h" 2 | 3 | void ge_tobytes(unsigned char *s,const ge_p2 *h) 4 | { 5 | fe recip; 6 | fe x; 7 | fe y; 8 | 9 | fe_invert(recip,h->Z); 10 | fe_mul(x,h->X,recip); 11 | fe_mul(y,h->Y,recip); 12 | fe_tobytes(s,y); 13 | s[31] ^= fe_isnegative(x) << 7; 14 | } 15 | -------------------------------------------------------------------------------- /native/ed25519/main/main.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "sha512.h" 4 | #include "curve_sigs.h" 5 | 6 | int main(int argc, char* argv[]) 7 | { 8 | unsigned char privkey[32]; 9 | unsigned char pubkey[32]; 10 | unsigned char signature[64]; 11 | unsigned char msg[100]; 12 | unsigned long long msg_len = 100; 13 | 14 | /* Initialize pubkey, privkey, msg */ 15 | memset(msg, 0, 100); 16 | memset(privkey, 0, 32); 17 | memset(pubkey, 0, 32); 18 | privkey[0] &= 248; 19 | privkey[31] &= 63; 20 | privkey[31] |= 64; 21 | 22 | privkey[8] = 189; /* just so there's some bits set */ 23 | 24 | curve25519_keygen(pubkey, privkey); 25 | 26 | curve25519_sign(signature, privkey, msg, msg_len); 27 | 28 | if (curve25519_verify(signature, pubkey, msg, msg_len) == 0) 29 | printf("success #1\n"); 30 | else 31 | printf("failure #1\n"); 32 | 33 | signature[0] ^= 1; 34 | 35 | if (curve25519_verify(signature, pubkey, msg, msg_len) == 0) 36 | printf("failure #2\n"); 37 | else 38 | printf("success #2\n"); 39 | 40 | return 1; 41 | } 42 | -------------------------------------------------------------------------------- /native/ed25519/nacl_includes/crypto_hash_sha512.h: -------------------------------------------------------------------------------- 1 | #ifndef crypto_hash_sha512_H 2 | #define crypto_hash_sha512_H 3 | 4 | #define crypto_hash_sha512_ref_BYTES 64 5 | #ifdef __cplusplus 6 | #include 7 | extern std::string crypto_hash_sha512_ref(const std::string &); 8 | extern "C" { 9 | #endif 10 | extern int crypto_hash_sha512_ref(unsigned char *,const unsigned char *,unsigned long long); 11 | #ifdef __cplusplus 12 | } 13 | #endif 14 | 15 | #define crypto_hash_sha512 crypto_hash_sha512_ref 16 | #define crypto_hash_sha512_BYTES crypto_hash_sha512_ref_BYTES 17 | #define crypto_hash_sha512_IMPLEMENTATION "crypto_hash/sha512/ref" 18 | #ifndef crypto_hash_sha512_ref_VERSION 19 | #define crypto_hash_sha512_ref_VERSION "-" 20 | #endif 21 | #define crypto_hash_sha512_VERSION crypto_hash_sha512_ref_VERSION 22 | 23 | #endif 24 | -------------------------------------------------------------------------------- /native/ed25519/nacl_includes/crypto_int32.h: -------------------------------------------------------------------------------- 1 | #ifndef crypto_int32_h 2 | #define crypto_int32_h 3 | 4 | typedef int crypto_int32; 5 | 6 | #endif 7 | -------------------------------------------------------------------------------- /native/ed25519/nacl_includes/crypto_int64.h: -------------------------------------------------------------------------------- 1 | #ifndef crypto_int64_h 2 | #define crypto_int64_h 3 | 4 | typedef long long crypto_int64; 5 | 6 | #endif 7 | -------------------------------------------------------------------------------- /native/ed25519/nacl_includes/crypto_sign.h: -------------------------------------------------------------------------------- 1 | #ifndef crypto_sign_H 2 | #define crypto_sign_H 3 | 4 | #include "crypto_sign_edwards25519sha512batch.h" 5 | 6 | #define crypto_sign crypto_sign_edwards25519sha512batch 7 | #define crypto_sign_open crypto_sign_edwards25519sha512batch_open 8 | #define crypto_sign_keypair crypto_sign_edwards25519sha512batch_keypair 9 | #define crypto_sign_BYTES crypto_sign_edwards25519sha512batch_BYTES 10 | #define crypto_sign_PUBLICKEYBYTES crypto_sign_edwards25519sha512batch_PUBLICKEYBYTES 11 | #define crypto_sign_SECRETKEYBYTES crypto_sign_edwards25519sha512batch_SECRETKEYBYTES 12 | #define crypto_sign_PRIMITIVE "edwards25519sha512batch" 13 | #define crypto_sign_IMPLEMENTATION crypto_sign_edwards25519sha512batch_IMPLEMENTATION 14 | #define crypto_sign_VERSION crypto_sign_edwards25519sha512batch_VERSION 15 | 16 | #endif 17 | -------------------------------------------------------------------------------- /native/ed25519/nacl_includes/crypto_sign_edwards25519sha512batch.h: -------------------------------------------------------------------------------- 1 | #ifndef crypto_sign_edwards25519sha512batch_H 2 | #define crypto_sign_edwards25519sha512batch_H 3 | 4 | #define crypto_sign_edwards25519sha512batch_ref10_SECRETKEYBYTES 64 5 | #define crypto_sign_edwards25519sha512batch_ref10_PUBLICKEYBYTES 32 6 | #define crypto_sign_edwards25519sha512batch_ref10_BYTES 64 7 | #ifdef __cplusplus 8 | #include 9 | extern std::string crypto_sign_edwards25519sha512batch_ref10(const std::string &,const std::string &); 10 | extern std::string crypto_sign_edwards25519sha512batch_ref10_open(const std::string &,const std::string &); 11 | extern std::string crypto_sign_edwards25519sha512batch_ref10_keypair(std::string *); 12 | extern "C" { 13 | #endif 14 | extern int crypto_sign_edwards25519sha512batch_ref10(unsigned char *,unsigned long long *,const unsigned char *,unsigned long long,const unsigned char *); 15 | extern int crypto_sign_edwards25519sha512batch_ref10_open(unsigned char *,unsigned long long *,const unsigned char *,unsigned long long,const unsigned char *); 16 | extern int crypto_sign_edwards25519sha512batch_ref10_keypair(unsigned char *,unsigned char *); 17 | #ifdef __cplusplus 18 | } 19 | #endif 20 | 21 | #define crypto_sign_edwards25519sha512batch crypto_sign_edwards25519sha512batch_ref10 22 | #define crypto_sign_edwards25519sha512batch_open crypto_sign_edwards25519sha512batch_ref10_open 23 | #define crypto_sign_edwards25519sha512batch_keypair crypto_sign_edwards25519sha512batch_ref10_keypair 24 | #define crypto_sign_edwards25519sha512batch_BYTES crypto_sign_edwards25519sha512batch_ref10_BYTES 25 | #define crypto_sign_edwards25519sha512batch_PUBLICKEYBYTES crypto_sign_edwards25519sha512batch_ref10_PUBLICKEYBYTES 26 | #define crypto_sign_edwards25519sha512batch_SECRETKEYBYTES crypto_sign_edwards25519sha512batch_ref10_SECRETKEYBYTES 27 | #define crypto_sign_edwards25519sha512batch_IMPLEMENTATION "crypto_sign/edwards25519sha512batch/ref10" 28 | #ifndef crypto_sign_edwards25519sha512batch_ref10_VERSION 29 | #define crypto_sign_edwards25519sha512batch_ref10_VERSION "-" 30 | #endif 31 | #define crypto_sign_edwards25519sha512batch_VERSION crypto_sign_edwards25519sha512batch_ref10_VERSION 32 | 33 | #endif 34 | -------------------------------------------------------------------------------- /native/ed25519/nacl_includes/crypto_uint32.h: -------------------------------------------------------------------------------- 1 | #ifndef crypto_uint32_h 2 | #define crypto_uint32_h 3 | 4 | typedef unsigned int crypto_uint32; 5 | 6 | #endif 7 | -------------------------------------------------------------------------------- /native/ed25519/nacl_includes/crypto_uint64.h: -------------------------------------------------------------------------------- 1 | #ifndef crypto_uint64_h 2 | #define crypto_uint64_h 3 | 4 | typedef unsigned long long crypto_uint64; 5 | 6 | #endif 7 | -------------------------------------------------------------------------------- /native/ed25519/nacl_includes/crypto_verify_32.h: -------------------------------------------------------------------------------- 1 | #ifndef crypto_verify_32_H 2 | #define crypto_verify_32_H 3 | 4 | #define crypto_verify_32_ref_BYTES 32 5 | #ifdef __cplusplus 6 | #include 7 | extern "C" { 8 | #endif 9 | extern int crypto_verify_32_ref(const unsigned char *,const unsigned char *); 10 | #ifdef __cplusplus 11 | } 12 | #endif 13 | 14 | #define crypto_verify_32 crypto_verify_32_ref 15 | #define crypto_verify_32_BYTES crypto_verify_32_ref_BYTES 16 | #define crypto_verify_32_IMPLEMENTATION "crypto_verify/32/ref" 17 | #ifndef crypto_verify_32_ref_VERSION 18 | #define crypto_verify_32_ref_VERSION "-" 19 | #endif 20 | #define crypto_verify_32_VERSION crypto_verify_32_ref_VERSION 21 | 22 | #endif 23 | -------------------------------------------------------------------------------- /native/ed25519/open.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "crypto_sign.h" 3 | #include "crypto_hash_sha512.h" 4 | #include "crypto_verify_32.h" 5 | #include "ge.h" 6 | #include "sc.h" 7 | 8 | int crypto_sign_open( 9 | unsigned char *m,unsigned long long *mlen, 10 | const unsigned char *sm,unsigned long long smlen, 11 | const unsigned char *pk 12 | ) 13 | { 14 | unsigned char pkcopy[32]; 15 | unsigned char rcopy[32]; 16 | unsigned char scopy[32]; 17 | unsigned char h[64]; 18 | unsigned char rcheck[32]; 19 | ge_p3 A; 20 | ge_p2 R; 21 | 22 | if (smlen < 64) goto badsig; 23 | if (sm[63] & 224) goto badsig; 24 | if (ge_frombytes_negate_vartime(&A,pk) != 0) goto badsig; 25 | 26 | memmove(pkcopy,pk,32); 27 | memmove(rcopy,sm,32); 28 | memmove(scopy,sm + 32,32); 29 | 30 | memmove(m,sm,smlen); 31 | memmove(m + 32,pkcopy,32); 32 | crypto_hash_sha512(h,m,smlen); 33 | sc_reduce(h); 34 | 35 | ge_double_scalarmult_vartime(&R,h,&A,scopy); 36 | ge_tobytes(rcheck,&R); 37 | if (crypto_verify_32(rcheck,rcopy) == 0) { 38 | memmove(m,m + 64,smlen - 64); 39 | memset(m + smlen - 64,0,64); 40 | *mlen = smlen - 64; 41 | return 0; 42 | } 43 | 44 | badsig: 45 | *mlen = -1; 46 | memset(m,0,smlen); 47 | return -1; 48 | } 49 | -------------------------------------------------------------------------------- /native/ed25519/pow22523.h: -------------------------------------------------------------------------------- 1 | 2 | /* qhasm: fe z1 */ 3 | 4 | /* qhasm: fe z2 */ 5 | 6 | /* qhasm: fe z8 */ 7 | 8 | /* qhasm: fe z9 */ 9 | 10 | /* qhasm: fe z11 */ 11 | 12 | /* qhasm: fe z22 */ 13 | 14 | /* qhasm: fe z_5_0 */ 15 | 16 | /* qhasm: fe z_10_5 */ 17 | 18 | /* qhasm: fe z_10_0 */ 19 | 20 | /* qhasm: fe z_20_10 */ 21 | 22 | /* qhasm: fe z_20_0 */ 23 | 24 | /* qhasm: fe z_40_20 */ 25 | 26 | /* qhasm: fe z_40_0 */ 27 | 28 | /* qhasm: fe z_50_10 */ 29 | 30 | /* qhasm: fe z_50_0 */ 31 | 32 | /* qhasm: fe z_100_50 */ 33 | 34 | /* qhasm: fe z_100_0 */ 35 | 36 | /* qhasm: fe z_200_100 */ 37 | 38 | /* qhasm: fe z_200_0 */ 39 | 40 | /* qhasm: fe z_250_50 */ 41 | 42 | /* qhasm: fe z_250_0 */ 43 | 44 | /* qhasm: fe z_252_2 */ 45 | 46 | /* qhasm: fe z_252_3 */ 47 | 48 | /* qhasm: enter pow22523 */ 49 | 50 | /* qhasm: z2 = z1^2^1 */ 51 | /* asm 1: fe_sq(>z2=fe#1,z2=fe#1,>z2=fe#1); */ 52 | /* asm 2: fe_sq(>z2=t0,z2=t0,>z2=t0); */ 53 | fe_sq(t0,z); for (i = 1;i < 1;++i) fe_sq(t0,t0); 54 | 55 | /* qhasm: z8 = z2^2^2 */ 56 | /* asm 1: fe_sq(>z8=fe#2,z8=fe#2,>z8=fe#2); */ 57 | /* asm 2: fe_sq(>z8=t1,z8=t1,>z8=t1); */ 58 | fe_sq(t1,t0); for (i = 1;i < 2;++i) fe_sq(t1,t1); 59 | 60 | /* qhasm: z9 = z1*z8 */ 61 | /* asm 1: fe_mul(>z9=fe#2,z9=t1,z11=fe#1,z11=t0,z22=fe#1,z22=fe#1,>z22=fe#1); */ 72 | /* asm 2: fe_sq(>z22=t0,z22=t0,>z22=t0); */ 73 | fe_sq(t0,t0); for (i = 1;i < 1;++i) fe_sq(t0,t0); 74 | 75 | /* qhasm: z_5_0 = z9*z22 */ 76 | /* asm 1: fe_mul(>z_5_0=fe#1,z_5_0=t0,z_10_5=fe#2,z_10_5=fe#2,>z_10_5=fe#2); */ 82 | /* asm 2: fe_sq(>z_10_5=t1,z_10_5=t1,>z_10_5=t1); */ 83 | fe_sq(t1,t0); for (i = 1;i < 5;++i) fe_sq(t1,t1); 84 | 85 | /* qhasm: z_10_0 = z_10_5*z_5_0 */ 86 | /* asm 1: fe_mul(>z_10_0=fe#1,z_10_0=t0,z_20_10=fe#2,z_20_10=fe#2,>z_20_10=fe#2); */ 92 | /* asm 2: fe_sq(>z_20_10=t1,z_20_10=t1,>z_20_10=t1); */ 93 | fe_sq(t1,t0); for (i = 1;i < 10;++i) fe_sq(t1,t1); 94 | 95 | /* qhasm: z_20_0 = z_20_10*z_10_0 */ 96 | /* asm 1: fe_mul(>z_20_0=fe#2,z_20_0=t1,z_40_20=fe#3,z_40_20=fe#3,>z_40_20=fe#3); */ 102 | /* asm 2: fe_sq(>z_40_20=t2,z_40_20=t2,>z_40_20=t2); */ 103 | fe_sq(t2,t1); for (i = 1;i < 20;++i) fe_sq(t2,t2); 104 | 105 | /* qhasm: z_40_0 = z_40_20*z_20_0 */ 106 | /* asm 1: fe_mul(>z_40_0=fe#2,z_40_0=t1,z_50_10=fe#2,z_50_10=fe#2,>z_50_10=fe#2); */ 112 | /* asm 2: fe_sq(>z_50_10=t1,z_50_10=t1,>z_50_10=t1); */ 113 | fe_sq(t1,t1); for (i = 1;i < 10;++i) fe_sq(t1,t1); 114 | 115 | /* qhasm: z_50_0 = z_50_10*z_10_0 */ 116 | /* asm 1: fe_mul(>z_50_0=fe#1,z_50_0=t0,z_100_50=fe#2,z_100_50=fe#2,>z_100_50=fe#2); */ 122 | /* asm 2: fe_sq(>z_100_50=t1,z_100_50=t1,>z_100_50=t1); */ 123 | fe_sq(t1,t0); for (i = 1;i < 50;++i) fe_sq(t1,t1); 124 | 125 | /* qhasm: z_100_0 = z_100_50*z_50_0 */ 126 | /* asm 1: fe_mul(>z_100_0=fe#2,z_100_0=t1,z_200_100=fe#3,z_200_100=fe#3,>z_200_100=fe#3); */ 132 | /* asm 2: fe_sq(>z_200_100=t2,z_200_100=t2,>z_200_100=t2); */ 133 | fe_sq(t2,t1); for (i = 1;i < 100;++i) fe_sq(t2,t2); 134 | 135 | /* qhasm: z_200_0 = z_200_100*z_100_0 */ 136 | /* asm 1: fe_mul(>z_200_0=fe#2,z_200_0=t1,z_250_50=fe#2,z_250_50=fe#2,>z_250_50=fe#2); */ 142 | /* asm 2: fe_sq(>z_250_50=t1,z_250_50=t1,>z_250_50=t1); */ 143 | fe_sq(t1,t1); for (i = 1;i < 50;++i) fe_sq(t1,t1); 144 | 145 | /* qhasm: z_250_0 = z_250_50*z_50_0 */ 146 | /* asm 1: fe_mul(>z_250_0=fe#1,z_250_0=t0,z_252_2=fe#1,z_252_2=fe#1,>z_252_2=fe#1); */ 152 | /* asm 2: fe_sq(>z_252_2=t0,z_252_2=t0,>z_252_2=t0); */ 153 | fe_sq(t0,t0); for (i = 1;i < 2;++i) fe_sq(t0,t0); 154 | 155 | /* qhasm: z_252_3 = z_252_2*z1 */ 156 | /* asm 1: fe_mul(>z_252_3=fe#12,z_252_3=out,z2=fe#1,z2=fe#1,>z2=fe#1); */ 52 | /* asm 2: fe_sq(>z2=t0,z2=t0,>z2=t0); */ 53 | fe_sq(t0,z); for (i = 1;i < 1;++i) fe_sq(t0,t0); 54 | 55 | /* qhasm: z8 = z2^2^2 */ 56 | /* asm 1: fe_sq(>z8=fe#2,z8=fe#2,>z8=fe#2); */ 57 | /* asm 2: fe_sq(>z8=t1,z8=t1,>z8=t1); */ 58 | fe_sq(t1,t0); for (i = 1;i < 2;++i) fe_sq(t1,t1); 59 | 60 | /* qhasm: z9 = z1*z8 */ 61 | /* asm 1: fe_mul(>z9=fe#2,z9=t1,z11=fe#1,z11=t0,z22=fe#3,z22=fe#3,>z22=fe#3); */ 72 | /* asm 2: fe_sq(>z22=t2,z22=t2,>z22=t2); */ 73 | fe_sq(t2,t0); for (i = 1;i < 1;++i) fe_sq(t2,t2); 74 | 75 | /* qhasm: z_5_0 = z9*z22 */ 76 | /* asm 1: fe_mul(>z_5_0=fe#2,z_5_0=t1,z_10_5=fe#3,z_10_5=fe#3,>z_10_5=fe#3); */ 82 | /* asm 2: fe_sq(>z_10_5=t2,z_10_5=t2,>z_10_5=t2); */ 83 | fe_sq(t2,t1); for (i = 1;i < 5;++i) fe_sq(t2,t2); 84 | 85 | /* qhasm: z_10_0 = z_10_5*z_5_0 */ 86 | /* asm 1: fe_mul(>z_10_0=fe#2,z_10_0=t1,z_20_10=fe#3,z_20_10=fe#3,>z_20_10=fe#3); */ 92 | /* asm 2: fe_sq(>z_20_10=t2,z_20_10=t2,>z_20_10=t2); */ 93 | fe_sq(t2,t1); for (i = 1;i < 10;++i) fe_sq(t2,t2); 94 | 95 | /* qhasm: z_20_0 = z_20_10*z_10_0 */ 96 | /* asm 1: fe_mul(>z_20_0=fe#3,z_20_0=t2,z_40_20=fe#4,z_40_20=fe#4,>z_40_20=fe#4); */ 102 | /* asm 2: fe_sq(>z_40_20=t3,z_40_20=t3,>z_40_20=t3); */ 103 | fe_sq(t3,t2); for (i = 1;i < 20;++i) fe_sq(t3,t3); 104 | 105 | /* qhasm: z_40_0 = z_40_20*z_20_0 */ 106 | /* asm 1: fe_mul(>z_40_0=fe#3,z_40_0=t2,z_50_10=fe#3,z_50_10=fe#3,>z_50_10=fe#3); */ 112 | /* asm 2: fe_sq(>z_50_10=t2,z_50_10=t2,>z_50_10=t2); */ 113 | fe_sq(t2,t2); for (i = 1;i < 10;++i) fe_sq(t2,t2); 114 | 115 | /* qhasm: z_50_0 = z_50_10*z_10_0 */ 116 | /* asm 1: fe_mul(>z_50_0=fe#2,z_50_0=t1,z_100_50=fe#3,z_100_50=fe#3,>z_100_50=fe#3); */ 122 | /* asm 2: fe_sq(>z_100_50=t2,z_100_50=t2,>z_100_50=t2); */ 123 | fe_sq(t2,t1); for (i = 1;i < 50;++i) fe_sq(t2,t2); 124 | 125 | /* qhasm: z_100_0 = z_100_50*z_50_0 */ 126 | /* asm 1: fe_mul(>z_100_0=fe#3,z_100_0=t2,z_200_100=fe#4,z_200_100=fe#4,>z_200_100=fe#4); */ 132 | /* asm 2: fe_sq(>z_200_100=t3,z_200_100=t3,>z_200_100=t3); */ 133 | fe_sq(t3,t2); for (i = 1;i < 100;++i) fe_sq(t3,t3); 134 | 135 | /* qhasm: z_200_0 = z_200_100*z_100_0 */ 136 | /* asm 1: fe_mul(>z_200_0=fe#3,z_200_0=t2,z_250_50=fe#3,z_250_50=fe#3,>z_250_50=fe#3); */ 142 | /* asm 2: fe_sq(>z_250_50=t2,z_250_50=t2,>z_250_50=t2); */ 143 | fe_sq(t2,t2); for (i = 1;i < 50;++i) fe_sq(t2,t2); 144 | 145 | /* qhasm: z_250_0 = z_250_50*z_50_0 */ 146 | /* asm 1: fe_mul(>z_250_0=fe#2,z_250_0=t1,z_255_5=fe#2,z_255_5=fe#2,>z_255_5=fe#2); */ 152 | /* asm 2: fe_sq(>z_255_5=t1,z_255_5=t1,>z_255_5=t1); */ 153 | fe_sq(t1,t1); for (i = 1;i < 5;++i) fe_sq(t1,t1); 154 | 155 | /* qhasm: z_255_21 = z_255_5*z11 */ 156 | /* asm 1: fe_mul(>z_255_21=fe#12,z_255_21=out,> 5); 39 | crypto_int64 s2 = 2097151 & (load_3(s + 5) >> 2); 40 | crypto_int64 s3 = 2097151 & (load_4(s + 7) >> 7); 41 | crypto_int64 s4 = 2097151 & (load_4(s + 10) >> 4); 42 | crypto_int64 s5 = 2097151 & (load_3(s + 13) >> 1); 43 | crypto_int64 s6 = 2097151 & (load_4(s + 15) >> 6); 44 | crypto_int64 s7 = 2097151 & (load_3(s + 18) >> 3); 45 | crypto_int64 s8 = 2097151 & load_3(s + 21); 46 | crypto_int64 s9 = 2097151 & (load_4(s + 23) >> 5); 47 | crypto_int64 s10 = 2097151 & (load_3(s + 26) >> 2); 48 | crypto_int64 s11 = 2097151 & (load_4(s + 28) >> 7); 49 | crypto_int64 s12 = 2097151 & (load_4(s + 31) >> 4); 50 | crypto_int64 s13 = 2097151 & (load_3(s + 34) >> 1); 51 | crypto_int64 s14 = 2097151 & (load_4(s + 36) >> 6); 52 | crypto_int64 s15 = 2097151 & (load_3(s + 39) >> 3); 53 | crypto_int64 s16 = 2097151 & load_3(s + 42); 54 | crypto_int64 s17 = 2097151 & (load_4(s + 44) >> 5); 55 | crypto_int64 s18 = 2097151 & (load_3(s + 47) >> 2); 56 | crypto_int64 s19 = 2097151 & (load_4(s + 49) >> 7); 57 | crypto_int64 s20 = 2097151 & (load_4(s + 52) >> 4); 58 | crypto_int64 s21 = 2097151 & (load_3(s + 55) >> 1); 59 | crypto_int64 s22 = 2097151 & (load_4(s + 57) >> 6); 60 | crypto_int64 s23 = (load_4(s + 60) >> 3); 61 | crypto_int64 carry0; 62 | crypto_int64 carry1; 63 | crypto_int64 carry2; 64 | crypto_int64 carry3; 65 | crypto_int64 carry4; 66 | crypto_int64 carry5; 67 | crypto_int64 carry6; 68 | crypto_int64 carry7; 69 | crypto_int64 carry8; 70 | crypto_int64 carry9; 71 | crypto_int64 carry10; 72 | crypto_int64 carry11; 73 | crypto_int64 carry12; 74 | crypto_int64 carry13; 75 | crypto_int64 carry14; 76 | crypto_int64 carry15; 77 | crypto_int64 carry16; 78 | 79 | s11 += s23 * 666643; 80 | s12 += s23 * 470296; 81 | s13 += s23 * 654183; 82 | s14 -= s23 * 997805; 83 | s15 += s23 * 136657; 84 | s16 -= s23 * 683901; 85 | s23 = 0; 86 | 87 | s10 += s22 * 666643; 88 | s11 += s22 * 470296; 89 | s12 += s22 * 654183; 90 | s13 -= s22 * 997805; 91 | s14 += s22 * 136657; 92 | s15 -= s22 * 683901; 93 | s22 = 0; 94 | 95 | s9 += s21 * 666643; 96 | s10 += s21 * 470296; 97 | s11 += s21 * 654183; 98 | s12 -= s21 * 997805; 99 | s13 += s21 * 136657; 100 | s14 -= s21 * 683901; 101 | s21 = 0; 102 | 103 | s8 += s20 * 666643; 104 | s9 += s20 * 470296; 105 | s10 += s20 * 654183; 106 | s11 -= s20 * 997805; 107 | s12 += s20 * 136657; 108 | s13 -= s20 * 683901; 109 | s20 = 0; 110 | 111 | s7 += s19 * 666643; 112 | s8 += s19 * 470296; 113 | s9 += s19 * 654183; 114 | s10 -= s19 * 997805; 115 | s11 += s19 * 136657; 116 | s12 -= s19 * 683901; 117 | s19 = 0; 118 | 119 | s6 += s18 * 666643; 120 | s7 += s18 * 470296; 121 | s8 += s18 * 654183; 122 | s9 -= s18 * 997805; 123 | s10 += s18 * 136657; 124 | s11 -= s18 * 683901; 125 | s18 = 0; 126 | 127 | carry6 = (s6 + (1<<20)) >> 21; s7 += carry6; s6 -= carry6 << 21; 128 | carry8 = (s8 + (1<<20)) >> 21; s9 += carry8; s8 -= carry8 << 21; 129 | carry10 = (s10 + (1<<20)) >> 21; s11 += carry10; s10 -= carry10 << 21; 130 | carry12 = (s12 + (1<<20)) >> 21; s13 += carry12; s12 -= carry12 << 21; 131 | carry14 = (s14 + (1<<20)) >> 21; s15 += carry14; s14 -= carry14 << 21; 132 | carry16 = (s16 + (1<<20)) >> 21; s17 += carry16; s16 -= carry16 << 21; 133 | 134 | carry7 = (s7 + (1<<20)) >> 21; s8 += carry7; s7 -= carry7 << 21; 135 | carry9 = (s9 + (1<<20)) >> 21; s10 += carry9; s9 -= carry9 << 21; 136 | carry11 = (s11 + (1<<20)) >> 21; s12 += carry11; s11 -= carry11 << 21; 137 | carry13 = (s13 + (1<<20)) >> 21; s14 += carry13; s13 -= carry13 << 21; 138 | carry15 = (s15 + (1<<20)) >> 21; s16 += carry15; s15 -= carry15 << 21; 139 | 140 | s5 += s17 * 666643; 141 | s6 += s17 * 470296; 142 | s7 += s17 * 654183; 143 | s8 -= s17 * 997805; 144 | s9 += s17 * 136657; 145 | s10 -= s17 * 683901; 146 | s17 = 0; 147 | 148 | s4 += s16 * 666643; 149 | s5 += s16 * 470296; 150 | s6 += s16 * 654183; 151 | s7 -= s16 * 997805; 152 | s8 += s16 * 136657; 153 | s9 -= s16 * 683901; 154 | s16 = 0; 155 | 156 | s3 += s15 * 666643; 157 | s4 += s15 * 470296; 158 | s5 += s15 * 654183; 159 | s6 -= s15 * 997805; 160 | s7 += s15 * 136657; 161 | s8 -= s15 * 683901; 162 | s15 = 0; 163 | 164 | s2 += s14 * 666643; 165 | s3 += s14 * 470296; 166 | s4 += s14 * 654183; 167 | s5 -= s14 * 997805; 168 | s6 += s14 * 136657; 169 | s7 -= s14 * 683901; 170 | s14 = 0; 171 | 172 | s1 += s13 * 666643; 173 | s2 += s13 * 470296; 174 | s3 += s13 * 654183; 175 | s4 -= s13 * 997805; 176 | s5 += s13 * 136657; 177 | s6 -= s13 * 683901; 178 | s13 = 0; 179 | 180 | s0 += s12 * 666643; 181 | s1 += s12 * 470296; 182 | s2 += s12 * 654183; 183 | s3 -= s12 * 997805; 184 | s4 += s12 * 136657; 185 | s5 -= s12 * 683901; 186 | s12 = 0; 187 | 188 | carry0 = (s0 + (1<<20)) >> 21; s1 += carry0; s0 -= carry0 << 21; 189 | carry2 = (s2 + (1<<20)) >> 21; s3 += carry2; s2 -= carry2 << 21; 190 | carry4 = (s4 + (1<<20)) >> 21; s5 += carry4; s4 -= carry4 << 21; 191 | carry6 = (s6 + (1<<20)) >> 21; s7 += carry6; s6 -= carry6 << 21; 192 | carry8 = (s8 + (1<<20)) >> 21; s9 += carry8; s8 -= carry8 << 21; 193 | carry10 = (s10 + (1<<20)) >> 21; s11 += carry10; s10 -= carry10 << 21; 194 | 195 | carry1 = (s1 + (1<<20)) >> 21; s2 += carry1; s1 -= carry1 << 21; 196 | carry3 = (s3 + (1<<20)) >> 21; s4 += carry3; s3 -= carry3 << 21; 197 | carry5 = (s5 + (1<<20)) >> 21; s6 += carry5; s5 -= carry5 << 21; 198 | carry7 = (s7 + (1<<20)) >> 21; s8 += carry7; s7 -= carry7 << 21; 199 | carry9 = (s9 + (1<<20)) >> 21; s10 += carry9; s9 -= carry9 << 21; 200 | carry11 = (s11 + (1<<20)) >> 21; s12 += carry11; s11 -= carry11 << 21; 201 | 202 | s0 += s12 * 666643; 203 | s1 += s12 * 470296; 204 | s2 += s12 * 654183; 205 | s3 -= s12 * 997805; 206 | s4 += s12 * 136657; 207 | s5 -= s12 * 683901; 208 | s12 = 0; 209 | 210 | carry0 = s0 >> 21; s1 += carry0; s0 -= carry0 << 21; 211 | carry1 = s1 >> 21; s2 += carry1; s1 -= carry1 << 21; 212 | carry2 = s2 >> 21; s3 += carry2; s2 -= carry2 << 21; 213 | carry3 = s3 >> 21; s4 += carry3; s3 -= carry3 << 21; 214 | carry4 = s4 >> 21; s5 += carry4; s4 -= carry4 << 21; 215 | carry5 = s5 >> 21; s6 += carry5; s5 -= carry5 << 21; 216 | carry6 = s6 >> 21; s7 += carry6; s6 -= carry6 << 21; 217 | carry7 = s7 >> 21; s8 += carry7; s7 -= carry7 << 21; 218 | carry8 = s8 >> 21; s9 += carry8; s8 -= carry8 << 21; 219 | carry9 = s9 >> 21; s10 += carry9; s9 -= carry9 << 21; 220 | carry10 = s10 >> 21; s11 += carry10; s10 -= carry10 << 21; 221 | carry11 = s11 >> 21; s12 += carry11; s11 -= carry11 << 21; 222 | 223 | s0 += s12 * 666643; 224 | s1 += s12 * 470296; 225 | s2 += s12 * 654183; 226 | s3 -= s12 * 997805; 227 | s4 += s12 * 136657; 228 | s5 -= s12 * 683901; 229 | s12 = 0; 230 | 231 | carry0 = s0 >> 21; s1 += carry0; s0 -= carry0 << 21; 232 | carry1 = s1 >> 21; s2 += carry1; s1 -= carry1 << 21; 233 | carry2 = s2 >> 21; s3 += carry2; s2 -= carry2 << 21; 234 | carry3 = s3 >> 21; s4 += carry3; s3 -= carry3 << 21; 235 | carry4 = s4 >> 21; s5 += carry4; s4 -= carry4 << 21; 236 | carry5 = s5 >> 21; s6 += carry5; s5 -= carry5 << 21; 237 | carry6 = s6 >> 21; s7 += carry6; s6 -= carry6 << 21; 238 | carry7 = s7 >> 21; s8 += carry7; s7 -= carry7 << 21; 239 | carry8 = s8 >> 21; s9 += carry8; s8 -= carry8 << 21; 240 | carry9 = s9 >> 21; s10 += carry9; s9 -= carry9 << 21; 241 | carry10 = s10 >> 21; s11 += carry10; s10 -= carry10 << 21; 242 | 243 | s[0] = s0 >> 0; 244 | s[1] = s0 >> 8; 245 | s[2] = (s0 >> 16) | (s1 << 5); 246 | s[3] = s1 >> 3; 247 | s[4] = s1 >> 11; 248 | s[5] = (s1 >> 19) | (s2 << 2); 249 | s[6] = s2 >> 6; 250 | s[7] = (s2 >> 14) | (s3 << 7); 251 | s[8] = s3 >> 1; 252 | s[9] = s3 >> 9; 253 | s[10] = (s3 >> 17) | (s4 << 4); 254 | s[11] = s4 >> 4; 255 | s[12] = s4 >> 12; 256 | s[13] = (s4 >> 20) | (s5 << 1); 257 | s[14] = s5 >> 7; 258 | s[15] = (s5 >> 15) | (s6 << 6); 259 | s[16] = s6 >> 2; 260 | s[17] = s6 >> 10; 261 | s[18] = (s6 >> 18) | (s7 << 3); 262 | s[19] = s7 >> 5; 263 | s[20] = s7 >> 13; 264 | s[21] = s8 >> 0; 265 | s[22] = s8 >> 8; 266 | s[23] = (s8 >> 16) | (s9 << 5); 267 | s[24] = s9 >> 3; 268 | s[25] = s9 >> 11; 269 | s[26] = (s9 >> 19) | (s10 << 2); 270 | s[27] = s10 >> 6; 271 | s[28] = (s10 >> 14) | (s11 << 7); 272 | s[29] = s11 >> 1; 273 | s[30] = s11 >> 9; 274 | s[31] = s11 >> 17; 275 | } 276 | -------------------------------------------------------------------------------- /native/ed25519/sha512/LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) 2007-2011 Projet RNRT SAPHIR 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining 4 | a copy of this software and associated documentation files (the 5 | "Software"), to deal in the Software without restriction, including 6 | without limitation the rights to use, copy, modify, merge, publish, 7 | distribute, sublicense, and/or sell copies of the Software, and to 8 | permit persons to whom the Software is furnished to do so, subject to 9 | the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included 12 | in all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 15 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 17 | IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 18 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 19 | TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 20 | SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /native/ed25519/sha512/sha2big.c: -------------------------------------------------------------------------------- 1 | /* $Id: sha2big.c 216 2010-06-08 09:46:57Z tp $ */ 2 | /* 3 | * SHA-384 / SHA-512 implementation. 4 | * 5 | * ==========================(LICENSE BEGIN)============================ 6 | * 7 | * Copyright (c) 2007-2010 Projet RNRT SAPHIR 8 | * 9 | * Permission is hereby granted, free of charge, to any person obtaining 10 | * a copy of this software and associated documentation files (the 11 | * "Software"), to deal in the Software without restriction, including 12 | * without limitation the rights to use, copy, modify, merge, publish, 13 | * distribute, sublicense, and/or sell copies of the Software, and to 14 | * permit persons to whom the Software is furnished to do so, subject to 15 | * the following conditions: 16 | * 17 | * The above copyright notice and this permission notice shall be 18 | * included in all copies or substantial portions of the Software. 19 | * 20 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 21 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 22 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 23 | * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 24 | * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 25 | * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 26 | * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 27 | * 28 | * ===========================(LICENSE END)============================= 29 | * 30 | * @author Thomas Pornin 31 | */ 32 | 33 | #include 34 | #include 35 | 36 | #include "sph_sha2.h" 37 | 38 | #if SPH_64 39 | 40 | #define CH(X, Y, Z) ((((Y) ^ (Z)) & (X)) ^ (Z)) 41 | #define MAJ(X, Y, Z) (((X) & (Y)) | (((X) | (Y)) & (Z))) 42 | 43 | #define ROTR64 SPH_ROTR64 44 | 45 | #define BSG5_0(x) (ROTR64(x, 28) ^ ROTR64(x, 34) ^ ROTR64(x, 39)) 46 | #define BSG5_1(x) (ROTR64(x, 14) ^ ROTR64(x, 18) ^ ROTR64(x, 41)) 47 | #define SSG5_0(x) (ROTR64(x, 1) ^ ROTR64(x, 8) ^ SPH_T64((x) >> 7)) 48 | #define SSG5_1(x) (ROTR64(x, 19) ^ ROTR64(x, 61) ^ SPH_T64((x) >> 6)) 49 | 50 | static const sph_u64 K512[80] = { 51 | SPH_C64(0x428A2F98D728AE22), SPH_C64(0x7137449123EF65CD), 52 | SPH_C64(0xB5C0FBCFEC4D3B2F), SPH_C64(0xE9B5DBA58189DBBC), 53 | SPH_C64(0x3956C25BF348B538), SPH_C64(0x59F111F1B605D019), 54 | SPH_C64(0x923F82A4AF194F9B), SPH_C64(0xAB1C5ED5DA6D8118), 55 | SPH_C64(0xD807AA98A3030242), SPH_C64(0x12835B0145706FBE), 56 | SPH_C64(0x243185BE4EE4B28C), SPH_C64(0x550C7DC3D5FFB4E2), 57 | SPH_C64(0x72BE5D74F27B896F), SPH_C64(0x80DEB1FE3B1696B1), 58 | SPH_C64(0x9BDC06A725C71235), SPH_C64(0xC19BF174CF692694), 59 | SPH_C64(0xE49B69C19EF14AD2), SPH_C64(0xEFBE4786384F25E3), 60 | SPH_C64(0x0FC19DC68B8CD5B5), SPH_C64(0x240CA1CC77AC9C65), 61 | SPH_C64(0x2DE92C6F592B0275), SPH_C64(0x4A7484AA6EA6E483), 62 | SPH_C64(0x5CB0A9DCBD41FBD4), SPH_C64(0x76F988DA831153B5), 63 | SPH_C64(0x983E5152EE66DFAB), SPH_C64(0xA831C66D2DB43210), 64 | SPH_C64(0xB00327C898FB213F), SPH_C64(0xBF597FC7BEEF0EE4), 65 | SPH_C64(0xC6E00BF33DA88FC2), SPH_C64(0xD5A79147930AA725), 66 | SPH_C64(0x06CA6351E003826F), SPH_C64(0x142929670A0E6E70), 67 | SPH_C64(0x27B70A8546D22FFC), SPH_C64(0x2E1B21385C26C926), 68 | SPH_C64(0x4D2C6DFC5AC42AED), SPH_C64(0x53380D139D95B3DF), 69 | SPH_C64(0x650A73548BAF63DE), SPH_C64(0x766A0ABB3C77B2A8), 70 | SPH_C64(0x81C2C92E47EDAEE6), SPH_C64(0x92722C851482353B), 71 | SPH_C64(0xA2BFE8A14CF10364), SPH_C64(0xA81A664BBC423001), 72 | SPH_C64(0xC24B8B70D0F89791), SPH_C64(0xC76C51A30654BE30), 73 | SPH_C64(0xD192E819D6EF5218), SPH_C64(0xD69906245565A910), 74 | SPH_C64(0xF40E35855771202A), SPH_C64(0x106AA07032BBD1B8), 75 | SPH_C64(0x19A4C116B8D2D0C8), SPH_C64(0x1E376C085141AB53), 76 | SPH_C64(0x2748774CDF8EEB99), SPH_C64(0x34B0BCB5E19B48A8), 77 | SPH_C64(0x391C0CB3C5C95A63), SPH_C64(0x4ED8AA4AE3418ACB), 78 | SPH_C64(0x5B9CCA4F7763E373), SPH_C64(0x682E6FF3D6B2B8A3), 79 | SPH_C64(0x748F82EE5DEFB2FC), SPH_C64(0x78A5636F43172F60), 80 | SPH_C64(0x84C87814A1F0AB72), SPH_C64(0x8CC702081A6439EC), 81 | SPH_C64(0x90BEFFFA23631E28), SPH_C64(0xA4506CEBDE82BDE9), 82 | SPH_C64(0xBEF9A3F7B2C67915), SPH_C64(0xC67178F2E372532B), 83 | SPH_C64(0xCA273ECEEA26619C), SPH_C64(0xD186B8C721C0C207), 84 | SPH_C64(0xEADA7DD6CDE0EB1E), SPH_C64(0xF57D4F7FEE6ED178), 85 | SPH_C64(0x06F067AA72176FBA), SPH_C64(0x0A637DC5A2C898A6), 86 | SPH_C64(0x113F9804BEF90DAE), SPH_C64(0x1B710B35131C471B), 87 | SPH_C64(0x28DB77F523047D84), SPH_C64(0x32CAAB7B40C72493), 88 | SPH_C64(0x3C9EBE0A15C9BEBC), SPH_C64(0x431D67C49C100D4C), 89 | SPH_C64(0x4CC5D4BECB3E42B6), SPH_C64(0x597F299CFC657E2A), 90 | SPH_C64(0x5FCB6FAB3AD6FAEC), SPH_C64(0x6C44198C4A475817) 91 | }; 92 | 93 | static const sph_u64 H384[8] = { 94 | SPH_C64(0xCBBB9D5DC1059ED8), SPH_C64(0x629A292A367CD507), 95 | SPH_C64(0x9159015A3070DD17), SPH_C64(0x152FECD8F70E5939), 96 | SPH_C64(0x67332667FFC00B31), SPH_C64(0x8EB44A8768581511), 97 | SPH_C64(0xDB0C2E0D64F98FA7), SPH_C64(0x47B5481DBEFA4FA4) 98 | }; 99 | 100 | static const sph_u64 H512[8] = { 101 | SPH_C64(0x6A09E667F3BCC908), SPH_C64(0xBB67AE8584CAA73B), 102 | SPH_C64(0x3C6EF372FE94F82B), SPH_C64(0xA54FF53A5F1D36F1), 103 | SPH_C64(0x510E527FADE682D1), SPH_C64(0x9B05688C2B3E6C1F), 104 | SPH_C64(0x1F83D9ABFB41BD6B), SPH_C64(0x5BE0CD19137E2179) 105 | }; 106 | 107 | /* 108 | * This macro defines the body for a SHA-384 / SHA-512 compression function 109 | * implementation. The "in" parameter should evaluate, when applied to a 110 | * numerical input parameter from 0 to 15, to an expression which yields 111 | * the corresponding input block. The "r" parameter should evaluate to 112 | * an array or pointer expression designating the array of 8 words which 113 | * contains the input and output of the compression function. 114 | * 115 | * SHA-512 is hard for the compiler. If the loop is completely unrolled, 116 | * then the code will be quite huge (possibly more than 100 kB), and the 117 | * performance will be degraded due to cache misses on the code. We 118 | * unroll only eight steps, which avoids all needless copies when 119 | * 64-bit registers are swapped. 120 | */ 121 | 122 | #define SHA3_STEP(A, B, C, D, E, F, G, H, i) do { \ 123 | sph_u64 T1, T2; \ 124 | T1 = SPH_T64(H + BSG5_1(E) + CH(E, F, G) + K512[i] + W[i]); \ 125 | T2 = SPH_T64(BSG5_0(A) + MAJ(A, B, C)); \ 126 | D = SPH_T64(D + T1); \ 127 | H = SPH_T64(T1 + T2); \ 128 | } while (0) 129 | 130 | #define SHA3_ROUND_BODY(in, r) do { \ 131 | int i; \ 132 | sph_u64 A, B, C, D, E, F, G, H; \ 133 | sph_u64 W[80]; \ 134 | \ 135 | for (i = 0; i < 16; i ++) \ 136 | W[i] = in(i); \ 137 | for (i = 16; i < 80; i ++) \ 138 | W[i] = SPH_T64(SSG5_1(W[i - 2]) + W[i - 7] \ 139 | + SSG5_0(W[i - 15]) + W[i - 16]); \ 140 | A = (r)[0]; \ 141 | B = (r)[1]; \ 142 | C = (r)[2]; \ 143 | D = (r)[3]; \ 144 | E = (r)[4]; \ 145 | F = (r)[5]; \ 146 | G = (r)[6]; \ 147 | H = (r)[7]; \ 148 | for (i = 0; i < 80; i += 8) { \ 149 | SHA3_STEP(A, B, C, D, E, F, G, H, i + 0); \ 150 | SHA3_STEP(H, A, B, C, D, E, F, G, i + 1); \ 151 | SHA3_STEP(G, H, A, B, C, D, E, F, i + 2); \ 152 | SHA3_STEP(F, G, H, A, B, C, D, E, i + 3); \ 153 | SHA3_STEP(E, F, G, H, A, B, C, D, i + 4); \ 154 | SHA3_STEP(D, E, F, G, H, A, B, C, i + 5); \ 155 | SHA3_STEP(C, D, E, F, G, H, A, B, i + 6); \ 156 | SHA3_STEP(B, C, D, E, F, G, H, A, i + 7); \ 157 | } \ 158 | (r)[0] = SPH_T64((r)[0] + A); \ 159 | (r)[1] = SPH_T64((r)[1] + B); \ 160 | (r)[2] = SPH_T64((r)[2] + C); \ 161 | (r)[3] = SPH_T64((r)[3] + D); \ 162 | (r)[4] = SPH_T64((r)[4] + E); \ 163 | (r)[5] = SPH_T64((r)[5] + F); \ 164 | (r)[6] = SPH_T64((r)[6] + G); \ 165 | (r)[7] = SPH_T64((r)[7] + H); \ 166 | } while (0) 167 | 168 | /* 169 | * One round of SHA-384 / SHA-512. The data must be aligned for 64-bit access. 170 | */ 171 | static void 172 | sha3_round(const unsigned char *data, sph_u64 r[8]) 173 | { 174 | #define SHA3_IN(x) sph_dec64be_aligned(data + (8 * (x))) 175 | SHA3_ROUND_BODY(SHA3_IN, r); 176 | #undef SHA3_IN 177 | } 178 | 179 | /* see sph_sha3.h */ 180 | void 181 | sph_sha384_init(void *cc) 182 | { 183 | sph_sha384_context *sc; 184 | 185 | sc = cc; 186 | memcpy(sc->val, H384, sizeof H384); 187 | sc->count = 0; 188 | } 189 | 190 | /* see sph_sha3.h */ 191 | void 192 | sph_sha512_init(void *cc) 193 | { 194 | sph_sha512_context *sc; 195 | 196 | sc = cc; 197 | memcpy(sc->val, H512, sizeof H512); 198 | sc->count = 0; 199 | } 200 | 201 | #define RFUN sha3_round 202 | #define HASH sha384 203 | #define BE64 1 204 | #include "md_helper.c" 205 | 206 | /* see sph_sha3.h */ 207 | void 208 | sph_sha384_close(void *cc, void *dst) 209 | { 210 | sha384_close(cc, dst, 6); 211 | sph_sha384_init(cc); 212 | } 213 | 214 | /* see sph_sha3.h */ 215 | void 216 | sph_sha384_addbits_and_close(void *cc, unsigned ub, unsigned n, void *dst) 217 | { 218 | sha384_addbits_and_close(cc, ub, n, dst, 6); 219 | sph_sha384_init(cc); 220 | } 221 | 222 | /* see sph_sha3.h */ 223 | void 224 | sph_sha512_close(void *cc, void *dst) 225 | { 226 | sha384_close(cc, dst, 8); 227 | sph_sha512_init(cc); 228 | } 229 | 230 | /* see sph_sha3.h */ 231 | void 232 | sph_sha512_addbits_and_close(void *cc, unsigned ub, unsigned n, void *dst) 233 | { 234 | sha384_addbits_and_close(cc, ub, n, dst, 8); 235 | sph_sha512_init(cc); 236 | } 237 | 238 | /* see sph_sha3.h */ 239 | void 240 | sph_sha384_comp(const sph_u64 msg[16], sph_u64 val[8]) 241 | { 242 | #define SHA3_IN(x) msg[x] 243 | SHA3_ROUND_BODY(SHA3_IN, val); 244 | #undef SHA3_IN 245 | } 246 | 247 | #endif 248 | -------------------------------------------------------------------------------- /native/ed25519/sign.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "crypto_sign.h" 3 | #include "crypto_hash_sha512.h" 4 | #include "ge.h" 5 | #include "sc.h" 6 | 7 | int crypto_sign( 8 | unsigned char *sm,unsigned long long *smlen, 9 | const unsigned char *m,unsigned long long mlen, 10 | const unsigned char *sk 11 | ) 12 | { 13 | unsigned char pk[32]; 14 | unsigned char az[64]; 15 | unsigned char nonce[64]; 16 | unsigned char hram[64]; 17 | ge_p3 R; 18 | 19 | memmove(pk,sk + 32,32); 20 | 21 | crypto_hash_sha512(az,sk,32); 22 | az[0] &= 248; 23 | az[31] &= 63; 24 | az[31] |= 64; 25 | 26 | *smlen = mlen + 64; 27 | memmove(sm + 64,m,mlen); 28 | memmove(sm + 32,az + 32,32); 29 | crypto_hash_sha512(nonce,sm + 32,mlen + 32); 30 | memmove(sm + 32,pk,32); 31 | 32 | sc_reduce(nonce); 33 | ge_scalarmult_base(&R,nonce); 34 | ge_p3_tobytes(sm,&R); 35 | 36 | crypto_hash_sha512(hram,sm,mlen + 64); 37 | sc_reduce(hram); 38 | sc_muladd(sm + 32,hram,az,nonce); 39 | 40 | return 0; 41 | } 42 | -------------------------------------------------------------------------------- /native/ed25519/sqrtm1.h: -------------------------------------------------------------------------------- 1 | -32595792,-7943725,9377950,3500415,12389472,-272473,-25146209,-2005654,326686,11406482 2 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "signal-protocol", 3 | "repository": "https://github.com/elsehow/signal-protocol", 4 | "description": "the signal ratcheting forward secrecy protocol, for node and browsers", 5 | "author": "elsehow", 6 | "contributors": [ 7 | "liliakai" 8 | ], 9 | "version": "0.1.3", 10 | "main": "src/main.js", 11 | "license": "GPL-3.0", 12 | "dependencies": { 13 | "bytebuffer": "^5.0.1", 14 | "chai": "^4.1.0", 15 | "long": "^3.2.0", 16 | "node-webcrypto-ossl": "^1.0.30", 17 | "protobufjs": "^5.0.1", 18 | "tiny-worker": "^2.1.1", 19 | "webworkify": "^1.4.0" 20 | }, 21 | "devDependencies": { 22 | "chai": "^4.1.0", 23 | "grunt": "^1.0.1", 24 | "grunt-browserify": "^5.0.0", 25 | "grunt-cli": "^1.2.0", 26 | "grunt-contrib-concat": "^1.0.1", 27 | "grunt-contrib-connect": "^1.0.2", 28 | "grunt-contrib-jshint": "^1.1.0", 29 | "grunt-jscs": "^3.0.1", 30 | "grunt-mocha-test": "^0.13.2", 31 | "grunt-preen": "^1.0.0 ", 32 | "grunt-saucelabs": "^9.0.0", 33 | "mocha": "^3.2.0" 34 | }, 35 | "scripts": { 36 | "build": "grunt build", 37 | "test": "grunt test", 38 | "lint": "grunt jshint" 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /protos/WhisperTextProtocol.proto: -------------------------------------------------------------------------------- 1 | package textsecure; 2 | 3 | option java_package = "org.whispersystems.libsignal.protocol"; 4 | option java_outer_classname = "WhisperProtos"; 5 | 6 | message WhisperMessage { 7 | optional bytes ephemeralKey = 1; 8 | optional uint32 counter = 2; 9 | optional uint32 previousCounter = 3; 10 | optional bytes ciphertext = 4; // PushMessageContent 11 | } 12 | 13 | message PreKeyWhisperMessage { 14 | optional uint32 registrationId = 5; 15 | optional uint32 preKeyId = 1; 16 | optional uint32 signedPreKeyId = 6; 17 | optional bytes baseKey = 2; 18 | optional bytes identityKey = 3; 19 | optional bytes message = 4; // WhisperMessage 20 | } 21 | 22 | message KeyExchangeMessage { 23 | optional uint32 id = 1; 24 | optional bytes baseKey = 2; 25 | optional bytes ephemeralKey = 3; 26 | optional bytes identityKey = 4; 27 | optional bytes baseKeySignature = 5; 28 | } 29 | -------------------------------------------------------------------------------- /src/BaseKeyType.js: -------------------------------------------------------------------------------- 1 | var BaseKeyType = { 2 | OURS: 1, 3 | THEIRS: 2 4 | }; 5 | 6 | module.exports = BaseKeyType; 7 | -------------------------------------------------------------------------------- /src/ChainType.js: -------------------------------------------------------------------------------- 1 | var ChainType = { 2 | SENDING: 1, 3 | RECEIVING: 2 4 | }; 5 | 6 | module.exports = ChainType; 7 | -------------------------------------------------------------------------------- /src/Curve.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var Crypto = require('crypto'); 4 | var CurveWrapper = require('./curve25519_wrapper.js'); 5 | 6 | function validatePrivKey(privKey) { 7 | if (privKey === undefined || !(privKey instanceof ArrayBuffer) || privKey.byteLength != 32) { 8 | throw new Error("Invalid private key"); 9 | } 10 | } 11 | 12 | function validatePubKeyFormat(pubKey) { 13 | if (pubKey === undefined || ((pubKey.byteLength != 33 || new Uint8Array(pubKey)[0] != 5) && pubKey.byteLength != 32)) { 14 | throw new Error("Invalid public key"); 15 | } 16 | if (pubKey.byteLength == 33) { 17 | return pubKey.slice(1); 18 | } else { 19 | console.error("WARNING: Expected pubkey of length 33, please report the ST and client that generated the pubkey"); 20 | return pubKey; 21 | } 22 | } 23 | 24 | function processKeys(raw_keys) { 25 | // prepend version byte 26 | var origPub = new Uint8Array(raw_keys.pubKey); 27 | var pub = new Uint8Array(33); 28 | pub.set(origPub, 1); 29 | pub[0] = 5; 30 | 31 | return { pubKey: pub.buffer, privKey: raw_keys.privKey }; 32 | } 33 | 34 | function wrapCurve25519(curve25519) { 35 | return { 36 | // Curve 25519 crypto 37 | createKeyPair: function(privKey) { 38 | validatePrivKey(privKey); 39 | var raw_keys = curve25519.keyPair(privKey); 40 | if (raw_keys instanceof Promise) { 41 | return raw_keys.then(processKeys); 42 | } else { 43 | return processKeys(raw_keys); 44 | } 45 | }, 46 | ECDHE: function(pubKey, privKey) { 47 | pubKey = validatePubKeyFormat(pubKey); 48 | validatePrivKey(privKey); 49 | 50 | if (pubKey === undefined || pubKey.byteLength != 32) { 51 | throw new Error("Invalid public key"); 52 | } 53 | 54 | return curve25519.sharedSecret(pubKey, privKey); 55 | }, 56 | Ed25519Sign: function(privKey, message) { 57 | validatePrivKey(privKey); 58 | 59 | if (message === undefined) { 60 | throw new Error("Invalid message"); 61 | } 62 | 63 | return curve25519.sign(privKey, message); 64 | }, 65 | Ed25519Verify: function(pubKey, msg, sig) { 66 | pubKey = validatePubKeyFormat(pubKey); 67 | 68 | if (pubKey === undefined || pubKey.byteLength != 32) { 69 | throw new Error("Invalid public key"); 70 | } 71 | 72 | if (msg === undefined) { 73 | throw new Error("Invalid message"); 74 | } 75 | 76 | if (sig === undefined || sig.byteLength != 64) { 77 | throw new Error("Invalid signature"); 78 | } 79 | 80 | return curve25519.verify(pubKey, msg, sig); 81 | } 82 | }; 83 | } 84 | 85 | function wrapCurve(curve) { 86 | return { 87 | generateKeyPair: function() { 88 | var privKey = Crypto.crypto.getRandomBytes(32); 89 | return curve.createKeyPair(privKey); 90 | }, 91 | createKeyPair: function(privKey) { 92 | return curve.createKeyPair(privKey); 93 | }, 94 | calculateAgreement: function(pubKey, privKey) { 95 | return curve.ECDHE(pubKey, privKey); 96 | }, 97 | verifySignature: function(pubKey, msg, sig) { 98 | return curve.Ed25519Verify(pubKey, msg, sig); 99 | }, 100 | calculateSignature: function(privKey, message) { 101 | return curve.Ed25519Sign(privKey, message); 102 | } 103 | }; 104 | } 105 | 106 | var curve = wrapCurve25519(CurveWrapper.curve25519); 107 | var async = wrapCurve25519(CurveWrapper.curve25519_async); 108 | var libsignal_Curve = wrapCurve(curve); 109 | var libsignal_Curve_async = wrapCurve(async); 110 | 111 | module.exports = { 112 | Curve: curve, 113 | async: async, 114 | libsignal_Curve: libsignal_Curve, 115 | libsignal_Curve_async: libsignal_Curve_async 116 | }; 117 | -------------------------------------------------------------------------------- /src/KeyHelper.js: -------------------------------------------------------------------------------- 1 | var Crypto = require('./crypto.js'); 2 | 3 | function isNonNegativeInteger(n) { 4 | return (typeof n === 'number' && (n % 1) === 0 && n >= 0); 5 | } 6 | 7 | var KeyHelper = { 8 | generateIdentityKeyPair: function() { 9 | return Crypto.crypto.createKeyPair(); 10 | }, 11 | 12 | generateRegistrationId: function() { 13 | var registrationId = new Uint16Array(Crypto.crypto.getRandomBytes(2))[0]; 14 | return registrationId & 0x3fff; 15 | }, 16 | 17 | generateSignedPreKey: function (identityKeyPair, signedKeyId) { 18 | if (!(identityKeyPair.privKey instanceof ArrayBuffer) || 19 | identityKeyPair.privKey.byteLength != 32 || 20 | !(identityKeyPair.pubKey instanceof ArrayBuffer) || 21 | identityKeyPair.pubKey.byteLength != 33) { 22 | throw new TypeError('Invalid argument for identityKeyPair'); 23 | } 24 | if (!isNonNegativeInteger(signedKeyId)) { 25 | throw new TypeError( 26 | 'Invalid argument for signedKeyId: ' + signedKeyId 27 | ); 28 | } 29 | 30 | return Crypto.crypto.createKeyPair().then(function(keyPair) { 31 | return Crypto.crypto.Ed25519Sign(identityKeyPair.privKey, keyPair.pubKey).then(function(sig) { 32 | return { 33 | keyId : signedKeyId, 34 | keyPair : keyPair, 35 | signature : sig 36 | }; 37 | }); 38 | }); 39 | }, 40 | 41 | generatePreKey: function(keyId) { 42 | if (!isNonNegativeInteger(keyId)) { 43 | throw new TypeError('Invalid argument for keyId: ' + keyId); 44 | } 45 | 46 | return Crypto.crypto.createKeyPair().then(function(keyPair) { 47 | return { keyId: keyId, keyPair: keyPair }; 48 | }); 49 | } 50 | }; 51 | 52 | module.exports = KeyHelper; 53 | -------------------------------------------------------------------------------- /src/NumericFingerprint.js: -------------------------------------------------------------------------------- 1 | var VERSION = 0; 2 | 3 | var Crypto = require('./crypto.js'); 4 | var dcodeIO = require('../build/dcodeIO.js'); 5 | 6 | function iterateHash(data, key, count) { 7 | data = dcodeIO.ByteBuffer.concat([data, key]).toArrayBuffer(); 8 | return Crypto.crypto.hash(data).then(function(result) { 9 | if (--count === 0) { 10 | return result; 11 | } else { 12 | return iterateHash(result, key, count); 13 | } 14 | }); 15 | } 16 | 17 | function shortToArrayBuffer(number) { 18 | return new Uint16Array([number]).buffer; 19 | } 20 | 21 | function getEncodedChunk(hash, offset) { 22 | var chunk = ( hash[offset] * Math.pow(2,32) + 23 | hash[offset+1] * Math.pow(2,24) + 24 | hash[offset+2] * Math.pow(2,16) + 25 | hash[offset+3] * Math.pow(2,8) + 26 | hash[offset+4] ) % 100000; 27 | var s = chunk.toString(); 28 | while (s.length < 5) { 29 | s = '0' + s; 30 | } 31 | return s; 32 | } 33 | 34 | function getDisplayStringFor(identifier, key, iterations) { 35 | var bytes = dcodeIO.ByteBuffer.concat([ 36 | shortToArrayBuffer(VERSION), key, identifier 37 | ]).toArrayBuffer(); 38 | return iterateHash(bytes, key, iterations).then(function(output) { 39 | output = new Uint8Array(output); 40 | return getEncodedChunk(output, 0) + 41 | getEncodedChunk(output, 5) + 42 | getEncodedChunk(output, 10) + 43 | getEncodedChunk(output, 15) + 44 | getEncodedChunk(output, 20) + 45 | getEncodedChunk(output, 25); 46 | }); 47 | } 48 | 49 | var FingerprintGenerator = function(iterations) { 50 | this.iterations = iterations; 51 | }; 52 | 53 | FingerprintGenerator.prototype = { 54 | createFor: function(localIdentifier, localIdentityKey, 55 | remoteIdentifier, remoteIdentityKey) { 56 | if (typeof localIdentifier !== 'string' || 57 | typeof remoteIdentifier !== 'string' || 58 | !(localIdentityKey instanceof ArrayBuffer) || 59 | !(remoteIdentityKey instanceof ArrayBuffer)) { 60 | 61 | throw new Error('Invalid arguments'); 62 | } 63 | 64 | return Promise.all([ 65 | getDisplayStringFor(localIdentifier, localIdentityKey, this.iterations), 66 | getDisplayStringFor(remoteIdentifier, remoteIdentityKey, this.iterations) 67 | ]).then(function(fingerprints) { 68 | return fingerprints.sort().join(''); 69 | }); 70 | } 71 | }; 72 | 73 | module.exports = FingerprintGenerator; 74 | -------------------------------------------------------------------------------- /src/SessionLock.js: -------------------------------------------------------------------------------- 1 | /* 2 | * jobQueue manages multiple queues indexed by device to serialize 3 | * session io ops on the database. 4 | */ 5 | 'use strict'; 6 | 7 | var SessionLock = {}; 8 | 9 | var jobQueue = {}; 10 | 11 | SessionLock.queueJobForNumber = function queueJobForNumber(number, runJob) { 12 | var runPrevious = jobQueue[number] || Promise.resolve(); 13 | var runCurrent = jobQueue[number] = runPrevious.then(runJob, runJob); 14 | runCurrent.then(function() { 15 | if (jobQueue[number] === runCurrent) { 16 | delete jobQueue[number]; 17 | } 18 | }); 19 | return runCurrent; 20 | }; 21 | 22 | module.exports = SessionLock; 23 | -------------------------------------------------------------------------------- /src/SignalProtocolAddress.js: -------------------------------------------------------------------------------- 1 | function SignalProtocolAddress(name, deviceId) { 2 | this.name = name; 3 | this.deviceId = deviceId; 4 | } 5 | 6 | SignalProtocolAddress.prototype = { 7 | getName: function() { 8 | return this.name; 9 | }, 10 | getDeviceId: function() { 11 | return this.deviceId; 12 | }, 13 | toString: function() { 14 | return this.name + '.' + this.deviceId; 15 | }, 16 | equals: function(other) { 17 | if (!(other instanceof SignalProtocolAddress)) { return false; } 18 | return other.name === this.name && other.deviceId === this.deviceId; 19 | } 20 | }; 21 | 22 | var mySignalProtocolAddress = function(name, deviceId) { 23 | var address = new SignalProtocolAddress(name, deviceId); 24 | 25 | ['getName', 'getDeviceId', 'toString', 'equals'].forEach(function(method) { 26 | this[method] = address[method].bind(address); 27 | }.bind(this)); 28 | }; 29 | 30 | mySignalProtocolAddress.fromString = function(encodedAddress) { 31 | if (typeof encodedAddress !== 'string' || !encodedAddress.match(/.*\.\d+/)) { 32 | throw new Error('Invalid SignalProtocolAddress string'); 33 | } 34 | var parts = encodedAddress.split('.'); 35 | return new mySignalProtocolAddress(parts[0], parseInt(parts[1])); 36 | }; 37 | 38 | module.exports = mySignalProtocolAddress; 39 | -------------------------------------------------------------------------------- /src/crypto.js: -------------------------------------------------------------------------------- 1 | /* 2 | * vim: ts=4:sw=4 3 | */ 4 | 'use strict'; 5 | 6 | 7 | // BROWSER POLYFILL 8 | var crypto = null; 9 | try { 10 | crypto = window.crypto; 11 | } catch (e) { 12 | crypto = require('./node_polyfills.js').crypto; 13 | } 14 | 15 | var Curve = require('./Curve.js'); 16 | var util = require('./helpers.js'); 17 | var dcodeIO = require('../build/dcodeIO.js'); 18 | 19 | if (!crypto || !crypto.subtle || typeof crypto.getRandomValues !== 'function') { 20 | throw new Error('WebCrypto not found, and node-webcrypto-ossl not imported!'); 21 | } 22 | 23 | // object for this crypto.js scope 24 | var myCrypto = {}; 25 | 26 | myCrypto.crypto = { 27 | getRandomBytes: function(size) { 28 | var array = new Uint8Array(size); 29 | crypto.getRandomValues(array); 30 | return array.buffer; 31 | }, 32 | encrypt: function(key, data, iv) { 33 | return crypto.subtle.importKey('raw', key, { 34 | name: 'AES-CBC' 35 | }, false, ['encrypt']) 36 | .then(function(key) { 37 | return crypto.subtle.encrypt({ 38 | name: 'AES-CBC', 39 | iv: new Uint8Array(iv) 40 | }, key, data); 41 | }); 42 | }, 43 | decrypt: function(key, data, iv) { 44 | return crypto.subtle.importKey('raw', key, {name: 'AES-CBC'}, false, ['decrypt']).then(function(key) { 45 | return crypto.subtle.decrypt({name: 'AES-CBC', iv: new Uint8Array(iv)}, key, data); 46 | }); 47 | }, 48 | sign: function(key, data) { 49 | return crypto.subtle.importKey('raw', key, {name: 'HMAC', hash: {name: 'SHA-256'}}, false, ['sign']).then(function(key) { 50 | return crypto.subtle.sign( {name: 'HMAC', hash: 'SHA-256'}, key, data); 51 | }); 52 | }, 53 | 54 | hash: function(data) { 55 | return crypto.subtle.digest({name: 'SHA-512'}, data); 56 | }, 57 | 58 | HKDF: function(input, salt, info) { 59 | // Specific implementation of RFC 5869 that only returns the first 3 32-byte chunks 60 | // TODO: We dont always need the third chunk, we might skip it 61 | return myCrypto.crypto.sign(salt, input).then(function(PRK) { 62 | var infoBuffer = new ArrayBuffer(info.byteLength + 1 + 32); 63 | var infoArray = new Uint8Array(infoBuffer); 64 | infoArray.set(new Uint8Array(info), 32); 65 | infoArray[infoArray.length - 1] = 1; 66 | return myCrypto.crypto.sign(PRK, infoBuffer.slice(32)).then(function(T1) { 67 | infoArray.set(new Uint8Array(T1)); 68 | infoArray[infoArray.length - 1] = 2; 69 | return myCrypto.crypto.sign(PRK, infoBuffer).then(function(T2) { 70 | infoArray.set(new Uint8Array(T2)); 71 | infoArray[infoArray.length - 1] = 3; 72 | return myCrypto.crypto.sign(PRK, infoBuffer).then(function(T3) { 73 | return [ T1, T2, T3 ]; 74 | }); 75 | }); 76 | }); 77 | }); 78 | }, 79 | 80 | // Curve 25519 crypto 81 | createKeyPair: function(privKey) { 82 | if (privKey === undefined) { 83 | privKey = myCrypto.crypto.getRandomBytes(32); 84 | } 85 | return Curve.async.createKeyPair(privKey); 86 | }, 87 | ECDHE: function(pubKey, privKey) { 88 | return Curve.async.ECDHE(pubKey, privKey); 89 | }, 90 | Ed25519Sign: function(privKey, message) { 91 | return Curve.async.Ed25519Sign(privKey, message); 92 | }, 93 | Ed25519Verify: function(pubKey, msg, sig) { 94 | return Curve.async.Ed25519Verify(pubKey, msg, sig); 95 | } 96 | }; 97 | 98 | 99 | // HKDF for TextSecure has a bit of additional handling - salts always end up being 32 bytes 100 | myCrypto.HKDF = function(input, salt, info) { 101 | if (salt.byteLength != 32) { 102 | throw new Error("Got salt of incorrect length"); 103 | } 104 | 105 | return myCrypto.crypto.HKDF(input, salt, util.toArrayBuffer(info)); 106 | }; 107 | 108 | myCrypto.verifyMAC = function(data, key, mac, length) { 109 | return myCrypto.crypto.sign(key, data).then(function(calculated_mac) { 110 | if (mac.byteLength != length || calculated_mac.byteLength < length) { 111 | throw new Error("Bad MAC length"); 112 | } 113 | var a = new Uint8Array(calculated_mac); 114 | var b = new Uint8Array(mac); 115 | var result = 0; 116 | for (var i=0; i < mac.byteLength; ++i) { 117 | result = result | (a[i] ^ b[i]); 118 | } 119 | if (result !== 0) { 120 | // console.log('Our MAC ', dcodeIO.ByteBuffer.wrap(calculated_mac).toHex()); 121 | // console.log('Their MAC', dcodeIO.ByteBuffer.wrap(mac).toHex()); 122 | throw new Error("Bad MAC"); 123 | } 124 | }); 125 | }; 126 | 127 | module.exports = myCrypto; 128 | 129 | // TODO will need to include these later...maybe? 130 | // module.exports = { 131 | // HKDF: { 132 | // deriveSecrets: function(input, salt, info) { 133 | // return myCrypto.HKDF(input, salt, info); 134 | // }, 135 | // }, 136 | // crypto: { 137 | // encrypt: function(key, data, iv) { 138 | // return myCrypto.crypto.encrypt(key, data, iv); 139 | // }, 140 | // decrypt: function(key, data, iv) { 141 | // return myCrypto.crypto.decrypt(key, data, iv); 142 | // }, 143 | // calculateMAC: function(key, data) { 144 | // return myCrypto.crypto.sign(key, data); 145 | // }, 146 | // verifyMAC: function(data, key, mac, length) { 147 | // return myCrypto.verifyMAC(data, key, mac, length); 148 | // }, 149 | // getRandomBytes: function(size) { 150 | // return myCrypto.crypto.getRandomBytes(size); 151 | // } 152 | // } 153 | // }; 154 | -------------------------------------------------------------------------------- /src/curve25519_worker.js: -------------------------------------------------------------------------------- 1 | // load a workr routine and export it 2 | var workRoutine = require('./curve_work_routine.js'); 3 | // our export is a function that takes `self` 4 | // `self` is passed in by webworkify. 5 | // https://github.com/substack/webworkify 6 | module.exports = function (self) { 7 | workRoutine.apply(self); 8 | }; 9 | -------------------------------------------------------------------------------- /src/curve25519_worker_manager.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | // I am the...workee? 4 | var origCurve25519 = require('./curve25519_wrapper.js'); 5 | // var CurveWrapper = require('./curve25519_wrapper.js'); 6 | 7 | // function workerRoutine () { 8 | // self.onmessage = function(e) { 9 | // origCurve25519.curve25519_async[e.data.methodName].apply(null, e.data.args).then(function(result) { 10 | // self.postMessage({ id: e.data.id, result: result }); 11 | // }).catch(function(error) { 12 | // self.postMessage({ id: e.data.id, error: error.message }); 13 | // }); 14 | // }; 15 | // } 16 | 17 | 18 | function Curve25519Worker() { 19 | this.jobs = {}; 20 | this.jobId = 0; 21 | // BROWSER POLYFILL 22 | try { 23 | var work = require('webworkify'); 24 | this.worker = work(require('./curve25519_worker.js')); 25 | } catch (e) { 26 | var Worker = require('./node_polyfills.js').Worker; 27 | var routine = require('./curve_work_routine.js'); 28 | this.worker = new Worker(routine); 29 | } 30 | // this.worker = new Worker(url); 31 | this.worker.onmessage = function(e) { 32 | var job = this.jobs[e.data.id]; 33 | if (e.data.error && typeof job.onerror === 'function') { 34 | job.onerror(new Error(e.data.error)); 35 | } else if (typeof job.onsuccess === 'function') { 36 | job.onsuccess(e.data.result); 37 | } 38 | delete this.jobs[e.data.id]; 39 | }.bind(this); 40 | } 41 | 42 | Curve25519Worker.prototype = { 43 | constructor: Curve25519Worker, 44 | postMessage: function(methodName, args, onsuccess, onerror) { 45 | return new Promise(function(resolve, reject) { 46 | this.jobs[this.jobId] = { onsuccess: resolve, onerror: reject }; 47 | this.worker.postMessage({ id: this.jobId, methodName: methodName, args: args }); 48 | this.jobId++; 49 | }.bind(this)); 50 | }, 51 | keyPair: function(privKey) { 52 | return this.postMessage('keyPair', [privKey]); 53 | }, 54 | sharedSecret: function(pubKey, privKey) { 55 | return this.postMessage('sharedSecret', [pubKey, privKey]); 56 | }, 57 | sign: function(privKey, message) { 58 | return this.postMessage('sign', [privKey, message]); 59 | }, 60 | verify: function(pubKey, message, sig) { 61 | return this.postMessage('verify', [pubKey, message, sig]); 62 | } 63 | }; 64 | 65 | // stuf for export 66 | 67 | var self = {}; 68 | 69 | self.startWorker = function(url) { 70 | self.stopWorker(); // there can be only one 71 | self.curve25519_async = new Curve25519Worker(url); 72 | }; 73 | 74 | self.stopWorker = function() { 75 | if (self.curve25519_async instanceof Curve25519Worker) { 76 | var worker = self.curve25519_async.worker; 77 | self.curve25519_async = origCurve25519; 78 | worker.terminate(); 79 | } 80 | }; 81 | 82 | 83 | module.exports = self; 84 | -------------------------------------------------------------------------------- /src/curve25519_wrapper.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var Internal = Internal || {}; 4 | var Module = require('../build/curve25519_concat.js'); 5 | 6 | // Insert some bytes into the emscripten memory and return a pointer 7 | function _allocate(bytes) { 8 | var address = Module._malloc(bytes.length); 9 | Module.HEAPU8.set(bytes, address); 10 | 11 | return address; 12 | } 13 | 14 | function _readBytes(address, length, array) { 15 | array.set(Module.HEAPU8.subarray(address, address + length)); 16 | } 17 | 18 | var basepoint = new Uint8Array(32); 19 | basepoint[0] = 9; 20 | 21 | Internal.curve25519 = { 22 | keyPair: function(privKey) { 23 | var priv = new Uint8Array(privKey); 24 | priv[0] &= 248; 25 | priv[31] &= 127; 26 | priv[31] |= 64; 27 | 28 | // Where to store the result 29 | var publicKey_ptr = Module._malloc(32); 30 | 31 | // Get a pointer to the private key 32 | var privateKey_ptr = _allocate(priv); 33 | 34 | // The basepoint for generating public keys 35 | var basepoint_ptr = _allocate(basepoint); 36 | 37 | // The return value is just 0, the operation is done in place 38 | var err = Module._curve25519_donna(publicKey_ptr, 39 | privateKey_ptr, 40 | basepoint_ptr); 41 | 42 | var res = new Uint8Array(32); 43 | _readBytes(publicKey_ptr, 32, res); 44 | 45 | Module._free(publicKey_ptr); 46 | Module._free(privateKey_ptr); 47 | Module._free(basepoint_ptr); 48 | 49 | return { pubKey: res.buffer, privKey: priv.buffer }; 50 | }, 51 | sharedSecret: function(pubKey, privKey) { 52 | // Where to store the result 53 | var sharedKey_ptr = Module._malloc(32); 54 | 55 | // Get a pointer to our private key 56 | var privateKey_ptr = _allocate(new Uint8Array(privKey)); 57 | 58 | // Get a pointer to their public key, the basepoint when you're 59 | // generating a shared secret 60 | var basepoint_ptr = _allocate(new Uint8Array(pubKey)); 61 | 62 | // Return value is 0 here too of course 63 | var err = Module._curve25519_donna(sharedKey_ptr, 64 | privateKey_ptr, 65 | basepoint_ptr); 66 | 67 | var res = new Uint8Array(32); 68 | _readBytes(sharedKey_ptr, 32, res); 69 | 70 | Module._free(sharedKey_ptr); 71 | Module._free(privateKey_ptr); 72 | Module._free(basepoint_ptr); 73 | 74 | return res.buffer; 75 | }, 76 | sign: function(privKey, message) { 77 | // Where to store the result 78 | var signature_ptr = Module._malloc(64); 79 | 80 | // Get a pointer to our private key 81 | var privateKey_ptr = _allocate(new Uint8Array(privKey)); 82 | 83 | // Get a pointer to the message 84 | var message_ptr = _allocate(new Uint8Array(message)); 85 | 86 | var err = Module._curve25519_sign(signature_ptr, 87 | privateKey_ptr, 88 | message_ptr, 89 | message.byteLength); 90 | 91 | var res = new Uint8Array(64); 92 | _readBytes(signature_ptr, 64, res); 93 | 94 | Module._free(signature_ptr); 95 | Module._free(privateKey_ptr); 96 | Module._free(message_ptr); 97 | 98 | return res.buffer; 99 | }, 100 | verify: function(pubKey, message, sig) { 101 | // Get a pointer to their public key 102 | var publicKey_ptr = _allocate(new Uint8Array(pubKey)); 103 | 104 | // Get a pointer to the signature 105 | var signature_ptr = _allocate(new Uint8Array(sig)); 106 | 107 | // Get a pointer to the message 108 | var message_ptr = _allocate(new Uint8Array(message)); 109 | 110 | var res = Module._curve25519_verify(signature_ptr, 111 | publicKey_ptr, 112 | message_ptr, 113 | message.byteLength); 114 | 115 | Module._free(publicKey_ptr); 116 | Module._free(signature_ptr); 117 | Module._free(message_ptr); 118 | 119 | return res !== 0; 120 | } 121 | }; 122 | 123 | Internal.curve25519_async = { 124 | keyPair: function(privKey) { 125 | return new Promise(function(resolve) { 126 | resolve(Internal.curve25519.keyPair(privKey)); 127 | }); 128 | }, 129 | sharedSecret: function(pubKey, privKey) { 130 | return new Promise(function(resolve) { 131 | resolve(Internal.curve25519.sharedSecret(pubKey, privKey)); 132 | }); 133 | }, 134 | sign: function(privKey, message) { 135 | return new Promise(function(resolve) { 136 | resolve(Internal.curve25519.sign(privKey, message)); 137 | }); 138 | }, 139 | verify: function(pubKey, message, sig) { 140 | return new Promise(function(resolve, reject) { 141 | if (Internal.curve25519.verify(pubKey, message, sig)) { 142 | reject(new Error("Invalid signature")); 143 | } else { 144 | resolve(); 145 | } 146 | }); 147 | }, 148 | }; 149 | 150 | module.exports = Internal; 151 | -------------------------------------------------------------------------------- /src/curve_work_routine.js: -------------------------------------------------------------------------------- 1 | var CurveWrapper = require('./curve25519_wrapper.js'); 2 | 3 | function curveWorkRoutine () { 4 | self.onmessage = function(e) { 5 | CurveWrapper.curve25519_async[e.data.methodName].apply(null, e.data.args).then(function(result) { 6 | self.postMessage({ id: e.data.id, result: result }); 7 | }).catch(function(error) { 8 | self.postMessage({ id: e.data.id, error: error.message }); 9 | }); 10 | }; 11 | } 12 | 13 | module.exports = curveWorkRoutine; 14 | -------------------------------------------------------------------------------- /src/helpers.js: -------------------------------------------------------------------------------- 1 | /* 2 | * vim: ts=4:sw=4 3 | */ 4 | 'use strict'; 5 | 6 | 7 | var dcodeIO = require('../build/dcodeIO.js'); 8 | var StaticArrayBufferProto = new ArrayBuffer().__proto__; 9 | 10 | function toString (thing) { 11 | if (typeof thing == 'string') { 12 | return thing; 13 | } 14 | return new dcodeIO.ByteBuffer.wrap(thing).toString('binary'); 15 | } 16 | 17 | function toArrayBuffer (thing) { 18 | if (thing === undefined) { 19 | return undefined; 20 | } 21 | if (thing === Object(thing)) { 22 | if (thing.__proto__ == StaticArrayBufferProto) { 23 | return thing; 24 | } 25 | } 26 | var str; 27 | if (typeof thing == "string") { 28 | str = thing; 29 | } else { 30 | throw new Error("Tried to convert a non-string of type " + typeof thing + " to an array buffer"); 31 | } 32 | return new dcodeIO.ByteBuffer.wrap(thing, 'binary').toArrayBuffer(); 33 | } 34 | 35 | function isEqual (a, b) { 36 | // TODO: Special-case arraybuffers, etc 37 | if (a === undefined || b === undefined) { 38 | return false; 39 | } 40 | a = toString(a); 41 | b = toString(b); 42 | var maxLength = Math.max(a.length, b.length); 43 | if (maxLength < 5) { 44 | throw new Error("a/b compare too short"); 45 | } 46 | return a.substring(0, Math.min(maxLength, a.length)) == b.substring(0, Math.min(maxLength, b.length)); 47 | } 48 | 49 | var util = { 50 | toString: toString, 51 | toArrayBuffer: toArrayBuffer, 52 | isEqual: isEqual 53 | }; 54 | 55 | module.exports = util; 56 | -------------------------------------------------------------------------------- /src/main.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | KeyHelper: require('./KeyHelper.js'), 3 | SignalProtocolAddress: require('./SignalProtocolAddress.js'), 4 | SessionBuilder: require('./SessionBuilder.js'), 5 | SessionCipher: require('./SessionCipher.js'), 6 | FingerprintGenerator: require('./NumericFingerprint.js'), 7 | // internal stuff 8 | _crypto: require('./crypto.js'), 9 | _curve: require('./Curve.js') 10 | }; 11 | -------------------------------------------------------------------------------- /src/main_window.js: -------------------------------------------------------------------------------- 1 | // for legacy builds 2 | // we browserify bundle this into a js file for folks to include in their html 3 | var libsignal = require('./main.js'); 4 | window.libsignal = libsignal; 5 | -------------------------------------------------------------------------------- /src/node_polyfills.js: -------------------------------------------------------------------------------- 1 | 2 | var WebCrypto = require('node-webcrypto-ossl'); 3 | crypto = new WebCrypto(); 4 | 5 | module.exports = { 6 | crypto: crypto, 7 | Worker: require('tiny-worker') 8 | }; 9 | -------------------------------------------------------------------------------- /src/protobufs.js: -------------------------------------------------------------------------------- 1 | /* vim: ts=4:sw=4 */ 2 | 3 | // this is concatinated after ../protos/WhisperTextProtocol.proto 4 | // Internal.protoText is getting passed in from that file 5 | // (see the Gruntfile's `protos_concat` routine) 6 | // here we export the loaded protobuf, an object 7 | // { WhisperMessage, PreKeyWhisperMessage } 8 | module.exports = function protobuf() { 9 | 'use strict'; 10 | var dcodeIO = require('../build/dcodeIO.js'); 11 | // var protobufjs = require('protobufjs') 12 | 13 | function loadProtoBufs(filename) { 14 | return dcodeIO.loadProto(Internal.protoText['protos/' + filename]).build('textsecure'); 15 | } 16 | 17 | var protocolMessages = loadProtoBufs('WhisperTextProtocol.proto'); 18 | 19 | return { 20 | WhisperMessage : protocolMessages.WhisperMessage, 21 | PreKeyWhisperMessage : protocolMessages.PreKeyWhisperMessage 22 | }; 23 | }(); 24 | -------------------------------------------------------------------------------- /test/IdentityKeyStore_test.js: -------------------------------------------------------------------------------- 1 | var Crypto = require('../src/crypto.js'); 2 | var assert = require('chai').assert; 3 | var test_util = require('./test_helpers.js'); 4 | var hexToArrayBuffer = test_util.hexToArrayBuffer; 5 | var assertEqualArrayBuffers = test_util.assertEqualArrayBuffers; 6 | 7 | function testIdentityKeyStore(store, registrationId, identityKey) { 8 | describe('IdentityKeyStore', function() { 9 | var number = '+5558675309'; 10 | var testKey; 11 | before(function(done) { 12 | Crypto.crypto.createKeyPair().then(function(keyPair) { 13 | testKey = keyPair; 14 | }).then(done,done); 15 | }); 16 | 17 | describe('getLocalRegistrationId', function() { 18 | it('retrieves my registration id', function(done) { 19 | store.getLocalRegistrationId().then(function(reg) { 20 | assert.strictEqual(reg, registrationId); 21 | }).then(done, done); 22 | }); 23 | }); 24 | describe('getIdentityKeyPair', function() { 25 | it('retrieves my identity key', function(done) { 26 | store.getIdentityKeyPair().then(function(key) { 27 | assertEqualArrayBuffers(key.pubKey, identityKey.pubKey); 28 | assertEqualArrayBuffers(key.privKey, identityKey.privKey); 29 | }).then(done,done); 30 | }); 31 | }); 32 | describe('saveIdentity', function() { 33 | it('stores identity keys', function(done) { 34 | store.saveIdentity(number, testKey.pubKey).then(function() { 35 | return store.loadIdentityKey(number).then(function(key) { 36 | assertEqualArrayBuffers(key, testKey.pubKey); 37 | }); 38 | }).then(done,done); 39 | }); 40 | }); 41 | describe('isTrustedIdentity', function() { 42 | it('returns true if a key is trusted', function(done) { 43 | store.saveIdentity(number, testKey.pubKey).then(function() { 44 | store.isTrustedIdentity(number, testKey.pubKey).then(function(trusted) { 45 | if (trusted) { 46 | done(); 47 | } else { 48 | done(new Error('Wrong value for trusted key')); 49 | } 50 | }).catch(done); 51 | }); 52 | }); 53 | it('returns false if a key is untrusted', function(done) { 54 | var newIdentity = Crypto.crypto.getRandomBytes(33); 55 | store.saveIdentity(number, testKey.pubKey).then(function() { 56 | store.isTrustedIdentity(number, newIdentity).then(function(trusted) { 57 | if (trusted) { 58 | done(new Error('Wrong value for untrusted key')); 59 | } else { 60 | done(); 61 | } 62 | }).catch(done); 63 | }); 64 | }); 65 | }); 66 | }); 67 | } 68 | 69 | module.exports = testIdentityKeyStore; 70 | -------------------------------------------------------------------------------- /test/InMemorySignalProtocolStore.js: -------------------------------------------------------------------------------- 1 | var util = require('../src/helpers.js'); 2 | 3 | function SignalProtocolStore() { 4 | this.store = {}; 5 | } 6 | 7 | SignalProtocolStore.prototype = { 8 | getIdentityKeyPair: function() { 9 | return Promise.resolve(this.get('identityKey')); 10 | }, 11 | getLocalRegistrationId: function() { 12 | return Promise.resolve(this.get('registrationId')); 13 | }, 14 | put: function(key, value) { 15 | if (key === undefined || value === undefined || key === null || value === null) 16 | throw new Error("Tried to store undefined/null"); 17 | this.store[key] = value; 18 | }, 19 | get: function(key, defaultValue) { 20 | if (key === null || key === undefined) 21 | throw new Error("Tried to get value for undefined/null key"); 22 | if (key in this.store) { 23 | return this.store[key]; 24 | } else { 25 | return defaultValue; 26 | } 27 | }, 28 | remove: function(key) { 29 | if (key === null || key === undefined) 30 | throw new Error("Tried to remove value for undefined/null key"); 31 | delete this.store[key]; 32 | }, 33 | 34 | isTrustedIdentity: function(identifier, identityKey) { 35 | if (identifier === null || identifier === undefined) { 36 | throw new Error("tried to check identity key for undefined/null key"); 37 | } 38 | if (!(identityKey instanceof ArrayBuffer)) { 39 | throw new Error("Expected identityKey to be an ArrayBuffer"); 40 | } 41 | var trusted = this.get('identityKey' + identifier); 42 | if (trusted === undefined) { 43 | return Promise.resolve(true); 44 | } 45 | return Promise.resolve(util.toString(identityKey) === util.toString(trusted)); 46 | }, 47 | loadIdentityKey: function(identifier) { 48 | if (identifier === null || identifier === undefined) 49 | throw new Error("Tried to get identity key for undefined/null key"); 50 | return Promise.resolve(this.get('identityKey' + identifier)); 51 | }, 52 | saveIdentity: function(identifier, identityKey) { 53 | if (identifier === null || identifier === undefined) 54 | throw new Error("Tried to put identity key for undefined/null key"); 55 | return Promise.resolve(this.put('identityKey' + identifier, identityKey)); 56 | }, 57 | 58 | /* Returns a prekeypair object or undefined */ 59 | loadPreKey: function(keyId) { 60 | var res = this.get('25519KeypreKey' + keyId); 61 | if (res !== undefined) { 62 | res = { pubKey: res.pubKey, privKey: res.privKey }; 63 | } 64 | return Promise.resolve(res); 65 | }, 66 | storePreKey: function(keyId, keyPair) { 67 | return Promise.resolve(this.put('25519KeypreKey' + keyId, keyPair)); 68 | }, 69 | removePreKey: function(keyId) { 70 | return Promise.resolve(this.remove('25519KeypreKey' + keyId)); 71 | }, 72 | 73 | /* Returns a signed keypair object or undefined */ 74 | loadSignedPreKey: function(keyId) { 75 | var res = this.get('25519KeysignedKey' + keyId); 76 | if (res !== undefined) { 77 | res = { pubKey: res.pubKey, privKey: res.privKey }; 78 | } 79 | return Promise.resolve(res); 80 | }, 81 | storeSignedPreKey: function(keyId, keyPair) { 82 | return Promise.resolve(this.put('25519KeysignedKey' + keyId, keyPair)); 83 | }, 84 | removeSignedPreKey: function(keyId) { 85 | return Promise.resolve(this.remove('25519KeysignedKey' + keyId)); 86 | }, 87 | 88 | loadSession: function(identifier) { 89 | return Promise.resolve(this.get('session' + identifier)); 90 | }, 91 | storeSession: function(identifier, record) { 92 | return Promise.resolve(this.put('session' + identifier, record)); 93 | }, 94 | removeSession: function(identifier) { 95 | return Promise.resolve(this.remove('session' + identifier)); 96 | }, 97 | removeAllSessions: function(identifier) { 98 | for (var id in this.store) { 99 | if (id.startsWith('session' + identifier)) { 100 | delete this.store[id]; 101 | } 102 | } 103 | return Promise.resolve(); 104 | } 105 | }; 106 | 107 | module.exports = SignalProtocolStore; 108 | -------------------------------------------------------------------------------- /test/IntegrationTest.js: -------------------------------------------------------------------------------- 1 | var signal = require('..'); 2 | var SignalStore = require('./InMemorySignalProtocolStore.js') 3 | var assert = require('chai').assert; 4 | var util = require('../src/helpers.js') 5 | 6 | describe('Integration test', function() { 7 | it('imports all methods', function(done) { 8 | assert.isDefined(signal); 9 | assert.isDefined(signal.KeyHelper); 10 | assert.isDefined(signal.SignalProtocolAddress); 11 | assert.isDefined(signal.SessionBuilder); 12 | assert.isDefined(signal.SessionCipher); 13 | assert.isDefined(signal.FingerprintGenerator); 14 | assert.isDefined(signal._crypto); 15 | assert.isDefined(signal._curve); 16 | done(); 17 | }); 18 | 19 | it('can play out install-time key stuff', function (done) { 20 | var KeyHelper = signal.KeyHelper; 21 | var registrationId = KeyHelper.generateRegistrationId(); 22 | var keyId = 1337; 23 | var ikp = null; // ref for later 24 | assert.isDefined(registrationId); 25 | KeyHelper.generateIdentityKeyPair().then(function(identityKeyPair) { 26 | assert.isDefined(identityKeyPair.pubKey); 27 | assert.isDefined(identityKeyPair.privKey); 28 | ikp = identityKeyPair; 29 | }).then(function () { 30 | return KeyHelper.generatePreKey(keyId); 31 | }).then(function(preKey) { 32 | assert.isDefined(preKey.keyId); 33 | assert.isDefined(preKey.keyPair); 34 | }).then(function () { 35 | return KeyHelper.generateSignedPreKey(ikp, keyId); 36 | }).then(function(signedPreKey) { 37 | assert.isDefined(signedPreKey.keyId); 38 | assert.isDefined(signedPreKey.keyPair); 39 | }).then(done, done); 40 | }); 41 | 42 | function generateIdentity(store) { 43 | return Promise.all([ 44 | signal.KeyHelper.generateIdentityKeyPair(), 45 | signal.KeyHelper.generateRegistrationId(), 46 | ]).then(function(result) { 47 | store.put('identityKey', result[0]); 48 | store.put('registrationId', result[1]); 49 | }); 50 | } 51 | 52 | function generatePreKeyBundle(store, preKeyId, signedPreKeyId) { 53 | return Promise.all([ 54 | store.getIdentityKeyPair(), 55 | store.getLocalRegistrationId() 56 | ]).then(function(result) { 57 | var identity = result[0]; 58 | var registrationId = result[1]; 59 | 60 | return Promise.all([ 61 | signal.KeyHelper.generatePreKey(preKeyId), 62 | signal.KeyHelper.generateSignedPreKey(identity, signedPreKeyId), 63 | ]).then(function(keys) { 64 | var preKey = keys[0]; 65 | var signedPreKey = keys[1]; 66 | 67 | store.storePreKey(preKeyId, preKey.keyPair); 68 | store.storeSignedPreKey(signedPreKeyId, signedPreKey.keyPair); 69 | 70 | return { 71 | identityKey: identity.pubKey, 72 | registrationId : registrationId, 73 | preKey: { 74 | keyId : preKeyId, 75 | publicKey : preKey.keyPair.pubKey 76 | }, 77 | signedPreKey: { 78 | keyId : signedPreKeyId, 79 | publicKey : signedPreKey.keyPair.pubKey, 80 | signature : signedPreKey.signature 81 | } 82 | }; 83 | }); 84 | }); 85 | } 86 | 87 | // returns a promise of 88 | // [ aliceSessionCipher, bobSessionCipher ] 89 | function bobAliceSessionCiphers () { 90 | var ALICE_ADDRESS = new signal.SignalProtocolAddress("+14151111111", 1); 91 | var BOB_ADDRESS = new signal.SignalProtocolAddress("+14152222222", 1); 92 | 93 | var aliceStore = new SignalStore(); 94 | var bobStore = new SignalStore(); 95 | 96 | var bobPreKeyId = 1337; 97 | var bobSignedKeyId = 1; 98 | 99 | return Promise.all([ 100 | generateIdentity(aliceStore), 101 | generateIdentity(bobStore), 102 | ]).then(function() { 103 | return generatePreKeyBundle(bobStore, bobPreKeyId, bobSignedKeyId); 104 | }).then(function(preKeyBundle) { 105 | var builder = new signal.SessionBuilder(aliceStore, BOB_ADDRESS); 106 | return builder.processPreKey(preKeyBundle); 107 | }).then(function () { 108 | var aliceSessionCipher = new signal.SessionCipher(aliceStore, BOB_ADDRESS); 109 | var bobSessionCipher = new signal.SessionCipher(bobStore, ALICE_ADDRESS); 110 | return [ aliceSessionCipher, bobSessionCipher ]; 111 | }) 112 | } 113 | 114 | it('can encrypt + decrypt a long message', function (done) { 115 | bobAliceSessionCiphers() 116 | .then(function (ciphers) { 117 | var aliceSessionCipher = ciphers[0] 118 | var bobSessionCipher = ciphers[1] 119 | var plaintext = require('./long-plaintext.json').plaintext; 120 | var b = new Buffer(plaintext, 'utf-8'); 121 | aliceSessionCipher.encrypt(b) 122 | .then(c => bobSessionCipher.decryptPreKeyWhisperMessage(c.body, 'binary')) 123 | .then(decodedPlaintext => { 124 | assert.equal(plaintext,new Buffer(decodedPlaintext)); 125 | done(); 126 | }).catch(function (err) { 127 | assert.isUndefined(err); 128 | }); 129 | }) 130 | }); 131 | }) 132 | -------------------------------------------------------------------------------- /test/KeyHelperTest.js: -------------------------------------------------------------------------------- 1 | var KeyHelper = require('../src/KeyHelper.js'); 2 | var assert = require('chai').assert; 3 | 4 | describe('KeyHelper', function() { 5 | function validateKeyPair(keyPair) { 6 | assert.isDefined(keyPair.pubKey); 7 | assert.isDefined(keyPair.privKey); 8 | assert.strictEqual(keyPair.privKey.byteLength, 32); 9 | assert.strictEqual(keyPair.pubKey.byteLength, 33); 10 | assert.strictEqual(new Uint8Array(keyPair.pubKey)[0], 5); 11 | } 12 | 13 | describe('generateIdentityKeyPair', function() { 14 | it ('works', function() { 15 | KeyHelper.generateIdentityKeyPair().then(function(keyPair) { 16 | validateKeyPair(keyPair); 17 | }); 18 | }); 19 | }); 20 | 21 | describe('generateRegistrationId', function() { 22 | it('generates a 14-bit integer', function() { 23 | var registrationId = KeyHelper.generateRegistrationId(); 24 | assert.isNumber(registrationId); 25 | assert(registrationId >= 0); 26 | assert(registrationId < 16384); 27 | assert.strictEqual(registrationId, Math.round(registrationId)); // integer 28 | }); 29 | }); 30 | 31 | describe("generatePreKey", function() { 32 | it('generates a preKey', function(done) { 33 | KeyHelper.generatePreKey(1337).then(function(result) { 34 | validateKeyPair(result.keyPair); 35 | assert.strictEqual(result.keyId, 1337); 36 | }).then(done, done); 37 | }); 38 | it('throws on bad keyId', function() { 39 | assert.throws(function(done) { 40 | KeyHelper.generatePreKey('bad'); 41 | }, TypeError); 42 | }); 43 | }); 44 | 45 | describe("generateSignedPreKey", function() { 46 | it('generates a preKey', function(done) { 47 | KeyHelper.generateIdentityKeyPair().then(function(identityKey) { 48 | KeyHelper.generateSignedPreKey(identityKey, 1337).then(function(result) { 49 | validateKeyPair(result.keyPair); 50 | assert.strictEqual(result.keyId, 1337); 51 | //todo: validate result.signature 52 | }); 53 | }).then(done, done); 54 | }); 55 | it('throws on bad keyId', function() { 56 | assert.throws(function(done) { 57 | KeyHelper.generateSignedPreKey('bad'); 58 | }, TypeError); 59 | }); 60 | }); 61 | }); 62 | -------------------------------------------------------------------------------- /test/NumericFingerprintTest.js: -------------------------------------------------------------------------------- 1 | /* 2 | * vim: ts=4:sw=4 3 | */ 4 | 5 | 'use strict'; 6 | 7 | var Crypto = require('../src/crypto.js'); 8 | var FingerprintGenerator = require('../src/NumericFingerprint.js'); 9 | var assert = require('chai').assert; 10 | 11 | describe('NumericFingerprint', function() { 12 | this.timeout(5000); 13 | var ALICE_IDENTITY = [ 14 | 0x05, 0x06, 0x86, 0x3b, 0xc6, 0x6d, 0x02, 0xb4, 0x0d, 0x27, 0xb8, 0xd4, 15 | 0x9c, 0xa7, 0xc0, 0x9e, 0x92, 0x39, 0x23, 0x6f, 0x9d, 0x7d, 0x25, 0xd6, 16 | 0xfc, 0xca, 0x5c, 0xe1, 0x3c, 0x70, 0x64, 0xd8, 0x68 17 | ]; 18 | var BOB_IDENTITY = [ 19 | 0x05, 0xf7, 0x81, 0xb6, 0xfb, 0x32, 0xfe, 0xd9, 0xba, 0x1c, 0xf2, 0xde, 20 | 0x97, 0x8d, 0x4d, 0x5d, 0xa2, 0x8d, 0xc3, 0x40, 0x46, 0xae, 0x81, 0x44, 21 | 0x02, 0xb5, 0xc0, 0xdb, 0xd9, 0x6f, 0xda, 0x90, 0x7b 22 | ]; 23 | var FINGERPRINT = "300354477692869396892869876765458257569162576843440918079131"; 24 | 25 | var alice = { 26 | identifier: '+14152222222', 27 | key: new Uint8Array(ALICE_IDENTITY).buffer 28 | }; 29 | var bob = { 30 | identifier: '+14153333333', 31 | key: new Uint8Array(BOB_IDENTITY).buffer 32 | }; 33 | 34 | it('returns the correct fingerprint', function(done) { 35 | var generator = new FingerprintGenerator(5200); 36 | generator.createFor( 37 | alice.identifier, alice.key, bob.identifier, bob.key 38 | ).then(function(fingerprint) { 39 | assert.strictEqual(fingerprint, FINGERPRINT); 40 | }).then(done,done); 41 | }); 42 | 43 | it ('alice and bob results match', function(done) { 44 | var generator = new FingerprintGenerator(1024); 45 | Promise.all([ 46 | generator.createFor( 47 | alice.identifier, alice.key, bob.identifier, bob.key 48 | ), 49 | generator.createFor( 50 | bob.identifier, bob.key, alice.identifier, alice.key 51 | ) 52 | ]).then(function(fingerprints) { 53 | assert.strictEqual(fingerprints[0], fingerprints[1]); 54 | }).then(done,done); 55 | }); 56 | 57 | it ('alice and !bob results mismatch', function(done) { 58 | var generator = new FingerprintGenerator(1024); 59 | Promise.all([ 60 | generator.createFor( 61 | alice.identifier, alice.key, '+15558675309', bob.key 62 | ), 63 | generator.createFor( 64 | bob.identifier, bob.key, alice.identifier, alice.key 65 | ) 66 | ]).then(function(fingerprints) { 67 | assert.notStrictEqual(fingerprints[0], fingerprints[1]); 68 | }).then(done,done); 69 | }); 70 | 71 | it ('alice and mitm results mismatch', function(done) { 72 | var mitm = Crypto.crypto.getRandomBytes(33); 73 | var generator = new FingerprintGenerator(1024); 74 | Promise.all([ 75 | generator.createFor( 76 | alice.identifier, alice.key, bob.identifier, mitm 77 | ), 78 | generator.createFor( 79 | bob.identifier, bob.key, alice.identifier, alice.key 80 | ) 81 | ]).then(function(fingerprints) { 82 | assert.notStrictEqual(fingerprints[0], fingerprints[1]); 83 | }).then(done,done); 84 | }); 85 | }); 86 | -------------------------------------------------------------------------------- /test/PreKeyStore_test.js: -------------------------------------------------------------------------------- 1 | var Crypto = require('../src/crypto.js'); 2 | var SignalProtocolAddress = require('../src/SignalProtocolAddress.js'); 3 | var assert = require('chai').assert; 4 | var test_util = require('./test_helpers.js'); 5 | var hexToArrayBuffer = test_util.hexToArrayBuffer; 6 | var assertEqualArrayBuffers = test_util.assertEqualArrayBuffers; 7 | 8 | function testPreKeyStore(store) { 9 | var number = '+5558675309'; 10 | var testKey; 11 | describe('PreKeyStore', function() { 12 | before(function(done) { 13 | Crypto.crypto.createKeyPair().then(function(keyPair) { 14 | testKey = keyPair; 15 | }).then(done,done); 16 | }); 17 | describe('storePreKey', function() { 18 | it('stores prekeys', function(done) { 19 | var address = new SignalProtocolAddress(number, 1); 20 | store.storePreKey(address.toString(), testKey).then(function() { 21 | return store.loadPreKey(address.toString()).then(function(key) { 22 | assertEqualArrayBuffers(key.pubKey, testKey.pubKey); 23 | assertEqualArrayBuffers(key.privKey, testKey.privKey); 24 | }); 25 | }).then(done,done); 26 | }); 27 | }); 28 | describe('loadPreKey', function() { 29 | it('returns prekeys that exist', function(done) { 30 | var address = new SignalProtocolAddress(number, 1); 31 | store.storePreKey(address.toString(), testKey).then(function() { 32 | return store.loadPreKey(address.toString()).then(function(key) { 33 | assertEqualArrayBuffers(key.pubKey, testKey.pubKey); 34 | assertEqualArrayBuffers(key.privKey, testKey.privKey); 35 | }); 36 | }).then(done,done); 37 | }); 38 | it('returns undefined for prekeys that do not exist', function(done) { 39 | var address = new SignalProtocolAddress(number, 2); 40 | store.loadPreKey(2).then(function(key) { 41 | assert.isUndefined(key); 42 | }).then(done,done); 43 | }); 44 | }); 45 | describe('removePreKey', function() { 46 | it('deletes prekeys', function(done) { 47 | var address = new SignalProtocolAddress(number, 2); 48 | before(function(done) { 49 | store.storePreKey(address.toString(), testKey).then(done); 50 | }); 51 | store.removePreKey(address.toString()).then(function() { 52 | return store.loadPreKey(address.toString()).then(function(key) { 53 | assert.isUndefined(key); 54 | }); 55 | }).then(done,done); 56 | }); 57 | }); 58 | }); 59 | } 60 | 61 | module.exports = testPreKeyStore; 62 | -------------------------------------------------------------------------------- /test/SessionBuilderTest.js: -------------------------------------------------------------------------------- 1 | var SessionRecord = require('../src/SessionRecord.js'); 2 | var KeyHelper = require('../src/KeyHelper.js'); 3 | var SessionCipher = require('../src/SessionCipher.js'); 4 | var SessionBuilder = require('../src/SessionBuilder.js'); 5 | var SignalProtocolAddress = require('../src/SignalProtocolAddress.js'); 6 | var util = require('../src/helpers.js'); 7 | var assert = require('chai').assert; 8 | var test_util = require('./test_helpers.js'); 9 | var hexToArrayBuffer = test_util.hexToArrayBuffer; 10 | var assertEqualArrayBuffers = test_util.assertEqualArrayBuffers; 11 | 12 | var SignalProtocolStore = require('./InMemorySignalProtocolStore.js'); 13 | 14 | describe('SessionBuilder', function() { 15 | this.timeout(5000); 16 | // var KeyHelper = KeyHelper; 17 | 18 | function generateIdentity(store) { 19 | return Promise.all([ 20 | KeyHelper.generateIdentityKeyPair(), 21 | KeyHelper.generateRegistrationId(), 22 | ]).then(function(result) { 23 | store.put('identityKey', result[0]); 24 | store.put('registrationId', result[1]); 25 | }); 26 | } 27 | 28 | function generatePreKeyBundle(store, preKeyId, signedPreKeyId) { 29 | return Promise.all([ 30 | store.getIdentityKeyPair(), 31 | store.getLocalRegistrationId() 32 | ]).then(function(result) { 33 | var identity = result[0]; 34 | var registrationId = result[1]; 35 | 36 | return Promise.all([ 37 | KeyHelper.generatePreKey(preKeyId), 38 | KeyHelper.generateSignedPreKey(identity, signedPreKeyId), 39 | ]).then(function(keys) { 40 | var preKey = keys[0] 41 | var signedPreKey = keys[1]; 42 | 43 | store.storePreKey(preKeyId, preKey.keyPair); 44 | store.storeSignedPreKey(signedPreKeyId, signedPreKey.keyPair); 45 | 46 | return { 47 | identityKey: identity.pubKey, 48 | registrationId : registrationId, 49 | preKey: { 50 | keyId : preKeyId, 51 | publicKey : preKey.keyPair.pubKey 52 | }, 53 | signedPreKey: { 54 | keyId : signedPreKeyId, 55 | publicKey : signedPreKey.keyPair.pubKey, 56 | signature : signedPreKey.signature 57 | } 58 | }; 59 | }); 60 | }); 61 | } 62 | 63 | var ALICE_ADDRESS = new SignalProtocolAddress("+14151111111", 1); 64 | var BOB_ADDRESS = new SignalProtocolAddress("+14152222222", 1); 65 | 66 | describe("basic prekey v3", function() { 67 | var aliceStore = new SignalProtocolStore(); 68 | 69 | var bobStore = new SignalProtocolStore(); 70 | var bobPreKeyId = 1337; 71 | var bobSignedKeyId = 1; 72 | 73 | var Curve = require('../src/Curve.js').Curve; 74 | 75 | before(function(done) { 76 | Promise.all([ 77 | generateIdentity(aliceStore), 78 | generateIdentity(bobStore), 79 | ]).then(function() { 80 | return generatePreKeyBundle(bobStore, bobPreKeyId, bobSignedKeyId); 81 | }).then(function(preKeyBundle) { 82 | var builder = new SessionBuilder(aliceStore, BOB_ADDRESS); 83 | return builder.processPreKey(preKeyBundle).then(function() { 84 | done(); 85 | }); 86 | }).catch(done); 87 | }); 88 | 89 | var originalMessage = util.toArrayBuffer("L'homme est condamné à être libre"); 90 | var aliceSessionCipher = new SessionCipher(aliceStore, BOB_ADDRESS); 91 | var bobSessionCipher = new SessionCipher(bobStore, ALICE_ADDRESS); 92 | 93 | it('creates a session', function(done) { 94 | aliceStore.loadSession(BOB_ADDRESS.toString()).then(function(record) { 95 | assert.isDefined(record); 96 | var sessionRecord = SessionRecord.deserialize(record); 97 | assert.isTrue(sessionRecord.haveOpenSession()); 98 | assert.isDefined(sessionRecord.getOpenSession()); 99 | }).then(done, done); 100 | }); 101 | 102 | it('the session can encrypt', function(done) { 103 | aliceSessionCipher.encrypt(originalMessage).then(function(ciphertext) { 104 | 105 | assert.strictEqual(ciphertext.type, 3); // PREKEY_BUNDLE 106 | 107 | return bobSessionCipher.decryptPreKeyWhisperMessage(ciphertext.body, 'binary'); 108 | 109 | }).then(function(plaintext) { 110 | 111 | assertEqualArrayBuffers(plaintext, originalMessage); 112 | 113 | }).then(done, done); 114 | }); 115 | 116 | it('the session can decrypt', function(done) { 117 | bobSessionCipher.encrypt(originalMessage).then(function(ciphertext) { 118 | 119 | return aliceSessionCipher.decryptWhisperMessage(ciphertext.body, 'binary'); 120 | 121 | }).then(function(plaintext) { 122 | 123 | assertEqualArrayBuffers(plaintext, originalMessage); 124 | 125 | }).then(done, done); 126 | }); 127 | 128 | it('accepts a new preKey with the same identity', function(done) { 129 | generatePreKeyBundle(bobStore, bobPreKeyId + 1, bobSignedKeyId + 1).then(function(preKeyBundle) { 130 | var builder = new SessionBuilder(aliceStore, BOB_ADDRESS); 131 | return builder.processPreKey(preKeyBundle).then(function() { 132 | return aliceStore.loadSession(BOB_ADDRESS.toString()).then(function(record) { 133 | assert.isDefined(record); 134 | var sessionRecord = SessionRecord.deserialize(record); 135 | assert.isTrue(sessionRecord.haveOpenSession()); 136 | assert.isDefined(sessionRecord.getOpenSession()); 137 | done(); 138 | }); 139 | }); 140 | }).catch(done); 141 | }); 142 | 143 | it('rejects untrusted identity keys', function(done) { 144 | KeyHelper.generateIdentityKeyPair().then(function(newIdentity) { 145 | var builder = new SessionBuilder(aliceStore, BOB_ADDRESS); 146 | return builder.processPreKey({ 147 | identityKey: newIdentity.pubKey, 148 | registrationId : 12356 149 | }).then(function(e) { 150 | assert.fail('should not be trusted'); 151 | }).catch(function(e) { 152 | assert.strictEqual(e.message, 'Identity key changed'); 153 | done(); 154 | }).catch(done); 155 | }); 156 | }); 157 | }); 158 | }); 159 | -------------------------------------------------------------------------------- /test/SessionStore_test.js: -------------------------------------------------------------------------------- 1 | var SignalProtocolAddress = require('../src/SignalProtocolAddress.js'); 2 | var assert = require('chai').assert; 3 | var test_util = require('./test_helpers.js'); 4 | var hexToArrayBuffer = test_util.hexToArrayBuffer; 5 | var assertEqualArrayBuffers = test_util.assertEqualArrayBuffers; 6 | 7 | function testSessionStore(store) { 8 | describe('SessionStore', function() { 9 | var number = '+5558675309'; 10 | var testRecord = 'an opaque string'; 11 | describe('storeSession', function() { 12 | var address = new SignalProtocolAddress(number, 1); 13 | it('stores sessions encoded as strings', function(done) { 14 | store.storeSession(address.toString(), testRecord).then(function() { 15 | store.loadSession(address.toString()).then(function(record) { 16 | assert.strictEqual(record, testRecord); 17 | }); 18 | }).then(done,done); 19 | }); 20 | it('stores sessions encoded as array buffers', function(done) { 21 | var testRecord = new Uint8Array([1,2,3]).buffer; 22 | store.storeSession(address.toString(), testRecord).then(function() { 23 | return store.loadSession(address.toString()).then(function(record) { 24 | assertEqualArrayBuffers(testRecord, record); 25 | }); 26 | }).then(done,done); 27 | }); 28 | }); 29 | describe('loadSession', function() { 30 | it('returns sessions that exist', function(done) { 31 | var address = new SignalProtocolAddress(number, 1); 32 | var testRecord = 'an opaque string'; 33 | store.storeSession(address.toString(), testRecord).then(function() { 34 | return store.loadSession(address.toString()).then(function(record) { 35 | assert.strictEqual(record, testRecord); 36 | }); 37 | }).then(done,done); 38 | }); 39 | it('returns undefined for sessions that do not exist', function(done) { 40 | var address = new SignalProtocolAddress(number, 2); 41 | store.loadSession(address.toString()).then(function(record) { 42 | assert.isUndefined(record); 43 | }).then(done,done); 44 | }); 45 | }); 46 | describe('removeSession', function() { 47 | it('deletes sessions', function(done) { 48 | var address = new SignalProtocolAddress(number, 1); 49 | before(function(done) { 50 | store.storeSession(address.toString(), testRecord).then(done); 51 | }); 52 | store.removeSession(address.toString()).then(function() { 53 | store.loadSession(address.toString()).then(function(record) { 54 | assert.isUndefined(record); 55 | }); 56 | }).then(done,done); 57 | }); 58 | }); 59 | describe('removeAllSessions', function() { 60 | it('removes all sessions for a number', function(done) { 61 | var devices = [1, 2, 3].map(function(deviceId) { 62 | var address = new SignalProtocolAddress(number, deviceId); 63 | return address.toString(); 64 | }); 65 | var promise = Promise.resolve(); 66 | devices.forEach(function(encodedNumber) { 67 | promise = promise.then(function() { 68 | return store.storeSession(encodedNumber, testRecord + encodedNumber); 69 | }); 70 | }); 71 | promise.then(function() { 72 | store.removeAllSessions(number).then(function(record) { 73 | return Promise.all(devices.map(store.loadSession.bind(store))).then(function(records) { 74 | for (var i in records) { 75 | assert.isUndefined(records[i]); 76 | }; 77 | }); 78 | }); 79 | }).then(done,done); 80 | }); 81 | }); 82 | }); 83 | } 84 | 85 | module.exports = testSessionStore; 86 | -------------------------------------------------------------------------------- /test/SignalProtocolAddressTest.js: -------------------------------------------------------------------------------- 1 | var SignalProtocolAddress = require('../src/SignalProtocolAddress.js'); 2 | var assert = require('chai').assert; 3 | 4 | describe('SignalProtocolAddress', function() { 5 | var name = 'name'; 6 | var deviceId = 42; 7 | var string = 'name.42'; 8 | describe('getName', function() { 9 | it('returns the name', function() { 10 | var address = new SignalProtocolAddress(name, 1); 11 | assert.strictEqual(name, address.getName()); 12 | }); 13 | }); 14 | describe('getDeviceId', function() { 15 | it('returns the deviceId', function() { 16 | var address = new SignalProtocolAddress(name, deviceId); 17 | assert.strictEqual(deviceId, address.getDeviceId()); 18 | }); 19 | }); 20 | describe('toString', function() { 21 | it('returns the address', function() { 22 | var address = new SignalProtocolAddress(name, deviceId); 23 | assert.strictEqual(string, address.toString()); 24 | }); 25 | }); 26 | describe('fromString', function() { 27 | it('throws on a bad inputs', function() { 28 | [ '', null, {} ].forEach(function(input) { 29 | assert.throws(function() { 30 | var address = SignalProtocolAddress.fromString(input); 31 | }); 32 | }); 33 | }); 34 | it('constructs the address', function() { 35 | var address = SignalProtocolAddress.fromString(string); 36 | assert.strictEqual(deviceId, address.getDeviceId()); 37 | assert.strictEqual(name, address.getName()); 38 | }); 39 | }); 40 | }); 41 | -------------------------------------------------------------------------------- /test/SignalProtocolStore_test.js: -------------------------------------------------------------------------------- 1 | /* vim: ts=4:sw=4 */ 2 | 3 | 'use strict'; 4 | 5 | var Crypto = require('../src/crypto.js'); 6 | var SignalProtocolStore = require('./InMemorySignalProtocolStore.js'); 7 | var assert = require('chai').assert; 8 | 9 | 10 | function testSignalProtocolStore (testIdentityKeyStore, testPreKeyStore, testSignedPreKeyStore, testSessionStore) { 11 | describe("SignalProtocolStore", function() { 12 | var store = new SignalProtocolStore(); 13 | var registrationId = 1337; 14 | var identityKey = { 15 | pubKey: Crypto.crypto.getRandomBytes(33), 16 | privKey: Crypto.crypto.getRandomBytes(32), 17 | }; 18 | before(function() { 19 | store.put('registrationId', registrationId); 20 | store.put('identityKey', identityKey); 21 | }); 22 | testIdentityKeyStore(store, registrationId, identityKey); 23 | testPreKeyStore(store); 24 | testSignedPreKeyStore(store); 25 | testSessionStore(store); 26 | }); 27 | } 28 | 29 | module.exports = testSignalProtocolStore; 30 | -------------------------------------------------------------------------------- /test/SignedPreKeyStore_test.js: -------------------------------------------------------------------------------- 1 | var Crypto = require('../src/crypto.js'); 2 | var assert = require('chai').assert; 3 | var test_util = require('./test_helpers.js'); 4 | var hexToArrayBuffer = test_util.hexToArrayBuffer; 5 | var assertEqualArrayBuffers = test_util.assertEqualArrayBuffers; 6 | 7 | function testSignedPreKeyStore(store) { 8 | describe('SignedPreKeyStore', function() { 9 | var testKey; 10 | before(function(done) { 11 | Crypto.crypto.createKeyPair().then(function(keyPair) { 12 | testKey = keyPair; 13 | }).then(done,done); 14 | }); 15 | describe('storeSignedPreKey', function() { 16 | it('stores signed prekeys', function(done) { 17 | store.storeSignedPreKey(3, testKey).then(function() { 18 | return store.loadSignedPreKey(3).then(function(key) { 19 | assertEqualArrayBuffers(key.pubKey, testKey.pubKey); 20 | assertEqualArrayBuffers(key.privKey, testKey.privKey); 21 | }); 22 | }).then(done,done); 23 | }); 24 | }); 25 | describe('loadSignedPreKey', function() { 26 | it('returns prekeys that exist', function(done) { 27 | store.storeSignedPreKey(1, testKey).then(function() { 28 | return store.loadSignedPreKey(1).then(function(key) { 29 | assertEqualArrayBuffers(key.pubKey, testKey.pubKey); 30 | assertEqualArrayBuffers(key.privKey, testKey.privKey); 31 | }); 32 | }).then(done,done); 33 | }); 34 | it('returns undefined for prekeys that do not exist', function(done) { 35 | store.storeSignedPreKey(1, testKey).then(function() { 36 | store.loadSignedPreKey(2).then(function(key) { 37 | assert.isUndefined(key); 38 | }); 39 | }).then(done,done); 40 | }); 41 | }); 42 | describe('removeSignedPreKey', function() { 43 | it('deletes signed prekeys', function(done) { 44 | before(function(done) { 45 | store.storeSignedPreKey(4, testKey).then(done); 46 | }); 47 | store.removeSignedPreKey(4, testKey).then(function() { 48 | return store.loadSignedPreKey(4).then(function(key) { 49 | assert.isUndefined(key); 50 | }); 51 | }).then(done,done); 52 | }); 53 | }); 54 | }); 55 | } 56 | 57 | module.exports = testSignedPreKeyStore; 58 | -------------------------------------------------------------------------------- /test/_test.js: -------------------------------------------------------------------------------- 1 | mocha.setup("bdd"); 2 | window.assert = chai.assert; 3 | 4 | (function() { 5 | var OriginalReporter = mocha._reporter; 6 | 7 | var SauceReporter = function(runner) { 8 | var failedTests = []; 9 | 10 | runner.on('end', function() { 11 | window.mochaResults = runner.stats; 12 | window.mochaResults.reports = failedTests; 13 | }); 14 | 15 | runner.on('fail', function(test, err) { 16 | var flattenTitles = function(test) { 17 | var titles = []; 18 | while (test.parent.title) { 19 | titles.push(test.parent.title); 20 | test = test.parent; 21 | } 22 | return titles.reverse(); 23 | }; 24 | failedTests.push({ 25 | name: test.title, 26 | result: false, 27 | message: err.message, 28 | stack: err.stack, 29 | titles: flattenTitles(test) 30 | }); 31 | }); 32 | 33 | new OriginalReporter(runner); 34 | }; 35 | 36 | SauceReporter.prototype = OriginalReporter.prototype; 37 | 38 | mocha.reporter(SauceReporter); 39 | }()); 40 | -------------------------------------------------------------------------------- /test/crypto_test.js: -------------------------------------------------------------------------------- 1 | /* 2 | * vim: ts=4:sw=4 3 | */ 4 | 5 | 'use strict'; 6 | // window.assert = chai.assert; 7 | 8 | var assert = require('chai').assert; 9 | var Crypto = require('../src/crypto.js'); 10 | var worker = require('../src/curve25519_worker_manager.js'); 11 | var test_util = require('./test_helpers.js'); 12 | var hexToArrayBuffer = test_util.hexToArrayBuffer; 13 | var assertEqualArrayBuffers = test_util.assertEqualArrayBuffers; 14 | 15 | describe("Crypto", function() { 16 | describe("Encrypt AES-CBC", function() { 17 | it('works', function(done) { 18 | var key = hexToArrayBuffer('603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4'); 19 | var iv = hexToArrayBuffer('000102030405060708090a0b0c0d0e0f'); 20 | var plaintext = hexToArrayBuffer('6bc1bee22e409f96e93d7e117393172aae2d8a571e03ac9c9eb76fac45af8e5130c81c46a35ce411e5fbc1191a0a52eff69f2445df4f9b17ad2b417be66c3710'); 21 | var ciphertext = hexToArrayBuffer('f58c4c04d6e5f1ba779eabfb5f7bfbd69cfc4e967edb808d679f777bc6702c7d39f23369a9d9bacfa530e26304231461b2eb05e2c39be9fcda6c19078c6a9d1b3f461796d6b0d6b2e0c2a72b4d80e644'); 22 | Crypto.crypto.encrypt(key, plaintext, iv).then(function(result) { 23 | assertEqualArrayBuffers(result, ciphertext); 24 | }).then(done).catch(done); 25 | }); 26 | }); 27 | 28 | describe("Decrypt AES-CBC", function() { 29 | it('works', function(done) { 30 | var key = hexToArrayBuffer('603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4'); 31 | var iv = hexToArrayBuffer('000102030405060708090a0b0c0d0e0f'); 32 | var plaintext = hexToArrayBuffer('6bc1bee22e409f96e93d7e117393172aae2d8a571e03ac9c9eb76fac45af8e5130c81c46a35ce411e5fbc1191a0a52eff69f2445df4f9b17ad2b417be66c3710'); 33 | var ciphertext = hexToArrayBuffer('f58c4c04d6e5f1ba779eabfb5f7bfbd69cfc4e967edb808d679f777bc6702c7d39f23369a9d9bacfa530e26304231461b2eb05e2c39be9fcda6c19078c6a9d1b3f461796d6b0d6b2e0c2a72b4d80e644'); 34 | Crypto.crypto.decrypt(key, ciphertext, iv).then(function(result) { 35 | assertEqualArrayBuffers(result, plaintext); 36 | }).then(done).catch(done); 37 | }); 38 | }); 39 | 40 | describe("HMAC SHA-256", function() { 41 | it("works", function(done) { 42 | var key = hexToArrayBuffer('6f35628d65813435534b5d67fbdb54cb33403d04e843103e6399f806cb5df95febbdd61236f33245'); 43 | var input = hexToArrayBuffer('752cff52e4b90768558e5369e75d97c69643509a5e5904e0a386cbe4d0970ef73f918f675945a9aefe26daea27587e8dc909dd56fd0468805f834039b345f855cfe19c44b55af241fff3ffcd8045cd5c288e6c4e284c3720570b58e4d47b8feeedc52fd1401f698a209fccfa3b4c0d9a797b046a2759f82a54c41ccd7b5f592b'); 44 | var mac = hexToArrayBuffer('05d1243e6465ed9620c9aec1c351a186'); 45 | Crypto.crypto.sign(key, input).then(function(result) { 46 | assertEqualArrayBuffers(result.slice(0, mac.byteLength), mac); 47 | }).then(done).catch(done); 48 | }); 49 | }); 50 | 51 | 52 | describe("HKDF", function() { 53 | it('works', function(done) { 54 | // HMAC RFC5869 Test vectors 55 | var T1 = hexToArrayBuffer("3cb25f25faacd57a90434f64d0362f2a2d2d0a90cf1a5a4c5db02d56ecc4c5bf"); 56 | var T2 = hexToArrayBuffer("34007208d5b887185865"); 57 | var IKM = new Uint8Array(new ArrayBuffer(22)); 58 | for (var i = 0; i < 22; i++) 59 | IKM[i] = 11; 60 | 61 | var salt = new Uint8Array(new ArrayBuffer(13)); 62 | for (var i = 0; i < 13; i++) 63 | salt[i] = i; 64 | 65 | var info = new Uint8Array(new ArrayBuffer(10)); 66 | for (var i = 0; i < 10; i++) 67 | info[i] = 240 + i; 68 | 69 | Crypto.crypto.HKDF(IKM.buffer, salt.buffer, info.buffer).then(function(OKM){ 70 | assertEqualArrayBuffers(OKM[0], T1); 71 | assertEqualArrayBuffers(OKM[1].slice(0, 10), T2); 72 | }).then(done).catch(done); 73 | }); 74 | }); 75 | 76 | function testCurve25519() { 77 | var alice_bytes = hexToArrayBuffer("77076d0a7318a57d3c16c17251b26645df4c2f87ebc0992ab177fba51db92c2a"); 78 | var alice_priv = hexToArrayBuffer("70076d0a7318a57d3c16c17251b26645df4c2f87ebc0992ab177fba51db92c6a"); 79 | var alice_pub = hexToArrayBuffer("058520f0098930a754748b7ddcb43ef75a0dbf3a0d26381af4eba4a98eaa9b4e6a"); 80 | var bob_bytes = hexToArrayBuffer("5dab087e624a8a4b79e17f8b83800ee66f3bb1292618b6fd1c2f8b27ff88e0eb"); 81 | var bob_priv = hexToArrayBuffer("58ab087e624a8a4b79e17f8b83800ee66f3bb1292618b6fd1c2f8b27ff88e06b"); 82 | var bob_pub = hexToArrayBuffer("05de9edb7d7b7dc1b4d35b61c2ece435373f8343c85b78674dadfc7e146f882b4f"); 83 | var shared_sec = hexToArrayBuffer("4a5d9d5ba4ce2de1728e3bf480350f25e07e21c947d19e3376f09b3c1e161742"); 84 | 85 | describe("createKeyPair", function() { 86 | it ('converts alice private keys to a keypair', function(done) { 87 | Crypto.crypto.createKeyPair(alice_bytes).then(function(keypair) { 88 | assertEqualArrayBuffers(keypair.privKey, alice_priv); 89 | assertEqualArrayBuffers(keypair.pubKey, alice_pub); 90 | done(); 91 | }).catch(done); 92 | }); 93 | it ('converts bob private keys to a keypair', function(done) { 94 | Crypto.crypto.createKeyPair(bob_bytes).then(function(keypair) { 95 | assertEqualArrayBuffers(keypair.privKey, bob_priv); 96 | assertEqualArrayBuffers(keypair.pubKey, bob_pub); 97 | done(); 98 | }).catch(done); 99 | }); 100 | it ('generates a key if one is not provided', function(done) { 101 | Crypto.crypto.createKeyPair().then(function(keypair) { 102 | assert.strictEqual(keypair.privKey.byteLength, 32); 103 | assert.strictEqual(keypair.pubKey.byteLength, 33); 104 | assert.strictEqual(new Uint8Array(keypair.pubKey)[0], 5); 105 | done(); 106 | }).catch(done); 107 | }); 108 | }); 109 | 110 | describe("ECDHE", function() { 111 | it("computes the shared secret for alice", function(done) { 112 | Crypto.crypto.ECDHE(bob_pub, alice_priv).then(function(secret) { 113 | assertEqualArrayBuffers(shared_sec, secret); 114 | done(); 115 | }).catch(done); 116 | }); 117 | it("computes the shared secret for bob", function(done) { 118 | Crypto.crypto.ECDHE(alice_pub, bob_priv).then(function(secret) { 119 | assertEqualArrayBuffers(shared_sec, secret); 120 | done(); 121 | }).catch(done); 122 | }); 123 | }); 124 | 125 | var priv = hexToArrayBuffer("48a8892cc4e49124b7b57d94fa15becfce071830d6449004685e387c62409973"); 126 | var pub = hexToArrayBuffer("0555f1bfede27b6a03e0dd389478ffb01462e5c52dbbac32cf870f00af1ed9af3a"); 127 | var msg = hexToArrayBuffer("617364666173646661736466"); 128 | var sig = hexToArrayBuffer("2bc06c745acb8bae10fbc607ee306084d0c28e2b3bb819133392473431291fd0dfa9c7f11479996cf520730d2901267387e08d85bbf2af941590e3035a545285"); 129 | describe("Ed25519Sign", function() { 130 | // Some self-generated test vectors 131 | it('works', function(done) { 132 | Crypto.crypto.Ed25519Sign(priv, msg).then(function(sigCalc) { 133 | assertEqualArrayBuffers(sig, sigCalc); 134 | }).then(done).catch(done); 135 | }); 136 | }); 137 | 138 | describe("Ed25519Verify", function() { 139 | it("throws on bad signature", function(done) { 140 | var badsig = sig.slice(0); 141 | new Uint8Array(badsig).set([0], 0); 142 | 143 | Crypto.crypto.Ed25519Verify(pub, msg, badsig).catch(function(e) { 144 | if (e.message === 'Invalid signature') { 145 | done(); 146 | } else { throw e; } 147 | }).catch(done); 148 | }); 149 | 150 | it("does not throw on good signature", function(done) { 151 | Crypto.crypto.Ed25519Verify(pub, msg, sig).then(done).catch(done); 152 | }); 153 | }); 154 | } 155 | 156 | describe('curve25519', function() { 157 | this.timeout(5000); 158 | testCurve25519(); 159 | }); 160 | describe('curve25519 in a worker', function() { 161 | before(function() { 162 | worker.startWorker(); 163 | }); 164 | after(function() { 165 | worker.stopWorker(); 166 | }); 167 | this.timeout(5000); 168 | testCurve25519(); 169 | }); 170 | }); 171 | -------------------------------------------------------------------------------- /test/helpers_test.js: -------------------------------------------------------------------------------- 1 | /* vim: ts=4:sw=4 */ 2 | 'use strict'; 3 | 4 | var util = require('../src/helpers.js'); 5 | var assert = require('chai').assert; 6 | 7 | describe('util', function() { 8 | describe("isEqual", function(){ 9 | it('returns false when a or b is undefined', function(){ 10 | assert.isFalse(util.isEqual("defined value", undefined)); 11 | assert.isFalse(util.isEqual(undefined, "defined value")); 12 | }); 13 | it('returns true when a and b are equal', function(){ 14 | var a = "same value"; 15 | var b = "same value"; 16 | assert.isTrue(util.isEqual(a, b)); 17 | }); 18 | it('returns false when a and b are not equal', function(){ 19 | var a = "same value"; 20 | var b = "diferent value"; 21 | assert.isFalse(util.isEqual(a, b)); 22 | }); 23 | it('throws an error when a/b compare is too short', function(){ 24 | var a = "1234"; 25 | var b = "1234"; 26 | assert.throw(function() { util.isEqual(a, b) }, 27 | Error, /a\/b compare too short/); 28 | }); 29 | }); 30 | }); 31 | -------------------------------------------------------------------------------- /test/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | libsignal-protocol tests 4 | 5 | 6 | 7 |
8 |
9 | 10 | 11 | 12 | 13 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /test/long-plaintext.json: -------------------------------------------------------------------------------- 1 | { 2 | "plaintext": "I have a kind of weird story related to death. Something my father told me. He said it was an actual experience he had when he was in his early twenties. Just the age I am now. I’ve heard the story so many times I can remember every detail. It’s a really strange story—it’s hard even now for me to believe it actually happened— but my father isn’t the type to lie about something like that. Or the type who would concoct such a story. I’m sure you know this, but when you make up a story the details change each time you retell it. You tend to embellish things, and forget what you said before. ... But my father’s story, from start to finish, was always exactly the same, each time he told it. So I think it must be something he actually experienced. I’m his son, and I know him really well, so the only thing I can do is believe what he said. But you don’t know my father, Tsukuru, so feel free to believe it or not. Just understand that this is what he told me. You can take it as folklore, or a tale of the supernatural, I don’t mind. It’s a long story, and it’s already late, but do you mind if I tell it?” Sure, Tsukuru said, that would be fine. I’m not sleepy yet. “When my father was young, he spent a year wandering around Japan,” Haida began. “This was at the end of the 1960s, the peak of the counterculture era, when the student movement was upending universities. I don’t know all the details, but when he was in college in Tokyo, a lot of stupid things happened, and he got fed up with politics and left the movement. He took a leave of absence from school and wandered around the country. He did odd jobs to earn a living, read books when he had the time, met all sorts of people, and gained a lot of real-life, practical experience. My father says this was the happiest time of his life, when he learned some important lessons. When I was a kid, he used to tell me stories from those days, like an old soldier reminiscing about long-ago battles in some far-off place. After those bohemian days, he went back to college, and returned to academic life. He never went on a long trip ever again. As far as I know, he’s spent his time since just shuttling back and forth between home and his office. It’s strange, isn’t it? No matter how quiet and conformist a person’s life seems, there’s always a time in the past when they reached an impasse. A time when they went a little crazy. I guess people need that sort of stage in their lives.” 549. The Rime of the Ancient Mariner PART I An ancient Mariner meeteth three gallants bidden to a wedding feast, and detaineth one.IT is an ancient Mariner, And he stoppeth one of three. 'By thy long beard and glittering eye, Now wherefore stopp'st thou me? The Bridegroom's doors are opened wide,5 And I am next of kin; The guests are met, the feast is set: May'st hear the merry din.' He holds him with his skinny hand, 'There was a ship,' quoth he." 3 | } 4 | 5 | -------------------------------------------------------------------------------- /test/main.js: -------------------------------------------------------------------------------- 1 | // /* vim: ts=4:sw=4 */ 2 | 3 | require('./helpers_test.js'); 4 | require('./crypto_test.js'); 5 | require('./SessionCipherTest.js'); 6 | require('./KeyHelperTest.js'); 7 | require('./NumericFingerprintTest.js'); 8 | require('./SessionBuilderTest.js'); 9 | var testIdentityKeyStore = require('./IdentityKeyStore_test.js'); 10 | var testPreKeyStore = require('./PreKeyStore_test.js'); 11 | var testSignedPreKeyStore = require('./SignedPreKeyStore_test.js'); 12 | var testSessionStore = require('./SessionStore_test.js'); 13 | require('./SignalProtocolStore_test.js')( 14 | testIdentityKeyStore, 15 | testPreKeyStore, 16 | testSignedPreKeyStore, 17 | testSessionStore 18 | ); 19 | require('./SignalProtocolAddressTest.js'); 20 | require('./IntegrationTest.js'); 21 | -------------------------------------------------------------------------------- /test/protos: -------------------------------------------------------------------------------- 1 | ../../protos/ -------------------------------------------------------------------------------- /test/temp_helpers.js: -------------------------------------------------------------------------------- 1 | var dcodeIO = require('../build/dcodeIO.js'); 2 | var pushMessages = dcodeIO.loadProto('package textsecure;\n' + 3 | '\n' + 4 | 'option java_package = "org.whispersystems.textsecure.push";\n' + 5 | 'option java_outer_classname = "PushMessageProtos";\n' + 6 | '\n' + 7 | 'message IncomingPushMessageSignal {\n' + 8 | ' enum Type {\n' + 9 | ' UNKNOWN = 0;\n' + 10 | ' CIPHERTEXT = 1;\n' + 11 | ' KEY_EXCHANGE = 2;\n' + 12 | ' PREKEY_BUNDLE = 3;\n' + 13 | ' PLAINTEXT = 4;\n' + 14 | ' RECEIPT = 5;\n' + 15 | ' PREKEY_BUNDLE_DEVICE_CONTROL = 6;\n' + 16 | ' DEVICE_CONTROL = 7;\n' + 17 | ' }\n' + 18 | ' optional Type type = 1;\n' + 19 | ' optional string source = 2;\n' + 20 | ' optional uint32 sourceDevice = 7;\n' + 21 | ' optional string relay = 3;\n' + 22 | ' optional uint64 timestamp = 5;\n' + 23 | ' optional bytes message = 6; // Contains an encrypted PushMessageContent\n' + 24 | '// repeated string destinations = 4; // No longer supported\n' + 25 | '}\n' + 26 | '\n' + 27 | 'message PushMessageContent {\n' + 28 | ' message AttachmentPointer {\n' + 29 | ' optional fixed64 id = 1;\n' + 30 | ' optional string contentType = 2;\n' + 31 | ' optional bytes key = 3;\n' + 32 | ' }\n' + 33 | '\n' + 34 | ' message GroupContext {\n' + 35 | ' enum Type {\n' + 36 | ' UNKNOWN = 0;\n' + 37 | ' UPDATE = 1;\n' + 38 | ' DELIVER = 2;\n' + 39 | ' QUIT = 3;\n' + 40 | ' }\n' + 41 | ' optional bytes id = 1;\n' + 42 | ' optional Type type = 2;\n' + 43 | ' optional string name = 3;\n' + 44 | ' repeated string members = 4;\n' + 45 | ' optional AttachmentPointer avatar = 5;\n' + 46 | ' }\n' + 47 | '\n' + 48 | ' enum Flags {\n' + 49 | ' END_SESSION = 1;\n' + 50 | ' }\n' + 51 | '\n' + 52 | ' optional string body = 1;\n' + 53 | ' repeated AttachmentPointer attachments = 2;\n' + 54 | ' optional GroupContext group = 3;\n' + 55 | ' optional uint32 flags = 4;\n' + 56 | '}').build('textsecure'); 57 | 58 | module.exports = { 59 | protobuf: { 60 | IncomingPushMessageSignal : pushMessages.IncomingPushMessageSignal, 61 | PushMessageContent : pushMessages.PushMessageContent, 62 | } 63 | 64 | }; 65 | -------------------------------------------------------------------------------- /test/test_helpers.js: -------------------------------------------------------------------------------- 1 | var assert = require('chai').assert; 2 | 3 | function assertEqualArrayBuffers(ab1, ab2) { 4 | assert.deepEqual(new Uint8Array(ab1), new Uint8Array(ab2)); 5 | }; 6 | 7 | function hexToArrayBuffer(str) { 8 | var ret = new ArrayBuffer(str.length / 2); 9 | var array = new Uint8Array(ret); 10 | for (var i = 0; i < str.length/2; i++) 11 | array[i] = parseInt(str.substr(i*2, 2), 16); 12 | return ret; 13 | }; 14 | 15 | module.exports = { 16 | assertEqualArrayBuffers: assertEqualArrayBuffers, 17 | hexToArrayBuffer: hexToArrayBuffer 18 | }; 19 | --------------------------------------------------------------------------------