2016-02-19 00:49:22 +01:00
|
|
|
/*
|
|
|
|
This file is part of TALER
|
|
|
|
(C) 2016 GNUnet e.V.
|
|
|
|
|
|
|
|
TALER is free software; you can redistribute it and/or modify it under the
|
|
|
|
terms of the GNU General Public License as published by the Free Software
|
|
|
|
Foundation; either version 3, or (at your option) any later version.
|
|
|
|
|
|
|
|
TALER is distributed in the hope that it will be useful, but WITHOUT ANY
|
|
|
|
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
|
|
|
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
|
|
|
|
|
|
|
You should have received a copy of the GNU General Public License along with
|
2016-07-07 17:59:29 +02:00
|
|
|
TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
|
2016-02-19 00:49:22 +01:00
|
|
|
*/
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Web worker for crypto operations.
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
2017-05-24 16:14:23 +02:00
|
|
|
/**
|
|
|
|
* Imports.
|
|
|
|
*/
|
2017-04-20 03:09:25 +02:00
|
|
|
import {
|
2017-05-01 04:05:16 +02:00
|
|
|
AmountJson,
|
2017-05-27 18:43:11 +02:00
|
|
|
Amounts,
|
|
|
|
CoinPaySig,
|
|
|
|
CoinRecord,
|
2017-05-01 04:05:16 +02:00
|
|
|
CoinStatus,
|
2017-05-27 18:43:11 +02:00
|
|
|
DenominationRecord,
|
|
|
|
PayCoinInfo,
|
2017-05-01 04:05:16 +02:00
|
|
|
PaybackRequest,
|
2017-05-27 18:43:11 +02:00
|
|
|
PreCoinRecord,
|
|
|
|
RefreshPreCoinRecord,
|
|
|
|
RefreshSessionRecord,
|
|
|
|
ReserveRecord,
|
|
|
|
WireFee,
|
|
|
|
} from "../types";
|
|
|
|
import {
|
|
|
|
CoinWithDenom,
|
|
|
|
OfferRecord,
|
|
|
|
} from "../wallet";
|
2017-05-28 01:10:54 +02:00
|
|
|
|
2017-05-27 18:43:11 +02:00
|
|
|
import {
|
|
|
|
Amount,
|
|
|
|
EddsaPublicKey,
|
|
|
|
HashCode,
|
|
|
|
HashContext,
|
|
|
|
RefreshMeltCoinAffirmationPS,
|
|
|
|
} from "./emscInterface";
|
2017-05-28 01:10:54 +02:00
|
|
|
import * as native from "./emscInterface";
|
2016-02-19 00:49:22 +01:00
|
|
|
|
|
|
|
|
2017-04-20 03:09:25 +02:00
|
|
|
namespace RpcFunctions {
|
2016-02-19 00:49:22 +01:00
|
|
|
|
2017-04-20 03:09:25 +02:00
|
|
|
/**
|
|
|
|
* Create a pre-coin of the given denomination to be withdrawn from then given
|
|
|
|
* reserve.
|
|
|
|
*/
|
|
|
|
export function createPreCoin(denom: DenominationRecord,
|
|
|
|
reserve: ReserveRecord): PreCoinRecord {
|
2017-05-28 01:10:54 +02:00
|
|
|
const reservePriv = new native.EddsaPrivateKey();
|
2017-04-20 03:09:25 +02:00
|
|
|
reservePriv.loadCrock(reserve.reserve_priv);
|
2017-05-28 01:10:54 +02:00
|
|
|
const reservePub = new native.EddsaPublicKey();
|
2017-04-20 03:09:25 +02:00
|
|
|
reservePub.loadCrock(reserve.reserve_pub);
|
2017-05-28 01:10:54 +02:00
|
|
|
const denomPub = native.RsaPublicKey.fromCrock(denom.denomPub);
|
|
|
|
const coinPriv = native.EddsaPrivateKey.create();
|
|
|
|
const coinPub = coinPriv.getPublicKey();
|
|
|
|
const blindingFactor = native.RsaBlindingKeySecret.create();
|
|
|
|
const pubHash: native.HashCode = coinPub.hash();
|
|
|
|
const ev = native.rsaBlind(pubHash, blindingFactor, denomPub);
|
2016-02-19 00:49:22 +01:00
|
|
|
|
2017-04-20 03:09:25 +02:00
|
|
|
if (!ev) {
|
|
|
|
throw Error("couldn't blind (malicious exchange key?)");
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!denom.feeWithdraw) {
|
|
|
|
throw Error("Field fee_withdraw missing");
|
|
|
|
}
|
|
|
|
|
2017-05-28 01:10:54 +02:00
|
|
|
const amountWithFee = new native.Amount(denom.value);
|
2017-04-20 03:09:25 +02:00
|
|
|
amountWithFee.add(new native.Amount(denom.feeWithdraw));
|
2017-05-28 01:10:54 +02:00
|
|
|
const withdrawFee = new native.Amount(denom.feeWithdraw);
|
2017-04-20 03:09:25 +02:00
|
|
|
|
|
|
|
// Signature
|
2017-05-28 01:10:54 +02:00
|
|
|
const withdrawRequest = new native.WithdrawRequestPS({
|
2017-04-20 03:09:25 +02:00
|
|
|
amount_with_fee: amountWithFee.toNbo(),
|
2017-05-28 01:10:54 +02:00
|
|
|
h_coin_envelope: ev.hash(),
|
2017-04-20 03:09:25 +02:00
|
|
|
h_denomination_pub: denomPub.encode().hash(),
|
2017-05-28 01:10:54 +02:00
|
|
|
reserve_pub: reservePub,
|
|
|
|
withdraw_fee: withdrawFee.toNbo(),
|
2017-04-20 03:09:25 +02:00
|
|
|
});
|
|
|
|
|
2017-05-28 01:10:54 +02:00
|
|
|
const sig = native.eddsaSign(withdrawRequest.toPurpose(), reservePriv);
|
2017-04-20 03:09:25 +02:00
|
|
|
|
2017-05-28 01:10:54 +02:00
|
|
|
const preCoin: PreCoinRecord = {
|
2017-04-20 03:09:25 +02:00
|
|
|
blindingKey: blindingFactor.toCrock(),
|
2017-05-28 01:10:54 +02:00
|
|
|
coinEv: ev.toCrock(),
|
2017-04-20 03:09:25 +02:00
|
|
|
coinPriv: coinPriv.toCrock(),
|
2017-05-28 01:10:54 +02:00
|
|
|
coinPub: coinPub.toCrock(),
|
|
|
|
coinValue: denom.value,
|
2017-04-20 03:09:25 +02:00
|
|
|
denomPub: denomPub.encode().toCrock(),
|
|
|
|
exchangeBaseUrl: reserve.exchange_base_url,
|
2017-05-28 01:10:54 +02:00
|
|
|
reservePub: reservePub.toCrock(),
|
2017-04-20 03:09:25 +02:00
|
|
|
withdrawSig: sig.toCrock(),
|
|
|
|
};
|
|
|
|
return preCoin;
|
|
|
|
}
|
|
|
|
|
2017-05-01 04:33:47 +02:00
|
|
|
export function createPaybackRequest(coin: CoinRecord): PaybackRequest {
|
2017-05-28 01:10:54 +02:00
|
|
|
const p = new native.PaybackRequestPS({
|
|
|
|
coin_blind: native.RsaBlindingKeySecret.fromCrock(coin.blindingKey),
|
2017-05-01 04:05:16 +02:00
|
|
|
coin_pub: native.EddsaPublicKey.fromCrock(coin.coinPub),
|
|
|
|
h_denom_pub: native.RsaPublicKey.fromCrock(coin.denomPub).encode().hash(),
|
|
|
|
});
|
2017-05-28 01:10:54 +02:00
|
|
|
const coinPriv = native.EddsaPrivateKey.fromCrock(coin.coinPriv);
|
|
|
|
const coinSig = native.eddsaSign(p.toPurpose(), coinPriv);
|
|
|
|
const paybackRequest: PaybackRequest = {
|
2017-05-01 04:33:47 +02:00
|
|
|
coin_blind_key_secret: coin.blindingKey,
|
2017-05-01 04:05:16 +02:00
|
|
|
coin_pub: coin.coinPub,
|
|
|
|
coin_sig: coinSig.toCrock(),
|
2017-05-28 01:10:54 +02:00
|
|
|
denom_pub: coin.denomPub,
|
|
|
|
denom_sig: coin.denomSig,
|
2017-05-01 04:05:16 +02:00
|
|
|
};
|
|
|
|
return paybackRequest;
|
|
|
|
}
|
2017-04-20 03:09:25 +02:00
|
|
|
|
2017-05-01 04:05:16 +02:00
|
|
|
|
|
|
|
export function isValidPaymentSignature(sig: string, contractHash: string, merchantPub: string): boolean {
|
2017-05-28 01:10:54 +02:00
|
|
|
const p = new native.PaymentSignaturePS({
|
2017-04-26 03:10:52 +02:00
|
|
|
contract_hash: native.HashCode.fromCrock(contractHash),
|
|
|
|
});
|
2017-05-28 01:10:54 +02:00
|
|
|
const nativeSig = new native.EddsaSignature();
|
2017-04-26 03:10:52 +02:00
|
|
|
nativeSig.loadCrock(sig);
|
2017-05-28 01:10:54 +02:00
|
|
|
const nativePub = native.EddsaPublicKey.fromCrock(merchantPub);
|
2017-04-26 03:10:52 +02:00
|
|
|
return native.eddsaVerify(native.SignaturePurpose.MERCHANT_PAYMENT_OK,
|
|
|
|
p.toPurpose(),
|
|
|
|
nativeSig,
|
|
|
|
nativePub);
|
|
|
|
}
|
|
|
|
|
2017-04-27 03:09:29 +02:00
|
|
|
export function isValidWireFee(type: string, wf: WireFee, masterPub: string): boolean {
|
2017-05-28 01:10:54 +02:00
|
|
|
const p = new native.MasterWireFeePS({
|
|
|
|
closing_fee: (new native.Amount(wf.closingFee)).toNbo(),
|
|
|
|
end_date: native.AbsoluteTimeNbo.fromStampSeconds(wf.endStamp),
|
2017-04-27 03:09:29 +02:00
|
|
|
h_wire_method: native.ByteArray.fromStringWithNull(type).hash(),
|
2017-04-27 04:06:48 +02:00
|
|
|
start_date: native.AbsoluteTimeNbo.fromStampSeconds(wf.startStamp),
|
2017-04-27 03:09:29 +02:00
|
|
|
wire_fee: (new native.Amount(wf.wireFee)).toNbo(),
|
|
|
|
});
|
|
|
|
|
2017-05-28 01:10:54 +02:00
|
|
|
const nativeSig = new native.EddsaSignature();
|
2017-04-27 03:09:29 +02:00
|
|
|
nativeSig.loadCrock(wf.sig);
|
2017-05-28 01:10:54 +02:00
|
|
|
const nativePub = native.EddsaPublicKey.fromCrock(masterPub);
|
2017-04-27 03:09:29 +02:00
|
|
|
|
|
|
|
return native.eddsaVerify(native.SignaturePurpose.MASTER_WIRE_FEES,
|
|
|
|
p.toPurpose(),
|
|
|
|
nativeSig,
|
|
|
|
nativePub);
|
|
|
|
}
|
|
|
|
|
2017-04-26 03:10:52 +02:00
|
|
|
|
2017-04-20 03:09:25 +02:00
|
|
|
export function isValidDenom(denom: DenominationRecord,
|
|
|
|
masterPub: string): boolean {
|
2017-05-28 01:10:54 +02:00
|
|
|
const p = new native.DenominationKeyValidityPS({
|
|
|
|
denom_hash: native.RsaPublicKey.fromCrock(denom.denomPub) .encode() .hash(),
|
2017-04-20 03:09:25 +02:00
|
|
|
expire_legal: native.AbsoluteTimeNbo.fromTalerString(denom.stampExpireLegal),
|
|
|
|
expire_spend: native.AbsoluteTimeNbo.fromTalerString(denom.stampExpireDeposit),
|
|
|
|
expire_withdraw: native.AbsoluteTimeNbo.fromTalerString(denom.stampExpireWithdraw),
|
|
|
|
fee_deposit: (new native.Amount(denom.feeDeposit)).toNbo(),
|
|
|
|
fee_refresh: (new native.Amount(denom.feeRefresh)).toNbo(),
|
|
|
|
fee_refund: (new native.Amount(denom.feeRefund)).toNbo(),
|
2017-05-28 01:10:54 +02:00
|
|
|
fee_withdraw: (new native.Amount(denom.feeWithdraw)).toNbo(),
|
|
|
|
master: native.EddsaPublicKey.fromCrock(masterPub),
|
|
|
|
start: native.AbsoluteTimeNbo.fromTalerString(denom.stampStart),
|
|
|
|
value: (new native.Amount(denom.value)).toNbo(),
|
2017-04-20 03:09:25 +02:00
|
|
|
});
|
|
|
|
|
2017-05-28 01:10:54 +02:00
|
|
|
const nativeSig = new native.EddsaSignature();
|
2017-04-20 03:09:25 +02:00
|
|
|
nativeSig.loadCrock(denom.masterSig);
|
|
|
|
|
2017-05-28 01:10:54 +02:00
|
|
|
const nativePub = native.EddsaPublicKey.fromCrock(masterPub);
|
2017-04-20 03:09:25 +02:00
|
|
|
|
|
|
|
return native.eddsaVerify(native.SignaturePurpose.MASTER_DENOMINATION_KEY_VALIDITY,
|
|
|
|
p.toPurpose(),
|
|
|
|
nativeSig,
|
|
|
|
nativePub);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
export function createEddsaKeypair(): {priv: string, pub: string} {
|
|
|
|
const priv = native.EddsaPrivateKey.create();
|
|
|
|
const pub = priv.getPublicKey();
|
|
|
|
return {priv: priv.toCrock(), pub: pub.toCrock()};
|
|
|
|
}
|
2016-02-19 00:49:22 +01:00
|
|
|
|
2017-04-20 03:09:25 +02:00
|
|
|
|
|
|
|
export function rsaUnblind(sig: string, bk: string, pk: string): string {
|
2017-05-28 01:10:54 +02:00
|
|
|
const denomSig = native.rsaUnblind(native.RsaSignature.fromCrock(sig),
|
2017-04-20 03:09:25 +02:00
|
|
|
native.RsaBlindingKeySecret.fromCrock(bk),
|
|
|
|
native.RsaPublicKey.fromCrock(pk));
|
2017-05-28 01:10:54 +02:00
|
|
|
return denomSig.encode().toCrock();
|
2017-04-20 03:09:25 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Generate updated coins (to store in the database)
|
|
|
|
* and deposit permissions for each given coin.
|
|
|
|
*/
|
|
|
|
export function signDeposit(offer: OfferRecord,
|
|
|
|
cds: CoinWithDenom[]): PayCoinInfo {
|
2017-05-28 01:10:54 +02:00
|
|
|
const ret: PayCoinInfo = [];
|
2017-04-20 03:09:25 +02:00
|
|
|
|
|
|
|
|
2017-05-28 01:10:54 +02:00
|
|
|
const feeList: AmountJson[] = cds.map((x) => x.denom.feeDeposit);
|
2017-04-20 03:09:25 +02:00
|
|
|
let fees = Amounts.add(Amounts.getZero(feeList[0].currency), ...feeList).amount;
|
|
|
|
// okay if saturates
|
|
|
|
fees = Amounts.sub(fees, offer.contract.max_fee).amount;
|
2017-05-28 01:10:54 +02:00
|
|
|
const total = Amounts.add(fees, offer.contract.amount).amount;
|
2017-04-20 03:09:25 +02:00
|
|
|
|
2017-05-28 01:10:54 +02:00
|
|
|
const amountSpent = native.Amount.getZero(cds[0].coin.currentAmount.currency);
|
|
|
|
const amountRemaining = new native.Amount(total);
|
|
|
|
for (const cd of cds) {
|
2017-04-20 03:09:25 +02:00
|
|
|
let coinSpend: Amount;
|
|
|
|
|
2017-05-28 01:10:54 +02:00
|
|
|
if (amountRemaining.value === 0 && amountRemaining.fraction === 0) {
|
2017-04-20 03:09:25 +02:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (amountRemaining.cmp(new native.Amount(cd.coin.currentAmount)) < 0) {
|
|
|
|
coinSpend = new native.Amount(amountRemaining.toJson());
|
|
|
|
} else {
|
|
|
|
coinSpend = new native.Amount(cd.coin.currentAmount);
|
|
|
|
}
|
|
|
|
|
|
|
|
amountSpent.add(coinSpend);
|
|
|
|
amountRemaining.sub(coinSpend);
|
|
|
|
|
2017-05-28 01:10:54 +02:00
|
|
|
const feeDeposit: Amount = new native.Amount(cd.denom.feeDeposit);
|
2017-04-20 03:09:25 +02:00
|
|
|
|
|
|
|
// Give the merchant at least the deposit fee, otherwise it'll reject
|
|
|
|
// the coin.
|
|
|
|
if (coinSpend.cmp(feeDeposit) < 0) {
|
|
|
|
coinSpend = feeDeposit;
|
|
|
|
}
|
|
|
|
|
2017-05-28 01:10:54 +02:00
|
|
|
const newAmount = new native.Amount(cd.coin.currentAmount);
|
2017-04-20 03:09:25 +02:00
|
|
|
newAmount.sub(coinSpend);
|
|
|
|
cd.coin.currentAmount = newAmount.toJson();
|
|
|
|
cd.coin.status = CoinStatus.TransactionPending;
|
|
|
|
|
2017-05-28 01:10:54 +02:00
|
|
|
const d = new native.DepositRequestPS({
|
2017-04-20 03:09:25 +02:00
|
|
|
amount_with_fee: coinSpend.toNbo(),
|
|
|
|
coin_pub: native.EddsaPublicKey.fromCrock(cd.coin.coinPub),
|
|
|
|
deposit_fee: new native.Amount(cd.denom.feeDeposit).toNbo(),
|
2017-05-28 01:10:54 +02:00
|
|
|
h_contract: native.HashCode.fromCrock(offer.H_contract),
|
|
|
|
h_wire: native.HashCode.fromCrock(offer.contract.H_wire),
|
2017-04-20 03:09:25 +02:00
|
|
|
merchant: native.EddsaPublicKey.fromCrock(offer.contract.merchant_pub),
|
|
|
|
refund_deadline: native.AbsoluteTimeNbo.fromTalerString(offer.contract.refund_deadline),
|
|
|
|
timestamp: native.AbsoluteTimeNbo.fromTalerString(offer.contract.timestamp),
|
2016-11-03 00:47:22 +01:00
|
|
|
});
|
2017-04-20 03:09:25 +02:00
|
|
|
|
2017-05-28 01:10:54 +02:00
|
|
|
const coinSig = native.eddsaSign(d.toPurpose(),
|
2017-04-20 03:09:25 +02:00
|
|
|
native.EddsaPrivateKey.fromCrock(cd.coin.coinPriv))
|
|
|
|
.toCrock();
|
|
|
|
|
2017-05-28 01:10:54 +02:00
|
|
|
const s: CoinPaySig = {
|
2017-04-20 03:09:25 +02:00
|
|
|
coin_pub: cd.coin.coinPub,
|
2017-05-28 01:10:54 +02:00
|
|
|
coin_sig: coinSig,
|
2017-04-20 03:09:25 +02:00
|
|
|
denom_pub: cd.coin.denomPub,
|
|
|
|
f: coinSpend.toJson(),
|
2017-05-28 01:10:54 +02:00
|
|
|
ub_sig: cd.coin.denomSig,
|
2017-04-20 03:09:25 +02:00
|
|
|
};
|
|
|
|
ret.push({sig: s, updatedCoin: cd.coin});
|
|
|
|
}
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
export function createRefreshSession(exchangeBaseUrl: string,
|
|
|
|
kappa: number,
|
|
|
|
meltCoin: CoinRecord,
|
|
|
|
newCoinDenoms: DenominationRecord[],
|
|
|
|
meltFee: AmountJson): RefreshSessionRecord {
|
|
|
|
|
|
|
|
let valueWithFee = Amounts.getZero(newCoinDenoms[0].value.currency);
|
|
|
|
|
2017-05-28 01:10:54 +02:00
|
|
|
for (const ncd of newCoinDenoms) {
|
2017-04-20 03:09:25 +02:00
|
|
|
valueWithFee = Amounts.add(valueWithFee,
|
|
|
|
ncd.value,
|
|
|
|
ncd.feeWithdraw).amount;
|
|
|
|
}
|
|
|
|
|
|
|
|
// melt fee
|
|
|
|
valueWithFee = Amounts.add(valueWithFee, meltFee).amount;
|
|
|
|
|
2017-05-28 01:10:54 +02:00
|
|
|
const sessionHc = new HashContext();
|
2017-04-20 03:09:25 +02:00
|
|
|
|
2017-05-28 01:10:54 +02:00
|
|
|
const transferPubs: string[] = [];
|
|
|
|
const transferPrivs: string[] = [];
|
2017-04-20 03:09:25 +02:00
|
|
|
|
2017-05-28 01:10:54 +02:00
|
|
|
const preCoinsForGammas: RefreshPreCoinRecord[][] = [];
|
2017-04-20 03:09:25 +02:00
|
|
|
|
|
|
|
for (let i = 0; i < kappa; i++) {
|
2017-05-28 01:10:54 +02:00
|
|
|
const t = native.EcdhePrivateKey.create();
|
|
|
|
const pub = t.getPublicKey();
|
2017-04-20 03:09:25 +02:00
|
|
|
sessionHc.read(pub);
|
|
|
|
transferPrivs.push(t.toCrock());
|
|
|
|
transferPubs.push(pub.toCrock());
|
|
|
|
}
|
|
|
|
|
2017-05-28 01:10:54 +02:00
|
|
|
for (const denom of newCoinDenoms) {
|
|
|
|
const r = native.RsaPublicKey.fromCrock(denom.denomPub);
|
2017-04-20 03:09:25 +02:00
|
|
|
sessionHc.read(r.encode());
|
|
|
|
}
|
|
|
|
|
|
|
|
sessionHc.read(native.EddsaPublicKey.fromCrock(meltCoin.coinPub));
|
|
|
|
sessionHc.read((new native.Amount(valueWithFee)).toNbo());
|
|
|
|
|
|
|
|
for (let i = 0; i < kappa; i++) {
|
2017-05-28 01:10:54 +02:00
|
|
|
const preCoins: RefreshPreCoinRecord[] = [];
|
2017-04-20 03:09:25 +02:00
|
|
|
for (let j = 0; j < newCoinDenoms.length; j++) {
|
|
|
|
|
2017-05-28 01:10:54 +02:00
|
|
|
const transferPriv = native.EcdhePrivateKey.fromCrock(transferPrivs[i]);
|
|
|
|
const oldCoinPub = native.EddsaPublicKey.fromCrock(meltCoin.coinPub);
|
|
|
|
const transferSecret = native.ecdhEddsa(transferPriv, oldCoinPub);
|
2017-04-20 03:09:25 +02:00
|
|
|
|
2017-05-28 01:10:54 +02:00
|
|
|
const fresh = native.setupFreshCoin(transferSecret, j);
|
2017-04-20 03:09:25 +02:00
|
|
|
|
2017-05-28 01:10:54 +02:00
|
|
|
const coinPriv = fresh.priv;
|
|
|
|
const coinPub = coinPriv.getPublicKey();
|
|
|
|
const blindingFactor = fresh.blindingKey;
|
|
|
|
const pubHash: native.HashCode = coinPub.hash();
|
|
|
|
const denomPub = native.RsaPublicKey.fromCrock(newCoinDenoms[j].denomPub);
|
|
|
|
const ev = native.rsaBlind(pubHash,
|
2017-04-20 03:09:25 +02:00
|
|
|
blindingFactor,
|
|
|
|
denomPub);
|
|
|
|
if (!ev) {
|
|
|
|
throw Error("couldn't blind (malicious exchange key?)");
|
|
|
|
}
|
2017-05-28 01:10:54 +02:00
|
|
|
const preCoin: RefreshPreCoinRecord = {
|
2017-04-20 03:09:25 +02:00
|
|
|
blindingKey: blindingFactor.toCrock(),
|
|
|
|
coinEv: ev.toCrock(),
|
|
|
|
privateKey: coinPriv.toCrock(),
|
2017-05-28 01:10:54 +02:00
|
|
|
publicKey: coinPub.toCrock(),
|
2017-04-20 03:09:25 +02:00
|
|
|
};
|
|
|
|
preCoins.push(preCoin);
|
|
|
|
sessionHc.read(ev);
|
|
|
|
}
|
|
|
|
preCoinsForGammas.push(preCoins);
|
|
|
|
}
|
|
|
|
|
2017-05-28 01:10:54 +02:00
|
|
|
const sessionHash = new HashCode();
|
2017-04-20 03:09:25 +02:00
|
|
|
sessionHash.alloc();
|
|
|
|
sessionHc.finish(sessionHash);
|
|
|
|
|
2017-05-28 01:10:54 +02:00
|
|
|
const confirmData = new RefreshMeltCoinAffirmationPS({
|
2017-04-20 03:09:25 +02:00
|
|
|
amount_with_fee: (new Amount(valueWithFee)).toNbo(),
|
2017-05-28 01:10:54 +02:00
|
|
|
coin_pub: EddsaPublicKey.fromCrock(meltCoin.coinPub),
|
|
|
|
melt_fee: (new Amount(meltFee)).toNbo(),
|
2017-04-20 03:09:25 +02:00
|
|
|
session_hash: sessionHash,
|
|
|
|
});
|
|
|
|
|
|
|
|
|
2017-05-28 01:10:54 +02:00
|
|
|
const confirmSig: string = native.eddsaSign(confirmData.toPurpose(),
|
2017-04-20 03:09:25 +02:00
|
|
|
native.EddsaPrivateKey.fromCrock(
|
|
|
|
meltCoin.coinPriv)).toCrock();
|
|
|
|
|
|
|
|
let valueOutput = Amounts.getZero(newCoinDenoms[0].value.currency);
|
2017-05-28 01:10:54 +02:00
|
|
|
for (const denom of newCoinDenoms) {
|
2017-04-20 03:09:25 +02:00
|
|
|
valueOutput = Amounts.add(valueOutput, denom.value).amount;
|
|
|
|
}
|
|
|
|
|
2017-05-28 01:10:54 +02:00
|
|
|
const refreshSession: RefreshSessionRecord = {
|
2017-04-20 03:09:25 +02:00
|
|
|
confirmSig,
|
2017-05-28 01:10:54 +02:00
|
|
|
exchangeBaseUrl,
|
|
|
|
finished: false,
|
2017-04-20 03:09:25 +02:00
|
|
|
hash: sessionHash.toCrock(),
|
2017-05-28 01:10:54 +02:00
|
|
|
meltCoinPub: meltCoin.coinPub,
|
|
|
|
newDenoms: newCoinDenoms.map((d) => d.denomPub),
|
2017-04-20 03:09:25 +02:00
|
|
|
norevealIndex: undefined,
|
2017-05-28 01:10:54 +02:00
|
|
|
preCoinsForGammas,
|
2017-04-20 03:09:25 +02:00
|
|
|
transferPrivs,
|
2017-05-28 01:10:54 +02:00
|
|
|
transferPubs,
|
2017-04-20 03:09:25 +02:00
|
|
|
valueOutput,
|
2017-05-28 01:10:54 +02:00
|
|
|
valueWithFee,
|
2017-04-20 03:09:25 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
return refreshSession;
|
|
|
|
}
|
|
|
|
|
2017-05-24 16:14:23 +02:00
|
|
|
/**
|
|
|
|
* Hash a string including the zero terminator.
|
|
|
|
*/
|
2017-04-20 03:09:25 +02:00
|
|
|
export function hashString(str: string): string {
|
|
|
|
const b = native.ByteArray.fromStringWithNull(str);
|
|
|
|
return b.hash().toCrock();
|
|
|
|
}
|
2017-05-01 04:05:16 +02:00
|
|
|
|
|
|
|
export function hashDenomPub(denomPub: string): string {
|
|
|
|
return native.RsaPublicKey.fromCrock(denomPub).encode().hash().toCrock();
|
|
|
|
}
|
2017-04-20 03:09:25 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2017-05-28 01:10:54 +02:00
|
|
|
const worker: Worker = (self as any) as Worker;
|
2017-04-20 03:09:25 +02:00
|
|
|
|
|
|
|
worker.onmessage = (msg: MessageEvent) => {
|
|
|
|
if (!Array.isArray(msg.data.args)) {
|
|
|
|
console.error("args must be array");
|
|
|
|
return;
|
|
|
|
}
|
2017-05-28 01:10:54 +02:00
|
|
|
if (typeof msg.data.id !== "number") {
|
2017-04-20 03:09:25 +02:00
|
|
|
console.error("RPC id must be number");
|
|
|
|
}
|
2017-05-28 01:10:54 +02:00
|
|
|
if (typeof msg.data.operation !== "string") {
|
2017-04-20 03:09:25 +02:00
|
|
|
console.error("RPC operation must be string");
|
|
|
|
}
|
2017-05-28 01:10:54 +02:00
|
|
|
const f = (RpcFunctions as any)[msg.data.operation];
|
2017-04-20 03:09:25 +02:00
|
|
|
if (!f) {
|
|
|
|
console.error(`unknown operation: '${msg.data.operation}'`);
|
|
|
|
return;
|
|
|
|
}
|
2017-05-28 01:10:54 +02:00
|
|
|
const res = f(...msg.data.args);
|
2017-04-20 03:09:25 +02:00
|
|
|
worker.postMessage({result: res, id: msg.data.id});
|
2017-05-28 01:10:54 +02:00
|
|
|
};
|