aboutsummaryrefslogtreecommitdiff
path: root/src/crypto
diff options
context:
space:
mode:
Diffstat (limited to 'src/crypto')
-rw-r--r--src/crypto/primitives/kdf.ts92
-rw-r--r--src/crypto/primitives/nacl-fast.ts1941
-rw-r--r--src/crypto/primitives/sha256.ts426
-rw-r--r--src/crypto/talerCrypto-test.ts197
-rw-r--r--src/crypto/talerCrypto.ts376
-rw-r--r--src/crypto/workers/browserWorkerEntry.ts74
-rw-r--r--src/crypto/workers/cryptoApi.ts467
-rw-r--r--src/crypto/workers/cryptoImplementation.ts581
-rw-r--r--src/crypto/workers/cryptoWorker.ts8
-rw-r--r--src/crypto/workers/nodeThreadWorker.ts183
-rw-r--r--src/crypto/workers/synchronousWorker.ts137
11 files changed, 0 insertions, 4482 deletions
diff --git a/src/crypto/primitives/kdf.ts b/src/crypto/primitives/kdf.ts
deleted file mode 100644
index edc681bc1..000000000
--- a/src/crypto/primitives/kdf.ts
+++ /dev/null
@@ -1,92 +0,0 @@
-/*
- This file is part of GNU Taler
- (C) 2019 GNUnet e.V.
-
- GNU Taler is free software; you can redistribute it and/or modify it under the
- terms of the GNU General Public License as published by the Free Software
- Foundation; either version 3, or (at your option) any later version.
-
- GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- A PARTICULAR PURPOSE. See the GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License along with
- GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
- */
-
-import * as nacl from "./nacl-fast";
-import { sha256 } from "./sha256";
-
-export function sha512(data: Uint8Array): Uint8Array {
- return nacl.hash(data);
-}
-
-export function hmac(
- digest: (d: Uint8Array) => Uint8Array,
- blockSize: number,
- key: Uint8Array,
- message: Uint8Array,
-): Uint8Array {
- if (key.byteLength > blockSize) {
- key = digest(key);
- }
- if (key.byteLength < blockSize) {
- const k = key;
- key = new Uint8Array(blockSize);
- key.set(k, 0);
- }
- const okp = new Uint8Array(blockSize);
- const ikp = new Uint8Array(blockSize);
- for (let i = 0; i < blockSize; i++) {
- ikp[i] = key[i] ^ 0x36;
- okp[i] = key[i] ^ 0x5c;
- }
- const b1 = new Uint8Array(blockSize + message.byteLength);
- b1.set(ikp, 0);
- b1.set(message, blockSize);
- const h0 = digest(b1);
- const b2 = new Uint8Array(blockSize + h0.length);
- b2.set(okp, 0);
- b2.set(h0, blockSize);
- return digest(b2);
-}
-
-export function hmacSha512(key: Uint8Array, message: Uint8Array): Uint8Array {
- return hmac(sha512, 128, key, message);
-}
-
-export function hmacSha256(key: Uint8Array, message: Uint8Array): Uint8Array {
- return hmac(sha256, 64, key, message);
-}
-
-export function kdf(
- outputLength: number,
- ikm: Uint8Array,
- salt: Uint8Array,
- info: Uint8Array,
-): Uint8Array {
- // extract
- const prk = hmacSha512(salt, ikm);
-
- // expand
- const N = Math.ceil(outputLength / 32);
- const output = new Uint8Array(N * 32);
- for (let i = 0; i < N; i++) {
- let buf;
- if (i == 0) {
- buf = new Uint8Array(info.byteLength + 1);
- buf.set(info, 0);
- } else {
- buf = new Uint8Array(info.byteLength + 1 + 32);
- for (let j = 0; j < 32; j++) {
- buf[j] = output[(i - 1) * 32 + j];
- }
- buf.set(info, 32);
- }
- buf[buf.length - 1] = i + 1;
- const chunk = hmacSha256(prk, buf);
- output.set(chunk, i * 32);
- }
-
- return output.slice(0, outputLength);
-}
diff --git a/src/crypto/primitives/nacl-fast.ts b/src/crypto/primitives/nacl-fast.ts
deleted file mode 100644
index 8d4aaeb63..000000000
--- a/src/crypto/primitives/nacl-fast.ts
+++ /dev/null
@@ -1,1941 +0,0 @@
-// Ported in 2014 by Dmitry Chestnykh and Devi Mandiri.
-// TypeScript port in 2019 by Florian Dold.
-// Public domain.
-//
-// Implementation derived from TweetNaCl version 20140427.
-// See for details: http://tweetnacl.cr.yp.to/
-
-const gf = function (init: number[] = []): Float64Array {
- const r = new Float64Array(16);
- if (init) for (let i = 0; i < init.length; i++) r[i] = init[i];
- return r;
-};
-
-// Pluggable, initialized in high-level API below.
-let randombytes = function (x: Uint8Array, n: number): void {
- throw new Error("no PRNG");
-};
-
-const _9 = new Uint8Array(32);
-_9[0] = 9;
-
-// prettier-ignore
-const gf0 = gf();
-const gf1 = gf([1]);
-const _121665 = gf([0xdb41, 1]);
-const D = gf([
- 0x78a3,
- 0x1359,
- 0x4dca,
- 0x75eb,
- 0xd8ab,
- 0x4141,
- 0x0a4d,
- 0x0070,
- 0xe898,
- 0x7779,
- 0x4079,
- 0x8cc7,
- 0xfe73,
- 0x2b6f,
- 0x6cee,
- 0x5203,
-]);
-const D2 = gf([
- 0xf159,
- 0x26b2,
- 0x9b94,
- 0xebd6,
- 0xb156,
- 0x8283,
- 0x149a,
- 0x00e0,
- 0xd130,
- 0xeef3,
- 0x80f2,
- 0x198e,
- 0xfce7,
- 0x56df,
- 0xd9dc,
- 0x2406,
-]);
-const X = gf([
- 0xd51a,
- 0x8f25,
- 0x2d60,
- 0xc956,
- 0xa7b2,
- 0x9525,
- 0xc760,
- 0x692c,
- 0xdc5c,
- 0xfdd6,
- 0xe231,
- 0xc0a4,
- 0x53fe,
- 0xcd6e,
- 0x36d3,
- 0x2169,
-]);
-const Y = gf([
- 0x6658,
- 0x6666,
- 0x6666,
- 0x6666,
- 0x6666,
- 0x6666,
- 0x6666,
- 0x6666,
- 0x6666,
- 0x6666,
- 0x6666,
- 0x6666,
- 0x6666,
- 0x6666,
- 0x6666,
- 0x6666,
-]);
-const I = gf([
- 0xa0b0,
- 0x4a0e,
- 0x1b27,
- 0xc4ee,
- 0xe478,
- 0xad2f,
- 0x1806,
- 0x2f43,
- 0xd7a7,
- 0x3dfb,
- 0x0099,
- 0x2b4d,
- 0xdf0b,
- 0x4fc1,
- 0x2480,
- 0x2b83,
-]);
-
-function ts64(x: Uint8Array, i: number, h: number, l: number): void {
- x[i] = (h >> 24) & 0xff;
- x[i + 1] = (h >> 16) & 0xff;
- x[i + 2] = (h >> 8) & 0xff;
- x[i + 3] = h & 0xff;
- x[i + 4] = (l >> 24) & 0xff;
- x[i + 5] = (l >> 16) & 0xff;
- x[i + 6] = (l >> 8) & 0xff;
- x[i + 7] = l & 0xff;
-}
-
-function vn(
- x: Uint8Array,
- xi: number,
- y: Uint8Array,
- yi: number,
- n: number,
-): number {
- let i,
- d = 0;
- for (i = 0; i < n; i++) d |= x[xi + i] ^ y[yi + i];
- return (1 & ((d - 1) >>> 8)) - 1;
-}
-
-function crypto_verify_32(
- x: Uint8Array,
- xi: number,
- y: Uint8Array,
- yi: number,
-): number {
- return vn(x, xi, y, yi, 32);
-}
-
-function set25519(r: Float64Array, a: Float64Array): void {
- let i;
- for (i = 0; i < 16; i++) r[i] = a[i] | 0;
-}
-
-function car25519(o: Float64Array): void {
- let i,
- v,
- c = 1;
- for (i = 0; i < 16; i++) {
- v = o[i] + c + 65535;
- c = Math.floor(v / 65536);
- o[i] = v - c * 65536;
- }
- o[0] += c - 1 + 37 * (c - 1);
-}
-
-function sel25519(p: Float64Array, q: Float64Array, b: number): void {
- let t;
- const c = ~(b - 1);
- for (let i = 0; i < 16; i++) {
- t = c & (p[i] ^ q[i]);
- p[i] ^= t;
- q[i] ^= t;
- }
-}
-
-function pack25519(o: Uint8Array, n: Float64Array): void {
- let i, j, b;
- const m = gf(),
- t = gf();
- for (i = 0; i < 16; i++) t[i] = n[i];
- car25519(t);
- car25519(t);
- car25519(t);
- for (j = 0; j < 2; j++) {
- m[0] = t[0] - 0xffed;
- for (i = 1; i < 15; i++) {
- m[i] = t[i] - 0xffff - ((m[i - 1] >> 16) & 1);
- m[i - 1] &= 0xffff;
- }
- m[15] = t[15] - 0x7fff - ((m[14] >> 16) & 1);
- b = (m[15] >> 16) & 1;
- m[14] &= 0xffff;
- sel25519(t, m, 1 - b);
- }
- for (i = 0; i < 16; i++) {
- o[2 * i] = t[i] & 0xff;
- o[2 * i + 1] = t[i] >> 8;
- }
-}
-
-function neq25519(a: Float64Array, b: Float64Array): number {
- const c = new Uint8Array(32),
- d = new Uint8Array(32);
- pack25519(c, a);
- pack25519(d, b);
- return crypto_verify_32(c, 0, d, 0);
-}
-
-function par25519(a: Float64Array): number {
- const d = new Uint8Array(32);
- pack25519(d, a);
- return d[0] & 1;
-}
-
-function unpack25519(o: Float64Array, n: Uint8Array): void {
- let i;
- for (i = 0; i < 16; i++) o[i] = n[2 * i] + (n[2 * i + 1] << 8);
- o[15] &= 0x7fff;
-}
-
-function A(o: Float64Array, a: Float64Array, b: Float64Array): void {
- for (let i = 0; i < 16; i++) o[i] = a[i] + b[i];
-}
-
-function Z(o: Float64Array, a: Float64Array, b: Float64Array): void {
- for (let i = 0; i < 16; i++) o[i] = a[i] - b[i];
-}
-
-function M(o: Float64Array, a: Float64Array, b: Float64Array): void {
- let v,
- c,
- t0 = 0,
- t1 = 0,
- t2 = 0,
- t3 = 0,
- t4 = 0,
- t5 = 0,
- t6 = 0,
- t7 = 0,
- t8 = 0,
- t9 = 0,
- t10 = 0,
- t11 = 0,
- t12 = 0,
- t13 = 0,
- t14 = 0,
- t15 = 0,
- t16 = 0,
- t17 = 0,
- t18 = 0,
- t19 = 0,
- t20 = 0,
- t21 = 0,
- t22 = 0,
- t23 = 0,
- t24 = 0,
- t25 = 0,
- t26 = 0,
- t27 = 0,
- t28 = 0,
- t29 = 0,
- t30 = 0;
- const b0 = b[0],
- b1 = b[1],
- b2 = b[2],
- b3 = b[3],
- b4 = b[4],
- b5 = b[5],
- b6 = b[6],
- b7 = b[7],
- b8 = b[8],
- b9 = b[9],
- b10 = b[10],
- b11 = b[11],
- b12 = b[12],
- b13 = b[13],
- b14 = b[14],
- b15 = b[15];
-
- v = a[0];
- t0 += v * b0;
- t1 += v * b1;
- t2 += v * b2;
- t3 += v * b3;
- t4 += v * b4;
- t5 += v * b5;
- t6 += v * b6;
- t7 += v * b7;
- t8 += v * b8;
- t9 += v * b9;
- t10 += v * b10;
- t11 += v * b11;
- t12 += v * b12;
- t13 += v * b13;
- t14 += v * b14;
- t15 += v * b15;
- v = a[1];
- t1 += v * b0;
- t2 += v * b1;
- t3 += v * b2;
- t4 += v * b3;
- t5 += v * b4;
- t6 += v * b5;
- t7 += v * b6;
- t8 += v * b7;
- t9 += v * b8;
- t10 += v * b9;
- t11 += v * b10;
- t12 += v * b11;
- t13 += v * b12;
- t14 += v * b13;
- t15 += v * b14;
- t16 += v * b15;
- v = a[2];
- t2 += v * b0;
- t3 += v * b1;
- t4 += v * b2;
- t5 += v * b3;
- t6 += v * b4;
- t7 += v * b5;
- t8 += v * b6;
- t9 += v * b7;
- t10 += v * b8;
- t11 += v * b9;
- t12 += v * b10;
- t13 += v * b11;
- t14 += v * b12;
- t15 += v * b13;
- t16 += v * b14;
- t17 += v * b15;
- v = a[3];
- t3 += v * b0;
- t4 += v * b1;
- t5 += v * b2;
- t6 += v * b3;
- t7 += v * b4;
- t8 += v * b5;
- t9 += v * b6;
- t10 += v * b7;
- t11 += v * b8;
- t12 += v * b9;
- t13 += v * b10;
- t14 += v * b11;
- t15 += v * b12;
- t16 += v * b13;
- t17 += v * b14;
- t18 += v * b15;
- v = a[4];
- t4 += v * b0;
- t5 += v * b1;
- t6 += v * b2;
- t7 += v * b3;
- t8 += v * b4;
- t9 += v * b5;
- t10 += v * b6;
- t11 += v * b7;
- t12 += v * b8;
- t13 += v * b9;
- t14 += v * b10;
- t15 += v * b11;
- t16 += v * b12;
- t17 += v * b13;
- t18 += v * b14;
- t19 += v * b15;
- v = a[5];
- t5 += v * b0;
- t6 += v * b1;
- t7 += v * b2;
- t8 += v * b3;
- t9 += v * b4;
- t10 += v * b5;
- t11 += v * b6;
- t12 += v * b7;
- t13 += v * b8;
- t14 += v * b9;
- t15 += v * b10;
- t16 += v * b11;
- t17 += v * b12;
- t18 += v * b13;
- t19 += v * b14;
- t20 += v * b15;
- v = a[6];
- t6 += v * b0;
- t7 += v * b1;
- t8 += v * b2;
- t9 += v * b3;
- t10 += v * b4;
- t11 += v * b5;
- t12 += v * b6;
- t13 += v * b7;
- t14 += v * b8;
- t15 += v * b9;
- t16 += v * b10;
- t17 += v * b11;
- t18 += v * b12;
- t19 += v * b13;
- t20 += v * b14;
- t21 += v * b15;
- v = a[7];
- t7 += v * b0;
- t8 += v * b1;
- t9 += v * b2;
- t10 += v * b3;
- t11 += v * b4;
- t12 += v * b5;
- t13 += v * b6;
- t14 += v * b7;
- t15 += v * b8;
- t16 += v * b9;
- t17 += v * b10;
- t18 += v * b11;
- t19 += v * b12;
- t20 += v * b13;
- t21 += v * b14;
- t22 += v * b15;
- v = a[8];
- t8 += v * b0;
- t9 += v * b1;
- t10 += v * b2;
- t11 += v * b3;
- t12 += v * b4;
- t13 += v * b5;
- t14 += v * b6;
- t15 += v * b7;
- t16 += v * b8;
- t17 += v * b9;
- t18 += v * b10;
- t19 += v * b11;
- t20 += v * b12;
- t21 += v * b13;
- t22 += v * b14;
- t23 += v * b15;
- v = a[9];
- t9 += v * b0;
- t10 += v * b1;
- t11 += v * b2;
- t12 += v * b3;
- t13 += v * b4;
- t14 += v * b5;
- t15 += v * b6;
- t16 += v * b7;
- t17 += v * b8;
- t18 += v * b9;
- t19 += v * b10;
- t20 += v * b11;
- t21 += v * b12;
- t22 += v * b13;
- t23 += v * b14;
- t24 += v * b15;
- v = a[10];
- t10 += v * b0;
- t11 += v * b1;
- t12 += v * b2;
- t13 += v * b3;
- t14 += v * b4;
- t15 += v * b5;
- t16 += v * b6;
- t17 += v * b7;
- t18 += v * b8;
- t19 += v * b9;
- t20 += v * b10;
- t21 += v * b11;
- t22 += v * b12;
- t23 += v * b13;
- t24 += v * b14;
- t25 += v * b15;
- v = a[11];
- t11 += v * b0;
- t12 += v * b1;
- t13 += v * b2;
- t14 += v * b3;
- t15 += v * b4;
- t16 += v * b5;
- t17 += v * b6;
- t18 += v * b7;
- t19 += v * b8;
- t20 += v * b9;
- t21 += v * b10;
- t22 += v * b11;
- t23 += v * b12;
- t24 += v * b13;
- t25 += v * b14;
- t26 += v * b15;
- v = a[12];
- t12 += v * b0;
- t13 += v * b1;
- t14 += v * b2;
- t15 += v * b3;
- t16 += v * b4;
- t17 += v * b5;
- t18 += v * b6;
- t19 += v * b7;
- t20 += v * b8;
- t21 += v * b9;
- t22 += v * b10;
- t23 += v * b11;
- t24 += v * b12;
- t25 += v * b13;
- t26 += v * b14;
- t27 += v * b15;
- v = a[13];
- t13 += v * b0;
- t14 += v * b1;
- t15 += v * b2;
- t16 += v * b3;
- t17 += v * b4;
- t18 += v * b5;
- t19 += v * b6;
- t20 += v * b7;
- t21 += v * b8;
- t22 += v * b9;
- t23 += v * b10;
- t24 += v * b11;
- t25 += v * b12;
- t26 += v * b13;
- t27 += v * b14;
- t28 += v * b15;
- v = a[14];
- t14 += v * b0;
- t15 += v * b1;
- t16 += v * b2;
- t17 += v * b3;
- t18 += v * b4;
- t19 += v * b5;
- t20 += v * b6;
- t21 += v * b7;
- t22 += v * b8;
- t23 += v * b9;
- t24 += v * b10;
- t25 += v * b11;
- t26 += v * b12;
- t27 += v * b13;
- t28 += v * b14;
- t29 += v * b15;
- v = a[15];
- t15 += v * b0;
- t16 += v * b1;
- t17 += v * b2;
- t18 += v * b3;
- t19 += v * b4;
- t20 += v * b5;
- t21 += v * b6;
- t22 += v * b7;
- t23 += v * b8;
- t24 += v * b9;
- t25 += v * b10;
- t26 += v * b11;
- t27 += v * b12;
- t28 += v * b13;
- t29 += v * b14;
- t30 += v * b15;
-
- t0 += 38 * t16;
- t1 += 38 * t17;
- t2 += 38 * t18;
- t3 += 38 * t19;
- t4 += 38 * t20;
- t5 += 38 * t21;
- t6 += 38 * t22;
- t7 += 38 * t23;
- t8 += 38 * t24;
- t9 += 38 * t25;
- t10 += 38 * t26;
- t11 += 38 * t27;
- t12 += 38 * t28;
- t13 += 38 * t29;
- t14 += 38 * t30;
- // t15 left as is
-
- // first car
- c = 1;
- v = t0 + c + 65535;
- c = Math.floor(v / 65536);
- t0 = v - c * 65536;
- v = t1 + c + 65535;
- c = Math.floor(v / 65536);
- t1 = v - c * 65536;
- v = t2 + c + 65535;
- c = Math.floor(v / 65536);
- t2 = v - c * 65536;
- v = t3 + c + 65535;
- c = Math.floor(v / 65536);
- t3 = v - c * 65536;
- v = t4 + c + 65535;
- c = Math.floor(v / 65536);
- t4 = v - c * 65536;
- v = t5 + c + 65535;
- c = Math.floor(v / 65536);
- t5 = v - c * 65536;
- v = t6 + c + 65535;
- c = Math.floor(v / 65536);
- t6 = v - c * 65536;
- v = t7 + c + 65535;
- c = Math.floor(v / 65536);
- t7 = v - c * 65536;
- v = t8 + c + 65535;
- c = Math.floor(v / 65536);
- t8 = v - c * 65536;
- v = t9 + c + 65535;
- c = Math.floor(v / 65536);
- t9 = v - c * 65536;
- v = t10 + c + 65535;
- c = Math.floor(v / 65536);
- t10 = v - c * 65536;
- v = t11 + c + 65535;
- c = Math.floor(v / 65536);
- t11 = v - c * 65536;
- v = t12 + c + 65535;
- c = Math.floor(v / 65536);
- t12 = v - c * 65536;
- v = t13 + c + 65535;
- c = Math.floor(v / 65536);
- t13 = v - c * 65536;
- v = t14 + c + 65535;
- c = Math.floor(v / 65536);
- t14 = v - c * 65536;
- v = t15 + c + 65535;
- c = Math.floor(v / 65536);
- t15 = v - c * 65536;
- t0 += c - 1 + 37 * (c - 1);
-
- // second car
- c = 1;
- v = t0 + c + 65535;
- c = Math.floor(v / 65536);
- t0 = v - c * 65536;
- v = t1 + c + 65535;
- c = Math.floor(v / 65536);
- t1 = v - c * 65536;
- v = t2 + c + 65535;
- c = Math.floor(v / 65536);
- t2 = v - c * 65536;
- v = t3 + c + 65535;
- c = Math.floor(v / 65536);
- t3 = v - c * 65536;
- v = t4 + c + 65535;
- c = Math.floor(v / 65536);
- t4 = v - c * 65536;
- v = t5 + c + 65535;
- c = Math.floor(v / 65536);
- t5 = v - c * 65536;
- v = t6 + c + 65535;
- c = Math.floor(v / 65536);
- t6 = v - c * 65536;
- v = t7 + c + 65535;
- c = Math.floor(v / 65536);
- t7 = v - c * 65536;
- v = t8 + c + 65535;
- c = Math.floor(v / 65536);
- t8 = v - c * 65536;
- v = t9 + c + 65535;
- c = Math.floor(v / 65536);
- t9 = v - c * 65536;
- v = t10 + c + 65535;
- c = Math.floor(v / 65536);
- t10 = v - c * 65536;
- v = t11 + c + 65535;
- c = Math.floor(v / 65536);
- t11 = v - c * 65536;
- v = t12 + c + 65535;
- c = Math.floor(v / 65536);
- t12 = v - c * 65536;
- v = t13 + c + 65535;
- c = Math.floor(v / 65536);
- t13 = v - c * 65536;
- v = t14 + c + 65535;
- c = Math.floor(v / 65536);
- t14 = v - c * 65536;
- v = t15 + c + 65535;
- c = Math.floor(v / 65536);
- t15 = v - c * 65536;
- t0 += c - 1 + 37 * (c - 1);
-
- o[0] = t0;
- o[1] = t1;
- o[2] = t2;
- o[3] = t3;
- o[4] = t4;
- o[5] = t5;
- o[6] = t6;
- o[7] = t7;
- o[8] = t8;
- o[9] = t9;
- o[10] = t10;
- o[11] = t11;
- o[12] = t12;
- o[13] = t13;
- o[14] = t14;
- o[15] = t15;
-}
-
-function S(o: Float64Array, a: Float64Array): void {
- M(o, a, a);
-}
-
-function inv25519(o: Float64Array, i: Float64Array): void {
- const c = gf();
- let a;
- for (a = 0; a < 16; a++) c[a] = i[a];
- for (a = 253; a >= 0; a--) {
- S(c, c);
- if (a !== 2 && a !== 4) M(c, c, i);
- }
- for (a = 0; a < 16; a++) o[a] = c[a];
-}
-
-function pow2523(o: Float64Array, i: Float64Array): void {
- const c = gf();
- let a;
- for (a = 0; a < 16; a++) c[a] = i[a];
- for (a = 250; a >= 0; a--) {
- S(c, c);
- if (a !== 1) M(c, c, i);
- }
- for (a = 0; a < 16; a++) o[a] = c[a];
-}
-
-function crypto_scalarmult(
- q: Uint8Array,
- n: Uint8Array,
- p: Uint8Array,
-): number {
- const z = new Uint8Array(32);
- const x = new Float64Array(80);
- let r;
- let i;
- const a = gf(),
- b = gf(),
- c = gf(),
- d = gf(),
- e = gf(),
- f = gf();
- for (i = 0; i < 31; i++) z[i] = n[i];
- z[31] = (n[31] & 127) | 64;
- z[0] &= 248;
- unpack25519(x, p);
- for (i = 0; i < 16; i++) {
- b[i] = x[i];
- d[i] = a[i] = c[i] = 0;
- }
- a[0] = d[0] = 1;
- for (i = 254; i >= 0; --i) {
- r = (z[i >>> 3] >>> (i & 7)) & 1;
- sel25519(a, b, r);
- sel25519(c, d, r);
- A(e, a, c);
- Z(a, a, c);
- A(c, b, d);
- Z(b, b, d);
- S(d, e);
- S(f, a);
- M(a, c, a);
- M(c, b, e);
- A(e, a, c);
- Z(a, a, c);
- S(b, a);
- Z(c, d, f);
- M(a, c, _121665);
- A(a, a, d);
- M(c, c, a);
- M(a, d, f);
- M(d, b, x);
- S(b, e);
- sel25519(a, b, r);
- sel25519(c, d, r);
- }
- for (i = 0; i < 16; i++) {
- x[i + 16] = a[i];
- x[i + 32] = c[i];
- x[i + 48] = b[i];
- x[i + 64] = d[i];
- }
- const x32 = x.subarray(32);
- const x16 = x.subarray(16);
- inv25519(x32, x32);
- M(x16, x16, x32);
- pack25519(q, x16);
- return 0;
-}
-
-function crypto_scalarmult_base(q: Uint8Array, n: Uint8Array): number {
- return crypto_scalarmult(q, n, _9);
-}
-
-// prettier-ignore
-const K = [
- 0x428a2f98, 0xd728ae22, 0x71374491, 0x23ef65cd,
- 0xb5c0fbcf, 0xec4d3b2f, 0xe9b5dba5, 0x8189dbbc,
- 0x3956c25b, 0xf348b538, 0x59f111f1, 0xb605d019,
- 0x923f82a4, 0xaf194f9b, 0xab1c5ed5, 0xda6d8118,
- 0xd807aa98, 0xa3030242, 0x12835b01, 0x45706fbe,
- 0x243185be, 0x4ee4b28c, 0x550c7dc3, 0xd5ffb4e2,
- 0x72be5d74, 0xf27b896f, 0x80deb1fe, 0x3b1696b1,
- 0x9bdc06a7, 0x25c71235, 0xc19bf174, 0xcf692694,
- 0xe49b69c1, 0x9ef14ad2, 0xefbe4786, 0x384f25e3,
- 0x0fc19dc6, 0x8b8cd5b5, 0x240ca1cc, 0x77ac9c65,
- 0x2de92c6f, 0x592b0275, 0x4a7484aa, 0x6ea6e483,
- 0x5cb0a9dc, 0xbd41fbd4, 0x76f988da, 0x831153b5,
- 0x983e5152, 0xee66dfab, 0xa831c66d, 0x2db43210,
- 0xb00327c8, 0x98fb213f, 0xbf597fc7, 0xbeef0ee4,
- 0xc6e00bf3, 0x3da88fc2, 0xd5a79147, 0x930aa725,
- 0x06ca6351, 0xe003826f, 0x14292967, 0x0a0e6e70,
- 0x27b70a85, 0x46d22ffc, 0x2e1b2138, 0x5c26c926,
- 0x4d2c6dfc, 0x5ac42aed, 0x53380d13, 0x9d95b3df,
- 0x650a7354, 0x8baf63de, 0x766a0abb, 0x3c77b2a8,
- 0x81c2c92e, 0x47edaee6, 0x92722c85, 0x1482353b,
- 0xa2bfe8a1, 0x4cf10364, 0xa81a664b, 0xbc423001,
- 0xc24b8b70, 0xd0f89791, 0xc76c51a3, 0x0654be30,
- 0xd192e819, 0xd6ef5218, 0xd6990624, 0x5565a910,
- 0xf40e3585, 0x5771202a, 0x106aa070, 0x32bbd1b8,
- 0x19a4c116, 0xb8d2d0c8, 0x1e376c08, 0x5141ab53,
- 0x2748774c, 0xdf8eeb99, 0x34b0bcb5, 0xe19b48a8,
- 0x391c0cb3, 0xc5c95a63, 0x4ed8aa4a, 0xe3418acb,
- 0x5b9cca4f, 0x7763e373, 0x682e6ff3, 0xd6b2b8a3,
- 0x748f82ee, 0x5defb2fc, 0x78a5636f, 0x43172f60,
- 0x84c87814, 0xa1f0ab72, 0x8cc70208, 0x1a6439ec,
- 0x90befffa, 0x23631e28, 0xa4506ceb, 0xde82bde9,
- 0xbef9a3f7, 0xb2c67915, 0xc67178f2, 0xe372532b,
- 0xca273ece, 0xea26619c, 0xd186b8c7, 0x21c0c207,
- 0xeada7dd6, 0xcde0eb1e, 0xf57d4f7f, 0xee6ed178,
- 0x06f067aa, 0x72176fba, 0x0a637dc5, 0xa2c898a6,
- 0x113f9804, 0xbef90dae, 0x1b710b35, 0x131c471b,
- 0x28db77f5, 0x23047d84, 0x32caab7b, 0x40c72493,
- 0x3c9ebe0a, 0x15c9bebc, 0x431d67c4, 0x9c100d4c,
- 0x4cc5d4be, 0xcb3e42b6, 0x597f299c, 0xfc657e2a,
- 0x5fcb6fab, 0x3ad6faec, 0x6c44198c, 0x4a475817
-];
-
-function crypto_hashblocks_hl(
- hh: Int32Array,
- hl: Int32Array,
- m: Uint8Array,
- n: number,
-): number {
- const wh = new Int32Array(16),
- wl = new Int32Array(16);
- let bh0,
- bh1,
- bh2,
- bh3,
- bh4,
- bh5,
- bh6,
- bh7,
- bl0,
- bl1,
- bl2,
- bl3,
- bl4,
- bl5,
- bl6,
- bl7,
- th,
- tl,
- i,
- j,
- h,
- l,
- a,
- b,
- c,
- d;
-
- let ah0 = hh[0],
- ah1 = hh[1],
- ah2 = hh[2],
- ah3 = hh[3],
- ah4 = hh[4],
- ah5 = hh[5],
- ah6 = hh[6],
- ah7 = hh[7],
- al0 = hl[0],
- al1 = hl[1],
- al2 = hl[2],
- al3 = hl[3],
- al4 = hl[4],
- al5 = hl[5],
- al6 = hl[6],
- al7 = hl[7];
-
- let pos = 0;
- while (n >= 128) {
- for (i = 0; i < 16; i++) {
- j = 8 * i + pos;
- wh[i] = (m[j + 0] << 24) | (m[j + 1] << 16) | (m[j + 2] << 8) | m[j + 3];
- wl[i] = (m[j + 4] << 24) | (m[j + 5] << 16) | (m[j + 6] << 8) | m[j + 7];
- }
- for (i = 0; i < 80; i++) {
- bh0 = ah0;
- bh1 = ah1;
- bh2 = ah2;
- bh3 = ah3;
- bh4 = ah4;
- bh5 = ah5;
- bh6 = ah6;
- bh7 = ah7;
-
- bl0 = al0;
- bl1 = al1;
- bl2 = al2;
- bl3 = al3;
- bl4 = al4;
- bl5 = al5;
- bl6 = al6;
- bl7 = al7;
-
- // add
- h = ah7;
- l = al7;
-
- a = l & 0xffff;
- b = l >>> 16;
- c = h & 0xffff;
- d = h >>> 16;
-
- // Sigma1
- h =
- ((ah4 >>> 14) | (al4 << (32 - 14))) ^
- ((ah4 >>> 18) | (al4 << (32 - 18))) ^
- ((al4 >>> (41 - 32)) | (ah4 << (32 - (41 - 32))));
- l =
- ((al4 >>> 14) | (ah4 << (32 - 14))) ^
- ((al4 >>> 18) | (ah4 << (32 - 18))) ^
- ((ah4 >>> (41 - 32)) | (al4 << (32 - (41 - 32))));
-
- a += l & 0xffff;
- b += l >>> 16;
- c += h & 0xffff;
- d += h >>> 16;
-
- // Ch
- h = (ah4 & ah5) ^ (~ah4 & ah6);
- l = (al4 & al5) ^ (~al4 & al6);
-
- a += l & 0xffff;
- b += l >>> 16;
- c += h & 0xffff;
- d += h >>> 16;
-
- // K
- h = K[i * 2];
- l = K[i * 2 + 1];
-
- a += l & 0xffff;
- b += l >>> 16;
- c += h & 0xffff;
- d += h >>> 16;
-
- // w
- h = wh[i % 16];
- l = wl[i % 16];
-
- a += l & 0xffff;
- b += l >>> 16;
- c += h & 0xffff;
- d += h >>> 16;
-
- b += a >>> 16;
- c += b >>> 16;
- d += c >>> 16;
-
- th = (c & 0xffff) | (d << 16);
- tl = (a & 0xffff) | (b << 16);
-
- // add
- h = th;
- l = tl;
-
- a = l & 0xffff;
- b = l >>> 16;
- c = h & 0xffff;
- d = h >>> 16;
-
- // Sigma0
- h =
- ((ah0 >>> 28) | (al0 << (32 - 28))) ^
- ((al0 >>> (34 - 32)) | (ah0 << (32 - (34 - 32)))) ^
- ((al0 >>> (39 - 32)) | (ah0 << (32 - (39 - 32))));
- l =
- ((al0 >>> 28) | (ah0 << (32 - 28))) ^
- ((ah0 >>> (34 - 32)) | (al0 << (32 - (34 - 32)))) ^
- ((ah0 >>> (39 - 32)) | (al0 << (32 - (39 - 32))));
-
- a += l & 0xffff;
- b += l >>> 16;
- c += h & 0xffff;
- d += h >>> 16;
-
- // Maj
- h = (ah0 & ah1) ^ (ah0 & ah2) ^ (ah1 & ah2);
- l = (al0 & al1) ^ (al0 & al2) ^ (al1 & al2);
-
- a += l & 0xffff;
- b += l >>> 16;
- c += h & 0xffff;
- d += h >>> 16;
-
- b += a >>> 16;
- c += b >>> 16;
- d += c >>> 16;
-
- bh7 = (c & 0xffff) | (d << 16);
- bl7 = (a & 0xffff) | (b << 16);
-
- // add
- h = bh3;
- l = bl3;
-
- a = l & 0xffff;
- b = l >>> 16;
- c = h & 0xffff;
- d = h >>> 16;
-
- h = th;
- l = tl;
-
- a += l & 0xffff;
- b += l >>> 16;
- c += h & 0xffff;
- d += h >>> 16;
-
- b += a >>> 16;
- c += b >>> 16;
- d += c >>> 16;
-
- bh3 = (c & 0xffff) | (d << 16);
- bl3 = (a & 0xffff) | (b << 16);
-
- ah1 = bh0;
- ah2 = bh1;
- ah3 = bh2;
- ah4 = bh3;
- ah5 = bh4;
- ah6 = bh5;
- ah7 = bh6;
- ah0 = bh7;
-
- al1 = bl0;
- al2 = bl1;
- al3 = bl2;
- al4 = bl3;
- al5 = bl4;
- al6 = bl5;
- al7 = bl6;
- al0 = bl7;
-
- if (i % 16 === 15) {
- for (j = 0; j < 16; j++) {
- // add
- h = wh[j];
- l = wl[j];
-
- a = l & 0xffff;
- b = l >>> 16;
- c = h & 0xffff;
- d = h >>> 16;
-
- h = wh[(j + 9) % 16];
- l = wl[(j + 9) % 16];
-
- a += l & 0xffff;
- b += l >>> 16;
- c += h & 0xffff;
- d += h >>> 16;
-
- // sigma0
- th = wh[(j + 1) % 16];
- tl = wl[(j + 1) % 16];
- h =
- ((th >>> 1) | (tl << (32 - 1))) ^
- ((th >>> 8) | (tl << (32 - 8))) ^
- (th >>> 7);
- l =
- ((tl >>> 1) | (th << (32 - 1))) ^
- ((tl >>> 8) | (th << (32 - 8))) ^
- ((tl >>> 7) | (th << (32 - 7)));
-
- a += l & 0xffff;
- b += l >>> 16;
- c += h & 0xffff;
- d += h >>> 16;
-
- // sigma1
- th = wh[(j + 14) % 16];
- tl = wl[(j + 14) % 16];
- h =
- ((th >>> 19) | (tl << (32 - 19))) ^
- ((tl >>> (61 - 32)) | (th << (32 - (61 - 32)))) ^
- (th >>> 6);
- l =
- ((tl >>> 19) | (th << (32 - 19))) ^
- ((th >>> (61 - 32)) | (tl << (32 - (61 - 32)))) ^
- ((tl >>> 6) | (th << (32 - 6)));
-
- a += l & 0xffff;
- b += l >>> 16;
- c += h & 0xffff;
- d += h >>> 16;
-
- b += a >>> 16;
- c += b >>> 16;
- d += c >>> 16;
-
- wh[j] = (c & 0xffff) | (d << 16);
- wl[j] = (a & 0xffff) | (b << 16);
- }
- }
- }
-
- // add
- h = ah0;
- l = al0;
-
- a = l & 0xffff;
- b = l >>> 16;
- c = h & 0xffff;
- d = h >>> 16;
-
- h = hh[0];
- l = hl[0];
-
- a += l & 0xffff;
- b += l >>> 16;
- c += h & 0xffff;
- d += h >>> 16;
-
- b += a >>> 16;
- c += b >>> 16;
- d += c >>> 16;
-
- hh[0] = ah0 = (c & 0xffff) | (d << 16);
- hl[0] = al0 = (a & 0xffff) | (b << 16);
-
- h = ah1;
- l = al1;
-
- a = l & 0xffff;
- b = l >>> 16;
- c = h & 0xffff;
- d = h >>> 16;
-
- h = hh[1];
- l = hl[1];
-
- a += l & 0xffff;
- b += l >>> 16;
- c += h & 0xffff;
- d += h >>> 16;
-
- b += a >>> 16;
- c += b >>> 16;
- d += c >>> 16;
-
- hh[1] = ah1 = (c & 0xffff) | (d << 16);
- hl[1] = al1 = (a & 0xffff) | (b << 16);
-
- h = ah2;
- l = al2;
-
- a = l & 0xffff;
- b = l >>> 16;
- c = h & 0xffff;
- d = h >>> 16;
-
- h = hh[2];
- l = hl[2];
-
- a += l & 0xffff;
- b += l >>> 16;
- c += h & 0xffff;
- d += h >>> 16;
-
- b += a >>> 16;
- c += b >>> 16;
- d += c >>> 16;
-
- hh[2] = ah2 = (c & 0xffff) | (d << 16);
- hl[2] = al2 = (a & 0xffff) | (b << 16);
-
- h = ah3;
- l = al3;
-
- a = l & 0xffff;
- b = l >>> 16;
- c = h & 0xffff;
- d = h >>> 16;
-
- h = hh[3];
- l = hl[3];
-
- a += l & 0xffff;
- b += l >>> 16;
- c += h & 0xffff;
- d += h >>> 16;
-
- b += a >>> 16;
- c += b >>> 16;
- d += c >>> 16;
-
- hh[3] = ah3 = (c & 0xffff) | (d << 16);
- hl[3] = al3 = (a & 0xffff) | (b << 16);
-
- h = ah4;
- l = al4;
-
- a = l & 0xffff;
- b = l >>> 16;
- c = h & 0xffff;
- d = h >>> 16;
-
- h = hh[4];
- l = hl[4];
-
- a += l & 0xffff;
- b += l >>> 16;
- c += h & 0xffff;
- d += h >>> 16;
-
- b += a >>> 16;
- c += b >>> 16;
- d += c >>> 16;
-
- hh[4] = ah4 = (c & 0xffff) | (d << 16);
- hl[4] = al4 = (a & 0xffff) | (b << 16);
-
- h = ah5;
- l = al5;
-
- a = l & 0xffff;
- b = l >>> 16;
- c = h & 0xffff;
- d = h >>> 16;
-
- h = hh[5];
- l = hl[5];
-
- a += l & 0xffff;
- b += l >>> 16;
- c += h & 0xffff;
- d += h >>> 16;
-
- b += a >>> 16;
- c += b >>> 16;
- d += c >>> 16;
-
- hh[5] = ah5 = (c & 0xffff) | (d << 16);
- hl[5] = al5 = (a & 0xffff) | (b << 16);
-
- h = ah6;
- l = al6;
-
- a = l & 0xffff;
- b = l >>> 16;
- c = h & 0xffff;
- d = h >>> 16;
-
- h = hh[6];
- l = hl[6];
-
- a += l & 0xffff;
- b += l >>> 16;
- c += h & 0xffff;
- d += h >>> 16;
-
- b += a >>> 16;
- c += b >>> 16;
- d += c >>> 16;
-
- hh[6] = ah6 = (c & 0xffff) | (d << 16);
- hl[6] = al6 = (a & 0xffff) | (b << 16);
-
- h = ah7;
- l = al7;
-
- a = l & 0xffff;
- b = l >>> 16;
- c = h & 0xffff;
- d = h >>> 16;
-
- h = hh[7];
- l = hl[7];
-
- a += l & 0xffff;
- b += l >>> 16;
- c += h & 0xffff;
- d += h >>> 16;
-
- b += a >>> 16;
- c += b >>> 16;
- d += c >>> 16;
-
- hh[7] = ah7 = (c & 0xffff) | (d << 16);
- hl[7] = al7 = (a & 0xffff) | (b << 16);
-
- pos += 128;
- n -= 128;
- }
-
- return n;
-}
-
-function crypto_hash(out: Uint8Array, m: Uint8Array, n: number): number {
- const hh = new Int32Array(8);
- const hl = new Int32Array(8);
- const x = new Uint8Array(256);
- const b = n;
-
- hh[0] = 0x6a09e667;
- hh[1] = 0xbb67ae85;
- hh[2] = 0x3c6ef372;
- hh[3] = 0xa54ff53a;
- hh[4] = 0x510e527f;
- hh[5] = 0x9b05688c;
- hh[6] = 0x1f83d9ab;
- hh[7] = 0x5be0cd19;
-
- hl[0] = 0xf3bcc908;
- hl[1] = 0x84caa73b;
- hl[2] = 0xfe94f82b;
- hl[3] = 0x5f1d36f1;
- hl[4] = 0xade682d1;
- hl[5] = 0x2b3e6c1f;
- hl[6] = 0xfb41bd6b;
- hl[7] = 0x137e2179;
-
- crypto_hashblocks_hl(hh, hl, m, n);
- n %= 128;
-
- for (let i = 0; i < n; i++) x[i] = m[b - n + i];
- x[n] = 128;
-
- n = 256 - 128 * (n < 112 ? 1 : 0);
- x[n - 9] = 0;
- ts64(x, n - 8, (b / 0x20000000) | 0, b << 3);
- crypto_hashblocks_hl(hh, hl, x, n);
-
- for (let i = 0; i < 8; i++) ts64(out, 8 * i, hh[i], hl[i]);
-
- return 0;
-}
-
-/**
- * Incremental version of crypto_hash.
- */
-export class HashState {
- private hh = new Int32Array(8);
- private hl = new Int32Array(8);
-
- private next = new Uint8Array(128);
- private p = 0;
- private total = 0;
-
- constructor() {
- this.hh[0] = 0x6a09e667;
- this.hh[1] = 0xbb67ae85;
- this.hh[2] = 0x3c6ef372;
- this.hh[3] = 0xa54ff53a;
- this.hh[4] = 0x510e527f;
- this.hh[5] = 0x9b05688c;
- this.hh[6] = 0x1f83d9ab;
- this.hh[7] = 0x5be0cd19;
-
- this.hl[0] = 0xf3bcc908;
- this.hl[1] = 0x84caa73b;
- this.hl[2] = 0xfe94f82b;
- this.hl[3] = 0x5f1d36f1;
- this.hl[4] = 0xade682d1;
- this.hl[5] = 0x2b3e6c1f;
- this.hl[6] = 0xfb41bd6b;
- this.hl[7] = 0x137e2179;
- }
-
- update(data: Uint8Array): HashState {
- this.total += data.length;
- let i = 0;
- while (i < data.length) {
- const r = 128 - this.p;
- if (r > data.length - i) {
- for (let j = 0; i + j < data.length; j++) {
- this.next[this.p + j] = data[i + j];
- }
- this.p += data.length - i;
- break;
- } else {
- for (let j = 0; this.p + j < 128; j++) {
- this.next[this.p + j] = data[i + j];
- }
- crypto_hashblocks_hl(this.hh, this.hl, this.next, 128);
- i += 128 - this.p;
- this.p = 0;
- }
- }
- return this;
- }
-
- finish(): Uint8Array {
- const out = new Uint8Array(64);
- let n = this.p;
- const x = new Uint8Array(256);
- const b = this.total;
- for (let i = 0; i < n; i++) x[i] = this.next[i];
- x[n] = 128;
-
- n = 256 - 128 * (n < 112 ? 1 : 0);
- x[n - 9] = 0;
- ts64(x, n - 8, (b / 0x20000000) | 0, b << 3);
- crypto_hashblocks_hl(this.hh, this.hl, x, n);
-
- for (let i = 0; i < 8; i++) ts64(out, 8 * i, this.hh[i], this.hl[i]);
- return out;
- }
-}
-
-function add(p: Float64Array[], q: Float64Array[]): void {
- const a = gf(),
- b = gf(),
- c = gf(),
- d = gf(),
- e = gf(),
- f = gf(),
- g = gf(),
- h = gf(),
- t = gf();
-
- Z(a, p[1], p[0]);
- Z(t, q[1], q[0]);
- M(a, a, t);
- A(b, p[0], p[1]);
- A(t, q[0], q[1]);
- M(b, b, t);
- M(c, p[3], q[3]);
- M(c, c, D2);
- M(d, p[2], q[2]);
- A(d, d, d);
- Z(e, b, a);
- Z(f, d, c);
- A(g, d, c);
- A(h, b, a);
-
- M(p[0], e, f);
- M(p[1], h, g);
- M(p[2], g, f);
- M(p[3], e, h);
-}
-
-function cswap(p: Float64Array[], q: Float64Array[], b: number): void {
- let i;
- for (i = 0; i < 4; i++) {
- sel25519(p[i], q[i], b);
- }
-}
-
-function pack(r: Uint8Array, p: Float64Array[]): void {
- const tx = gf(),
- ty = gf(),
- zi = gf();
- inv25519(zi, p[2]);
- M(tx, p[0], zi);
- M(ty, p[1], zi);
- pack25519(r, ty);
- r[31] ^= par25519(tx) << 7;
-}
-
-function scalarmult(p: Float64Array[], q: Float64Array[], s: Uint8Array): void {
- let b, i;
- set25519(p[0], gf0);
- set25519(p[1], gf1);
- set25519(p[2], gf1);
- set25519(p[3], gf0);
- for (i = 255; i >= 0; --i) {
- b = (s[(i / 8) | 0] >> (i & 7)) & 1;
- cswap(p, q, b);
- add(q, p);
- add(p, p);
- cswap(p, q, b);
- }
-}
-
-function scalarbase(p: Float64Array[], s: Uint8Array): void {
- const q = [gf(), gf(), gf(), gf()];
- set25519(q[0], X);
- set25519(q[1], Y);
- set25519(q[2], gf1);
- M(q[3], X, Y);
- scalarmult(p, q, s);
-}
-
-function crypto_sign_keypair(
- pk: Uint8Array,
- sk: Uint8Array,
- seeded: boolean,
-): number {
- const d = new Uint8Array(64);
- const p = [gf(), gf(), gf(), gf()];
-
- if (!seeded) randombytes(sk, 32);
- crypto_hash(d, sk, 32);
- d[0] &= 248;
- d[31] &= 127;
- d[31] |= 64;
-
- scalarbase(p, d);
- pack(pk, p);
-
- for (let i = 0; i < 32; i++) sk[i + 32] = pk[i];
- return 0;
-}
-
-const L = new Float64Array([
- 0xed,
- 0xd3,
- 0xf5,
- 0x5c,
- 0x1a,
- 0x63,
- 0x12,
- 0x58,
- 0xd6,
- 0x9c,
- 0xf7,
- 0xa2,
- 0xde,
- 0xf9,
- 0xde,
- 0x14,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0x10,
-]);
-
-function modL(r: Uint8Array, x: Float64Array): void {
- let carry, i, j, k;
- for (i = 63; i >= 32; --i) {
- carry = 0;
- for (j = i - 32, k = i - 12; j < k; ++j) {
- x[j] += carry - 16 * x[i] * L[j - (i - 32)];
- carry = (x[j] + 128) >> 8;
- x[j] -= carry * 256;
- }
- x[j] += carry;
- x[i] = 0;
- }
- carry = 0;
- for (j = 0; j < 32; j++) {
- x[j] += carry - (x[31] >> 4) * L[j];
- carry = x[j] >> 8;
- x[j] &= 255;
- }
- for (j = 0; j < 32; j++) x[j] -= carry * L[j];
- for (i = 0; i < 32; i++) {
- x[i + 1] += x[i] >> 8;
- r[i] = x[i] & 255;
- }
-}
-
-function reduce(r: Uint8Array): void {
- const x = new Float64Array(64);
- for (let i = 0; i < 64; i++) x[i] = r[i];
- for (let i = 0; i < 64; i++) r[i] = 0;
- modL(r, x);
-}
-
-// Note: difference from C - smlen returned, not passed as argument.
-function crypto_sign(
- sm: Uint8Array,
- m: Uint8Array,
- n: number,
- sk: Uint8Array,
-): number {
- const d = new Uint8Array(64),
- h = new Uint8Array(64),
- r = new Uint8Array(64);
- let i, j;
- const x = new Float64Array(64);
- const p = [gf(), gf(), gf(), gf()];
-
- crypto_hash(d, sk, 32);
- d[0] &= 248;
- d[31] &= 127;
- d[31] |= 64;
-
- const smlen = n + 64;
- for (i = 0; i < n; i++) sm[64 + i] = m[i];
- for (i = 0; i < 32; i++) sm[32 + i] = d[32 + i];
-
- crypto_hash(r, sm.subarray(32), n + 32);
- reduce(r);
- scalarbase(p, r);
- pack(sm, p);
-
- for (i = 32; i < 64; i++) sm[i] = sk[i];
- crypto_hash(h, sm, n + 64);
- reduce(h);
-
- for (i = 0; i < 64; i++) x[i] = 0;
- for (i = 0; i < 32; i++) x[i] = r[i];
- for (i = 0; i < 32; i++) {
- for (j = 0; j < 32; j++) {
- x[i + j] += h[i] * d[j];
- }
- }
-
- modL(sm.subarray(32), x);
- return smlen;
-}
-
-function unpackneg(r: Float64Array[], p: Uint8Array): number {
- const t = gf();
- const chk = gf();
- const num = gf();
- const den = gf();
- const den2 = gf();
- const den4 = gf();
- const den6 = gf();
-
- set25519(r[2], gf1);
- unpack25519(r[1], p);
- S(num, r[1]);
- M(den, num, D);
- Z(num, num, r[2]);
- A(den, r[2], den);
-
- S(den2, den);
- S(den4, den2);
- M(den6, den4, den2);
- M(t, den6, num);
- M(t, t, den);
-
- pow2523(t, t);
- M(t, t, num);
- M(t, t, den);
- M(t, t, den);
- M(r[0], t, den);
-
- S(chk, r[0]);
- M(chk, chk, den);
- if (neq25519(chk, num)) M(r[0], r[0], I);
-
- S(chk, r[0]);
- M(chk, chk, den);
- if (neq25519(chk, num)) return -1;
-
- if (par25519(r[0]) === p[31] >> 7) Z(r[0], gf0, r[0]);
-
- M(r[3], r[0], r[1]);
- return 0;
-}
-
-function crypto_sign_open(
- m: Uint8Array,
- sm: Uint8Array,
- n: number,
- pk: Uint8Array,
-): number {
- let i, mlen;
- const t = new Uint8Array(32),
- h = new Uint8Array(64);
- const p = [gf(), gf(), gf(), gf()],
- q = [gf(), gf(), gf(), gf()];
-
- mlen = -1;
- if (n < 64) return -1;
-
- if (unpackneg(q, pk)) return -1;
-
- for (i = 0; i < n; i++) m[i] = sm[i];
- for (i = 0; i < 32; i++) m[i + 32] = pk[i];
- crypto_hash(h, m, n);
- reduce(h);
- scalarmult(p, q, h);
-
- scalarbase(q, sm.subarray(32));
- add(p, q);
- pack(t, p);
-
- n -= 64;
- if (crypto_verify_32(sm, 0, t, 0)) {
- for (i = 0; i < n; i++) m[i] = 0;
- return -1;
- }
-
- for (i = 0; i < n; i++) m[i] = sm[i + 64];
- mlen = n;
- return mlen;
-}
-
-const crypto_scalarmult_BYTES = 32,
- crypto_scalarmult_SCALARBYTES = 32,
- crypto_sign_BYTES = 64,
- crypto_sign_PUBLICKEYBYTES = 32,
- crypto_sign_SECRETKEYBYTES = 64,
- crypto_sign_SEEDBYTES = 32,
- crypto_hash_BYTES = 64;
-
-/* High-level API */
-
-function checkArrayTypes(...args: Uint8Array[]): void {
- for (let i = 0; i < args.length; i++) {
- if (!(args[i] instanceof Uint8Array))
- throw new TypeError("unexpected type, use Uint8Array");
- }
-}
-
-function cleanup(arr: Uint8Array): void {
- for (let i = 0; i < arr.length; i++) arr[i] = 0;
-}
-
-export function randomBytes(n: number): Uint8Array {
- const b = new Uint8Array(n);
- randombytes(b, n);
- return b;
-}
-
-export function scalarMult(n: Uint8Array, p: Uint8Array): Uint8Array {
- checkArrayTypes(n, p);
- if (n.length !== crypto_scalarmult_SCALARBYTES) throw new Error("bad n size");
- if (p.length !== crypto_scalarmult_BYTES) throw new Error("bad p size");
- const q = new Uint8Array(crypto_scalarmult_BYTES);
- crypto_scalarmult(q, n, p);
- return q;
-}
-
-export function scalarMult_base(n: Uint8Array): Uint8Array {
- checkArrayTypes(n);
- if (n.length !== crypto_scalarmult_SCALARBYTES) throw new Error("bad n size");
- const q = new Uint8Array(crypto_scalarmult_BYTES);
- crypto_scalarmult_base(q, n);
- return q;
-}
-
-export const scalarMult_scalarLength = crypto_scalarmult_SCALARBYTES;
-export const scalarMult_groupElementLength = crypto_scalarmult_BYTES;
-
-export function sign(msg: Uint8Array, secretKey: Uint8Array): Uint8Array {
- checkArrayTypes(msg, secretKey);
- if (secretKey.length !== crypto_sign_SECRETKEYBYTES)
- throw new Error("bad secret key size");
- const signedMsg = new Uint8Array(crypto_sign_BYTES + msg.length);
- crypto_sign(signedMsg, msg, msg.length, secretKey);
- return signedMsg;
-}
-
-export function sign_open(
- signedMsg: Uint8Array,
- publicKey: Uint8Array,
-): Uint8Array | null {
- checkArrayTypes(signedMsg, publicKey);
- if (publicKey.length !== crypto_sign_PUBLICKEYBYTES)
- throw new Error("bad public key size");
- const tmp = new Uint8Array(signedMsg.length);
- const mlen = crypto_sign_open(tmp, signedMsg, signedMsg.length, publicKey);
- if (mlen < 0) return null;
- const m = new Uint8Array(mlen);
- for (let i = 0; i < m.length; i++) m[i] = tmp[i];
- return m;
-}
-
-export function sign_detached(
- msg: Uint8Array,
- secretKey: Uint8Array,
-): Uint8Array {
- const signedMsg = sign(msg, secretKey);
- const sig = new Uint8Array(crypto_sign_BYTES);
- for (let i = 0; i < sig.length; i++) sig[i] = signedMsg[i];
- return sig;
-}
-
-export function sign_detached_verify(
- msg: Uint8Array,
- sig: Uint8Array,
- publicKey: Uint8Array,
-): boolean {
- checkArrayTypes(msg, sig, publicKey);
- if (sig.length !== crypto_sign_BYTES) throw new Error("bad signature size");
- if (publicKey.length !== crypto_sign_PUBLICKEYBYTES)
- throw new Error("bad public key size");
- const sm = new Uint8Array(crypto_sign_BYTES + msg.length);
- const m = new Uint8Array(crypto_sign_BYTES + msg.length);
- let i;
- for (i = 0; i < crypto_sign_BYTES; i++) sm[i] = sig[i];
- for (i = 0; i < msg.length; i++) sm[i + crypto_sign_BYTES] = msg[i];
- return crypto_sign_open(m, sm, sm.length, publicKey) >= 0;
-}
-
-export function sign_keyPair(): {
- publicKey: Uint8Array;
- secretKey: Uint8Array;
-} {
- const pk = new Uint8Array(crypto_sign_PUBLICKEYBYTES);
- const sk = new Uint8Array(crypto_sign_SECRETKEYBYTES);
- crypto_sign_keypair(pk, sk, false);
- return { publicKey: pk, secretKey: sk };
-}
-
-export function x25519_edwards_keyPair_fromSecretKey(
- secretKey: Uint8Array,
-): Uint8Array {
- const p = [gf(), gf(), gf(), gf()];
- const pk = new Uint8Array(32);
-
- const d = new Uint8Array(64);
- if (secretKey.length != 32) {
- throw new Error("bad secret key size");
- }
- d.set(secretKey, 0);
- //crypto_hash(d, secretKey, 32);
-
- d[0] &= 248;
- d[31] &= 127;
- d[31] |= 64;
-
- scalarbase(p, d);
- pack(pk, p);
-
- return pk;
-}
-
-export function sign_keyPair_fromSecretKey(
- secretKey: Uint8Array,
-): {
- publicKey: Uint8Array;
- secretKey: Uint8Array;
-} {
- checkArrayTypes(secretKey);
- if (secretKey.length !== crypto_sign_SECRETKEYBYTES)
- throw new Error("bad secret key size");
- const pk = new Uint8Array(crypto_sign_PUBLICKEYBYTES);
- for (let i = 0; i < pk.length; i++) pk[i] = secretKey[32 + i];
- return { publicKey: pk, secretKey: new Uint8Array(secretKey) };
-}
-
-export function sign_keyPair_fromSeed(
- seed: Uint8Array,
-): {
- publicKey: Uint8Array;
- secretKey: Uint8Array;
-} {
- checkArrayTypes(seed);
- if (seed.length !== crypto_sign_SEEDBYTES) throw new Error("bad seed size");
- const pk = new Uint8Array(crypto_sign_PUBLICKEYBYTES);
- const sk = new Uint8Array(crypto_sign_SECRETKEYBYTES);
- for (let i = 0; i < 32; i++) sk[i] = seed[i];
- crypto_sign_keypair(pk, sk, true);
- return { publicKey: pk, secretKey: sk };
-}
-
-export const sign_publicKeyLength = crypto_sign_PUBLICKEYBYTES;
-export const sign_secretKeyLength = crypto_sign_SECRETKEYBYTES;
-export const sign_seedLength = crypto_sign_SEEDBYTES;
-export const sign_signatureLength = crypto_sign_BYTES;
-
-export function hash(msg: Uint8Array): Uint8Array {
- checkArrayTypes(msg);
- const h = new Uint8Array(crypto_hash_BYTES);
- crypto_hash(h, msg, msg.length);
- return h;
-}
-
-export const hash_hashLength = crypto_hash_BYTES;
-
-export function verify(x: Uint8Array, y: Uint8Array): boolean {
- checkArrayTypes(x, y);
- // Zero length arguments are considered not equal.
- if (x.length === 0 || y.length === 0) return false;
- if (x.length !== y.length) return false;
- return vn(x, 0, y, 0, x.length) === 0 ? true : false;
-}
-
-export function setPRNG(fn: (x: Uint8Array, n: number) => void): void {
- randombytes = fn;
-}
-
-export function sign_ed25519_pk_to_curve25519(
- ed25519_pk: Uint8Array,
-): Uint8Array {
- const ge_a = [gf(), gf(), gf(), gf()];
- const x = gf();
- const one_minus_y = gf();
- const x25519_pk = new Uint8Array(32);
-
- if (unpackneg(ge_a, ed25519_pk)) {
- throw Error("invalid public key");
- }
-
- set25519(one_minus_y, gf1);
- Z(one_minus_y, one_minus_y, ge_a[1]);
-
- set25519(x, gf1);
- A(x, x, ge_a[1]);
-
- inv25519(one_minus_y, one_minus_y);
- M(x, x, one_minus_y);
- pack25519(x25519_pk, x);
-
- return x25519_pk;
-}
-
-(function () {
- // Initialize PRNG if environment provides CSPRNG.
- // If not, methods calling randombytes will throw.
- const cr =
- typeof self !== "undefined" ? self.crypto || (self as any).msCrypto : null;
- if (cr && cr.getRandomValues) {
- // Browsers.
- const QUOTA = 65536;
- setPRNG(function (x: Uint8Array, n: number) {
- let i;
- const v = new Uint8Array(n);
- for (i = 0; i < n; i += QUOTA) {
- cr.getRandomValues(v.subarray(i, i + Math.min(n - i, QUOTA)));
- }
- for (i = 0; i < n; i++) x[i] = v[i];
- cleanup(v);
- });
- } else if (typeof require !== "undefined") {
- // Node.js.
- // eslint-disable-next-line @typescript-eslint/no-var-requires
- const cr = require("crypto");
- if (cr && cr.randomBytes) {
- setPRNG(function (x: Uint8Array, n: number) {
- const v = cr.randomBytes(n);
- for (let i = 0; i < n; i++) x[i] = v[i];
- cleanup(v);
- });
- }
- }
-})();
diff --git a/src/crypto/primitives/sha256.ts b/src/crypto/primitives/sha256.ts
deleted file mode 100644
index 97723dbfc..000000000
--- a/src/crypto/primitives/sha256.ts
+++ /dev/null
@@ -1,426 +0,0 @@
-// SHA-256 for JavaScript.
-//
-// Written in 2014-2016 by Dmitry Chestnykh.
-// Public domain, no warranty.
-//
-// Functions (accept and return Uint8Arrays):
-//
-// sha256(message) -> hash
-// sha256.hmac(key, message) -> mac
-//
-// Classes:
-//
-// new sha256.Hash()
-export const digestLength = 32;
-export const blockSize = 64;
-
-// SHA-256 constants
-const K = new Uint32Array([
- 0x428a2f98,
- 0x71374491,
- 0xb5c0fbcf,
- 0xe9b5dba5,
- 0x3956c25b,
- 0x59f111f1,
- 0x923f82a4,
- 0xab1c5ed5,
- 0xd807aa98,
- 0x12835b01,
- 0x243185be,
- 0x550c7dc3,
- 0x72be5d74,
- 0x80deb1fe,
- 0x9bdc06a7,
- 0xc19bf174,
- 0xe49b69c1,
- 0xefbe4786,
- 0x0fc19dc6,
- 0x240ca1cc,
- 0x2de92c6f,
- 0x4a7484aa,
- 0x5cb0a9dc,
- 0x76f988da,
- 0x983e5152,
- 0xa831c66d,
- 0xb00327c8,
- 0xbf597fc7,
- 0xc6e00bf3,
- 0xd5a79147,
- 0x06ca6351,
- 0x14292967,
- 0x27b70a85,
- 0x2e1b2138,
- 0x4d2c6dfc,
- 0x53380d13,
- 0x650a7354,
- 0x766a0abb,
- 0x81c2c92e,
- 0x92722c85,
- 0xa2bfe8a1,
- 0xa81a664b,
- 0xc24b8b70,
- 0xc76c51a3,
- 0xd192e819,
- 0xd6990624,
- 0xf40e3585,
- 0x106aa070,
- 0x19a4c116,
- 0x1e376c08,
- 0x2748774c,
- 0x34b0bcb5,
- 0x391c0cb3,
- 0x4ed8aa4a,
- 0x5b9cca4f,
- 0x682e6ff3,
- 0x748f82ee,
- 0x78a5636f,
- 0x84c87814,
- 0x8cc70208,
- 0x90befffa,
- 0xa4506ceb,
- 0xbef9a3f7,
- 0xc67178f2,
-]);
-
-function hashBlocks(
- w: Int32Array,
- v: Int32Array,
- p: Uint8Array,
- pos: number,
- len: number,
-): number {
- let a: number,
- b: number,
- c: number,
- d: number,
- e: number,
- f: number,
- g: number,
- h: number,
- u: number,
- i: number,
- j: number,
- t1: number,
- t2: number;
- while (len >= 64) {
- a = v[0];
- b = v[1];
- c = v[2];
- d = v[3];
- e = v[4];
- f = v[5];
- g = v[6];
- h = v[7];
-
- for (i = 0; i < 16; i++) {
- j = pos + i * 4;
- w[i] =
- ((p[j] & 0xff) << 24) |
- ((p[j + 1] & 0xff) << 16) |
- ((p[j + 2] & 0xff) << 8) |
- (p[j + 3] & 0xff);
- }
-
- for (i = 16; i < 64; i++) {
- u = w[i - 2];
- t1 =
- ((u >>> 17) | (u << (32 - 17))) ^
- ((u >>> 19) | (u << (32 - 19))) ^
- (u >>> 10);
-
- u = w[i - 15];
- t2 =
- ((u >>> 7) | (u << (32 - 7))) ^
- ((u >>> 18) | (u << (32 - 18))) ^
- (u >>> 3);
-
- w[i] = ((t1 + w[i - 7]) | 0) + ((t2 + w[i - 16]) | 0);
- }
-
- for (i = 0; i < 64; i++) {
- t1 =
- ((((((e >>> 6) | (e << (32 - 6))) ^
- ((e >>> 11) | (e << (32 - 11))) ^
- ((e >>> 25) | (e << (32 - 25)))) +
- ((e & f) ^ (~e & g))) |
- 0) +
- ((h + ((K[i] + w[i]) | 0)) | 0)) |
- 0;
-
- t2 =
- ((((a >>> 2) | (a << (32 - 2))) ^
- ((a >>> 13) | (a << (32 - 13))) ^
- ((a >>> 22) | (a << (32 - 22)))) +
- ((a & b) ^ (a & c) ^ (b & c))) |
- 0;
-
- h = g;
- g = f;
- f = e;
- e = (d + t1) | 0;
- d = c;
- c = b;
- b = a;
- a = (t1 + t2) | 0;
- }
-
- v[0] += a;
- v[1] += b;
- v[2] += c;
- v[3] += d;
- v[4] += e;
- v[5] += f;
- v[6] += g;
- v[7] += h;
-
- pos += 64;
- len -= 64;
- }
- return pos;
-}
-
-// Hash implements SHA256 hash algorithm.
-export class HashSha256 {
- digestLength: number = digestLength;
- blockSize: number = blockSize;
-
- // Note: Int32Array is used instead of Uint32Array for performance reasons.
- private state: Int32Array = new Int32Array(8); // hash state
- private temp: Int32Array = new Int32Array(64); // temporary state
- private buffer: Uint8Array = new Uint8Array(128); // buffer for data to hash
- private bufferLength = 0; // number of bytes in buffer
- private bytesHashed = 0; // number of total bytes hashed
-
- finished = false; // indicates whether the hash was finalized
-
- constructor() {
- this.reset();
- }
-
- // Resets hash state making it possible
- // to re-use this instance to hash other data.
- reset(): this {
- this.state[0] = 0x6a09e667;
- this.state[1] = 0xbb67ae85;
- this.state[2] = 0x3c6ef372;
- this.state[3] = 0xa54ff53a;
- this.state[4] = 0x510e527f;
- this.state[5] = 0x9b05688c;
- this.state[6] = 0x1f83d9ab;
- this.state[7] = 0x5be0cd19;
- this.bufferLength = 0;
- this.bytesHashed = 0;
- this.finished = false;
- return this;
- }
-
- // Cleans internal buffers and re-initializes hash state.
- clean(): void {
- for (let i = 0; i < this.buffer.length; i++) {
- this.buffer[i] = 0;
- }
- for (let i = 0; i < this.temp.length; i++) {
- this.temp[i] = 0;
- }
- this.reset();
- }
-
- // Updates hash state with the given data.
- //
- // Optionally, length of the data can be specified to hash
- // fewer bytes than data.length.
- //
- // Throws error when trying to update already finalized hash:
- // instance must be reset to use it again.
- update(data: Uint8Array, dataLength: number = data.length): this {
- if (this.finished) {
- throw new Error("SHA256: can't update because hash was finished.");
- }
- let dataPos = 0;
- this.bytesHashed += dataLength;
- if (this.bufferLength > 0) {
- while (this.bufferLength < 64 && dataLength > 0) {
- this.buffer[this.bufferLength++] = data[dataPos++];
- dataLength--;
- }
- if (this.bufferLength === 64) {
- hashBlocks(this.temp, this.state, this.buffer, 0, 64);
- this.bufferLength = 0;
- }
- }
- if (dataLength >= 64) {
- dataPos = hashBlocks(this.temp, this.state, data, dataPos, dataLength);
- dataLength %= 64;
- }
- while (dataLength > 0) {
- this.buffer[this.bufferLength++] = data[dataPos++];
- dataLength--;
- }
- return this;
- }
-
- // Finalizes hash state and puts hash into out.
- //
- // If hash was already finalized, puts the same value.
- finish(out: Uint8Array): this {
- if (!this.finished) {
- const bytesHashed = this.bytesHashed;
- const left = this.bufferLength;
- const bitLenHi = (bytesHashed / 0x20000000) | 0;
- const bitLenLo = bytesHashed << 3;
- const padLength = bytesHashed % 64 < 56 ? 64 : 128;
-
- this.buffer[left] = 0x80;
- for (let i = left + 1; i < padLength - 8; i++) {
- this.buffer[i] = 0;
- }
- this.buffer[padLength - 8] = (bitLenHi >>> 24) & 0xff;
- this.buffer[padLength - 7] = (bitLenHi >>> 16) & 0xff;
- this.buffer[padLength - 6] = (bitLenHi >>> 8) & 0xff;
- this.buffer[padLength - 5] = (bitLenHi >>> 0) & 0xff;
- this.buffer[padLength - 4] = (bitLenLo >>> 24) & 0xff;
- this.buffer[padLength - 3] = (bitLenLo >>> 16) & 0xff;
- this.buffer[padLength - 2] = (bitLenLo >>> 8) & 0xff;
- this.buffer[padLength - 1] = (bitLenLo >>> 0) & 0xff;
-
- hashBlocks(this.temp, this.state, this.buffer, 0, padLength);
-
- this.finished = true;
- }
-
- for (let i = 0; i < 8; i++) {
- out[i * 4 + 0] = (this.state[i] >>> 24) & 0xff;
- out[i * 4 + 1] = (this.state[i] >>> 16) & 0xff;
- out[i * 4 + 2] = (this.state[i] >>> 8) & 0xff;
- out[i * 4 + 3] = (this.state[i] >>> 0) & 0xff;
- }
-
- return this;
- }
-
- // Returns the final hash digest.
- digest(): Uint8Array {
- const out = new Uint8Array(this.digestLength);
- this.finish(out);
- return out;
- }
-
- // Internal function for use in HMAC for optimization.
- _saveState(out: Uint32Array): void {
- for (let i = 0; i < this.state.length; i++) {
- out[i] = this.state[i];
- }
- }
-
- // Internal function for use in HMAC for optimization.
- _restoreState(from: Uint32Array, bytesHashed: number): void {
- for (let i = 0; i < this.state.length; i++) {
- this.state[i] = from[i];
- }
- this.bytesHashed = bytesHashed;
- this.finished = false;
- this.bufferLength = 0;
- }
-}
-
-// HMAC implements HMAC-SHA256 message authentication algorithm.
-export class HMAC {
- private inner: HashSha256 = new HashSha256();
- private outer: HashSha256 = new HashSha256();
-
- blockSize: number = this.inner.blockSize;
- digestLength: number = this.inner.digestLength;
-
- // Copies of hash states after keying.
- // Need for quick reset without hashing they key again.
- private istate: Uint32Array;
- private ostate: Uint32Array;
-
- constructor(key: Uint8Array) {
- const pad = new Uint8Array(this.blockSize);
- if (key.length > this.blockSize) {
- new HashSha256().update(key).finish(pad).clean();
- } else {
- for (let i = 0; i < key.length; i++) {
- pad[i] = key[i];
- }
- }
- for (let i = 0; i < pad.length; i++) {
- pad[i] ^= 0x36;
- }
- this.inner.update(pad);
-
- for (let i = 0; i < pad.length; i++) {
- pad[i] ^= 0x36 ^ 0x5c;
- }
- this.outer.update(pad);
-
- this.istate = new Uint32Array(8);
- this.ostate = new Uint32Array(8);
-
- this.inner._saveState(this.istate);
- this.outer._saveState(this.ostate);
-
- for (let i = 0; i < pad.length; i++) {
- pad[i] = 0;
- }
- }
-
- // Returns HMAC state to the state initialized with key
- // to make it possible to run HMAC over the other data with the same
- // key without creating a new instance.
- reset(): this {
- this.inner._restoreState(this.istate, this.inner.blockSize);
- this.outer._restoreState(this.ostate, this.outer.blockSize);
- return this;
- }
-
- // Cleans HMAC state.
- clean(): void {
- for (let i = 0; i < this.istate.length; i++) {
- this.ostate[i] = this.istate[i] = 0;
- }
- this.inner.clean();
- this.outer.clean();
- }
-
- // Updates state with provided data.
- update(data: Uint8Array): this {
- this.inner.update(data);
- return this;
- }
-
- // Finalizes HMAC and puts the result in out.
- finish(out: Uint8Array): this {
- if (this.outer.finished) {
- this.outer.finish(out);
- } else {
- this.inner.finish(out);
- this.outer.update(out, this.digestLength).finish(out);
- }
- return this;
- }
-
- // Returns message authentication code.
- digest(): Uint8Array {
- const out = new Uint8Array(this.digestLength);
- this.finish(out);
- return out;
- }
-}
-
-// Returns SHA256 hash of data.
-export function sha256(data: Uint8Array): Uint8Array {
- const h = new HashSha256().update(data);
- const digest = h.digest();
- h.clean();
- return digest;
-}
-
-// Returns HMAC-SHA256 of data under the key.
-export function hmacSha256(key: Uint8Array, data: Uint8Array): Uint8Array {
- const h = new HMAC(key).update(data);
- const digest = h.digest();
- h.clean();
- return digest;
-}
diff --git a/src/crypto/talerCrypto-test.ts b/src/crypto/talerCrypto-test.ts
deleted file mode 100644
index 1cd9da3e2..000000000
--- a/src/crypto/talerCrypto-test.ts
+++ /dev/null
@@ -1,197 +0,0 @@
-/*
- This file is part of GNU Taler
- (C) 2019 GNUnet e.V.
-
- GNU Taler is free software; you can redistribute it and/or modify it under the
- terms of the GNU General Public License as published by the Free Software
- Foundation; either version 3, or (at your option) any later version.
-
- GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- A PARTICULAR PURPOSE. See the GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License along with
- GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
- */
-
-/**
- * Imports
- */
-import test from "ava";
-import {
- encodeCrock,
- decodeCrock,
- ecdheGetPublic,
- eddsaGetPublic,
- keyExchangeEddsaEcdhe,
- keyExchangeEcdheEddsa,
- rsaBlind,
- rsaUnblind,
- rsaVerify,
-} from "./talerCrypto";
-import { sha512, kdf } from "./primitives/kdf";
-import * as nacl from "./primitives/nacl-fast";
-
-test("encoding", (t) => {
- const utf8decoder = new TextDecoder("utf-8");
- const utf8encoder = new TextEncoder();
- const s = "Hello, World";
- const encStr = encodeCrock(utf8encoder.encode(s));
- const outBuf = decodeCrock(encStr);
- const sOut = utf8decoder.decode(outBuf);
- t.deepEqual(s, sOut);
-});
-
-test("taler-exchange-tvg hash code", (t) => {
- const input = "91JPRV3F5GG4EKJN41A62V35E8";
- const output =
- "CW96WR74JS8T53EC8GKSGD49QKH4ZNFTZXDAWMMV5GJ1E4BM6B8GPN5NVHDJ8ZVXNCW7Q4WBYCV61HCA3PZC2YJD850DT29RHHN7ESR";
-
- const myOutput = encodeCrock(sha512(decodeCrock(input)));
-
- t.deepEqual(myOutput, output);
-});
-
-test("taler-exchange-tvg ecdhe key", (t) => {
- const priv1 = "X4T4N0M8PVQXQEBW2BA7049KFSM7J437NSDFC6GDNM3N5J9367A0";
- const pub1 = "M997P494MS6A95G1P0QYWW2VNPSHSX5Q6JBY5B9YMNYWP0B50X3G";
- const priv2 = "14A0MMQ64DCV8HE0CS3WBC9DHFJAHXRGV7NEARFJPC5R5E1697E0";
- const skm =
- "NXRY2YCY7H9B6KM928ZD55WG964G59YR0CPX041DYXKBZZ85SAWNPQ8B30QRM5FMHYCXJAN0EAADJYWEF1X3PAC2AJN28626TR5A6AR";
-
- const myPub1 = nacl.scalarMult_base(decodeCrock(priv1));
- t.deepEqual(encodeCrock(myPub1), pub1);
-
- const mySkm = nacl.hash(
- nacl.scalarMult(decodeCrock(priv2), decodeCrock(pub1)),
- );
- t.deepEqual(encodeCrock(mySkm), skm);
-});
-
-test("taler-exchange-tvg eddsa key", (t) => {
- const priv = "9TM70AKDTS57AWY9JK2J4TMBTMW6K62WHHGZWYDG0VM5ABPZKD40";
- const pub = "8GSJZ649T2PXMKZC01Y4ANNBE7MF14QVK9SQEC4E46ZHKCVG8AS0";
-
- const pair = nacl.sign_keyPair_fromSeed(decodeCrock(priv));
- t.deepEqual(encodeCrock(pair.publicKey), pub);
-});
-
-test("taler-exchange-tvg kdf", (t) => {
- const salt = "94KPT83PCNS7J83KC5P78Y8";
- const ikm = "94KPT83MD1JJ0WV5CDS6AX10D5Q70XBM41NPAY90DNGQ8SBJD5GPR";
- const ctx =
- "94KPT83141HPYVKMCNW78833D1TPWTSC41GPRWVF41NPWVVQDRG62WS04XMPWSKF4WG6JVH0EHM6A82J8S1G";
- const outLen = 64;
- const out =
- "GTMR4QT05Z9WF5HKVG0WK9RPXGHSMHJNW377G9GJXCA8B0FEKPF4D27RJMSJZYWSQNTBJ5EYVV7ZW18B48Z0JVJJ80RHB706Y96Q358";
-
- const myOut = kdf(
- outLen,
- decodeCrock(ikm),
- decodeCrock(salt),
- decodeCrock(ctx),
- );
-
- t.deepEqual(encodeCrock(myOut), out);
-});
-
-test("taler-exchange-tvg eddsa_ecdh", (t) => {
- const priv_ecdhe = "4AFZWMSGTVCHZPQ0R81NWXDCK4N58G7SDBBE5KXE080Y50370JJG";
- const pub_ecdhe = "FXFN5GPAFTKVPWJDPVXQ87167S8T82T5ZV8CDYC0NH2AE14X0M30";
- const priv_eddsa = "1KG54M8T3X8BSFSZXCR3SQBSR7Y9P53NX61M864S7TEVMJ2XVPF0";
- const pub_eddsa = "7BXWKG6N224C57RTDV8XEAHR108HG78NMA995BE8QAT5GC1S7E80";
- const key_material =
- "PKZ42Z56SVK2796HG1QYBRJ6ZQM2T9QGA3JA4AAZ8G7CWK9FPX175Q9JE5P0ZAX3HWWPHAQV4DPCK10R9X3SAXHRV0WF06BHEC2ZTKR";
-
- const myEcdhePub = ecdheGetPublic(decodeCrock(priv_ecdhe));
- t.deepEqual(encodeCrock(myEcdhePub), pub_ecdhe);
-
- const myEddsaPub = eddsaGetPublic(decodeCrock(priv_eddsa));
- t.deepEqual(encodeCrock(myEddsaPub), pub_eddsa);
-
- const myKm1 = keyExchangeEddsaEcdhe(
- decodeCrock(priv_eddsa),
- decodeCrock(pub_ecdhe),
- );
- t.deepEqual(encodeCrock(myKm1), key_material);
-
- const myKm2 = keyExchangeEcdheEddsa(
- decodeCrock(priv_ecdhe),
- decodeCrock(pub_eddsa),
- );
- t.deepEqual(encodeCrock(myKm2), key_material);
-});
-
-test("taler-exchange-tvg blind signing", (t) => {
- const messageHash =
- "TT1R28D79EJEJ9PC35AQS35CCG85DSXSZ508MV2HS2FN4ME6AHESZX5WP485R8A75KG53FN6F1YNW95008663TKAPWB81420VG17BY8";
- const rsaPublicKey =
- "040000Y62RSDDKZXTE7GDVA302ZZR0DY224RSDT6WDWR1XGT8E3YG80XV6TMT3ZCNP8XC84W0N6MSZ0EF8S3YB1JJ2AXY9JQZW3MCA0CG38ER4YE2RY4Q2666DEZSNKT29V6CKZVCDHXSAKY8W6RPEKEQ5YSBYQK23MRK3CQTNNJXQFDKEMRHEC5Y6RDHAC5RJCV8JJ8BF18VPKZ2Q7BB14YN1HJ22H8EZGW0RDGG9YPEWA9183BHEQ651PP81J514TJ9K8DH23AJ50SZFNS429HQ390VRP5E4MQ7RK7ZJXXTSZAQSRTC0QF28P23PD37C17QFQB0BBC54MB8MDH7RW104STG6VN0J22P39JP4EXPVGK5D9AX5W869MDQ6SRD42ZYK5H20227Q8CCWSQ6C3132WP0F0H04002";
- const bks = "7QD31RPJH0W306RJWBRG646Z2FTA1F89BKSXPDAG7YM0N5Z0B610";
- const bm =
- "GA8PC6YH9VF5MW6P2DKTV0W0ZTQ24DZ9EAN5QH3SQXRH7SCZHFMM21ZY05F0BS7MFW8TSEP4SEB280BYP5ACHNQWGE10PCXDDMK7ECXJDPHJ224JBCV4KYNWG6NBR3SC9HK8FXVFX55GFBJFNQHNZGEB8DB0KN9MSVYFDXN45KPMSNY03FVX0JZ0R3YG9XQ8XVGB5SYZCF0QSHWH61MT0Q10CZD2V114BT64D3GD86EJ5S9WBMYG51SDN5CSKEJ734YAJ4HCEWW0RDN8GXA9ZMA18SKVW8T3TTBCPJRF2Y77JGQ08GF35SYGA2HWFV1HGVS8RCTER6GB9SZHRG4T7919H9C1KFAP50G2KSV6X42D6KNJANNSGKQH649TJ00YJQXPHPNFBSS198RY2C243D4B4W";
- const bs =
- "5VW0MS5PRBA3W8TPATSTDA2YRFQM1Z7F2DWKQ8ATMZYYY768Q3STZ3HGNVYQ6JB5NKP80G5HGE58616FPA70SX9PTW7EN8EJ23E26FASBWZBP8E2RWQQ5E0F72B2PWRP5ZCA2J3AB3F6P86XK4PZYT64RF94MDGHY0GSDSSBH5YSFB3VM0KVXA52H2Y2G9S85AVCSD3BTMHQRF5BJJ8JE00T4GK70PSTVCGMRKRNA7DGW7GD2F35W55AXF7R2YJC8PAGNSJYWKC3PC75A5N8H69K299AK5PM3CDDHNS4BMRNGF7K49CR4ZBFRXDAWMB3X6T05Q4NKSG0F1KP5JA0XBMF2YJK7KEPRD1EWCHJE44T9YXBTK4W9CV77X7Z9P407ZC6YB3M2ARANZXHJKSM3XC33M";
- const sig =
- "PFT6WQJGCM9DE6264DJS6RMG4XDMCDBJKZGSXAF3BEXWZ979Q13NETKK05S1YV91CX3Y034FSS86SSHZTTE8097RRESQP52EKFGTWJXKHZJEQJ49YHMBNQDHW4CFBJECNJSV2PMHWVGXV7HB84R6P0S3ES559HWQX01Q9MYDEGRNHKW87QR2BNSG951D5NQGAKEJ2SSJBE18S6WYAC24FAP8TT8ANECH5371J0DJY0YR0VWAFWVJDV8XQSFXWMJ80N3A80SPSHPYJY3WZZXW63WQ46WHYY56ZSNE5G1RZ5CR0XYV2ECKPM8R0FS58EV16WTRAM1ABBFVNAT3CAEFAZCWP3XHPVBQY5NZVTD5QS2Q8SKJQ2XB30E11CWDN9KTV5CBK4DN72EVG73F3W3BATAKHG";
-
- const myBm = rsaBlind(
- decodeCrock(messageHash),
- decodeCrock(bks),
- decodeCrock(rsaPublicKey),
- );
- t.deepEqual(encodeCrock(myBm), bm);
-
- const mySig = rsaUnblind(
- decodeCrock(bs),
- decodeCrock(rsaPublicKey),
- decodeCrock(bks),
- );
- t.deepEqual(encodeCrock(mySig), sig);
-
- const v = rsaVerify(
- decodeCrock(messageHash),
- decodeCrock(sig),
- decodeCrock(rsaPublicKey),
- );
- t.true(v);
-});
-
-test("incremental hashing #1", (t) => {
- const n = 1024;
- const d = nacl.randomBytes(n);
-
- const h1 = nacl.hash(d);
- const h2 = new nacl.HashState().update(d).finish();
-
- const s = new nacl.HashState();
- for (let i = 0; i < n; i++) {
- const b = new Uint8Array(1);
- b[0] = d[i];
- s.update(b);
- }
-
- const h3 = s.finish();
-
- t.deepEqual(encodeCrock(h1), encodeCrock(h2));
- t.deepEqual(encodeCrock(h1), encodeCrock(h3));
-});
-
-test("incremental hashing #2", (t) => {
- const n = 10;
- const d = nacl.randomBytes(n);
-
- const h1 = nacl.hash(d);
- const h2 = new nacl.HashState().update(d).finish();
- const s = new nacl.HashState();
- for (let i = 0; i < n; i++) {
- const b = new Uint8Array(1);
- b[0] = d[i];
- s.update(b);
- }
-
- const h3 = s.finish();
-
- t.deepEqual(encodeCrock(h1), encodeCrock(h3));
- t.deepEqual(encodeCrock(h1), encodeCrock(h2));
-});
diff --git a/src/crypto/talerCrypto.ts b/src/crypto/talerCrypto.ts
deleted file mode 100644
index 457009a04..000000000
--- a/src/crypto/talerCrypto.ts
+++ /dev/null
@@ -1,376 +0,0 @@
-/*
- This file is part of GNU Taler
- (C) 2019 GNUnet e.V.
-
- GNU Taler is free software; you can redistribute it and/or modify it under the
- terms of the GNU General Public License as published by the Free Software
- Foundation; either version 3, or (at your option) any later version.
-
- GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- A PARTICULAR PURPOSE. See the GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License along with
- GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
- */
-
-/**
- * Native implementation of GNU Taler crypto.
- */
-
-import * as nacl from "./primitives/nacl-fast";
-import bigint from "big-integer";
-import { kdf } from "./primitives/kdf";
-
-export function getRandomBytes(n: number): Uint8Array {
- return nacl.randomBytes(n);
-}
-
-const encTable = "0123456789ABCDEFGHJKMNPQRSTVWXYZ";
-
-class EncodingError extends Error {
- constructor() {
- super("Encoding error");
- Object.setPrototypeOf(this, EncodingError.prototype);
- }
-}
-
-function getValue(chr: string): number {
- let a = chr;
- switch (chr) {
- case "O":
- case "o":
- a = "0;";
- break;
- case "i":
- case "I":
- case "l":
- case "L":
- a = "1";
- break;
- case "u":
- case "U":
- a = "V";
- }
-
- if (a >= "0" && a <= "9") {
- return a.charCodeAt(0) - "0".charCodeAt(0);
- }
-
- if (a >= "a" && a <= "z") a = a.toUpperCase();
- let dec = 0;
- if (a >= "A" && a <= "Z") {
- if ("I" < a) dec++;
- if ("L" < a) dec++;
- if ("O" < a) dec++;
- if ("U" < a) dec++;
- return a.charCodeAt(0) - "A".charCodeAt(0) + 10 - dec;
- }
- throw new EncodingError();
-}
-
-export function encodeCrock(data: ArrayBuffer): string {
- const dataBytes = new Uint8Array(data);
- let sb = "";
- const size = data.byteLength;
- let bitBuf = 0;
- let numBits = 0;
- let pos = 0;
- while (pos < size || numBits > 0) {
- if (pos < size && numBits < 5) {
- const d = dataBytes[pos++];
- bitBuf = (bitBuf << 8) | d;
- numBits += 8;
- }
- if (numBits < 5) {
- // zero-padding
- bitBuf = bitBuf << (5 - numBits);
- numBits = 5;
- }
- const v = (bitBuf >>> (numBits - 5)) & 31;
- sb += encTable[v];
- numBits -= 5;
- }
- return sb;
-}
-
-export function decodeCrock(encoded: string): Uint8Array {
- const size = encoded.length;
- let bitpos = 0;
- let bitbuf = 0;
- let readPosition = 0;
- const outLen = Math.floor((size * 5) / 8);
- const out = new Uint8Array(outLen);
- let outPos = 0;
-
- while (readPosition < size || bitpos > 0) {
- if (readPosition < size) {
- const v = getValue(encoded[readPosition++]);
- bitbuf = (bitbuf << 5) | v;
- bitpos += 5;
- }
- while (bitpos >= 8) {
- const d = (bitbuf >>> (bitpos - 8)) & 0xff;
- out[outPos++] = d;
- bitpos -= 8;
- }
- if (readPosition == size && bitpos > 0) {
- bitbuf = (bitbuf << (8 - bitpos)) & 0xff;
- bitpos = bitbuf == 0 ? 0 : 8;
- }
- }
- return out;
-}
-
-export function eddsaGetPublic(eddsaPriv: Uint8Array): Uint8Array {
- const pair = nacl.sign_keyPair_fromSeed(eddsaPriv);
- return pair.publicKey;
-}
-
-export function ecdheGetPublic(ecdhePriv: Uint8Array): Uint8Array {
- return nacl.scalarMult_base(ecdhePriv);
-}
-
-export function keyExchangeEddsaEcdhe(
- eddsaPriv: Uint8Array,
- ecdhePub: Uint8Array,
-): Uint8Array {
- const ph = nacl.hash(eddsaPriv);
- const a = new Uint8Array(32);
- for (let i = 0; i < 32; i++) {
- a[i] = ph[i];
- }
- const x = nacl.scalarMult(a, ecdhePub);
- return nacl.hash(x);
-}
-
-export function keyExchangeEcdheEddsa(
- ecdhePriv: Uint8Array,
- eddsaPub: Uint8Array,
-): Uint8Array {
- const curve25519Pub = nacl.sign_ed25519_pk_to_curve25519(eddsaPub);
- const x = nacl.scalarMult(ecdhePriv, curve25519Pub);
- return nacl.hash(x);
-}
-
-interface RsaPub {
- N: bigint.BigInteger;
- e: bigint.BigInteger;
-}
-
-interface RsaBlindingKey {
- r: bigint.BigInteger;
-}
-
-/**
- * KDF modulo a big integer.
- */
-function kdfMod(
- n: bigint.BigInteger,
- ikm: Uint8Array,
- salt: Uint8Array,
- info: Uint8Array,
-): bigint.BigInteger {
- const nbits = n.bitLength().toJSNumber();
- const buflen = Math.floor((nbits - 1) / 8 + 1);
- const mask = (1 << (8 - (buflen * 8 - nbits))) - 1;
- let counter = 0;
- while (true) {
- const ctx = new Uint8Array(info.byteLength + 2);
- ctx.set(info, 0);
- ctx[ctx.length - 2] = (counter >>> 8) & 0xff;
- ctx[ctx.length - 1] = counter & 0xff;
- const buf = kdf(buflen, ikm, salt, ctx);
- const arr = Array.from(buf);
- arr[0] = arr[0] & mask;
- const r = bigint.fromArray(arr, 256, false);
- if (r.lt(n)) {
- return r;
- }
- counter++;
- }
-}
-
-export function stringToBytes(s: string): Uint8Array {
- const te = new TextEncoder();
- return te.encode(s);
-}
-
-function loadBigInt(arr: Uint8Array): bigint.BigInteger {
- return bigint.fromArray(Array.from(arr), 256, false);
-}
-
-function rsaBlindingKeyDerive(
- rsaPub: RsaPub,
- bks: Uint8Array,
-): bigint.BigInteger {
- const salt = stringToBytes("Blinding KDF extrator HMAC key");
- const info = stringToBytes("Blinding KDF");
- return kdfMod(rsaPub.N, bks, salt, info);
-}
-
-/*
- * Test for malicious RSA key.
- *
- * Assuming n is an RSA modulous and r is generated using a call to
- * GNUNET_CRYPTO_kdf_mod_mpi, if gcd(r,n) != 1 then n must be a
- * malicious RSA key designed to deanomize the user.
- *
- * @param r KDF result
- * @param n RSA modulus of the public key
- */
-function rsaGcdValidate(r: bigint.BigInteger, n: bigint.BigInteger): void {
- const t = bigint.gcd(r, n);
- if (!t.equals(bigint.one)) {
- throw Error("malicious RSA public key");
- }
-}
-
-function rsaFullDomainHash(hm: Uint8Array, rsaPub: RsaPub): bigint.BigInteger {
- const info = stringToBytes("RSA-FDA FTpsW!");
- const salt = rsaPubEncode(rsaPub);
- const r = kdfMod(rsaPub.N, hm, salt, info);
- rsaGcdValidate(r, rsaPub.N);
- return r;
-}
-
-function rsaPubDecode(rsaPub: Uint8Array): RsaPub {
- const modulusLength = (rsaPub[0] << 8) | rsaPub[1];
- const exponentLength = (rsaPub[2] << 8) | rsaPub[3];
- if (4 + exponentLength + modulusLength != rsaPub.length) {
- throw Error("invalid RSA public key (format wrong)");
- }
- const modulus = rsaPub.slice(4, 4 + modulusLength);
- const exponent = rsaPub.slice(
- 4 + modulusLength,
- 4 + modulusLength + exponentLength,
- );
- const res = {
- N: loadBigInt(modulus),
- e: loadBigInt(exponent),
- };
- return res;
-}
-
-function rsaPubEncode(rsaPub: RsaPub): Uint8Array {
- const mb = rsaPub.N.toArray(256).value;
- const eb = rsaPub.e.toArray(256).value;
- const out = new Uint8Array(4 + mb.length + eb.length);
- out[0] = (mb.length >>> 8) & 0xff;
- out[1] = mb.length & 0xff;
- out[2] = (eb.length >>> 8) & 0xff;
- out[3] = eb.length & 0xff;
- out.set(mb, 4);
- out.set(eb, 4 + mb.length);
- return out;
-}
-
-export function rsaBlind(
- hm: Uint8Array,
- bks: Uint8Array,
- rsaPubEnc: Uint8Array,
-): Uint8Array {
- const rsaPub = rsaPubDecode(rsaPubEnc);
- const data = rsaFullDomainHash(hm, rsaPub);
- const r = rsaBlindingKeyDerive(rsaPub, bks);
- const r_e = r.modPow(rsaPub.e, rsaPub.N);
- const bm = r_e.multiply(data).mod(rsaPub.N);
- return new Uint8Array(bm.toArray(256).value);
-}
-
-export function rsaUnblind(
- sig: Uint8Array,
- rsaPubEnc: Uint8Array,
- bks: Uint8Array,
-): Uint8Array {
- const rsaPub = rsaPubDecode(rsaPubEnc);
- const blinded_s = loadBigInt(sig);
- const r = rsaBlindingKeyDerive(rsaPub, bks);
- const r_inv = r.modInv(rsaPub.N);
- const s = blinded_s.multiply(r_inv).mod(rsaPub.N);
- return new Uint8Array(s.toArray(256).value);
-}
-
-export function rsaVerify(
- hm: Uint8Array,
- rsaSig: Uint8Array,
- rsaPubEnc: Uint8Array,
-): boolean {
- const rsaPub = rsaPubDecode(rsaPubEnc);
- const d = rsaFullDomainHash(hm, rsaPub);
- const sig = loadBigInt(rsaSig);
- const sig_e = sig.modPow(rsaPub.e, rsaPub.N);
- return sig_e.equals(d);
-}
-
-export interface EddsaKeyPair {
- eddsaPub: Uint8Array;
- eddsaPriv: Uint8Array;
-}
-
-export interface EcdheKeyPair {
- ecdhePub: Uint8Array;
- ecdhePriv: Uint8Array;
-}
-
-export function createEddsaKeyPair(): EddsaKeyPair {
- const eddsaPriv = nacl.randomBytes(32);
- const eddsaPub = eddsaGetPublic(eddsaPriv);
- return { eddsaPriv, eddsaPub };
-}
-
-export function createEcdheKeyPair(): EcdheKeyPair {
- const ecdhePriv = nacl.randomBytes(32);
- const ecdhePub = ecdheGetPublic(ecdhePriv);
- return { ecdhePriv, ecdhePub };
-}
-
-export function createBlindingKeySecret(): Uint8Array {
- return nacl.randomBytes(32);
-}
-
-export function hash(d: Uint8Array): Uint8Array {
- return nacl.hash(d);
-}
-
-export function eddsaSign(msg: Uint8Array, eddsaPriv: Uint8Array): Uint8Array {
- const pair = nacl.sign_keyPair_fromSeed(eddsaPriv);
- return nacl.sign_detached(msg, pair.secretKey);
-}
-
-export function eddsaVerify(
- msg: Uint8Array,
- sig: Uint8Array,
- eddsaPub: Uint8Array,
-): boolean {
- return nacl.sign_detached_verify(msg, sig, eddsaPub);
-}
-
-export function createHashContext(): nacl.HashState {
- return new nacl.HashState();
-}
-
-export interface FreshCoin {
- coinPub: Uint8Array;
- coinPriv: Uint8Array;
- bks: Uint8Array;
-}
-
-export function setupRefreshPlanchet(
- secretSeed: Uint8Array,
- coinNumber: number,
-): FreshCoin {
- const info = stringToBytes("taler-coin-derivation");
- const saltArrBuf = new ArrayBuffer(4);
- const salt = new Uint8Array(saltArrBuf);
- const saltDataView = new DataView(saltArrBuf);
- saltDataView.setUint32(0, coinNumber);
- const out = kdf(64, secretSeed, salt, info);
- const coinPriv = out.slice(0, 32);
- const bks = out.slice(32, 64);
- return {
- bks,
- coinPriv,
- coinPub: eddsaGetPublic(coinPriv),
- };
-}
diff --git a/src/crypto/workers/browserWorkerEntry.ts b/src/crypto/workers/browserWorkerEntry.ts
deleted file mode 100644
index 87cb0b28b..000000000
--- a/src/crypto/workers/browserWorkerEntry.ts
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
- This file is part of TALER
- (C) 2016 GNUnet e.V.
-
- TALER is free software; you can redistribute it and/or modify it under the
- terms of the GNU General Public License as published by the Free Software
- Foundation; either version 3, or (at your option) any later version.
-
- TALER is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- A PARTICULAR PURPOSE. See the GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License along with
- TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
-*/
-
-/**
- * Web worker for crypto operations.
- */
-
-/**
- * Imports.
- */
-
-import { CryptoImplementation } from "./cryptoImplementation";
-
-const worker: Worker = (self as any) as Worker;
-
-async function handleRequest(
- operation: string,
- id: number,
- args: string[],
-): Promise<void> {
- const impl = new CryptoImplementation();
-
- if (!(operation in impl)) {
- console.error(`crypto operation '${operation}' not found`);
- return;
- }
-
- try {
- const result = (impl as any)[operation](...args);
- worker.postMessage({ result, id });
- } catch (e) {
- console.log("error during operation", e);
- return;
- }
-}
-
-worker.onmessage = (msg: MessageEvent) => {
- const args = msg.data.args;
- if (!Array.isArray(args)) {
- console.error("args must be array");
- return;
- }
- const id = msg.data.id;
- if (typeof id !== "number") {
- console.error("RPC id must be number");
- return;
- }
- const operation = msg.data.operation;
- if (typeof operation !== "string") {
- console.error("RPC operation must be string");
- return;
- }
-
- if (CryptoImplementation.enableTracing) {
- console.log("onmessage with", operation);
- }
-
- handleRequest(operation, id, args).catch((e) => {
- console.error("error in browsere worker", e);
- });
-};
diff --git a/src/crypto/workers/cryptoApi.ts b/src/crypto/workers/cryptoApi.ts
deleted file mode 100644
index 5e922ec02..000000000
--- a/src/crypto/workers/cryptoApi.ts
+++ /dev/null
@@ -1,467 +0,0 @@
-/*
- This file is part of TALER
- (C) 2016 GNUnet e.V.
-
- TALER is free software; you can redistribute it and/or modify it under the
- terms of the GNU General Public License as published by the Free Software
- Foundation; either version 3, or (at your option) any later version.
-
- TALER is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- A PARTICULAR PURPOSE. See the GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License along with
- TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
- */
-
-/**
- * API to access the Taler crypto worker thread.
- * @author Florian Dold
- */
-
-/**
- * Imports.
- */
-import { AmountJson } from "../../util/amounts";
-
-import {
- CoinRecord,
- DenominationRecord,
- RefreshSessionRecord,
- TipPlanchet,
- WireFee,
- DenominationSelectionInfo,
-} from "../../types/dbTypes";
-
-import { CryptoWorker } from "./cryptoWorker";
-
-import { RecoupRequest, CoinDepositPermission } from "../../types/talerTypes";
-
-import {
- BenchmarkResult,
- PlanchetCreationResult,
- PlanchetCreationRequest,
- DepositInfo,
-} from "../../types/walletTypes";
-
-import * as timer from "../../util/timer";
-import { Logger } from "../../util/logging";
-
-const logger = new Logger("cryptoApi.ts");
-
-/**
- * State of a crypto worker.
- */
-interface WorkerState {
- /**
- * The actual worker thread.
- */
- w: CryptoWorker | null;
-
- /**
- * Work we're currently executing or null if not busy.
- */
- currentWorkItem: WorkItem | null;
-
- /**
- * Timer to terminate the worker if it's not busy enough.
- */
- terminationTimerHandle: timer.TimerHandle | null;
-}
-
-interface WorkItem {
- operation: string;
- args: any[];
- resolve: any;
- reject: any;
-
- /**
- * Serial id to identify a matching response.
- */
- rpcId: number;
-
- /**
- * Time when the work was submitted to a (non-busy) worker thread.
- */
- startTime: number;
-}
-
-/**
- * Number of different priorities. Each priority p
- * must be 0 <= p < NUM_PRIO.
- */
-const NUM_PRIO = 5;
-
-export interface CryptoWorkerFactory {
- /**
- * Start a new worker.
- */
- startWorker(): CryptoWorker;
-
- /**
- * Query the number of workers that should be
- * run at the same time.
- */
- getConcurrency(): number;
-}
-
-export class BrowserCryptoWorkerFactory implements CryptoWorkerFactory {
- startWorker(): CryptoWorker {
- const workerCtor = Worker;
- const workerPath = "/browserWorkerEntry.js";
- return new workerCtor(workerPath) as CryptoWorker;
- }
-
- getConcurrency(): number {
- let concurrency = 2;
- try {
- // only works in the browser
- // tslint:disable-next-line:no-string-literal
- concurrency = (navigator as any)["hardwareConcurrency"];
- concurrency = Math.max(1, Math.ceil(concurrency / 2));
- } catch (e) {
- concurrency = 2;
- }
- return concurrency;
- }
-}
-
-/**
- * Crypto API that interfaces manages a background crypto thread
- * for the execution of expensive operations.
- */
-export class CryptoApi {
- private nextRpcId = 1;
- private workers: WorkerState[];
- private workQueues: WorkItem[][];
-
- private workerFactory: CryptoWorkerFactory;
-
- /**
- * Number of busy workers.
- */
- private numBusy = 0;
-
- /**
- * Did we stop accepting new requests?
- */
- private stopped = false;
-
- /**
- * Terminate all worker threads.
- */
- terminateWorkers(): void {
- for (const worker of this.workers) {
- if (worker.w) {
- logger.trace("terminating worker");
- worker.w.terminate();
- if (worker.terminationTimerHandle) {
- worker.terminationTimerHandle.clear();
- worker.terminationTimerHandle = null;
- }
- if (worker.currentWorkItem) {
- worker.currentWorkItem.reject(Error("explicitly terminated"));
- worker.currentWorkItem = null;
- }
- worker.w = null;
- }
- }
- }
-
- stop(): void {
- this.terminateWorkers();
- this.stopped = true;
- }
-
- /**
- * Start a worker (if not started) and set as busy.
- */
- wake(ws: WorkerState, work: WorkItem): void {
- if (this.stopped) {
- logger.trace("cryptoApi is stopped");
- return;
- }
- if (ws.currentWorkItem !== null) {
- throw Error("assertion failed");
- }
- ws.currentWorkItem = work;
- this.numBusy++;
- let worker: CryptoWorker;
- if (!ws.w) {
- worker = this.workerFactory.startWorker();
- worker.onmessage = (m: MessageEvent) => this.handleWorkerMessage(ws, m);
- worker.onerror = (e: ErrorEvent) => this.handleWorkerError(ws, e);
- ws.w = worker;
- } else {
- worker = ws.w;
- }
-
- const msg: any = {
- args: work.args,
- id: work.rpcId,
- operation: work.operation,
- };
- this.resetWorkerTimeout(ws);
- work.startTime = timer.performanceNow();
- setTimeout(() => worker.postMessage(msg), 0);
- }
-
- resetWorkerTimeout(ws: WorkerState): void {
- if (ws.terminationTimerHandle !== null) {
- ws.terminationTimerHandle.clear();
- ws.terminationTimerHandle = null;
- }
- const destroy = (): void => {
- // terminate worker if it's idle
- if (ws.w && ws.currentWorkItem === null) {
- ws.w.terminate();
- ws.w = null;
- }
- };
- ws.terminationTimerHandle = timer.after(15 * 1000, destroy);
- }
-
- handleWorkerError(ws: WorkerState, e: ErrorEvent): void {
- if (ws.currentWorkItem) {
- console.error(
- `error in worker during ${ws.currentWorkItem.operation}`,
- e,
- );
- } else {
- console.error("error in worker", e);
- }
- console.error(e.message);
- try {
- if (ws.w) {
- ws.w.terminate();
- ws.w = null;
- }
- } catch (e) {
- console.error(e);
- }
- if (ws.currentWorkItem !== null) {
- ws.currentWorkItem.reject(e);
- ws.currentWorkItem = null;
- this.numBusy--;
- }
- this.findWork(ws);
- }
-
- private findWork(ws: WorkerState): void {
- // try to find more work for this worker
- for (let i = 0; i < NUM_PRIO; i++) {
- const q = this.workQueues[NUM_PRIO - i - 1];
- if (q.length !== 0) {
- const work: WorkItem | undefined = q.shift();
- if (!work) {
- continue;
- }
- this.wake(ws, work);
- return;
- }
- }
- }
-
- handleWorkerMessage(ws: WorkerState, msg: MessageEvent): void {
- const id = msg.data.id;
- if (typeof id !== "number") {
- console.error("rpc id must be number");
- return;
- }
- const currentWorkItem = ws.currentWorkItem;
- ws.currentWorkItem = null;
- this.numBusy--;
- this.findWork(ws);
- if (!currentWorkItem) {
- console.error("unsolicited response from worker");
- return;
- }
- if (id !== currentWorkItem.rpcId) {
- console.error(`RPC with id ${id} has no registry entry`);
- return;
- }
-
- currentWorkItem.resolve(msg.data.result);
- }
-
- constructor(workerFactory: CryptoWorkerFactory) {
- this.workerFactory = workerFactory;
- this.workers = new Array<WorkerState>(workerFactory.getConcurrency());
-
- for (let i = 0; i < this.workers.length; i++) {
- this.workers[i] = {
- currentWorkItem: null,
- terminationTimerHandle: null,
- w: null,
- };
- }
-
- this.workQueues = [];
- for (let i = 0; i < NUM_PRIO; i++) {
- this.workQueues.push([]);
- }
- }
-
- private doRpc<T>(
- operation: string,
- priority: number,
- ...args: any[]
- ): Promise<T> {
- const p: Promise<T> = new Promise<T>((resolve, reject) => {
- const rpcId = this.nextRpcId++;
- const workItem: WorkItem = {
- operation,
- args,
- resolve,
- reject,
- rpcId,
- startTime: 0,
- };
-
- if (this.numBusy === this.workers.length) {
- const q = this.workQueues[priority];
- if (!q) {
- throw Error("assertion failed");
- }
- this.workQueues[priority].push(workItem);
- return;
- }
-
- for (const ws of this.workers) {
- if (ws.currentWorkItem !== null) {
- continue;
- }
- this.wake(ws, workItem);
- return;
- }
-
- throw Error("assertion failed");
- });
-
- return p;
- }
-
- createPlanchet(
- req: PlanchetCreationRequest,
- ): Promise<PlanchetCreationResult> {
- return this.doRpc<PlanchetCreationResult>("createPlanchet", 1, req);
- }
-
- createTipPlanchet(denom: DenominationRecord): Promise<TipPlanchet> {
- return this.doRpc<TipPlanchet>("createTipPlanchet", 1, denom);
- }
-
- hashString(str: string): Promise<string> {
- return this.doRpc<string>("hashString", 1, str);
- }
-
- hashEncoded(encodedBytes: string): Promise<string> {
- return this.doRpc<string>("hashEncoded", 1, encodedBytes);
- }
-
- isValidDenom(denom: DenominationRecord, masterPub: string): Promise<boolean> {
- return this.doRpc<boolean>("isValidDenom", 2, denom, masterPub);
- }
-
- isValidWireFee(
- type: string,
- wf: WireFee,
- masterPub: string,
- ): Promise<boolean> {
- return this.doRpc<boolean>("isValidWireFee", 2, type, wf, masterPub);
- }
-
- isValidPaymentSignature(
- sig: string,
- contractHash: string,
- merchantPub: string,
- ): Promise<boolean> {
- return this.doRpc<boolean>(
- "isValidPaymentSignature",
- 1,
- sig,
- contractHash,
- merchantPub,
- );
- }
-
- signDepositPermission(
- depositInfo: DepositInfo,
- ): Promise<CoinDepositPermission> {
- return this.doRpc<CoinDepositPermission>(
- "signDepositPermission",
- 3,
- depositInfo,
- );
- }
-
- createEddsaKeypair(): Promise<{ priv: string; pub: string }> {
- return this.doRpc<{ priv: string; pub: string }>("createEddsaKeypair", 1);
- }
-
- rsaUnblind(sig: string, bk: string, pk: string): Promise<string> {
- return this.doRpc<string>("rsaUnblind", 4, sig, bk, pk);
- }
-
- rsaVerify(hm: string, sig: string, pk: string): Promise<boolean> {
- return this.doRpc<boolean>("rsaVerify", 4, hm, sig, pk);
- }
-
- isValidWireAccount(
- paytoUri: string,
- sig: string,
- masterPub: string,
- ): Promise<boolean> {
- return this.doRpc<boolean>(
- "isValidWireAccount",
- 4,
- paytoUri,
- sig,
- masterPub,
- );
- }
-
- createRecoupRequest(coin: CoinRecord): Promise<RecoupRequest> {
- return this.doRpc<RecoupRequest>("createRecoupRequest", 1, coin);
- }
-
- createRefreshSession(
- exchangeBaseUrl: string,
- kappa: number,
- meltCoin: CoinRecord,
- newCoinDenoms: DenominationSelectionInfo,
- meltFee: AmountJson,
- ): Promise<RefreshSessionRecord> {
- return this.doRpc<RefreshSessionRecord>(
- "createRefreshSession",
- 4,
- exchangeBaseUrl,
- kappa,
- meltCoin,
- newCoinDenoms,
- meltFee,
- );
- }
-
- signCoinLink(
- oldCoinPriv: string,
- newDenomHash: string,
- oldCoinPub: string,
- transferPub: string,
- coinEv: string,
- ): Promise<string> {
- return this.doRpc<string>(
- "signCoinLink",
- 4,
- oldCoinPriv,
- newDenomHash,
- oldCoinPub,
- transferPub,
- coinEv,
- );
- }
-
- benchmark(repetitions: number): Promise<BenchmarkResult> {
- return this.doRpc<BenchmarkResult>("benchmark", 1, repetitions);
- }
-}
diff --git a/src/crypto/workers/cryptoImplementation.ts b/src/crypto/workers/cryptoImplementation.ts
deleted file mode 100644
index 979fe41d8..000000000
--- a/src/crypto/workers/cryptoImplementation.ts
+++ /dev/null
@@ -1,581 +0,0 @@
-/*
- This file is part of GNU Taler
- (C) 2019-2020 Taler Systems SA
-
- TALER is free software; you can redistribute it and/or modify it under the
- terms of the GNU General Public License as published by the Free Software
- Foundation; either version 3, or (at your option) any later version.
-
- TALER is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- A PARTICULAR PURPOSE. See the GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License along with
- TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
- */
-
-/**
- * Synchronous implementation of crypto-related functions for the wallet.
- *
- * The functionality is parameterized over an Emscripten environment.
- *
- * @author Florian Dold <dold@taler.net>
- */
-
-/**
- * Imports.
- */
-
-import {
- CoinRecord,
- DenominationRecord,
- RefreshPlanchetRecord,
- RefreshSessionRecord,
- TipPlanchet,
- WireFee,
- CoinSourceType,
- DenominationSelectionInfo,
-} from "../../types/dbTypes";
-
-import { CoinDepositPermission, RecoupRequest } from "../../types/talerTypes";
-import {
- BenchmarkResult,
- PlanchetCreationResult,
- PlanchetCreationRequest,
- DepositInfo,
-} from "../../types/walletTypes";
-import { AmountJson, Amounts } from "../../util/amounts";
-import * as timer from "../../util/timer";
-import {
- encodeCrock,
- decodeCrock,
- createEddsaKeyPair,
- createBlindingKeySecret,
- hash,
- rsaBlind,
- eddsaVerify,
- eddsaSign,
- rsaUnblind,
- stringToBytes,
- createHashContext,
- createEcdheKeyPair,
- keyExchangeEcdheEddsa,
- setupRefreshPlanchet,
- rsaVerify,
-} from "../talerCrypto";
-import { randomBytes } from "../primitives/nacl-fast";
-import { kdf } from "../primitives/kdf";
-import {
- Timestamp,
- getTimestampNow,
- timestampTruncateToSecond,
-} from "../../util/time";
-
-enum SignaturePurpose {
- WALLET_RESERVE_WITHDRAW = 1200,
- WALLET_COIN_DEPOSIT = 1201,
- MASTER_DENOMINATION_KEY_VALIDITY = 1025,
- MASTER_WIRE_FEES = 1028,
- MASTER_WIRE_DETAILS = 1030,
- WALLET_COIN_MELT = 1202,
- TEST = 4242,
- MERCHANT_PAYMENT_OK = 1104,
- WALLET_COIN_RECOUP = 1203,
- WALLET_COIN_LINK = 1204,
- EXCHANGE_CONFIRM_RECOUP = 1039,
- EXCHANGE_CONFIRM_RECOUP_REFRESH = 1041,
-}
-
-function amountToBuffer(amount: AmountJson): Uint8Array {
- const buffer = new ArrayBuffer(8 + 4 + 12);
- const dvbuf = new DataView(buffer);
- const u8buf = new Uint8Array(buffer);
- const te = new TextEncoder();
- const curr = te.encode(amount.currency);
- dvbuf.setBigUint64(0, BigInt(amount.value));
- dvbuf.setUint32(8, amount.fraction);
- u8buf.set(curr, 8 + 4);
-
- return u8buf;
-}
-
-function timestampRoundedToBuffer(ts: Timestamp): Uint8Array {
- const b = new ArrayBuffer(8);
- const v = new DataView(b);
- const tsRounded = timestampTruncateToSecond(ts);
- const s = BigInt(tsRounded.t_ms) * BigInt(1000);
- v.setBigUint64(0, s);
- return new Uint8Array(b);
-}
-
-class SignaturePurposeBuilder {
- private chunks: Uint8Array[] = [];
-
- constructor(private purposeNum: number) {}
-
- put(bytes: Uint8Array): SignaturePurposeBuilder {
- this.chunks.push(Uint8Array.from(bytes));
- return this;
- }
-
- build(): Uint8Array {
- let payloadLen = 0;
- for (const c of this.chunks) {
- payloadLen += c.byteLength;
- }
- const buf = new ArrayBuffer(4 + 4 + payloadLen);
- const u8buf = new Uint8Array(buf);
- let p = 8;
- for (const c of this.chunks) {
- u8buf.set(c, p);
- p += c.byteLength;
- }
- const dvbuf = new DataView(buf);
- dvbuf.setUint32(0, payloadLen + 4 + 4);
- dvbuf.setUint32(4, this.purposeNum);
- return u8buf;
- }
-}
-
-function buildSigPS(purposeNum: number): SignaturePurposeBuilder {
- return new SignaturePurposeBuilder(purposeNum);
-}
-
-export class CryptoImplementation {
- static enableTracing = false;
-
- /**
- * Create a pre-coin of the given denomination to be withdrawn from then given
- * reserve.
- */
- createPlanchet(req: PlanchetCreationRequest): PlanchetCreationResult {
- const reservePub = decodeCrock(req.reservePub);
- const reservePriv = decodeCrock(req.reservePriv);
- const denomPub = decodeCrock(req.denomPub);
- const coinKeyPair = createEddsaKeyPair();
- const blindingFactor = createBlindingKeySecret();
- const coinPubHash = hash(coinKeyPair.eddsaPub);
- const ev = rsaBlind(coinPubHash, blindingFactor, denomPub);
- const amountWithFee = Amounts.add(req.value, req.feeWithdraw).amount;
- const denomPubHash = hash(denomPub);
- const evHash = hash(ev);
-
- const withdrawRequest = buildSigPS(SignaturePurpose.WALLET_RESERVE_WITHDRAW)
- .put(reservePub)
- .put(amountToBuffer(amountWithFee))
- .put(denomPubHash)
- .put(evHash)
- .build();
-
- const sig = eddsaSign(withdrawRequest, reservePriv);
-
- const planchet: PlanchetCreationResult = {
- blindingKey: encodeCrock(blindingFactor),
- coinEv: encodeCrock(ev),
- coinPriv: encodeCrock(coinKeyPair.eddsaPriv),
- coinPub: encodeCrock(coinKeyPair.eddsaPub),
- coinValue: req.value,
- denomPub: encodeCrock(denomPub),
- denomPubHash: encodeCrock(denomPubHash),
- reservePub: encodeCrock(reservePub),
- withdrawSig: encodeCrock(sig),
- coinEvHash: encodeCrock(evHash),
- };
- return planchet;
- }
-
- /**
- * Create a planchet used for tipping, including the private keys.
- */
- createTipPlanchet(denom: DenominationRecord): TipPlanchet {
- const denomPub = decodeCrock(denom.denomPub);
- const coinKeyPair = createEddsaKeyPair();
- const blindingFactor = createBlindingKeySecret();
- const coinPubHash = hash(coinKeyPair.eddsaPub);
- const ev = rsaBlind(coinPubHash, blindingFactor, denomPub);
-
- const tipPlanchet: TipPlanchet = {
- blindingKey: encodeCrock(blindingFactor),
- coinEv: encodeCrock(ev),
- coinPriv: encodeCrock(coinKeyPair.eddsaPriv),
- coinPub: encodeCrock(coinKeyPair.eddsaPub),
- coinValue: denom.value,
- denomPub: encodeCrock(denomPub),
- denomPubHash: encodeCrock(hash(denomPub)),
- };
- return tipPlanchet;
- }
-
- /**
- * Create and sign a message to recoup a coin.
- */
- createRecoupRequest(coin: CoinRecord): RecoupRequest {
- const p = buildSigPS(SignaturePurpose.WALLET_COIN_RECOUP)
- .put(decodeCrock(coin.coinPub))
- .put(decodeCrock(coin.denomPubHash))
- .put(decodeCrock(coin.blindingKey))
- .build();
-
- const coinPriv = decodeCrock(coin.coinPriv);
- const coinSig = eddsaSign(p, coinPriv);
- const paybackRequest: RecoupRequest = {
- coin_blind_key_secret: coin.blindingKey,
- coin_pub: coin.coinPub,
- coin_sig: encodeCrock(coinSig),
- denom_pub_hash: coin.denomPubHash,
- denom_sig: coin.denomSig,
- refreshed: coin.coinSource.type === CoinSourceType.Refresh,
- };
- return paybackRequest;
- }
-
- /**
- * Check if a payment signature is valid.
- */
- isValidPaymentSignature(
- sig: string,
- contractHash: string,
- merchantPub: string,
- ): boolean {
- const p = buildSigPS(SignaturePurpose.MERCHANT_PAYMENT_OK)
- .put(decodeCrock(contractHash))
- .build();
- const sigBytes = decodeCrock(sig);
- const pubBytes = decodeCrock(merchantPub);
- return eddsaVerify(p, sigBytes, pubBytes);
- }
-
- /**
- * Check if a wire fee is correctly signed.
- */
- isValidWireFee(type: string, wf: WireFee, masterPub: string): boolean {
- const p = buildSigPS(SignaturePurpose.MASTER_WIRE_FEES)
- .put(hash(stringToBytes(type + "\0")))
- .put(timestampRoundedToBuffer(wf.startStamp))
- .put(timestampRoundedToBuffer(wf.endStamp))
- .put(amountToBuffer(wf.wireFee))
- .put(amountToBuffer(wf.closingFee))
- .build();
- const sig = decodeCrock(wf.sig);
- const pub = decodeCrock(masterPub);
- return eddsaVerify(p, sig, pub);
- }
-
- /**
- * Check if the signature of a denomination is valid.
- */
- isValidDenom(denom: DenominationRecord, masterPub: string): boolean {
- const p = buildSigPS(SignaturePurpose.MASTER_DENOMINATION_KEY_VALIDITY)
- .put(decodeCrock(masterPub))
- .put(timestampRoundedToBuffer(denom.stampStart))
- .put(timestampRoundedToBuffer(denom.stampExpireWithdraw))
- .put(timestampRoundedToBuffer(denom.stampExpireDeposit))
- .put(timestampRoundedToBuffer(denom.stampExpireLegal))
- .put(amountToBuffer(denom.value))
- .put(amountToBuffer(denom.feeWithdraw))
- .put(amountToBuffer(denom.feeDeposit))
- .put(amountToBuffer(denom.feeRefresh))
- .put(amountToBuffer(denom.feeRefund))
- .put(decodeCrock(denom.denomPubHash))
- .build();
- const sig = decodeCrock(denom.masterSig);
- const pub = decodeCrock(masterPub);
- return eddsaVerify(p, sig, pub);
- }
-
- isValidWireAccount(
- paytoUri: string,
- sig: string,
- masterPub: string,
- ): boolean {
- const h = kdf(
- 64,
- stringToBytes("exchange-wire-signature"),
- stringToBytes(paytoUri + "\0"),
- new Uint8Array(0),
- );
- const p = buildSigPS(SignaturePurpose.MASTER_WIRE_DETAILS).put(h).build();
- return eddsaVerify(p, decodeCrock(sig), decodeCrock(masterPub));
- }
-
- /**
- * Create a new EdDSA key pair.
- */
- createEddsaKeypair(): { priv: string; pub: string } {
- const pair = createEddsaKeyPair();
- return {
- priv: encodeCrock(pair.eddsaPriv),
- pub: encodeCrock(pair.eddsaPub),
- };
- }
-
- /**
- * Unblind a blindly signed value.
- */
- rsaUnblind(blindedSig: string, bk: string, pk: string): string {
- const denomSig = rsaUnblind(
- decodeCrock(blindedSig),
- decodeCrock(pk),
- decodeCrock(bk),
- );
- return encodeCrock(denomSig);
- }
-
- /**
- * Unblind a blindly signed value.
- */
- rsaVerify(hm: string, sig: string, pk: string): boolean {
- return rsaVerify(hash(decodeCrock(hm)), decodeCrock(sig), decodeCrock(pk));
- }
-
- /**
- * Generate updated coins (to store in the database)
- * and deposit permissions for each given coin.
- */
- signDepositPermission(depositInfo: DepositInfo): CoinDepositPermission {
- const d = buildSigPS(SignaturePurpose.WALLET_COIN_DEPOSIT)
- .put(decodeCrock(depositInfo.contractTermsHash))
- .put(decodeCrock(depositInfo.wireInfoHash))
- .put(decodeCrock(depositInfo.denomPubHash))
- .put(timestampRoundedToBuffer(depositInfo.timestamp))
- .put(timestampRoundedToBuffer(depositInfo.refundDeadline))
- .put(amountToBuffer(depositInfo.spendAmount))
- .put(amountToBuffer(depositInfo.feeDeposit))
- .put(decodeCrock(depositInfo.merchantPub))
- .put(decodeCrock(depositInfo.coinPub))
- .build();
- const coinSig = eddsaSign(d, decodeCrock(depositInfo.coinPriv));
-
- const s: CoinDepositPermission = {
- coin_pub: depositInfo.coinPub,
- coin_sig: encodeCrock(coinSig),
- contribution: Amounts.stringify(depositInfo.spendAmount),
- h_denom: depositInfo.denomPubHash,
- exchange_url: depositInfo.exchangeBaseUrl,
- ub_sig: depositInfo.denomSig,
- };
- return s;
- }
-
- /**
- * Create a new refresh session.
- */
- createRefreshSession(
- exchangeBaseUrl: string,
- kappa: number,
- meltCoin: CoinRecord,
- newCoinDenoms: DenominationSelectionInfo,
- meltFee: AmountJson,
- ): RefreshSessionRecord {
- const currency = newCoinDenoms.selectedDenoms[0].denom.value.currency;
- let valueWithFee = Amounts.getZero(currency);
-
- for (const ncd of newCoinDenoms.selectedDenoms) {
- const t = Amounts.add(ncd.denom.value, ncd.denom.feeWithdraw).amount;
- valueWithFee = Amounts.add(
- valueWithFee,
- Amounts.mult(t, ncd.count).amount,
- ).amount;
- }
-
- // melt fee
- valueWithFee = Amounts.add(valueWithFee, meltFee).amount;
-
- const sessionHc = createHashContext();
-
- const transferPubs: string[] = [];
- const transferPrivs: string[] = [];
-
- const planchetsForGammas: RefreshPlanchetRecord[][] = [];
-
- for (let i = 0; i < kappa; i++) {
- const transferKeyPair = createEcdheKeyPair();
- sessionHc.update(transferKeyPair.ecdhePub);
- transferPrivs.push(encodeCrock(transferKeyPair.ecdhePriv));
- transferPubs.push(encodeCrock(transferKeyPair.ecdhePub));
- }
-
- for (const denomSel of newCoinDenoms.selectedDenoms) {
- for (let i = 0; i < denomSel.count; i++) {
- const r = decodeCrock(denomSel.denom.denomPub);
- sessionHc.update(r);
- }
- }
-
- sessionHc.update(decodeCrock(meltCoin.coinPub));
- sessionHc.update(amountToBuffer(valueWithFee));
-
- for (let i = 0; i < kappa; i++) {
- const planchets: RefreshPlanchetRecord[] = [];
- for (let j = 0; j < newCoinDenoms.selectedDenoms.length; j++) {
- const denomSel = newCoinDenoms.selectedDenoms[j];
- for (let k = 0; k < denomSel.count; k++) {
- const coinNumber = planchets.length;
- const transferPriv = decodeCrock(transferPrivs[i]);
- const oldCoinPub = decodeCrock(meltCoin.coinPub);
- const transferSecret = keyExchangeEcdheEddsa(
- transferPriv,
- oldCoinPub,
- );
- const fresh = setupRefreshPlanchet(transferSecret, coinNumber);
- const coinPriv = fresh.coinPriv;
- const coinPub = fresh.coinPub;
- const blindingFactor = fresh.bks;
- const pubHash = hash(coinPub);
- const denomPub = decodeCrock(denomSel.denom.denomPub);
- const ev = rsaBlind(pubHash, blindingFactor, denomPub);
- const planchet: RefreshPlanchetRecord = {
- blindingKey: encodeCrock(blindingFactor),
- coinEv: encodeCrock(ev),
- privateKey: encodeCrock(coinPriv),
- publicKey: encodeCrock(coinPub),
- };
- planchets.push(planchet);
- sessionHc.update(ev);
- }
- }
- planchetsForGammas.push(planchets);
- }
-
- const sessionHash = sessionHc.finish();
-
- const confirmData = buildSigPS(SignaturePurpose.WALLET_COIN_MELT)
- .put(sessionHash)
- .put(decodeCrock(meltCoin.denomPubHash))
- .put(amountToBuffer(valueWithFee))
- .put(amountToBuffer(meltFee))
- .put(decodeCrock(meltCoin.coinPub))
- .build();
-
- const confirmSig = eddsaSign(confirmData, decodeCrock(meltCoin.coinPriv));
-
- let valueOutput = Amounts.getZero(currency);
- for (const denomSel of newCoinDenoms.selectedDenoms) {
- const denom = denomSel.denom;
- for (let i = 0; i < denomSel.count; i++) {
- valueOutput = Amounts.add(valueOutput, denom.value).amount;
- }
- }
-
- const newDenoms: string[] = [];
- const newDenomHashes: string[] = [];
-
- for (const denomSel of newCoinDenoms.selectedDenoms) {
- const denom = denomSel.denom;
- for (let i = 0; i < denomSel.count; i++) {
- newDenoms.push(denom.denomPub);
- newDenomHashes.push(denom.denomPubHash);
- }
- }
-
- const refreshSession: RefreshSessionRecord = {
- confirmSig: encodeCrock(confirmSig),
- exchangeBaseUrl,
- hash: encodeCrock(sessionHash),
- meltCoinPub: meltCoin.coinPub,
- newDenomHashes,
- newDenoms,
- norevealIndex: undefined,
- planchetsForGammas: planchetsForGammas,
- transferPrivs,
- transferPubs,
- amountRefreshOutput: valueOutput,
- amountRefreshInput: valueWithFee,
- timestampCreated: getTimestampNow(),
- finishedTimestamp: undefined,
- lastError: undefined,
- };
-
- return refreshSession;
- }
-
- /**
- * Hash a string including the zero terminator.
- */
- hashString(str: string): string {
- const ts = new TextEncoder();
- const b = ts.encode(str + "\0");
- return encodeCrock(hash(b));
- }
-
- /**
- * Hash a crockford encoded value.
- */
- hashEncoded(encodedBytes: string): string {
- return encodeCrock(hash(decodeCrock(encodedBytes)));
- }
-
- signCoinLink(
- oldCoinPriv: string,
- newDenomHash: string,
- oldCoinPub: string,
- transferPub: string,
- coinEv: string,
- ): string {
- const coinEvHash = hash(decodeCrock(coinEv));
- const coinLink = buildSigPS(SignaturePurpose.WALLET_COIN_LINK)
- .put(decodeCrock(newDenomHash))
- .put(decodeCrock(oldCoinPub))
- .put(decodeCrock(transferPub))
- .put(coinEvHash)
- .build();
- const coinPriv = decodeCrock(oldCoinPriv);
- const sig = eddsaSign(coinLink, coinPriv);
- return encodeCrock(sig);
- }
-
- benchmark(repetitions: number): BenchmarkResult {
- let time_hash = 0;
- for (let i = 0; i < repetitions; i++) {
- const start = timer.performanceNow();
- this.hashString("hello world");
- time_hash += timer.performanceNow() - start;
- }
-
- let time_hash_big = 0;
- for (let i = 0; i < repetitions; i++) {
- const ba = randomBytes(4096);
- const start = timer.performanceNow();
- hash(ba);
- time_hash_big += timer.performanceNow() - start;
- }
-
- let time_eddsa_create = 0;
- for (let i = 0; i < repetitions; i++) {
- const start = timer.performanceNow();
- createEddsaKeyPair();
- time_eddsa_create += timer.performanceNow() - start;
- }
-
- let time_eddsa_sign = 0;
- const p = randomBytes(4096);
-
- const pair = createEddsaKeyPair();
-
- for (let i = 0; i < repetitions; i++) {
- const start = timer.performanceNow();
- eddsaSign(p, pair.eddsaPriv);
- time_eddsa_sign += timer.performanceNow() - start;
- }
-
- const sig = eddsaSign(p, pair.eddsaPriv);
-
- let time_eddsa_verify = 0;
- for (let i = 0; i < repetitions; i++) {
- const start = timer.performanceNow();
- eddsaVerify(p, sig, pair.eddsaPub);
- time_eddsa_verify += timer.performanceNow() - start;
- }
-
- return {
- repetitions,
- time: {
- hash_small: time_hash,
- hash_big: time_hash_big,
- eddsa_create: time_eddsa_create,
- eddsa_sign: time_eddsa_sign,
- eddsa_verify: time_eddsa_verify,
- },
- };
- }
-}
diff --git a/src/crypto/workers/cryptoWorker.ts b/src/crypto/workers/cryptoWorker.ts
deleted file mode 100644
index 9f3ee6f50..000000000
--- a/src/crypto/workers/cryptoWorker.ts
+++ /dev/null
@@ -1,8 +0,0 @@
-export interface CryptoWorker {
- postMessage(message: any): void;
-
- terminate(): void;
-
- onmessage: ((m: any) => void) | undefined;
- onerror: ((m: any) => void) | undefined;
-}
diff --git a/src/crypto/workers/nodeThreadWorker.ts b/src/crypto/workers/nodeThreadWorker.ts
deleted file mode 100644
index 6c9dfc569..000000000
--- a/src/crypto/workers/nodeThreadWorker.ts
+++ /dev/null
@@ -1,183 +0,0 @@
-/*
- This file is part of TALER
- (C) 2016 GNUnet e.V.
-
- TALER is free software; you can redistribute it and/or modify it under the
- terms of the GNU General Public License as published by the Free Software
- Foundation; either version 3, or (at your option) any later version.
-
- TALER is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- A PARTICULAR PURPOSE. See the GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License along with
- TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
- */
-
-/**
- * Imports
- */
-import { CryptoWorkerFactory } from "./cryptoApi";
-import { CryptoWorker } from "./cryptoWorker";
-import os from "os";
-import { CryptoImplementation } from "./cryptoImplementation";
-
-const f = __filename;
-
-const workerCode = `
- // Try loading the glue library for Android
- try {
- require("akono");
- } catch (e) {
- // Probably we're not on Android ...
- }
- const worker_threads = require('worker_threads');
- const parentPort = worker_threads.parentPort;
- let tw;
- try {
- tw = require("${f}");
- } catch (e) {
- console.log("could not load from ${f}");
- }
- if (!tw) {
- try {
- tw = require("taler-wallet-android");
- } catch (e) {
- console.log("could not load taler-wallet-android either");
- throw e;
- }
- }
- parentPort.on("message", tw.handleWorkerMessage);
- parentPort.on("error", tw.handleWorkerError);
-`;
-
-/**
- * This function is executed in the worker thread to handle
- * a message.
- */
-export function handleWorkerMessage(msg: any): void {
- const args = msg.args;
- if (!Array.isArray(args)) {
- console.error("args must be array");
- return;
- }
- const id = msg.id;
- if (typeof id !== "number") {
- console.error("RPC id must be number");
- return;
- }
- const operation = msg.operation;
- if (typeof operation !== "string") {
- console.error("RPC operation must be string");
- return;
- }
-
- const handleRequest = async (): Promise<void> => {
- const impl = new CryptoImplementation();
-
- if (!(operation in impl)) {
- console.error(`crypto operation '${operation}' not found`);
- return;
- }
-
- try {
- const result = (impl as any)[operation](...args);
- // eslint-disable-next-line @typescript-eslint/no-var-requires
- const worker_threads = require("worker_threads");
- const p = worker_threads.parentPort;
- worker_threads.parentPort?.postMessage;
- if (p) {
- p.postMessage({ data: { result, id } });
- } else {
- console.error("parent port not available (not running in thread?");
- }
- } catch (e) {
- console.error("error during operation", e);
- return;
- }
- };
-
- handleRequest().catch((e) => {
- console.error("error in node worker", e);
- });
-}
-
-export function handleWorkerError(e: Error): void {
- console.log("got error from worker", e);
-}
-
-export class NodeThreadCryptoWorkerFactory implements CryptoWorkerFactory {
- startWorker(): CryptoWorker {
- if (typeof require === "undefined") {
- throw Error("cannot make worker, require(...) not defined");
- }
- return new NodeThreadCryptoWorker();
- }
-
- getConcurrency(): number {
- return Math.max(1, os.cpus().length - 1);
- }
-}
-
-/**
- * Worker implementation that uses node subprocesses.
- */
-class NodeThreadCryptoWorker implements CryptoWorker {
- /**
- * Function to be called when we receive a message from the worker thread.
- */
- onmessage: undefined | ((m: any) => void);
-
- /**
- * Function to be called when we receive an error from the worker thread.
- */
- onerror: undefined | ((m: any) => void);
-
- private nodeWorker: import("worker_threads").Worker;
-
- constructor() {
- // eslint-disable-next-line @typescript-eslint/no-var-requires
- const worker_threads = require("worker_threads");
- this.nodeWorker = new worker_threads.Worker(workerCode, { eval: true });
- this.nodeWorker.on("error", (err: Error) => {
- console.error("error in node worker:", err);
- if (this.onerror) {
- this.onerror(err);
- }
- });
- this.nodeWorker.on("message", (v: any) => {
- if (this.onmessage) {
- this.onmessage(v);
- }
- });
- this.nodeWorker.unref();
- }
-
- /**
- * Add an event listener for either an "error" or "message" event.
- */
- addEventListener(event: "message" | "error", fn: (x: any) => void): void {
- switch (event) {
- case "message":
- this.onmessage = fn;
- break;
- case "error":
- this.onerror = fn;
- break;
- }
- }
-
- /**
- * Send a message to the worker thread.
- */
- postMessage(msg: any): void {
- this.nodeWorker.postMessage(msg);
- }
-
- /**
- * Forcibly terminate the worker thread.
- */
- terminate(): void {
- this.nodeWorker.terminate();
- }
-}
diff --git a/src/crypto/workers/synchronousWorker.ts b/src/crypto/workers/synchronousWorker.ts
deleted file mode 100644
index 2cc740975..000000000
--- a/src/crypto/workers/synchronousWorker.ts
+++ /dev/null
@@ -1,137 +0,0 @@
-/*
- This file is part of GNU Taler
- (C) 2019 GNUnet e.V.
-
- GNU Taler is free software; you can redistribute it and/or modify it under the
- terms of the GNU General Public License as published by the Free Software
- Foundation; either version 3, or (at your option) any later version.
-
- GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- A PARTICULAR PURPOSE. See the GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License along with
- GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
- */
-
-import { CryptoImplementation } from "./cryptoImplementation";
-
-import { CryptoWorkerFactory } from "./cryptoApi";
-import { CryptoWorker } from "./cryptoWorker";
-
-/**
- * The synchronous crypto worker produced by this factory doesn't run in the
- * background, but actually blocks the caller until the operation is done.
- */
-export class SynchronousCryptoWorkerFactory implements CryptoWorkerFactory {
- startWorker(): CryptoWorker {
- if (typeof require === "undefined") {
- throw Error("cannot make worker, require(...) not defined");
- }
- const workerCtor = require("./synchronousWorker").SynchronousCryptoWorker;
- return new workerCtor();
- }
-
- getConcurrency(): number {
- return 1;
- }
-}
-
-/**
- * Worker implementation that uses node subprocesses.
- */
-export class SynchronousCryptoWorker {
- /**
- * Function to be called when we receive a message from the worker thread.
- */
- onmessage: undefined | ((m: any) => void);
-
- /**
- * Function to be called when we receive an error from the worker thread.
- */
- onerror: undefined | ((m: any) => void);
-
- constructor() {
- this.onerror = undefined;
- this.onmessage = undefined;
- }
-
- /**
- * Add an event listener for either an "error" or "message" event.
- */
- addEventListener(event: "message" | "error", fn: (x: any) => void): void {
- switch (event) {
- case "message":
- this.onmessage = fn;
- break;
- case "error":
- this.onerror = fn;
- break;
- }
- }
-
- private dispatchMessage(msg: any): void {
- if (this.onmessage) {
- this.onmessage({ data: msg });
- }
- }
-
- private async handleRequest(
- operation: string,
- id: number,
- args: string[],
- ): Promise<void> {
- const impl = new CryptoImplementation();
-
- if (!(operation in impl)) {
- console.error(`crypto operation '${operation}' not found`);
- return;
- }
-
- let result: any;
- try {
- result = (impl as any)[operation](...args);
- } catch (e) {
- console.log("error during operation", e);
- return;
- }
-
- try {
- setTimeout(() => this.dispatchMessage({ result, id }), 0);
- } catch (e) {
- console.log("got error during dispatch", e);
- }
- }
-
- /**
- * Send a message to the worker thread.
- */
- postMessage(msg: any): void {
- const args = msg.args;
- if (!Array.isArray(args)) {
- console.error("args must be array");
- return;
- }
- const id = msg.id;
- if (typeof id !== "number") {
- console.error("RPC id must be number");
- return;
- }
- const operation = msg.operation;
- if (typeof operation !== "string") {
- console.error("RPC operation must be string");
- return;
- }
-
- this.handleRequest(operation, id, args).catch((e) => {
- console.error("Error while handling crypto request:", e);
- });
- }
-
- /**
- * Forcibly terminate the worker thread.
- */
- terminate(): void {
- // This is a no-op.
- }
-}