Make withdrawal signature work.

This commit is contained in:
Florian Dold 2015-12-14 16:54:47 +01:00
parent e92d26a937
commit f588e1a60e
5 changed files with 4082 additions and 3670 deletions

View File

@ -17,6 +17,10 @@
"use strict";
// Size of a native pointer.
const PTR_SIZE = 4;
const GNUNET_OK = 1;
const GNUNET_YES = 1;
const GNUNET_NO = 0;
const GNUNET_SYSERR = -1;
let getEmsc = Module.cwrap;
var emsc = {
free: (ptr) => Module._free(ptr),
@ -32,7 +36,9 @@ var emsc = {
hash: getEmsc('GNUNET_CRYPTO_hash', 'void', ['number', 'number', 'number']),
memmove: getEmsc('memmove', 'number', ['number', 'number', 'number']),
rsa_public_key_free: getEmsc('GNUNET_CRYPTO_rsa_public_key_free', 'void', ['number']),
string_to_data: getEmsc('GNUNET_STRINGS_string_to_data', 'void', ['number', 'number', 'number', 'number'])
string_to_data: getEmsc('GNUNET_STRINGS_string_to_data', 'void', ['number', 'number', 'number', 'number']),
eddsa_sign: getEmsc('GNUNET_CRYPTO_eddsa_sign', 'number', ['number', 'number', 'number']),
hash_create_random: getEmsc('GNUNET_CRYPTO_hash_create_random', 'void', ['number', 'number']),
};
var emscAlloc = {
get_amount: getEmsc('TALER_WRALL_get_amount', 'number', ['number', 'number', 'number', 'string']),
@ -45,14 +51,22 @@ var emscAlloc = {
rsa_blinding_key_encode: getEmsc('GNUNET_CRYPTO_rsa_blinding_key_encode', 'void', ['number', 'number']),
rsa_blinding_key_decode: getEmsc('GNUNET_CRYPTO_rsa_blinding_key_decode', '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']),
malloc: (size) => Module._malloc(size),
};
var SignaturePurpose;
(function (SignaturePurpose) {
SignaturePurpose[SignaturePurpose["RESERVE_WITHDRAW"] = 1200] = "RESERVE_WITHDRAW";
})(SignaturePurpose || (SignaturePurpose = {}));
var RandomQuality;
(function (RandomQuality) {
RandomQuality[RandomQuality["WEAK"] = 0] = "WEAK";
RandomQuality[RandomQuality["STRONG"] = 1] = "STRONG";
RandomQuality[RandomQuality["NONCE"] = 2] = "NONCE";
})(RandomQuality || (RandomQuality = {}));
class ArenaObject {
constructor(arena) {
this.nativePtr = 0;
this.nativePtr = null;
if (!arena)
arena = defaultArena;
arena.put(this);
@ -66,7 +80,7 @@ class Arena {
put(obj) {
this.heap.push(obj);
}
destroy(obj) {
destroy() {
// XXX: todo
}
}
@ -149,13 +163,13 @@ class PackedArenaObject extends ArenaObject {
constructor(a) {
super(a);
}
stringEncode() {
toCrock() {
var d = emscAlloc.data_to_string_alloc(this.nativePtr, this.size());
var s = Module.Pointer_stringify(d);
emsc.free(d);
return s;
}
stringDecode(s) {
loadCrock(s) {
this.alloc();
// We need to get the javascript string
// to the emscripten heap first.
@ -177,6 +191,7 @@ class PackedArenaObject extends ArenaObject {
}
hash() {
var x = new HashCode();
x.alloc();
emsc.hash(this.nativePtr, this.size(), x.nativePtr);
return x;
}
@ -206,11 +221,11 @@ class RsaBlindingKey extends ArenaObject {
o.nativePtr = emscAlloc.rsa_blinding_key_create(len);
return o;
}
stringEncode() {
toCrock() {
let ptr = emscAlloc.malloc(PTR_SIZE);
let size = emscAlloc.rsa_blinding_key_encode(this.nativePtr, ptr);
let res = new ByteArray(size, Module.getValue(ptr, '*'));
let s = res.stringEncode();
let s = res.toCrock();
emsc.free(ptr);
res.destroy();
return s;
@ -221,6 +236,27 @@ class RsaBlindingKey extends ArenaObject {
}
class HashCode extends PackedArenaObject {
size() { return 64; }
random(qualStr) {
let qual;
switch (qualStr) {
case "weak":
qual = RandomQuality.WEAK;
break;
case "strong":
case null:
case undefined:
qual = RandomQuality.STRONG;
break;
case "nonce":
qual = RandomQuality.NONCE;
break;
break;
default:
throw Error(format("unknown crypto quality: {0}", qual));
}
this.alloc();
emsc.hash_create_random(qual, this.nativePtr);
}
}
class ByteArray extends PackedArenaObject {
constructor(desiredSize, init, a) {
@ -239,13 +275,26 @@ class ByteArray extends PackedArenaObject {
Module.writeStringToMemory(s, hstr);
return new ByteArray(s.length, hstr, a);
}
static fromCrock(s, a) {
let hstr = emscAlloc.malloc(s.length + 1);
Module.writeStringToMemory(s, hstr);
let decodedLen = Math.floor((s.length * 5) / 8);
let ba = new ByteArray(decodedLen, null, a);
let res = emsc.string_to_data(hstr, s.length, ba.nativePtr, decodedLen);
emsc.free(hstr);
if (res != GNUNET_OK) {
throw Error("decoding failed");
}
return ba;
}
}
class EccSignaturePurpose extends PackedArenaObject {
constructor(purpose, payload, a) {
super(a);
this.nativePtr = emscAlloc.purpose_create(purpose, payload.nativePtr, payload.size());
this.payloadSize = payload.size();
}
size() { return this.payload.size() + 8; }
size() { return this.payloadSize + 8; }
}
class SignatureStruct {
constructor() {
@ -259,7 +308,7 @@ class SignatureStruct {
if (!member) {
throw Error(format("Member {0} not set", name));
}
totalSize += this.members[name].size();
totalSize += member.size();
}
let buf = emscAlloc.malloc(totalSize);
let ptr = buf;
@ -271,7 +320,7 @@ class SignatureStruct {
ptr += size;
}
let ba = new ByteArray(totalSize, buf, a);
let x = new EccSignaturePurpose(this.purpose(), ba, a);
let x = new EccSignaturePurpose(this.purpose(), ba);
return x;
}
set(name, value) {
@ -280,38 +329,47 @@ class SignatureStruct {
typemap[f[0]] = f[1];
}
if (!(name in typemap)) {
throw { error: "Key not found", key: name };
throw Error(format("Key {0} not found", name));
}
if (!(value instanceof typemap[name])) {
throw { error: "Wrong type", key: name };
throw Error(format("Wrong type for {0}", name));
}
// TODO: check type!
this.members[name] = value;
}
}
class WithdrawRequestPS extends SignatureStruct {
purpose() { return undefined; }
purpose() { return SignaturePurpose.RESERVE_WITHDRAW; }
fieldTypes() {
return [
["reserve_pub", EddsaPublicKey],
["amount_with_fee", Amount],
["withdraw_fee", Amount],
["amount_with_fee", AmountNbo],
["withdraw_fee", AmountNbo],
["h_denomination_pub", HashCode],
["h_coin_envelope", HashCode]];
}
}
class RsaPublicKey extends ArenaObject {
static stringDecode(s, a) {
static fromCrock(s, a) {
let obj = new RsaPublicKey(a);
let buf = ByteArray.fromString(s);
obj.nativePtr = emscAlloc.rsa_public_key_decode(buf.nativePtr, s.length);
let buf = ByteArray.fromCrock(s);
obj.nativePtr = emscAlloc.rsa_public_key_decode(buf.nativePtr, buf.size());
buf.destroy();
return obj;
}
toCrock() {
return this.encode().toCrock();
}
destroy() {
emsc.rsa_public_key_free(this.nativePtr);
this.nativePtr = 0;
}
encode(arena) {
let ptr = emscAlloc.malloc(PTR_SIZE);
let len = emscAlloc.rsa_public_key_encode(this.nativePtr, ptr);
let res = new ByteArray(len, Module.getValue(ptr, '*'), arena);
emsc.free(ptr);
return res;
}
}
class EddsaSignature extends PackedArenaObject {
size() { return 64; }
@ -323,5 +381,11 @@ function rsaBlind(hashCode, blindingKey, pkey, arena) {
return res;
}
function eddsaSign(purpose, priv, a) {
throw "Not implemented";
let sig = new EddsaSignature(a);
sig.alloc();
let res = emsc.eddsa_sign(priv.nativePtr, purpose.nativePtr, sig.nativePtr);
if (res < 1) {
throw Error("EdDSA signing failed");
}
return sig;
}

View File

@ -23,6 +23,11 @@ declare var Module : any;
// Size of a native pointer.
const PTR_SIZE = 4;
const GNUNET_OK = 1;
const GNUNET_YES = 1;
const GNUNET_NO = 0;
const GNUNET_SYSERR = -1;
let getEmsc = Module.cwrap;
var emsc = {
@ -65,7 +70,13 @@ var emsc = {
['number']),
string_to_data: getEmsc('GNUNET_STRINGS_string_to_data',
'void',
['number', 'number', 'number', 'number'])
['number', 'number', 'number', 'number']),
eddsa_sign: getEmsc('GNUNET_CRYPTO_eddsa_sign',
'number',
['number', 'number', 'number']),
hash_create_random: getEmsc('GNUNET_CRYPTO_hash_create_random',
'void',
['number', 'number']),
};
var emscAlloc = {
@ -98,11 +109,21 @@ var emscAlloc = {
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']),
malloc: (size: number) => Module._malloc(size),
};
enum SignaturePurpose {
RESERVE_WITHDRAW = 1200
}
enum RandomQuality {
WEAK = 0,
STRONG = 1,
NONCE = 2
}
@ -112,7 +133,7 @@ abstract class ArenaObject {
abstract destroy(): void;
constructor(arena?: Arena) {
this.nativePtr = 0;
this.nativePtr = null;
if (!arena)
arena = defaultArena;
arena.put(this);
@ -130,7 +151,7 @@ class Arena {
this.heap.push(obj);
}
destroy(obj) {
destroy() {
// XXX: todo
}
}
@ -232,14 +253,14 @@ abstract class PackedArenaObject extends ArenaObject {
super(a);
}
stringEncode(): string {
toCrock(): string {
var d = emscAlloc.data_to_string_alloc(this.nativePtr, this.size());
var s = Module.Pointer_stringify(d);
emsc.free(d);
return s;
}
stringDecode(s: string) {
loadCrock(s: string) {
this.alloc();
// We need to get the javascript string
// to the emscripten heap first.
@ -264,6 +285,7 @@ abstract class PackedArenaObject extends ArenaObject {
hash(): HashCode {
var x = new HashCode();
x.alloc();
emsc.hash(this.nativePtr, this.size(), x.nativePtr);
return x;
}
@ -304,11 +326,11 @@ class RsaBlindingKey extends ArenaObject {
return o;
}
stringEncode(): string {
toCrock(): string {
let ptr = emscAlloc.malloc(PTR_SIZE);
let size = emscAlloc.rsa_blinding_key_encode(this.nativePtr, ptr);
let res = new ByteArray(size, Module.getValue(ptr, '*'));
let s = res.stringEncode();
let s = res.toCrock();
emsc.free(ptr);
res.destroy();
return s;
@ -322,6 +344,28 @@ class RsaBlindingKey extends ArenaObject {
class HashCode extends PackedArenaObject {
size() { return 64; }
random(qualStr: string) {
let qual: RandomQuality;
switch (qualStr) {
case "weak":
qual = RandomQuality.WEAK;
break;
case "strong":
case null:
case undefined:
qual = RandomQuality.STRONG;
break;
case "nonce":
qual = RandomQuality.NONCE;
break;
break;
default:
throw Error(format("unknown crypto quality: {0}", qual));
}
this.alloc();
emsc.hash_create_random(qual, this.nativePtr);
}
}
@ -344,15 +388,29 @@ class ByteArray extends PackedArenaObject {
Module.writeStringToMemory(s, hstr);
return new ByteArray(s.length, hstr, a);
}
static fromCrock(s: string, a?: Arena): ByteArray {
let hstr = emscAlloc.malloc(s.length + 1);
Module.writeStringToMemory(s, hstr);
let decodedLen = Math.floor((s.length * 5) / 8);
let ba = new ByteArray(decodedLen, null, a);
let res = emsc.string_to_data(hstr, s.length, ba.nativePtr, decodedLen);
emsc.free(hstr);
if (res != GNUNET_OK) {
throw Error("decoding failed");
}
return ba;
}
}
class EccSignaturePurpose extends PackedArenaObject {
size() { return this.payload.size() + 8; }
payload: PackedArenaObject;
size() { return this.payloadSize + 8; }
payloadSize: number;
constructor(purpose: SignaturePurpose, payload: PackedArenaObject, a?: Arena) {
super(a);
this.nativePtr = emscAlloc.purpose_create(purpose, payload.nativePtr, payload.size());
this.payloadSize = payload.size();
}
}
@ -369,8 +427,9 @@ abstract class SignatureStruct {
if (!member) {
throw Error(format("Member {0} not set", name));
}
totalSize += this.members[name].size();
totalSize += member.size();
}
let buf = emscAlloc.malloc(totalSize);
let ptr = buf;
for (let f of this.fieldTypes()) {
@ -381,33 +440,33 @@ abstract class SignatureStruct {
ptr += size;
}
let ba = new ByteArray(totalSize, buf, a);
let x = new EccSignaturePurpose(this.purpose(), ba, a);
let x = new EccSignaturePurpose(this.purpose(), ba);
return x;
}
set(name: string, value: any) {
set(name: string, value: PackedArenaObject) {
let typemap: any = {}
for (let f of this.fieldTypes()) {
typemap[f[0]] = f[1];
}
if (!(name in typemap)) {
throw {error: "Key not found", key: name};
throw Error(format("Key {0} not found", name));
}
if (!(value instanceof typemap[name])) {
throw {error: "Wrong type", key: name};
throw Error(format("Wrong type for {0}", name));
}
// TODO: check type!
this.members[name] = value;
}
}
class WithdrawRequestPS extends SignatureStruct {
purpose() { return undefined; }
purpose() { return SignaturePurpose.RESERVE_WITHDRAW; }
fieldTypes() {
return [
["reserve_pub", EddsaPublicKey],
["amount_with_fee", Amount],
["withdraw_fee", Amount],
["amount_with_fee", AmountNbo],
["withdraw_fee", AmountNbo],
["h_denomination_pub", HashCode],
["h_coin_envelope", HashCode]];
}
@ -415,20 +474,34 @@ class WithdrawRequestPS extends SignatureStruct {
class RsaPublicKey extends ArenaObject {
static stringDecode(s: string, a?: Arena): RsaPublicKey {
static fromCrock(s: string, a?: Arena): RsaPublicKey {
let obj = new RsaPublicKey(a);
let buf = ByteArray.fromString(s);
obj.nativePtr = emscAlloc.rsa_public_key_decode(buf.nativePtr, s.length);
let buf = ByteArray.fromCrock(s);
obj.nativePtr = emscAlloc.rsa_public_key_decode(buf.nativePtr, buf.size());
buf.destroy();
return obj;
}
toCrock() {
return this.encode().toCrock();
}
destroy() {
emsc.rsa_public_key_free(this.nativePtr);
this.nativePtr = 0;
}
encode(arena?: Arena): ByteArray {
let ptr = emscAlloc.malloc(PTR_SIZE);
let len = emscAlloc.rsa_public_key_encode(this.nativePtr, ptr);
let res = new ByteArray(len, Module.getValue(ptr, '*'), arena);
emsc.free(ptr);
return res;
}
}
class EddsaSignature extends PackedArenaObject {
size() { return 64; }
}
@ -450,6 +523,12 @@ function eddsaSign(purpose: EccSignaturePurpose,
priv: EddsaPrivateKey,
a?: Arena): EddsaSignature
{
throw "Not implemented";
let sig = new EddsaSignature(a);
sig.alloc();
let res = emsc.eddsa_sign(priv.nativePtr, purpose.nativePtr, sig.nativePtr);
if (res < 1) {
throw Error("EdDSA signing failed");
}
return sig;
}

File diff suppressed because one or more lines are too long

View File

@ -50,7 +50,7 @@ function confirmReserve(db, detail, sendResponse) {
let form = new FormData();
let now = (new Date()).toString();
form.append(detail.field_amount, detail.amount_str);
form.append(detail.field_reserve_pub, reservePub.stringEncode());
form.append(detail.field_reserve_pub, reservePub.toCrock());
form.append(detail.field_mint, detail.mint);
// XXX: set bank-specified fields.
let myRequest = new XMLHttpRequest();
@ -68,8 +68,8 @@ function confirmReserve(db, detail, sendResponse) {
backlink: undefined
};
let reserveRecord = {
reserve_pub: reservePub.stringEncode(),
reserve_priv: reservePriv.stringEncode(),
reserve_pub: reservePub.toCrock(),
reserve_priv: reservePriv.toCrock(),
mint_base_url: mintBaseUrl,
created: now,
last_query: null,
@ -114,25 +114,72 @@ function rankDenom(denom1, denom2) {
return (-1) * v1.cmp(v2);
}
function withdraw(denom, reserve, mint) {
let wd = {
denom_pub: denom.denom_pub,
reserve_pub: reserve.reserve_pub,
};
let reservePriv = new EddsaPrivateKey();
reservePriv.stringDecode(reserve.reserve_priv);
let reservePub = new EddsaPublicKey();
reservePub.stringDecode(reserve.reserve_pub);
let denomPub = RsaPublicKey.stringDecode(denom.denom_pub);
let coinPriv = EddsaPrivateKey.create();
let coinPub = coinPriv.getPublicKey();
let blindingFactor = RsaBlindingKey.create(1024);
let pubHash = coinPub.hash();
let ev = rsaBlind(pubHash, blindingFactor, denomPub);
// Signature
let withdrawRequest = new WithdrawRequestPS();
withdrawRequest.set("reserve_pub", reservePub);
// ...
var sig = eddsaSign(withdrawRequest.toPurpose(), reservePriv);
console.log("in withdraw");
let wd = {};
wd.denom_pub = denom.denom_pub;
wd.reserve_pub = reserve.reserve_pub;
let a = new Arena();
try {
let reservePriv = new EddsaPrivateKey();
reservePriv.loadCrock(reserve.reserve_priv);
let reservePub = new EddsaPublicKey();
reservePub.loadCrock(reserve.reserve_pub);
let denomPub = RsaPublicKey.fromCrock(denom.denom_pub);
let coinPriv = EddsaPrivateKey.create();
let coinPub = coinPriv.getPublicKey();
let blindingFactor = RsaBlindingKey.create(1024);
let pubHash = coinPub.hash();
console.log("about to blind");
let ev = rsaBlind(pubHash, blindingFactor, denomPub);
console.log("blinded");
if (!denom.fee_withdraw) {
throw Error("Field fee_withdraw missing");
}
let amountWithFee = new Amount(denom.value);
amountWithFee.add(new Amount(denom.fee_withdraw));
let withdrawFee = new Amount(denom.fee_withdraw);
// Signature
let withdrawRequest = new WithdrawRequestPS();
withdrawRequest.set("reserve_pub", reservePub);
withdrawRequest.set("amount_with_fee", amountWithFee.toNbo());
withdrawRequest.set("withdraw_fee", withdrawFee.toNbo());
withdrawRequest.set("h_denomination_pub", denomPub.encode().hash());
withdrawRequest.set("h_coin_envelope", ev.hash());
console.log("about to sign");
var sig = eddsaSign(withdrawRequest.toPurpose(), reservePriv);
console.log("signed");
wd.reserve_sig = sig.toCrock();
wd.coin_ev = ev.toCrock();
}
finally {
a.destroy();
}
console.log("crypto done, doing request");
console.log("request:");
console.log(JSON.stringify(wd));
return new Promise((resolve, reject) => {
let reqUrl = URI("reserve/withdraw").absoluteTo(mint.baseUrl);
let myRequest = new XMLHttpRequest();
console.log("making request to " + reqUrl.href());
myRequest.open('post', reqUrl.href());
myRequest.setRequestHeader("Content-Type", "application/json;charset=UTF-8");
myRequest.send(JSON.stringify(wd));
myRequest.addEventListener('readystatechange', (e) => {
if (myRequest.readyState == XMLHttpRequest.DONE) {
if (myRequest.status != 200) {
console.log("Withdrawal failed, status ", myRequest.status);
reject();
return;
}
console.log("Withdrawal successful");
console.log(myRequest.responseText);
resolve();
}
else {
console.log("ready state change to", myRequest.status);
}
});
});
}
/**
* Withdraw coins from a reserve until it is empty.
@ -141,6 +188,7 @@ function depleteReserve(db, reserve, mint) {
let denoms = copy(mint.keys.denoms);
let remaining = new Amount(reserve.current_amount);
denoms.sort(rankDenom);
let workList = [];
for (let i = 0; i < 1000; i++) {
let found = false;
for (let d of denoms) {
@ -150,24 +198,33 @@ function depleteReserve(db, reserve, mint) {
continue;
}
found = true;
console.log("Subbing " + JSON.stringify(remaining.toJson()));
console.log("With " + JSON.stringify(cost.toJson()));
remaining.sub(cost);
withdraw(d, reserve, mint);
workList.push([d, reserve, mint]);
}
if (!found) {
break;
}
}
// Do the request one by one.
function work() {
if (workList.length == 0) {
return;
}
console.log("doing work");
let w = workList.pop();
withdraw(w[0], w[1], w[2])
.then(() => work());
}
work();
}
function updateReserve(db, reservePub, mint) {
let reserve;
return new Promise((resolve, reject) => {
let tx = db.transaction(['reserves']);
tx.objectStore('reserves').get(reservePub.stringEncode()).onsuccess = (e) => {
tx.objectStore('reserves').get(reservePub.toCrock()).onsuccess = (e) => {
let reserve = e.target.result;
let reqUrl = URI("reserve/status").absoluteTo(mint.baseUrl);
reqUrl.query({ 'reserve_pub': reservePub.stringEncode() });
reqUrl.query({ 'reserve_pub': reservePub.toCrock() });
let myRequest = new XMLHttpRequest();
console.log("making request to " + reqUrl.href());
myRequest.open('get', reqUrl.href());

View File

@ -57,7 +57,7 @@ function confirmReserve(db, detail, sendResponse) {
let form = new FormData();
let now = (new Date()).toString();
form.append(detail.field_amount, detail.amount_str);
form.append(detail.field_reserve_pub, reservePub.stringEncode());
form.append(detail.field_reserve_pub, reservePub.toCrock());
form.append(detail.field_mint, detail.mint);
// XXX: set bank-specified fields.
let myRequest = new XMLHttpRequest();
@ -75,8 +75,8 @@ function confirmReserve(db, detail, sendResponse) {
backlink: undefined
};
let reserveRecord = {
reserve_pub: reservePub.stringEncode(),
reserve_priv: reservePriv.stringEncode(),
reserve_pub: reservePub.toCrock(),
reserve_priv: reservePriv.toCrock(),
mint_base_url: mintBaseUrl,
created: now,
last_query: null,
@ -126,26 +126,78 @@ function rankDenom(denom1: any, denom2: any) {
}
function withdraw(denom, reserve, mint) {
let wd = {
denom_pub: denom.denom_pub,
reserve_pub: reserve.reserve_pub,
};
let reservePriv = new EddsaPrivateKey();
reservePriv.stringDecode(reserve.reserve_priv);
let reservePub = new EddsaPublicKey();
reservePub.stringDecode(reserve.reserve_pub);
let denomPub = RsaPublicKey.stringDecode(denom.denom_pub);
let coinPriv = EddsaPrivateKey.create();
let coinPub = coinPriv.getPublicKey();
let blindingFactor = RsaBlindingKey.create(1024);
let pubHash = coinPub.hash();
let ev = rsaBlind(pubHash, blindingFactor, denomPub);
// Signature
let withdrawRequest = new WithdrawRequestPS();
withdrawRequest.set("reserve_pub", reservePub);
// ...
var sig = eddsaSign(withdrawRequest.toPurpose(), reservePriv);
function withdraw(denom, reserve, mint): Promise<void> {
console.log("in withdraw");
let wd: any = {};
wd.denom_pub = denom.denom_pub;
wd.reserve_pub = reserve.reserve_pub;
let a = new Arena();
try {
let reservePriv = new EddsaPrivateKey();
reservePriv.loadCrock(reserve.reserve_priv);
let reservePub = new EddsaPublicKey();
reservePub.loadCrock(reserve.reserve_pub);
let denomPub = RsaPublicKey.fromCrock(denom.denom_pub);
let coinPriv = EddsaPrivateKey.create();
let coinPub = coinPriv.getPublicKey();
let blindingFactor = RsaBlindingKey.create(1024);
let pubHash: HashCode = coinPub.hash();
console.log("about to blind");
let ev: ByteArray = rsaBlind(pubHash, blindingFactor, denomPub);
console.log("blinded");
if (!denom.fee_withdraw) {
throw Error("Field fee_withdraw missing");
}
let amountWithFee = new Amount(denom.value);
amountWithFee.add(new Amount(denom.fee_withdraw));
let withdrawFee = new Amount(denom.fee_withdraw);
// Signature
let withdrawRequest = new WithdrawRequestPS();
withdrawRequest.set("reserve_pub", reservePub);
withdrawRequest.set("amount_with_fee", amountWithFee.toNbo());
withdrawRequest.set("withdraw_fee", withdrawFee.toNbo());
withdrawRequest.set("h_denomination_pub", denomPub.encode().hash());
withdrawRequest.set("h_coin_envelope", ev.hash());
console.log("about to sign");
var sig = eddsaSign(withdrawRequest.toPurpose(), reservePriv);
console.log("signed");
wd.reserve_sig = sig.toCrock();
wd.coin_ev = ev.toCrock();
} finally {
a.destroy();
}
console.log("crypto done, doing request");
console.log("request:");
console.log(JSON.stringify(wd));
return new Promise<void>((resolve, reject) => {
let reqUrl = URI("reserve/withdraw").absoluteTo(mint.baseUrl);
let myRequest = new XMLHttpRequest();
console.log("making request to " + reqUrl.href());
myRequest.open('post', reqUrl.href());
myRequest.setRequestHeader("Content-Type", "application/json;charset=UTF-8");
myRequest.send(JSON.stringify(wd));
myRequest.addEventListener('readystatechange', (e) => {
if (myRequest.readyState == XMLHttpRequest.DONE) {
if (myRequest.status != 200) {
console.log("Withdrawal failed, status ", myRequest.status);
reject();
return;
}
console.log("Withdrawal successful");
console.log(myRequest.responseText);
resolve();
} else {
console.log("ready state change to", myRequest.status);
}
});
});
}
@ -156,6 +208,7 @@ function depleteReserve(db, reserve, mint) {
let denoms = copy(mint.keys.denoms);
let remaining = new Amount(reserve.current_amount);
denoms.sort(rankDenom);
let workList = []
for (let i = 0; i < 1000; i++) {
let found = false;
for (let d of denoms) {
@ -165,16 +218,26 @@ function depleteReserve(db, reserve, mint) {
continue;
}
found = true;
console.log("Subbing " + JSON.stringify(remaining.toJson()));
console.log("With " + JSON.stringify(cost.toJson()));
remaining.sub(cost);
withdraw(d, reserve, mint);
workList.push([d, reserve, mint]);
}
if (!found) {
break;
}
}
// Do the request one by one.
function work(): void {
if (workList.length == 0) {
return;
}
console.log("doing work");
let w = workList.pop();
withdraw(w[0], w[1], w[2])
.then(() => work());
}
work();
}
@ -182,10 +245,10 @@ function updateReserve(db, reservePub: EddsaPublicKey, mint) {
let reserve;
return new Promise((resolve, reject) => {
let tx = db.transaction(['reserves']);
tx.objectStore('reserves').get(reservePub.stringEncode()).onsuccess = (e) => {
tx.objectStore('reserves').get(reservePub.toCrock()).onsuccess = (e) => {
let reserve = e.target.result;
let reqUrl = URI("reserve/status").absoluteTo(mint.baseUrl);
reqUrl.query({'reserve_pub': reservePub.stringEncode()});
reqUrl.query({'reserve_pub': reservePub.toCrock()});
let myRequest = new XMLHttpRequest();
console.log("making request to " + reqUrl.href());
myRequest.open('get', reqUrl.href());