diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/crypto/cryptoWorker.ts | 20 | ||||
-rw-r--r-- | src/crypto/emscInterface.ts | 379 | ||||
-rw-r--r-- | src/crypto/emscLoader.d.ts | 8 | ||||
-rw-r--r-- | src/crypto/emscLoader.js | 29 |
4 files changed, 281 insertions, 155 deletions
diff --git a/src/crypto/cryptoWorker.ts b/src/crypto/cryptoWorker.ts index 7cec5f284..3e71794b4 100644 --- a/src/crypto/cryptoWorker.ts +++ b/src/crypto/cryptoWorker.ts @@ -53,6 +53,8 @@ import { import { canonicalJson } from "../helpers"; +import * as emscLoader from "./emscLoader"; + import { Amount, EddsaPublicKey, @@ -580,6 +582,20 @@ worker.onmessage = (msg: MessageEvent) => { console.error(`unknown operation: '${msg.data.operation}'`); return; } - const res = f(...msg.data.args); - worker.postMessage({result: res, id: msg.data.id}); + + console.log("onmessage with", msg.data.operation); + console.log("foo"); + + emscLoader.getLib().then((p) => { + const lib = p.lib; + if (!native.isInitialized()) { + console.log("initializing emscripten for then first time with lib"); + native.initialize(lib); + } + + console.log("about to execute", msg.data.operation); + const res = f(...msg.data.args); + console.log("finished executing", msg.data.operation); + worker.postMessage({ result: res, id: msg.data.id }); + }); }; diff --git a/src/crypto/emscInterface.ts b/src/crypto/emscInterface.ts index 0662f4a71..eae8ee5c0 100644 --- a/src/crypto/emscInterface.ts +++ b/src/crypto/emscInterface.ts @@ -28,9 +28,34 @@ */ import { AmountJson } from "../amounts"; -import { EmscFunGen, getLib } from "./emscLoader"; +import { EmscFunGen, EmscLib } from "./emscLoader"; -const emscLib = getLib(); + +// Will be set only after initialization. +let maybeEmscEnv: EmscEnvironment | undefined = undefined; + +export function isInitialized() { + return !!maybeEmscEnv; +} + + +export function initialize(lib: EmscLib) { + if (!lib) { + throw Error("library must be object"); + } + if (maybeEmscEnv) { + throw Error("emsc lib already initialized"); + } + maybeEmscEnv = new EmscEnvironment(lib); +} + + +function emsc() { + if (maybeEmscEnv) { + return maybeEmscEnv; + } + throw Error("cannot use taler emscripten before initialization"); +} /** @@ -41,75 +66,131 @@ const PTR_SIZE = 4; const GNUNET_OK = 1; +interface EmscFunctions { + amount_add(a1: number, a2: number, a3: number): number; + amount_cmp(a1: number, a2: number): number; + amount_get_zero(a1: string, a2: number): number; + amount_hton(a1: number, a2: number): void; + amount_normalize(a1: number): void; + amount_ntoh(a1: number, a2: number): void; + amount_subtract(a1: number, a2: number, a3: number): number; + ecdh_eddsa(a1: number, a2: number, a3: number): number; + eddsa_sign(a1: number, a2: number, a3: number): number; + eddsa_verify(a1: number, a2: number, a3: number, a4: number): number; + free(ptr: number): void; + get_currency(a: number): string; + get_fraction(a: number): number; + get_value(a: number): number; + hash(a1: number, a2: number, a3: number): void; + hash_context_abort(ctx: number): void; + hash_context_finish(a1: number, a2: number): void; + hash_context_read(a1: number, a2: number, a3: number): void; + hash_create_random(a1: number, a2: number): void; + memmove(a1: number, a2: number, a3: number): number; + random_block(a1: number, a2: number, a3: number): void; + rsa_blinding_key_free(a1: number): void; + rsa_public_key_free(a1: number): void; + rsa_signature_free(a1: number): void; + setup_fresh_coin(a1: number, a2: number, a3: number): void; + string_to_data(a1: number, a2: number, a3: number, a4: number): number; +} -/** - * Get an emscripten-compiled function. - */ -const getEmsc: EmscFunGen = (name: string, ret: any, argTypes: any[]) => { - return (...args: any[]) => { - return emscLib.ccall(name, ret, argTypes, args); - }; -}; +interface EmscAllocFunctions { + data_to_string_alloc(a1: number, a2: number): number; + ecdhe_key_create(): number; + ecdhe_public_key_from_private(a1: number): number; + ecdsa_key_create(): number; + ecdsa_public_key_from_private(a1: number): number; + eddsa_key_create(): number; + eddsa_public_key_from_private(a1: number): number; + get_amount(a1: number, a2: number, a22: number, a3: string): number; + hash_context_start(): number; + malloc(size: number): number; + purpose_create(a1: number, a2: number, a3: number): number; + rsa_blind(a1: number, a2: number, a3: number, a4: number, a5: number): number; + rsa_blinding_key_create(a1: number): number; + rsa_blinding_key_decode(a1: number, a2: number): number; + rsa_blinding_key_encode(a1: number, a2: number): number; + rsa_public_key_decode(a1: number, a2: number): number; + rsa_public_key_encode(a1: number, a2: number): number; + rsa_signature_encode(a1: number, a2: number): number; + rsa_signature_decode(a1: number, a2: number): number; + rsa_unblind(a1: number, a2: number, a3: number): number; +} +class EmscEnvironment { -/** - * Wrapped emscripten functions that do not allocate any memory. - */ -const emsc = { - amount_add: getEmsc("TALER_amount_add", "number", ["number", "number", "number"]), - amount_cmp: getEmsc("TALER_amount_cmp", "number", ["number", "number"]), - amount_get_zero: getEmsc("TALER_amount_get_zero", "number", ["string", "number"]), - amount_hton: getEmsc("TALER_amount_hton", "void", ["number", "number"]), - amount_normalize: getEmsc("TALER_amount_normalize", "void", ["number"]), - amount_ntoh: getEmsc("TALER_amount_ntoh", "void", ["number", "number"]), - amount_subtract: getEmsc("TALER_amount_subtract", "number", ["number", "number", "number"]), - ecdh_eddsa: getEmsc("GNUNET_CRYPTO_ecdh_eddsa", "number", ["number", "number", "number"]), - eddsa_sign: getEmsc("GNUNET_CRYPTO_eddsa_sign", "number", ["number", "number", "number"]), - eddsa_verify: getEmsc("GNUNET_CRYPTO_eddsa_verify", "number", ["number", "number", "number", "number"]), - free: (ptr: number) => emscLib._free(ptr), - get_currency: getEmsc("TALER_WR_get_currency", "string", ["number"]), - get_fraction: getEmsc("TALER_WR_get_fraction", "number", ["number"]), - get_value: getEmsc("TALER_WR_get_value", "number", ["number"]), - hash: getEmsc("GNUNET_CRYPTO_hash", "void", ["number", "number", "number"]), - hash_context_abort: getEmsc("GNUNET_CRYPTO_hash_context_abort", "void", ["number"]), - hash_context_finish: getEmsc("GNUNET_CRYPTO_hash_context_finish", "void", ["number", "number"]), - hash_context_read: getEmsc("GNUNET_CRYPTO_hash_context_read", "void", ["number", "number", "number"]), - hash_create_random: getEmsc("GNUNET_CRYPTO_hash_create_random", "void", ["number", "number"]), - memmove: getEmsc("memmove", "number", ["number", "number", "number"]), - random_block: getEmsc("GNUNET_CRYPTO_random_block", "void", ["number", "number", "number"]), - rsa_blinding_key_destroy: getEmsc("GNUNET_CRYPTO_rsa_blinding_key_free", "void", ["number"]), - rsa_public_key_free: getEmsc("GNUNET_CRYPTO_rsa_public_key_free", "void", ["number"]), - rsa_signature_free: getEmsc("GNUNET_CRYPTO_rsa_signature_free", "void", ["number"]), - setup_fresh_coin: getEmsc( "TALER_setup_fresh_coin", "void", ["number", "number", "number"]), - string_to_data: getEmsc("GNUNET_STRINGS_string_to_data", "number", ["number", "number", "number", "number"]), -}; + /** + * Emscripten functions that don't do any memory allocations. + */ + public funcs: EmscFunctions; + /** + * Emscripten functions that allocate memory. + */ + public allocFuncs: EmscAllocFunctions; -/** - * Emscripten functions that allocate memory. - */ -const emscAlloc = { - data_to_string_alloc: getEmsc("GNUNET_STRINGS_data_to_string_alloc", "number", ["number", "number"]), - ecdhe_key_create: getEmsc("GNUNET_CRYPTO_ecdhe_key_create", "number", []), - ecdhe_public_key_from_private: getEmsc( "TALER_WRALL_ecdhe_public_key_from_private", "number", ["number"]), - ecdsa_key_create: getEmsc("GNUNET_CRYPTO_ecdsa_key_create", "number", []), - ecdsa_public_key_from_private: getEmsc( "TALER_WRALL_ecdsa_public_key_from_private", "number", ["number"]), - eddsa_key_create: getEmsc("GNUNET_CRYPTO_eddsa_key_create", "number", []), - eddsa_public_key_from_private: getEmsc( "TALER_WRALL_eddsa_public_key_from_private", "number", ["number"]), - get_amount: getEmsc("TALER_WRALL_get_amount", "number", ["number", "number", "number", "string"]), - hash_context_start: getEmsc("GNUNET_CRYPTO_hash_context_start", "number", []), - malloc: (size: number) => emscLib._malloc(size), - purpose_create: getEmsc("TALER_WRALL_purpose_create", "number", ["number", "number", "number"]), - rsa_blind: getEmsc("GNUNET_CRYPTO_rsa_blind", "number", ["number", "number", "number", "number", "number"]), - rsa_blinding_key_create: getEmsc("GNUNET_CRYPTO_rsa_blinding_key_create", "number", ["number"]), - rsa_blinding_key_decode: getEmsc("GNUNET_CRYPTO_rsa_blinding_key_decode", "number", ["number", "number"]), - rsa_blinding_key_encode: getEmsc("GNUNET_CRYPTO_rsa_blinding_key_encode", "number", ["number", "number"]), - rsa_public_key_decode: getEmsc("GNUNET_CRYPTO_rsa_public_key_decode", "number", ["number", "number"]), - rsa_public_key_encode: getEmsc("GNUNET_CRYPTO_rsa_public_key_encode", "number", ["number", "number"]), - rsa_signature_decode: getEmsc("GNUNET_CRYPTO_rsa_signature_decode", "number", ["number", "number"]), - rsa_signature_encode: getEmsc("GNUNET_CRYPTO_rsa_signature_encode", "number", ["number", "number"]), - rsa_unblind: getEmsc("GNUNET_CRYPTO_rsa_unblind", "number", ["number", "number", "number"]), -}; + public lib: EmscLib; + + constructor(lib: EmscLib) { + const getEmsc: EmscFunGen = (name: string, ret: any, argTypes: any[]) => { + return (...args: any[]) => { + return lib.ccall(name, ret, argTypes, args); + }; + }; + this.lib = lib; + this.allocFuncs = { + data_to_string_alloc: getEmsc("GNUNET_STRINGS_data_to_string_alloc", "number", ["number", "number"]), + ecdhe_key_create: getEmsc("GNUNET_CRYPTO_ecdhe_key_create", "number", []), + ecdhe_public_key_from_private: getEmsc( "TALER_WRALL_ecdhe_public_key_from_private", "number", ["number"]), + ecdsa_key_create: getEmsc("GNUNET_CRYPTO_ecdsa_key_create", "number", []), + ecdsa_public_key_from_private: getEmsc( "TALER_WRALL_ecdsa_public_key_from_private", "number", ["number"]), + eddsa_key_create: getEmsc("GNUNET_CRYPTO_eddsa_key_create", "number", []), + eddsa_public_key_from_private: getEmsc( "TALER_WRALL_eddsa_public_key_from_private", "number", ["number"]), + get_amount: getEmsc("TALER_WRALL_get_amount", "number", ["number", "number", "string"]), + hash_context_start: getEmsc("GNUNET_CRYPTO_hash_context_start", "number", []), + malloc: (size: number) => lib._malloc(size), + purpose_create: getEmsc("TALER_WRALL_purpose_create", "number", ["number", "number", "number"]), + rsa_blind: getEmsc("GNUNET_CRYPTO_rsa_blind", "number", ["number", "number", "number", "number", "number"]), + rsa_blinding_key_create: getEmsc("GNUNET_CRYPTO_rsa_blinding_key_create", "number", ["number"]), + rsa_blinding_key_decode: getEmsc("GNUNET_CRYPTO_rsa_blinding_key_decode", "number", ["number", "number"]), + rsa_blinding_key_encode: getEmsc("GNUNET_CRYPTO_rsa_blinding_key_encode", "number", ["number", "number"]), + rsa_public_key_decode: getEmsc("GNUNET_CRYPTO_rsa_public_key_decode", "number", ["number", "number"]), + rsa_public_key_encode: getEmsc("GNUNET_CRYPTO_rsa_public_key_encode", "number", ["number", "number"]), + rsa_signature_decode: getEmsc("GNUNET_CRYPTO_rsa_signature_decode", "number", ["number", "number"]), + rsa_signature_encode: getEmsc("GNUNET_CRYPTO_rsa_signature_encode", "number", ["number", "number"]), + rsa_unblind: getEmsc("GNUNET_CRYPTO_rsa_unblind", "number", ["number", "number", "number"]), + }; + this.funcs = { + amount_add: getEmsc("TALER_amount_add", "number", ["number", "number", "number"]), + amount_cmp: getEmsc("TALER_amount_cmp", "number", ["number", "number"]), + amount_get_zero: getEmsc("TALER_amount_get_zero", "number", ["string", "number"]), + amount_hton: getEmsc("TALER_amount_hton", "void", ["number", "number"]), + amount_normalize: getEmsc("TALER_amount_normalize", "void", ["number"]), + amount_ntoh: getEmsc("TALER_amount_ntoh", "void", ["number", "number"]), + amount_subtract: getEmsc("TALER_amount_subtract", "number", ["number", "number", "number"]), + ecdh_eddsa: getEmsc("GNUNET_CRYPTO_ecdh_eddsa", "number", ["number", "number", "number"]), + eddsa_sign: getEmsc("GNUNET_CRYPTO_eddsa_sign", "number", ["number", "number", "number"]), + eddsa_verify: getEmsc("GNUNET_CRYPTO_eddsa_verify", "number", ["number", "number", "number", "number"]), + free: (ptr: number) => lib._free(ptr), + get_currency: getEmsc("TALER_WR_get_currency", "string", ["number"]), + get_fraction: getEmsc("TALER_WR_get_fraction", "number", ["number"]), + get_value: getEmsc("TALER_WR_get_value", "number", ["number"]), + hash: getEmsc("GNUNET_CRYPTO_hash", "void", ["number", "number", "number"]), + hash_context_abort: getEmsc("GNUNET_CRYPTO_hash_context_abort", "void", ["number"]), + hash_context_finish: getEmsc("GNUNET_CRYPTO_hash_context_finish", "void", ["number", "number"]), + hash_context_read: getEmsc("GNUNET_CRYPTO_hash_context_read", "void", ["number", "number", "number"]), + hash_create_random: getEmsc("GNUNET_CRYPTO_hash_create_random", "void", ["number", "number"]), + memmove: getEmsc("memmove", "number", ["number", "number", "number"]), + random_block: getEmsc("GNUNET_CRYPTO_random_block", "void", ["number", "number", "number"]), + rsa_blinding_key_free: getEmsc("GNUNET_CRYPTO_rsa_blinding_key_free", "void", ["number"]), + rsa_public_key_free: getEmsc("GNUNET_CRYPTO_rsa_public_key_free", "void", ["number"]), + rsa_signature_free: getEmsc("GNUNET_CRYPTO_rsa_signature_free", "void", ["number"]), + setup_fresh_coin: getEmsc("TALER_setup_fresh_coin", "void", ["number", "number", "number"]), + string_to_data: getEmsc("GNUNET_STRINGS_string_to_data", "number", ["number", "number", "number", "number"]), + }; + } +} /** @@ -152,7 +233,7 @@ export class HashContext implements ArenaObject { private hashContextPtr: number | undefined; constructor() { - this.hashContextPtr = emscAlloc.hash_context_start(); + this.hashContextPtr = emsc().allocFuncs.hash_context_start(); } /** @@ -162,7 +243,7 @@ export class HashContext implements ArenaObject { if (!this.hashContextPtr) { throw Error("assertion failed"); } - emsc.hash_context_read(this.hashContextPtr, obj.nativePtr, obj.size()); + emsc().funcs.hash_context_read(this.hashContextPtr, obj.nativePtr, obj.size()); } /** @@ -173,7 +254,7 @@ export class HashContext implements ArenaObject { throw Error("assertion failed"); } h.alloc(); - emsc.hash_context_finish(this.hashContextPtr, h.nativePtr); + emsc().funcs.hash_context_finish(this.hashContextPtr, h.nativePtr); } /** @@ -181,7 +262,7 @@ export class HashContext implements ArenaObject { */ destroy(): void { if (this.hashContextPtr) { - emsc.hash_context_abort(this.hashContextPtr); + emsc().funcs.hash_context_abort(this.hashContextPtr); } this.hashContextPtr = undefined; } @@ -201,7 +282,7 @@ abstract class MallocArenaObject implements ArenaObject { destroy(): void { if (this._nativePtr && !this.isWeak) { - emsc.free(this.nativePtr); + emsc().funcs.free(this.nativePtr); this._nativePtr = undefined; } } @@ -220,7 +301,7 @@ abstract class MallocArenaObject implements ArenaObject { if (this._nativePtr !== undefined) { throw Error("Double allocation"); } - this.nativePtr = emscAlloc.malloc(size); + this.nativePtr = emsc().allocFuncs.malloc(size); } set nativePtr(v: number) { @@ -314,18 +395,18 @@ export class Amount extends MallocArenaObject { constructor(args?: AmountJson, arena?: Arena) { super(arena); if (args) { - this.nativePtr = emscAlloc.get_amount(args.value, + this.nativePtr = emsc().allocFuncs.get_amount(args.value, 0, args.fraction, args.currency); } else { - this.nativePtr = emscAlloc.get_amount(0, 0, 0, ""); + this.nativePtr = emsc().allocFuncs.get_amount(0, 0, 0, ""); } } static getZero(currency: string, a?: Arena): Amount { const am = new Amount(undefined, a); - const r = emsc.amount_get_zero(currency, am.nativePtr); + const r = emsc().funcs.amount_get_zero(currency, am.nativePtr); if (r !== GNUNET_OK) { throw Error("invalid currency"); } @@ -336,31 +417,31 @@ export class Amount extends MallocArenaObject { toNbo(a?: Arena): AmountNbo { const x = new AmountNbo(a); x.alloc(); - emsc.amount_hton(x.nativePtr, this.nativePtr); + emsc().funcs.amount_hton(x.nativePtr, this.nativePtr); return x; } fromNbo(nbo: AmountNbo): void { - emsc.amount_ntoh(this.nativePtr, nbo.nativePtr); + emsc().funcs.amount_ntoh(this.nativePtr, nbo.nativePtr); } get value() { - return emsc.get_value(this.nativePtr); + return emsc().funcs.get_value(this.nativePtr); } get fraction() { - return emsc.get_fraction(this.nativePtr); + return emsc().funcs.get_fraction(this.nativePtr); } get currency(): string { - return emsc.get_currency(this.nativePtr); + return emsc().funcs.get_currency(this.nativePtr); } toJson(): AmountJson { return { - currency: emsc.get_currency(this.nativePtr), - fraction: emsc.get_fraction(this.nativePtr), - value: emsc.get_value(this.nativePtr), + currency: emsc().funcs.get_currency(this.nativePtr), + fraction: emsc().funcs.get_fraction(this.nativePtr), + value: emsc().funcs.get_value(this.nativePtr), }; } @@ -368,7 +449,7 @@ export class Amount extends MallocArenaObject { * Add an amount to this amount. */ add(a: Amount) { - const res = emsc.amount_add(this.nativePtr, a.nativePtr, this.nativePtr); + const res = emsc().funcs.amount_add(this.nativePtr, a.nativePtr, this.nativePtr); if (res < 1) { // Overflow return false; @@ -381,7 +462,7 @@ export class Amount extends MallocArenaObject { */ sub(a: Amount) { // this = this - a - const res = emsc.amount_subtract(this.nativePtr, this.nativePtr, a.nativePtr); + const res = emsc().funcs.amount_subtract(this.nativePtr, this.nativePtr, a.nativePtr); if (res === 0) { // Underflow return false; @@ -397,11 +478,11 @@ export class Amount extends MallocArenaObject { if (this.currency !== a.currency) { throw Error(`incomparable currencies (${this.currency} and ${a.currency})`); } - return emsc.amount_cmp(this.nativePtr, a.nativePtr); + return emsc().funcs.amount_cmp(this.nativePtr, a.nativePtr); } normalize() { - emsc.amount_normalize(this.nativePtr); + emsc().funcs.amount_normalize(this.nativePtr); } } @@ -443,13 +524,13 @@ abstract class PackedArenaObject extends MallocArenaObject { } randomize(qual: RandomQuality = RandomQuality.STRONG): void { - emsc.random_block(qual, this.nativePtr, this.size()); + emsc().funcs.random_block(qual, this.nativePtr, this.size()); } toCrock(): string { - const d = emscAlloc.data_to_string_alloc(this.nativePtr, this.size()); - const s = emscLib.Pointer_stringify(d); - emsc.free(d); + const d = emsc().allocFuncs.data_to_string_alloc(this.nativePtr, this.size()); + const s = emsc().lib.Pointer_stringify(d); + emsc().funcs.free(d); return s; } @@ -465,7 +546,7 @@ abstract class PackedArenaObject extends MallocArenaObject { // We need to get the javascript string // to the emscripten heap first. const buf = ByteArray.fromStringWithNull(s); - const res = emsc.string_to_data(buf.nativePtr, + const res = emsc().funcs.string_to_data(buf.nativePtr, s.length, this.nativePtr, this.size()); @@ -478,21 +559,21 @@ abstract class PackedArenaObject extends MallocArenaObject { alloc() { // FIXME: should the client be allowed to call alloc multiple times? if (!this._nativePtr) { - this.nativePtr = emscAlloc.malloc(this.size()); + this.nativePtr = emsc().allocFuncs.malloc(this.size()); } } hash(): HashCode { const x = new HashCode(); x.alloc(); - emsc.hash(this.nativePtr, this.size(), x.nativePtr); + emsc().funcs.hash(this.nativePtr, this.size(), x.nativePtr); return x; } hexdump() { const bytes: string[] = []; for (let i = 0; i < this.size(); i++) { - let b = emscLib.getValue(this.nativePtr + i, "i8"); + let b = emsc().lib.getValue(this.nativePtr + i, "i8"); b = (b + 256) % 256; bytes.push("0".concat(b.toString(16)).slice(-2)); } @@ -554,11 +635,11 @@ function fromCrockDecoded<T extends MallocArenaObject>(s: string, * Encode an object using a special encoding function. */ function encode<T extends MallocArenaObject>(obj: T, encodeFn: any, arena?: Arena): ByteArray { - const ptr = emscAlloc.malloc(PTR_SIZE); + const ptr = emsc().allocFuncs.malloc(PTR_SIZE); const len = encodeFn(obj.nativePtr, ptr); const res = new ByteArray(len, undefined, arena); - res.nativePtr = emscLib.getValue(ptr, "*"); - emsc.free(ptr); + res.nativePtr = emsc().lib.getValue(ptr, "*"); + emsc().funcs.free(ptr); return res; } @@ -569,7 +650,7 @@ function encode<T extends MallocArenaObject>(obj: T, encodeFn: any, arena?: Aren export class EddsaPrivateKey extends PackedArenaObject { static create(a?: Arena): EddsaPrivateKey { const obj = new EddsaPrivateKey(a); - obj.nativePtr = emscAlloc.eddsa_key_create(); + obj.nativePtr = emsc().allocFuncs.eddsa_key_create(); return obj; } @@ -579,7 +660,7 @@ export class EddsaPrivateKey extends PackedArenaObject { getPublicKey(a?: Arena): EddsaPublicKey { const obj = new EddsaPublicKey(a); - obj.nativePtr = emscAlloc.eddsa_public_key_from_private(this.nativePtr); + obj.nativePtr = emsc().allocFuncs.eddsa_public_key_from_private(this.nativePtr); return obj; } @@ -595,7 +676,7 @@ export class EddsaPrivateKey extends PackedArenaObject { export class EcdsaPrivateKey extends PackedArenaObject { static create(a?: Arena): EcdsaPrivateKey { const obj = new EcdsaPrivateKey(a); - obj.nativePtr = emscAlloc.ecdsa_key_create(); + obj.nativePtr = emsc().allocFuncs.ecdsa_key_create(); return obj; } @@ -605,7 +686,7 @@ export class EcdsaPrivateKey extends PackedArenaObject { getPublicKey(a?: Arena): EcdsaPublicKey { const obj = new EcdsaPublicKey(a); - obj.nativePtr = emscAlloc.ecdsa_public_key_from_private(this.nativePtr); + obj.nativePtr = emsc().allocFuncs.ecdsa_public_key_from_private(this.nativePtr); return obj; } @@ -621,7 +702,7 @@ export class EcdsaPrivateKey extends PackedArenaObject { export class EcdhePrivateKey extends PackedArenaObject { static create(a?: Arena): EcdhePrivateKey { const obj = new EcdhePrivateKey(a); - obj.nativePtr = emscAlloc.ecdhe_key_create(); + obj.nativePtr = emsc().allocFuncs.ecdhe_key_create(); return obj; } @@ -631,7 +712,7 @@ export class EcdhePrivateKey extends PackedArenaObject { getPublicKey(a?: Arena): EcdhePublicKey { const obj = new EcdhePublicKey(a); - obj.nativePtr = emscAlloc.ecdhe_public_key_from_private(this.nativePtr); + obj.nativePtr = emsc().allocFuncs.ecdhe_public_key_from_private(this.nativePtr); return obj; } @@ -728,7 +809,7 @@ export class HashCode extends PackedArenaObject { random(qual: RandomQuality = RandomQuality.STRONG) { this.alloc(); - emsc.hash_create_random(qual, this.nativePtr); + emsc().funcs.hash_create_random(qual, this.nativePtr); } } @@ -746,7 +827,7 @@ export class ByteArray extends PackedArenaObject { constructor(desiredSize: number, init?: number, a?: Arena) { super(a); if (init === undefined) { - this.nativePtr = emscAlloc.malloc(desiredSize); + this.nativePtr = emsc().allocFuncs.malloc(desiredSize); } else { this.nativePtr = init; } @@ -756,16 +837,16 @@ export class ByteArray extends PackedArenaObject { static fromStringWithoutNull(s: string, a?: Arena): ByteArray { // UTF-8 bytes, including 0-terminator const terminatedByteLength = countUtf8Bytes(s) + 1; - const hstr = emscAlloc.malloc(terminatedByteLength); - emscLib.stringToUTF8(s, hstr, terminatedByteLength); + const hstr = emsc().allocFuncs.malloc(terminatedByteLength); + emsc().lib.stringToUTF8(s, hstr, terminatedByteLength); return new ByteArray(terminatedByteLength - 1, hstr, a); } static fromStringWithNull(s: string, a?: Arena): ByteArray { // UTF-8 bytes, including 0-terminator const terminatedByteLength = countUtf8Bytes(s) + 1; - const hstr = emscAlloc.malloc(terminatedByteLength); - emscLib.stringToUTF8(s, hstr, terminatedByteLength); + const hstr = emsc().allocFuncs.malloc(terminatedByteLength); + emsc().lib.stringToUTF8(s, hstr, terminatedByteLength); return new ByteArray(terminatedByteLength, hstr, a); } @@ -773,12 +854,12 @@ export class ByteArray extends PackedArenaObject { // this one is a bit more complicated than the other fromCrock functions, // since we don't have a fixed size const byteLength = countUtf8Bytes(s); - const hstr = emscAlloc.malloc(byteLength + 1); - emscLib.stringToUTF8(s, hstr, byteLength + 1); + const hstr = emsc().allocFuncs.malloc(byteLength + 1); + emsc().lib.stringToUTF8(s, hstr, byteLength + 1); const decodedLen = Math.floor((byteLength * 5) / 8); const ba = new ByteArray(decodedLen, undefined, a); - const res = emsc.string_to_data(hstr, byteLength, ba.nativePtr, decodedLen); - emsc.free(hstr); + const res = emsc().funcs.string_to_data(hstr, byteLength, ba.nativePtr, decodedLen); + emsc().funcs.free(hstr); if (res !== GNUNET_OK) { throw Error("decoding failed"); } @@ -802,9 +883,9 @@ export class EccSignaturePurpose extends PackedArenaObject { payload: PackedArenaObject, a?: Arena) { super(a); - this.nativePtr = emscAlloc.purpose_create(purpose, - payload.nativePtr, - payload.size()); + this.nativePtr = emsc().allocFuncs.purpose_create(purpose, + payload.nativePtr, + payload.size()); this.payloadSize = payload.size(); } } @@ -834,13 +915,13 @@ abstract class SignatureStruct { totalSize += member.size(); } - const buf = emscAlloc.malloc(totalSize); + const buf = emsc().allocFuncs.malloc(totalSize); let ptr = buf; for (const f of this.fieldTypes()) { const name = f[0]; const member = this.members[name]; const size = member.size(); - emsc.memmove(ptr, member.nativePtr, size); + emsc().funcs.memmove(ptr, member.nativePtr, size); ptr += size; } const ba = new ByteArray(totalSize, buf, a); @@ -1081,7 +1162,7 @@ export class AbsoluteTimeNbo extends PackedArenaObject { // XXX: This only works up to 54 bit numbers. function set64(p: number, n: number) { for (let i = 0; i < 8; ++i) { - emscLib.setValue(p + (7 - i), n & 0xFF, "i8"); + emsc().lib.setValue(p + (7 - i), n & 0xFF, "i8"); n = Math.floor(n / 256); } } @@ -1089,7 +1170,7 @@ function set64(p: number, n: number) { // XXX: This only works up to 54 bit numbers. function set32(p: number, n: number) { for (let i = 0; i < 4; ++i) { - emscLib.setValue(p + (3 - i), n & 0xFF, "i8"); + emsc().lib.setValue(p + (3 - i), n & 0xFF, "i8"); n = Math.floor(n / 256); } } @@ -1277,7 +1358,7 @@ export class PaymentSignaturePS extends SignatureStruct { */ export class RsaPublicKey extends MallocArenaObject { static fromCrock(s: string): RsaPublicKey { - return fromCrockDecoded(s, this, emscAlloc.rsa_public_key_decode); + return fromCrockDecoded(s, this, emsc().allocFuncs.rsa_public_key_decode); } toCrock() { @@ -1285,12 +1366,12 @@ export class RsaPublicKey extends MallocArenaObject { } destroy() { - emsc.rsa_public_key_free(this.nativePtr); + emsc().funcs.rsa_public_key_free(this.nativePtr); this.nativePtr = 0; } encode(arena?: Arena): ByteArray { - return encode(this, emscAlloc.rsa_public_key_encode); + return encode(this, emsc().allocFuncs.rsa_public_key_encode); } } @@ -1313,15 +1394,15 @@ export class EddsaSignature extends PackedArenaObject { */ export class RsaSignature extends MallocArenaObject { static fromCrock(s: string, a?: Arena) { - return fromCrockDecoded(s, this, emscAlloc.rsa_signature_decode); + return fromCrockDecoded(s, this, emsc().allocFuncs.rsa_signature_decode); } encode(arena?: Arena): ByteArray { - return encode(this, emscAlloc.rsa_signature_encode); + return encode(this, emsc().allocFuncs.rsa_signature_encode); } destroy() { - emsc.rsa_signature_free(this.nativePtr); + emsc().funcs.rsa_signature_free(this.nativePtr); this.nativePtr = 0; } } @@ -1334,17 +1415,17 @@ export function rsaBlind(hashCode: HashCode, blindingKey: RsaBlindingKeySecret, pkey: RsaPublicKey, arena?: Arena): ByteArray|null { - const buf_ptr_out = emscAlloc.malloc(PTR_SIZE); - const buf_size_out = emscAlloc.malloc(PTR_SIZE); - const res = emscAlloc.rsa_blind(hashCode.nativePtr, - blindingKey.nativePtr, - pkey.nativePtr, - buf_ptr_out, - buf_size_out); - const buf_ptr = emscLib.getValue(buf_ptr_out, "*"); - const buf_size = emscLib.getValue(buf_size_out, "*"); - emsc.free(buf_ptr_out); - emsc.free(buf_size_out); + const buf_ptr_out = emsc().allocFuncs.malloc(PTR_SIZE); + const buf_size_out = emsc().allocFuncs.malloc(PTR_SIZE); + const res = emsc().allocFuncs.rsa_blind(hashCode.nativePtr, + blindingKey.nativePtr, + pkey.nativePtr, + buf_ptr_out, + buf_size_out); + const buf_ptr = emsc().lib.getValue(buf_ptr_out, "*"); + const buf_size = emsc().lib.getValue(buf_size_out, "*"); + emsc().funcs.free(buf_ptr_out); + emsc().funcs.free(buf_size_out); if (res !== GNUNET_OK) { // malicious key return null; @@ -1361,7 +1442,7 @@ export function eddsaSign(purpose: EccSignaturePurpose, a?: Arena): EddsaSignature { const sig = new EddsaSignature(a); sig.alloc(); - const res = emsc.eddsa_sign(priv.nativePtr, purpose.nativePtr, sig.nativePtr); + const res = emsc().funcs.eddsa_sign(priv.nativePtr, purpose.nativePtr, sig.nativePtr); if (res < 1) { throw Error("EdDSA signing failed"); } @@ -1377,10 +1458,10 @@ export function eddsaVerify(purposeNum: number, sig: EddsaSignature, pub: EddsaPublicKey, a?: Arena): boolean { - const r = emsc.eddsa_verify(purposeNum, - verify.nativePtr, - sig.nativePtr, - pub.nativePtr); + const r = emsc().funcs.eddsa_verify(purposeNum, + verify.nativePtr, + sig.nativePtr, + pub.nativePtr); return r === GNUNET_OK; } @@ -1393,9 +1474,9 @@ export function rsaUnblind(sig: RsaSignature, pk: RsaPublicKey, a?: Arena): RsaSignature { const x = new RsaSignature(a); - x.nativePtr = emscAlloc.rsa_unblind(sig.nativePtr, - bk.nativePtr, - pk.nativePtr); + x.nativePtr = emsc().allocFuncs.rsa_unblind(sig.nativePtr, + bk.nativePtr, + pk.nativePtr); return x; } @@ -1424,7 +1505,7 @@ export function ecdhEddsa(priv: EcdhePrivateKey, pub: EddsaPublicKey): HashCode { const h = new HashCode(); h.alloc(); - const res = emsc.ecdh_eddsa(priv.nativePtr, pub.nativePtr, h.nativePtr); + const res = emsc().funcs.ecdh_eddsa(priv.nativePtr, pub.nativePtr, h.nativePtr); if (res !== GNUNET_OK) { throw Error("ecdh_eddsa failed"); } @@ -1443,10 +1524,10 @@ export function setupFreshCoin(secretSeed: TransferSecretP, blindingKey.isWeak = true; const buf = new ByteArray(priv.size() + blindingKey.size()); - emsc.setup_fresh_coin(secretSeed.nativePtr, coinIndex, buf.nativePtr); + emsc().funcs.setup_fresh_coin(secretSeed.nativePtr, coinIndex, buf.nativePtr); priv.nativePtr = buf.nativePtr; blindingKey.nativePtr = buf.nativePtr + priv.size(); - return {priv, blindingKey}; + return { priv, blindingKey }; } diff --git a/src/crypto/emscLoader.d.ts b/src/crypto/emscLoader.d.ts index f62604ee1..3ec4f4cfb 100644 --- a/src/crypto/emscLoader.d.ts +++ b/src/crypto/emscLoader.d.ts @@ -15,7 +15,7 @@ */ -declare function getLib(): EmscLib; +declare function getLib(): Promise<{ lib: EmscLib }>; /** * Signature of the function that retrieves emscripten @@ -44,6 +44,12 @@ interface EmscLib { stringToUTF8(s: string, addr: number, maxLength: number): void; + onRuntimeInitialized(f: () => void): void; + + readBinary?: (filename: string) => Promise<ArrayBuffer>; + + calledRun?: boolean; + _free(ptr: number): void; _malloc(n: number): number; diff --git a/src/crypto/emscLoader.js b/src/crypto/emscLoader.js index ed8662818..7251a5984 100644 --- a/src/crypto/emscLoader.js +++ b/src/crypto/emscLoader.js @@ -24,6 +24,8 @@ * the right way to load the library. */ +let cachedLib = undefined; + /** * Load the taler emscripten lib. * @@ -31,6 +33,11 @@ * be globally available. Inside node, require is used. */ export function getLib() { + console.log("in getLib"); + if (cachedLib) { + console.log("lib is cached"); + return Promise.resolve({ lib: cachedLib }); + } if (typeof require !== "undefined") { // Make sure that TypeScript doesn't try // to check the taler-emscripten-lib. @@ -45,7 +52,8 @@ export function getLib() { const lib = indirectRequire("../../../emscripten/taler-emscripten-lib.js"); g.importScripts = savedImportScripts; if (lib) { - return lib; + cachedLib = lib; + return Promise.resolve({ lib: cachedLib }); } // When we're running as a webpack bundle, the above require might // have failed and returned 'undefined', so we try other ways to import. @@ -57,7 +65,22 @@ export function getLib() { if (!self.TalerEmscriptenLib) { throw Error("can't import taler emscripten lib"); } - return self.TalerEmscriptenLib + const locateFile = (path, scriptDir) => { + console.log("locating file", "path", path, "scriptDir", scriptDir); + // This is quite hacky and assumes that our scriptDir is dist/ + return scriptDir + "../emscripten/" + path; + }; + console.log("instantiating TalerEmscriptenLib"); + //const lib = self.TalerEmscriptenLib({ locateFile }); + const lib = self.TalerEmscriptenLib; + cachedLib = lib; + return Promise.resolve({ lib: lib }); + //return new Promise((resolve, reject) => { + // lib.then(mod => { + // console.log("emscripten module fully loaded"); + // resolve({ lib: mod }); + // }); + //}); } // Last resort, we don't have require, we're not running in a webworker. @@ -66,7 +89,7 @@ export function getLib() { if (typeof window !== "undefined") { if (window.TalerEmscriptenLib) { - return TalerEmscriptenLib; + return Promise.resolve(TalerEmscriptenLib); } throw Error("Looks like running in browser, but TalerEmscriptenLib is not defined"); } |