-
Notifications
You must be signed in to change notification settings - Fork 9
/
pseudonyms.spec.ts
432 lines (352 loc) · 16.5 KB
/
pseudonyms.spec.ts
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
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
import { generateRandomFieldElement } from 'crypto-wasm-new';
import {
AttributeBoundPseudonym,
CompositeProof,
initializeWasm,
MetaStatement,
MetaStatements,
ProofSpec,
Pseudonym,
PseudonymBases,
Statement,
Statements,
Witness,
WitnessEqualityMetaStatement,
Witnesses
} from '../../src';
import { buildWitness, Scheme, Signature } from '../scheme';
import {
checkResult,
getParamsAndKeys,
getRevealedUnrevealed,
proverStmt,
signAndVerify,
stringToBytes,
verifierStmt
} from '../utils';
// Get some attributes for testing
function getAttributes(): Uint8Array[] {
// Messages to sign
const attributes: Uint8Array[] = [];
// SSN
attributes.push(stringToBytes('123-456789-0'));
// First name
attributes.push(stringToBytes('John'));
// Last name
attributes.push(stringToBytes('Smith'));
// Email
attributes.push(stringToBytes('[email protected]'));
// Encode attributes for signing as well as adding to the accumulator
const encodedAttributes: Uint8Array[] = [];
for (let i = 0; i < attributes.length; i++) {
encodedAttributes.push(Signature.encodeMessageForSigning(attributes[i]));
}
return encodedAttributes;
}
// User creates a proof that it knows the secret key used in the pseudonym and verifier verifies the proof
function registerUsingPseudonym(pseudonym: Pseudonym, base: Uint8Array, secretKey: Uint8Array) {
const statement = Statement.pseudonym(pseudonym, base);
const statements = new Statements();
statements.add(statement);
const proofSpec = new ProofSpec(statements, new MetaStatements());
const witness = Witness.pseudonym(secretKey);
const witnesses = new Witnesses();
witnesses.add(witness);
const proof = CompositeProof.generate(proofSpec, witnesses);
checkResult(proof.verify(proofSpec));
}
// User creates a proof that it knows the secret key and attributes used in the pseudonym and verifier verifies the proof
function registerUsingAttributeBoundPseudonym(
pseudonym: AttributeBoundPseudonym,
basesForAttributes: Uint8Array[],
attributes: Uint8Array[],
baseForSecretKey?: Uint8Array,
secretKey?: Uint8Array
) {
const statement = Statement.attributeBoundPseudonym(pseudonym, basesForAttributes, baseForSecretKey);
const statements = new Statements();
statements.add(statement);
const proofSpec = new ProofSpec(statements, new MetaStatements());
const witness = Witness.attributeBoundPseudonym(attributes, secretKey);
const witnesses = new Witnesses();
witnesses.add(witness);
const proof = CompositeProof.generate(proofSpec, witnesses);
checkResult(proof.verify(proofSpec));
}
describe(`${Scheme} Register using pseudonym not bound to any attributes`, () => {
// User creates a secret key and creates 2 pseudonyms from it, one for each service provider.
let secretKey: Uint8Array;
const scope1 = stringToBytes('Service provider 1');
// Base created by service provider 1
let base1: Uint8Array;
// Pseudonym used at service provider 1
let pseudonym1: Pseudonym;
const scope2 = stringToBytes('Service provider 2');
// Base created by service provider 2
let base2: Uint8Array;
// Pseudonym used at service provider 2
let pseudonym2: Pseudonym;
beforeAll(async () => {
// Load the WASM module
await initializeWasm();
// User creates a secret key
secretKey = generateRandomFieldElement();
});
it('At service provider 1', () => {
// Service provider creates a base
base1 = PseudonymBases.generateBaseForSecretKey(scope1);
// User creates a pseudonym from its secret key
pseudonym1 = Pseudonym.new(base1, secretKey);
// User registers pseudonym as service provider 1
registerUsingPseudonym(pseudonym1, base1, secretKey);
});
it('At service provider 2', () => {
// Service provider creates a base
base2 = PseudonymBases.generateBaseForSecretKey(scope2);
// User creates a pseudonym from its secret key
pseudonym2 = Pseudonym.new(base2, secretKey);
// User registers pseudonym as service provider 2
registerUsingPseudonym(pseudonym2, base2, secretKey);
});
it('Pseudonym different at both service providers', () => {
expect(base1).not.toEqual(base2);
expect(pseudonym1.value).not.toEqual(pseudonym2.value);
});
it('Usage along with credential', () => {
// User gets a credential (attributes + signature)
const encodedAttributes = getAttributes();
const label = stringToBytes('My sig params in g1');
// Signers keys
const [sigParams, sigSk, sigPk] = getParamsAndKeys(encodedAttributes.length, label);
const [sig, result] = signAndVerify(encodedAttributes, sigParams, sigSk, sigPk);
checkResult(result);
// Prover is not revealing any attribute
const [_, unrevealed] = getRevealedUnrevealed(encodedAttributes, new Set());
// User using its pseudonym at service provider 1
{
const statement1 = proverStmt(sigParams, new Map(), sigPk);
const statement2 = Statement.pseudonym(pseudonym1, base1);
const proverStatements = new Statements();
proverStatements.add(statement1);
proverStatements.add(statement2);
const proverProofSpec = new ProofSpec(proverStatements, new MetaStatements());
const witness1 = buildWitness(sig, unrevealed, false);
const witness2 = Witness.pseudonym(secretKey);
const witnesses = new Witnesses(witness1);
witnesses.add(witness2);
const proof = CompositeProof.generate(proverProofSpec, witnesses);
const statement3 = verifierStmt(sigParams, new Map(), sigPk);
const verifierStatements = new Statements();
verifierStatements.add(statement3);
verifierStatements.add(statement2);
const verifierProofSpec = new ProofSpec(verifierStatements, new MetaStatements());
checkResult(proof.verify(verifierProofSpec));
}
// User using its pseudonym at service provider 2
{
const statement1 = proverStmt(sigParams, new Map(), sigPk);
const statement2 = Statement.pseudonym(pseudonym2, base2);
const proverStatements = new Statements(statement1);
proverStatements.add(statement2);
const proverProofSpec = new ProofSpec(proverStatements, new MetaStatements());
const witness1 = buildWitness(sig, unrevealed, false);
const witness2 = Witness.pseudonym(secretKey);
const witnesses = new Witnesses(witness1);
witnesses.add(witness2);
const proof = CompositeProof.generate(proverProofSpec, witnesses);
const statement3 = verifierStmt(sigParams, new Map(), sigPk);
const verifierStatements = new Statements();
verifierStatements.add(statement3);
verifierStatements.add(statement2);
const verifierProofSpec = new ProofSpec(verifierStatements, new MetaStatements());
checkResult(proof.verify(verifierProofSpec));
}
});
});
describe(`${Scheme} Using pseudonym bound to some attributes`, () => {
// User creates a secret key and chooses certain attributes from a credential and creates 3 pseudonyms from those, one for each service provider.
let secretKey: Uint8Array;
const scope1 = stringToBytes('Service provider 1');
// Base for secret key created by service provider 1
let base1ForSecretKey: Uint8Array;
// Bases for attributes created by service provider 1
let bases1ForAttributes: Uint8Array[];
// Pseudonym used at service provider 1
let pseudonym1: Pseudonym;
// attributes bound to pseudonym1
let attributesPseudonym1: Uint8Array[];
const scope2 = stringToBytes('Service provider 2');
// Base for secret key created by service provider 2
let base2ForSecretKey: Uint8Array;
// Bases for attributes created by service provider 2
let bases2ForAttributes: Uint8Array[];
// Pseudonym used at service provider 2
let pseudonym2: Pseudonym;
// attributes bound to pseudonym2
let attributesPseudonym2: Uint8Array[];
const scope3 = stringToBytes('Service provider 3');
// Service provider 3 does not want user to use its secret key but treat the combination of some of its attributes as
// secret key. This approach however is vulnerable to an brute force attack where the verifier (service provider here)
// can enumerate over all possible combinations of attributes to guess what they are.
// Bases for attributes created by service provider 3
let bases3ForAttributes: Uint8Array[];
// Pseudonym used at service provider 3
let pseudonym3: Pseudonym;
// attributes bound to pseudonym3
let attributesPseudonym3: Uint8Array[];
let encodedAttributes: Uint8Array[];
beforeAll(async () => {
// Load the WASM module
await initializeWasm();
// Service provider 1 creates bases
base1ForSecretKey = PseudonymBases.generateBaseForSecretKey(scope1);
// Pseudonym used is bound to 1 credential attribute
bases1ForAttributes = PseudonymBases.generateBasesForAttributes(1, scope1);
// Service provider 2 creates bases
base2ForSecretKey = PseudonymBases.generateBaseForSecretKey(scope2);
// Pseudonym used is bound to 2 credential attributes
bases2ForAttributes = PseudonymBases.generateBasesForAttributes(2, scope2);
// Service provider 3 creates bases and pseudonym used is bound to 2 credential attributes
bases3ForAttributes = PseudonymBases.generateBasesForAttributes(2, scope3);
// User creates a secret key
secretKey = generateRandomFieldElement();
encodedAttributes = getAttributes();
attributesPseudonym1 = [encodedAttributes[0]];
attributesPseudonym2 = [encodedAttributes[0], encodedAttributes[3]];
attributesPseudonym3 = [encodedAttributes[0], encodedAttributes[3]];
// User creates pseudonym for service provider 1. This pseudonym is bound to 1 attribute and the secret key
pseudonym1 = AttributeBoundPseudonym.new(bases1ForAttributes, attributesPseudonym1, base1ForSecretKey, secretKey);
// User creates pseudonym for service provider 2. This pseudonym is bound to 2 attributes and the secret key
pseudonym2 = AttributeBoundPseudonym.new(bases2ForAttributes, attributesPseudonym2, base2ForSecretKey, secretKey);
// User creates pseudonym for service provider 3. This pseudonym is bound only to 2 attributes but not the secret key
pseudonym3 = AttributeBoundPseudonym.new(bases3ForAttributes, attributesPseudonym3);
});
it('Registration of pseudonyms', () => {
// User registers pseudonym as service provider 1
registerUsingAttributeBoundPseudonym(
pseudonym1,
bases1ForAttributes,
attributesPseudonym1,
base1ForSecretKey,
secretKey
);
// User registers pseudonym as service provider 2
registerUsingAttributeBoundPseudonym(
pseudonym2,
bases2ForAttributes,
attributesPseudonym2,
base2ForSecretKey,
secretKey
);
// User registers pseudonym as service provider 3
registerUsingAttributeBoundPseudonym(pseudonym3, bases3ForAttributes, attributesPseudonym3);
});
it('Usage along with credential', () => {
const label = stringToBytes('My sig params in g1');
const [sigParams, sigSk, sigPk] = getParamsAndKeys(encodedAttributes.length, label);
const [sig, result] = signAndVerify(encodedAttributes, sigParams, sigSk, sigPk, false);
checkResult(result);
// Prover is not revealing 1 attribute
const revealedIndices = new Set<number>();
revealedIndices.add(1);
const [revealed, unrevealed] = getRevealedUnrevealed(encodedAttributes, revealedIndices);
// User using its pseudonym at service provider 1
{
const statement1 = proverStmt(sigParams, revealed, sigPk);
const statement2 = Statement.attributeBoundPseudonym(pseudonym1, bases1ForAttributes, base1ForSecretKey);
const proverStatements = new Statements();
proverStatements.add(statement1);
proverStatements.add(statement2);
// The 0th attribute in the credential is bound to the pseudonym
const witnessEq = new WitnessEqualityMetaStatement();
// Witness ref for 0th attribute in the credential
witnessEq.addWitnessRef(0, 0);
// Witness ref for bound attribute
witnessEq.addWitnessRef(1, 0);
const metaStatements = new MetaStatements();
metaStatements.add(MetaStatement.witnessEquality(witnessEq));
const proverProofSpec = new ProofSpec(proverStatements, metaStatements);
const witness1 = buildWitness(sig, unrevealed, false);
const witness2 = Witness.attributeBoundPseudonym(attributesPseudonym1, secretKey);
const witnesses = new Witnesses(witness1);
witnesses.add(witness2);
const proof = CompositeProof.generate(proverProofSpec, witnesses);
const statement3 = verifierStmt(sigParams, revealed, sigPk);
const verifierStatements = new Statements();
verifierStatements.add(statement3);
verifierStatements.add(statement2);
const verifierProofSpec = new ProofSpec(verifierStatements, metaStatements);
checkResult(proof.verify(verifierProofSpec));
}
// User using its pseudonym at service provider 2
{
const statement1 = proverStmt(sigParams, revealed, sigPk);
const statement2 = Statement.attributeBoundPseudonym(pseudonym2, bases2ForAttributes, base2ForSecretKey);
const proverStatements = new Statements();
proverStatements.add(statement1);
proverStatements.add(statement2);
// The 0th attribute in the credential is bound to the pseudonym at index 0
const witnessEq1 = new WitnessEqualityMetaStatement();
// Witness ref for 0th attribute in the credential
witnessEq1.addWitnessRef(0, 0);
// Witness ref for 1st bound attribute
witnessEq1.addWitnessRef(1, 0);
// The 3rd attribute in the credential is bound to the pseudonym at index 1
const witnessEq2 = new WitnessEqualityMetaStatement();
// Witness ref for 3rd attribute in the credential
witnessEq2.addWitnessRef(0, 3);
// Witness ref for 2nd bound attribute
witnessEq2.addWitnessRef(1, 1);
const metaStatements = new MetaStatements();
metaStatements.add(MetaStatement.witnessEquality(witnessEq1));
metaStatements.add(MetaStatement.witnessEquality(witnessEq2));
const proverProofSpec = new ProofSpec(proverStatements, metaStatements);
const witness1 = buildWitness(sig, unrevealed, false);
const witness2 = Witness.attributeBoundPseudonym(attributesPseudonym2, secretKey);
const witnesses = new Witnesses(witness1);
witnesses.add(witness2);
const proof = CompositeProof.generate(proverProofSpec, witnesses);
const statement3 = verifierStmt(sigParams, revealed, sigPk);
const verifierStatements = new Statements();
verifierStatements.add(statement3);
verifierStatements.add(statement2);
const verifierProofSpec = new ProofSpec(verifierStatements, metaStatements);
checkResult(proof.verify(verifierProofSpec));
}
// User using its pseudonym at service provider 3
{
const statement1 = proverStmt(sigParams, revealed, sigPk);
const statement2 = Statement.attributeBoundPseudonym(pseudonym3, bases3ForAttributes);
const proverStatements = new Statements();
proverStatements.add(statement1);
proverStatements.add(statement2);
// The 0th attribute in the credential is bound to the pseudonym at index 0
const witnessEq1 = new WitnessEqualityMetaStatement();
// Witness ref for 0th attribute in the credential
witnessEq1.addWitnessRef(0, 0);
// Witness ref for 1st bound attribute
witnessEq1.addWitnessRef(1, 0);
// The 3rd attribute in the credential is bound to the pseudonym at index 1
const witnessEq2 = new WitnessEqualityMetaStatement();
// Witness ref for 3rd attribute in the credential
witnessEq2.addWitnessRef(0, 3);
// Witness ref for 2nd bound attribute
witnessEq2.addWitnessRef(1, 1);
const metaStatements = new MetaStatements();
metaStatements.add(MetaStatement.witnessEquality(witnessEq1));
metaStatements.add(MetaStatement.witnessEquality(witnessEq2));
const proverProofSpec = new ProofSpec(proverStatements, metaStatements);
const witness1 = buildWitness(sig, unrevealed, false);
const witness2 = Witness.attributeBoundPseudonym(attributesPseudonym3);
const witnesses = new Witnesses(witness1);
witnesses.add(witness2);
const proof = CompositeProof.generate(proverProofSpec, witnesses);
const statement3 = verifierStmt(sigParams, revealed, sigPk);
const verifierStatements = new Statements();
verifierStatements.add(statement3);
verifierStatements.add(statement2);
const verifierProofSpec = new ProofSpec(verifierStatements, metaStatements);
checkResult(proof.verify(verifierProofSpec));
}
});
});