From 41c4451a6a95b5a048da425ef5a5b45543264f09 Mon Sep 17 00:00:00 2001 From: Oleksandr Brezhniev Date: Fri, 23 Feb 2024 17:39:10 +0000 Subject: [PATCH 1/2] Add ValueCommitment modifier operator --- circuits/lib/linked/linkId.circom | 5 ++-- circuits/lib/query/modifiers.circom | 4 ++- .../query/processQueryWithModifiers.circom | 8 +++++- circuits/lib/query/query.circom | 1 + circuits/lib/query/valueCommitment.circom | 27 +++++++++++++++++++ circuits/linked/multiQuery.circom | 4 ++- .../credentialAtomicQueryV3OffChain.circom | 2 ++ .../credentialAtomicQueryV3OnChain.circom | 2 ++ 8 files changed, 48 insertions(+), 5 deletions(-) create mode 100644 circuits/lib/query/valueCommitment.circom diff --git a/circuits/lib/linked/linkId.circom b/circuits/lib/linked/linkId.circom index 03f961f7..c72d486f 100644 --- a/circuits/lib/linked/linkId.circom +++ b/circuits/lib/linked/linkId.circom @@ -1,11 +1,12 @@ pragma circom 2.1.5; -include "../../../node_modules/circomlib/circuits/poseidon.circom"; include "../../../node_modules/circomlib/circuits/comparators.circom"; +include "../../../node_modules/circomlib/circuits/mux1.circom"; +include "../../../node_modules/circomlib/circuits/poseidon.circom"; template LinkID() { signal input claimHash; - signal input linkNonce; + signal input linkNonce; // private random nonce to make the commitment unique and secure signal output out; diff --git a/circuits/lib/query/modifiers.circom b/circuits/lib/query/modifiers.circom index b9fa8347..fb931327 100644 --- a/circuits/lib/query/modifiers.circom +++ b/circuits/lib/query/modifiers.circom @@ -7,6 +7,7 @@ include "../../../node_modules/circomlib/circuits/mux4.circom"; /* Modifier/computation operators: 16 - selective disclosure (16 = 10000 binary) + 17 - value commitment (17 = 10001 binary) */ // modifierValidatorOutputSelector validates modifier operation and selects output value @@ -24,7 +25,8 @@ template modifierValidatorOutputSelector() { modifierOpValid.s <== [opBits[0], opBits[1], opBits[2], opBits[3]]; modifierOpValid.c <== [ 1, // valid operator: 16 - selective disclosure (16-16 = index 0) - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + 1, // valid operator: 17 - value commitment (17-1 = index 1) + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ]; ForceEqualIfEnabled()( diff --git a/circuits/lib/query/processQueryWithModifiers.circom b/circuits/lib/query/processQueryWithModifiers.circom index 769aa1da..174090ca 100644 --- a/circuits/lib/query/processQueryWithModifiers.circom +++ b/circuits/lib/query/processQueryWithModifiers.circom @@ -3,6 +3,7 @@ pragma circom 2.1.1; include "../../../node_modules/circomlib/circuits/comparators.circom"; include "query.circom"; include "modifiers.circom"; +include "valueCommitment.circom"; include "../utils/claimUtils.circom"; include "../utils/arraySizeValidator.circom"; @@ -18,6 +19,7 @@ template ProcessQueryWithModifiers(claimLevels, maxValueArraySize){ signal input operator; signal input value[maxValueArraySize]; signal input valueArraySize; + signal input commitNonce; signal input issuerClaim[8]; signal input merklized; @@ -101,6 +103,9 @@ template ProcessQueryWithModifiers(claimLevels, maxValueArraySize){ // selective disclosure // no need to calc anything, fieldValue is just passed as an output + // value commitment + signal valueCommitment <== ValueCommitment()(fieldValue, commitNonce); + ///////////////////////////////////////////////////////////////// // Modifier Operator Validation & Output Preparation ///////////////////////////////////////////////////////////////// @@ -110,7 +115,8 @@ template ProcessQueryWithModifiers(claimLevels, maxValueArraySize){ operator <== operator, modifierOutputs <== [ fieldValue, // 16 - selective disclosure (16-16 = index 0) - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 // 17-31 - not used + valueCommitment, // 17 - value commitment (17-16 = index 1) + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 // 18-31 - not used ] ); } \ No newline at end of file diff --git a/circuits/lib/query/query.circom b/circuits/lib/query/query.circom index 0cb2e59c..29e3fd52 100644 --- a/circuits/lib/query/query.circom +++ b/circuits/lib/query/query.circom @@ -23,6 +23,7 @@ include "comparators.circom"; 11 - exist Modifier/computation operators: 16 - selective disclosure (16 = 10000 binary) + 17 - value commitment (17 = 10001 binary) */ // Query template works only with Query operators (0-15), for the rest returns 0 diff --git a/circuits/lib/query/valueCommitment.circom b/circuits/lib/query/valueCommitment.circom new file mode 100644 index 00000000..da5a0aff --- /dev/null +++ b/circuits/lib/query/valueCommitment.circom @@ -0,0 +1,27 @@ +pragma circom 2.1.1; + +include "../../../node_modules/circomlib/circuits/mux1.circom"; +include "../../../node_modules/circomlib/circuits/comparators.circom"; +include "../../../node_modules/circomlib/circuits/poseidon.circom"; + +/** +Value commitment circuit allows to commit to a specific value and then +reveal it later or use such a commitment in another circuits to prove that +multiple circuits work with the same value without revealing it. +*/ + +template ValueCommitment() { + signal input value; + signal input commitNonce; // private random nonce to make the commitment unique and secure + + signal output out; + + signal isNonceZero <== IsZero()(commitNonce); + + signal commit <== Poseidon(2)([value, commitNonce]); + + out <== Mux1()( + [commit, 0], + isNonceZero + ); +} diff --git a/circuits/linked/multiQuery.circom b/circuits/linked/multiQuery.circom index c38b6f7b..88bf2859 100644 --- a/circuits/linked/multiQuery.circom +++ b/circuits/linked/multiQuery.circom @@ -26,6 +26,7 @@ template LinkedMultiQuery(N, claimLevels, maxValueArraySize) { signal input operator[N]; signal input value[N][maxValueArraySize]; signal input valueArraySize[N]; + signal input commitNonce[N]; // Outputs signal output linkID; @@ -68,7 +69,7 @@ template LinkedMultiQuery(N, claimLevels, maxValueArraySize) { ///////////////////////////////////////////////////////////////// for (var i=0; i Date: Thu, 2 May 2024 00:55:56 +0100 Subject: [PATCH 2/2] Unit tests for ValueCommitment --- .../circuits/query/valueCommitmentTest.circom | 5 +++ test/query/valueCommitment.test.ts | 31 +++++++++++++++++++ 2 files changed, 36 insertions(+) create mode 100644 test/circuits/query/valueCommitmentTest.circom create mode 100644 test/query/valueCommitment.test.ts diff --git a/test/circuits/query/valueCommitmentTest.circom b/test/circuits/query/valueCommitmentTest.circom new file mode 100644 index 00000000..d18d5930 --- /dev/null +++ b/test/circuits/query/valueCommitmentTest.circom @@ -0,0 +1,5 @@ +pragma circom 2.1.1; + +include "../../../circuits/lib/query/valueCommitment.circom"; + +component main = ValueCommitment(); diff --git a/test/query/valueCommitment.test.ts b/test/query/valueCommitment.test.ts new file mode 100644 index 00000000..24d9df82 --- /dev/null +++ b/test/query/valueCommitment.test.ts @@ -0,0 +1,31 @@ +import {describe} from "mocha"; + +const path = require("path"); +const wasm_tester = require("circom_tester").wasm; + + +describe("ValueCommitment test", function () { + let valueCommitmentCircuit; + + before(async function () { + valueCommitmentCircuit = await wasm_tester(path.join(__dirname, "../circuits/query/", "valueCommitmentTest.circom")); + }); + + it("should commit a value with a non-zero nonce", async () => { + const inputs = { value: "5", commitNonce: "7" }; + const expectedOut = { out: "21007229687521157814825902919006068496120320911167801732994749038798743998593" }; + + const witness = await valueCommitmentCircuit.calculateWitness(inputs, true); + await valueCommitmentCircuit.assertOut(witness, expectedOut); + await valueCommitmentCircuit.checkConstraints(witness); + }); + + it("should return zero for a commit with zero nonce", async () => { + const inputs = { value: "10", commitNonce: "0" }; + const expectedOut = { out: "0" }; + + const witness = await valueCommitmentCircuit.calculateWitness(inputs, true); + await valueCommitmentCircuit.assertOut(witness, expectedOut); + await valueCommitmentCircuit.checkConstraints(witness); + }); +}); \ No newline at end of file