-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathclient.js
105 lines (89 loc) · 2.68 KB
/
client.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
"use strict";
const blindSignatures = require('blind-signatures');
const { Coin, COIN_RIS_LENGTH, IDENT_STR, BANK_STR, NUM_COINS_REQUIRED } = require('./coin.js');
const utils = require('./utils.js');
const TOKEN_RIS_LENGTH = 20;
// Simple class simulating a client in out network.
// For simplicity sake, a client can only hold 1 coin at a time.
class Client {
// Every client must have a name to identify them.
constructor(name) {
this.name = name;
}
// Buys a coin from the bank, calling the bank's "sellCoin" method.
// This approach uses a "cut-and-choose" strategy so that the bank
// will sign the coin without seeing it.
buyCoin(bank, amount) {
if (!!this.coin) {
throw new Error('Already have a coin');
}
let coins = [];
let blindingFactors = [];
let blindedHashes = [];
for (let i=0; i<NUM_COINS_REQUIRED; i++) {
coins[i] = new Coin(this.name, amount, bank.n, bank.e);
blindingFactors[i] = coins[i].blind();
blindedHashes[i] = coins[i].blinded;
}
let bf;
let signature = bank.sellCoin(this.name, amount, blindedHashes, (selected) => {
this.coin = coins[selected];
bf = blindingFactors[selected];
delete coins[selected];
return [blindingFactors, coins];
});
this.coin.signature = signature;
this.coin.unblind(bf);
}
// Transfers a coin to another user, deleting it from this user.
giveCoin(other) {
if (!this.coin) {
throw new Error('Do not have a coin');
} else if (!!other.coin) {
throw new Error(`${other.name} already have a coin`);
}
other.acceptCoin(this.coin);
delete this.coin;
}
// Procedure for a client accepting a token.
// The client randomly selects the left or
// right halves of the identity string.
acceptCoin(coin) {
let cs = coin.toString();
let valid = blindSignatures.verify({
unblinded: coin.signature,
N: coin.n,
E: coin.e,
message: cs
});
if(!valid){
throw new Error("Bad signature.");
}
let [lh, rh] = Coin.parseCoin(cs);
let ris = [];
for(let i = 0; i < lh.length; i++){
let isLeft = !!utils.randInt(2);
let identHalf = coin.getRis(isLeft, i);
let hashVal = isLeft ? lh[i] : rh[i];
let h = utils.hash(identHalf);
if(h !== hashVal){
throw new Error();
}
ris.push(identHalf);
}
this.ris = ris;
this.coin = coin;
}
// Deposits the coin to the bank,
// deleting it from the user.
redeemCoin(bank) {
bank.redeemCoin({
account: this.name,
coin: this.coin,
ris: this.ris,
});
delete this.coin;
delete this.ris;
}
}
exports.Client = Client;