crypto for refreshing
This commit is contained in:
parent
d4be3906e3
commit
122e069d91
5
.vscode/settings.json
vendored
5
.vscode/settings.json
vendored
@ -1,6 +1,6 @@
|
|||||||
// Place your settings in this file to overwrite default and user settings.
|
// Place your settings in this file to overwrite default and user settings.
|
||||||
{
|
{
|
||||||
// Use latest language services
|
// Use latest language servicesu
|
||||||
"typescript.tsdk": "node_modules/typescript/lib",
|
"typescript.tsdk": "node_modules/typescript/lib",
|
||||||
// Defines space handling after a comma delimiter
|
// Defines space handling after a comma delimiter
|
||||||
"typescript.format.insertSpaceAfterCommaDelimiter": true,
|
"typescript.format.insertSpaceAfterCommaDelimiter": true,
|
||||||
@ -33,5 +33,6 @@
|
|||||||
"when": "$(basename).tsx"
|
"when": "$(basename).tsx"
|
||||||
},
|
},
|
||||||
"**/*.js.map": true
|
"**/*.js.map": true
|
||||||
}
|
},
|
||||||
|
"editor.wrappingIndent": "same"
|
||||||
}
|
}
|
2
lib/emscripten/emsc.d.ts
vendored
2
lib/emscripten/emsc.d.ts
vendored
@ -33,6 +33,8 @@ export interface EmscFunGen {
|
|||||||
export declare namespace Module {
|
export declare namespace Module {
|
||||||
var cwrap: EmscFunGen;
|
var cwrap: EmscFunGen;
|
||||||
|
|
||||||
|
function ccall(name: string, ret:"number"|"string", argTypes: any[], args: any[]): any
|
||||||
|
|
||||||
function stringToUTF8(s: string, addr: number, maxLength: number): void
|
function stringToUTF8(s: string, addr: number, maxLength: number): void
|
||||||
|
|
||||||
function _free(ptr: number): void;
|
function _free(ptr: number): void;
|
||||||
|
@ -14,13 +14,13 @@
|
|||||||
TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
|
TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import {AmountJson} from "./types";
|
import { AmountJson } from "./types";
|
||||||
import * as EmscWrapper from "../emscripten/emsc";
|
import * as EmscWrapper from "../emscripten/emsc";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* High-level interface to emscripten-compiled modules used
|
* High-level interface to emscripten-compiled modules used
|
||||||
* by the wallet.
|
* by the wallet.
|
||||||
* @module EmscriptIf
|
*
|
||||||
* @author Florian Dold
|
* @author Florian Dold
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@ -43,110 +43,122 @@ let getEmsc: EmscWrapper.EmscFunGen = (...args: any[]) => Module.cwrap.apply(
|
|||||||
var emsc = {
|
var emsc = {
|
||||||
free: (ptr: number) => Module._free(ptr),
|
free: (ptr: number) => Module._free(ptr),
|
||||||
get_value: getEmsc('TALER_WR_get_value',
|
get_value: getEmsc('TALER_WR_get_value',
|
||||||
'number',
|
'number',
|
||||||
['number']),
|
['number']),
|
||||||
get_fraction: getEmsc('TALER_WR_get_fraction',
|
get_fraction: getEmsc('TALER_WR_get_fraction',
|
||||||
'number',
|
'number',
|
||||||
['number']),
|
['number']),
|
||||||
get_currency: getEmsc('TALER_WR_get_currency',
|
get_currency: getEmsc('TALER_WR_get_currency',
|
||||||
'string',
|
'string',
|
||||||
['number']),
|
['number']),
|
||||||
amount_add: getEmsc('TALER_amount_add',
|
amount_add: getEmsc('TALER_amount_add',
|
||||||
'number',
|
'number',
|
||||||
['number', 'number', 'number']),
|
['number', 'number', 'number']),
|
||||||
amount_subtract: getEmsc('TALER_amount_subtract',
|
amount_subtract: getEmsc('TALER_amount_subtract',
|
||||||
'number',
|
'number',
|
||||||
['number', 'number', 'number']),
|
['number', 'number', 'number']),
|
||||||
amount_normalize: getEmsc('TALER_amount_normalize',
|
amount_normalize: getEmsc('TALER_amount_normalize',
|
||||||
'void',
|
'void',
|
||||||
['number']),
|
['number']),
|
||||||
amount_get_zero: getEmsc('TALER_amount_get_zero',
|
amount_get_zero: getEmsc('TALER_amount_get_zero',
|
||||||
'number',
|
'number',
|
||||||
['string', 'number']),
|
['string', 'number']),
|
||||||
amount_cmp: getEmsc('TALER_amount_cmp',
|
amount_cmp: getEmsc('TALER_amount_cmp',
|
||||||
'number',
|
'number',
|
||||||
['number', 'number']),
|
['number', 'number']),
|
||||||
amount_hton: getEmsc('TALER_amount_hton',
|
amount_hton: getEmsc('TALER_amount_hton',
|
||||||
'void',
|
'void',
|
||||||
['number', 'number']),
|
['number', 'number']),
|
||||||
amount_ntoh: getEmsc('TALER_amount_ntoh',
|
amount_ntoh: getEmsc('TALER_amount_ntoh',
|
||||||
'void',
|
'void',
|
||||||
['number', 'number']),
|
['number', 'number']),
|
||||||
hash: getEmsc('GNUNET_CRYPTO_hash',
|
hash: getEmsc('GNUNET_CRYPTO_hash',
|
||||||
'void',
|
'void',
|
||||||
['number', 'number', 'number']),
|
['number', 'number', 'number']),
|
||||||
memmove: getEmsc('memmove',
|
memmove: getEmsc('memmove',
|
||||||
'number',
|
'number',
|
||||||
['number', 'number', 'number']),
|
['number', 'number', 'number']),
|
||||||
rsa_public_key_free: getEmsc('GNUNET_CRYPTO_rsa_public_key_free',
|
rsa_public_key_free: getEmsc('GNUNET_CRYPTO_rsa_public_key_free',
|
||||||
'void',
|
'void',
|
||||||
['number']),
|
['number']),
|
||||||
rsa_signature_free: getEmsc('GNUNET_CRYPTO_rsa_signature_free',
|
rsa_signature_free: getEmsc('GNUNET_CRYPTO_rsa_signature_free',
|
||||||
'void',
|
'void',
|
||||||
['number']),
|
['number']),
|
||||||
string_to_data: getEmsc('GNUNET_STRINGS_string_to_data',
|
string_to_data: getEmsc('GNUNET_STRINGS_string_to_data',
|
||||||
'number',
|
'number',
|
||||||
['number', 'number', 'number', 'number']),
|
['number', 'number', 'number', 'number']),
|
||||||
eddsa_sign: getEmsc('GNUNET_CRYPTO_eddsa_sign',
|
eddsa_sign: getEmsc('GNUNET_CRYPTO_eddsa_sign',
|
||||||
'number',
|
'number',
|
||||||
['number', 'number', 'number']),
|
['number', 'number', 'number']),
|
||||||
eddsa_verify: getEmsc('GNUNET_CRYPTO_eddsa_verify',
|
eddsa_verify: getEmsc('GNUNET_CRYPTO_eddsa_verify',
|
||||||
'number',
|
'number',
|
||||||
['number', 'number', 'number', 'number']),
|
['number', 'number', 'number', 'number']),
|
||||||
hash_create_random: getEmsc('GNUNET_CRYPTO_hash_create_random',
|
hash_create_random: getEmsc('GNUNET_CRYPTO_hash_create_random',
|
||||||
'void',
|
'void',
|
||||||
['number', 'number']),
|
['number', 'number']),
|
||||||
rsa_blinding_key_destroy: getEmsc('GNUNET_CRYPTO_rsa_blinding_key_free',
|
rsa_blinding_key_destroy: getEmsc('GNUNET_CRYPTO_rsa_blinding_key_free',
|
||||||
'void',
|
'void',
|
||||||
['number']),
|
['number']),
|
||||||
random_block: getEmsc('GNUNET_CRYPTO_random_block',
|
random_block: getEmsc('GNUNET_CRYPTO_random_block',
|
||||||
'void',
|
'void',
|
||||||
['number', 'number', 'number']),
|
['number', 'number', 'number']),
|
||||||
|
hash_context_abort: getEmsc('GNUNET_CRYPTO_hash_context_abort',
|
||||||
|
'void',
|
||||||
|
['number']),
|
||||||
|
hash_context_read: getEmsc('GNUNET_CRYPTO_hash_context_read',
|
||||||
|
'void',
|
||||||
|
['number', 'number', 'number']),
|
||||||
|
hash_context_finish: getEmsc('GNUNET_CRYPTO_hash_context_finish',
|
||||||
|
'void',
|
||||||
|
['number', 'number']),
|
||||||
};
|
};
|
||||||
|
|
||||||
var emscAlloc = {
|
var emscAlloc = {
|
||||||
get_amount: getEmsc('TALER_WRALL_get_amount',
|
get_amount: getEmsc('TALER_WRALL_get_amount',
|
||||||
'number',
|
'number',
|
||||||
['number', 'number', 'number', 'string']),
|
['number', 'number', 'number', 'string']),
|
||||||
eddsa_key_create: getEmsc('GNUNET_CRYPTO_eddsa_key_create',
|
eddsa_key_create: getEmsc('GNUNET_CRYPTO_eddsa_key_create',
|
||||||
'number', []),
|
'number', []),
|
||||||
eddsa_public_key_from_private: getEmsc(
|
eddsa_public_key_from_private: getEmsc(
|
||||||
'TALER_WRALL_eddsa_public_key_from_private',
|
'TALER_WRALL_eddsa_public_key_from_private',
|
||||||
'number',
|
'number',
|
||||||
['number']),
|
['number']),
|
||||||
data_to_string_alloc: getEmsc('GNUNET_STRINGS_data_to_string_alloc',
|
data_to_string_alloc: getEmsc('GNUNET_STRINGS_data_to_string_alloc',
|
||||||
'number',
|
'number',
|
||||||
['number', 'number']),
|
['number', 'number']),
|
||||||
purpose_create: getEmsc('TALER_WRALL_purpose_create',
|
purpose_create: getEmsc('TALER_WRALL_purpose_create',
|
||||||
'number',
|
'number',
|
||||||
['number', 'number', 'number']),
|
['number', 'number', 'number']),
|
||||||
rsa_blind: getEmsc('GNUNET_CRYPTO_rsa_blind',
|
rsa_blind: getEmsc('GNUNET_CRYPTO_rsa_blind',
|
||||||
'number',
|
'number',
|
||||||
['number', 'number', 'number', 'number']),
|
['number', 'number', 'number', 'number']),
|
||||||
rsa_blinding_key_create: getEmsc('GNUNET_CRYPTO_rsa_blinding_key_create',
|
rsa_blinding_key_create: getEmsc('GNUNET_CRYPTO_rsa_blinding_key_create',
|
||||||
'number',
|
'number',
|
||||||
['number']),
|
['number']),
|
||||||
rsa_blinding_key_encode: getEmsc('GNUNET_CRYPTO_rsa_blinding_key_encode',
|
rsa_blinding_key_encode: getEmsc('GNUNET_CRYPTO_rsa_blinding_key_encode',
|
||||||
'number',
|
'number',
|
||||||
['number', 'number']),
|
['number', 'number']),
|
||||||
rsa_signature_encode: getEmsc('GNUNET_CRYPTO_rsa_signature_encode',
|
rsa_signature_encode: getEmsc('GNUNET_CRYPTO_rsa_signature_encode',
|
||||||
'number',
|
'number',
|
||||||
['number', 'number']),
|
['number', 'number']),
|
||||||
rsa_blinding_key_decode: getEmsc('GNUNET_CRYPTO_rsa_blinding_key_decode',
|
rsa_blinding_key_decode: getEmsc('GNUNET_CRYPTO_rsa_blinding_key_decode',
|
||||||
'number',
|
'number',
|
||||||
['number', 'number']),
|
['number', 'number']),
|
||||||
rsa_public_key_decode: getEmsc('GNUNET_CRYPTO_rsa_public_key_decode',
|
rsa_public_key_decode: getEmsc('GNUNET_CRYPTO_rsa_public_key_decode',
|
||||||
'number',
|
'number',
|
||||||
['number', 'number']),
|
['number', 'number']),
|
||||||
rsa_signature_decode: getEmsc('GNUNET_CRYPTO_rsa_signature_decode',
|
rsa_signature_decode: getEmsc('GNUNET_CRYPTO_rsa_signature_decode',
|
||||||
'number',
|
'number',
|
||||||
['number', 'number']),
|
['number', 'number']),
|
||||||
rsa_public_key_encode: getEmsc('GNUNET_CRYPTO_rsa_public_key_encode',
|
rsa_public_key_encode: getEmsc('GNUNET_CRYPTO_rsa_public_key_encode',
|
||||||
'number',
|
'number',
|
||||||
['number', 'number']),
|
['number', 'number']),
|
||||||
rsa_unblind: getEmsc('GNUNET_CRYPTO_rsa_unblind',
|
rsa_unblind: getEmsc('GNUNET_CRYPTO_rsa_unblind',
|
||||||
'number',
|
'number',
|
||||||
['number', 'number', 'number']),
|
['number', 'number', 'number']),
|
||||||
|
hash_context_start: getEmsc('GNUNET_CRYPTO_hash_context_start',
|
||||||
|
'number',
|
||||||
|
[]),
|
||||||
malloc: (size: number) => Module._malloc(size),
|
malloc: (size: number) => Module._malloc(size),
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -155,6 +167,7 @@ export enum SignaturePurpose {
|
|||||||
RESERVE_WITHDRAW = 1200,
|
RESERVE_WITHDRAW = 1200,
|
||||||
WALLET_COIN_DEPOSIT = 1201,
|
WALLET_COIN_DEPOSIT = 1201,
|
||||||
MASTER_DENOMINATION_KEY_VALIDITY = 1025,
|
MASTER_DENOMINATION_KEY_VALIDITY = 1025,
|
||||||
|
WALLET_COIN_MELT = 1202,
|
||||||
}
|
}
|
||||||
|
|
||||||
enum RandomQuality {
|
enum RandomQuality {
|
||||||
@ -163,9 +176,49 @@ enum RandomQuality {
|
|||||||
NONCE = 2
|
NONCE = 2
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface ArenaObject {
|
||||||
|
destroy(): void;
|
||||||
|
}
|
||||||
|
|
||||||
abstract class ArenaObject {
|
|
||||||
|
class HashContext implements ArenaObject {
|
||||||
|
private hashContextPtr: number | undefined;
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
this.hashContextPtr = emscAlloc.hash_context_start();
|
||||||
|
}
|
||||||
|
|
||||||
|
read(obj: PackedArenaObject): void {
|
||||||
|
if (!this.hashContextPtr) {
|
||||||
|
throw Error("assertion failed");
|
||||||
|
}
|
||||||
|
emsc.hash_context_read(this.hashContextPtr, obj.getNative(), obj.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
finish(h: HashCode) {
|
||||||
|
if (!this.hashContextPtr) {
|
||||||
|
throw Error("assertion failed");
|
||||||
|
}
|
||||||
|
h.alloc();
|
||||||
|
emsc.hash_context_finish(this.hashContextPtr, h.getNative());
|
||||||
|
}
|
||||||
|
|
||||||
|
destroy(): void {
|
||||||
|
if (this.hashContextPtr) {
|
||||||
|
emsc.hash_context_abort(this.hashContextPtr);
|
||||||
|
}
|
||||||
|
this.hashContextPtr = undefined;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
abstract class MallocArenaObject implements ArenaObject {
|
||||||
protected _nativePtr: number | undefined = undefined;
|
protected _nativePtr: number | undefined = undefined;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Is this a weak reference to the underlying memory?
|
||||||
|
*/
|
||||||
|
isWeak = false;
|
||||||
arena: Arena;
|
arena: Arena;
|
||||||
|
|
||||||
abstract destroy(): void;
|
abstract destroy(): void;
|
||||||
@ -192,7 +245,7 @@ abstract class ArenaObject {
|
|||||||
}
|
}
|
||||||
|
|
||||||
free() {
|
free() {
|
||||||
if (this.nativePtr) {
|
if (this.nativePtr && !this.isWeak) {
|
||||||
emsc.free(this.nativePtr);
|
emsc.free(this.nativePtr);
|
||||||
this._nativePtr = undefined;
|
this._nativePtr = undefined;
|
||||||
}
|
}
|
||||||
@ -270,7 +323,7 @@ class SyncArena extends DefaultArena {
|
|||||||
super();
|
super();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(obj: ArenaObject) {
|
pub(obj: MallocArenaObject) {
|
||||||
super.put(obj);
|
super.put(obj);
|
||||||
if (!this.isScheduled) {
|
if (!this.isScheduled) {
|
||||||
this.schedule();
|
this.schedule();
|
||||||
@ -295,14 +348,14 @@ let arenaStack: Arena[] = [];
|
|||||||
arenaStack.push(new SyncArena());
|
arenaStack.push(new SyncArena());
|
||||||
|
|
||||||
|
|
||||||
export class Amount extends ArenaObject {
|
export class Amount extends MallocArenaObject {
|
||||||
constructor(args?: AmountJson, arena?: Arena) {
|
constructor(args?: AmountJson, arena?: Arena) {
|
||||||
super(arena);
|
super(arena);
|
||||||
if (args) {
|
if (args) {
|
||||||
this.nativePtr = emscAlloc.get_amount(args.value,
|
this.nativePtr = emscAlloc.get_amount(args.value,
|
||||||
0,
|
0,
|
||||||
args.fraction,
|
args.fraction,
|
||||||
args.currency);
|
args.currency);
|
||||||
} else {
|
} else {
|
||||||
this.nativePtr = emscAlloc.get_amount(0, 0, 0, "");
|
this.nativePtr = emscAlloc.get_amount(0, 0, 0, "");
|
||||||
}
|
}
|
||||||
@ -399,7 +452,7 @@ export class Amount extends ArenaObject {
|
|||||||
/**
|
/**
|
||||||
* Count the UTF-8 characters in a JavaScript string.
|
* Count the UTF-8 characters in a JavaScript string.
|
||||||
*/
|
*/
|
||||||
function countBytes(str: string): number {
|
function countUtf8Bytes(str: string): number {
|
||||||
var s = str.length;
|
var s = str.length;
|
||||||
// JavaScript strings are UTF-16 arrays
|
// JavaScript strings are UTF-16 arrays
|
||||||
for (let i = str.length - 1; i >= 0; i--) {
|
for (let i = str.length - 1; i >= 0; i--) {
|
||||||
@ -424,7 +477,7 @@ function countBytes(str: string): number {
|
|||||||
* Managed reference to a contiguous block of memory in the Emscripten heap.
|
* Managed reference to a contiguous block of memory in the Emscripten heap.
|
||||||
* Should contain only data, not pointers.
|
* Should contain only data, not pointers.
|
||||||
*/
|
*/
|
||||||
abstract class PackedArenaObject extends ArenaObject {
|
abstract class PackedArenaObject extends MallocArenaObject {
|
||||||
abstract size(): number;
|
abstract size(): number;
|
||||||
|
|
||||||
constructor(a?: Arena) {
|
constructor(a?: Arena) {
|
||||||
@ -455,12 +508,12 @@ abstract class PackedArenaObject extends ArenaObject {
|
|||||||
// to the emscripten heap first.
|
// to the emscripten heap first.
|
||||||
let buf = ByteArray.fromString(s);
|
let buf = ByteArray.fromString(s);
|
||||||
let res = emsc.string_to_data(buf.nativePtr,
|
let res = emsc.string_to_data(buf.nativePtr,
|
||||||
s.length,
|
s.length,
|
||||||
this.nativePtr,
|
this.nativePtr,
|
||||||
this.size());
|
this.size());
|
||||||
buf.destroy();
|
buf.destroy();
|
||||||
if (res < 1) {
|
if (res < 1) {
|
||||||
throw {error: "wrong encoding"};
|
throw { error: "wrong encoding" };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -581,7 +634,7 @@ function makeFromCrock(decodeFn: (p: number, s: number) => number) {
|
|||||||
let obj = new this(a);
|
let obj = new this(a);
|
||||||
let buf = ByteArray.fromCrock(s);
|
let buf = ByteArray.fromCrock(s);
|
||||||
obj.setNative(decodeFn(buf.getNative(),
|
obj.setNative(decodeFn(buf.getNative(),
|
||||||
buf.size()));
|
buf.size()));
|
||||||
buf.destroy();
|
buf.destroy();
|
||||||
return obj;
|
return obj;
|
||||||
}
|
}
|
||||||
@ -590,7 +643,7 @@ function makeFromCrock(decodeFn: (p: number, s: number) => number) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function makeToCrock(encodeFn: (po: number,
|
function makeToCrock(encodeFn: (po: number,
|
||||||
ps: number) => number): () => string {
|
ps: number) => number): () => string {
|
||||||
function toCrock() {
|
function toCrock() {
|
||||||
let ptr = emscAlloc.malloc(PTR_SIZE);
|
let ptr = emscAlloc.malloc(PTR_SIZE);
|
||||||
let size = emscAlloc.rsa_blinding_key_encode(this.nativePtr, ptr);
|
let size = emscAlloc.rsa_blinding_key_encode(this.nativePtr, ptr);
|
||||||
@ -658,14 +711,14 @@ export class ByteArray extends PackedArenaObject {
|
|||||||
|
|
||||||
static fromString(s: string, a?: Arena): ByteArray {
|
static fromString(s: string, a?: Arena): ByteArray {
|
||||||
// UTF-8 bytes, including 0-terminator
|
// UTF-8 bytes, including 0-terminator
|
||||||
let terminatedByteLength = countBytes(s) + 1;
|
let terminatedByteLength = countUtf8Bytes(s) + 1;
|
||||||
let hstr = emscAlloc.malloc(terminatedByteLength);
|
let hstr = emscAlloc.malloc(terminatedByteLength);
|
||||||
Module.stringToUTF8(s, hstr, terminatedByteLength);
|
Module.stringToUTF8(s, hstr, terminatedByteLength);
|
||||||
return new ByteArray(terminatedByteLength, hstr, a);
|
return new ByteArray(terminatedByteLength, hstr, a);
|
||||||
}
|
}
|
||||||
|
|
||||||
static fromCrock(s: string, a?: Arena): ByteArray {
|
static fromCrock(s: string, a?: Arena): ByteArray {
|
||||||
let byteLength = countBytes(s);
|
let byteLength = countUtf8Bytes(s);
|
||||||
let hstr = emscAlloc.malloc(byteLength + 1);
|
let hstr = emscAlloc.malloc(byteLength + 1);
|
||||||
Module.stringToUTF8(s, hstr, byteLength + 1);
|
Module.stringToUTF8(s, hstr, byteLength + 1);
|
||||||
let decodedLen = Math.floor((byteLength * 5) / 8);
|
let decodedLen = Math.floor((byteLength * 5) / 8);
|
||||||
@ -688,12 +741,12 @@ export class EccSignaturePurpose extends PackedArenaObject {
|
|||||||
payloadSize: number;
|
payloadSize: number;
|
||||||
|
|
||||||
constructor(purpose: SignaturePurpose,
|
constructor(purpose: SignaturePurpose,
|
||||||
payload: PackedArenaObject,
|
payload: PackedArenaObject,
|
||||||
a?: Arena) {
|
a?: Arena) {
|
||||||
super(a);
|
super(a);
|
||||||
this.nativePtr = emscAlloc.purpose_create(purpose,
|
this.nativePtr = emscAlloc.purpose_create(purpose,
|
||||||
payload.nativePtr,
|
payload.nativePtr,
|
||||||
payload.size());
|
payload.size());
|
||||||
this.payloadSize = payload.size();
|
this.payloadSize = payload.size();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -798,6 +851,34 @@ export class WithdrawRequestPS extends SignatureStruct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
interface RefreshMeltCoinAffirmationPS_Args {
|
||||||
|
session_hash: HashCode;
|
||||||
|
amount_with_fee: AmountNbo;
|
||||||
|
melt_fee: AmountNbo;
|
||||||
|
coin_pub: EddsaPublicKey;
|
||||||
|
}
|
||||||
|
|
||||||
|
export class RefreshMeltCoinAffirmationPS extends SignatureStruct {
|
||||||
|
|
||||||
|
constructor(w: RefreshMeltCoinAffirmationPS_Args) {
|
||||||
|
super(w);
|
||||||
|
}
|
||||||
|
|
||||||
|
purpose() {
|
||||||
|
return SignaturePurpose.WALLET_COIN_MELT;
|
||||||
|
}
|
||||||
|
|
||||||
|
fieldTypes() {
|
||||||
|
return [
|
||||||
|
["session_hash", HashCode],
|
||||||
|
["amount_with_fee", AmountNbo],
|
||||||
|
["melt_fee", AmountNbo],
|
||||||
|
["coin_pub", EddsaPublicKey]
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
export class AbsoluteTimeNbo extends PackedArenaObject {
|
export class AbsoluteTimeNbo extends PackedArenaObject {
|
||||||
static fromTalerString(s: string): AbsoluteTimeNbo {
|
static fromTalerString(s: string): AbsoluteTimeNbo {
|
||||||
let x = new AbsoluteTimeNbo();
|
let x = new AbsoluteTimeNbo();
|
||||||
@ -825,7 +906,14 @@ function set64(p: number, n: number) {
|
|||||||
Module.setValue(p + (7 - i), n & 0xFF, "i8");
|
Module.setValue(p + (7 - i), n & 0xFF, "i8");
|
||||||
n = Math.floor(n / 256);
|
n = Math.floor(n / 256);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// XXX: This only works up to 54 bit numbers.
|
||||||
|
function set32(p: number, n: number) {
|
||||||
|
for (let i = 0; i < 4; ++i) {
|
||||||
|
Module.setValue(p + (3 - i), n & 0xFF, "i8");
|
||||||
|
n = Math.floor(n / 256);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -843,6 +931,20 @@ export class UInt64 extends PackedArenaObject {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export class UInt32 extends PackedArenaObject {
|
||||||
|
static fromNumber(n: number): UInt64 {
|
||||||
|
let x = new UInt32();
|
||||||
|
x.alloc();
|
||||||
|
set32(x.getNative(), n);
|
||||||
|
return x;
|
||||||
|
}
|
||||||
|
|
||||||
|
size() {
|
||||||
|
return 8;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// It's redundant, but more type safe.
|
// It's redundant, but more type safe.
|
||||||
export interface DepositRequestPS_Args {
|
export interface DepositRequestPS_Args {
|
||||||
h_contract: HashCode;
|
h_contract: HashCode;
|
||||||
@ -940,7 +1042,7 @@ function makeEncode(encodeFn: any) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
export class RsaPublicKey extends ArenaObject implements Encodeable {
|
export class RsaPublicKey extends MallocArenaObject implements Encodeable {
|
||||||
static fromCrock: (s: string, a?: Arena) => RsaPublicKey;
|
static fromCrock: (s: string, a?: Arena) => RsaPublicKey;
|
||||||
|
|
||||||
toCrock() {
|
toCrock() {
|
||||||
@ -965,7 +1067,7 @@ export class EddsaSignature extends PackedArenaObject {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
export class RsaSignature extends ArenaObject implements Encodeable {
|
export class RsaSignature extends MallocArenaObject implements Encodeable {
|
||||||
static fromCrock: (s: string, a?: Arena) => RsaSignature;
|
static fromCrock: (s: string, a?: Arena) => RsaSignature;
|
||||||
|
|
||||||
encode: (arena?: Arena) => ByteArray;
|
encode: (arena?: Arena) => ByteArray;
|
||||||
@ -980,21 +1082,21 @@ mixin(RsaSignature, makeEncode(emscAlloc.rsa_signature_encode));
|
|||||||
|
|
||||||
|
|
||||||
export function rsaBlind(hashCode: HashCode,
|
export function rsaBlind(hashCode: HashCode,
|
||||||
blindingKey: RsaBlindingKeySecret,
|
blindingKey: RsaBlindingKeySecret,
|
||||||
pkey: RsaPublicKey,
|
pkey: RsaPublicKey,
|
||||||
arena?: Arena): ByteArray {
|
arena?: Arena): ByteArray {
|
||||||
let ptr = emscAlloc.malloc(PTR_SIZE);
|
let ptr = emscAlloc.malloc(PTR_SIZE);
|
||||||
let s = emscAlloc.rsa_blind(hashCode.nativePtr,
|
let s = emscAlloc.rsa_blind(hashCode.nativePtr,
|
||||||
blindingKey.nativePtr,
|
blindingKey.nativePtr,
|
||||||
pkey.nativePtr,
|
pkey.nativePtr,
|
||||||
ptr);
|
ptr);
|
||||||
return new ByteArray(s, Module.getValue(ptr, '*'), arena);
|
return new ByteArray(s, Module.getValue(ptr, '*'), arena);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
export function eddsaSign(purpose: EccSignaturePurpose,
|
export function eddsaSign(purpose: EccSignaturePurpose,
|
||||||
priv: EddsaPrivateKey,
|
priv: EddsaPrivateKey,
|
||||||
a?: Arena): EddsaSignature {
|
a?: Arena): EddsaSignature {
|
||||||
let sig = new EddsaSignature(a);
|
let sig = new EddsaSignature(a);
|
||||||
sig.alloc();
|
sig.alloc();
|
||||||
let res = emsc.eddsa_sign(priv.nativePtr, purpose.nativePtr, sig.nativePtr);
|
let res = emsc.eddsa_sign(priv.nativePtr, purpose.nativePtr, sig.nativePtr);
|
||||||
@ -1006,14 +1108,14 @@ export function eddsaSign(purpose: EccSignaturePurpose,
|
|||||||
|
|
||||||
|
|
||||||
export function eddsaVerify(purposeNum: number,
|
export function eddsaVerify(purposeNum: number,
|
||||||
verify: EccSignaturePurpose,
|
verify: EccSignaturePurpose,
|
||||||
sig: EddsaSignature,
|
sig: EddsaSignature,
|
||||||
pub: EddsaPublicKey,
|
pub: EddsaPublicKey,
|
||||||
a?: Arena): boolean {
|
a?: Arena): boolean {
|
||||||
let r = emsc.eddsa_verify(purposeNum,
|
let r = emsc.eddsa_verify(purposeNum,
|
||||||
verify.nativePtr,
|
verify.nativePtr,
|
||||||
sig.nativePtr,
|
sig.nativePtr,
|
||||||
pub.nativePtr);
|
pub.nativePtr);
|
||||||
if (r === GNUNET_OK) {
|
if (r === GNUNET_OK) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -1022,12 +1124,61 @@ export function eddsaVerify(purposeNum: number,
|
|||||||
|
|
||||||
|
|
||||||
export function rsaUnblind(sig: RsaSignature,
|
export function rsaUnblind(sig: RsaSignature,
|
||||||
bk: RsaBlindingKeySecret,
|
bk: RsaBlindingKeySecret,
|
||||||
pk: RsaPublicKey,
|
pk: RsaPublicKey,
|
||||||
a?: Arena): RsaSignature {
|
a?: Arena): RsaSignature {
|
||||||
let x = new RsaSignature(a);
|
let x = new RsaSignature(a);
|
||||||
x.nativePtr = emscAlloc.rsa_unblind(sig.nativePtr,
|
x.nativePtr = emscAlloc.rsa_unblind(sig.nativePtr,
|
||||||
bk.nativePtr,
|
bk.nativePtr,
|
||||||
pk.nativePtr);
|
pk.nativePtr);
|
||||||
return x;
|
return x;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
type TransferSecretP = HashCode;
|
||||||
|
|
||||||
|
export function kdf(outLength: number,
|
||||||
|
salt: PackedArenaObject,
|
||||||
|
skm: PackedArenaObject,
|
||||||
|
...contextChunks: PackedArenaObject[]): ByteArray {
|
||||||
|
const args: number[] = [];
|
||||||
|
let out = new ByteArray(outLength);
|
||||||
|
args.push(out.nativePtr, outLength);
|
||||||
|
args.push(salt.nativePtr, salt.size());
|
||||||
|
args.push(skm.nativePtr, skm.size());
|
||||||
|
for (let chunk of contextChunks) {
|
||||||
|
args.push(chunk.nativePtr, chunk.size());
|
||||||
|
}
|
||||||
|
// end terminator (it's varargs)
|
||||||
|
args.push(0);
|
||||||
|
args.push(0);
|
||||||
|
|
||||||
|
let argTypes = args.map(() => "number");
|
||||||
|
|
||||||
|
const res = Module.ccall("GNUNET_CRYPTO_kdf", "number", argTypes, args);
|
||||||
|
if (res != GNUNET_OK) {
|
||||||
|
throw Error("fatal: kdf failed");
|
||||||
|
}
|
||||||
|
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export interface FreshCoin {
|
||||||
|
priv: EddsaPrivateKey;
|
||||||
|
blindingKey: RsaBlindingKeySecret;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function setupFreshCoin(secretSeed: TransferSecretP, coinIndex: number): FreshCoin {
|
||||||
|
let priv = new EddsaPrivateKey();
|
||||||
|
priv.isWeak = true;
|
||||||
|
let blindingKey = new RsaBlindingKeySecret();
|
||||||
|
blindingKey.isWeak = true;
|
||||||
|
|
||||||
|
let buf = kdf(priv.size() + blindingKey.size(), UInt32.fromNumber(coinIndex), ByteArray.fromString("taler-coin-derivation"));
|
||||||
|
|
||||||
|
priv.nativePtr = buf.nativePtr;
|
||||||
|
blindingKey.nativePtr = buf.nativePtr + priv.size();
|
||||||
|
|
||||||
|
return { priv, blindingKey };
|
||||||
|
}
|
@ -14,7 +14,6 @@
|
|||||||
TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
|
TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Smaller helper functions that do not depend
|
* Smaller helper functions that do not depend
|
||||||
* on the emscripten machinery.
|
* on the emscripten machinery.
|
||||||
@ -22,7 +21,10 @@
|
|||||||
* @author Florian Dold
|
* @author Florian Dold
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/// <reference path="../decl/urijs/URIjs.d.ts" />
|
||||||
|
|
||||||
import {AmountJson} from "./types";
|
import {AmountJson} from "./types";
|
||||||
|
import URI = uri.URI;
|
||||||
|
|
||||||
export function substituteFulfillmentUrl(url: string, vars: any) {
|
export function substituteFulfillmentUrl(url: string, vars: any) {
|
||||||
url = url.replace("${H_contract}", vars.H_contract);
|
url = url.replace("${H_contract}", vars.H_contract);
|
||||||
@ -43,7 +45,7 @@ export function amountToPretty(amount: AmountJson): string {
|
|||||||
* See http://api.taler.net/wallet.html#general
|
* See http://api.taler.net/wallet.html#general
|
||||||
*/
|
*/
|
||||||
export function canonicalizeBaseUrl(url: string) {
|
export function canonicalizeBaseUrl(url: string) {
|
||||||
let x = new URI(url);
|
let x: URI = new URI(url);
|
||||||
if (!x.protocol()) {
|
if (!x.protocol()) {
|
||||||
x.protocol("https");
|
x.protocol("https");
|
||||||
}
|
}
|
||||||
|
@ -25,7 +25,7 @@
|
|||||||
* @author Florian Dold
|
* @author Florian Dold
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import {Checkable} from "./checkable";
|
import { Checkable } from "./checkable";
|
||||||
|
|
||||||
@Checkable.Class
|
@Checkable.Class
|
||||||
export class AmountJson {
|
export class AmountJson {
|
||||||
@ -120,7 +120,7 @@ export interface IExchangeInfo {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export interface WireInfo {
|
export interface WireInfo {
|
||||||
[type: string]: any;
|
[type: string]: any;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ReserveCreationInfo {
|
export interface ReserveCreationInfo {
|
||||||
@ -148,6 +148,53 @@ export interface PreCoin {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Ongoing refresh
|
||||||
|
*/
|
||||||
|
export interface RefreshSession {
|
||||||
|
/**
|
||||||
|
* Public key that's being melted in this session.
|
||||||
|
*/
|
||||||
|
meltCoinPub: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* How much of the coin's value is melted away
|
||||||
|
* with this refresh session?
|
||||||
|
*/
|
||||||
|
valueWithFee: AmountJson
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Signature to confirm the melting.
|
||||||
|
*/
|
||||||
|
confirmSig: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Denominations of the newly requested coins
|
||||||
|
*/
|
||||||
|
newDenoms: string[];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Blinded public keys for the requested coins.
|
||||||
|
*/
|
||||||
|
newCoinBlanks: string[][];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Blinding factors for the new coins.
|
||||||
|
*/
|
||||||
|
newCoinBlindingFactors: string[][];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Private keys for the requested coins.
|
||||||
|
*/
|
||||||
|
newCoinPrivs: string[][];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The transfer keys, kappa of them.
|
||||||
|
*/
|
||||||
|
transferPubs: string[];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
export interface Reserve {
|
export interface Reserve {
|
||||||
exchange_base_url: string
|
exchange_base_url: string
|
||||||
reserve_priv: string;
|
reserve_priv: string;
|
||||||
@ -165,7 +212,6 @@ export interface CoinPaySig {
|
|||||||
f: AmountJson;
|
f: AmountJson;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Coin as stored in the "coins" data store
|
* Coin as stored in the "coins" data store
|
||||||
* of the wallet database.
|
* of the wallet database.
|
||||||
@ -291,7 +337,7 @@ export namespace Amounts {
|
|||||||
return {
|
return {
|
||||||
currency,
|
currency,
|
||||||
value: Number.MAX_SAFE_INTEGER,
|
value: Number.MAX_SAFE_INTEGER,
|
||||||
fraction: 2**32,
|
fraction: 2 ** 32,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -307,7 +353,7 @@ export namespace Amounts {
|
|||||||
let currency = first.currency;
|
let currency = first.currency;
|
||||||
let value = first.value + Math.floor(first.fraction / 1e6);
|
let value = first.value + Math.floor(first.fraction / 1e6);
|
||||||
if (value > Number.MAX_SAFE_INTEGER) {
|
if (value > Number.MAX_SAFE_INTEGER) {
|
||||||
return {amount: getMaxAmount(currency), saturated: true};
|
return { amount: getMaxAmount(currency), saturated: true };
|
||||||
}
|
}
|
||||||
let fraction = first.fraction % 1e6;
|
let fraction = first.fraction % 1e6;
|
||||||
for (let x of rest) {
|
for (let x of rest) {
|
||||||
@ -318,10 +364,10 @@ export namespace Amounts {
|
|||||||
value = value + x.value + Math.floor((fraction + x.fraction) / 1e6);
|
value = value + x.value + Math.floor((fraction + x.fraction) / 1e6);
|
||||||
fraction = (fraction + x.fraction) % 1e6;
|
fraction = (fraction + x.fraction) % 1e6;
|
||||||
if (value > Number.MAX_SAFE_INTEGER) {
|
if (value > Number.MAX_SAFE_INTEGER) {
|
||||||
return {amount: getMaxAmount(currency), saturated: true};
|
return { amount: getMaxAmount(currency), saturated: true };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return {amount: {currency, value, fraction}, saturated: false};
|
return { amount: { currency, value, fraction }, saturated: false };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -334,7 +380,7 @@ export namespace Amounts {
|
|||||||
let fraction = a.fraction;
|
let fraction = a.fraction;
|
||||||
if (fraction < b.fraction) {
|
if (fraction < b.fraction) {
|
||||||
if (value < 1) {
|
if (value < 1) {
|
||||||
return {amount: {currency, value: 0, fraction: 0}, saturated: true};
|
return { amount: { currency, value: 0, fraction: 0 }, saturated: true };
|
||||||
}
|
}
|
||||||
value--;
|
value--;
|
||||||
fraction += 1e6;
|
fraction += 1e6;
|
||||||
@ -342,10 +388,10 @@ export namespace Amounts {
|
|||||||
console.assert(fraction >= b.fraction);
|
console.assert(fraction >= b.fraction);
|
||||||
fraction -= b.fraction;
|
fraction -= b.fraction;
|
||||||
if (value < b.value) {
|
if (value < b.value) {
|
||||||
return {amount: {currency, value: 0, fraction: 0}, saturated: true};
|
return { amount: { currency, value: 0, fraction: 0 }, saturated: true };
|
||||||
}
|
}
|
||||||
value -= b.value;
|
value -= b.value;
|
||||||
return {amount: {currency, value, fraction}, saturated: false};
|
return { amount: { currency, value, fraction }, saturated: false };
|
||||||
}
|
}
|
||||||
|
|
||||||
export function cmp(a: AmountJson, b: AmountJson): number {
|
export function cmp(a: AmountJson, b: AmountJson): number {
|
||||||
|
@ -84,6 +84,30 @@ interface CoinViewProps {
|
|||||||
coin: Coin;
|
coin: Coin;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface RefreshDialogProps {
|
||||||
|
coin: Coin;
|
||||||
|
}
|
||||||
|
|
||||||
|
class RefreshDialog extends ImplicitStateComponent<RefreshDialogProps> {
|
||||||
|
refreshRequested = this.makeState<boolean>(false);
|
||||||
|
render(): JSX.Element {
|
||||||
|
if (!this.refreshRequested()) {
|
||||||
|
return (
|
||||||
|
<div style="display:inline;">
|
||||||
|
<button onClick={() => this.refreshRequested(true)}>refresh</button>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
Refresh amount: <input type="text" size={10} />
|
||||||
|
<button>ok</button>
|
||||||
|
<button onClick={() => this.refreshRequested(false)}>cancel</button>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
class CoinView extends preact.Component<CoinViewProps, void> {
|
class CoinView extends preact.Component<CoinViewProps, void> {
|
||||||
render() {
|
render() {
|
||||||
let c = this.props.coin;
|
let c = this.props.coin;
|
||||||
@ -94,6 +118,7 @@ class CoinView extends preact.Component<CoinViewProps, void> {
|
|||||||
<li>Current amount: {prettyAmount(c.currentAmount)}</li>
|
<li>Current amount: {prettyAmount(c.currentAmount)}</li>
|
||||||
<li>Denomination: {abbrev(c.denomPub, 20)}</li>
|
<li>Denomination: {abbrev(c.denomPub, 20)}</li>
|
||||||
<li>Suspended: {(c.suspended || false).toString()}</li>
|
<li>Suspended: {(c.suspended || false).toString()}</li>
|
||||||
|
<li><RefreshDialog coin={c} /></li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
Loading…
Reference in New Issue
Block a user