From f044c46a8ff3253d4113c6bef54c9330f337e9e8 Mon Sep 17 00:00:00 2001 From: Oleksandr Brezhniev Date: Fri, 13 Aug 2021 17:57:58 +0300 Subject: [PATCH] Fixed existing circuit templates and unit tests. Added new ones for more granular checks of credentials. --- circuits/credential.circom | 256 ++++++++++++++++-- test/buildClaimBasicAboutId.test.ts | 2 +- test/buildClaimKeyBBJJ.test.ts | 6 +- .../credential_verifyClaimsTreeRoot.circom | 3 + .../credential_verifyCredentialMtp.circom | 3 + .../credential_verifyCredentialMtpHiHv.circom | 3 + ...edential_verifyCredentialNotRevoked.circom | 3 + .../credential_verifyCredentialSubject.circom | 3 + ...dential_verifyIdenStateMatchesRoots.circom | 3 + test/credential.test.ts | 2 +- test/credential_verifyFunctions.test.ts | 98 +++++++ test/idOwnership.test.ts | 2 +- test/idOwnershipGenesis.test.ts | 6 +- test/idState.test.ts | 10 +- test/poseidon.test.ts | 21 +- 15 files changed, 364 insertions(+), 57 deletions(-) create mode 100644 test/circuits/credential_verifyClaimsTreeRoot.circom create mode 100644 test/circuits/credential_verifyCredentialMtp.circom create mode 100644 test/circuits/credential_verifyCredentialMtpHiHv.circom create mode 100644 test/circuits/credential_verifyCredentialNotRevoked.circom create mode 100644 test/circuits/credential_verifyCredentialSubject.circom create mode 100644 test/circuits/credential_verifyIdenStateMatchesRoots.circom create mode 100644 test/credential_verifyFunctions.test.ts diff --git a/circuits/credential.circom b/circuits/credential.circom index 7eaa6d5e..5d07145d 100644 --- a/circuits/credential.circom +++ b/circuits/credential.circom @@ -84,20 +84,16 @@ template getClaimHiHv() { signal output hi; signal output hv; - component hashHi = Poseidon(6); + component hashHi = Poseidon(4); for (var i=0; i<4; i++) { hashHi.inputs[i] <== claim[0*4 + i]; } - hashHi.inputs[4] <== 0; - hashHi.inputs[5] <== 0; hi <== hashHi.out; - component hashHv = Poseidon(6); + component hashHv = Poseidon(4); for (var i=0; i<4; i++) { hashHv.inputs[i] <== claim[1*4 + i]; } - hashHv.inputs[4] <== 0; - hashHv.inputs[5] <== 0; hv <== hashHv.out; } @@ -110,13 +106,10 @@ template getIdenState() { signal output idenState; - component calcIdState = Poseidon(6); + component calcIdState = Poseidon(3); calcIdState.inputs[0] <== claimsTreeRoot; calcIdState.inputs[1] <== revTreeRoot; calcIdState.inputs[2] <== rootsTreeRoot; - for (var i=3; i<6; i++) { - calcIdState.inputs[i] <== 0; - } idenState <== calcIdState.out; } @@ -138,8 +131,17 @@ template getRevNonceNoVerHiHv() { } hi <== hashHi.out; + component hashHv = Poseidon(6); + hashHv.inputs[0] <== 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff; + for (var i=1; i<6; i++) { + hashHv.inputs[i] <== 0; + } + hv <== hashHv.out; + // hv = Poseidon([0xffff_ffff, 0, 0, 0, 0) - hv <== 17142353815121200339963760108352696118925531835836661574604762966243856573359; + //hv <== Poseidon([0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff, 0, 0, 0, 0, 0]) + //hv <== 17142353815121200339963760108352696118925531835836661574604762966243856573359; + //hv <== 8137207316649344643315856769015464323293372071975540252804619894838929375565; // new from go } // getRootHiHv calculates the hashes Hi and Hv of the leaf used in the roots @@ -157,36 +159,57 @@ template getRootHiHv() { } hi <== hashHi.out; - // hv = Poseidon([0, 0, 0, 0, 0) - hv <== 951383894958571821976060584138905353883650994872035011055912076785884444545; + component hashHv = Poseidon(6); + for (var i=0; i<6; i++) { + hashHv.inputs[i] <== 0; + } + hv <== hashHv.out; + + //hv <== Poseidon([0, 0, 0, 0, 0, 0]) + //hv <== 951383894958571821976060584138905353883650994872035011055912076785884444545; + //hv <== 14408838593220040598588012778523101864903887657864399481915450526643617223637; // new from go +} + +// getClaimSchema gets the schema of a claim +template getClaimSchema() { + signal input claim[8]; + + signal output schema; + + component i0Bits = Num2Bits(256); + i0Bits.in <== claim[0*4 + 0] + + component schemaNum = Bits2Num(64); + + for (var i=0; i<64; i++) { + schemaNum.in[i] <== i0Bits.out[i]; + } + schema <== schemaNum.out; } // proveCredentialOwnership proves ownership of an identity (found in `claim[1]`) which // is contained in a claim (`claim`) issued by an identity that has a recent // identity state (`isIdenState`), while proving that the claim has not been -// revoed as of the recent identity state. +// revoked as of the recent identity state. template proveCredentialOwnership(IdOwnershipLevels, IssuerLevels) { - var idOwnershipLevels = IdOwnershipLevels + 1; - var issuerLevels = IssuerLevels + 1; - // A signal input claim[8]; // B. holder proof of claimKOp in the genesis signal input hoKOpSk; - signal input hoClaimKOpMtp[idOwnershipLevels]; + signal input hoClaimKOpMtp[IdOwnershipLevels]; signal input hoClaimKOpClaimsTreeRoot; // signal input hoClaimKOpRevTreeRoot; // signal input hoClaimKOpRootsTreeRoot; // C. issuer proof of claim existence - signal input isProofExistMtp[issuerLevels]; + signal input isProofExistMtp[IssuerLevels]; signal input isProofExistClaimsTreeRoot; // signal input isProofExistRevTreeRoot; // signal input isProofExistRootsTreeRoot; // D. issuer proof of claim validity - signal input isProofValidNotRevMtp[issuerLevels]; + signal input isProofValidNotRevMtp[IssuerLevels]; signal input isProofValidNotRevMtpNoAux; signal input isProofValidNotRevMtpAuxHi; signal input isProofValidNotRevMtpAuxHv; @@ -195,7 +218,7 @@ template proveCredentialOwnership(IdOwnershipLevels, IssuerLevels) { signal input isProofValidRootsTreeRoot; // E. issuer proof of Root (ExistClaimsTreeRoot) - signal input isProofRootMtp[issuerLevels]; + signal input isProofRootMtp[IssuerLevels]; // F. issuer recent idenState signal input isIdenState; @@ -225,10 +248,10 @@ template proveCredentialOwnership(IdOwnershipLevels, IssuerLevels) { // // B. Prove ownership of the kOpSk associated with the holder identity // - component idOwnership = IdOwnershipGenesis(idOwnershipLevels); + component idOwnership = IdOwnershipGenesis(IdOwnershipLevels); idOwnership.id <== subjectOtherIden.id; idOwnership.userPrivateKey <== hoKOpSk; - for (var i=0; i { diff --git a/test/buildClaimKeyBBJJ.test.ts b/test/buildClaimKeyBBJJ.test.ts index a6377996..700727f4 100644 --- a/test/buildClaimKeyBBJJ.test.ts +++ b/test/buildClaimKeyBBJJ.test.ts @@ -14,14 +14,12 @@ describe("buildClaimKeyBBJJ test", function () { {reduceConstraints: false} ); - const ay = "20634138280259599560273310290025659992320584624461316485434108770067472477956"; - const witness = await circuit.calculateWitness({ ax: "17640206035128972995519606214765283372613874593503528180869261482403155458945", ay: "20634138280259599560273310290025659992320584624461316485434108770067472477956" }, true); await circuit.checkConstraints(witness); - await circuit.assertOut(witness, {hi: "13983541343321049801827232936939574644850750015280974697557168766727391751003"}); - await circuit.assertOut(witness, {hv: "951383894958571821976060584138905353883650994872035011055912076785884444545"}); + await circuit.assertOut(witness, {hi: "21194384538535854141301572543647862109415814559971895464714089489459043607338"}); + await circuit.assertOut(witness, {hv: "2351654555892372227640888372176282444150254868378439619268573230312091195718"}); }); }); diff --git a/test/circuits/credential_verifyClaimsTreeRoot.circom b/test/circuits/credential_verifyClaimsTreeRoot.circom new file mode 100644 index 00000000..ebf05f97 --- /dev/null +++ b/test/circuits/credential_verifyClaimsTreeRoot.circom @@ -0,0 +1,3 @@ +include "../../circuits/credential.circom"; + +component main = verifyClaimsTreeRoot(17); diff --git a/test/circuits/credential_verifyCredentialMtp.circom b/test/circuits/credential_verifyCredentialMtp.circom new file mode 100644 index 00000000..858a9031 --- /dev/null +++ b/test/circuits/credential_verifyCredentialMtp.circom @@ -0,0 +1,3 @@ +include "../../circuits/credential.circom"; + +component main = verifyCredentialMtp(17); diff --git a/test/circuits/credential_verifyCredentialMtpHiHv.circom b/test/circuits/credential_verifyCredentialMtpHiHv.circom new file mode 100644 index 00000000..bcb78846 --- /dev/null +++ b/test/circuits/credential_verifyCredentialMtpHiHv.circom @@ -0,0 +1,3 @@ +include "../../circuits/credential.circom"; + +component main = verifyCredentialMtpHiHv(4); diff --git a/test/circuits/credential_verifyCredentialNotRevoked.circom b/test/circuits/credential_verifyCredentialNotRevoked.circom new file mode 100644 index 00000000..54e4a27c --- /dev/null +++ b/test/circuits/credential_verifyCredentialNotRevoked.circom @@ -0,0 +1,3 @@ +include "../../circuits/credential.circom"; + +component main = verifyCredentialNotRevoked(17); diff --git a/test/circuits/credential_verifyCredentialSubject.circom b/test/circuits/credential_verifyCredentialSubject.circom new file mode 100644 index 00000000..02b7be1c --- /dev/null +++ b/test/circuits/credential_verifyCredentialSubject.circom @@ -0,0 +1,3 @@ +include "../../circuits/credential.circom"; + +component main = verifyCredentialSubject(); diff --git a/test/circuits/credential_verifyIdenStateMatchesRoots.circom b/test/circuits/credential_verifyIdenStateMatchesRoots.circom new file mode 100644 index 00000000..e4f1c4f5 --- /dev/null +++ b/test/circuits/credential_verifyIdenStateMatchesRoots.circom @@ -0,0 +1,3 @@ +include "../../circuits/credential.circom"; + +component main = verifyIdenStateMatchesRoots(); diff --git a/test/credential.test.ts b/test/credential.test.ts index 97c7f14b..6f82279d 100644 --- a/test/credential.test.ts +++ b/test/credential.test.ts @@ -136,7 +136,7 @@ const inputs2JSON = ` } `; -describe("credential test", function () { +describe("credential test (old)", function () { this.timeout(200000); it("Test Credential", async () => { diff --git a/test/credential_verifyFunctions.test.ts b/test/credential_verifyFunctions.test.ts new file mode 100644 index 00000000..5e5956ee --- /dev/null +++ b/test/credential_verifyFunctions.test.ts @@ -0,0 +1,98 @@ +const path = require("path"); +const tester = require("circom").tester; +const circomlib = require("circomlib"); +const chai = require("chai"); +const assert = chai.assert; + +export {}; + +const verifyCredentialSubject = { + claim: [ + "21024475908144731912815848438102736712390369823686656", + "197990912273762023075897629417744831667514652778362723486029975898079821824", + "0", + "0", + "1330878123", + "0", + "0", + "0", + ], + id: "197990912273762023075897629417744831667514652778362723486029975898079821824", // 117twYCgGzxHUtMsAfjM3muCrypTXcu6oc7cSsuGHM +} + +describe("credential verifyCredentialSubject test", function () { + this.timeout(200000); + it("Test credential verifyCredentialSubject", async () => { + const circuit = await tester( + path.join(__dirname, "circuits", "credential_verifyCredentialSubject.circom"), + {reduceConstraints: false}, + ); + + const witness = await circuit.calculateWitness(verifyCredentialSubject, true); + await circuit.checkConstraints(witness); + }); +}); + +const verifyCredentialMtp = { + "claim": [ + "20654715993900013474510316175425517108417418890313728", + "40727245799613559019751726539717406914187024287975587258911930442547331072", + "0", + "0", + "3422259402", + "0", + "0", + "0" + ], + "isProofExistMtp": [ + "8642944718030808750631174116590545595346699877855966554837410767850901050241", + "0", + "2559121857990624749645748723611740625389471552768523819941100032832108291070", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0" + ], + "isProofExistClaimsTreeRoot": "8983046041355403090199265671506633595311694354613197795337389712944858482798" +} + +describe("credential verifyCredentialMtp test", function () { + this.timeout(200000); + it("Test credential verifyCredentialMtp", async () => { + const circuit = await tester( + path.join(__dirname, "circuits", "credential_verifyCredentialMtp.circom"), + //{reduceConstraints: false}, + ); + + const witness = await circuit.calculateWitness(verifyCredentialMtp, true); + await circuit.checkConstraints(witness); + }); +}); + +describe("credential verifyIdenStateMatchesRoots test", function () { + this.timeout(200000); + it("Test credential verifyIdenStateMatchesRoots", async () => { + const circuit = await tester( + path.join(__dirname, "circuits", "credential_verifyIdenStateMatchesRoots.circom"), + //{reduceConstraints: false}, + ); + + const witness = await circuit.calculateWitness({ + "isProofValidClaimsTreeRoot": "5390978791160263927985161830452830346003784422812143177724675599288112176057", + "isProofValidRevTreeRoot": "0", + "isProofValidRootsTreeRoot": "0", + "isIdenState": "17685575544241839934776615609352503109564813484662571173826983469932580732343" + }, true); + await circuit.checkConstraints(witness); + }); +}); diff --git a/test/idOwnership.test.ts b/test/idOwnership.test.ts index 9587301c..62c4ec77 100644 --- a/test/idOwnership.test.ts +++ b/test/idOwnership.test.ts @@ -5,7 +5,7 @@ const assert = chai.assert; export {}; -describe("idOwnership test", function () { +describe("idOwnership test (asserted values need to be fixed)", function () { this.timeout(200000); diff --git a/test/idOwnershipGenesis.test.ts b/test/idOwnershipGenesis.test.ts index f3747c91..438c630f 100644 --- a/test/idOwnershipGenesis.test.ts +++ b/test/idOwnershipGenesis.test.ts @@ -19,10 +19,10 @@ describe("idOwnershipGenesis test", function () { // input data generated with circuits/test/testvectorsgen/idState_test.go, which uses go-iden3-core const witness = await circuit.calculateWitness({ - id: "418819843184716391854950027336187830212226236089582432322628806588929540096", - userPrivateKey: "6190793965647866647574058687473278714480561351424348391693421151024369116465", + id: "436488163496163801239772944702740493390396197235644466912178158704332374016", + userPrivateKey: "4957679760459508851420863521780560830598415356609971490286236508349735930306", siblings: ["0", "0", "0", "0"], - claimsTreeRoot: "19759495200350784025545259483378281480848861021788190330947710448581962628389", + claimsTreeRoot: "1729006260119089712818713806538777619892421181772209370118162803020343827555", }); await circuit.checkConstraints(witness); }); diff --git a/test/idState.test.ts b/test/idState.test.ts index 30d60d92..c8c65db6 100644 --- a/test/idState.test.ts +++ b/test/idState.test.ts @@ -15,16 +15,14 @@ describe("idState test", function () { {reduceConstraints: false} ); - const privKStr = "6190793965647866647574058687473278714480561351424348391693421151024369116465"; - // input data generated with circuits/test/testvectorsgen/idState_test.go, which uses go-iden3-core const witness = await circuit.calculateWitness({ - id: "418819843184716391854950027336187830212226236089582432322628806588929540096", + id: "436488163496163801239772944702740493390396197235644466912178158704332374016", oldIdState: "0", - userPrivateKey: "6190793965647866647574058687473278714480561351424348391693421151024369116465", + userPrivateKey: "4957679760459508851420863521780560830598415356609971490286236508349735930306", siblings: ["0", "0", "0", "0"], - claimsTreeRoot: "19759495200350784025545259483378281480848861021788190330947710448581962628389", - newIdState: "418819843184716391854950027336187830212226236089582432322628806588929540096" + claimsTreeRoot: "1729006260119089712818713806538777619892421181772209370118162803020343827555", + newIdState: "436488163496163801239772944702740493390396197235644466912178158704332374016" }); await circuit.checkConstraints(witness); // await circuit.assertOut(witness, {out0: "0"}); diff --git a/test/poseidon.test.ts b/test/poseidon.test.ts index ce574682..6602a7da 100644 --- a/test/poseidon.test.ts +++ b/test/poseidon.test.ts @@ -11,9 +11,7 @@ export {}; describe("poseidon test", function () { this.timeout(200000); - const levels : number = 3; - - it("Test poseidon compatibility with go-iden3-crypto/poseidon", async () => { + it("Test poseidon compatibility with circomlib/poseidon", async () => { const circuit = await tester( path.join(__dirname, "circuits", "poseidon.circom"), { reduceConstraints: false } @@ -23,35 +21,34 @@ describe("poseidon test", function () { in: ["0", "0", "0"] }); await circuit.checkConstraints(witness); - await circuit.assertOut(witness, {out: "951383894958571821976060584138905353883650994872035011055912076785884444545"}); + await circuit.assertOut(witness, {out: "5317387130258456662214331362918410991734007599705406860481038345552731150762"}); witness = await circuit.calculateWitness({ in: ["1", "0", "0"] }); await circuit.checkConstraints(witness); - await circuit.assertOut(witness, {out: "2279272124503809695177170942549831206840003426178943720957919922723804431629"}); + await circuit.assertOut(witness, {out: "16319005924338521988144249782199320915969277491928916027259324394544057385749"}); // check circomlib javascript poseidon output - const jsPoseidon = circomlib.poseidon.createHash(6, 8, 57); - let jsOut = jsPoseidon([1, 0, 0]).toString(); - assert.equal(jsOut, "2279272124503809695177170942549831206840003426178943720957919922723804431629", "not equal"); + let jsOut = circomlib.poseidon([1, 0, 0]).toString(); + assert.equal(jsOut, "16319005924338521988144249782199320915969277491928916027259324394544057385749", "not equal"); witness = await circuit.calculateWitness({ in: ["2", "0", "0"] }); await circuit.checkConstraints(witness); - await circuit.assertOut(witness, {out: "13132721937331725951616278520078927153934890115891049388516726302689567578587"}); + await circuit.assertOut(witness, {out: "13234400070188801104792523922697988244748411503422448631147834118387475842488"}); const testValues = ["72057594037927936", "1", "20634138280259599560273310290025659992320584624461316485434108770067472477956"]; witness = await circuit.calculateWitness({ in: testValues }); await circuit.checkConstraints(witness); - await circuit.assertOut(witness, {out: "10395143007367284783361235630029585391855532481545192724789751124286001219030"}); + await circuit.assertOut(witness, {out: "3135714887432857880402997813814046724922969450336546007917491784497158924950"}); // check circomlib javascript poseidon output - jsOut = jsPoseidon(testValues).toString(); - assert.equal(jsOut, "10395143007367284783361235630029585391855532481545192724789751124286001219030", "not equal"); + jsOut = circomlib.poseidon(testValues).toString(); + assert.equal(jsOut, "3135714887432857880402997813814046724922969450336546007917491784497158924950", "not equal"); }); });