Skip to content

Commit f044c46

Browse files
committed
Fixed existing circuit templates and unit tests. Added new ones for more granular checks of credentials.
1 parent 98d0ac5 commit f044c46

15 files changed

+364
-57
lines changed

circuits/credential.circom

Lines changed: 227 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -84,20 +84,16 @@ template getClaimHiHv() {
8484
signal output hi;
8585
signal output hv;
8686

87-
component hashHi = Poseidon(6);
87+
component hashHi = Poseidon(4);
8888
for (var i=0; i<4; i++) {
8989
hashHi.inputs[i] <== claim[0*4 + i];
9090
}
91-
hashHi.inputs[4] <== 0;
92-
hashHi.inputs[5] <== 0;
9391
hi <== hashHi.out;
9492

95-
component hashHv = Poseidon(6);
93+
component hashHv = Poseidon(4);
9694
for (var i=0; i<4; i++) {
9795
hashHv.inputs[i] <== claim[1*4 + i];
9896
}
99-
hashHv.inputs[4] <== 0;
100-
hashHv.inputs[5] <== 0;
10197
hv <== hashHv.out;
10298
}
10399

@@ -110,13 +106,10 @@ template getIdenState() {
110106

111107
signal output idenState;
112108

113-
component calcIdState = Poseidon(6);
109+
component calcIdState = Poseidon(3);
114110
calcIdState.inputs[0] <== claimsTreeRoot;
115111
calcIdState.inputs[1] <== revTreeRoot;
116112
calcIdState.inputs[2] <== rootsTreeRoot;
117-
for (var i=3; i<6; i++) {
118-
calcIdState.inputs[i] <== 0;
119-
}
120113

121114
idenState <== calcIdState.out;
122115
}
@@ -138,8 +131,17 @@ template getRevNonceNoVerHiHv() {
138131
}
139132
hi <== hashHi.out;
140133

134+
component hashHv = Poseidon(6);
135+
hashHv.inputs[0] <== 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff;
136+
for (var i=1; i<6; i++) {
137+
hashHv.inputs[i] <== 0;
138+
}
139+
hv <== hashHv.out;
140+
141141
// hv = Poseidon([0xffff_ffff, 0, 0, 0, 0)
142-
hv <== 17142353815121200339963760108352696118925531835836661574604762966243856573359;
142+
//hv <== Poseidon([0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff, 0, 0, 0, 0, 0])
143+
//hv <== 17142353815121200339963760108352696118925531835836661574604762966243856573359;
144+
//hv <== 8137207316649344643315856769015464323293372071975540252804619894838929375565; // new from go
143145
}
144146

145147
// getRootHiHv calculates the hashes Hi and Hv of the leaf used in the roots
@@ -157,36 +159,57 @@ template getRootHiHv() {
157159
}
158160
hi <== hashHi.out;
159161

160-
// hv = Poseidon([0, 0, 0, 0, 0)
161-
hv <== 951383894958571821976060584138905353883650994872035011055912076785884444545;
162+
component hashHv = Poseidon(6);
163+
for (var i=0; i<6; i++) {
164+
hashHv.inputs[i] <== 0;
165+
}
166+
hv <== hashHv.out;
167+
168+
//hv <== Poseidon([0, 0, 0, 0, 0, 0])
169+
//hv <== 951383894958571821976060584138905353883650994872035011055912076785884444545;
170+
//hv <== 14408838593220040598588012778523101864903887657864399481915450526643617223637; // new from go
171+
}
172+
173+
// getClaimSchema gets the schema of a claim
174+
template getClaimSchema() {
175+
signal input claim[8];
176+
177+
signal output schema;
178+
179+
component i0Bits = Num2Bits(256);
180+
i0Bits.in <== claim[0*4 + 0]
181+
182+
component schemaNum = Bits2Num(64);
183+
184+
for (var i=0; i<64; i++) {
185+
schemaNum.in[i] <== i0Bits.out[i];
186+
}
187+
schema <== schemaNum.out;
162188
}
163189

164190
// proveCredentialOwnership proves ownership of an identity (found in `claim[1]`) which
165191
// is contained in a claim (`claim`) issued by an identity that has a recent
166192
// identity state (`isIdenState`), while proving that the claim has not been
167-
// revoed as of the recent identity state.
193+
// revoked as of the recent identity state.
168194
template proveCredentialOwnership(IdOwnershipLevels, IssuerLevels) {
169-
var idOwnershipLevels = IdOwnershipLevels + 1;
170-
var issuerLevels = IssuerLevels + 1;
171-
172195
// A
173196
signal input claim[8];
174197

175198
// B. holder proof of claimKOp in the genesis
176199
signal input hoKOpSk;
177-
signal input hoClaimKOpMtp[idOwnershipLevels];
200+
signal input hoClaimKOpMtp[IdOwnershipLevels];
178201
signal input hoClaimKOpClaimsTreeRoot;
179202
// signal input hoClaimKOpRevTreeRoot;
180203
// signal input hoClaimKOpRootsTreeRoot;
181204

182205
// C. issuer proof of claim existence
183-
signal input isProofExistMtp[issuerLevels];
206+
signal input isProofExistMtp[IssuerLevels];
184207
signal input isProofExistClaimsTreeRoot;
185208
// signal input isProofExistRevTreeRoot;
186209
// signal input isProofExistRootsTreeRoot;
187210

188211
// D. issuer proof of claim validity
189-
signal input isProofValidNotRevMtp[issuerLevels];
212+
signal input isProofValidNotRevMtp[IssuerLevels];
190213
signal input isProofValidNotRevMtpNoAux;
191214
signal input isProofValidNotRevMtpAuxHi;
192215
signal input isProofValidNotRevMtpAuxHv;
@@ -195,7 +218,7 @@ template proveCredentialOwnership(IdOwnershipLevels, IssuerLevels) {
195218
signal input isProofValidRootsTreeRoot;
196219

197220
// E. issuer proof of Root (ExistClaimsTreeRoot)
198-
signal input isProofRootMtp[issuerLevels];
221+
signal input isProofRootMtp[IssuerLevels];
199222

200223
// F. issuer recent idenState
201224
signal input isIdenState;
@@ -225,22 +248,22 @@ template proveCredentialOwnership(IdOwnershipLevels, IssuerLevels) {
225248
//
226249
// B. Prove ownership of the kOpSk associated with the holder identity
227250
//
228-
component idOwnership = IdOwnershipGenesis(idOwnershipLevels);
251+
component idOwnership = IdOwnershipGenesis(IdOwnershipLevels);
229252
idOwnership.id <== subjectOtherIden.id;
230253
idOwnership.userPrivateKey <== hoKOpSk;
231-
for (var i=0; i<idOwnershipLevels; i++) { idOwnership.siblings[i] <== hoClaimKOpMtp[i]; }
254+
for (var i=0; i<IdOwnershipLevels; i++) { idOwnership.siblings[i] <== hoClaimKOpMtp[i]; }
232255
idOwnership.claimsTreeRoot <== hoClaimKOpClaimsTreeRoot;
233256
// idOwnership.revTreeRoot <== hoClaimKOpRevTreeRoot;
234257
// idOwnership.rootsTreeRoot <== hoClaimKOpRootsTreeRoot;
235258

236259
//
237260
// C. Claim proof of existence (isProofExist)
238261
//
239-
component smtClaimExists = SMTVerifier(issuerLevels);
262+
component smtClaimExists = SMTVerifier(IssuerLevels);
240263
smtClaimExists.enabled <== 1;
241264
smtClaimExists.fnc <== 0; // Inclusion
242265
smtClaimExists.root <== isProofExistClaimsTreeRoot;
243-
for (var i=0; i<issuerLevels; i++) { smtClaimExists.siblings[i] <== isProofExistMtp[i]; }
266+
for (var i=0; i<IssuerLevels; i++) { smtClaimExists.siblings[i] <== isProofExistMtp[i]; }
244267
smtClaimExists.oldKey <== 0;
245268
smtClaimExists.oldValue <== 0;
246269
smtClaimExists.isOld0 <== 0;
@@ -259,34 +282,209 @@ template proveCredentialOwnership(IdOwnershipLevels, IssuerLevels) {
259282
component revNonceHiHv = getRevNonceNoVerHiHv();
260283
revNonceHiHv.revNonce <== claimRevNonce.revNonce;
261284

262-
component smtClaimValid = SMTVerifier(issuerLevels);
285+
component smtClaimValid = SMTVerifier(IssuerLevels);
286+
smtClaimValid.enabled <== 1;
287+
smtClaimValid.fnc <== 1; // Non-inclusion
288+
smtClaimValid.root <== isProofValidRevTreeRoot;
289+
for (var i=0; i<IssuerLevels; i++) { smtClaimValid.siblings[i] <== isProofValidNotRevMtp[i]; }
290+
smtClaimValid.oldKey <== isProofValidNotRevMtpAuxHi;
291+
smtClaimValid.oldValue <== isProofValidNotRevMtpAuxHv;
292+
smtClaimValid.isOld0 <== isProofValidNotRevMtpNoAux;
293+
smtClaimValid.key <== revNonceHiHv.hi;
294+
smtClaimValid.value <== 0;
295+
296+
297+
//
298+
// E. Claim proof of root
299+
//
300+
component rootHiHv = getRootHiHv();
301+
rootHiHv.root <== isProofExistClaimsTreeRoot;
302+
303+
component smtRootValid = SMTVerifier(IssuerLevels);
304+
smtRootValid.enabled <== 1;
305+
smtRootValid.fnc <== 0; // Inclusion
306+
smtRootValid.root <== isProofValidRootsTreeRoot;
307+
for (var i=0; i<IssuerLevels; i++) { smtRootValid.siblings[i] <== isProofRootMtp[i]; }
308+
smtRootValid.oldKey <== 0;
309+
smtRootValid.oldValue <== 0;
310+
smtRootValid.isOld0 <== 0;
311+
smtRootValid.key <== rootHiHv.hi;
312+
smtRootValid.value <== rootHiHv.hv;
313+
314+
//
315+
// F. Verify ValidIdenState == isIdenState
316+
//
317+
component isProofValidIdenState = getIdenState();
318+
isProofValidIdenState.claimsTreeRoot <== isProofValidClaimsTreeRoot;
319+
isProofValidIdenState.revTreeRoot <== isProofValidRevTreeRoot;
320+
isProofValidIdenState.rootsTreeRoot <== isProofValidRootsTreeRoot;
321+
// out: isProofValidIdenState.idenState
322+
323+
isProofValidIdenState.idenState === isIdenState;
324+
}
325+
326+
327+
328+
329+
330+
331+
// verifyCredentialSubject verifies that claim is issued to a specified identity
332+
template verifyCredentialSubject() {
333+
signal input claim[8];
334+
signal input id;
335+
336+
//
337+
// A. Prove that the claim has subject OtherIden, and take the subject identity.
338+
//
339+
component header = getClaimHeader();
340+
for (var i=0; i<8; i++) { header.claim[i] <== claim[i]; }
341+
// out: header.claimType
342+
// out: header.claimFlags[32]
343+
344+
// TODO: add reading SubjectPos from claim (0 = index, 1 = value) and providing it to the following component
345+
component subjectOtherIden = getClaimSubjectOtherIden(0);
346+
for (var i=0; i<8; i++) { subjectOtherIden.claim[i] <== claim[i]; }
347+
for (var i=0; i<32; i++) { subjectOtherIden.claimFlags[i] <== header.claimFlags[i]; }
348+
// out: subjectOtherIden.id
349+
350+
subjectOtherIden.id === id;
351+
}
352+
353+
// verifyCredentialSchema verifies that claim matches provided schema
354+
template verifyCredentialSchema() {
355+
signal input claim[8];
356+
signal input schema;
357+
358+
component claimSchema = getClaimHeader();
359+
360+
isProofValidIdenState.idenState === isIdenState;
361+
}
362+
363+
// verifyCredentialNotRevoked verifies that claim is not included into the revocation tree
364+
// TODO: how do we get all of these params and why do we need them at all?
365+
template verifyCredentialNotRevoked(IssuerLevels) {
366+
signal input claim[8];
367+
368+
// D. issuer proof of claim validity
369+
signal input isProofValidNotRevMtp[IssuerLevels];
370+
signal input isProofValidNotRevMtpNoAux;
371+
signal input isProofValidNotRevMtpAuxHi;
372+
signal input isProofValidNotRevMtpAuxHv;
373+
signal input isProofValidRevTreeRoot;
374+
375+
376+
component claimRevNonce = getClaimRevNonce();
377+
for (var i=0; i<8; i++) { claimRevNonce.claim[i] <== claim[i]; }
378+
// out: claimRevNonce.revNonce
379+
380+
//
381+
// D. Claim proof of non revocation (validity)
382+
//
383+
component revNonceHiHv = getRevNonceNoVerHiHv();
384+
revNonceHiHv.revNonce <== claimRevNonce.revNonce;
385+
386+
component smtClaimValid = SMTVerifier(IssuerLevels);
263387
smtClaimValid.enabled <== 1;
264388
smtClaimValid.fnc <== 1; // Non-inclusion
265389
smtClaimValid.root <== isProofValidRevTreeRoot;
266-
for (var i=0; i<issuerLevels; i++) { smtClaimValid.siblings[i] <== isProofValidNotRevMtp[i]; }
390+
for (var i=0; i<IssuerLevels; i++) { smtClaimValid.siblings[i] <== isProofValidNotRevMtp[i]; }
267391
smtClaimValid.oldKey <== isProofValidNotRevMtpAuxHi;
268392
smtClaimValid.oldValue <== isProofValidNotRevMtpAuxHv;
269393
smtClaimValid.isOld0 <== isProofValidNotRevMtpNoAux;
270394
smtClaimValid.key <== revNonceHiHv.hi;
271395
smtClaimValid.value <== 0;
396+
}
397+
398+
// verifyCredentialMtp verifies that claim is issued by the issuer and included into the claim tree root
399+
template verifyCredentialMtp(IssuerLevels) {
400+
signal input claim[8];
401+
402+
// C. issuer proof of claim existence
403+
// TODO: rename signals
404+
signal input isProofExistMtp[IssuerLevels]; // issuerClaimMtp
405+
signal input isProofExistClaimsTreeRoot; // issuerClaimTreeRoot
406+
// signal input isProofExistRevTreeRoot; // issuerRevTreeRoot
407+
// signal input isProofExistRootsTreeRoot; // issuerRootsTreeRoot
408+
409+
component claimHiHv = getClaimHiHv();
410+
for (var i=0; i<8; i++) { claimHiHv.claim[i] <== claim[i]; }
411+
// out: claimHiHv.hi
412+
// out: claimHiHv.hv
413+
414+
//
415+
// C. Claim proof of existence (isProofExist)
416+
//
417+
component smtClaimExists = SMTVerifier(IssuerLevels);
418+
smtClaimExists.enabled <== 1;
419+
smtClaimExists.fnc <== 0; // Inclusion
420+
smtClaimExists.root <== isProofExistClaimsTreeRoot;
421+
for (var i=0; i<IssuerLevels; i++) { smtClaimExists.siblings[i] <== isProofExistMtp[i]; }
422+
smtClaimExists.oldKey <== 0;
423+
smtClaimExists.oldValue <== 0;
424+
smtClaimExists.isOld0 <== 0;
425+
smtClaimExists.key <== claimHiHv.hi;
426+
smtClaimExists.value <== claimHiHv.hv;
427+
}
428+
429+
// verifyCredentialMtp verifies that claim is issued by the issuer and included into the claim tree root
430+
template verifyCredentialMtpHiHv(IssuerLevels) {
431+
signal input hi;
432+
signal input hv;
433+
434+
signal input isProofExistMtp[IssuerLevels]; // issuerClaimMtp
435+
signal input isProofExistClaimsTreeRoot; // issuerClaimTreeRoot
436+
// signal input isProofExistRevTreeRoot; // issuerRevTreeRoot
437+
// signal input isProofExistRootsTreeRoot; // issuerRootsTreeRoot
272438

439+
component smtClaimExists = SMTVerifier(IssuerLevels);
440+
smtClaimExists.enabled <== 1;
441+
smtClaimExists.fnc <== 0; // Inclusion
442+
smtClaimExists.root <== isProofExistClaimsTreeRoot;
443+
for (var i=0; i<IssuerLevels; i++) { smtClaimExists.siblings[i] <== isProofExistMtp[i]; }
444+
smtClaimExists.oldKey <== 0;
445+
smtClaimExists.oldValue <== 0;
446+
smtClaimExists.isOld0 <== 0;
447+
smtClaimExists.key <== hi;
448+
smtClaimExists.value <== hv;
449+
}
450+
451+
// verifyClaimsTreeRoot verifies that claim is issued by the issuer and included into the claim tree root
452+
// TODO: what is this check doing? Is it checking inclusion of claim tree root to the roots tree for indirect identities?
453+
// TODO: Or it should be included to the roots tree for direct identities too?
454+
template verifyClaimsTreeRoot(IssuerLevels) {
455+
signal input isProofExistClaimsTreeRoot; // issuerClaimTreeRoot
456+
signal input isProofValidRootsTreeRoot;
457+
458+
// E. issuer proof of Root (ExistClaimsTreeRoot)
459+
signal input isProofRootMtp[IssuerLevels];
273460

274461
//
275462
// E. Claim proof of root
276463
//
277464
component rootHiHv = getRootHiHv();
278465
rootHiHv.root <== isProofExistClaimsTreeRoot;
279466

280-
component smtRootValid = SMTVerifier(issuerLevels);
467+
component smtRootValid = SMTVerifier(IssuerLevels);
281468
smtRootValid.enabled <== 1;
282469
smtRootValid.fnc <== 0; // Inclusion
283470
smtRootValid.root <== isProofValidRootsTreeRoot;
284-
for (var i=0; i<issuerLevels; i++) { smtRootValid.siblings[i] <== isProofRootMtp[i]; }
471+
for (var i=0; i<IssuerLevels; i++) { smtRootValid.siblings[i] <== isProofRootMtp[i]; }
285472
smtRootValid.oldKey <== 0;
286473
smtRootValid.oldValue <== 0;
287474
smtRootValid.isOld0 <== 0;
288475
smtRootValid.key <== rootHiHv.hi;
289476
smtRootValid.value <== rootHiHv.hv;
477+
}
478+
479+
// verifyCredentialExistence verifies that claim is issued by the issuer
480+
// is contained in a claim (`claim`) issued by an identity that has a recent
481+
// identity state (`isIdenState`), while proving that the claim has not been
482+
// revoked as of the recent identity state.
483+
template verifyIdenStateMatchesRoots() {
484+
signal input isProofValidClaimsTreeRoot;
485+
signal input isProofValidRevTreeRoot;
486+
signal input isProofValidRootsTreeRoot;
487+
signal input isIdenState;
290488

291489
//
292490
// F. Verify ValidIdenState == isIdenState

test/buildClaimBasicAboutId.test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ const assert = chai.assert;
77

88
export {};
99

10-
describe("buildClaimBasicAboutId test", function () {
10+
describe("buildClaimBasicAboutId test (old)", function () {
1111
this.timeout(200000);
1212

1313
it("Test BuildClaimBasicAboutId", async () => {

test/buildClaimKeyBBJJ.test.ts

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,14 +14,12 @@ describe("buildClaimKeyBBJJ test", function () {
1414
{reduceConstraints: false}
1515
);
1616

17-
const ay = "20634138280259599560273310290025659992320584624461316485434108770067472477956";
18-
1917
const witness = await circuit.calculateWitness({
2018
ax: "17640206035128972995519606214765283372613874593503528180869261482403155458945",
2119
ay: "20634138280259599560273310290025659992320584624461316485434108770067472477956"
2220
}, true);
2321
await circuit.checkConstraints(witness);
24-
await circuit.assertOut(witness, {hi: "13983541343321049801827232936939574644850750015280974697557168766727391751003"});
25-
await circuit.assertOut(witness, {hv: "951383894958571821976060584138905353883650994872035011055912076785884444545"});
22+
await circuit.assertOut(witness, {hi: "21194384538535854141301572543647862109415814559971895464714089489459043607338"});
23+
await circuit.assertOut(witness, {hv: "2351654555892372227640888372176282444150254868378439619268573230312091195718"});
2624
});
2725
});

0 commit comments

Comments
 (0)