-
Notifications
You must be signed in to change notification settings - Fork 9
/
presentation-specification.ts
279 lines (256 loc) · 9.41 KB
/
presentation-specification.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
import { KBUniversalAccumulatorValue } from '../accumulator/kb-universal-accumulator';
import {
AttributeEquality,
BlindedAttributeEquality,
ID_STR,
BlindSignatureType,
BoundCheckProtocol,
CircomProtocol,
RevocationStatusProtocol,
SignatureType,
VerifiableEncryptionProtocol,
REV_CHECK_STR,
TYPE_STR,
InequalityProtocol,
AccumulatorValueType, VERSION_STR, SCHEMA_DETAILS_STR
} from './types-and-consts';
import b58 from 'bs58';
import { CredentialSchema } from './schema';
export interface IPresentedStatus {
[ID_STR]: string;
[TYPE_STR]: RevocationStatusProtocol;
[REV_CHECK_STR]: string;
accumulated: AccumulatorValueType;
extra: object;
}
export interface IPresentedAttributeBound {
min: number;
max: number;
// paramId will be absent when Bulletproofs++ with default setup is used
paramId?: string;
protocol: BoundCheckProtocol;
}
export interface IPresentedAttributeVE {
chunkBitSize: number;
commitmentGensId: string;
encryptionKeyId: string;
snarkKeyId: string;
protocol: VerifiableEncryptionProtocol;
}
/**
* A mapping of one private variable of the Circom circuit to one or more attributes
*/
export interface ICircuitPrivateVar {
varName: string;
// A circuit variable can be a single value or an array and thus map to one or more attributes
attributeName: { [key: string]: null | object } | { [key: string]: null | object }[];
}
/**
* A mapping of one private variable of the Circom circuit to one or more (credential, attribute) pairs
*/
export interface ICircuitPrivateVarMultiCred {
varName: string;
// A circuit variable can be reference to a single attribute or an array and thus map to one
// or more attribute references. Each attribute reference is a pair with 1st item is the credential
// index and 2nd is the attribute name
attributeRef: [number, { [key: string]: null | object }] | [number, { [key: string]: null | object }][];
}
/**
* A mapping of one public variable of the Circom circuit to one or more values
*/
export interface ICircuitPublicVar {
varName: string;
// A circuit variable can be a single value or an array and thus map to one or more values
value: Uint8Array | Uint8Array[];
}
/**
* R1CS public inputs, private attribute names involved in circuit.
*/
export interface ICircomPredicate<PV> {
privateVars: PV[];
publicVars: ICircuitPublicVar[];
// Used to identify the circuit and associated R1CS and WASM files
circuitId: string;
snarkKeyId: string;
protocol: CircomProtocol;
}
export interface IPresentedAttributeInequality {
inEqualTo: any;
// paramId will be absent when default commitment key is used
paramId?: string;
protocol: InequalityProtocol;
}
export interface IPresentedCredential {
sigType?: SignatureType;
version: string;
schema: string | {[ID_STR]: string, [TYPE_STR]: string, [VERSION_STR]: string, [SCHEMA_DETAILS_STR]: string};
// Attributes being revealed to the verifier
revealedAttributes: object;
// Credential status used for checking revocation
status?: IPresentedStatus;
// Bounds proved of any attribute(s)
bounds?: { [key: string]: string | IPresentedAttributeBound | IPresentedAttributeBound[] };
// Verifiable encryption of any attributes
verifiableEncryptions?: { [key: string]: string | IPresentedAttributeVE | IPresentedAttributeVE[] };
// Predicates proved using Circom. Can be over any number of attributes
circomPredicates?: ICircomPredicate<ICircuitPrivateVar>[];
attributeInequalities?: { [key: string]: string | IPresentedAttributeInequality[] };
}
export interface IBoundedPseudonymCommitKey {
basesForAttributes: string[];
baseForSecretKey?: string;
}
export interface IPresentedBoundedPseudonym {
commitKey: IBoundedPseudonymCommitKey;
// key is credIdx, values are attribute names in the credential corresponding to the credIdx
attributes: { [key: number]: string[] };
}
export interface IUnboundedPseudonymCommitKey {
baseForSecretKey: string;
}
export interface IPresentedUnboundedPseudonym {
commitKey: IUnboundedPseudonymCommitKey;
}
// Pseudonym bounded to credential as well as blinded attributes. Used when requesting blinded credential.
export interface IPresentedBoundedPseudonymInBlindedCredReq {
commitKey: IBoundedPseudonymCommitKey;
// key is credIdx, values are attribute names in the credential corresponding to the credIdx
credentialAttributes: { [key: number]: string[] };
blindedAttributes: string[];
}
export interface IBlindCredentialRequest {
// Type of the signature requested, like BBS, BBS+
sigType: BlindSignatureType;
version: string;
// The schema of the whole (unblinded credential). This should include all attributes, i.e. blinded and unblinded
schema: CredentialSchema;
blindedAttributes: object;
// Commitment to the blinded attributes
commitment: Uint8Array;
attributeInequalities?: { [key: string]: string | IPresentedAttributeInequality[] };
// Bounds proved of any attribute(s)
bounds?: { [key: string]: string | IPresentedAttributeBound[] };
// Verifiable encryption of any blinded attributes
verifiableEncryptions?: { [key: string]: string | IPresentedAttributeVE[] };
// Predicates proved using Circom. Can be over any number of blinded attributes
circomPredicates?: ICircomPredicate<ICircuitPrivateVar>[];
// Equalities between the blinded attributes and credential attributes
blindedAttributeEqualities?: BlindedAttributeEquality[];
pseudonyms?: { [key: string]: IPresentedBoundedPseudonymInBlindedCredReq };
// Attributes user is telling the signer to add to the credential (should be part of schema)
unBlindedAttributes?: object;
}
/**
* Specifies what the presentation is proving like what credentials, what's being revealed, which attributes are being proven
* equal, bounds being enforced, etc
*/
export class PresentationSpecification {
// The credentials used in the presentation
credentials: IPresentedCredential[];
// The attributes being proved equal
attributeEqualities?: AttributeEquality[];
// key == pseudonym
boundedPseudonyms?: { [key: string]: IPresentedBoundedPseudonym };
// key == pseudonym
unboundedPseudonyms?: { [key: string]: IPresentedUnboundedPseudonym };
blindCredentialRequest?: IBlindCredentialRequest;
circomPredicatesMultiCred?: ICircomPredicate<ICircuitPrivateVarMultiCred>[];
constructor() {
this.credentials = [];
this.attributeEqualities = [];
this.boundedPseudonyms = {};
this.unboundedPseudonyms = {};
}
addPresentedCredential(
version: string,
schema: string,
revealedAttributes: object,
status?: IPresentedStatus,
bounds?: { [key: string]: string | IPresentedAttributeBound[] },
verifiableEncryptions?: { [key: string]: string | IPresentedAttributeVE[] },
circomPredicates?: ICircomPredicate<ICircuitPrivateVar>[],
sigType?: SignatureType,
attributeInequalities?: { [key: string]: string | IPresentedAttributeInequality[] }
) {
const ps = {
version,
schema,
revealedAttributes
};
if (status !== undefined) {
ps['status'] = status;
}
if (bounds !== undefined) {
ps['bounds'] = bounds;
}
if (verifiableEncryptions !== undefined) {
ps['verifiableEncryptions'] = verifiableEncryptions;
}
if (circomPredicates !== undefined) {
ps['circomPredicates'] = circomPredicates;
}
if (sigType !== undefined) {
ps['sigType'] = sigType;
}
if (attributeInequalities !== undefined) {
ps['attributeInequalities'] = attributeInequalities;
}
this.credentials.push(ps);
}
addAttributeEquality(eql: AttributeEquality) {
if (this.attributeEqualities === undefined) {
this.attributeEqualities = [];
}
this.attributeEqualities.push(eql);
}
getStatus(credIndex: number): IPresentedStatus | undefined {
if (credIndex >= this.credentials.length) {
throw new Error(`Invalid credential index ${credIndex}`);
}
return this.credentials[credIndex].status;
}
toJSON(): object {
const j = {
credentials: [],
attributeEqualities: this.attributeEqualities,
boundedPseudonyms: this.boundedPseudonyms,
unboundedPseudonyms: this.unboundedPseudonyms,
blindCredentialRequest: this.blindCredentialRequest,
circomPredicatesMultiCred: this.circomPredicatesMultiCred
};
for (const pc of this.credentials) {
const curJ = {
version: pc.version,
schema: pc.schema,
revealedAttributes: pc.revealedAttributes
};
if (pc.sigType !== undefined) {
curJ['sigType'] = pc.sigType;
}
if (pc.status !== undefined) {
curJ['status'] = { ...pc.status };
if (pc.status[TYPE_STR] === RevocationStatusProtocol.Vb22) {
curJ['status'].accumulated = b58.encode(pc.status.accumulated as Uint8Array);
}
if (pc.status[TYPE_STR] === RevocationStatusProtocol.KbUni24) {
curJ['status'].accumulated = b58.encode((pc.status.accumulated as KBUniversalAccumulatorValue).toBytes());
}
}
if (pc.attributeInequalities !== undefined) {
curJ['attributeInequalities'] = pc.attributeInequalities;
}
if (pc.bounds !== undefined) {
curJ['bounds'] = pc.bounds;
}
if (pc.verifiableEncryptions !== undefined) {
curJ['verifiableEncryptions'] = pc.verifiableEncryptions;
}
if (pc.circomPredicates !== undefined) {
curJ['circomPredicates'] = pc.circomPredicates;
}
// @ts-ignore
j.credentials.push(curJ);
}
return j;
}
}