add link signature to /refresh/reveal

This commit is contained in:
Florian Dold 2019-06-26 15:30:32 +02:00
parent 420a5ba23a
commit cfa1df7343
No known key found for this signature in database
GPG Key ID: D2E4F00F29D02A4B
4 changed files with 1217 additions and 695 deletions

View File

@ -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/>
*/ */
/** /**
* API to access the Taler crypto worker thread. * API to access the Taler crypto worker thread.
* @author Florian Dold * @author Florian Dold
@ -35,22 +34,14 @@ import {
WireFee, WireFee,
} from "../dbTypes"; } from "../dbTypes";
import { import { ContractTerms, PaybackRequest } from "../talerTypes";
ContractTerms,
PaybackRequest,
} from "../talerTypes";
import { import { BenchmarkResult, CoinWithDenom, PayCoinInfo } from "../walletTypes";
BenchmarkResult,
CoinWithDenom,
PayCoinInfo,
} from "../walletTypes";
import * as timer from "../timer"; import * as timer from "../timer";
import { startWorker } from "./startWorker"; import { startWorker } from "./startWorker";
/** /**
* State of a crypto worker. * State of a crypto worker.
*/ */
@ -58,17 +49,17 @@ interface WorkerState {
/** /**
* The actual worker thread. * The actual worker thread.
*/ */
w: Worker|null; w: Worker | null;
/** /**
* Work we're currently executing or null if not busy. * Work we're currently executing or null if not busy.
*/ */
currentWorkItem: WorkItem|null; currentWorkItem: WorkItem | null;
/** /**
* Timer to terminate the worker if it's not busy enough. * Timer to terminate the worker if it's not busy enough.
*/ */
terminationTimerHandle: timer.TimerHandle|null; terminationTimerHandle: timer.TimerHandle | null;
} }
interface WorkItem { interface WorkItem {
@ -88,7 +79,6 @@ interface WorkItem {
startTime: number; startTime: number;
} }
/** /**
* Number of different priorities. Each priority p * Number of different priorities. Each priority p
* must be 0 <= p < NUM_PRIO. * must be 0 <= p < NUM_PRIO.
@ -151,8 +141,10 @@ export class CryptoApi {
handleWorkerError(ws: WorkerState, e: ErrorEvent) { handleWorkerError(ws: WorkerState, e: ErrorEvent) {
if (ws.currentWorkItem) { if (ws.currentWorkItem) {
console.error(`error in worker during ${ws.currentWorkItem!.operation}`, console.error(
e); `error in worker during ${ws.currentWorkItem!.operation}`,
e,
);
} else { } else {
console.error("error in worker", e); console.error("error in worker", e);
} }
@ -201,7 +193,10 @@ export class CryptoApi {
console.error(`RPC with id ${id} has no registry entry`); console.error(`RPC with id ${id} has no registry entry`);
return; return;
} }
console.log(`rpc ${currentWorkItem.operation} took ${timer.performanceNow() - currentWorkItem.startTime}ms`); console.log(
`rpc ${currentWorkItem.operation} took ${timer.performanceNow() -
currentWorkItem.startTime}ms`,
);
currentWorkItem.resolve(msg.data.result); currentWorkItem.resolve(msg.data.result);
} }
@ -230,12 +225,21 @@ export class CryptoApi {
} }
} }
private doRpc<T>(operation: string, priority: number, private doRpc<T>(
...args: any[]): Promise<T> { operation: string,
priority: number,
...args: any[]
): Promise<T> {
const p: Promise<T> = new Promise<T>((resolve, reject) => { const p: Promise<T> = new Promise<T>((resolve, reject) => {
const rpcId = this.nextRpcId++; const rpcId = this.nextRpcId++;
const workItem: WorkItem = {operation, args, resolve, reject, rpcId, startTime: 0}; const workItem: WorkItem = {
operation,
args,
resolve,
reject,
rpcId,
startTime: 0,
};
if (this.numBusy === this.workers.length) { if (this.numBusy === this.workers.length) {
const q = this.workQueues[priority]; const q = this.workQueues[priority];
@ -263,8 +267,10 @@ export class CryptoApi {
}); });
} }
createPreCoin(
createPreCoin(denom: DenominationRecord, reserve: ReserveRecord): Promise<PreCoinRecord> { denom: DenominationRecord,
reserve: ReserveRecord,
): Promise<PreCoinRecord> {
return this.doRpc<PreCoinRecord>("createPreCoin", 1, denom, reserve); return this.doRpc<PreCoinRecord>("createPreCoin", 1, denom, reserve);
} }
@ -280,27 +286,48 @@ export class CryptoApi {
return this.doRpc<string>("hashDenomPub", 1, denomPub); return this.doRpc<string>("hashDenomPub", 1, denomPub);
} }
isValidDenom(denom: DenominationRecord, isValidDenom(denom: DenominationRecord, masterPub: string): Promise<boolean> {
masterPub: string): Promise<boolean> {
return this.doRpc<boolean>("isValidDenom", 2, denom, masterPub); return this.doRpc<boolean>("isValidDenom", 2, denom, masterPub);
} }
isValidWireFee(type: string, wf: WireFee, masterPub: string): Promise<boolean> { isValidWireFee(
type: string,
wf: WireFee,
masterPub: string,
): Promise<boolean> {
return this.doRpc<boolean>("isValidWireFee", 2, type, wf, masterPub); return this.doRpc<boolean>("isValidWireFee", 2, type, wf, masterPub);
} }
isValidPaymentSignature(sig: string, contractHash: string, merchantPub: string): Promise<boolean> { isValidPaymentSignature(
return this.doRpc<boolean>("isValidPaymentSignature", 1, sig, contractHash, merchantPub); sig: string,
contractHash: string,
merchantPub: string,
): Promise<boolean> {
return this.doRpc<boolean>(
"isValidPaymentSignature",
1,
sig,
contractHash,
merchantPub,
);
} }
signDeposit(contractTerms: ContractTerms, signDeposit(
cds: CoinWithDenom[], contractTerms: ContractTerms,
totalAmount: AmountJson): Promise<PayCoinInfo> { cds: CoinWithDenom[],
return this.doRpc<PayCoinInfo>("signDeposit", 3, contractTerms, cds, totalAmount); totalAmount: AmountJson,
): Promise<PayCoinInfo> {
return this.doRpc<PayCoinInfo>(
"signDeposit",
3,
contractTerms,
cds,
totalAmount,
);
} }
createEddsaKeypair(): Promise<{priv: string, pub: string}> { createEddsaKeypair(): Promise<{ priv: string; pub: string }> {
return this.doRpc<{priv: string, pub: string}>("createEddsaKeypair", 1); return this.doRpc<{ priv: string; pub: string }>("createEddsaKeypair", 1);
} }
rsaUnblind(sig: string, bk: string, pk: string): Promise<string> { rsaUnblind(sig: string, bk: string, pk: string): Promise<string> {
@ -311,23 +338,43 @@ export class CryptoApi {
return this.doRpc<PaybackRequest>("createPaybackRequest", 1, coin); return this.doRpc<PaybackRequest>("createPaybackRequest", 1, coin);
} }
createRefreshSession(exchangeBaseUrl: string, createRefreshSession(
kappa: number, exchangeBaseUrl: string,
meltCoin: CoinRecord, kappa: number,
newCoinDenoms: DenominationRecord[], meltCoin: CoinRecord,
meltFee: AmountJson): Promise<RefreshSessionRecord> { newCoinDenoms: DenominationRecord[],
return this.doRpc<RefreshSessionRecord>("createRefreshSession", meltFee: AmountJson,
4, ): Promise<RefreshSessionRecord> {
exchangeBaseUrl, return this.doRpc<RefreshSessionRecord>(
kappa, "createRefreshSession",
meltCoin, 4,
newCoinDenoms, exchangeBaseUrl,
meltFee); kappa,
meltCoin,
newCoinDenoms,
meltFee,
);
}
signCoinLink(
oldCoinPriv: string,
newDenomHash: string,
oldCoinPub: string,
transferPub: string,
coinEv: string,
): Promise<string> {
return this.doRpc<string>(
"signCoinLink",
4,
oldCoinPriv,
newDenomHash,
oldCoinPub,
transferPub,
coinEv,
);
} }
benchmark(repetitions: number): Promise<BenchmarkResult> { benchmark(repetitions: number): Promise<BenchmarkResult> {
return this.doRpc<BenchmarkResult>("benchmark", return this.doRpc<BenchmarkResult>("benchmark", 1, repetitions);
1,
repetitions);
} }
} }

View File

@ -18,7 +18,6 @@
* Web worker for crypto operations. * Web worker for crypto operations.
*/ */
/** /**
* Imports. * Imports.
*/ */
@ -39,17 +38,9 @@ import {
WireFee, WireFee,
} from "../dbTypes"; } from "../dbTypes";
import { import { CoinPaySig, ContractTerms, PaybackRequest } from "../talerTypes";
CoinPaySig,
ContractTerms,
PaybackRequest,
} from "../talerTypes";
import { import { BenchmarkResult, CoinWithDenom, PayCoinInfo } from "../walletTypes";
BenchmarkResult,
CoinWithDenom,
PayCoinInfo,
} from "../walletTypes";
import { canonicalJson } from "../helpers"; import { canonicalJson } from "../helpers";
@ -64,15 +55,15 @@ import {
} from "./emscInterface"; } from "./emscInterface";
import * as native from "./emscInterface"; import * as native from "./emscInterface";
namespace RpcFunctions { namespace RpcFunctions {
/** /**
* Create a pre-coin of the given denomination to be withdrawn from then given * Create a pre-coin of the given denomination to be withdrawn from then given
* reserve. * reserve.
*/ */
export function createPreCoin(denom: DenominationRecord, export function createPreCoin(
reserve: ReserveRecord): PreCoinRecord { denom: DenominationRecord,
reserve: ReserveRecord,
): PreCoinRecord {
const reservePriv = new native.EddsaPrivateKey(); const reservePriv = new native.EddsaPrivateKey();
reservePriv.loadCrock(reserve.reserve_priv); reservePriv.loadCrock(reserve.reserve_priv);
const reservePub = new native.EddsaPublicKey(); const reservePub = new native.EddsaPublicKey();
@ -125,7 +116,6 @@ namespace RpcFunctions {
return preCoin; return preCoin;
} }
/** /**
* Create a planchet used for tipping, including the private keys. * Create a planchet used for tipping, including the private keys.
*/ */
@ -152,12 +142,14 @@ namespace RpcFunctions {
coinPub: coinPub.toCrock(), coinPub: coinPub.toCrock(),
coinValue: denom.value, coinValue: denom.value,
denomPub: denomPub.encode().toCrock(), denomPub: denomPub.encode().toCrock(),
denomPubHash: denomPub.encode().hash().toCrock(), denomPubHash: denomPub
.encode()
.hash()
.toCrock(),
}; };
return tipPlanchet; return tipPlanchet;
} }
/** /**
* Create and sign a message to request payback for a coin. * Create and sign a message to request payback for a coin.
*/ */
@ -165,7 +157,9 @@ namespace RpcFunctions {
const p = new native.PaybackRequestPS({ const p = new native.PaybackRequestPS({
coin_blind: native.RsaBlindingKeySecret.fromCrock(coin.blindingKey), coin_blind: native.RsaBlindingKeySecret.fromCrock(coin.blindingKey),
coin_pub: native.EddsaPublicKey.fromCrock(coin.coinPub), coin_pub: native.EddsaPublicKey.fromCrock(coin.coinPub),
h_denom_pub: native.RsaPublicKey.fromCrock(coin.denomPub).encode().hash(), h_denom_pub: native.RsaPublicKey.fromCrock(coin.denomPub)
.encode()
.hash(),
}); });
const coinPriv = native.EddsaPrivateKey.fromCrock(coin.coinPriv); const coinPriv = native.EddsaPrivateKey.fromCrock(coin.coinPriv);
const coinSig = native.eddsaSign(p.toPurpose(), coinPriv); const coinSig = native.eddsaSign(p.toPurpose(), coinPriv);
@ -179,63 +173,83 @@ namespace RpcFunctions {
return paybackRequest; return paybackRequest;
} }
/** /**
* Check if a payment signature is valid. * Check if a payment signature is valid.
*/ */
export function isValidPaymentSignature(sig: string, contractHash: string, merchantPub: string): boolean { export function isValidPaymentSignature(
sig: string,
contractHash: string,
merchantPub: string,
): boolean {
const p = new native.PaymentSignaturePS({ const p = new native.PaymentSignaturePS({
contract_hash: native.HashCode.fromCrock(contractHash), contract_hash: native.HashCode.fromCrock(contractHash),
}); });
const nativeSig = new native.EddsaSignature(); const nativeSig = new native.EddsaSignature();
nativeSig.loadCrock(sig); nativeSig.loadCrock(sig);
const nativePub = native.EddsaPublicKey.fromCrock(merchantPub); const nativePub = native.EddsaPublicKey.fromCrock(merchantPub);
return native.eddsaVerify(native.SignaturePurpose.MERCHANT_PAYMENT_OK, return native.eddsaVerify(
p.toPurpose(), native.SignaturePurpose.MERCHANT_PAYMENT_OK,
nativeSig, p.toPurpose(),
nativePub); nativeSig,
nativePub,
);
} }
/** /**
* Check if a wire fee is correctly signed. * Check if a wire fee is correctly signed.
*/ */
export function isValidWireFee(type: string, wf: WireFee, masterPub: string): boolean { export function isValidWireFee(
type: string,
wf: WireFee,
masterPub: string,
): boolean {
const p = new native.MasterWireFeePS({ const p = new native.MasterWireFeePS({
closing_fee: (new native.Amount(wf.closingFee)).toNbo(), closing_fee: new native.Amount(wf.closingFee).toNbo(),
end_date: native.AbsoluteTimeNbo.fromStampSeconds(wf.endStamp), end_date: native.AbsoluteTimeNbo.fromStampSeconds(wf.endStamp),
h_wire_method: native.ByteArray.fromStringWithNull(type).hash(), h_wire_method: native.ByteArray.fromStringWithNull(type).hash(),
start_date: native.AbsoluteTimeNbo.fromStampSeconds(wf.startStamp), start_date: native.AbsoluteTimeNbo.fromStampSeconds(wf.startStamp),
wire_fee: (new native.Amount(wf.wireFee)).toNbo(), wire_fee: new native.Amount(wf.wireFee).toNbo(),
}); });
const nativeSig = new native.EddsaSignature(); const nativeSig = new native.EddsaSignature();
nativeSig.loadCrock(wf.sig); nativeSig.loadCrock(wf.sig);
const nativePub = native.EddsaPublicKey.fromCrock(masterPub); const nativePub = native.EddsaPublicKey.fromCrock(masterPub);
return native.eddsaVerify(native.SignaturePurpose.MASTER_WIRE_FEES, return native.eddsaVerify(
p.toPurpose(), native.SignaturePurpose.MASTER_WIRE_FEES,
nativeSig, p.toPurpose(),
nativePub); nativeSig,
nativePub,
);
} }
/** /**
* Check if the signature of a denomination is valid. * Check if the signature of a denomination is valid.
*/ */
export function isValidDenom(denom: DenominationRecord, export function isValidDenom(
masterPub: string): boolean { denom: DenominationRecord,
masterPub: string,
): boolean {
const p = new native.DenominationKeyValidityPS({ const p = new native.DenominationKeyValidityPS({
denom_hash: native.RsaPublicKey.fromCrock(denom.denomPub) .encode() .hash(), denom_hash: native.RsaPublicKey.fromCrock(denom.denomPub)
expire_legal: native.AbsoluteTimeNbo.fromTalerString(denom.stampExpireLegal), .encode()
expire_spend: native.AbsoluteTimeNbo.fromTalerString(denom.stampExpireDeposit), .hash(),
expire_withdraw: native.AbsoluteTimeNbo.fromTalerString(denom.stampExpireWithdraw), expire_legal: native.AbsoluteTimeNbo.fromTalerString(
fee_deposit: (new native.Amount(denom.feeDeposit)).toNbo(), denom.stampExpireLegal,
fee_refresh: (new native.Amount(denom.feeRefresh)).toNbo(), ),
fee_refund: (new native.Amount(denom.feeRefund)).toNbo(), expire_spend: native.AbsoluteTimeNbo.fromTalerString(
fee_withdraw: (new native.Amount(denom.feeWithdraw)).toNbo(), 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(),
fee_withdraw: new native.Amount(denom.feeWithdraw).toNbo(),
master: native.EddsaPublicKey.fromCrock(masterPub), master: native.EddsaPublicKey.fromCrock(masterPub),
start: native.AbsoluteTimeNbo.fromTalerString(denom.stampStart), start: native.AbsoluteTimeNbo.fromTalerString(denom.stampStart),
value: (new native.Amount(denom.value)).toNbo(), value: new native.Amount(denom.value).toNbo(),
}); });
const nativeSig = new native.EddsaSignature(); const nativeSig = new native.EddsaSignature();
@ -243,42 +257,44 @@ namespace RpcFunctions {
const nativePub = native.EddsaPublicKey.fromCrock(masterPub); const nativePub = native.EddsaPublicKey.fromCrock(masterPub);
return native.eddsaVerify(native.SignaturePurpose.MASTER_DENOMINATION_KEY_VALIDITY, return native.eddsaVerify(
p.toPurpose(), native.SignaturePurpose.MASTER_DENOMINATION_KEY_VALIDITY,
nativeSig, p.toPurpose(),
nativePub); nativeSig,
nativePub,
);
} }
/** /**
* Create a new EdDSA key pair. * Create a new EdDSA key pair.
*/ */
export function createEddsaKeypair(): {priv: string, pub: string} { export function createEddsaKeypair(): { priv: string; pub: string } {
const priv = native.EddsaPrivateKey.create(); const priv = native.EddsaPrivateKey.create();
const pub = priv.getPublicKey(); const pub = priv.getPublicKey();
return {priv: priv.toCrock(), pub: pub.toCrock()}; return { priv: priv.toCrock(), pub: pub.toCrock() };
} }
/** /**
* Unblind a blindly signed value. * Unblind a blindly signed value.
*/ */
export function rsaUnblind(sig: string, bk: string, pk: string): string { export function rsaUnblind(sig: string, bk: string, pk: string): string {
const denomSig = native.rsaUnblind(native.RsaSignature.fromCrock(sig), const denomSig = native.rsaUnblind(
native.RsaBlindingKeySecret.fromCrock(bk), native.RsaSignature.fromCrock(sig),
native.RsaPublicKey.fromCrock(pk)); native.RsaBlindingKeySecret.fromCrock(bk),
native.RsaPublicKey.fromCrock(pk),
);
return denomSig.encode().toCrock(); return denomSig.encode().toCrock();
} }
/** /**
* Generate updated coins (to store in the database) * Generate updated coins (to store in the database)
* and deposit permissions for each given coin. * and deposit permissions for each given coin.
*/ */
export function signDeposit(contractTerms: ContractTerms, export function signDeposit(
cds: CoinWithDenom[], contractTerms: ContractTerms,
totalAmount: AmountJson): PayCoinInfo { cds: CoinWithDenom[],
totalAmount: AmountJson,
): PayCoinInfo {
const ret: PayCoinInfo = { const ret: PayCoinInfo = {
originalCoins: [], originalCoins: [],
sigs: [], sigs: [],
@ -287,17 +303,21 @@ namespace RpcFunctions {
const contractTermsHash = hashString(canonicalJson(contractTerms)); const contractTermsHash = hashString(canonicalJson(contractTerms));
const feeList: AmountJson[] = cds.map((x) => x.denom.feeDeposit); const feeList: AmountJson[] = cds.map(x => x.denom.feeDeposit);
let fees = Amounts.add(Amounts.getZero(feeList[0].currency), ...feeList).amount; let fees = Amounts.add(Amounts.getZero(feeList[0].currency), ...feeList)
.amount;
// okay if saturates // okay if saturates
fees = Amounts.sub(fees, Amounts.parseOrThrow(contractTerms.max_fee)).amount; fees = Amounts.sub(fees, Amounts.parseOrThrow(contractTerms.max_fee))
.amount;
const total = Amounts.add(fees, totalAmount).amount; const total = Amounts.add(fees, totalAmount).amount;
const amountSpent = native.Amount.getZero(cds[0].coin.currentAmount.currency); const amountSpent = native.Amount.getZero(
cds[0].coin.currentAmount.currency,
);
const amountRemaining = new native.Amount(total); const amountRemaining = new native.Amount(total);
for (const cd of cds) { for (const cd of cds) {
let coinSpend: Amount; let coinSpend: Amount;
const originalCoin = { ...(cd.coin) }; const originalCoin = { ...cd.coin };
if (amountRemaining.value === 0 && amountRemaining.fraction === 0) { if (amountRemaining.value === 0 && amountRemaining.fraction === 0) {
break; break;
@ -332,13 +352,20 @@ namespace RpcFunctions {
h_contract: native.HashCode.fromCrock(contractTermsHash), h_contract: native.HashCode.fromCrock(contractTermsHash),
h_wire: native.HashCode.fromCrock(contractTerms.H_wire), h_wire: native.HashCode.fromCrock(contractTerms.H_wire),
merchant: native.EddsaPublicKey.fromCrock(contractTerms.merchant_pub), merchant: native.EddsaPublicKey.fromCrock(contractTerms.merchant_pub),
refund_deadline: native.AbsoluteTimeNbo.fromTalerString(contractTerms.refund_deadline), refund_deadline: native.AbsoluteTimeNbo.fromTalerString(
timestamp: native.AbsoluteTimeNbo.fromTalerString(contractTerms.timestamp), contractTerms.refund_deadline,
),
timestamp: native.AbsoluteTimeNbo.fromTalerString(
contractTerms.timestamp,
),
}); });
const coinSig = native.eddsaSign(d.toPurpose(), const coinSig = native
native.EddsaPrivateKey.fromCrock(cd.coin.coinPriv)) .eddsaSign(
.toCrock(); d.toPurpose(),
native.EddsaPrivateKey.fromCrock(cd.coin.coinPriv),
)
.toCrock();
const s: CoinPaySig = { const s: CoinPaySig = {
coin_pub: cd.coin.coinPub, coin_pub: cd.coin.coinPub,
@ -355,22 +382,21 @@ namespace RpcFunctions {
return ret; return ret;
} }
/** /**
* Create a new refresh session. * Create a new refresh session.
*/ */
export function createRefreshSession(exchangeBaseUrl: string, export function createRefreshSession(
kappa: number, exchangeBaseUrl: string,
meltCoin: CoinRecord, kappa: number,
newCoinDenoms: DenominationRecord[], meltCoin: CoinRecord,
meltFee: AmountJson): RefreshSessionRecord { newCoinDenoms: DenominationRecord[],
meltFee: AmountJson,
): RefreshSessionRecord {
let valueWithFee = Amounts.getZero(newCoinDenoms[0].value.currency); let valueWithFee = Amounts.getZero(newCoinDenoms[0].value.currency);
for (const ncd of newCoinDenoms) { for (const ncd of newCoinDenoms) {
valueWithFee = Amounts.add(valueWithFee, valueWithFee = Amounts.add(valueWithFee, ncd.value, ncd.feeWithdraw)
ncd.value, .amount;
ncd.feeWithdraw).amount;
} }
// melt fee // melt fee
@ -397,12 +423,11 @@ namespace RpcFunctions {
} }
sessionHc.read(native.EddsaPublicKey.fromCrock(meltCoin.coinPub)); sessionHc.read(native.EddsaPublicKey.fromCrock(meltCoin.coinPub));
sessionHc.read((new native.Amount(valueWithFee)).toNbo()); sessionHc.read(new native.Amount(valueWithFee).toNbo());
for (let i = 0; i < kappa; i++) { for (let i = 0; i < kappa; i++) {
const preCoins: RefreshPreCoinRecord[] = []; const preCoins: RefreshPreCoinRecord[] = [];
for (let j = 0; j < newCoinDenoms.length; j++) { for (let j = 0; j < newCoinDenoms.length; j++) {
const transferPriv = native.EcdhePrivateKey.fromCrock(transferPrivs[i]); const transferPriv = native.EcdhePrivateKey.fromCrock(transferPrivs[i]);
const oldCoinPub = native.EddsaPublicKey.fromCrock(meltCoin.coinPub); const oldCoinPub = native.EddsaPublicKey.fromCrock(meltCoin.coinPub);
const transferSecret = native.ecdhEddsa(transferPriv, oldCoinPub); const transferSecret = native.ecdhEddsa(transferPriv, oldCoinPub);
@ -413,10 +438,10 @@ namespace RpcFunctions {
const coinPub = coinPriv.getPublicKey(); const coinPub = coinPriv.getPublicKey();
const blindingFactor = fresh.blindingKey; const blindingFactor = fresh.blindingKey;
const pubHash: native.HashCode = coinPub.hash(); const pubHash: native.HashCode = coinPub.hash();
const denomPub = native.RsaPublicKey.fromCrock(newCoinDenoms[j].denomPub); const denomPub = native.RsaPublicKey.fromCrock(
const ev = native.rsaBlind(pubHash, newCoinDenoms[j].denomPub,
blindingFactor, );
denomPub); const ev = native.rsaBlind(pubHash, blindingFactor, denomPub);
if (!ev) { if (!ev) {
throw Error("couldn't blind (malicious exchange key?)"); throw Error("couldn't blind (malicious exchange key?)");
} }
@ -437,16 +462,18 @@ namespace RpcFunctions {
sessionHc.finish(sessionHash); sessionHc.finish(sessionHash);
const confirmData = new RefreshMeltCoinAffirmationPS({ const confirmData = new RefreshMeltCoinAffirmationPS({
amount_with_fee: (new Amount(valueWithFee)).toNbo(), amount_with_fee: new Amount(valueWithFee).toNbo(),
coin_pub: EddsaPublicKey.fromCrock(meltCoin.coinPub), coin_pub: EddsaPublicKey.fromCrock(meltCoin.coinPub),
melt_fee: (new Amount(meltFee)).toNbo(), melt_fee: new Amount(meltFee).toNbo(),
session_hash: sessionHash, session_hash: sessionHash,
}); });
const confirmSig: string = native
const confirmSig: string = native.eddsaSign(confirmData.toPurpose(), .eddsaSign(
native.EddsaPrivateKey.fromCrock( confirmData.toPurpose(),
meltCoin.coinPriv)).toCrock(); native.EddsaPrivateKey.fromCrock(meltCoin.coinPriv),
)
.toCrock();
let valueOutput = Amounts.getZero(newCoinDenoms[0].value.currency); let valueOutput = Amounts.getZero(newCoinDenoms[0].value.currency);
for (const denom of newCoinDenoms) { for (const denom of newCoinDenoms) {
@ -459,8 +486,8 @@ namespace RpcFunctions {
finished: false, finished: false,
hash: sessionHash.toCrock(), hash: sessionHash.toCrock(),
meltCoinPub: meltCoin.coinPub, meltCoinPub: meltCoin.coinPub,
newDenomHashes: newCoinDenoms.map((d) => d.denomPubHash), newDenomHashes: newCoinDenoms.map(d => d.denomPubHash),
newDenoms: newCoinDenoms.map((d) => d.denomPub), newDenoms: newCoinDenoms.map(d => d.denomPub),
norevealIndex: undefined, norevealIndex: undefined,
preCoinsForGammas, preCoinsForGammas,
transferPrivs, transferPrivs,
@ -484,7 +511,33 @@ namespace RpcFunctions {
* Hash a denomination public key. * Hash a denomination public key.
*/ */
export function hashDenomPub(denomPub: string): string { export function hashDenomPub(denomPub: string): string {
return native.RsaPublicKey.fromCrock(denomPub).encode().hash().toCrock(); return native.RsaPublicKey.fromCrock(denomPub)
.encode()
.hash()
.toCrock();
}
export function signCoinLink(
oldCoinPriv: string,
newDenomHash: string,
oldCoinPub: string,
transferPub: string,
coinEv: string,
): string {
const coinEvHash = native.ByteArray.fromCrock(coinEv).hash();
const coinLink = new native.CoinLinkSignaturePS({
coin_envelope_hash: coinEvHash,
h_denom_pub: native.HashCode.fromCrock(newDenomHash),
old_coin_pub: native.EddsaPublicKey.fromCrock(oldCoinPub),
transfer_pub: native.EcdhePublicKey.fromCrock(transferPub),
});
const coinPriv = native.EddsaPrivateKey.fromCrock(oldCoinPriv);
const sig = native.eddsaSign(coinLink.toPurpose(), coinPriv);
return sig.toCrock();
} }
export function benchmark(repetitions: number): BenchmarkResult { export function benchmark(repetitions: number): BenchmarkResult {
@ -500,7 +553,7 @@ namespace RpcFunctions {
for (let i = 0; i < repetitions; i++) { for (let i = 0; i < repetitions; i++) {
ba.randomize(native.RandomQuality.WEAK); ba.randomize(native.RandomQuality.WEAK);
const start = timer.performanceNow(); const start = timer.performanceNow();
ba.hash(); ba.hash();
time_hash_big += timer.performanceNow() - start; time_hash_big += timer.performanceNow() - start;
} }
@ -508,7 +561,7 @@ namespace RpcFunctions {
for (let i = 0; i < repetitions; i++) { for (let i = 0; i < repetitions; i++) {
const start = timer.performanceNow(); const start = timer.performanceNow();
const priv: native.EddsaPrivateKey = native.EddsaPrivateKey.create(); const priv: native.EddsaPrivateKey = native.EddsaPrivateKey.create();
time_eddsa_create += timer.performanceNow() - start; time_eddsa_create += timer.performanceNow() - start;
priv.destroy(); priv.destroy();
} }
@ -541,14 +594,15 @@ namespace RpcFunctions {
priv.destroy(); priv.destroy();
} }
let time_eddsa_verify = 0; let time_eddsa_verify = 0;
for (let i = 0; i < repetitions; i++) { for (let i = 0; i < repetitions; i++) {
const start = timer.performanceNow(); const start = timer.performanceNow();
native.eddsaVerify(native.SignaturePurpose.MERCHANT_PAYMENT_OK, native.eddsaVerify(
p, native.SignaturePurpose.MERCHANT_PAYMENT_OK,
eddsaSig, p,
eddsaPub); eddsaSig,
eddsaPub,
);
time_eddsa_verify += timer.performanceNow() - start; time_eddsa_verify += timer.performanceNow() - start;
} }
@ -564,11 +618,18 @@ namespace RpcFunctions {
time_rsa_2048_blind += timer.performanceNow() - start; time_rsa_2048_blind += timer.performanceNow() - start;
} }
const blindedMessage2048 = native.rsaBlind(h, blindingSecret2048, rsaPub2048); const blindedMessage2048 = native.rsaBlind(
h,
blindingSecret2048,
rsaPub2048,
);
if (!blindedMessage2048) { if (!blindedMessage2048) {
throw Error("should not happen"); throw Error("should not happen");
} }
const rsaBlindSig2048 = native.rsaSignBlinded(rsaPriv2048, blindedMessage2048); const rsaBlindSig2048 = native.rsaSignBlinded(
rsaPriv2048,
blindedMessage2048,
);
let time_rsa_2048_unblind = 0; let time_rsa_2048_unblind = 0;
for (let i = 0; i < repetitions; i++) { for (let i = 0; i < repetitions; i++) {
@ -577,7 +638,11 @@ namespace RpcFunctions {
time_rsa_2048_unblind += timer.performanceNow() - start; time_rsa_2048_unblind += timer.performanceNow() - start;
} }
const unblindedSig2048 = native.rsaUnblind(rsaBlindSig2048, blindingSecret2048, rsaPub2048); const unblindedSig2048 = native.rsaUnblind(
rsaBlindSig2048,
blindingSecret2048,
rsaPub2048,
);
let time_rsa_2048_verify = 0; let time_rsa_2048_verify = 0;
for (let i = 0; i < repetitions; i++) { for (let i = 0; i < repetitions; i++) {
@ -586,7 +651,6 @@ namespace RpcFunctions {
time_rsa_2048_verify += timer.performanceNow() - start; time_rsa_2048_verify += timer.performanceNow() - start;
} }
/* rsa 4096 */ /* rsa 4096 */
let time_rsa_4096_blind = 0; let time_rsa_4096_blind = 0;
@ -599,11 +663,18 @@ namespace RpcFunctions {
time_rsa_4096_blind += timer.performanceNow() - start; time_rsa_4096_blind += timer.performanceNow() - start;
} }
const blindedMessage4096 = native.rsaBlind(h, blindingSecret4096, rsaPub4096); const blindedMessage4096 = native.rsaBlind(
h,
blindingSecret4096,
rsaPub4096,
);
if (!blindedMessage4096) { if (!blindedMessage4096) {
throw Error("should not happen"); throw Error("should not happen");
} }
const rsaBlindSig4096 = native.rsaSignBlinded(rsaPriv4096, blindedMessage4096); const rsaBlindSig4096 = native.rsaSignBlinded(
rsaPriv4096,
blindedMessage4096,
);
let time_rsa_4096_unblind = 0; let time_rsa_4096_unblind = 0;
for (let i = 0; i < repetitions; i++) { for (let i = 0; i < repetitions; i++) {
@ -612,7 +683,11 @@ namespace RpcFunctions {
time_rsa_4096_unblind += timer.performanceNow() - start; time_rsa_4096_unblind += timer.performanceNow() - start;
} }
const unblindedSig4096 = native.rsaUnblind(rsaBlindSig4096, blindingSecret4096, rsaPub4096); const unblindedSig4096 = native.rsaUnblind(
rsaBlindSig4096,
blindingSecret4096,
rsaPub4096,
);
let time_rsa_4096_verify = 0; let time_rsa_4096_verify = 0;
for (let i = 0; i < repetitions; i++) { for (let i = 0; i < repetitions; i++) {
@ -621,7 +696,6 @@ namespace RpcFunctions {
time_rsa_4096_verify += timer.performanceNow() - start; time_rsa_4096_verify += timer.performanceNow() - start;
} }
return { return {
repetitions, repetitions,
time: { time: {
@ -637,12 +711,11 @@ namespace RpcFunctions {
rsa_4096_blind: time_rsa_4096_blind, rsa_4096_blind: time_rsa_4096_blind,
rsa_4096_unblind: time_rsa_4096_unblind, rsa_4096_unblind: time_rsa_4096_unblind,
rsa_4096_verify: time_rsa_4096_verify, rsa_4096_verify: time_rsa_4096_verify,
} },
}; };
} }
} }
const worker: Worker = (self as any) as Worker; const worker: Worker = (self as any) as Worker;
worker.onmessage = (msg: MessageEvent) => { worker.onmessage = (msg: MessageEvent) => {
@ -665,7 +738,7 @@ worker.onmessage = (msg: MessageEvent) => {
console.log("onmessage with", msg.data.operation); console.log("onmessage with", msg.data.operation);
console.log("foo"); console.log("foo");
emscLoader.getLib().then((p) => { emscLoader.getLib().then(p => {
const lib = p.lib; const lib = p.lib;
if (!native.isInitialized()) { if (!native.isInitialized()) {
console.log("initializing emscripten for then first time with lib"); console.log("initializing emscripten for then first time with lib");

View File

@ -223,6 +223,7 @@ export enum SignaturePurpose {
MERCHANT_PAYMENT_OK = 1104, MERCHANT_PAYMENT_OK = 1104,
MASTER_WIRE_FEES = 1028, MASTER_WIRE_FEES = 1028,
WALLET_COIN_PAYBACK = 1203, WALLET_COIN_PAYBACK = 1203,
WALLET_COIN_LINK = 1204,
} }
@ -970,7 +971,7 @@ abstract class SignatureStruct {
throw Error(`Key ${name} not found`); throw Error(`Key ${name} not found`);
} }
if (!(value instanceof typemap[name])) { if (!(value instanceof typemap[name])) {
throw Error("Wrong type for ${name}"); throw Error(`Wrong type for ${name}`);
} }
this.members[name] = value; this.members[name] = value;
} }
@ -1293,6 +1294,35 @@ export class DepositRequestPS extends SignatureStruct {
} }
} }
interface CoinLinkSignaturePS_args {
h_denom_pub: HashCode;
old_coin_pub: EddsaPublicKey;
transfer_pub: EcdhePublicKey;
coin_envelope_hash: HashCode;
}
export class CoinLinkSignaturePS extends SignatureStruct {
constructor(w: CoinLinkSignaturePS_args) {
super(w);
}
purpose() {
return SignaturePurpose.WALLET_COIN_LINK;
}
fieldTypes() {
return [
["h_denom_pub", HashCode],
["old_coin_pub", EddsaPublicKey],
["transfer_pub", EcdhePublicKey],
["coin_envelope_hash", HashCode],
];
}
}
/** /**
* Arguments for constuctor of [[DenominationKeyValidityPS]]. * Arguments for constuctor of [[DenominationKeyValidityPS]].
*/ */

File diff suppressed because it is too large Load Diff