├── .eslintrc.json ├── .gitignore ├── .npmrc ├── Gruntfile.js ├── LICENSE ├── README.md ├── build └── curve25519.js ├── index.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 ├── .eslintrc.json ├── base_key_type.js ├── chain_type.js ├── crypto.js ├── curve.js ├── curve25519_wrapper.js ├── errors.js ├── keyhelper.js ├── numeric_fingerprint.js ├── protobufs.js ├── protocol_address.js ├── queue_job.js ├── session_builder.js ├── session_cipher.js └── session_record.js /.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "parserOptions": { 3 | "ecmaVersion": 8 4 | }, 5 | "env": { 6 | "es6": true, 7 | "node": true 8 | }, 9 | "extends": "eslint:recommended", 10 | "rules": { 11 | "quotes": "off", 12 | "semi": [ 13 | "error", 14 | "always" 15 | ], 16 | "no-console": "off", 17 | "no-debugger": "off", 18 | "no-unused-vars": [ 19 | "error", 20 | { 21 | "args": "none" 22 | } 23 | ], 24 | "no-constant-condition": [ 25 | "error", 26 | { 27 | "checkLoops": false 28 | } 29 | ] 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | *.swp 3 | npm-debug.log 4 | -------------------------------------------------------------------------------- /.npmrc: -------------------------------------------------------------------------------- 1 | package-lock=false 2 | -------------------------------------------------------------------------------- /Gruntfile.js: -------------------------------------------------------------------------------- 1 | var child_process = require('child_process'); 2 | var util = require('util'); 3 | 4 | module.exports = function(grunt) { 5 | 'use strict'; 6 | 7 | grunt.initConfig({ 8 | pkg: grunt.file.readJSON('package.json'), 9 | compile: { 10 | curve25519: { 11 | src_files: [ 12 | 'native/ed25519/additions/*.c', 13 | 'native/curve25519-donna.c', 14 | 'native/ed25519/*.c', 15 | 'native/ed25519/sha512/sha2big.c' 16 | ], 17 | methods: [ 18 | 'curve25519_donna', 19 | 'curve25519_sign', 20 | 'curve25519_verify', 21 | 'crypto_sign_ed25519_ref10_ge_scalarmult_base', 22 | 'sph_sha512_init', 23 | 'malloc' 24 | ] 25 | } 26 | } 27 | }); 28 | 29 | grunt.registerMultiTask('compile', 'Compile the C libraries with emscripten.', function() { 30 | var callback = this.async(); 31 | var outfile = 'build/' + this.target + '.js'; 32 | 33 | var exported_functions = this.data.methods.map(function(name) { 34 | return "'_" + name + "'"; 35 | }); 36 | var flags = [ 37 | '-O3', 38 | '--memory-init-file 0', 39 | '-Qunused-arguments', 40 | '-s INLINING_LIMIT=1', 41 | '-s WASM=0', 42 | '--minify 0', 43 | '-o', outfile, 44 | '-Inative/ed25519/nacl_includes -Inative/ed25519 -Inative/ed25519/sha512', 45 | '-s', "EXPORTED_FUNCTIONS=\"[" + exported_functions.join(',') + "]\""]; 46 | var command = [].concat('emcc', this.data.src_files, flags).join(' '); 47 | grunt.log.writeln('Compiling via emscripten to ' + outfile); 48 | 49 | var exitCode = 0; 50 | grunt.verbose.subhead(command); 51 | grunt.verbose.writeln(util.format('Expecting exit code %d', exitCode)); 52 | 53 | var child = child_process.exec(command); 54 | child.stdout.on('data', function (d) { grunt.log.write(d); }); 55 | child.stderr.on('data', function (d) { grunt.log.error(d); }); 56 | child.on('exit', function(code) { 57 | if (code !== exitCode) { 58 | grunt.log.error(util.format('Exited with code: %d.', code)); 59 | return callback(false); 60 | } 61 | 62 | grunt.verbose.ok(util.format('Exited with code: %d.', code)); 63 | callback(true); 64 | }); 65 | }); 66 | 67 | grunt.registerTask('default', ['compile']); 68 | grunt.registerTask('build', ['compile']); 69 | }; 70 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | libsignal-node 2 | ======== 3 | Signal protocol implementation for Node.js based on 4 | [libsignal-protocol-javascript](https://github.com/WhisperSystems/libsignal-protocol-javascript). 5 | 6 | [![npm](https://img.shields.io/npm/v/libsignal.svg)](https://www.npmjs.com/package/libsignal) 7 | [![npm](https://img.shields.io/npm/l/libsignal.svg)](https://github.com/ForstaLabs/libsignal-node) 8 | 9 | 10 | Overview 11 | -------- 12 | A ratcheting forward secrecy protocol that works in synchronous and 13 | asynchronous messaging environments. 14 | 15 | 16 | PreKeys 17 | -------- 18 | This protocol uses a concept called 'PreKeys'. A PreKey is an ECPublicKey and 19 | an associated unique ID which are stored together by a server. PreKeys can also 20 | be signed. 21 | 22 | At install time, clients generate a single signed PreKey, as well as a large 23 | list of unsigned PreKeys, and transmit all of them to the server. 24 | 25 | 26 | Sessions 27 | -------- 28 | Signal Protocol is session-oriented. Clients establish a "session," which is 29 | then used for all subsequent encrypt/decrypt operations. There is no need to 30 | ever tear down a session once one has been established. 31 | 32 | Sessions are established in one of two ways: 33 | 34 | 1. PreKeyBundles. A client that wishes to send a message to a recipient can 35 | establish a session by retrieving a PreKeyBundle for that recipient from the 36 | server. 37 | 2. PreKeySignalMessages. A client can receive a PreKeySignalMessage from a 38 | recipient and use it to establish a session. 39 | 40 | 41 | State 42 | -------- 43 | An established session encapsulates a lot of state between two clients. That 44 | state is maintained in durable records which need to be kept for the life of 45 | the session. 46 | 47 | State is kept in the following places: 48 | 49 | * Identity State. Clients will need to maintain the state of their own identity 50 | key pair, as well as identity keys received from other clients. 51 | * PreKey State. Clients will need to maintain the state of their generated 52 | PreKeys. 53 | * Signed PreKey States. Clients will need to maintain the state of their signed 54 | PreKeys. 55 | * Session State. Clients will need to maintain the state of the sessions they 56 | have established. 57 | 58 | 59 | License 60 | -------- 61 | Licensed under the GPLv3: http://www.gnu.org/licenses/gpl-3.0.html 62 | 63 | * Copyright 2015-2016 Open Whisper Systems 64 | * Copyright 2017-2018 Forsta Inc 65 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | exports.crypto = require('./src/crypto'); 4 | exports.curve = require('./src/curve'); 5 | exports.keyhelper = require('./src/keyhelper'); 6 | exports.ProtocolAddress = require('./src/protocol_address'); 7 | exports.SessionBuilder = require('./src/session_builder'); 8 | exports.SessionCipher = require('./src/session_cipher'); 9 | exports.SessionRecord = require('./src/session_record'); 10 | Object.assign(exports, require('./src/errors')); 11 | -------------------------------------------------------------------------------- /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_mul.c: -------------------------------------------------------------------------------- 1 | #include "fe.h" 2 | #include "crypto_int64.h" 3 | 4 | /* 5 | h = f * g 6 | Can overlap h with f or g. 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 | |g| bounded by 1.65*2^26,1.65*2^25,1.65*2^26,1.65*2^25,etc. 11 | 12 | Postconditions: 13 | |h| bounded by 1.01*2^25,1.01*2^24,1.01*2^25,1.01*2^24,etc. 14 | */ 15 | 16 | /* 17 | Notes on implementation strategy: 18 | 19 | Using schoolbook multiplication. 20 | Karatsuba would save a little in some cost models. 21 | 22 | Most multiplications by 2 and 19 are 32-bit precomputations; 23 | cheaper than 64-bit postcomputations. 24 | 25 | There is one remaining multiplication by 19 in the carry chain; 26 | one *19 precomputation can be merged into this, 27 | but the resulting data flow is considerably less clean. 28 | 29 | There are 12 carries below. 30 | 10 of them are 2-way parallelizable and vectorizable. 31 | Can get away with 11 carries, but then data flow is much deeper. 32 | 33 | With tighter constraints on inputs can squeeze carries into int32. 34 | */ 35 | 36 | void fe_mul(fe h,const fe f,const fe g) 37 | { 38 | crypto_int32 f0 = f[0]; 39 | crypto_int32 f1 = f[1]; 40 | crypto_int32 f2 = f[2]; 41 | crypto_int32 f3 = f[3]; 42 | crypto_int32 f4 = f[4]; 43 | crypto_int32 f5 = f[5]; 44 | crypto_int32 f6 = f[6]; 45 | crypto_int32 f7 = f[7]; 46 | crypto_int32 f8 = f[8]; 47 | crypto_int32 f9 = f[9]; 48 | crypto_int32 g0 = g[0]; 49 | crypto_int32 g1 = g[1]; 50 | crypto_int32 g2 = g[2]; 51 | crypto_int32 g3 = g[3]; 52 | crypto_int32 g4 = g[4]; 53 | crypto_int32 g5 = g[5]; 54 | crypto_int32 g6 = g[6]; 55 | crypto_int32 g7 = g[7]; 56 | crypto_int32 g8 = g[8]; 57 | crypto_int32 g9 = g[9]; 58 | crypto_int32 g1_19 = 19 * g1; /* 1.959375*2^29 */ 59 | crypto_int32 g2_19 = 19 * g2; /* 1.959375*2^30; still ok */ 60 | crypto_int32 g3_19 = 19 * g3; 61 | crypto_int32 g4_19 = 19 * g4; 62 | crypto_int32 g5_19 = 19 * g5; 63 | crypto_int32 g6_19 = 19 * g6; 64 | crypto_int32 g7_19 = 19 * g7; 65 | crypto_int32 g8_19 = 19 * g8; 66 | crypto_int32 g9_19 = 19 * g9; 67 | crypto_int32 f1_2 = 2 * f1; 68 | crypto_int32 f3_2 = 2 * f3; 69 | crypto_int32 f5_2 = 2 * f5; 70 | crypto_int32 f7_2 = 2 * f7; 71 | crypto_int32 f9_2 = 2 * f9; 72 | crypto_int64 f0g0 = f0 * (crypto_int64) g0; 73 | crypto_int64 f0g1 = f0 * (crypto_int64) g1; 74 | crypto_int64 f0g2 = f0 * (crypto_int64) g2; 75 | crypto_int64 f0g3 = f0 * (crypto_int64) g3; 76 | crypto_int64 f0g4 = f0 * (crypto_int64) g4; 77 | crypto_int64 f0g5 = f0 * (crypto_int64) g5; 78 | crypto_int64 f0g6 = f0 * (crypto_int64) g6; 79 | crypto_int64 f0g7 = f0 * (crypto_int64) g7; 80 | crypto_int64 f0g8 = f0 * (crypto_int64) g8; 81 | crypto_int64 f0g9 = f0 * (crypto_int64) g9; 82 | crypto_int64 f1g0 = f1 * (crypto_int64) g0; 83 | crypto_int64 f1g1_2 = f1_2 * (crypto_int64) g1; 84 | crypto_int64 f1g2 = f1 * (crypto_int64) g2; 85 | crypto_int64 f1g3_2 = f1_2 * (crypto_int64) g3; 86 | crypto_int64 f1g4 = f1 * (crypto_int64) g4; 87 | crypto_int64 f1g5_2 = f1_2 * (crypto_int64) g5; 88 | crypto_int64 f1g6 = f1 * (crypto_int64) g6; 89 | crypto_int64 f1g7_2 = f1_2 * (crypto_int64) g7; 90 | crypto_int64 f1g8 = f1 * (crypto_int64) g8; 91 | crypto_int64 f1g9_38 = f1_2 * (crypto_int64) g9_19; 92 | crypto_int64 f2g0 = f2 * (crypto_int64) g0; 93 | crypto_int64 f2g1 = f2 * (crypto_int64) g1; 94 | crypto_int64 f2g2 = f2 * (crypto_int64) g2; 95 | crypto_int64 f2g3 = f2 * (crypto_int64) g3; 96 | crypto_int64 f2g4 = f2 * (crypto_int64) g4; 97 | crypto_int64 f2g5 = f2 * (crypto_int64) g5; 98 | crypto_int64 f2g6 = f2 * (crypto_int64) g6; 99 | crypto_int64 f2g7 = f2 * (crypto_int64) g7; 100 | crypto_int64 f2g8_19 = f2 * (crypto_int64) g8_19; 101 | crypto_int64 f2g9_19 = f2 * (crypto_int64) g9_19; 102 | crypto_int64 f3g0 = f3 * (crypto_int64) g0; 103 | crypto_int64 f3g1_2 = f3_2 * (crypto_int64) g1; 104 | crypto_int64 f3g2 = f3 * (crypto_int64) g2; 105 | crypto_int64 f3g3_2 = f3_2 * (crypto_int64) g3; 106 | crypto_int64 f3g4 = f3 * (crypto_int64) g4; 107 | crypto_int64 f3g5_2 = f3_2 * (crypto_int64) g5; 108 | crypto_int64 f3g6 = f3 * (crypto_int64) g6; 109 | crypto_int64 f3g7_38 = f3_2 * (crypto_int64) g7_19; 110 | crypto_int64 f3g8_19 = f3 * (crypto_int64) g8_19; 111 | crypto_int64 f3g9_38 = f3_2 * (crypto_int64) g9_19; 112 | crypto_int64 f4g0 = f4 * (crypto_int64) g0; 113 | crypto_int64 f4g1 = f4 * (crypto_int64) g1; 114 | crypto_int64 f4g2 = f4 * (crypto_int64) g2; 115 | crypto_int64 f4g3 = f4 * (crypto_int64) g3; 116 | crypto_int64 f4g4 = f4 * (crypto_int64) g4; 117 | crypto_int64 f4g5 = f4 * (crypto_int64) g5; 118 | crypto_int64 f4g6_19 = f4 * (crypto_int64) g6_19; 119 | crypto_int64 f4g7_19 = f4 * (crypto_int64) g7_19; 120 | crypto_int64 f4g8_19 = f4 * (crypto_int64) g8_19; 121 | crypto_int64 f4g9_19 = f4 * (crypto_int64) g9_19; 122 | crypto_int64 f5g0 = f5 * (crypto_int64) g0; 123 | crypto_int64 f5g1_2 = f5_2 * (crypto_int64) g1; 124 | crypto_int64 f5g2 = f5 * (crypto_int64) g2; 125 | crypto_int64 f5g3_2 = f5_2 * (crypto_int64) g3; 126 | crypto_int64 f5g4 = f5 * (crypto_int64) g4; 127 | crypto_int64 f5g5_38 = f5_2 * (crypto_int64) g5_19; 128 | crypto_int64 f5g6_19 = f5 * (crypto_int64) g6_19; 129 | crypto_int64 f5g7_38 = f5_2 * (crypto_int64) g7_19; 130 | crypto_int64 f5g8_19 = f5 * (crypto_int64) g8_19; 131 | crypto_int64 f5g9_38 = f5_2 * (crypto_int64) g9_19; 132 | crypto_int64 f6g0 = f6 * (crypto_int64) g0; 133 | crypto_int64 f6g1 = f6 * (crypto_int64) g1; 134 | crypto_int64 f6g2 = f6 * (crypto_int64) g2; 135 | crypto_int64 f6g3 = f6 * (crypto_int64) g3; 136 | crypto_int64 f6g4_19 = f6 * (crypto_int64) g4_19; 137 | crypto_int64 f6g5_19 = f6 * (crypto_int64) g5_19; 138 | crypto_int64 f6g6_19 = f6 * (crypto_int64) g6_19; 139 | crypto_int64 f6g7_19 = f6 * (crypto_int64) g7_19; 140 | crypto_int64 f6g8_19 = f6 * (crypto_int64) g8_19; 141 | crypto_int64 f6g9_19 = f6 * (crypto_int64) g9_19; 142 | crypto_int64 f7g0 = f7 * (crypto_int64) g0; 143 | crypto_int64 f7g1_2 = f7_2 * (crypto_int64) g1; 144 | crypto_int64 f7g2 = f7 * (crypto_int64) g2; 145 | crypto_int64 f7g3_38 = f7_2 * (crypto_int64) g3_19; 146 | crypto_int64 f7g4_19 = f7 * (crypto_int64) g4_19; 147 | crypto_int64 f7g5_38 = f7_2 * (crypto_int64) g5_19; 148 | crypto_int64 f7g6_19 = f7 * (crypto_int64) g6_19; 149 | crypto_int64 f7g7_38 = f7_2 * (crypto_int64) g7_19; 150 | crypto_int64 f7g8_19 = f7 * (crypto_int64) g8_19; 151 | crypto_int64 f7g9_38 = f7_2 * (crypto_int64) g9_19; 152 | crypto_int64 f8g0 = f8 * (crypto_int64) g0; 153 | crypto_int64 f8g1 = f8 * (crypto_int64) g1; 154 | crypto_int64 f8g2_19 = f8 * (crypto_int64) g2_19; 155 | crypto_int64 f8g3_19 = f8 * (crypto_int64) g3_19; 156 | crypto_int64 f8g4_19 = f8 * (crypto_int64) g4_19; 157 | crypto_int64 f8g5_19 = f8 * (crypto_int64) g5_19; 158 | crypto_int64 f8g6_19 = f8 * (crypto_int64) g6_19; 159 | crypto_int64 f8g7_19 = f8 * (crypto_int64) g7_19; 160 | crypto_int64 f8g8_19 = f8 * (crypto_int64) g8_19; 161 | crypto_int64 f8g9_19 = f8 * (crypto_int64) g9_19; 162 | crypto_int64 f9g0 = f9 * (crypto_int64) g0; 163 | crypto_int64 f9g1_38 = f9_2 * (crypto_int64) g1_19; 164 | crypto_int64 f9g2_19 = f9 * (crypto_int64) g2_19; 165 | crypto_int64 f9g3_38 = f9_2 * (crypto_int64) g3_19; 166 | crypto_int64 f9g4_19 = f9 * (crypto_int64) g4_19; 167 | crypto_int64 f9g5_38 = f9_2 * (crypto_int64) g5_19; 168 | crypto_int64 f9g6_19 = f9 * (crypto_int64) g6_19; 169 | crypto_int64 f9g7_38 = f9_2 * (crypto_int64) g7_19; 170 | crypto_int64 f9g8_19 = f9 * (crypto_int64) g8_19; 171 | crypto_int64 f9g9_38 = f9_2 * (crypto_int64) g9_19; 172 | crypto_int64 h0 = f0g0+f1g9_38+f2g8_19+f3g7_38+f4g6_19+f5g5_38+f6g4_19+f7g3_38+f8g2_19+f9g1_38; 173 | crypto_int64 h1 = f0g1+f1g0 +f2g9_19+f3g8_19+f4g7_19+f5g6_19+f6g5_19+f7g4_19+f8g3_19+f9g2_19; 174 | crypto_int64 h2 = f0g2+f1g1_2 +f2g0 +f3g9_38+f4g8_19+f5g7_38+f6g6_19+f7g5_38+f8g4_19+f9g3_38; 175 | crypto_int64 h3 = f0g3+f1g2 +f2g1 +f3g0 +f4g9_19+f5g8_19+f6g7_19+f7g6_19+f8g5_19+f9g4_19; 176 | crypto_int64 h4 = f0g4+f1g3_2 +f2g2 +f3g1_2 +f4g0 +f5g9_38+f6g8_19+f7g7_38+f8g6_19+f9g5_38; 177 | crypto_int64 h5 = f0g5+f1g4 +f2g3 +f3g2 +f4g1 +f5g0 +f6g9_19+f7g8_19+f8g7_19+f9g6_19; 178 | crypto_int64 h6 = f0g6+f1g5_2 +f2g4 +f3g3_2 +f4g2 +f5g1_2 +f6g0 +f7g9_38+f8g8_19+f9g7_38; 179 | crypto_int64 h7 = f0g7+f1g6 +f2g5 +f3g4 +f4g3 +f5g2 +f6g1 +f7g0 +f8g9_19+f9g8_19; 180 | crypto_int64 h8 = f0g8+f1g7_2 +f2g6 +f3g5_2 +f4g4 +f5g3_2 +f6g2 +f7g1_2 +f8g0 +f9g9_38; 181 | crypto_int64 h9 = f0g9+f1g8 +f2g7 +f3g6 +f4g5 +f5g4 +f6g3 +f7g2 +f8g1 +f9g0 ; 182 | crypto_int64 carry0; 183 | crypto_int64 carry1; 184 | crypto_int64 carry2; 185 | crypto_int64 carry3; 186 | crypto_int64 carry4; 187 | crypto_int64 carry5; 188 | crypto_int64 carry6; 189 | crypto_int64 carry7; 190 | crypto_int64 carry8; 191 | crypto_int64 carry9; 192 | 193 | /* 194 | |h0| <= (1.65*1.65*2^52*(1+19+19+19+19)+1.65*1.65*2^50*(38+38+38+38+38)) 195 | i.e. |h0| <= 1.4*2^60; narrower ranges for h2, h4, h6, h8 196 | |h1| <= (1.65*1.65*2^51*(1+1+19+19+19+19+19+19+19+19)) 197 | i.e. |h1| <= 1.7*2^59; narrower ranges for h3, h5, h7, h9 198 | */ 199 | 200 | carry0 = (h0 + (crypto_int64) (1<<25)) >> 26; h1 += carry0; h0 -= carry0 << 26; 201 | carry4 = (h4 + (crypto_int64) (1<<25)) >> 26; h5 += carry4; h4 -= carry4 << 26; 202 | /* |h0| <= 2^25 */ 203 | /* |h4| <= 2^25 */ 204 | /* |h1| <= 1.71*2^59 */ 205 | /* |h5| <= 1.71*2^59 */ 206 | 207 | carry1 = (h1 + (crypto_int64) (1<<24)) >> 25; h2 += carry1; h1 -= carry1 << 25; 208 | carry5 = (h5 + (crypto_int64) (1<<24)) >> 25; h6 += carry5; h5 -= carry5 << 25; 209 | /* |h1| <= 2^24; from now on fits into int32 */ 210 | /* |h5| <= 2^24; from now on fits into int32 */ 211 | /* |h2| <= 1.41*2^60 */ 212 | /* |h6| <= 1.41*2^60 */ 213 | 214 | carry2 = (h2 + (crypto_int64) (1<<25)) >> 26; h3 += carry2; h2 -= carry2 << 26; 215 | carry6 = (h6 + (crypto_int64) (1<<25)) >> 26; h7 += carry6; h6 -= carry6 << 26; 216 | /* |h2| <= 2^25; from now on fits into int32 unchanged */ 217 | /* |h6| <= 2^25; from now on fits into int32 unchanged */ 218 | /* |h3| <= 1.71*2^59 */ 219 | /* |h7| <= 1.71*2^59 */ 220 | 221 | carry3 = (h3 + (crypto_int64) (1<<24)) >> 25; h4 += carry3; h3 -= carry3 << 25; 222 | carry7 = (h7 + (crypto_int64) (1<<24)) >> 25; h8 += carry7; h7 -= carry7 << 25; 223 | /* |h3| <= 2^24; from now on fits into int32 unchanged */ 224 | /* |h7| <= 2^24; from now on fits into int32 unchanged */ 225 | /* |h4| <= 1.72*2^34 */ 226 | /* |h8| <= 1.41*2^60 */ 227 | 228 | carry4 = (h4 + (crypto_int64) (1<<25)) >> 26; h5 += carry4; h4 -= carry4 << 26; 229 | carry8 = (h8 + (crypto_int64) (1<<25)) >> 26; h9 += carry8; h8 -= carry8 << 26; 230 | /* |h4| <= 2^25; from now on fits into int32 unchanged */ 231 | /* |h8| <= 2^25; from now on fits into int32 unchanged */ 232 | /* |h5| <= 1.01*2^24 */ 233 | /* |h9| <= 1.71*2^59 */ 234 | 235 | carry9 = (h9 + (crypto_int64) (1<<24)) >> 25; h0 += carry9 * 19; h9 -= carry9 << 25; 236 | /* |h9| <= 2^24; from now on fits into int32 unchanged */ 237 | /* |h0| <= 1.1*2^39 */ 238 | 239 | carry0 = (h0 + (crypto_int64) (1<<25)) >> 26; h1 += carry0; h0 -= carry0 << 26; 240 | /* |h0| <= 2^25; from now on fits into int32 unchanged */ 241 | /* |h1| <= 1.01*2^24 */ 242 | 243 | h[0] = h0; 244 | h[1] = h1; 245 | h[2] = h2; 246 | h[3] = h3; 247 | h[4] = h4; 248 | h[5] = h5; 249 | h[6] = h6; 250 | h[7] = h7; 251 | h[8] = h8; 252 | h[9] = h9; 253 | } 254 | -------------------------------------------------------------------------------- /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); 40 | crypto_int64 a2 = 2097151 & (load_3(a + 5) >> 2); 41 | crypto_int64 a3 = 2097151 & (load_4(a + 7) >> 7); 42 | crypto_int64 a4 = 2097151 & (load_4(a + 10) >> 4); 43 | crypto_int64 a5 = 2097151 & (load_3(a + 13) >> 1); 44 | crypto_int64 a6 = 2097151 & (load_4(a + 15) >> 6); 45 | crypto_int64 a7 = 2097151 & (load_3(a + 18) >> 3); 46 | crypto_int64 a8 = 2097151 & load_3(a + 21); 47 | crypto_int64 a9 = 2097151 & (load_4(a + 23) >> 5); 48 | crypto_int64 a10 = 2097151 & (load_3(a + 26) >> 2); 49 | crypto_int64 a11 = (load_4(a + 28) >> 7); 50 | crypto_int64 b0 = 2097151 & load_3(b); 51 | crypto_int64 b1 = 2097151 & (load_4(b + 2) >> 5); 52 | crypto_int64 b2 = 2097151 & (load_3(b + 5) >> 2); 53 | crypto_int64 b3 = 2097151 & (load_4(b + 7) >> 7); 54 | crypto_int64 b4 = 2097151 & (load_4(b + 10) >> 4); 55 | crypto_int64 b5 = 2097151 & (load_3(b + 13) >> 1); 56 | crypto_int64 b6 = 2097151 & (load_4(b + 15) >> 6); 57 | crypto_int64 b7 = 2097151 & (load_3(b + 18) >> 3); 58 | crypto_int64 b8 = 2097151 & load_3(b + 21); 59 | crypto_int64 b9 = 2097151 & (load_4(b + 23) >> 5); 60 | crypto_int64 b10 = 2097151 & (load_3(b + 26) >> 2); 61 | crypto_int64 b11 = (load_4(b + 28) >> 7); 62 | crypto_int64 c0 = 2097151 & load_3(c); 63 | crypto_int64 c1 = 2097151 & (load_4(c + 2) >> 5); 64 | crypto_int64 c2 = 2097151 & (load_3(c + 5) >> 2); 65 | crypto_int64 c3 = 2097151 & (load_4(c + 7) >> 7); 66 | crypto_int64 c4 = 2097151 & (load_4(c + 10) >> 4); 67 | crypto_int64 c5 = 2097151 & (load_3(c + 13) >> 1); 68 | crypto_int64 c6 = 2097151 & (load_4(c + 15) >> 6); 69 | crypto_int64 c7 = 2097151 & (load_3(c + 18) >> 3); 70 | crypto_int64 c8 = 2097151 & load_3(c + 21); 71 | crypto_int64 c9 = 2097151 & (load_4(c + 23) >> 5); 72 | crypto_int64 c10 = 2097151 & (load_3(c + 26) >> 2); 73 | crypto_int64 c11 = (load_4(c + 28) >> 7); 74 | crypto_int64 s0; 75 | crypto_int64 s1; 76 | crypto_int64 s2; 77 | crypto_int64 s3; 78 | crypto_int64 s4; 79 | crypto_int64 s5; 80 | crypto_int64 s6; 81 | crypto_int64 s7; 82 | crypto_int64 s8; 83 | crypto_int64 s9; 84 | crypto_int64 s10; 85 | crypto_int64 s11; 86 | crypto_int64 s12; 87 | crypto_int64 s13; 88 | crypto_int64 s14; 89 | crypto_int64 s15; 90 | crypto_int64 s16; 91 | crypto_int64 s17; 92 | crypto_int64 s18; 93 | crypto_int64 s19; 94 | crypto_int64 s20; 95 | crypto_int64 s21; 96 | crypto_int64 s22; 97 | crypto_int64 s23; 98 | crypto_int64 carry0; 99 | crypto_int64 carry1; 100 | crypto_int64 carry2; 101 | crypto_int64 carry3; 102 | crypto_int64 carry4; 103 | crypto_int64 carry5; 104 | crypto_int64 carry6; 105 | crypto_int64 carry7; 106 | crypto_int64 carry8; 107 | crypto_int64 carry9; 108 | crypto_int64 carry10; 109 | crypto_int64 carry11; 110 | crypto_int64 carry12; 111 | crypto_int64 carry13; 112 | crypto_int64 carry14; 113 | crypto_int64 carry15; 114 | crypto_int64 carry16; 115 | crypto_int64 carry17; 116 | crypto_int64 carry18; 117 | crypto_int64 carry19; 118 | crypto_int64 carry20; 119 | crypto_int64 carry21; 120 | crypto_int64 carry22; 121 | 122 | s0 = c0 + a0*b0; 123 | s1 = c1 + a0*b1 + a1*b0; 124 | s2 = c2 + a0*b2 + a1*b1 + a2*b0; 125 | s3 = c3 + a0*b3 + a1*b2 + a2*b1 + a3*b0; 126 | s4 = c4 + a0*b4 + a1*b3 + a2*b2 + a3*b1 + a4*b0; 127 | s5 = c5 + a0*b5 + a1*b4 + a2*b3 + a3*b2 + a4*b1 + a5*b0; 128 | s6 = c6 + a0*b6 + a1*b5 + a2*b4 + a3*b3 + a4*b2 + a5*b1 + a6*b0; 129 | s7 = c7 + a0*b7 + a1*b6 + a2*b5 + a3*b4 + a4*b3 + a5*b2 + a6*b1 + a7*b0; 130 | s8 = c8 + a0*b8 + a1*b7 + a2*b6 + a3*b5 + a4*b4 + a5*b3 + a6*b2 + a7*b1 + a8*b0; 131 | s9 = c9 + a0*b9 + a1*b8 + a2*b7 + a3*b6 + a4*b5 + a5*b4 + a6*b3 + a7*b2 + a8*b1 + a9*b0; 132 | s10 = c10 + a0*b10 + a1*b9 + a2*b8 + a3*b7 + a4*b6 + a5*b5 + a6*b4 + a7*b3 + a8*b2 + a9*b1 + a10*b0; 133 | s11 = c11 + a0*b11 + a1*b10 + a2*b9 + a3*b8 + a4*b7 + a5*b6 + a6*b5 + a7*b4 + a8*b3 + a9*b2 + a10*b1 + a11*b0; 134 | s12 = a1*b11 + a2*b10 + a3*b9 + a4*b8 + a5*b7 + a6*b6 + a7*b5 + a8*b4 + a9*b3 + a10*b2 + a11*b1; 135 | s13 = a2*b11 + a3*b10 + a4*b9 + a5*b8 + a6*b7 + a7*b6 + a8*b5 + a9*b4 + a10*b3 + a11*b2; 136 | s14 = a3*b11 + a4*b10 + a5*b9 + a6*b8 + a7*b7 + a8*b6 + a9*b5 + a10*b4 + a11*b3; 137 | s15 = a4*b11 + a5*b10 + a6*b9 + a7*b8 + a8*b7 + a9*b6 + a10*b5 + a11*b4; 138 | s16 = a5*b11 + a6*b10 + a7*b9 + a8*b8 + a9*b7 + a10*b6 + a11*b5; 139 | s17 = a6*b11 + a7*b10 + a8*b9 + a9*b8 + a10*b7 + a11*b6; 140 | s18 = a7*b11 + a8*b10 + a9*b9 + a10*b8 + a11*b7; 141 | s19 = a8*b11 + a9*b10 + a10*b9 + a11*b8; 142 | s20 = a9*b11 + a10*b10 + a11*b9; 143 | s21 = a10*b11 + a11*b10; 144 | s22 = a11*b11; 145 | s23 = 0; 146 | 147 | carry0 = (s0 + (1<<20)) >> 21; s1 += carry0; s0 -= carry0 << 21; 148 | carry2 = (s2 + (1<<20)) >> 21; s3 += carry2; s2 -= carry2 << 21; 149 | carry4 = (s4 + (1<<20)) >> 21; s5 += carry4; s4 -= carry4 << 21; 150 | carry6 = (s6 + (1<<20)) >> 21; s7 += carry6; s6 -= carry6 << 21; 151 | carry8 = (s8 + (1<<20)) >> 21; s9 += carry8; s8 -= carry8 << 21; 152 | carry10 = (s10 + (1<<20)) >> 21; s11 += carry10; s10 -= carry10 << 21; 153 | carry12 = (s12 + (1<<20)) >> 21; s13 += carry12; s12 -= carry12 << 21; 154 | carry14 = (s14 + (1<<20)) >> 21; s15 += carry14; s14 -= carry14 << 21; 155 | carry16 = (s16 + (1<<20)) >> 21; s17 += carry16; s16 -= carry16 << 21; 156 | carry18 = (s18 + (1<<20)) >> 21; s19 += carry18; s18 -= carry18 << 21; 157 | carry20 = (s20 + (1<<20)) >> 21; s21 += carry20; s20 -= carry20 << 21; 158 | carry22 = (s22 + (1<<20)) >> 21; s23 += carry22; s22 -= carry22 << 21; 159 | 160 | carry1 = (s1 + (1<<20)) >> 21; s2 += carry1; s1 -= carry1 << 21; 161 | carry3 = (s3 + (1<<20)) >> 21; s4 += carry3; s3 -= carry3 << 21; 162 | carry5 = (s5 + (1<<20)) >> 21; s6 += carry5; s5 -= carry5 << 21; 163 | carry7 = (s7 + (1<<20)) >> 21; s8 += carry7; s7 -= carry7 << 21; 164 | carry9 = (s9 + (1<<20)) >> 21; s10 += carry9; s9 -= carry9 << 21; 165 | carry11 = (s11 + (1<<20)) >> 21; s12 += carry11; s11 -= carry11 << 21; 166 | carry13 = (s13 + (1<<20)) >> 21; s14 += carry13; s13 -= carry13 << 21; 167 | carry15 = (s15 + (1<<20)) >> 21; s16 += carry15; s15 -= carry15 << 21; 168 | carry17 = (s17 + (1<<20)) >> 21; s18 += carry17; s17 -= carry17 << 21; 169 | carry19 = (s19 + (1<<20)) >> 21; s20 += carry19; s19 -= carry19 << 21; 170 | carry21 = (s21 + (1<<20)) >> 21; s22 += carry21; s21 -= carry21 << 21; 171 | 172 | s11 += s23 * 666643; 173 | s12 += s23 * 470296; 174 | s13 += s23 * 654183; 175 | s14 -= s23 * 997805; 176 | s15 += s23 * 136657; 177 | s16 -= s23 * 683901; 178 | s23 = 0; 179 | 180 | s10 += s22 * 666643; 181 | s11 += s22 * 470296; 182 | s12 += s22 * 654183; 183 | s13 -= s22 * 997805; 184 | s14 += s22 * 136657; 185 | s15 -= s22 * 683901; 186 | s22 = 0; 187 | 188 | s9 += s21 * 666643; 189 | s10 += s21 * 470296; 190 | s11 += s21 * 654183; 191 | s12 -= s21 * 997805; 192 | s13 += s21 * 136657; 193 | s14 -= s21 * 683901; 194 | s21 = 0; 195 | 196 | s8 += s20 * 666643; 197 | s9 += s20 * 470296; 198 | s10 += s20 * 654183; 199 | s11 -= s20 * 997805; 200 | s12 += s20 * 136657; 201 | s13 -= s20 * 683901; 202 | s20 = 0; 203 | 204 | s7 += s19 * 666643; 205 | s8 += s19 * 470296; 206 | s9 += s19 * 654183; 207 | s10 -= s19 * 997805; 208 | s11 += s19 * 136657; 209 | s12 -= s19 * 683901; 210 | s19 = 0; 211 | 212 | s6 += s18 * 666643; 213 | s7 += s18 * 470296; 214 | s8 += s18 * 654183; 215 | s9 -= s18 * 997805; 216 | s10 += s18 * 136657; 217 | s11 -= s18 * 683901; 218 | s18 = 0; 219 | 220 | carry6 = (s6 + (1<<20)) >> 21; s7 += carry6; s6 -= carry6 << 21; 221 | carry8 = (s8 + (1<<20)) >> 21; s9 += carry8; s8 -= carry8 << 21; 222 | carry10 = (s10 + (1<<20)) >> 21; s11 += carry10; s10 -= carry10 << 21; 223 | carry12 = (s12 + (1<<20)) >> 21; s13 += carry12; s12 -= carry12 << 21; 224 | carry14 = (s14 + (1<<20)) >> 21; s15 += carry14; s14 -= carry14 << 21; 225 | carry16 = (s16 + (1<<20)) >> 21; s17 += carry16; s16 -= carry16 << 21; 226 | 227 | carry7 = (s7 + (1<<20)) >> 21; s8 += carry7; s7 -= carry7 << 21; 228 | carry9 = (s9 + (1<<20)) >> 21; s10 += carry9; s9 -= carry9 << 21; 229 | carry11 = (s11 + (1<<20)) >> 21; s12 += carry11; s11 -= carry11 << 21; 230 | carry13 = (s13 + (1<<20)) >> 21; s14 += carry13; s13 -= carry13 << 21; 231 | carry15 = (s15 + (1<<20)) >> 21; s16 += carry15; s15 -= carry15 << 21; 232 | 233 | s5 += s17 * 666643; 234 | s6 += s17 * 470296; 235 | s7 += s17 * 654183; 236 | s8 -= s17 * 997805; 237 | s9 += s17 * 136657; 238 | s10 -= s17 * 683901; 239 | s17 = 0; 240 | 241 | s4 += s16 * 666643; 242 | s5 += s16 * 470296; 243 | s6 += s16 * 654183; 244 | s7 -= s16 * 997805; 245 | s8 += s16 * 136657; 246 | s9 -= s16 * 683901; 247 | s16 = 0; 248 | 249 | s3 += s15 * 666643; 250 | s4 += s15 * 470296; 251 | s5 += s15 * 654183; 252 | s6 -= s15 * 997805; 253 | s7 += s15 * 136657; 254 | s8 -= s15 * 683901; 255 | s15 = 0; 256 | 257 | s2 += s14 * 666643; 258 | s3 += s14 * 470296; 259 | s4 += s14 * 654183; 260 | s5 -= s14 * 997805; 261 | s6 += s14 * 136657; 262 | s7 -= s14 * 683901; 263 | s14 = 0; 264 | 265 | s1 += s13 * 666643; 266 | s2 += s13 * 470296; 267 | s3 += s13 * 654183; 268 | s4 -= s13 * 997805; 269 | s5 += s13 * 136657; 270 | s6 -= s13 * 683901; 271 | s13 = 0; 272 | 273 | s0 += s12 * 666643; 274 | s1 += s12 * 470296; 275 | s2 += s12 * 654183; 276 | s3 -= s12 * 997805; 277 | s4 += s12 * 136657; 278 | s5 -= s12 * 683901; 279 | s12 = 0; 280 | 281 | carry0 = (s0 + (1<<20)) >> 21; s1 += carry0; s0 -= carry0 << 21; 282 | carry2 = (s2 + (1<<20)) >> 21; s3 += carry2; s2 -= carry2 << 21; 283 | carry4 = (s4 + (1<<20)) >> 21; s5 += carry4; s4 -= carry4 << 21; 284 | carry6 = (s6 + (1<<20)) >> 21; s7 += carry6; s6 -= carry6 << 21; 285 | carry8 = (s8 + (1<<20)) >> 21; s9 += carry8; s8 -= carry8 << 21; 286 | carry10 = (s10 + (1<<20)) >> 21; s11 += carry10; s10 -= carry10 << 21; 287 | 288 | carry1 = (s1 + (1<<20)) >> 21; s2 += carry1; s1 -= carry1 << 21; 289 | carry3 = (s3 + (1<<20)) >> 21; s4 += carry3; s3 -= carry3 << 21; 290 | carry5 = (s5 + (1<<20)) >> 21; s6 += carry5; s5 -= carry5 << 21; 291 | carry7 = (s7 + (1<<20)) >> 21; s8 += carry7; s7 -= carry7 << 21; 292 | carry9 = (s9 + (1<<20)) >> 21; s10 += carry9; s9 -= carry9 << 21; 293 | carry11 = (s11 + (1<<20)) >> 21; s12 += carry11; s11 -= carry11 << 21; 294 | 295 | s0 += s12 * 666643; 296 | s1 += s12 * 470296; 297 | s2 += s12 * 654183; 298 | s3 -= s12 * 997805; 299 | s4 += s12 * 136657; 300 | s5 -= s12 * 683901; 301 | s12 = 0; 302 | 303 | carry0 = s0 >> 21; s1 += carry0; s0 -= carry0 << 21; 304 | carry1 = s1 >> 21; s2 += carry1; s1 -= carry1 << 21; 305 | carry2 = s2 >> 21; s3 += carry2; s2 -= carry2 << 21; 306 | carry3 = s3 >> 21; s4 += carry3; s3 -= carry3 << 21; 307 | carry4 = s4 >> 21; s5 += carry4; s4 -= carry4 << 21; 308 | carry5 = s5 >> 21; s6 += carry5; s5 -= carry5 << 21; 309 | carry6 = s6 >> 21; s7 += carry6; s6 -= carry6 << 21; 310 | carry7 = s7 >> 21; s8 += carry7; s7 -= carry7 << 21; 311 | carry8 = s8 >> 21; s9 += carry8; s8 -= carry8 << 21; 312 | carry9 = s9 >> 21; s10 += carry9; s9 -= carry9 << 21; 313 | carry10 = s10 >> 21; s11 += carry10; s10 -= carry10 << 21; 314 | carry11 = s11 >> 21; s12 += carry11; s11 -= carry11 << 21; 315 | 316 | s0 += s12 * 666643; 317 | s1 += s12 * 470296; 318 | s2 += s12 * 654183; 319 | s3 -= s12 * 997805; 320 | s4 += s12 * 136657; 321 | s5 -= s12 * 683901; 322 | s12 = 0; 323 | 324 | carry0 = s0 >> 21; s1 += carry0; s0 -= carry0 << 21; 325 | carry1 = s1 >> 21; s2 += carry1; s1 -= carry1 << 21; 326 | carry2 = s2 >> 21; s3 += carry2; s2 -= carry2 << 21; 327 | carry3 = s3 >> 21; s4 += carry3; s3 -= carry3 << 21; 328 | carry4 = s4 >> 21; s5 += carry4; s4 -= carry4 << 21; 329 | carry5 = s5 >> 21; s6 += carry5; s5 -= carry5 << 21; 330 | carry6 = s6 >> 21; s7 += carry6; s6 -= carry6 << 21; 331 | carry7 = s7 >> 21; s8 += carry7; s7 -= carry7 << 21; 332 | carry8 = s8 >> 21; s9 += carry8; s8 -= carry8 << 21; 333 | carry9 = s9 >> 21; s10 += carry9; s9 -= carry9 << 21; 334 | carry10 = s10 >> 21; s11 += carry10; s10 -= carry10 << 21; 335 | 336 | s[0] = s0 >> 0; 337 | s[1] = s0 >> 8; 338 | s[2] = (s0 >> 16) | (s1 << 5); 339 | s[3] = s1 >> 3; 340 | s[4] = s1 >> 11; 341 | s[5] = (s1 >> 19) | (s2 << 2); 342 | s[6] = s2 >> 6; 343 | s[7] = (s2 >> 14) | (s3 << 7); 344 | s[8] = s3 >> 1; 345 | s[9] = s3 >> 9; 346 | s[10] = (s3 >> 17) | (s4 << 4); 347 | s[11] = s4 >> 4; 348 | s[12] = s4 >> 12; 349 | s[13] = (s4 >> 20) | (s5 << 1); 350 | s[14] = s5 >> 7; 351 | s[15] = (s5 >> 15) | (s6 << 6); 352 | s[16] = s6 >> 2; 353 | s[17] = s6 >> 10; 354 | s[18] = (s6 >> 18) | (s7 << 3); 355 | s[19] = s7 >> 5; 356 | s[20] = s7 >> 13; 357 | s[21] = s8 >> 0; 358 | s[22] = s8 >> 8; 359 | s[23] = (s8 >> 16) | (s9 << 5); 360 | s[24] = s9 >> 3; 361 | s[25] = s9 >> 11; 362 | s[26] = (s9 >> 19) | (s10 << 2); 363 | s[27] = s10 >> 6; 364 | s[28] = (s10 >> 14) | (s11 << 7); 365 | s[29] = s11 >> 1; 366 | s[30] = s11 >> 9; 367 | s[31] = s11 >> 17; 368 | } 369 | -------------------------------------------------------------------------------- /native/ed25519/sc_reduce.c: -------------------------------------------------------------------------------- 1 | #include "sc.h" 2 | #include "crypto_int64.h" 3 | #include "crypto_uint32.h" 4 | #include "crypto_uint64.h" 5 | 6 | static crypto_uint64 load_3(const unsigned char *in) 7 | { 8 | crypto_uint64 result; 9 | result = (crypto_uint64) in[0]; 10 | result |= ((crypto_uint64) in[1]) << 8; 11 | result |= ((crypto_uint64) in[2]) << 16; 12 | return result; 13 | } 14 | 15 | static crypto_uint64 load_4(const unsigned char *in) 16 | { 17 | crypto_uint64 result; 18 | result = (crypto_uint64) in[0]; 19 | result |= ((crypto_uint64) in[1]) << 8; 20 | result |= ((crypto_uint64) in[2]) << 16; 21 | result |= ((crypto_uint64) in[3]) << 24; 22 | return result; 23 | } 24 | 25 | /* 26 | Input: 27 | s[0]+256*s[1]+...+256^63*s[63] = s 28 | 29 | Output: 30 | s[0]+256*s[1]+...+256^31*s[31] = s mod l 31 | where l = 2^252 + 27742317777372353535851937790883648493. 32 | Overwrites s in place. 33 | */ 34 | 35 | void sc_reduce(unsigned char *s) 36 | { 37 | crypto_int64 s0 = 2097151 & load_3(s); 38 | crypto_int64 s1 = 2097151 & (load_4(s + 2) >> 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/md_helper.c: -------------------------------------------------------------------------------- 1 | /* $Id: md_helper.c 216 2010-06-08 09:46:57Z tp $ */ 2 | /* 3 | * This file contains some functions which implement the external data 4 | * handling and padding for Merkle-Damgard hash functions which follow 5 | * the conventions set out by MD4 (little-endian) or SHA-1 (big-endian). 6 | * 7 | * API: this file is meant to be included, not compiled as a stand-alone 8 | * file. Some macros must be defined: 9 | * RFUN name for the round function 10 | * HASH "short name" for the hash function 11 | * BE32 defined for big-endian, 32-bit based (e.g. SHA-1) 12 | * LE32 defined for little-endian, 32-bit based (e.g. MD5) 13 | * BE64 defined for big-endian, 64-bit based (e.g. SHA-512) 14 | * LE64 defined for little-endian, 64-bit based (no example yet) 15 | * PW01 if defined, append 0x01 instead of 0x80 (for Tiger) 16 | * BLEN if defined, length of a message block (in bytes) 17 | * PLW1 if defined, length is defined on one 64-bit word only (for Tiger) 18 | * PLW4 if defined, length is defined on four 64-bit words (for WHIRLPOOL) 19 | * SVAL if defined, reference to the context state information 20 | * 21 | * BLEN is used when a message block is not 16 (32-bit or 64-bit) words: 22 | * this is used for instance for Tiger, which works on 64-bit words but 23 | * uses 512-bit message blocks (eight 64-bit words). PLW1 and PLW4 are 24 | * ignored if 32-bit words are used; if 64-bit words are used and PLW1 is 25 | * set, then only one word (64 bits) will be used to encode the input 26 | * message length (in bits), otherwise two words will be used (as in 27 | * SHA-384 and SHA-512). If 64-bit words are used and PLW4 is defined (but 28 | * not PLW1), four 64-bit words will be used to encode the message length 29 | * (in bits). Note that regardless of those settings, only 64-bit message 30 | * lengths are supported (in bits): messages longer than 2 Exabytes will be 31 | * improperly hashed (this is unlikely to happen soon: 2 Exabytes is about 32 | * 2 millions Terabytes, which is huge). 33 | * 34 | * If CLOSE_ONLY is defined, then this file defines only the sph_XXX_close() 35 | * function. This is used for Tiger2, which is identical to Tiger except 36 | * when it comes to the padding (Tiger2 uses the standard 0x80 byte instead 37 | * of the 0x01 from original Tiger). 38 | * 39 | * The RFUN function is invoked with two arguments, the first pointing to 40 | * aligned data (as a "const void *"), the second being state information 41 | * from the context structure. By default, this state information is the 42 | * "val" field from the context, and this field is assumed to be an array 43 | * of words ("sph_u32" or "sph_u64", depending on BE32/LE32/BE64/LE64). 44 | * from the context structure. The "val" field can have any type, except 45 | * for the output encoding which assumes that it is an array of "sph_u32" 46 | * values. By defining NO_OUTPUT, this last step is deactivated; the 47 | * includer code is then responsible for writing out the hash result. When 48 | * NO_OUTPUT is defined, the third parameter to the "close()" function is 49 | * ignored. 50 | * 51 | * ==========================(LICENSE BEGIN)============================ 52 | * 53 | * Copyright (c) 2007-2010 Projet RNRT SAPHIR 54 | * 55 | * Permission is hereby granted, free of charge, to any person obtaining 56 | * a copy of this software and associated documentation files (the 57 | * "Software"), to deal in the Software without restriction, including 58 | * without limitation the rights to use, copy, modify, merge, publish, 59 | * distribute, sublicense, and/or sell copies of the Software, and to 60 | * permit persons to whom the Software is furnished to do so, subject to 61 | * the following conditions: 62 | * 63 | * The above copyright notice and this permission notice shall be 64 | * included in all copies or substantial portions of the Software. 65 | * 66 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 67 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 68 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 69 | * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 70 | * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 71 | * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 72 | * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 73 | * 74 | * ===========================(LICENSE END)============================= 75 | * 76 | * @author Thomas Pornin 77 | */ 78 | 79 | #ifdef _MSC_VER 80 | #pragma warning (disable: 4146) 81 | #endif 82 | 83 | #undef SPH_XCAT 84 | #define SPH_XCAT(a, b) SPH_XCAT_(a, b) 85 | #undef SPH_XCAT_ 86 | #define SPH_XCAT_(a, b) a ## b 87 | 88 | #undef SPH_BLEN 89 | #undef SPH_WLEN 90 | #if defined BE64 || defined LE64 91 | #define SPH_BLEN 128U 92 | #define SPH_WLEN 8U 93 | #else 94 | #define SPH_BLEN 64U 95 | #define SPH_WLEN 4U 96 | #endif 97 | 98 | #ifdef BLEN 99 | #undef SPH_BLEN 100 | #define SPH_BLEN BLEN 101 | #endif 102 | 103 | #undef SPH_MAXPAD 104 | #if defined PLW1 105 | #define SPH_MAXPAD (SPH_BLEN - SPH_WLEN) 106 | #elif defined PLW4 107 | #define SPH_MAXPAD (SPH_BLEN - (SPH_WLEN << 2)) 108 | #else 109 | #define SPH_MAXPAD (SPH_BLEN - (SPH_WLEN << 1)) 110 | #endif 111 | 112 | #undef SPH_VAL 113 | #undef SPH_NO_OUTPUT 114 | #ifdef SVAL 115 | #define SPH_VAL SVAL 116 | #define SPH_NO_OUTPUT 1 117 | #else 118 | #define SPH_VAL sc->val 119 | #endif 120 | 121 | #ifndef CLOSE_ONLY 122 | 123 | #ifdef SPH_UPTR 124 | static void 125 | SPH_XCAT(HASH, _short)(void *cc, const void *data, size_t len) 126 | #else 127 | void 128 | SPH_XCAT(sph_, HASH)(void *cc, const void *data, size_t len) 129 | #endif 130 | { 131 | SPH_XCAT(sph_, SPH_XCAT(HASH, _context)) *sc; 132 | unsigned current; 133 | 134 | sc = cc; 135 | #if SPH_64 136 | current = (unsigned)sc->count & (SPH_BLEN - 1U); 137 | #else 138 | current = (unsigned)sc->count_low & (SPH_BLEN - 1U); 139 | #endif 140 | while (len > 0) { 141 | unsigned clen; 142 | #if !SPH_64 143 | sph_u32 clow, clow2; 144 | #endif 145 | 146 | clen = SPH_BLEN - current; 147 | if (clen > len) 148 | clen = len; 149 | memcpy(sc->buf + current, data, clen); 150 | data = (const unsigned char *)data + clen; 151 | current += clen; 152 | len -= clen; 153 | if (current == SPH_BLEN) { 154 | RFUN(sc->buf, SPH_VAL); 155 | current = 0; 156 | } 157 | #if SPH_64 158 | sc->count += clen; 159 | #else 160 | clow = sc->count_low; 161 | clow2 = SPH_T32(clow + clen); 162 | sc->count_low = clow2; 163 | if (clow2 < clow) 164 | sc->count_high ++; 165 | #endif 166 | } 167 | } 168 | 169 | #ifdef SPH_UPTR 170 | void 171 | SPH_XCAT(sph_, HASH)(void *cc, const void *data, size_t len) 172 | { 173 | SPH_XCAT(sph_, SPH_XCAT(HASH, _context)) *sc; 174 | unsigned current; 175 | size_t orig_len; 176 | #if !SPH_64 177 | sph_u32 clow, clow2; 178 | #endif 179 | 180 | if (len < (2 * SPH_BLEN)) { 181 | SPH_XCAT(HASH, _short)(cc, data, len); 182 | return; 183 | } 184 | sc = cc; 185 | #if SPH_64 186 | current = (unsigned)sc->count & (SPH_BLEN - 1U); 187 | #else 188 | current = (unsigned)sc->count_low & (SPH_BLEN - 1U); 189 | #endif 190 | if (current > 0) { 191 | unsigned t; 192 | 193 | t = SPH_BLEN - current; 194 | SPH_XCAT(HASH, _short)(cc, data, t); 195 | data = (const unsigned char *)data + t; 196 | len -= t; 197 | } 198 | #if !SPH_UNALIGNED 199 | if (((SPH_UPTR)data & (SPH_WLEN - 1U)) != 0) { 200 | SPH_XCAT(HASH, _short)(cc, data, len); 201 | return; 202 | } 203 | #endif 204 | orig_len = len; 205 | while (len >= SPH_BLEN) { 206 | RFUN(data, SPH_VAL); 207 | len -= SPH_BLEN; 208 | data = (const unsigned char *)data + SPH_BLEN; 209 | } 210 | if (len > 0) 211 | memcpy(sc->buf, data, len); 212 | #if SPH_64 213 | sc->count += (sph_u64)orig_len; 214 | #else 215 | clow = sc->count_low; 216 | clow2 = SPH_T32(clow + orig_len); 217 | sc->count_low = clow2; 218 | if (clow2 < clow) 219 | sc->count_high ++; 220 | /* 221 | * This code handles the improbable situation where "size_t" is 222 | * greater than 32 bits, and yet we do not have a 64-bit type. 223 | */ 224 | orig_len >>= 12; 225 | orig_len >>= 10; 226 | orig_len >>= 10; 227 | sc->count_high += orig_len; 228 | #endif 229 | } 230 | #endif 231 | 232 | #endif 233 | 234 | /* 235 | * Perform padding and produce result. The context is NOT reinitialized 236 | * by this function. 237 | */ 238 | static void 239 | SPH_XCAT(HASH, _addbits_and_close)(void *cc, 240 | unsigned ub, unsigned n, void *dst, unsigned rnum) 241 | { 242 | SPH_XCAT(sph_, SPH_XCAT(HASH, _context)) *sc; 243 | unsigned current, u; 244 | #if !SPH_64 245 | sph_u32 low, high; 246 | #endif 247 | 248 | sc = cc; 249 | #if SPH_64 250 | current = (unsigned)sc->count & (SPH_BLEN - 1U); 251 | #else 252 | current = (unsigned)sc->count_low & (SPH_BLEN - 1U); 253 | #endif 254 | #ifdef PW01 255 | sc->buf[current ++] = (0x100 | (ub & 0xFF)) >> (8 - n); 256 | #else 257 | { 258 | unsigned z; 259 | 260 | z = 0x80 >> n; 261 | sc->buf[current ++] = ((ub & -z) | z) & 0xFF; 262 | } 263 | #endif 264 | if (current > SPH_MAXPAD) { 265 | memset(sc->buf + current, 0, SPH_BLEN - current); 266 | RFUN(sc->buf, SPH_VAL); 267 | memset(sc->buf, 0, SPH_MAXPAD); 268 | } else { 269 | memset(sc->buf + current, 0, SPH_MAXPAD - current); 270 | } 271 | #if defined BE64 272 | #if defined PLW1 273 | sph_enc64be_aligned(sc->buf + SPH_MAXPAD, 274 | SPH_T64(sc->count << 3) + (sph_u64)n); 275 | #elif defined PLW4 276 | memset(sc->buf + SPH_MAXPAD, 0, 2 * SPH_WLEN); 277 | sph_enc64be_aligned(sc->buf + SPH_MAXPAD + 2 * SPH_WLEN, 278 | sc->count >> 61); 279 | sph_enc64be_aligned(sc->buf + SPH_MAXPAD + 3 * SPH_WLEN, 280 | SPH_T64(sc->count << 3) + (sph_u64)n); 281 | #else 282 | sph_enc64be_aligned(sc->buf + SPH_MAXPAD, sc->count >> 61); 283 | sph_enc64be_aligned(sc->buf + SPH_MAXPAD + SPH_WLEN, 284 | SPH_T64(sc->count << 3) + (sph_u64)n); 285 | #endif 286 | #elif defined LE64 287 | #if defined PLW1 288 | sph_enc64le_aligned(sc->buf + SPH_MAXPAD, 289 | SPH_T64(sc->count << 3) + (sph_u64)n); 290 | #elif defined PLW1 291 | sph_enc64le_aligned(sc->buf + SPH_MAXPAD, 292 | SPH_T64(sc->count << 3) + (sph_u64)n); 293 | sph_enc64le_aligned(sc->buf + SPH_MAXPAD + SPH_WLEN, sc->count >> 61); 294 | memset(sc->buf + SPH_MAXPAD + 2 * SPH_WLEN, 0, 2 * SPH_WLEN); 295 | #else 296 | sph_enc64le_aligned(sc->buf + SPH_MAXPAD, 297 | SPH_T64(sc->count << 3) + (sph_u64)n); 298 | sph_enc64le_aligned(sc->buf + SPH_MAXPAD + SPH_WLEN, sc->count >> 61); 299 | #endif 300 | #else 301 | #if SPH_64 302 | #ifdef BE32 303 | sph_enc64be_aligned(sc->buf + SPH_MAXPAD, 304 | SPH_T64(sc->count << 3) + (sph_u64)n); 305 | #else 306 | sph_enc64le_aligned(sc->buf + SPH_MAXPAD, 307 | SPH_T64(sc->count << 3) + (sph_u64)n); 308 | #endif 309 | #else 310 | low = sc->count_low; 311 | high = SPH_T32((sc->count_high << 3) | (low >> 29)); 312 | low = SPH_T32(low << 3) + (sph_u32)n; 313 | #ifdef BE32 314 | sph_enc32be(sc->buf + SPH_MAXPAD, high); 315 | sph_enc32be(sc->buf + SPH_MAXPAD + SPH_WLEN, low); 316 | #else 317 | sph_enc32le(sc->buf + SPH_MAXPAD, low); 318 | sph_enc32le(sc->buf + SPH_MAXPAD + SPH_WLEN, high); 319 | #endif 320 | #endif 321 | #endif 322 | RFUN(sc->buf, SPH_VAL); 323 | #ifdef SPH_NO_OUTPUT 324 | (void)dst; 325 | (void)rnum; 326 | (void)u; 327 | #else 328 | for (u = 0; u < rnum; u ++) { 329 | #if defined BE64 330 | sph_enc64be((unsigned char *)dst + 8 * u, sc->val[u]); 331 | #elif defined LE64 332 | sph_enc64le((unsigned char *)dst + 8 * u, sc->val[u]); 333 | #elif defined BE32 334 | sph_enc32be((unsigned char *)dst + 4 * u, sc->val[u]); 335 | #else 336 | sph_enc32le((unsigned char *)dst + 4 * u, sc->val[u]); 337 | #endif 338 | } 339 | #endif 340 | } 341 | 342 | static void 343 | SPH_XCAT(HASH, _close)(void *cc, void *dst, unsigned rnum) 344 | { 345 | SPH_XCAT(HASH, _addbits_and_close)(cc, 0, 0, dst, rnum); 346 | } 347 | -------------------------------------------------------------------------------- /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/sha512/sph_sha2.h: -------------------------------------------------------------------------------- 1 | /* $Id: sph_sha2.h 216 2010-06-08 09:46:57Z tp $ */ 2 | /** 3 | * SHA-224, SHA-256, SHA-384 and SHA-512 interface. 4 | * 5 | * SHA-256 has been published in FIPS 180-2, now amended with a change 6 | * notice to include SHA-224 as well (which is a simple variation on 7 | * SHA-256). SHA-384 and SHA-512 are also defined in FIPS 180-2. FIPS 8 | * standards can be found at: 9 | * http://csrc.nist.gov/publications/fips/ 10 | * 11 | * ==========================(LICENSE BEGIN)============================ 12 | * 13 | * Copyright (c) 2007-2010 Projet RNRT SAPHIR 14 | * 15 | * Permission is hereby granted, free of charge, to any person obtaining 16 | * a copy of this software and associated documentation files (the 17 | * "Software"), to deal in the Software without restriction, including 18 | * without limitation the rights to use, copy, modify, merge, publish, 19 | * distribute, sublicense, and/or sell copies of the Software, and to 20 | * permit persons to whom the Software is furnished to do so, subject to 21 | * the following conditions: 22 | * 23 | * The above copyright notice and this permission notice shall be 24 | * included in all copies or substantial portions of the Software. 25 | * 26 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 27 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 28 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 29 | * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 30 | * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 31 | * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 32 | * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 33 | * 34 | * ===========================(LICENSE END)============================= 35 | * 36 | * @file sph_sha2.h 37 | * @author Thomas Pornin 38 | */ 39 | 40 | #ifndef SPH_SHA2_H__ 41 | #define SPH_SHA2_H__ 42 | 43 | #include 44 | #include "sph_types.h" 45 | 46 | /** 47 | * Output size (in bits) for SHA-224. 48 | */ 49 | #define SPH_SIZE_sha224 224 50 | 51 | /** 52 | * Output size (in bits) for SHA-256. 53 | */ 54 | #define SPH_SIZE_sha256 256 55 | 56 | /** 57 | * This structure is a context for SHA-224 computations: it contains the 58 | * intermediate values and some data from the last entered block. Once 59 | * a SHA-224 computation has been performed, the context can be reused for 60 | * another computation. 61 | * 62 | * The contents of this structure are private. A running SHA-224 computation 63 | * can be cloned by copying the context (e.g. with a simple 64 | * memcpy()). 65 | */ 66 | typedef struct { 67 | #ifndef DOXYGEN_IGNORE 68 | unsigned char buf[64]; /* first field, for alignment */ 69 | sph_u32 val[8]; 70 | #if SPH_64 71 | sph_u64 count; 72 | #else 73 | sph_u32 count_high, count_low; 74 | #endif 75 | #endif 76 | } sph_sha224_context; 77 | 78 | /** 79 | * This structure is a context for SHA-256 computations. It is identical 80 | * to the SHA-224 context. However, a context is initialized for SHA-224 81 | * or SHA-256, but not both (the internal IV is not the 82 | * same). 83 | */ 84 | typedef sph_sha224_context sph_sha256_context; 85 | 86 | /** 87 | * Initialize a SHA-224 context. This process performs no memory allocation. 88 | * 89 | * @param cc the SHA-224 context (pointer to 90 | * a sph_sha224_context) 91 | */ 92 | void sph_sha224_init(void *cc); 93 | 94 | /** 95 | * Process some data bytes. It is acceptable that len is zero 96 | * (in which case this function does nothing). 97 | * 98 | * @param cc the SHA-224 context 99 | * @param data the input data 100 | * @param len the input data length (in bytes) 101 | */ 102 | void sph_sha224(void *cc, const void *data, size_t len); 103 | 104 | /** 105 | * Terminate the current SHA-224 computation and output the result into the 106 | * provided buffer. The destination buffer must be wide enough to 107 | * accomodate the result (28 bytes). The context is automatically 108 | * reinitialized. 109 | * 110 | * @param cc the SHA-224 context 111 | * @param dst the destination buffer 112 | */ 113 | void sph_sha224_close(void *cc, void *dst); 114 | 115 | /** 116 | * Add a few additional bits (0 to 7) to the current computation, then 117 | * terminate it and output the result in the provided buffer, which must 118 | * be wide enough to accomodate the result (28 bytes). If bit number i 119 | * in ub has value 2^i, then the extra bits are those 120 | * numbered 7 downto 8-n (this is the big-endian convention at the byte 121 | * level). The context is automatically reinitialized. 122 | * 123 | * @param cc the SHA-224 context 124 | * @param ub the extra bits 125 | * @param n the number of extra bits (0 to 7) 126 | * @param dst the destination buffer 127 | */ 128 | void sph_sha224_addbits_and_close(void *cc, unsigned ub, unsigned n, void *dst); 129 | 130 | /** 131 | * Apply the SHA-224 compression function on the provided data. The 132 | * msg parameter contains the 16 32-bit input blocks, 133 | * as numerical values (hence after the big-endian decoding). The 134 | * val parameter contains the 8 32-bit input blocks for 135 | * the compression function; the output is written in place in this 136 | * array. 137 | * 138 | * @param msg the message block (16 values) 139 | * @param val the function 256-bit input and output 140 | */ 141 | void sph_sha224_comp(const sph_u32 msg[16], sph_u32 val[8]); 142 | 143 | /** 144 | * Initialize a SHA-256 context. This process performs no memory allocation. 145 | * 146 | * @param cc the SHA-256 context (pointer to 147 | * a sph_sha256_context) 148 | */ 149 | void sph_sha256_init(void *cc); 150 | 151 | #ifdef DOXYGEN_IGNORE 152 | /** 153 | * Process some data bytes, for SHA-256. This function is identical to 154 | * sha_224() 155 | * 156 | * @param cc the SHA-224 context 157 | * @param data the input data 158 | * @param len the input data length (in bytes) 159 | */ 160 | void sph_sha256(void *cc, const void *data, size_t len); 161 | #endif 162 | 163 | #ifndef DOXYGEN_IGNORE 164 | #define sph_sha256 sph_sha224 165 | #endif 166 | 167 | /** 168 | * Terminate the current SHA-256 computation and output the result into the 169 | * provided buffer. The destination buffer must be wide enough to 170 | * accomodate the result (32 bytes). The context is automatically 171 | * reinitialized. 172 | * 173 | * @param cc the SHA-256 context 174 | * @param dst the destination buffer 175 | */ 176 | void sph_sha256_close(void *cc, void *dst); 177 | 178 | /** 179 | * Add a few additional bits (0 to 7) to the current computation, then 180 | * terminate it and output the result in the provided buffer, which must 181 | * be wide enough to accomodate the result (32 bytes). If bit number i 182 | * in ub has value 2^i, then the extra bits are those 183 | * numbered 7 downto 8-n (this is the big-endian convention at the byte 184 | * level). The context is automatically reinitialized. 185 | * 186 | * @param cc the SHA-256 context 187 | * @param ub the extra bits 188 | * @param n the number of extra bits (0 to 7) 189 | * @param dst the destination buffer 190 | */ 191 | void sph_sha256_addbits_and_close(void *cc, unsigned ub, unsigned n, void *dst); 192 | 193 | #ifdef DOXYGEN_IGNORE 194 | /** 195 | * Apply the SHA-256 compression function on the provided data. This 196 | * function is identical to sha224_comp(). 197 | * 198 | * @param msg the message block (16 values) 199 | * @param val the function 256-bit input and output 200 | */ 201 | void sph_sha256_comp(const sph_u32 msg[16], sph_u32 val[8]); 202 | #endif 203 | 204 | #ifndef DOXYGEN_IGNORE 205 | #define sph_sha256_comp sph_sha224_comp 206 | #endif 207 | 208 | #if SPH_64 209 | 210 | /** 211 | * Output size (in bits) for SHA-384. 212 | */ 213 | #define SPH_SIZE_sha384 384 214 | 215 | /** 216 | * Output size (in bits) for SHA-512. 217 | */ 218 | #define SPH_SIZE_sha512 512 219 | 220 | /** 221 | * This structure is a context for SHA-384 computations: it contains the 222 | * intermediate values and some data from the last entered block. Once 223 | * a SHA-384 computation has been performed, the context can be reused for 224 | * another computation. 225 | * 226 | * The contents of this structure are private. A running SHA-384 computation 227 | * can be cloned by copying the context (e.g. with a simple 228 | * memcpy()). 229 | */ 230 | typedef struct { 231 | #ifndef DOXYGEN_IGNORE 232 | unsigned char buf[128]; /* first field, for alignment */ 233 | sph_u64 val[8]; 234 | sph_u64 count; 235 | #endif 236 | } sph_sha384_context; 237 | 238 | /** 239 | * Initialize a SHA-384 context. This process performs no memory allocation. 240 | * 241 | * @param cc the SHA-384 context (pointer to 242 | * a sph_sha384_context) 243 | */ 244 | void sph_sha384_init(void *cc); 245 | 246 | /** 247 | * Process some data bytes. It is acceptable that len is zero 248 | * (in which case this function does nothing). 249 | * 250 | * @param cc the SHA-384 context 251 | * @param data the input data 252 | * @param len the input data length (in bytes) 253 | */ 254 | void sph_sha384(void *cc, const void *data, size_t len); 255 | 256 | /** 257 | * Terminate the current SHA-384 computation and output the result into the 258 | * provided buffer. The destination buffer must be wide enough to 259 | * accomodate the result (48 bytes). The context is automatically 260 | * reinitialized. 261 | * 262 | * @param cc the SHA-384 context 263 | * @param dst the destination buffer 264 | */ 265 | void sph_sha384_close(void *cc, void *dst); 266 | 267 | /** 268 | * Add a few additional bits (0 to 7) to the current computation, then 269 | * terminate it and output the result in the provided buffer, which must 270 | * be wide enough to accomodate the result (48 bytes). If bit number i 271 | * in ub has value 2^i, then the extra bits are those 272 | * numbered 7 downto 8-n (this is the big-endian convention at the byte 273 | * level). The context is automatically reinitialized. 274 | * 275 | * @param cc the SHA-384 context 276 | * @param ub the extra bits 277 | * @param n the number of extra bits (0 to 7) 278 | * @param dst the destination buffer 279 | */ 280 | void sph_sha384_addbits_and_close(void *cc, unsigned ub, unsigned n, void *dst); 281 | 282 | /** 283 | * Apply the SHA-384 compression function on the provided data. The 284 | * msg parameter contains the 16 64-bit input blocks, 285 | * as numerical values (hence after the big-endian decoding). The 286 | * val parameter contains the 8 64-bit input blocks for 287 | * the compression function; the output is written in place in this 288 | * array. 289 | * 290 | * @param msg the message block (16 values) 291 | * @param val the function 512-bit input and output 292 | */ 293 | void sph_sha384_comp(const sph_u64 msg[16], sph_u64 val[8]); 294 | 295 | /** 296 | * This structure is a context for SHA-512 computations. It is identical 297 | * to the SHA-384 context. However, a context is initialized for SHA-384 298 | * or SHA-512, but not both (the internal IV is not the 299 | * same). 300 | */ 301 | typedef sph_sha384_context sph_sha512_context; 302 | 303 | /** 304 | * Initialize a SHA-512 context. This process performs no memory allocation. 305 | * 306 | * @param cc the SHA-512 context (pointer to 307 | * a sph_sha512_context) 308 | */ 309 | void sph_sha512_init(void *cc); 310 | 311 | #ifdef DOXYGEN_IGNORE 312 | /** 313 | * Process some data bytes, for SHA-512. This function is identical to 314 | * sph_sha384(). 315 | * 316 | * @param cc the SHA-384 context 317 | * @param data the input data 318 | * @param len the input data length (in bytes) 319 | */ 320 | void sph_sha512(void *cc, const void *data, size_t len); 321 | #endif 322 | 323 | #ifndef DOXYGEN_IGNORE 324 | #define sph_sha512 sph_sha384 325 | #endif 326 | 327 | /** 328 | * Terminate the current SHA-512 computation and output the result into the 329 | * provided buffer. The destination buffer must be wide enough to 330 | * accomodate the result (64 bytes). The context is automatically 331 | * reinitialized. 332 | * 333 | * @param cc the SHA-512 context 334 | * @param dst the destination buffer 335 | */ 336 | void sph_sha512_close(void *cc, void *dst); 337 | 338 | /** 339 | * Add a few additional bits (0 to 7) to the current computation, then 340 | * terminate it and output the result in the provided buffer, which must 341 | * be wide enough to accomodate the result (64 bytes). If bit number i 342 | * in ub has value 2^i, then the extra bits are those 343 | * numbered 7 downto 8-n (this is the big-endian convention at the byte 344 | * level). The context is automatically reinitialized. 345 | * 346 | * @param cc the SHA-512 context 347 | * @param ub the extra bits 348 | * @param n the number of extra bits (0 to 7) 349 | * @param dst the destination buffer 350 | */ 351 | void sph_sha512_addbits_and_close(void *cc, unsigned ub, unsigned n, void *dst); 352 | 353 | #ifdef DOXYGEN_IGNORE 354 | /** 355 | * Apply the SHA-512 compression function. This function is identical to 356 | * sph_sha384_comp(). 357 | * 358 | * @param msg the message block (16 values) 359 | * @param val the function 512-bit input and output 360 | */ 361 | void sph_sha512_comp(const sph_u64 msg[16], sph_u64 val[8]); 362 | #endif 363 | 364 | #ifndef DOXYGEN_IGNORE 365 | #define sph_sha512_comp sph_sha384_comp 366 | #endif 367 | 368 | #endif 369 | 370 | #endif 371 | -------------------------------------------------------------------------------- /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": "libsignal", 3 | "version": "2.0.1", 4 | "description": "Open Whisper Systems' libsignal for Node.js", 5 | "repository": "ForstaLabs/libsignal-node", 6 | "keywords": [ 7 | "signal", 8 | "whispersystems", 9 | "crypto" 10 | ], 11 | "license": "GPL-3.0", 12 | "dependencies": { 13 | "protobufjs": "6.8.8" 14 | }, 15 | "devDependencies": { 16 | "eslint": "6.0.1", 17 | "grunt": "1.0.4", 18 | "grunt-cli": "1.2.0" 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /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/.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "parserOptions": { 3 | "ecmaVersion": 8 4 | }, 5 | "env": { 6 | "es6": true, 7 | "node": true 8 | }, 9 | "extends": "eslint:recommended", 10 | "rules": { 11 | "quotes": "off", 12 | "semi": [ 13 | "error", 14 | "always" 15 | ], 16 | "no-console": "off", 17 | "no-debugger": "off", 18 | "no-unused-vars": [ 19 | "error", 20 | { 21 | "args": "none" 22 | } 23 | ], 24 | "no-constant-condition": [ 25 | "error", 26 | { 27 | "checkLoops": false 28 | } 29 | ] 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/base_key_type.js: -------------------------------------------------------------------------------- 1 | 2 | const BaseKeyType = { 3 | OURS: 1, 4 | THEIRS: 2 5 | }; 6 | 7 | module.exports = BaseKeyType; 8 | -------------------------------------------------------------------------------- /src/chain_type.js: -------------------------------------------------------------------------------- 1 | const ChainType = { 2 | SENDING: 1, 3 | RECEIVING: 2 4 | }; 5 | 6 | module.exports = ChainType; 7 | -------------------------------------------------------------------------------- /src/crypto.js: -------------------------------------------------------------------------------- 1 | // vim: ts=4:sw=4 2 | 3 | 'use strict'; 4 | 5 | const nodeCrypto = require('crypto'); 6 | const assert = require('assert'); 7 | 8 | 9 | function assertBuffer(value) { 10 | if (!(value instanceof Buffer)) { 11 | throw TypeError(`Expected Buffer instead of: ${value.constructor.name}`); 12 | } 13 | return value; 14 | } 15 | 16 | 17 | function encrypt(key, data, iv) { 18 | assertBuffer(key); 19 | assertBuffer(data); 20 | assertBuffer(iv); 21 | const cipher = nodeCrypto.createCipheriv('aes-256-cbc', key, iv); 22 | return Buffer.concat([cipher.update(data), cipher.final()]); 23 | } 24 | 25 | 26 | function decrypt(key, data, iv) { 27 | assertBuffer(key); 28 | assertBuffer(data); 29 | assertBuffer(iv); 30 | const decipher = nodeCrypto.createDecipheriv('aes-256-cbc', key, iv); 31 | return Buffer.concat([decipher.update(data), decipher.final()]); 32 | } 33 | 34 | 35 | function calculateMAC(key, data) { 36 | assertBuffer(key); 37 | assertBuffer(data); 38 | const hmac = nodeCrypto.createHmac('sha256', key); 39 | hmac.update(data); 40 | return Buffer.from(hmac.digest()); 41 | } 42 | 43 | 44 | function hash(data) { 45 | assertBuffer(data); 46 | const sha512 = nodeCrypto.createHash('sha512'); 47 | sha512.update(data); 48 | return sha512.digest(); 49 | } 50 | 51 | 52 | // Salts always end up being 32 bytes 53 | function deriveSecrets(input, salt, info, chunks) { 54 | // Specific implementation of RFC 5869 that only returns the first 3 32-byte chunks 55 | assertBuffer(input); 56 | assertBuffer(salt); 57 | assertBuffer(info); 58 | if (salt.byteLength != 32) { 59 | throw new Error("Got salt of incorrect length"); 60 | } 61 | chunks = chunks || 3; 62 | assert(chunks >= 1 && chunks <= 3); 63 | const PRK = calculateMAC(salt, input); 64 | const infoArray = new Uint8Array(info.byteLength + 1 + 32); 65 | infoArray.set(info, 32); 66 | infoArray[infoArray.length - 1] = 1; 67 | const signed = [calculateMAC(PRK, Buffer.from(infoArray.slice(32)))]; 68 | if (chunks > 1) { 69 | infoArray.set(signed[signed.length - 1]); 70 | infoArray[infoArray.length - 1] = 2; 71 | signed.push(calculateMAC(PRK, Buffer.from(infoArray))); 72 | } 73 | if (chunks > 2) { 74 | infoArray.set(signed[signed.length - 1]); 75 | infoArray[infoArray.length - 1] = 3; 76 | signed.push(calculateMAC(PRK, Buffer.from(infoArray))); 77 | } 78 | return signed; 79 | } 80 | 81 | function verifyMAC(data, key, mac, length) { 82 | const calculatedMac = calculateMAC(key, data).slice(0, length); 83 | if (mac.length !== length || calculatedMac.length !== length) { 84 | throw new Error("Bad MAC length"); 85 | } 86 | if (!mac.equals(calculatedMac)) { 87 | throw new Error("Bad MAC"); 88 | } 89 | } 90 | 91 | module.exports = { 92 | deriveSecrets, 93 | decrypt, 94 | encrypt, 95 | hash, 96 | calculateMAC, 97 | verifyMAC 98 | }; 99 | -------------------------------------------------------------------------------- /src/curve.js: -------------------------------------------------------------------------------- 1 | 2 | 'use strict'; 3 | 4 | const curve25519 = require('../src/curve25519_wrapper'); 5 | const nodeCrypto = require('crypto'); 6 | 7 | 8 | function validatePrivKey(privKey) { 9 | if (privKey === undefined) { 10 | throw new Error("Undefined private key"); 11 | } 12 | if (!(privKey instanceof Buffer)) { 13 | throw new Error(`Invalid private key type: ${privKey.constructor.name}`); 14 | } 15 | if (privKey.byteLength != 32) { 16 | throw new Error(`Incorrect private key length: ${privKey.byteLength}`); 17 | } 18 | } 19 | 20 | function scrubPubKeyFormat(pubKey) { 21 | if (!(pubKey instanceof Buffer)) { 22 | throw new Error(`Invalid public key type: ${pubKey.constructor.name}`); 23 | } 24 | if (pubKey === undefined || ((pubKey.byteLength != 33 || pubKey[0] != 5) && pubKey.byteLength != 32)) { 25 | throw new Error("Invalid public key"); 26 | } 27 | if (pubKey.byteLength == 33) { 28 | return pubKey.slice(1); 29 | } else { 30 | console.error("WARNING: Expected pubkey of length 33, please report the ST and client that generated the pubkey"); 31 | return pubKey; 32 | } 33 | } 34 | 35 | exports.createKeyPair = function(privKey) { 36 | validatePrivKey(privKey); 37 | const keys = curve25519.keyPair(privKey); 38 | // prepend version byte 39 | var origPub = new Uint8Array(keys.pubKey); 40 | var pub = new Uint8Array(33); 41 | pub.set(origPub, 1); 42 | pub[0] = 5; 43 | return { 44 | pubKey: Buffer.from(pub), 45 | privKey: Buffer.from(keys.privKey) 46 | }; 47 | }; 48 | 49 | exports.calculateAgreement = function(pubKey, privKey) { 50 | pubKey = scrubPubKeyFormat(pubKey); 51 | validatePrivKey(privKey); 52 | if (!pubKey || pubKey.byteLength != 32) { 53 | throw new Error("Invalid public key"); 54 | } 55 | return Buffer.from(curve25519.sharedSecret(pubKey, privKey)); 56 | }; 57 | 58 | exports.calculateSignature = function(privKey, message) { 59 | validatePrivKey(privKey); 60 | if (!message) { 61 | throw new Error("Invalid message"); 62 | } 63 | return Buffer.from(curve25519.sign(privKey, message)); 64 | }; 65 | 66 | exports.verifySignature = function(pubKey, msg, sig) { 67 | pubKey = scrubPubKeyFormat(pubKey); 68 | if (!pubKey || pubKey.byteLength != 32) { 69 | throw new Error("Invalid public key"); 70 | } 71 | if (!msg) { 72 | throw new Error("Invalid message"); 73 | } 74 | if (!sig || sig.byteLength != 64) { 75 | throw new Error("Invalid signature"); 76 | } 77 | return curve25519.verify(pubKey, msg, sig); 78 | }; 79 | 80 | exports.generateKeyPair = function() { 81 | const privKey = nodeCrypto.randomBytes(32); 82 | return exports.createKeyPair(privKey); 83 | }; 84 | -------------------------------------------------------------------------------- /src/curve25519_wrapper.js: -------------------------------------------------------------------------------- 1 | // vim: ts=4:sw=4:expandtab 2 | 3 | // Remove the dubious emscripten callback that invokes process.exit(1) on any 4 | // unhandledRejection event. 5 | let _exitCallback; 6 | const captureExitCallback = (ev, callback) => { 7 | if (ev === 'unhandledRejection') { 8 | _exitCallback = callback; // Must remove outside emit context. 9 | process.removeListener(ev, callback); 10 | } 11 | }; 12 | process.addListener('newListener', captureExitCallback); 13 | const curve25519 = require('../build/curve25519'); 14 | process.removeListener('newListener', captureExitCallback); 15 | process.removeListener('unhandledRejection', _exitCallback); 16 | 17 | // Insert some bytes into the emscripten memory and return a pointer 18 | function _allocate(bytes) { 19 | const address = curve25519._malloc(bytes.length); 20 | curve25519.HEAPU8.set(bytes, address); 21 | 22 | return address; 23 | } 24 | 25 | function _readBytes(address, length, array) { 26 | array.set(curve25519.HEAPU8.subarray(address, address + length)); 27 | } 28 | 29 | const basepoint = new Uint8Array(32); 30 | basepoint[0] = 9; 31 | 32 | exports.keyPair = function(privKey) { 33 | const priv = new Uint8Array(privKey); 34 | priv[0] &= 248; 35 | priv[31] &= 127; 36 | priv[31] |= 64; 37 | 38 | // Where to store the result 39 | const publicKey_ptr = curve25519._malloc(32); 40 | 41 | // Get a pointer to the private key 42 | const privateKey_ptr = _allocate(priv); 43 | 44 | // The basepoint for generating public keys 45 | const basepoint_ptr = _allocate(basepoint); 46 | 47 | // The return value is just 0, the operation is done in place 48 | curve25519._curve25519_donna(publicKey_ptr, privateKey_ptr, basepoint_ptr); 49 | 50 | const res = new Uint8Array(32); 51 | _readBytes(publicKey_ptr, 32, res); 52 | 53 | curve25519._free(publicKey_ptr); 54 | curve25519._free(privateKey_ptr); 55 | curve25519._free(basepoint_ptr); 56 | 57 | return { 58 | pubKey: res.buffer, 59 | privKey: priv.buffer 60 | }; 61 | }; 62 | 63 | exports.sharedSecret = function(pubKey, privKey) { 64 | // Where to store the result 65 | const sharedKey_ptr = curve25519._malloc(32); 66 | 67 | // Get a pointer to our private key 68 | const privateKey_ptr = _allocate(new Uint8Array(privKey)); 69 | 70 | // Get a pointer to their public key, the basepoint when you're 71 | // generating a shared secret 72 | const basepoint_ptr = _allocate(new Uint8Array(pubKey)); 73 | 74 | // Return value is 0 here too of course 75 | curve25519._curve25519_donna(sharedKey_ptr, privateKey_ptr, basepoint_ptr); 76 | 77 | const res = new Uint8Array(32); 78 | _readBytes(sharedKey_ptr, 32, res); 79 | 80 | curve25519._free(sharedKey_ptr); 81 | curve25519._free(privateKey_ptr); 82 | curve25519._free(basepoint_ptr); 83 | 84 | return res.buffer; 85 | }; 86 | 87 | exports.sign = function(privKey, message) { 88 | // Where to store the result 89 | const signature_ptr = curve25519._malloc(64); 90 | 91 | // Get a pointer to our private key 92 | const privateKey_ptr = _allocate(new Uint8Array(privKey)); 93 | 94 | // Get a pointer to the message 95 | const message_ptr = _allocate(new Uint8Array(message)); 96 | 97 | curve25519._curve25519_sign(signature_ptr, privateKey_ptr, message_ptr, 98 | message.byteLength); 99 | 100 | const res = new Uint8Array(64); 101 | _readBytes(signature_ptr, 64, res); 102 | 103 | curve25519._free(signature_ptr); 104 | curve25519._free(privateKey_ptr); 105 | curve25519._free(message_ptr); 106 | 107 | return res.buffer; 108 | }; 109 | 110 | exports.verify = function(pubKey, message, sig) { 111 | // Get a pointer to their public key 112 | const publicKey_ptr = _allocate(new Uint8Array(pubKey)); 113 | 114 | // Get a pointer to the signature 115 | const signature_ptr = _allocate(new Uint8Array(sig)); 116 | 117 | // Get a pointer to the message 118 | const message_ptr = _allocate(new Uint8Array(message)); 119 | 120 | const res = curve25519._curve25519_verify(signature_ptr, publicKey_ptr, message_ptr, 121 | message.byteLength); 122 | 123 | curve25519._free(publicKey_ptr); 124 | curve25519._free(signature_ptr); 125 | curve25519._free(message_ptr); 126 | 127 | if (res !== 0) { 128 | throw new Error("Invalid signature"); 129 | } 130 | }; 131 | -------------------------------------------------------------------------------- /src/errors.js: -------------------------------------------------------------------------------- 1 | // vim: ts=4:sw=4:expandtab 2 | 3 | exports.SignalError = class SignalError extends Error {}; 4 | 5 | exports.UntrustedIdentityKeyError = class UntrustedIdentityKeyError extends exports.SignalError { 6 | constructor(addr, identityKey) { 7 | super(); 8 | this.name = 'UntrustedIdentityKeyError'; 9 | this.addr = addr; 10 | this.identityKey = identityKey; 11 | } 12 | }; 13 | 14 | exports.SessionError = class SessionError extends exports.SignalError { 15 | constructor(message) { 16 | super(message); 17 | this.name = 'SessionError'; 18 | } 19 | }; 20 | 21 | exports.MessageCounterError = class MessageCounterError extends exports.SessionError { 22 | constructor(message) { 23 | super(message); 24 | this.name = 'MessageCounterError'; 25 | } 26 | }; 27 | 28 | exports.PreKeyError = class PreKeyError extends exports.SessionError { 29 | constructor(message) { 30 | super(message); 31 | this.name = 'PreKeyError'; 32 | } 33 | }; 34 | -------------------------------------------------------------------------------- /src/keyhelper.js: -------------------------------------------------------------------------------- 1 | // vim: ts=4:sw=4:expandtab 2 | 3 | const curve = require('./curve'); 4 | const nodeCrypto = require('crypto'); 5 | 6 | function isNonNegativeInteger(n) { 7 | return (typeof n === 'number' && (n % 1) === 0 && n >= 0); 8 | } 9 | 10 | exports.generateIdentityKeyPair = curve.generateKeyPair; 11 | 12 | exports.generateRegistrationId = function() { 13 | var registrationId = Uint16Array.from(nodeCrypto.randomBytes(2))[0]; 14 | return registrationId & 0x3fff; 15 | }; 16 | 17 | exports.generateSignedPreKey = function(identityKeyPair, signedKeyId) { 18 | if (!(identityKeyPair.privKey instanceof Buffer) || 19 | identityKeyPair.privKey.byteLength != 32 || 20 | !(identityKeyPair.pubKey instanceof Buffer) || 21 | identityKeyPair.pubKey.byteLength != 33) { 22 | throw new TypeError('Invalid argument for identityKeyPair'); 23 | } 24 | if (!isNonNegativeInteger(signedKeyId)) { 25 | throw new TypeError('Invalid argument for signedKeyId: ' + signedKeyId); 26 | } 27 | const keyPair = curve.generateKeyPair(); 28 | const sig = curve.calculateSignature(identityKeyPair.privKey, keyPair.pubKey); 29 | return { 30 | keyId: signedKeyId, 31 | keyPair: keyPair, 32 | signature: sig 33 | }; 34 | }; 35 | 36 | exports.generatePreKey = function(keyId) { 37 | if (!isNonNegativeInteger(keyId)) { 38 | throw new TypeError('Invalid argument for keyId: ' + keyId); 39 | } 40 | const keyPair = curve.generateKeyPair(); 41 | return { 42 | keyId, 43 | keyPair 44 | }; 45 | }; 46 | -------------------------------------------------------------------------------- /src/numeric_fingerprint.js: -------------------------------------------------------------------------------- 1 | 2 | const crypto = require('./crypto.js'); 3 | 4 | var VERSION = 0; 5 | 6 | 7 | async function iterateHash(data, key, count) { 8 | const combined = (new Uint8Array(Buffer.concat([data, key]))).buffer; 9 | const result = crypto.hash(combined); 10 | if (--count === 0) { 11 | return result; 12 | } else { 13 | return iterateHash(result, key, count); 14 | } 15 | } 16 | 17 | 18 | function shortToArrayBuffer(number) { 19 | return new Uint16Array([number]).buffer; 20 | } 21 | 22 | function getEncodedChunk(hash, offset) { 23 | var chunk = ( hash[offset] * Math.pow(2,32) + 24 | hash[offset+1] * Math.pow(2,24) + 25 | hash[offset+2] * Math.pow(2,16) + 26 | hash[offset+3] * Math.pow(2,8) + 27 | hash[offset+4] ) % 100000; 28 | var s = chunk.toString(); 29 | while (s.length < 5) { 30 | s = '0' + s; 31 | } 32 | return s; 33 | } 34 | 35 | async function getDisplayStringFor(identifier, key, iterations) { 36 | const bytes = Buffer.concat([ 37 | shortToArrayBuffer(VERSION), 38 | key, 39 | identifier 40 | ]); 41 | const arraybuf = (new Uint8Array(bytes)).buffer; 42 | const output = new Uint8Array(await iterateHash(arraybuf, key, iterations)); 43 | return getEncodedChunk(output, 0) + 44 | getEncodedChunk(output, 5) + 45 | getEncodedChunk(output, 10) + 46 | getEncodedChunk(output, 15) + 47 | getEncodedChunk(output, 20) + 48 | getEncodedChunk(output, 25); 49 | } 50 | 51 | exports.FingerprintGenerator = function(iterations) { 52 | this.iterations = iterations; 53 | }; 54 | 55 | exports.FingerprintGenerator.prototype = { 56 | createFor: function(localIdentifier, localIdentityKey, 57 | remoteIdentifier, remoteIdentityKey) { 58 | if (typeof localIdentifier !== 'string' || 59 | typeof remoteIdentifier !== 'string' || 60 | !(localIdentityKey instanceof ArrayBuffer) || 61 | !(remoteIdentityKey instanceof ArrayBuffer)) { 62 | throw new Error('Invalid arguments'); 63 | } 64 | 65 | return Promise.all([ 66 | getDisplayStringFor(localIdentifier, localIdentityKey, this.iterations), 67 | getDisplayStringFor(remoteIdentifier, remoteIdentityKey, this.iterations) 68 | ]).then(function(fingerprints) { 69 | return fingerprints.sort().join(''); 70 | }); 71 | } 72 | }; 73 | -------------------------------------------------------------------------------- /src/protobufs.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const path = require('path'); 4 | const protobuf = require('protobufjs'); 5 | 6 | const protodir = path.resolve(__dirname, '../protos/'); 7 | const p = protobuf.loadSync(path.join(protodir, 'WhisperTextProtocol.proto')).lookup('textsecure'); 8 | 9 | module.exports = { 10 | WhisperMessage: p.lookup('WhisperMessage'), 11 | PreKeyWhisperMessage: p.lookup('PreKeyWhisperMessage') 12 | }; 13 | -------------------------------------------------------------------------------- /src/protocol_address.js: -------------------------------------------------------------------------------- 1 | // vim: ts=4:sw=4:expandtab 2 | 3 | 4 | class ProtocolAddress { 5 | 6 | static from(encodedAddress) { 7 | if (typeof encodedAddress !== 'string' || !encodedAddress.match(/.*\.\d+/)) { 8 | throw new Error('Invalid address encoding'); 9 | } 10 | const parts = encodedAddress.split('.'); 11 | return new this(parts[0], parseInt(parts[1])); 12 | } 13 | 14 | constructor(id, deviceId) { 15 | if (typeof id !== 'string') { 16 | throw new TypeError('id required for addr'); 17 | } 18 | if (id.indexOf('.') !== -1) { 19 | throw new TypeError('encoded addr detected'); 20 | } 21 | this.id = id; 22 | if (typeof deviceId !== 'number') { 23 | throw new TypeError('number required for deviceId'); 24 | } 25 | this.deviceId = deviceId; 26 | } 27 | 28 | toString() { 29 | return `${this.id}.${this.deviceId}`; 30 | } 31 | 32 | is(other) { 33 | if (!(other instanceof ProtocolAddress)) { 34 | return false; 35 | } 36 | return other.id === this.id && other.deviceId === this.deviceId; 37 | } 38 | } 39 | 40 | module.exports = ProtocolAddress; 41 | -------------------------------------------------------------------------------- /src/queue_job.js: -------------------------------------------------------------------------------- 1 | // vim: ts=4:sw=4:expandtab 2 | 3 | /* 4 | * jobQueue manages multiple queues indexed by device to serialize 5 | * session io ops on the database. 6 | */ 7 | 'use strict'; 8 | 9 | 10 | const _queueAsyncBuckets = new Map(); 11 | const _gcLimit = 10000; 12 | 13 | async function _asyncQueueExecutor(queue, cleanup) { 14 | let offt = 0; 15 | while (true) { 16 | let limit = Math.min(queue.length, _gcLimit); // Break up thundering hurds for GC duty. 17 | for (let i = offt; i < limit; i++) { 18 | const job = queue[i]; 19 | try { 20 | job.resolve(await job.awaitable()); 21 | } catch(e) { 22 | job.reject(e); 23 | } 24 | } 25 | if (limit < queue.length) { 26 | /* Perform lazy GC of queue for faster iteration. */ 27 | if (limit >= _gcLimit) { 28 | queue.splice(0, limit); 29 | offt = 0; 30 | } else { 31 | offt = limit; 32 | } 33 | } else { 34 | break; 35 | } 36 | } 37 | cleanup(); 38 | } 39 | 40 | module.exports = function(bucket, awaitable) { 41 | /* Run the async awaitable only when all other async calls registered 42 | * here have completed (or thrown). The bucket argument is a hashable 43 | * key representing the task queue to use. */ 44 | if (!awaitable.name) { 45 | // Make debuging easier by adding a name to this function. 46 | Object.defineProperty(awaitable, 'name', {writable: true}); 47 | if (typeof bucket === 'string') { 48 | awaitable.name = bucket; 49 | } else { 50 | console.warn("Unhandled bucket type (for naming):", typeof bucket, bucket); 51 | } 52 | } 53 | let inactive; 54 | if (!_queueAsyncBuckets.has(bucket)) { 55 | _queueAsyncBuckets.set(bucket, []); 56 | inactive = true; 57 | } 58 | const queue = _queueAsyncBuckets.get(bucket); 59 | const job = new Promise((resolve, reject) => queue.push({ 60 | awaitable, 61 | resolve, 62 | reject 63 | })); 64 | if (inactive) { 65 | /* An executor is not currently active; Start one now. */ 66 | _asyncQueueExecutor(queue, () => _queueAsyncBuckets.delete(bucket)); 67 | } 68 | return job; 69 | }; 70 | -------------------------------------------------------------------------------- /src/session_builder.js: -------------------------------------------------------------------------------- 1 | 2 | 'use strict'; 3 | 4 | const BaseKeyType = require('./base_key_type'); 5 | const ChainType = require('./chain_type'); 6 | const SessionRecord = require('./session_record'); 7 | const crypto = require('./crypto'); 8 | const curve = require('./curve'); 9 | const errors = require('./errors'); 10 | const queueJob = require('./queue_job'); 11 | 12 | 13 | class SessionBuilder { 14 | 15 | constructor(storage, protocolAddress) { 16 | this.addr = protocolAddress; 17 | this.storage = storage; 18 | } 19 | 20 | async initOutgoing(device) { 21 | const fqAddr = this.addr.toString(); 22 | return await queueJob(fqAddr, async () => { 23 | if (!await this.storage.isTrustedIdentity(this.addr.id, device.identityKey)) { 24 | throw new errors.UntrustedIdentityKeyError(this.addr.id, device.identityKey); 25 | } 26 | curve.verifySignature(device.identityKey, device.signedPreKey.publicKey, 27 | device.signedPreKey.signature); 28 | const baseKey = curve.generateKeyPair(); 29 | const devicePreKey = device.preKey && device.preKey.publicKey; 30 | const session = await this.initSession(true, baseKey, undefined, device.identityKey, 31 | devicePreKey, device.signedPreKey.publicKey, 32 | device.registrationId); 33 | session.pendingPreKey = { 34 | signedKeyId: device.signedPreKey.keyId, 35 | baseKey: baseKey.pubKey 36 | }; 37 | if (device.preKey) { 38 | session.pendingPreKey.preKeyId = device.preKey.keyId; 39 | } 40 | let record = await this.storage.loadSession(fqAddr); 41 | if (!record) { 42 | record = new SessionRecord(); 43 | } else { 44 | const openSession = record.getOpenSession(); 45 | if (openSession) { 46 | console.warn("Closing stale open session for new outgoing prekey bundle"); 47 | record.closeSession(openSession); 48 | } 49 | } 50 | record.setSession(session); 51 | await this.storage.storeSession(fqAddr, record); 52 | }); 53 | } 54 | 55 | async initIncoming(record, message) { 56 | const fqAddr = this.addr.toString(); 57 | if (!await this.storage.isTrustedIdentity(fqAddr, message.identityKey)) { 58 | throw new errors.UntrustedIdentityKeyError(this.addr.id, message.identityKey); 59 | } 60 | if (record.getSession(message.baseKey)) { 61 | // This just means we haven't replied. 62 | return; 63 | } 64 | const preKeyPair = await this.storage.loadPreKey(message.preKeyId); 65 | if (message.preKeyId && !preKeyPair) { 66 | throw new errors.PreKeyError('Invalid PreKey ID'); 67 | } 68 | const signedPreKeyPair = await this.storage.loadSignedPreKey(message.signedPreKeyId); 69 | if (!signedPreKeyPair) { 70 | throw new errors.PreKeyError("Missing SignedPreKey"); 71 | } 72 | const existingOpenSession = record.getOpenSession(); 73 | if (existingOpenSession) { 74 | console.warn("Closing open session in favor of incoming prekey bundle"); 75 | record.closeSession(existingOpenSession); 76 | } 77 | record.setSession(await this.initSession(false, preKeyPair, signedPreKeyPair, 78 | message.identityKey, message.baseKey, 79 | undefined, message.registrationId)); 80 | return message.preKeyId; 81 | } 82 | 83 | async initSession(isInitiator, ourEphemeralKey, ourSignedKey, theirIdentityPubKey, 84 | theirEphemeralPubKey, theirSignedPubKey, registrationId) { 85 | if (isInitiator) { 86 | if (ourSignedKey) { 87 | throw new Error("Invalid call to initSession"); 88 | } 89 | ourSignedKey = ourEphemeralKey; 90 | } else { 91 | if (theirSignedPubKey) { 92 | throw new Error("Invalid call to initSession"); 93 | } 94 | theirSignedPubKey = theirEphemeralPubKey; 95 | } 96 | let sharedSecret; 97 | if (!ourEphemeralKey || !theirEphemeralPubKey) { 98 | sharedSecret = new Uint8Array(32 * 4); 99 | } else { 100 | sharedSecret = new Uint8Array(32 * 5); 101 | } 102 | for (var i = 0; i < 32; i++) { 103 | sharedSecret[i] = 0xff; 104 | } 105 | const ourIdentityKey = await this.storage.getOurIdentity(); 106 | const a1 = curve.calculateAgreement(theirSignedPubKey, ourIdentityKey.privKey); 107 | const a2 = curve.calculateAgreement(theirIdentityPubKey, ourSignedKey.privKey); 108 | const a3 = curve.calculateAgreement(theirSignedPubKey, ourSignedKey.privKey); 109 | if (isInitiator) { 110 | sharedSecret.set(new Uint8Array(a1), 32); 111 | sharedSecret.set(new Uint8Array(a2), 32 * 2); 112 | } else { 113 | sharedSecret.set(new Uint8Array(a1), 32 * 2); 114 | sharedSecret.set(new Uint8Array(a2), 32); 115 | } 116 | sharedSecret.set(new Uint8Array(a3), 32 * 3); 117 | if (ourEphemeralKey && theirEphemeralPubKey) { 118 | const a4 = curve.calculateAgreement(theirEphemeralPubKey, ourEphemeralKey.privKey); 119 | sharedSecret.set(new Uint8Array(a4), 32 * 4); 120 | } 121 | const masterKey = crypto.deriveSecrets(Buffer.from(sharedSecret), Buffer.alloc(32), 122 | Buffer.from("WhisperText")); 123 | const session = SessionRecord.createEntry(); 124 | session.registrationId = registrationId; 125 | session.currentRatchet = { 126 | rootKey: masterKey[0], 127 | ephemeralKeyPair: isInitiator ? curve.generateKeyPair() : ourSignedKey, 128 | lastRemoteEphemeralKey: theirSignedPubKey, 129 | previousCounter: 0 130 | }; 131 | session.indexInfo = { 132 | created: Date.now(), 133 | used: Date.now(), 134 | remoteIdentityKey: theirIdentityPubKey, 135 | baseKey: isInitiator ? ourEphemeralKey.pubKey : theirEphemeralPubKey, 136 | baseKeyType: isInitiator ? BaseKeyType.OURS : BaseKeyType.THEIRS, 137 | closed: -1 138 | }; 139 | if (isInitiator) { 140 | // If we're initiating we go ahead and set our first sending ephemeral key now, 141 | // otherwise we figure it out when we first maybeStepRatchet with the remote's 142 | // ephemeral key 143 | this.calculateSendingRatchet(session, theirSignedPubKey); 144 | } 145 | return session; 146 | } 147 | 148 | calculateSendingRatchet(session, remoteKey) { 149 | const ratchet = session.currentRatchet; 150 | const sharedSecret = curve.calculateAgreement(remoteKey, ratchet.ephemeralKeyPair.privKey); 151 | const masterKey = crypto.deriveSecrets(sharedSecret, ratchet.rootKey, Buffer.from("WhisperRatchet")); 152 | session.addChain(ratchet.ephemeralKeyPair.pubKey, { 153 | messageKeys: {}, 154 | chainKey: { 155 | counter: -1, 156 | key: masterKey[1] 157 | }, 158 | chainType: ChainType.SENDING 159 | }); 160 | ratchet.rootKey = masterKey[0]; 161 | } 162 | } 163 | 164 | module.exports = SessionBuilder; 165 | -------------------------------------------------------------------------------- /src/session_cipher.js: -------------------------------------------------------------------------------- 1 | // vim: ts=4:sw=4:expandtab 2 | 3 | const ChainType = require('./chain_type'); 4 | const ProtocolAddress = require('./protocol_address'); 5 | const SessionBuilder = require('./session_builder'); 6 | const SessionRecord = require('./session_record'); 7 | const crypto = require('./crypto'); 8 | const curve = require('./curve'); 9 | const errors = require('./errors'); 10 | const protobufs = require('./protobufs'); 11 | const queueJob = require('./queue_job'); 12 | 13 | const VERSION = 3; 14 | 15 | function assertBuffer(value) { 16 | if (!(value instanceof Buffer)) { 17 | throw TypeError(`Expected Buffer instead of: ${value.constructor.name}`); 18 | } 19 | return value; 20 | } 21 | 22 | 23 | class SessionCipher { 24 | 25 | constructor(storage, protocolAddress) { 26 | if (!(protocolAddress instanceof ProtocolAddress)) { 27 | throw new TypeError("protocolAddress must be a ProtocolAddress"); 28 | } 29 | this.addr = protocolAddress; 30 | this.storage = storage; 31 | } 32 | 33 | _encodeTupleByte(number1, number2) { 34 | if (number1 > 15 || number2 > 15) { 35 | throw TypeError("Numbers must be 4 bits or less"); 36 | } 37 | return (number1 << 4) | number2; 38 | } 39 | 40 | _decodeTupleByte(byte) { 41 | return [byte >> 4, byte & 0xf]; 42 | } 43 | 44 | toString() { 45 | return ``; 46 | } 47 | 48 | async getRecord() { 49 | const record = await this.storage.loadSession(this.addr.toString()); 50 | if (record && !(record instanceof SessionRecord)) { 51 | throw new TypeError('SessionRecord type expected from loadSession'); 52 | } 53 | return record; 54 | } 55 | 56 | async storeRecord(record) { 57 | record.removeOldSessions(); 58 | await this.storage.storeSession(this.addr.toString(), record); 59 | } 60 | 61 | async queueJob(awaitable) { 62 | return await queueJob(this.addr.toString(), awaitable); 63 | } 64 | 65 | async encrypt(data) { 66 | assertBuffer(data); 67 | const ourIdentityKey = await this.storage.getOurIdentity(); 68 | return await this.queueJob(async () => { 69 | const record = await this.getRecord(); 70 | if (!record) { 71 | throw new errors.SessionError("No sessions"); 72 | } 73 | const session = record.getOpenSession(); 74 | if (!session) { 75 | throw new errors.SessionError("No open session"); 76 | } 77 | const remoteIdentityKey = session.indexInfo.remoteIdentityKey; 78 | if (!await this.storage.isTrustedIdentity(this.addr.id, remoteIdentityKey)) { 79 | throw new errors.UntrustedIdentityKeyError(this.addr.id, remoteIdentityKey); 80 | } 81 | const chain = session.getChain(session.currentRatchet.ephemeralKeyPair.pubKey); 82 | if (chain.chainType === ChainType.RECEIVING) { 83 | throw new Error("Tried to encrypt on a receiving chain"); 84 | } 85 | this.fillMessageKeys(chain, chain.chainKey.counter + 1); 86 | const keys = crypto.deriveSecrets(chain.messageKeys[chain.chainKey.counter], 87 | Buffer.alloc(32), Buffer.from("WhisperMessageKeys")); 88 | delete chain.messageKeys[chain.chainKey.counter]; 89 | const msg = protobufs.WhisperMessage.create(); 90 | msg.ephemeralKey = session.currentRatchet.ephemeralKeyPair.pubKey; 91 | msg.counter = chain.chainKey.counter; 92 | msg.previousCounter = session.currentRatchet.previousCounter; 93 | msg.ciphertext = crypto.encrypt(keys[0], data, keys[2].slice(0, 16)); 94 | const msgBuf = protobufs.WhisperMessage.encode(msg).finish(); 95 | const macInput = new Buffer(msgBuf.byteLength + (33 * 2) + 1); 96 | macInput.set(ourIdentityKey.pubKey); 97 | macInput.set(session.indexInfo.remoteIdentityKey, 33); 98 | macInput[33 * 2] = this._encodeTupleByte(VERSION, VERSION); 99 | macInput.set(msgBuf, (33 * 2) + 1); 100 | const mac = crypto.calculateMAC(keys[1], macInput); 101 | const result = new Buffer(msgBuf.byteLength + 9); 102 | result[0] = this._encodeTupleByte(VERSION, VERSION); 103 | result.set(msgBuf, 1); 104 | result.set(mac.slice(0, 8), msgBuf.byteLength + 1); 105 | await this.storeRecord(record); 106 | let type, body; 107 | if (session.pendingPreKey) { 108 | type = 3; // prekey bundle 109 | const preKeyMsg = protobufs.PreKeyWhisperMessage.create({ 110 | identityKey: ourIdentityKey.pubKey, 111 | registrationId: await this.storage.getOurRegistrationId(), 112 | baseKey: session.pendingPreKey.baseKey, 113 | signedPreKeyId: session.pendingPreKey.signedKeyId, 114 | message: result 115 | }); 116 | if (session.pendingPreKey.preKeyId) { 117 | preKeyMsg.preKeyId = session.pendingPreKey.preKeyId; 118 | } 119 | body = Buffer.concat([ 120 | Buffer.from([this._encodeTupleByte(VERSION, VERSION)]), 121 | protobufs.PreKeyWhisperMessage.encode(preKeyMsg).finish() 122 | ]); 123 | } else { 124 | type = 1; // normal 125 | body = result; 126 | } 127 | return { 128 | type, 129 | body, 130 | registrationId: session.registrationId 131 | }; 132 | }); 133 | } 134 | 135 | async decryptWithSessions(data, sessions) { 136 | // Iterate through the sessions, attempting to decrypt using each one. 137 | // Stop and return the result if we get a valid result. 138 | if (!sessions.length) { 139 | throw new errors.SessionError("No sessions available"); 140 | } 141 | const errs = []; 142 | for (const session of sessions) { 143 | let plaintext; 144 | try { 145 | plaintext = await this.doDecryptWhisperMessage(data, session); 146 | session.indexInfo.used = Date.now(); 147 | return { 148 | session, 149 | plaintext 150 | }; 151 | } catch(e) { 152 | errs.push(e); 153 | } 154 | } 155 | console.error("Failed to decrypt message with any known session..."); 156 | for (const e of errs) { 157 | console.error("Session error:" + e, e.stack); 158 | } 159 | throw new errors.SessionError("No matching sessions found for message"); 160 | } 161 | 162 | async decryptWhisperMessage(data) { 163 | assertBuffer(data); 164 | return await this.queueJob(async () => { 165 | const record = await this.getRecord(); 166 | if (!record) { 167 | throw new errors.SessionError("No session record"); 168 | } 169 | const result = await this.decryptWithSessions(data, record.getSessions()); 170 | const remoteIdentityKey = result.session.indexInfo.remoteIdentityKey; 171 | if (!await this.storage.isTrustedIdentity(this.addr.id, remoteIdentityKey)) { 172 | throw new errors.UntrustedIdentityKeyError(this.addr.id, remoteIdentityKey); 173 | } 174 | if (record.isClosed(result.session)) { 175 | // It's possible for this to happen when processing a backlog of messages. 176 | // The message was, hopefully, just sent back in a time when this session 177 | // was the most current. Simply make a note of it and continue. If our 178 | // actual open session is for reason invalid, that must be handled via 179 | // a full SessionError response. 180 | console.warn("Decrypted message with closed session."); 181 | } 182 | await this.storeRecord(record); 183 | return result.plaintext; 184 | }); 185 | } 186 | 187 | async decryptPreKeyWhisperMessage(data) { 188 | assertBuffer(data); 189 | const versions = this._decodeTupleByte(data[0]); 190 | if (versions[1] > 3 || versions[0] < 3) { // min version > 3 or max version < 3 191 | throw new Error("Incompatible version number on PreKeyWhisperMessage"); 192 | } 193 | return await this.queueJob(async () => { 194 | let record = await this.getRecord(); 195 | const preKeyProto = protobufs.PreKeyWhisperMessage.decode(data.slice(1)); 196 | if (!record) { 197 | if (preKeyProto.registrationId == null) { 198 | throw new Error("No registrationId"); 199 | } 200 | record = new SessionRecord(); 201 | } 202 | const builder = new SessionBuilder(this.storage, this.addr); 203 | const preKeyId = await builder.initIncoming(record, preKeyProto); 204 | const session = record.getSession(preKeyProto.baseKey); 205 | const plaintext = await this.doDecryptWhisperMessage(preKeyProto.message, session); 206 | await this.storeRecord(record); 207 | if (preKeyId) { 208 | await this.storage.removePreKey(preKeyId); 209 | } 210 | return plaintext; 211 | }); 212 | } 213 | 214 | async doDecryptWhisperMessage(messageBuffer, session) { 215 | assertBuffer(messageBuffer); 216 | if (!session) { 217 | throw new TypeError("session required"); 218 | } 219 | const versions = this._decodeTupleByte(messageBuffer[0]); 220 | if (versions[1] > 3 || versions[0] < 3) { // min version > 3 or max version < 3 221 | throw new Error("Incompatible version number on WhisperMessage"); 222 | } 223 | const messageProto = messageBuffer.slice(1, -8); 224 | const message = protobufs.WhisperMessage.decode(messageProto); 225 | this.maybeStepRatchet(session, message.ephemeralKey, message.previousCounter); 226 | const chain = session.getChain(message.ephemeralKey); 227 | if (chain.chainType === ChainType.SENDING) { 228 | throw new Error("Tried to decrypt on a sending chain"); 229 | } 230 | this.fillMessageKeys(chain, message.counter); 231 | if (!chain.messageKeys.hasOwnProperty(message.counter)) { 232 | // Most likely the message was already decrypted and we are trying to process 233 | // twice. This can happen if the user restarts before the server gets an ACK. 234 | throw new errors.MessageCounterError('Key used already or never filled'); 235 | } 236 | const messageKey = chain.messageKeys[message.counter]; 237 | delete chain.messageKeys[message.counter]; 238 | const keys = crypto.deriveSecrets(messageKey, Buffer.alloc(32), 239 | Buffer.from("WhisperMessageKeys")); 240 | const ourIdentityKey = await this.storage.getOurIdentity(); 241 | const macInput = new Buffer(messageProto.byteLength + (33 * 2) + 1); 242 | macInput.set(session.indexInfo.remoteIdentityKey); 243 | macInput.set(ourIdentityKey.pubKey, 33); 244 | macInput[33 * 2] = this._encodeTupleByte(VERSION, VERSION); 245 | macInput.set(messageProto, (33 * 2) + 1); 246 | // This is where we most likely fail if the session is not a match. 247 | // Don't misinterpret this as corruption. 248 | crypto.verifyMAC(macInput, keys[1], messageBuffer.slice(-8), 8); 249 | const plaintext = crypto.decrypt(keys[0], message.ciphertext, keys[2].slice(0, 16)); 250 | delete session.pendingPreKey; 251 | return plaintext; 252 | } 253 | 254 | fillMessageKeys(chain, counter) { 255 | if (chain.chainKey.counter >= counter) { 256 | return; 257 | } 258 | if (counter - chain.chainKey.counter > 2000) { 259 | throw new errors.SessionError('Over 2000 messages into the future!'); 260 | } 261 | if (chain.chainKey.key === undefined) { 262 | throw new errors.SessionError('Chain closed'); 263 | } 264 | const key = chain.chainKey.key; 265 | chain.messageKeys[chain.chainKey.counter + 1] = crypto.calculateMAC(key, Buffer.from([1])); 266 | chain.chainKey.key = crypto.calculateMAC(key, Buffer.from([2])); 267 | chain.chainKey.counter += 1; 268 | return this.fillMessageKeys(chain, counter); 269 | } 270 | 271 | maybeStepRatchet(session, remoteKey, previousCounter) { 272 | if (session.getChain(remoteKey)) { 273 | return; 274 | } 275 | const ratchet = session.currentRatchet; 276 | let previousRatchet = session.getChain(ratchet.lastRemoteEphemeralKey); 277 | if (previousRatchet) { 278 | this.fillMessageKeys(previousRatchet, previousCounter); 279 | delete previousRatchet.chainKey.key; // Close 280 | } 281 | this.calculateRatchet(session, remoteKey, false); 282 | // Now swap the ephemeral key and calculate the new sending chain 283 | const prevCounter = session.getChain(ratchet.ephemeralKeyPair.pubKey); 284 | if (prevCounter) { 285 | ratchet.previousCounter = prevCounter.chainKey.counter; 286 | session.deleteChain(ratchet.ephemeralKeyPair.pubKey); 287 | } 288 | ratchet.ephemeralKeyPair = curve.generateKeyPair(); 289 | this.calculateRatchet(session, remoteKey, true); 290 | ratchet.lastRemoteEphemeralKey = remoteKey; 291 | } 292 | 293 | calculateRatchet(session, remoteKey, sending) { 294 | let ratchet = session.currentRatchet; 295 | const sharedSecret = curve.calculateAgreement(remoteKey, ratchet.ephemeralKeyPair.privKey); 296 | const masterKey = crypto.deriveSecrets(sharedSecret, ratchet.rootKey, 297 | Buffer.from("WhisperRatchet"), /*chunks*/ 2); 298 | const chainKey = sending ? ratchet.ephemeralKeyPair.pubKey : remoteKey; 299 | session.addChain(chainKey, { 300 | messageKeys: {}, 301 | chainKey: { 302 | counter: -1, 303 | key: masterKey[1] 304 | }, 305 | chainType: sending ? ChainType.SENDING : ChainType.RECEIVING 306 | }); 307 | ratchet.rootKey = masterKey[0]; 308 | } 309 | 310 | async hasOpenSession() { 311 | return await this.queueJob(async () => { 312 | const record = await this.getRecord(); 313 | if (!record) { 314 | return false; 315 | } 316 | return record.haveOpenSession(); 317 | }); 318 | } 319 | 320 | async closeOpenSession() { 321 | return await this.queueJob(async () => { 322 | const record = await this.getRecord(); 323 | if (record) { 324 | const openSession = record.getOpenSession(); 325 | if (openSession) { 326 | record.closeSession(openSession); 327 | await this.storeRecord(record); 328 | } 329 | } 330 | }); 331 | } 332 | } 333 | 334 | module.exports = SessionCipher; 335 | -------------------------------------------------------------------------------- /src/session_record.js: -------------------------------------------------------------------------------- 1 | // vim: ts=4:sw=4 2 | 3 | const BaseKeyType = require('./base_key_type'); 4 | 5 | const CLOSED_SESSIONS_MAX = 40; 6 | const SESSION_RECORD_VERSION = 'v1'; 7 | 8 | function assertBuffer(value) { 9 | if (!Buffer.isBuffer(value)) { 10 | throw new TypeError("Buffer required"); 11 | } 12 | } 13 | 14 | 15 | class SessionEntry { 16 | 17 | constructor() { 18 | this._chains = {}; 19 | } 20 | 21 | toString() { 22 | const baseKey = this.indexInfo && this.indexInfo.baseKey && 23 | this.indexInfo.baseKey.toString('base64'); 24 | return ``; 25 | } 26 | 27 | inspect() { 28 | return this.toString(); 29 | } 30 | 31 | addChain(key, value) { 32 | assertBuffer(key); 33 | const id = key.toString('base64'); 34 | if (this._chains.hasOwnProperty(id)) { 35 | throw new Error("Overwrite attempt"); 36 | } 37 | this._chains[id] = value; 38 | } 39 | 40 | getChain(key) { 41 | assertBuffer(key); 42 | return this._chains[key.toString('base64')]; 43 | } 44 | 45 | deleteChain(key) { 46 | assertBuffer(key); 47 | const id = key.toString('base64'); 48 | if (!this._chains.hasOwnProperty(id)) { 49 | throw new ReferenceError("Not Found"); 50 | } 51 | delete this._chains[id]; 52 | } 53 | 54 | *chains() { 55 | for (const [k, v] of Object.entries(this._chains)) { 56 | yield [Buffer.from(k, 'base64'), v]; 57 | } 58 | } 59 | 60 | serialize() { 61 | const data = { 62 | registrationId: this.registrationId, 63 | currentRatchet: { 64 | ephemeralKeyPair: { 65 | pubKey: this.currentRatchet.ephemeralKeyPair.pubKey.toString('base64'), 66 | privKey: this.currentRatchet.ephemeralKeyPair.privKey.toString('base64') 67 | }, 68 | lastRemoteEphemeralKey: this.currentRatchet.lastRemoteEphemeralKey.toString('base64'), 69 | previousCounter: this.currentRatchet.previousCounter, 70 | rootKey: this.currentRatchet.rootKey.toString('base64') 71 | }, 72 | indexInfo: { 73 | baseKey: this.indexInfo.baseKey.toString('base64'), 74 | baseKeyType: this.indexInfo.baseKeyType, 75 | closed: this.indexInfo.closed, 76 | used: this.indexInfo.used, 77 | created: this.indexInfo.created, 78 | remoteIdentityKey: this.indexInfo.remoteIdentityKey.toString('base64') 79 | }, 80 | _chains: this._serialize_chains(this._chains) 81 | }; 82 | if (this.pendingPreKey) { 83 | data.pendingPreKey = Object.assign({}, this.pendingPreKey); 84 | data.pendingPreKey.baseKey = this.pendingPreKey.baseKey.toString('base64'); 85 | } 86 | return data; 87 | } 88 | 89 | static deserialize(data) { 90 | const obj = new this(); 91 | obj.registrationId = data.registrationId; 92 | obj.currentRatchet = { 93 | ephemeralKeyPair: { 94 | pubKey: Buffer.from(data.currentRatchet.ephemeralKeyPair.pubKey, 'base64'), 95 | privKey: Buffer.from(data.currentRatchet.ephemeralKeyPair.privKey, 'base64') 96 | }, 97 | lastRemoteEphemeralKey: Buffer.from(data.currentRatchet.lastRemoteEphemeralKey, 'base64'), 98 | previousCounter: data.currentRatchet.previousCounter, 99 | rootKey: Buffer.from(data.currentRatchet.rootKey, 'base64') 100 | }; 101 | obj.indexInfo = { 102 | baseKey: Buffer.from(data.indexInfo.baseKey, 'base64'), 103 | baseKeyType: data.indexInfo.baseKeyType, 104 | closed: data.indexInfo.closed, 105 | used: data.indexInfo.used, 106 | created: data.indexInfo.created, 107 | remoteIdentityKey: Buffer.from(data.indexInfo.remoteIdentityKey, 'base64') 108 | }; 109 | obj._chains = this._deserialize_chains(data._chains); 110 | if (data.pendingPreKey) { 111 | obj.pendingPreKey = Object.assign({}, data.pendingPreKey); 112 | obj.pendingPreKey.baseKey = Buffer.from(data.pendingPreKey.baseKey, 'base64'); 113 | } 114 | return obj; 115 | } 116 | 117 | _serialize_chains(chains) { 118 | const r = {}; 119 | for (const key of Object.keys(chains)) { 120 | const c = chains[key]; 121 | const messageKeys = {}; 122 | for (const [idx, key] of Object.entries(c.messageKeys)) { 123 | messageKeys[idx] = key.toString('base64'); 124 | } 125 | r[key] = { 126 | chainKey: { 127 | counter: c.chainKey.counter, 128 | key: c.chainKey.key && c.chainKey.key.toString('base64') 129 | }, 130 | chainType: c.chainType, 131 | messageKeys: messageKeys 132 | }; 133 | } 134 | return r; 135 | } 136 | 137 | static _deserialize_chains(chains_data) { 138 | const r = {}; 139 | for (const key of Object.keys(chains_data)) { 140 | const c = chains_data[key]; 141 | const messageKeys = {}; 142 | for (const [idx, key] of Object.entries(c.messageKeys)) { 143 | messageKeys[idx] = Buffer.from(key, 'base64'); 144 | } 145 | r[key] = { 146 | chainKey: { 147 | counter: c.chainKey.counter, 148 | key: c.chainKey.key && Buffer.from(c.chainKey.key, 'base64') 149 | }, 150 | chainType: c.chainType, 151 | messageKeys: messageKeys 152 | }; 153 | } 154 | return r; 155 | } 156 | 157 | } 158 | 159 | 160 | const migrations = [{ 161 | version: 'v1', 162 | migrate: function migrateV1(data) { 163 | const sessions = data._sessions; 164 | if (data.registrationId) { 165 | for (const key in sessions) { 166 | if (!sessions[key].registrationId) { 167 | sessions[key].registrationId = data.registrationId; 168 | } 169 | } 170 | } else { 171 | for (const key in sessions) { 172 | if (sessions[key].indexInfo.closed === -1) { 173 | console.error('V1 session storage migration error: registrationId', 174 | data.registrationId, 'for open session version', 175 | data.version); 176 | } 177 | } 178 | } 179 | } 180 | }]; 181 | 182 | 183 | class SessionRecord { 184 | 185 | static createEntry() { 186 | return new SessionEntry(); 187 | } 188 | 189 | static migrate(data) { 190 | let run = (data.version === undefined); 191 | for (let i = 0; i < migrations.length; ++i) { 192 | if (run) { 193 | console.info("Migrating session to:", migrations[i].version); 194 | migrations[i].migrate(data); 195 | } else if (migrations[i].version === data.version) { 196 | run = true; 197 | } 198 | } 199 | if (!run) { 200 | throw new Error("Error migrating SessionRecord"); 201 | } 202 | } 203 | 204 | static deserialize(data) { 205 | if (data.version !== SESSION_RECORD_VERSION) { 206 | this.migrate(data); 207 | } 208 | const obj = new this(); 209 | if (data._sessions) { 210 | for (const [key, entry] of Object.entries(data._sessions)) { 211 | obj.sessions[key] = SessionEntry.deserialize(entry); 212 | } 213 | } 214 | return obj; 215 | } 216 | 217 | constructor() { 218 | this.sessions = {}; 219 | this.version = SESSION_RECORD_VERSION; 220 | } 221 | 222 | serialize() { 223 | const _sessions = {}; 224 | for (const [key, entry] of Object.entries(this.sessions)) { 225 | _sessions[key] = entry.serialize(); 226 | } 227 | return { 228 | _sessions, 229 | version: this.version 230 | }; 231 | } 232 | 233 | haveOpenSession() { 234 | const openSession = this.getOpenSession(); 235 | return (!!openSession && typeof openSession.registrationId === 'number'); 236 | } 237 | 238 | getSession(key) { 239 | assertBuffer(key); 240 | const session = this.sessions[key.toString('base64')]; 241 | if (session && session.indexInfo.baseKeyType === BaseKeyType.OURS) { 242 | throw new Error("Tried to lookup a session using our basekey"); 243 | } 244 | return session; 245 | } 246 | 247 | getOpenSession() { 248 | for (const session of Object.values(this.sessions)) { 249 | if (!this.isClosed(session)) { 250 | return session; 251 | } 252 | } 253 | } 254 | 255 | setSession(session) { 256 | this.sessions[session.indexInfo.baseKey.toString('base64')] = session; 257 | } 258 | 259 | getSessions() { 260 | // Return sessions ordered with most recently used first. 261 | return Array.from(Object.values(this.sessions)).sort((a, b) => { 262 | const aUsed = a.indexInfo.used || 0; 263 | const bUsed = b.indexInfo.used || 0; 264 | return aUsed === bUsed ? 0 : aUsed < bUsed ? 1 : -1; 265 | }); 266 | } 267 | 268 | closeSession(session) { 269 | if (this.isClosed(session)) { 270 | console.warn("Session already closed", session); 271 | return; 272 | } 273 | console.info("Closing session:", session); 274 | session.indexInfo.closed = Date.now(); 275 | } 276 | 277 | openSession(session) { 278 | if (!this.isClosed(session)) { 279 | console.warn("Session already open"); 280 | } 281 | console.info("Opening session:", session); 282 | session.indexInfo.closed = -1; 283 | } 284 | 285 | isClosed(session) { 286 | return session.indexInfo.closed !== -1; 287 | } 288 | 289 | removeOldSessions() { 290 | while (Object.keys(this.sessions).length > CLOSED_SESSIONS_MAX) { 291 | let oldestKey; 292 | let oldestSession; 293 | for (const [key, session] of Object.entries(this.sessions)) { 294 | if (session.indexInfo.closed !== -1 && 295 | (!oldestSession || session.indexInfo.closed < oldestSession.indexInfo.closed)) { 296 | oldestKey = key; 297 | oldestSession = session; 298 | } 299 | } 300 | if (oldestKey) { 301 | console.info("Removing old closed session:", oldestSession); 302 | delete this.sessions[oldestKey]; 303 | } else { 304 | throw new Error('Corrupt sessions object'); 305 | } 306 | } 307 | } 308 | 309 | deleteAllSessions() { 310 | for (const key of Object.keys(this.sessions)) { 311 | delete this.sessions[key]; 312 | } 313 | } 314 | } 315 | 316 | module.exports = SessionRecord; 317 | --------------------------------------------------------------------------------