diff --git a/.vscode/settings.json b/.vscode/settings.json index 87b5da09..279a0077 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -2,5 +2,37 @@ "yaml.format.singleQuote": false, "prettier.enable": true, "prettier.jsxSingleQuote": false, - "yaml.format.enable": true + "yaml.format.enable": true, + "cSpell.words": [ + "babyjub", + "Babyjubjub", + "circom", + "circomlib", + "circomlibjs", + "Commonlib", + "ECDH", + "fflonk", + "Groth", + "iden", + "izeto", + "Jubjub", + "keypair", + "maci", + "merkletree", + "ptau", + "ptaus", + "rapidsnark", + "snarkjs", + "solidityverifier", + "supplypike", + "tokenid", + "UTXO", + "UTXOs", + "UTXOSMT", + "UUPS", + "verificationkey", + "vkey", + "WTNS", + "zeto" + ] } \ No newline at end of file diff --git a/doc-site/docs/assets/paladin-icon-light.png b/doc-site/docs/assets/paladin-icon-light.png deleted file mode 100644 index 5222675c..00000000 Binary files a/doc-site/docs/assets/paladin-icon-light.png and /dev/null differ diff --git a/doc-site/docs/assets/paladin-logo-dark.svg b/doc-site/docs/assets/paladin-logo-dark.svg deleted file mode 100644 index d326b322..00000000 --- a/doc-site/docs/assets/paladin-logo-dark.svg +++ /dev/null @@ -1,15 +0,0 @@ - - - - - - - - - - - - - - - diff --git a/doc-site/docs/assets/paladin-logo-light.svg b/doc-site/docs/assets/paladin-logo-light.svg deleted file mode 100644 index d075c322..00000000 --- a/doc-site/docs/assets/paladin-logo-light.svg +++ /dev/null @@ -1,15 +0,0 @@ - - - - - - - - - - - - - - - diff --git a/doc-site/docs/assets/zeto-icon.jpeg b/doc-site/docs/assets/zeto-icon.jpeg new file mode 100644 index 00000000..d77ebe28 Binary files /dev/null and b/doc-site/docs/assets/zeto-icon.jpeg differ diff --git a/doc-site/docs/assets/zeto-logo-dark.jpg b/doc-site/docs/assets/zeto-logo-dark.jpg new file mode 100644 index 00000000..b992c1df Binary files /dev/null and b/doc-site/docs/assets/zeto-logo-dark.jpg differ diff --git a/doc-site/docs/assets/zeto-logo-light.jpg b/doc-site/docs/assets/zeto-logo-light.jpg new file mode 100644 index 00000000..b992c1df Binary files /dev/null and b/doc-site/docs/assets/zeto-logo-light.jpg differ diff --git a/doc-site/docs/assets/zeto-logo.png b/doc-site/docs/assets/zeto-logo.png new file mode 100644 index 00000000..571db4a7 Binary files /dev/null and b/doc-site/docs/assets/zeto-logo.png differ diff --git a/doc-site/docs/stylesheets/zeto.css b/doc-site/docs/stylesheets/zeto.css index b4a3d712..ecd8d188 100644 --- a/doc-site/docs/stylesheets/zeto.css +++ b/doc-site/docs/stylesheets/zeto.css @@ -43,4 +43,5 @@ display: none; } +.md-header__button.md-logo img[alt=zeto] { height: 2rem; } img[alt=pqc] { width: 75px; border-radius: 15px; } \ No newline at end of file diff --git a/doc-site/mkdocs.yml b/doc-site/mkdocs.yml index f62a436e..79c053c2 100644 --- a/doc-site/mkdocs.yml +++ b/doc-site/mkdocs.yml @@ -4,9 +4,9 @@ repo_url: https://github.com/hyperledger-labs/zeto theme: name: material custom_dir: overrides - logo: assets/paladin-logo-light.svg - logo_dark: assets/paladin-logo-dark.svg - favicon: assets/paladin-icon-light.png + logo: assets/zeto-logo-light.jpg + logo_dark: assets/zeto-logo-dark.jpg + favicon: assets/zeto-icon.jpg icon: repo: fontawesome/brands/github palette: diff --git a/doc-site/overrides/partials/logo.html b/doc-site/overrides/partials/logo.html index 15a370c1..29a0cbb6 100644 --- a/doc-site/overrides/partials/logo.html +++ b/doc-site/overrides/partials/logo.html @@ -21,5 +21,5 @@ --> -Paladin -Paladin +zeto +zeto diff --git a/go-sdk/go.mod b/go-sdk/go.mod index 67be85c9..e6aad9a9 100644 --- a/go-sdk/go.mod +++ b/go-sdk/go.mod @@ -2,7 +2,7 @@ module github.com/hyperledger-labs/zeto/go-sdk go 1.23.0 -toolchain go1.23.1 +toolchain go1.23.7 require ( github.com/iden3/go-rapidsnark/witness/wasmer v0.0.0-20230524142950-0986cf057d4e diff --git a/solidity/contracts/verifiers/verifier_anon_nullifier_kyc.sol b/solidity/contracts/verifiers/verifier_anon_nullifier_kyc.sol index 2b385504..ce117dfa 100644 --- a/solidity/contracts/verifiers/verifier_anon_nullifier_kyc.sol +++ b/solidity/contracts/verifiers/verifier_anon_nullifier_kyc.sol @@ -43,8 +43,8 @@ contract Groth16Verifier_AnonNullifierKyc { uint256 constant deltay2 = 8495653923123431417604973247489272438418190587263600148770280649306958101930; - uint256 constant IC0x = 17336513663167332377949169478575466284101907029078607810833872321788374659601; - uint256 constant IC0y = 10397020245967735952916558183702669414774017177600319015152617686952244560097; + uint256 constant IC0x = 1368020126977316196213187057636983114330468061731699977744344817587788882990; + uint256 constant IC0y = 7686063895143330261591855899880142399404728944441362517893141962995856727929; uint256 constant IC1x = 14502254530076089964675033671517993862419783705089359180705605116873724842019; uint256 constant IC1y = 9049190990509151956509627927047158802465613185726643157556086701266946091568; @@ -52,17 +52,17 @@ contract Groth16Verifier_AnonNullifierKyc { uint256 constant IC2x = 3455128039314231841012773119366413118715790719104028464745205146228319556246; uint256 constant IC2y = 13175890403996370630092498196483049850968580675778268285842736204668575597675; - uint256 constant IC3x = 21609063410160746920311288333521282110904871128213587386326528382033849936047; - uint256 constant IC3y = 19053685498975284212451452487100951511472691870576100676350891466084386725324; + uint256 constant IC3x = 13393887812211802083177209056510129401898394892926768888874562627657192399962; + uint256 constant IC3y = 9042351346749284573092801161759462514076637268352518870596537996458419743091; - uint256 constant IC4x = 20839558467714218135816548507020277920013840149039689464195289045825016957066; - uint256 constant IC4y = 18171040984983395519673410253443945069876908714083596530196234237277378369754; + uint256 constant IC4x = 19203333608926332054415117565053561595496895142521866494460868409916811713957; + uint256 constant IC4y = 4334310208006613584617716058867417381004655491738058483537403401767079516612; - uint256 constant IC5x = 10186020517678246646201919013132136611100376409259802036221169773081382803557; - uint256 constant IC5y = 2024398128793281448742186646024870038510529605597905826731951443459182184482; + uint256 constant IC5x = 8459703094760317168584339428426828704909860684147786556335328845261416934167; + uint256 constant IC5y = 5466581123301380049065739652342512947564262375698860839217249516144678047196; - uint256 constant IC6x = 6817038550232615580081523910729732019328824723898271013459916846209181496148; - uint256 constant IC6y = 5007540534237292740105202068038033915182587070518049525579057126474202747048; + uint256 constant IC6x = 15924950080287000946685929883765297309673360990922044949928505866624182997859; + uint256 constant IC6y = 5360581200037747345688259956951448973597185992056174685326726615654044407192; uint256 constant IC7x = 9672280002529117458221100657711877410026000365131526255571070587277130104994; uint256 constant IC7y = 8600285172183660002776649258511861921290142756223662537727755349462907425056; diff --git a/solidity/contracts/verifiers/verifier_anon_nullifier_kyc_batch.sol b/solidity/contracts/verifiers/verifier_anon_nullifier_kyc_batch.sol index b806e45f..ae84d105 100644 --- a/solidity/contracts/verifiers/verifier_anon_nullifier_kyc_batch.sol +++ b/solidity/contracts/verifiers/verifier_anon_nullifier_kyc_batch.sol @@ -43,8 +43,8 @@ contract Groth16Verifier_AnonNullifierKycBatch { uint256 constant deltay2 = 8495653923123431417604973247489272438418190587263600148770280649306958101930; - uint256 constant IC0x = 5903479180487694997279265064344131881874542681454350742852120100073440524296; - uint256 constant IC0y = 9530657098554586749733666785385875949917582344806050500162894090355413522611; + uint256 constant IC0x = 17956394547302156521165787305425039553395368579665815878321069616384660821974; + uint256 constant IC0y = 6992882796389782419988913396487952889902510842290875072729183489463067562180; uint256 constant IC1x = 20973102971231858407268823830547921302985922314772564832818590542439356456221; uint256 constant IC1y = 8755463976472172454997983726165070757321336399692622916062903478185835201876; @@ -76,41 +76,41 @@ contract Groth16Verifier_AnonNullifierKycBatch { uint256 constant IC10x = 10027027914330943530569092473741094434086563269833520803780904295572828067751; uint256 constant IC10y = 421990751027288915733155885330259124989116330315517655643992915427432279442; - uint256 constant IC11x = 599244215281404141046456725437495318313391113948484631072822414812570716776; - uint256 constant IC11y = 10068255294045654417350386146388876221615727778457099371804026702882247474491; + uint256 constant IC11x = 11892755591860674046473115755992830180366136817328130148390945571128812998539; + uint256 constant IC11y = 9268798073089241248606702568568173938283201894666754305960489893725720318606; - uint256 constant IC12x = 21556964792859825649107667215781058705147965296731829911281160087820610838533; - uint256 constant IC12y = 13889886910952233505246502579980063028755614337122208662602852777579996569369; + uint256 constant IC12x = 10152555671693387741890273303761544089843267797975508348153732359110012549852; + uint256 constant IC12y = 6851215785130794843983404241253819330754997644123241414047997028799190421511; - uint256 constant IC13x = 20336517095597583565227873677117826914448174923218395440417472253759155911879; - uint256 constant IC13y = 13787294756325562052369133551051867132268321423810906151242602397719118060605; + uint256 constant IC13x = 15926389673646585067450607026615448882721273998707051750117711890545377843835; + uint256 constant IC13y = 6092524264858685061882637835001794548781930013420575912363384400816087682216; - uint256 constant IC14x = 723470074228247172376833529746853811390760610497044842304414745837297007793; - uint256 constant IC14y = 20473431670688220490381842545562296561006547604975254617604046916777297966342; + uint256 constant IC14x = 13758282793278046562484444741285107092317198764383609568883044140011006548296; + uint256 constant IC14y = 13297381771926142142906590533466958927079262003147219405302530238513936419715; - uint256 constant IC15x = 15002382818055737103129754932077118357634513012564080449864984893716211852169; - uint256 constant IC15y = 20986355934261372161815389867821841925843222171872598595602774389117273842363; + uint256 constant IC15x = 8974123089488822435414123220888650328624602168169290172017148632209729116247; + uint256 constant IC15y = 7022946489738753214417591939848011153517681920411366193658001703205231678394; - uint256 constant IC16x = 12194141240267141280402887975844644072507435166373817904521349435520239196563; - uint256 constant IC16y = 14593389642349486216409486354692535004279895256912795030101019816199908203510; + uint256 constant IC16x = 20285092191624000431458767079646131768817472892775292620424272081037439332800; + uint256 constant IC16y = 14677998525481291699643046995288705154622139789585886228695961572520744332931; - uint256 constant IC17x = 21015394223495022989411464000109008933122362273422924620851048926767533637678; - uint256 constant IC17y = 19949217149297160174771427449019144865727740578144251352593703549274424714243; + uint256 constant IC17x = 8653881030606523422653589889738043954964914655770505886480501697282389807422; + uint256 constant IC17y = 17802396532844609366494957607232915674517758974199893104755207809450698359725; - uint256 constant IC18x = 3943681362690863707194051007800503356665352728683045015484432282818996793654; - uint256 constant IC18y = 5926512517402465313700496622240148434683755798658418845914485987943511193577; + uint256 constant IC18x = 14222398084106517583634417674989764066430290828203827716243250821844511251642; + uint256 constant IC18y = 6595930713961692153773738963013914489592721577697364968088466912149388548163; - uint256 constant IC19x = 18521510625410973039043143625576116776310762869742273135122587764220766348395; - uint256 constant IC19y = 7566293396936121921157226464680078121529744119588821801602132955535815373956; + uint256 constant IC19x = 12301660154151583884980964450898433820033490381713715854436873218466423853515; + uint256 constant IC19y = 4868266765264225304664047279128447863928184956669291516153146669883676129155; - uint256 constant IC20x = 6955777603382581542780895326909850846348823267515133043834193460373252526587; - uint256 constant IC20y = 5404988211516657994220064031142977435521957627605222735616136075971916277477; + uint256 constant IC20x = 5600239864290768624288046938500983244220814692930262847591352146343383885481; + uint256 constant IC20y = 2725094490550109268734974010025210344524901385710087689968146552059031411979; - uint256 constant IC21x = 15342762311956869996626100728582941890438868605264297782193785457846632248470; - uint256 constant IC21y = 20548254230250891011773309995179021079622280572238402743503817964378124498364; + uint256 constant IC21x = 6506763475723656181886384700320184865762413529344881749723025499240876882623; + uint256 constant IC21y = 10863601731071513803837079879724831979468910760425582740082420817744191562393; - uint256 constant IC22x = 13468425754230748688976754818188805414992261059993406476820218042607689692919; - uint256 constant IC22y = 19259260110764955907957588951746942381445285741917061612123980235317042412735; + uint256 constant IC22x = 11014910699225719219658528849253210342134261845924428798796231729535338732066; + uint256 constant IC22y = 11833382714481648781585346617218200770199760228872321410398030590697079674233; uint256 constant IC23x = 7617190663029341979667377709868897026767966101370820487323419742367227464607; uint256 constant IC23y = 5828305386936705254095338960335559624881719900670519001227372129217412593638; diff --git a/zkp/circuits/basetokens/anon_base.circom b/zkp/circuits/basetokens/anon_base.circom index 8a01e6f5..e23b33bf 100644 --- a/zkp/circuits/basetokens/anon_base.circom +++ b/zkp/circuits/basetokens/anon_base.circom @@ -43,12 +43,24 @@ template Zeto(nInputs, nOutputs) { var inputOwnerPubKeyAx, inputOwnerPubKeyAy; (inputOwnerPubKeyAx, inputOwnerPubKeyAy) = BabyPbk()(in <== inputOwnerPrivateKey); - var inputOwnerPublicKeys[nInputs][2]; + CheckPositive(nOutputs)(outputValues <== outputValues); + + CommitmentInputs() inAuxInputs[nInputs]; for (var i = 0; i < nInputs; i++) { - inputOwnerPublicKeys[i]= [inputOwnerPubKeyAx, inputOwnerPubKeyAy]; + inAuxInputs[i].value <== inputValues[i]; + inAuxInputs[i].salt <== inputSalts[i]; + inAuxInputs[i].ownerPublicKey <== [inputOwnerPubKeyAx, inputOwnerPubKeyAy]; } - CheckPositive(nOutputs)(outputValues <== outputValues); - CheckHashes(nInputs)(commitments <== inputCommitments, values <== inputValues, salts <== inputSalts, ownerPublicKeys <== inputOwnerPublicKeys); - CheckHashes(nOutputs)(commitments <== outputCommitments, values <== outputValues, salts <== outputSalts, ownerPublicKeys <== outputOwnerPublicKeys); + + CommitmentInputs() outAuxInputs[nOutputs]; + for (var i = 0; i < nOutputs; i++) { + outAuxInputs[i].value <== outputValues[i]; + outAuxInputs[i].salt <== outputSalts[i]; + outAuxInputs[i].ownerPublicKey <== outputOwnerPublicKeys[i]; + } + + CheckHashes(nInputs)(commitmentHashes <== inputCommitments, commitmentInputs <== inAuxInputs); + CheckHashes(nOutputs)(commitmentHashes <== outputCommitments, commitmentInputs <== outAuxInputs); + CheckSum(nInputs, nOutputs)(inputValues <== inputValues, outputValues <== outputValues); } diff --git a/zkp/circuits/basetokens/anon_enc_base.circom b/zkp/circuits/basetokens/anon_enc_base.circom index 9c3e3da6..5eabedc9 100644 --- a/zkp/circuits/basetokens/anon_enc_base.circom +++ b/zkp/circuits/basetokens/anon_enc_base.circom @@ -55,18 +55,26 @@ template Zeto(nInputs, nOutputs) { var inputOwnerPubKeyAx, inputOwnerPubKeyAy; (inputOwnerPubKeyAx, inputOwnerPubKeyAy) = BabyPbk()(in <== inputOwnerPrivateKey); - var inputOwnerPublicKeys[nInputs][2]; + CheckPositive(nOutputs)(outputValues <== outputValues); + + CommitmentInputs() inAuxInputs[nInputs]; for (var i = 0; i < nInputs; i++) { - inputOwnerPublicKeys[i]= [inputOwnerPubKeyAx, inputOwnerPubKeyAy]; + inAuxInputs[i].value <== inputValues[i]; + inAuxInputs[i].salt <== inputSalts[i]; + inAuxInputs[i].ownerPublicKey <== [inputOwnerPubKeyAx, inputOwnerPubKeyAy]; } - CheckPositive(nOutputs)(outputValues <== outputValues); - - CheckHashes(nInputs)(commitments <== inputCommitments, values <== inputValues, salts <== inputSalts, ownerPublicKeys <== inputOwnerPublicKeys); + CommitmentInputs() outAuxInputs[nOutputs]; + for (var i = 0; i < nOutputs; i++) { + outAuxInputs[i].value <== outputValues[i]; + outAuxInputs[i].salt <== outputSalts[i]; + outAuxInputs[i].ownerPublicKey <== outputOwnerPublicKeys[i]; + } - CheckHashes(nOutputs)(commitments <== outputCommitments, values <== outputValues, salts <== outputSalts, ownerPublicKeys <== outputOwnerPublicKeys); + CheckHashes(nInputs)(commitmentHashes <== inputCommitments, commitmentInputs <== inAuxInputs); + CheckHashes(nOutputs)(commitmentHashes <== outputCommitments, commitmentInputs <== outAuxInputs); CheckSum(nInputs, nOutputs)(inputValues <== inputValues, outputValues <== outputValues); - (ecdhPublicKey,cipherTexts ) <== EncryptOutputs(nOutputs)(ecdhPrivateKey <== ecdhPrivateKey, outputValues <== outputValues, outputSalts <== outputSalts, outputOwnerPublicKeys <== outputOwnerPublicKeys, encryptionNonce <== encryptionNonce); + (ecdhPublicKey,cipherTexts ) <== EncryptOutputs(nOutputs)(ecdhPrivateKey <== ecdhPrivateKey, encryptionNonce <== encryptionNonce, commitmentInputs <== outAuxInputs); } diff --git a/zkp/circuits/basetokens/anon_enc_nullifier_base.circom b/zkp/circuits/basetokens/anon_enc_nullifier_base.circom index ba863623..fa0d39aa 100644 --- a/zkp/circuits/basetokens/anon_enc_nullifier_base.circom +++ b/zkp/circuits/basetokens/anon_enc_nullifier_base.circom @@ -62,16 +62,24 @@ template Zeto(nInputs, nOutputs, nSMTLevels) { var inputOwnerPubKeyAx, inputOwnerPubKeyAy; (inputOwnerPubKeyAx, inputOwnerPubKeyAy) = BabyPbk()(in <== inputOwnerPrivateKey); - var inputOwnerPublicKeys[nInputs][2]; + CheckPositive(nOutputs)(outputValues <== outputValues); + + CommitmentInputs() inAuxInputs[nInputs]; for (var i = 0; i < nInputs; i++) { - inputOwnerPublicKeys[i]= [inputOwnerPubKeyAx, inputOwnerPubKeyAy]; + inAuxInputs[i].value <== inputValues[i]; + inAuxInputs[i].salt <== inputSalts[i]; + inAuxInputs[i].ownerPublicKey <== [inputOwnerPubKeyAx, inputOwnerPubKeyAy]; } - CheckPositive(nOutputs)(outputValues <== outputValues); - - CheckHashes(nInputs)(commitments <== inputCommitments, values <== inputValues, salts <== inputSalts, ownerPublicKeys <== inputOwnerPublicKeys); + CommitmentInputs() outAuxInputs[nOutputs]; + for (var i = 0; i < nOutputs; i++) { + outAuxInputs[i].value <== outputValues[i]; + outAuxInputs[i].salt <== outputSalts[i]; + outAuxInputs[i].ownerPublicKey <== outputOwnerPublicKeys[i]; + } - CheckHashes(nOutputs)(commitments <== outputCommitments, values <== outputValues, salts <== outputSalts, ownerPublicKeys <== outputOwnerPublicKeys); + CheckHashes(nInputs)(commitmentHashes <== inputCommitments, commitmentInputs <== inAuxInputs); + CheckHashes(nOutputs)(commitmentHashes <== outputCommitments, commitmentInputs <== outAuxInputs); CheckNullifiers(nInputs)(nullifiers <== nullifiers, values <== inputValues, salts <== inputSalts, ownerPrivateKey <== inputOwnerPrivateKey); @@ -84,5 +92,5 @@ template Zeto(nInputs, nOutputs, nSMTLevels) { // Merkle Tree with the root `root`. CheckSMTProof(nInputs, nSMTLevels)(root <== root, merkleProof <== merkleProof, enabled <== enabled, leafNodeIndexes <== inputCommitments, leafNodeValues <== inputCommitments); - (ecdhPublicKey, cipherTexts) <== EncryptOutputs(nOutputs)(ecdhPrivateKey <== ecdhPrivateKey, outputValues <== outputValues, outputSalts <== outputSalts, outputOwnerPublicKeys <== outputOwnerPublicKeys, encryptionNonce <== encryptionNonce); + (ecdhPublicKey, cipherTexts) <== EncryptOutputs(nOutputs)(ecdhPrivateKey <== ecdhPrivateKey, encryptionNonce <== encryptionNonce, commitmentInputs <== outAuxInputs); } diff --git a/zkp/circuits/basetokens/anon_enc_nullifier_kyc_base.circom b/zkp/circuits/basetokens/anon_enc_nullifier_kyc_base.circom index 8450f2bd..3fa689fc 100644 --- a/zkp/circuits/basetokens/anon_enc_nullifier_kyc_base.circom +++ b/zkp/circuits/basetokens/anon_enc_nullifier_kyc_base.circom @@ -65,16 +65,24 @@ template Zeto(nInputs, nOutputs, nUTXOSMTLevels, nIdentitiesSMTLevels) { var inputOwnerPubKeyAx, inputOwnerPubKeyAy; (inputOwnerPubKeyAx, inputOwnerPubKeyAy) = BabyPbk()(in <== inputOwnerPrivateKey); - var inputOwnerPublicKeys[nInputs][2]; + CheckPositive(nOutputs)(outputValues <== outputValues); + + CommitmentInputs() inAuxInputs[nInputs]; for (var i = 0; i < nInputs; i++) { - inputOwnerPublicKeys[i]= [inputOwnerPubKeyAx, inputOwnerPubKeyAy]; + inAuxInputs[i].value <== inputValues[i]; + inAuxInputs[i].salt <== inputSalts[i]; + inAuxInputs[i].ownerPublicKey <== [inputOwnerPubKeyAx, inputOwnerPubKeyAy]; } - CheckPositive(nOutputs)(outputValues <== outputValues); - - CheckHashes(nInputs)(commitments <== inputCommitments, values <== inputValues, salts <== inputSalts, ownerPublicKeys <== inputOwnerPublicKeys); + CommitmentInputs() outAuxInputs[nOutputs]; + for (var i = 0; i < nOutputs; i++) { + outAuxInputs[i].value <== outputValues[i]; + outAuxInputs[i].salt <== outputSalts[i]; + outAuxInputs[i].ownerPublicKey <== outputOwnerPublicKeys[i]; + } - CheckHashes(nOutputs)(commitments <== outputCommitments, values <== outputValues, salts <== outputSalts, ownerPublicKeys <== outputOwnerPublicKeys); + CheckHashes(nInputs)(commitmentHashes <== inputCommitments, commitmentInputs <== inAuxInputs); + CheckHashes(nOutputs)(commitmentHashes <== outputCommitments, commitmentInputs <== outAuxInputs); CheckNullifiers(nInputs)(nullifiers <== nullifiers, values <== inputValues, salts <== inputSalts, ownerPrivateKey <== inputOwnerPrivateKey); @@ -101,5 +109,5 @@ template Zeto(nInputs, nOutputs, nUTXOSMTLevels, nIdentitiesSMTLevels) { CheckSMTProof(nOutputs + 1, nIdentitiesSMTLevels)(root <== identitiesRoot, merkleProof <== identitiesMerkleProof, enabled <== identitiesMTPCheckEnabled, leafNodeIndexes <== ownerPublicKeyHashes, leafNodeValues <== ownerPublicKeyHashes); - (ecdhPublicKey, cipherTexts) <== EncryptOutputs(nOutputs)(ecdhPrivateKey <== ecdhPrivateKey, outputValues <== outputValues, outputSalts <== outputSalts, outputOwnerPublicKeys <== outputOwnerPublicKeys, encryptionNonce <== encryptionNonce); + (ecdhPublicKey, cipherTexts) <== EncryptOutputs(nOutputs)(ecdhPrivateKey <== ecdhPrivateKey, encryptionNonce <== encryptionNonce, commitmentInputs <== outAuxInputs); } \ No newline at end of file diff --git a/zkp/circuits/basetokens/anon_enc_nullifier_non_repudiation_base.circom b/zkp/circuits/basetokens/anon_enc_nullifier_non_repudiation_base.circom index 001a10b5..5aebb884 100644 --- a/zkp/circuits/basetokens/anon_enc_nullifier_non_repudiation_base.circom +++ b/zkp/circuits/basetokens/anon_enc_nullifier_non_repudiation_base.circom @@ -78,16 +78,24 @@ template Zeto(nInputs, nOutputs, nSMTLevels) { var inputOwnerPubKeyAx, inputOwnerPubKeyAy; (inputOwnerPubKeyAx, inputOwnerPubKeyAy) = BabyPbk()(in <== inputOwnerPrivateKey); - var inputOwnerPublicKeys[nInputs][2]; + CheckPositive(nOutputs)(outputValues <== outputValues); + + CommitmentInputs() inAuxInputs[nInputs]; for (var i = 0; i < nInputs; i++) { - inputOwnerPublicKeys[i] = [inputOwnerPubKeyAx, inputOwnerPubKeyAy]; + inAuxInputs[i].value <== inputValues[i]; + inAuxInputs[i].salt <== inputSalts[i]; + inAuxInputs[i].ownerPublicKey <== [inputOwnerPubKeyAx, inputOwnerPubKeyAy]; } - CheckPositive(nOutputs)(outputValues <== outputValues); - - CheckHashes(nInputs)(commitments <== inputCommitments, values <== inputValues, salts <== inputSalts, ownerPublicKeys <== inputOwnerPublicKeys); + CommitmentInputs() outAuxInputs[nOutputs]; + for (var i = 0; i < nOutputs; i++) { + outAuxInputs[i].value <== outputValues[i]; + outAuxInputs[i].salt <== outputSalts[i]; + outAuxInputs[i].ownerPublicKey <== outputOwnerPublicKeys[i]; + } - CheckHashes(nOutputs)(commitments <== outputCommitments, values <== outputValues, salts <== outputSalts, ownerPublicKeys <== outputOwnerPublicKeys); + CheckHashes(nInputs)(commitmentHashes <== inputCommitments, commitmentInputs <== inAuxInputs); + CheckHashes(nOutputs)(commitmentHashes <== outputCommitments, commitmentInputs <== outAuxInputs); CheckNullifiers(nInputs)(nullifiers <== nullifiers, values <== inputValues, salts <== inputSalts, ownerPrivateKey <== inputOwnerPrivateKey); @@ -100,7 +108,7 @@ template Zeto(nInputs, nOutputs, nSMTLevels) { CheckSMTProof(nInputs, nSMTLevels)(root <== root, merkleProof <== merkleProof, enabled <== enabled, leafNodeIndexes <== inputCommitments, leafNodeValues <== inputCommitments); // Generate cipher text for output utxos - (ecdhPublicKey, cipherTexts) <== EncryptOutputs(nOutputs)(ecdhPrivateKey <== ecdhPrivateKey, outputValues <== outputValues, outputSalts <== outputSalts, outputOwnerPublicKeys <== outputOwnerPublicKeys, encryptionNonce <== encryptionNonce); + (ecdhPublicKey, cipherTexts) <== EncryptOutputs(nOutputs)(ecdhPrivateKey <== ecdhPrivateKey, encryptionNonce <== encryptionNonce, commitmentInputs <== outAuxInputs); // generate shared secret for the authority var sharedSecretAuthority[2]; diff --git a/zkp/circuits/basetokens/anon_nullifier_base.circom b/zkp/circuits/basetokens/anon_nullifier_base.circom index 550e30bb..9ff1b0a9 100644 --- a/zkp/circuits/basetokens/anon_nullifier_base.circom +++ b/zkp/circuits/basetokens/anon_nullifier_base.circom @@ -54,16 +54,24 @@ template Zeto(nInputs, nOutputs, nSMTLevels) { var inputOwnerPubKeyAx, inputOwnerPubKeyAy; (inputOwnerPubKeyAx, inputOwnerPubKeyAy) = BabyPbk()(in <== inputOwnerPrivateKey); - var inputOwnerPublicKeys[nInputs][2]; + CheckPositive(nOutputs)(outputValues <== outputValues); + + CommitmentInputs() inAuxInputs[nInputs]; for (var i = 0; i < nInputs; i++) { - inputOwnerPublicKeys[i] = [inputOwnerPubKeyAx, inputOwnerPubKeyAy]; + inAuxInputs[i].value <== inputValues[i]; + inAuxInputs[i].salt <== inputSalts[i]; + inAuxInputs[i].ownerPublicKey <== [inputOwnerPubKeyAx, inputOwnerPubKeyAy]; } - CheckPositive(nOutputs)(outputValues <== outputValues); - - CheckHashes(nInputs)(commitments <== inputCommitments, values <== inputValues, salts <== inputSalts, ownerPublicKeys <== inputOwnerPublicKeys); + CommitmentInputs() outAuxInputs[nOutputs]; + for (var i = 0; i < nOutputs; i++) { + outAuxInputs[i].value <== outputValues[i]; + outAuxInputs[i].salt <== outputSalts[i]; + outAuxInputs[i].ownerPublicKey <== outputOwnerPublicKeys[i]; + } - CheckHashes(nOutputs)(commitments <== outputCommitments, values <== outputValues, salts <== outputSalts, ownerPublicKeys <== outputOwnerPublicKeys); + CheckHashes(nInputs)(commitmentHashes <== inputCommitments, commitmentInputs <== inAuxInputs); + CheckHashes(nOutputs)(commitmentHashes <== outputCommitments, commitmentInputs <== outAuxInputs); CheckNullifiers(nInputs)(nullifiers <== nullifiers, values <== inputValues, salts <== inputSalts, ownerPrivateKey <== inputOwnerPrivateKey); diff --git a/zkp/circuits/basetokens/anon_nullifier_kyc_base.circom b/zkp/circuits/basetokens/anon_nullifier_kyc_base.circom index 3e83d932..d77889d5 100644 --- a/zkp/circuits/basetokens/anon_nullifier_kyc_base.circom +++ b/zkp/circuits/basetokens/anon_nullifier_kyc_base.circom @@ -56,16 +56,24 @@ template Zeto(nInputs, nOutputs, nUTXOSMTLevels, nIdentitiesSMTLevels) { var inputOwnerPubKeyAx, inputOwnerPubKeyAy; (inputOwnerPubKeyAx, inputOwnerPubKeyAy) = BabyPbk()(in <== inputOwnerPrivateKey); - var inputOwnerPublicKeys[nInputs][2]; + CheckPositive(nOutputs)(outputValues <== outputValues); + + CommitmentInputs() inAuxInputs[nInputs]; for (var i = 0; i < nInputs; i++) { - inputOwnerPublicKeys[i] = [inputOwnerPubKeyAx, inputOwnerPubKeyAy]; + inAuxInputs[i].value <== inputValues[i]; + inAuxInputs[i].salt <== inputSalts[i]; + inAuxInputs[i].ownerPublicKey <== [inputOwnerPubKeyAx, inputOwnerPubKeyAy]; } - CheckPositive(nOutputs)(outputValues <== outputValues); - - CheckHashes(nInputs)(commitments <== inputCommitments, values <== inputValues, salts <== inputSalts, ownerPublicKeys <== inputOwnerPublicKeys); + CommitmentInputs() outAuxInputs[nOutputs]; + for (var i = 0; i < nOutputs; i++) { + outAuxInputs[i].value <== outputValues[i]; + outAuxInputs[i].salt <== outputSalts[i]; + outAuxInputs[i].ownerPublicKey <== outputOwnerPublicKeys[i]; + } - CheckHashes(nOutputs)(commitments <== outputCommitments, values <== outputValues, salts <== outputSalts, ownerPublicKeys <== outputOwnerPublicKeys); + CheckHashes(nInputs)(commitmentHashes <== inputCommitments, commitmentInputs <== inAuxInputs); + CheckHashes(nOutputs)(commitmentHashes <== outputCommitments, commitmentInputs <== outAuxInputs); CheckNullifiers(nInputs)(nullifiers <== nullifiers, values <== inputValues, salts <== inputSalts, ownerPrivateKey <== inputOwnerPrivateKey); diff --git a/zkp/circuits/check_nullifiers.circom b/zkp/circuits/check_nullifiers.circom index 3dd7616e..4bab5d5c 100644 --- a/zkp/circuits/check_nullifiers.circom +++ b/zkp/circuits/check_nullifiers.circom @@ -25,11 +25,11 @@ include "./node_modules/circomlib/circuits/babyjub.circom"; // commitment = hash(value, salt, ownerPublicKey1, ownerPublicKey2) // nullifier = hash(value, salt, ownerPrivatekey) // -template Zeto(numInputs) { - signal input nullifiers[numInputs]; - signal input inputCommitments[numInputs]; - signal input inputValues[numInputs]; - signal input inputSalts[numInputs]; +template Zeto(nInputs) { + signal input nullifiers[nInputs]; + signal input inputCommitments[nInputs]; + signal input inputValues[nInputs]; + signal input inputSalts[nInputs]; // must be properly hashed and trimmed to be compatible with the BabyJub curve. // Reference: https://github.com/iden3/circomlib/blob/master/test/babyjub.js#L103 signal input inputOwnerPrivateKey; @@ -41,14 +41,16 @@ template Zeto(numInputs) { var inputOwnerPubKeyAx, inputOwnerPubKeyAy; (inputOwnerPubKeyAx, inputOwnerPubKeyAy) = BabyPbk()(in <== inputOwnerPrivateKey); - var inputOwnerPublicKeys[numInputs][2]; - for (var i = 0; i < numInputs; i++) { - inputOwnerPublicKeys[i] = [inputOwnerPubKeyAx, inputOwnerPubKeyAy]; + CommitmentInputs() auxInputs[nInputs]; + for (var i = 0; i < nInputs; i++) { + auxInputs[i].value <== inputValues[i]; + auxInputs[i].salt <== inputSalts[i]; + auxInputs[i].ownerPublicKey <== [inputOwnerPubKeyAx, inputOwnerPubKeyAy]; } - CheckHashes(numInputs)(commitments <== inputCommitments, values <== inputValues, salts <== inputSalts, ownerPublicKeys <== inputOwnerPublicKeys); + CheckHashes(nInputs)(commitmentHashes <== inputCommitments, commitmentInputs <== auxInputs); - CheckNullifiers(numInputs)(nullifiers <== nullifiers, values <== inputValues, salts <== inputSalts, ownerPrivateKey <== inputOwnerPrivateKey); + CheckNullifiers(nInputs)(nullifiers <== nullifiers, values <== inputValues, salts <== inputSalts, ownerPrivateKey <== inputOwnerPrivateKey); } component main { public [ nullifiers, inputCommitments ] } = Zeto(2); \ No newline at end of file diff --git a/zkp/circuits/deposit.circom b/zkp/circuits/deposit.circom index 32c86f42..c822f91d 100644 --- a/zkp/circuits/deposit.circom +++ b/zkp/circuits/deposit.circom @@ -27,7 +27,14 @@ template Zeto(nOutputs) { CheckPositive(nOutputs)(outputValues <== outputValues); - CheckHashes(nOutputs)(commitments <== outputCommitments, values <== outputValues, salts <== outputSalts, ownerPublicKeys <== outputOwnerPublicKeys); + CommitmentInputs() auxInputs[nOutputs]; + for (var i = 0; i < nOutputs; i++) { + auxInputs[i].value <== outputValues[i]; + auxInputs[i].salt <== outputSalts[i]; + auxInputs[i].ownerPublicKey <== outputOwnerPublicKeys[i]; + } + + CheckHashes(nOutputs)(commitmentHashes <== outputCommitments, commitmentInputs <== auxInputs); // calculate the sum of output values and set to the output var sumOutputs = 0; diff --git a/zkp/circuits/lib/burn-nullifiers.circom b/zkp/circuits/lib/burn-nullifiers.circom index d1b859b0..4e014568 100644 --- a/zkp/circuits/lib/burn-nullifiers.circom +++ b/zkp/circuits/lib/burn-nullifiers.circom @@ -61,11 +61,21 @@ template BurnNullifiers(numInputs, nSMTLevels) { CheckPositive(1)(outputValues <== [outputValue]); - CheckHashes(numInputs)(commitments <== inputCommitments, values <== inputValues, salts <== inputSalts, ownerPublicKeys <== ownerPublicKeys); + CommitmentInputs() inAuxInputs[numInputs]; + for (var i = 0; i < numInputs; i++) { + inAuxInputs[i].value <== inputValues[i]; + inAuxInputs[i].salt <== inputSalts[i]; + inAuxInputs[i].ownerPublicKey <== [ownerPubKeyAx, ownerPubKeyAy]; + } + CheckHashes(numInputs)(commitmentHashes <== inputCommitments, commitmentInputs <== inAuxInputs); CheckNullifiers(numInputs)(nullifiers <== nullifiers, values <== inputValues, salts <== inputSalts, ownerPrivateKey <== ownerPrivateKey); - CheckHashes(1)(commitments <== [outputCommitment], values <== [outputValue], salts <== [outputSalt], ownerPublicKeys <== [[ownerPubKeyAx, ownerPubKeyAy]]); + CommitmentInputs() outAuxInputs[1]; + outAuxInputs[0].value <== outputValue; + outAuxInputs[0].salt <== outputSalt; + outAuxInputs[0].ownerPublicKey <== [ownerPubKeyAx, ownerPubKeyAy]; + CheckHashes(1)(commitmentHashes <== [outputCommitment], commitmentInputs <== outAuxInputs); // With the above steps, we demonstrated that the nullifiers // are securely bound to the input commitments. Now we need to diff --git a/zkp/circuits/lib/burn.circom b/zkp/circuits/lib/burn.circom index 1af64881..58c65e87 100644 --- a/zkp/circuits/lib/burn.circom +++ b/zkp/circuits/lib/burn.circom @@ -52,9 +52,19 @@ template Burn(numInputs) { CheckPositive(1)(outputValues <== [outputValue]); - CheckHashes(numInputs)(commitments <== inputCommitments, values <== inputValues, salts <== inputSalts, ownerPublicKeys <== ownerPublicKeys); + CommitmentInputs() inAuxInputs[numInputs]; + for (var i = 0; i < numInputs; i++) { + inAuxInputs[i].value <== inputValues[i]; + inAuxInputs[i].salt <== inputSalts[i]; + inAuxInputs[i].ownerPublicKey <== [ownerPubKeyAx, ownerPubKeyAy]; + } + CheckHashes(numInputs)(commitmentHashes <== inputCommitments, commitmentInputs <== inAuxInputs); - CheckHashes(1)(commitments <== [outputCommitment], values <== [outputValue], salts <== [outputSalt], ownerPublicKeys <== [[ownerPubKeyAx, ownerPubKeyAy]]); + CommitmentInputs() outAuxInputs[1]; + outAuxInputs[0].value <== outputValue; + outAuxInputs[0].salt <== outputSalt; + outAuxInputs[0].ownerPublicKey <== [ownerPubKeyAx, ownerPubKeyAy]; + CheckHashes(1)(commitmentHashes <== [outputCommitment], commitmentInputs <== outAuxInputs); // check that the sum of input values is greater than or equal to the sum of output values var sumInputs = 0; diff --git a/zkp/circuits/lib/buses.circom b/zkp/circuits/lib/buses.circom new file mode 100644 index 00000000..861e289d --- /dev/null +++ b/zkp/circuits/lib/buses.circom @@ -0,0 +1,33 @@ +// Copyright © 2025 Kaleido, Inc. +// +// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +pragma circom 2.2.2; + +bus CommitmentInputs(){ + signal value; + signal salt; + signal ownerPublicKey[2]; +} + +template CheckPositiveValues(nInputs) { + input CommitmentInputs() commitmentInputs[nInputs]; + + // check that the output values are within the expected range. we don't allow negative values + for (var i = 0; i < nInputs; i++) { + var greaterEqThanZero; + greaterEqThanZero = GreaterEqThan(100)(in <== [commitmentInputs[i].value, 0]); + greaterEqThanZero === 1; + } +} \ No newline at end of file diff --git a/zkp/circuits/lib/check-hashes-tokenid-uri.circom b/zkp/circuits/lib/check-hashes-tokenid-uri.circom index 27b52f36..9f38b9bf 100644 --- a/zkp/circuits/lib/check-hashes-tokenid-uri.circom +++ b/zkp/circuits/lib/check-hashes-tokenid-uri.circom @@ -26,15 +26,15 @@ include "../node_modules/circomlib/circuits/comparators.circom"; // tokenIds: array of token ids, as preimages for the input hashes and output hashes // tokenUris: array of token uris, as preimages for the input hashes and output hashes // -template CheckHashesForTokenIdAndUri(numInputs) { - signal input tokenIds[numInputs]; - signal input tokenUris[numInputs]; - signal input commitments[numInputs]; - signal input salts[numInputs]; - signal input ownerPublicKeys[numInputs][2]; +template CheckHashesForTokenIdAndUri(nInputs) { + signal input tokenIds[nInputs]; + signal input tokenUris[nInputs]; + signal input commitments[nInputs]; + signal input salts[nInputs]; + signal input ownerPublicKeys[nInputs][2]; // hash the input values - for (var i = 0; i < numInputs; i++) { + for (var i = 0; i < nInputs; i++) { // perform the hash calculation even though they are not needed when the input // commitment at the current index is 0; this is because in zkp circuits we // must always perform the same computation (have the the same constraints) diff --git a/zkp/circuits/lib/check-hashes.circom b/zkp/circuits/lib/check-hashes.circom index 6ec354bb..898ff94a 100644 --- a/zkp/circuits/lib/check-hashes.circom +++ b/zkp/circuits/lib/check-hashes.circom @@ -17,33 +17,31 @@ pragma circom 2.2.2; include "../node_modules/circomlib/circuits/poseidon.circom"; include "../node_modules/circomlib/circuits/comparators.circom"; +include "./buses.circom"; // CheckHashes is a circuit that checks the integrity of transactions of Fungible Tokens // - check that the commitments are the hash of the values, salts and owner public keys // // commitment = hash(value, salt, owner public key) // -template CheckHashes(numInputs) { - signal input commitments[numInputs]; - signal input values[numInputs]; - signal input salts[numInputs]; - signal input ownerPublicKeys[numInputs][2]; +template CheckHashes(nInputs) { + signal input commitmentHashes[nInputs]; + input CommitmentInputs() commitmentInputs[nInputs]; // hash the input values - for (var i = 0; i < numInputs; i++) { + for (var i = 0; i < nInputs; i++) { // perform the hash calculation even though they are not needed when the input // commitment at the current index is 0; this is because in zkp circuits we // must always perform the same computation (have the the same constraints) var calculatedHash; - calculatedHash = Poseidon(4)([values[i], salts[i], ownerPublicKeys[i][0], ownerPublicKeys[i][1]]); + calculatedHash = Poseidon(4)([commitmentInputs[i].value, commitmentInputs[i].salt, commitmentInputs[i].ownerPublicKey[0], commitmentInputs[i].ownerPublicKey[1]]); // check that the input commitments match the calculated hashes var isCommitmentZero; - isCommitmentZero = IsZero()(in <== commitments[i]); + isCommitmentZero = IsZero()(in <== commitmentHashes[i]); var isHashEqual; - isHashEqual = IsEqual()(in <== [commitments[i], (1 - isCommitmentZero) * calculatedHash /* ensure when commitment is 0, compare with 0 */]); - + isHashEqual = IsEqual()(in <== [commitmentHashes[i], (1 - isCommitmentZero) * calculatedHash /* ensure when commitment is 0, compare with 0 */]); isHashEqual === 1; } } diff --git a/zkp/circuits/lib/check-inputs-outputs-value-base.circom b/zkp/circuits/lib/check-inputs-outputs-value-base.circom index a9d48f93..33cb9390 100644 --- a/zkp/circuits/lib/check-inputs-outputs-value-base.circom +++ b/zkp/circuits/lib/check-inputs-outputs-value-base.circom @@ -30,17 +30,17 @@ include "../node_modules/circomlib/circuits/comparators.circom"; // // commitment = hash(value, salt, owner public key) // -template CheckInputsOutputsValue(numInputs, numOutputs) { - signal input inputCommitments[numInputs]; - signal input inputValues[numInputs]; - signal input inputSalts[numInputs]; +template CheckInputsOutputsValue(nInputs, nOutputs) { + signal input inputCommitments[nInputs]; + signal input inputValues[nInputs]; + signal input inputSalts[nInputs]; // must be properly hashed and trimmed to be compatible with the BabyJub curve. // Reference: https://github.com/iden3/circomlib/blob/master/test/babyjub.js#L103 signal input inputOwnerPrivateKey; - signal input outputCommitments[numOutputs]; - signal input outputValues[numOutputs]; - signal input outputSalts[numOutputs]; - signal input outputOwnerPublicKeys[numOutputs][2]; + signal input outputCommitments[nOutputs]; + signal input outputValues[nOutputs]; + signal input outputSalts[nOutputs]; + signal input outputOwnerPublicKeys[nOutputs][2]; signal output out; // derive the sender's public key from the secret input @@ -50,24 +50,32 @@ template CheckInputsOutputsValue(numInputs, numOutputs) { var inputOwnerPubKeyAx, inputOwnerPubKeyAy; (inputOwnerPubKeyAx, inputOwnerPubKeyAy) = BabyPbk()(in <== inputOwnerPrivateKey); - var inputOwnerPublicKeys[numInputs][2]; - for (var i = 0; i < numInputs; i++) { - inputOwnerPublicKeys[i] = [inputOwnerPubKeyAx, inputOwnerPubKeyAy]; - } + CheckPositive(nOutputs)(outputValues <== outputValues); - CheckPositive(numOutputs)(outputValues <== outputValues); + CommitmentInputs() inAuxInputs[nInputs]; + for (var i = 0; i < nInputs; i++) { + inAuxInputs[i].value <== inputValues[i]; + inAuxInputs[i].salt <== inputSalts[i]; + inAuxInputs[i].ownerPublicKey <== [inputOwnerPubKeyAx, inputOwnerPubKeyAy]; + } - CheckHashes(numInputs)(commitments <== inputCommitments, values <== inputValues, salts <== inputSalts, ownerPublicKeys <== inputOwnerPublicKeys); + CommitmentInputs() outAuxInputs[nOutputs]; + for (var i = 0; i < nOutputs; i++) { + outAuxInputs[i].value <== outputValues[i]; + outAuxInputs[i].salt <== outputSalts[i]; + outAuxInputs[i].ownerPublicKey <== outputOwnerPublicKeys[i]; + } - CheckHashes(numOutputs)(commitments <== outputCommitments, values <== outputValues, salts <== outputSalts, ownerPublicKeys <== outputOwnerPublicKeys); + CheckHashes(nInputs)(commitmentHashes <== inputCommitments, commitmentInputs <== inAuxInputs); + CheckHashes(nOutputs)(commitmentHashes <== outputCommitments, commitmentInputs <== outAuxInputs); // check that the sum of input values is greater than or equal to the sum of output values var sumInputs = 0; - for (var i = 0; i < numInputs; i++) { + for (var i = 0; i < nInputs; i++) { sumInputs = sumInputs + inputValues[i]; } var sumOutputs = 0; - for (var i = 0; i < numOutputs; i++) { + for (var i = 0; i < nOutputs; i++) { sumOutputs = sumOutputs + outputValues[i]; } diff --git a/zkp/circuits/lib/check-nullifiers-tokenid-uri.circom b/zkp/circuits/lib/check-nullifiers-tokenid-uri.circom index 08bb4c7a..333358c7 100644 --- a/zkp/circuits/lib/check-nullifiers-tokenid-uri.circom +++ b/zkp/circuits/lib/check-nullifiers-tokenid-uri.circom @@ -28,17 +28,17 @@ include "../node_modules/circomlib/circuits/smt/smtverifier.circom"; // commitment = hash(tokenId, uri, salt, ownerPublicKey1, ownerPublicKey2) // nullifier = hash(tokenId, uri, salt, ownerPrivatekey) // -template CheckNullifiersForTokenIdAndUri(numInputs) { - signal input tokenIds[numInputs]; - signal input tokenUris[numInputs]; - signal input nullifiers[numInputs]; - signal input salts[numInputs]; +template CheckNullifiersForTokenIdAndUri(nInputs) { + signal input tokenIds[nInputs]; + signal input tokenUris[nInputs]; + signal input nullifiers[nInputs]; + signal input salts[nInputs]; // must be properly hashed and trimmed to be compatible with the BabyJub curve. // Reference: https://github.com/iden3/circomlib/blob/master/test/babyjub.js#L103 signal input ownerPrivateKey; // calculate the nullifier values from the input values - for (var i = 0; i < numInputs; i++) { + for (var i = 0; i < nInputs; i++) { var calculatedHash; calculatedHash = Poseidon(4)([tokenIds[i], tokenUris[i], salts[i], ownerPrivateKey]); diff --git a/zkp/circuits/lib/check-nullifiers-value-base.circom b/zkp/circuits/lib/check-nullifiers-value-base.circom index b89a32ae..2f26d533 100644 --- a/zkp/circuits/lib/check-nullifiers-value-base.circom +++ b/zkp/circuits/lib/check-nullifiers-value-base.circom @@ -32,21 +32,21 @@ include "./check-smt-proof.circom"; // commitment = hash(value, salt, owner public key) // nullifier = hash(value, salt, ownerPrivatekey) // -template CheckNullifiersInputsOutputsValue(numInputs, numOutputs, nSMTLevels) { - signal input nullifiers[numInputs]; - signal input inputCommitments[numInputs]; - signal input inputValues[numInputs]; - signal input inputSalts[numInputs]; +template CheckNullifiersInputsOutputsValue(nInputs, nOutputs, nSMTLevels) { + signal input nullifiers[nInputs]; + signal input inputCommitments[nInputs]; + signal input inputValues[nInputs]; + signal input inputSalts[nInputs]; // must be properly hashed and trimmed to be compatible with the BabyJub curve. // Reference: https://github.com/iden3/circomlib/blob/master/test/babyjub.js#L103 signal input inputOwnerPrivateKey; signal input root; - signal input merkleProof[numInputs][nSMTLevels]; - signal input enabled[numInputs]; - signal input outputCommitments[numOutputs]; - signal input outputValues[numOutputs]; - signal input outputSalts[numOutputs]; - signal input outputOwnerPublicKeys[numOutputs][2]; + signal input merkleProof[nInputs][nSMTLevels]; + signal input enabled[nInputs]; + signal input outputCommitments[nOutputs]; + signal input outputValues[nOutputs]; + signal input outputSalts[nOutputs]; + signal input outputOwnerPublicKeys[nOutputs][2]; signal output out; // derive the sender's public key from the secret input @@ -56,32 +56,40 @@ template CheckNullifiersInputsOutputsValue(numInputs, numOutputs, nSMTLevels) { var inputOwnerPubKeyAx, inputOwnerPubKeyAy; (inputOwnerPubKeyAx, inputOwnerPubKeyAy) = BabyPbk()(in <== inputOwnerPrivateKey); - var inputOwnerPublicKeys[numInputs][2]; - for (var i = 0; i < numInputs; i++) { - inputOwnerPublicKeys[i] = [inputOwnerPubKeyAx, inputOwnerPubKeyAy]; - } + CheckPositive(nOutputs)(outputValues <== outputValues); - CheckPositive(numOutputs)(outputValues <== outputValues); + CommitmentInputs() inAuxInputs[nInputs]; + for (var i = 0; i < nInputs; i++) { + inAuxInputs[i].value <== inputValues[i]; + inAuxInputs[i].salt <== inputSalts[i]; + inAuxInputs[i].ownerPublicKey <== [inputOwnerPubKeyAx, inputOwnerPubKeyAy]; + } - CheckHashes(numInputs)(commitments <== inputCommitments, values <== inputValues, salts <== inputSalts, ownerPublicKeys <== inputOwnerPublicKeys); + CommitmentInputs() outAuxInputs[nOutputs]; + for (var i = 0; i < nOutputs; i++) { + outAuxInputs[i].value <== outputValues[i]; + outAuxInputs[i].salt <== outputSalts[i]; + outAuxInputs[i].ownerPublicKey <== outputOwnerPublicKeys[i]; + } - CheckNullifiers(numInputs)(nullifiers <== nullifiers, values <== inputValues, salts <== inputSalts, ownerPrivateKey <== inputOwnerPrivateKey); + CheckHashes(nInputs)(commitmentHashes <== inputCommitments, commitmentInputs <== inAuxInputs); - CheckHashes(numOutputs)(commitments <== outputCommitments, values <== outputValues, salts <== outputSalts, ownerPublicKeys <== outputOwnerPublicKeys); + CheckNullifiers(nInputs)(nullifiers <== nullifiers, values <== inputValues, salts <== inputSalts, ownerPrivateKey <== inputOwnerPrivateKey); + CheckHashes(nOutputs)(commitmentHashes <== outputCommitments, commitmentInputs <== outAuxInputs); // With the above steps, we demonstrated that the nullifiers // are securely bound to the input commitments. Now we need to // demonstrate that the input commitments belong to the Sparse // Merkle Tree with the root `root`. - CheckSMTProof(numInputs, nSMTLevels)(root <== root, merkleProof <== merkleProof, enabled <== enabled, leafNodeIndexes <== inputCommitments, leafNodeValues <== inputCommitments); + CheckSMTProof(nInputs, nSMTLevels)(root <== root, merkleProof <== merkleProof, enabled <== enabled, leafNodeIndexes <== inputCommitments, leafNodeValues <== inputCommitments); // check that the sum of input values equals the sum of output values var sumInputs = 0; - for (var i = 0; i < numInputs; i++) { + for (var i = 0; i < nInputs; i++) { sumInputs = sumInputs + inputValues[i]; } var sumOutputs = 0; - for (var i = 0; i < numOutputs; i++) { + for (var i = 0; i < nOutputs; i++) { sumOutputs = sumOutputs + outputValues[i]; } diff --git a/zkp/circuits/lib/check-nullifiers.circom b/zkp/circuits/lib/check-nullifiers.circom index a3c33a9f..81a91322 100644 --- a/zkp/circuits/lib/check-nullifiers.circom +++ b/zkp/circuits/lib/check-nullifiers.circom @@ -27,17 +27,17 @@ include "../node_modules/circomlib/circuits/smt/smtverifier.circom"; // commitment = hash(value, salt, ownerPublicKey1, ownerPublicKey2) // nullifier = hash(value, salt, ownerPrivatekey) // -template CheckNullifiers(numInputs) { - signal input nullifiers[numInputs]; - signal input values[numInputs]; - signal input salts[numInputs]; +template CheckNullifiers(nInputs) { + signal input nullifiers[nInputs]; + signal input values[nInputs]; + signal input salts[nInputs]; // must be properly hashed and trimmed to be compatible with the BabyJub curve. // Reference: https://github.com/iden3/circomlib/blob/master/test/babyjub.js#L103 signal input ownerPrivateKey; // calculate the nullifier values from the input values - for (var i = 0; i < numInputs; i++) { + for (var i = 0; i < nInputs; i++) { var calculatedHash; calculatedHash = Poseidon(3)(inputs <== [values[i], salts[i], ownerPrivateKey]); diff --git a/zkp/circuits/lib/check-positive.circom b/zkp/circuits/lib/check-positive.circom index 9777e2b4..9b0ad71d 100644 --- a/zkp/circuits/lib/check-positive.circom +++ b/zkp/circuits/lib/check-positive.circom @@ -25,11 +25,11 @@ include "../node_modules/circomlib/circuits/smt/smtverifier.circom"; // // outputValues: array of values, as preimages for the output hashes, for the output utxos // -template CheckPositive(numOutputs) { - signal input outputValues[numOutputs]; +template CheckPositive(nOutputs) { + signal input outputValues[nOutputs]; // check that the output values are within the expected range. we don't allow negative values - for (var i = 0; i < numOutputs; i++) { + for (var i = 0; i < nOutputs; i++) { var greaterEqThanZero; greaterEqThanZero = GreaterEqThan(100)(in <== [outputValues[i], 0]); diff --git a/zkp/circuits/lib/check-smt-proof.circom b/zkp/circuits/lib/check-smt-proof.circom index 661a75a5..80e314bb 100644 --- a/zkp/circuits/lib/check-smt-proof.circom +++ b/zkp/circuits/lib/check-smt-proof.circom @@ -20,14 +20,14 @@ include "../node_modules/circomlib/circuits/smt/smtverifier.circom"; // CheckSMTProof is a general purpose circuit that checks the membership // inclusion proof of a set of hashes in a Sparse Merkle Tree // -template CheckSMTProof(numInputs, nSMTLevels) { - signal input leafNodeIndexes[numInputs]; - signal input leafNodeValues[numInputs]; +template CheckSMTProof(nInputs, nSMTLevels) { + signal input leafNodeIndexes[nInputs]; + signal input leafNodeValues[nInputs]; signal input root; - signal input merkleProof[numInputs][nSMTLevels]; - signal input enabled[numInputs]; + signal input merkleProof[nInputs][nSMTLevels]; + signal input enabled[nInputs]; - for (var i = 0; i < numInputs; i++) { + for (var i = 0; i < nInputs; i++) { var siblings[nSMTLevels]; for (var j = 0; j < nSMTLevels; j++) { siblings[j] = merkleProof[i][j]; diff --git a/zkp/circuits/lib/check-sum.circom b/zkp/circuits/lib/check-sum.circom index df804dca..8a199aeb 100644 --- a/zkp/circuits/lib/check-sum.circom +++ b/zkp/circuits/lib/check-sum.circom @@ -20,17 +20,17 @@ include "../node_modules/circomlib/circuits/comparators.circom"; // CheckSum is a circuit that checks that the sum of input values equals the sum of output values // -template CheckSum(numInputs, numOutputs) { - signal input inputValues[numInputs]; - signal input outputValues[numOutputs]; +template CheckSum(nInputs, nOutputs) { + signal input inputValues[nInputs]; + signal input outputValues[nOutputs]; // check that the sum of input values equals the sum of output values var sumInputs = 0; - for (var i = 0; i < numInputs; i++) { + for (var i = 0; i < nInputs; i++) { sumInputs = sumInputs + inputValues[i]; } var sumOutputs = 0; - for (var i = 0; i < numOutputs; i++) { + for (var i = 0; i < nOutputs; i++) { sumOutputs = sumOutputs + outputValues[i]; } diff --git a/zkp/circuits/lib/encrypt-outputs.circom b/zkp/circuits/lib/encrypt-outputs.circom index 90bba05c..fcc149c5 100644 --- a/zkp/circuits/lib/encrypt-outputs.circom +++ b/zkp/circuits/lib/encrypt-outputs.circom @@ -3,31 +3,31 @@ pragma circom 2.2.2; include "./ecdh.circom"; include "./encrypt.circom"; include "../node_modules/circomlib/circuits/babyjub.circom"; +include "./buses.circom"; // encrypts a list of output UTXO values & salts // with the corresponding shared ECDH keys for their // owners. A single ephemeral private key is used // to generate ECDH shared keys for different owners -template EncryptOutputs(numOutputs) { +template EncryptOutputs(nOutputs) { signal input ecdhPrivateKey; signal input encryptionNonce; - signal input outputValues[numOutputs]; - signal input outputSalts[numOutputs]; - signal input outputOwnerPublicKeys[numOutputs][2]; + input CommitmentInputs() commitmentInputs[nOutputs]; + // the output for the public key of the ephemeral private key used in generating ECDH shared key signal output ecdhPublicKey[2]; // the output for the list of encrypted output UTXOs cipher texts - signal output cipherTexts[numOutputs][4]; + signal output cipherTexts[nOutputs][4]; - for (var i = 0; i < numOutputs; i++) { + for (var i = 0; i < nOutputs; i++) { // generate shared secret var sharedSecret[2]; - sharedSecret = Ecdh()(privKey <== ecdhPrivateKey, pubKey <== outputOwnerPublicKeys[i]); + sharedSecret = Ecdh()(privKey <== ecdhPrivateKey, pubKey <== commitmentInputs[i].ownerPublicKey); // encrypt the value for the output UTXOs - cipherTexts[i] <== SymmetricEncrypt(2)(plainText <== [outputValues[i], outputSalts[i]], key <== sharedSecret, nonce <== encryptionNonce); + cipherTexts[i] <== SymmetricEncrypt(2)(plainText <== [commitmentInputs[i].value, commitmentInputs[i].salt], key <== sharedSecret, nonce <== encryptionNonce); } (ecdhPublicKey[0], ecdhPublicKey[1]) <== BabyPbk()(in <== ecdhPrivateKey); diff --git a/zkp/circuits/scripts/gen-config.json b/zkp/circuits/scripts/gen-config.json index 54db1677..f07acfe6 100644 --- a/zkp/circuits/scripts/gen-config.json +++ b/zkp/circuits/scripts/gen-config.json @@ -3,88 +3,71 @@ "circuits": { "anon": { "ptau": "powersOfTau28_hez_final_13", - "batchPtau": "powersOfTau28_hez_final_15", - "skipSolidityGenaration": false + "batchPtau": "powersOfTau28_hez_final_15" }, "anon_enc": { "ptau": "powersOfTau28_hez_final_15", - "batchPtau": "powersOfTau28_hez_final_17", - "skipSolidityGenaration": false + "batchPtau": "powersOfTau28_hez_final_17" }, "anon_nullifier_transfer": { "ptau": "powersOfTau28_hez_final_17", - "batchPtau": "powersOfTau28_hez_final_19", - "skipSolidityGenaration": false + "batchPtau": "powersOfTau28_hez_final_19" }, "anon_nullifier_transferLocked": { "ptau": "powersOfTau28_hez_final_17", - "batchPtau": "powersOfTau28_hez_final_19", - "skipSolidityGenaration": false + "batchPtau": "powersOfTau28_hez_final_19" }, "anon_nullifier_qurrency_transfer": { "ptau": "powersOfTau28_hez_final_22", - "batchPtau": "powersOfTau28_hez_final_22", - "skipSolidityGenaration": false + "batchPtau": "powersOfTau28_hez_final_22" }, "anon_nullifier_kyc": { "ptau": "powersOfTau28_hez_final_17", - "batchPtau": "powersOfTau28_hez_final_19", - "skipSolidityGenaration": false + "batchPtau": "powersOfTau28_hez_final_19" }, "anon_enc_nullifier_non_repudiation": { "ptau": "powersOfTau28_hez_final_17", - "batchPtau": "powersOfTau28_hez_final_19", - "skipSolidityGenaration": false + "batchPtau": "powersOfTau28_hez_final_19" }, "anon_enc_nullifier": { "ptau": "powersOfTau28_hez_final_17", - "batchPtau": "powersOfTau28_hez_final_19", - "skipSolidityGenaration": false + "batchPtau": "powersOfTau28_hez_final_19" }, "anon_enc_nullifier_kyc": { "ptau": "powersOfTau28_hez_final_17", - "batchPtau": "powersOfTau28_hez_final_20", - "skipSolidityGenaration": false + "batchPtau": "powersOfTau28_hez_final_20" }, "nf_anon": { - "ptau": "powersOfTau28_hez_final_13", - "skipSolidityGenaration": false + "ptau": "powersOfTau28_hez_final_13" }, "nf_anon_nullifier_transfer": { - "ptau": "powersOfTau28_hez_final_16", - "skipSolidityGenaration": false + "ptau": "powersOfTau28_hez_final_16" }, "nf_anon_nullifier_transferLocked": { - "ptau": "powersOfTau28_hez_final_16", - "skipSolidityGenaration": false + "ptau": "powersOfTau28_hez_final_16" }, "deposit": { - "ptau": "powersOfTau28_hez_final_11", - "skipSolidityGenaration": false + "ptau": "powersOfTau28_hez_final_11" }, "withdraw": { "ptau": "powersOfTau28_hez_final_13", - "batchPtau": "powersOfTau28_hez_final_14", - "skipSolidityGenaration": false + "batchPtau": "powersOfTau28_hez_final_14" }, "withdraw_nullifier": { "ptau": "powersOfTau28_hez_final_17", - "batchPtau": "powersOfTau28_hez_final_19", - "skipSolidityGenaration": false + "batchPtau": "powersOfTau28_hez_final_19" }, "check_nullifiers": { "ptau": "powersOfTau28_hez_final_13", - "skipSolidityGenaration": true + "skipSolidityGeneration": true }, "burn": { "ptau": "powersOfTau28_hez_final_13", - "batchPtau": "powersOfTau28_hez_final_14", - "skipSolidityGenaration": false + "batchPtau": "powersOfTau28_hez_final_14" }, "burn_nullifier": { "ptau": "powersOfTau28_hez_final_17", - "batchPtau": "powersOfTau28_hez_final_19", - "skipSolidityGenaration": false + "batchPtau": "powersOfTau28_hez_final_19" } } } diff --git a/zkp/circuits/scripts/gen.js b/zkp/circuits/scripts/gen.js index a9af75f9..1b253ecc 100644 --- a/zkp/circuits/scripts/gen.js +++ b/zkp/circuits/scripts/gen.js @@ -1,43 +1,43 @@ -const fs = require("fs"); -const path = require("path"); -const { exec } = require("child_process"); -const { promisify } = require("util"); -const axios = require("axios"); -const yargs = require("yargs/yargs"); +const fs = require('fs'); +const path = require('path'); +const { exec } = require('child_process'); +const { promisify } = require('util'); +const axios = require('axios'); +const yargs = require('yargs/yargs'); const blake = require('blakejs'); -const { hideBin } = require("yargs/helpers"); +const { hideBin } = require('yargs/helpers'); const argv = yargs(hideBin(process.argv)) - .option("c", { - alias: "circuit", - describe: "Specify a single circuit to build", - type: "string", + .option('c', { + alias: 'circuit', + describe: 'Specify a single circuit to build', + type: 'string', }) - .option("v", { - alias: "verbose", - describe: "Enable verbose mode", - type: "boolean", + .option('v', { + alias: 'verbose', + describe: 'Enable verbose mode', + type: 'boolean', default: false, }) - .option("cp", { - alias: "compileOnly", - describe: "Compile only", - type: "boolean", + .option('cp', { + alias: 'compileOnly', + describe: 'Compile only', + type: 'boolean', default: false, }) - .option("cr", { - alias: "circuitsRoot", - describe: "Specify the root folder for storing circuits compilation files", - type: "string", + .option('cr', { + alias: 'circuitsRoot', + describe: 'Specify the root folder for storing circuits compilation files', + type: 'string', }) - .option("pk", { - alias: "provingKeysRoot", - describe: "Specify the root folder for storing generated proving keys", - type: "string", + .option('pk', { + alias: 'provingKeysRoot', + describe: 'Specify the root folder for storing generated proving keys', + type: 'string', }) - .option("pt", { - alias: "ptauDownloadPath", - describe: "Specify the root folder for storing downloaded PTAU", - type: "string", + .option('pt', { + alias: 'ptauDownloadPath', + describe: 'Specify the root folder for storing downloaded PTAU', + type: 'string', }).argv; const circuitsRoot = process.env.CIRCUITS_ROOT || argv.circuitsRoot; @@ -50,22 +50,22 @@ const parallelLimit = parseInt(process.env.GEN_CONCURRENCY, 10) || 8; // Default // check env vars if (!circuitsRoot) { - console.error("Error: CIRCUITS_ROOT is not set."); + console.error('Error: CIRCUITS_ROOT is not set.'); process.exit(1); } if (!compileOnly && !provingKeysRoot) { - console.error("Error: PROVING_KEYS_ROOT is not set."); + console.error('Error: PROVING_KEYS_ROOT is not set.'); process.exit(1); } if (!compileOnly && !ptauDownload) { - console.error("Error: PTAU_DOWNLOAD_PATH is not set."); + console.error('Error: PTAU_DOWNLOAD_PATH is not set.'); process.exit(1); } console.log( - "Generating circuits with the following settings:\n" + + 'Generating circuits with the following settings:\n' + JSON.stringify( { specificCircuits, @@ -77,21 +77,21 @@ console.log( ptauDownload, }, null, - 2, + 2 ) + - "\n", + '\n' ); // load configuration -const genConfig = require("./gen-config.json"); +const genConfig = require('./gen-config.json'); const circuits = genConfig.circuits; const toCamelCase = (str) => { return str - .split("_") + .split('_') .map((word) => word.charAt(0).toUpperCase() + word.slice(1)) - .join(""); + .join(''); }; // util functions @@ -102,50 +102,45 @@ const timestamp = () => new Date().toISOString(); const logPrefix = (circuit) => `[${timestamp()}] [${circuit}]`; const log = (circuit, message) => { - console.log(logPrefix(circuit) + " " + message); + console.log(logPrefix(circuit) + ' ' + message); }; const calculateHash = async (ptauFile) => { - return new Promise ((resolve, reject) => { + return new Promise((resolve, reject) => { const context = blake.blake2bInit(64, null); const ptauStream = fs.createReadStream(ptauFile); - ptauStream.on('data', chunk => { + ptauStream.on('data', (chunk) => { blake.blake2bUpdate(context, chunk); }); ptauStream.on('end', () => { const computedHashBytes = blake.blake2bFinal(context); - const computedHash = Buffer.from(computedHashBytes).toString("hex"); + const computedHash = Buffer.from(computedHashBytes).toString('hex'); resolve(computedHash); }); - ptauStream.on('error', err => { + ptauStream.on('error', (err) => { reject(err); }); }); }; const downloadAndVerifyPtau = async (ptau) => { - const ptauFile = path.join(ptauDownload, `${ptau}.ptau`); if (!compileOnly && !fs.existsSync(ptauFile)) { log(ptau, `PTAU file does not exist, downloading and verifying`); try { - const response = await axios.get( - `https://storage.googleapis.com/zkevm/ptau/${ptau}.ptau`, - { - responseType: "stream", - }, - ); + const response = await axios.get(`https://storage.googleapis.com/zkevm/ptau/${ptau}.ptau`, { + responseType: 'stream', + }); const writer = fs.createWriteStream(ptauFile); response.data.pipe(writer); await new Promise((resolve, reject) => { - writer.on("finish", resolve); - writer.on("error", reject); + writer.on('finish', resolve); + writer.on('error', reject); }); - } catch (error) { log(ptau, `Failed to download PTAU file: ${error}`); process.exit(1); @@ -153,10 +148,9 @@ const downloadAndVerifyPtau = async (ptau) => { // Compute blake2b hash and compare to expected value try { - const computedHash = await calculateHash(ptauFile); - const ptauHashes = require("./ptau_valid_hashes.json"); + const ptauHashes = require('./ptau_valid_hashes.json'); const expectedHash = ptauHashes[`${ptau}`]; if (verbose) { @@ -167,7 +161,7 @@ const downloadAndVerifyPtau = async (ptau) => { if (expectedHash != computedHash) { throw new Error(`${ptau} Expected PTAU hash ${expectedHash}, got ${computedHash}`); } else { - log(ptau, "Verification successful"); + log(ptau, 'Verification successful'); } } catch (error) { log(ptau, `Failed to validate PTAU file: ${error}`); @@ -177,8 +171,8 @@ const downloadAndVerifyPtau = async (ptau) => { }; // main circuit process logic -const processCircuit = async (circuit, ptau, skipSolidityGenaration) => { - const circomInput = path.join(__dirname, "../", `${circuit}.circom`); +const processCircuit = async (circuit, ptau, skipSolidityGeneration) => { + const circomInput = path.join(__dirname, '../', `${circuit}.circom`); const ptauFile = path.join(ptauDownload, `${ptau}.ptau`); const zkeyOutput = path.join(provingKeysRoot, `${circuit}.zkey`); @@ -188,103 +182,73 @@ const processCircuit = async (circuit, ptau, skipSolidityGenaration) => { } log(circuit, `Compiling circuit`); - const { stdout: cmOut, stderr: cmErr } = await execAsync( - `circom ${circomInput} --output ${circuitsRoot} --sym --wasm`, - ); + const { stdout: cmOut, stderr: cmErr } = await execAsync(`circom ${circomInput} --output ${circuitsRoot} --sym --wasm`); if (verbose) { if (cmOut) { - log(circuit, "compile output:\n" + cmOut); + log(circuit, 'compile output:\n' + cmOut); } if (cmErr) { - log(circuit, "compile error:\n" + cmErr); + log(circuit, 'compile error:\n' + cmErr); } } if (compileOnly) { return; } - const { stdout: ctOut, stderr: ctErr } = await execAsync( - `circom ${circomInput} --output ${provingKeysRoot} --r1cs`, - ); + const { stdout: ctOut, stderr: ctErr } = await execAsync(`circom ${circomInput} --output ${provingKeysRoot} --r1cs`); if (verbose) { if (ctOut) { - log(circuit, "constraint generation output:\n" + ctOut); - const { stdout: csOut } = await execAsync( - `npx snarkjs r1cs print ${provingKeysRoot}/${circuit}.r1cs ${circuitsRoot}/${circuit}.sym `, - ); + log(circuit, 'constraint generation output:\n' + ctOut); + const { stdout: csOut } = await execAsync(`npx snarkjs r1cs print ${provingKeysRoot}/${circuit}.r1cs ${circuitsRoot}/${circuit}.sym `); // log(circuit, "constraints:\n" + csOut); } if (ctErr) { - log(circuit, "constraint error:\n" + ctErr); + log(circuit, 'constraint error:\n' + ctErr); } } log(circuit, `Generating test proving key with ${ptau}`); - const { stdout: pkOut, stderr: pkErr } = await execAsync( - `npx snarkjs groth16 setup ${path.join( - provingKeysRoot, - `${circuit}.r1cs`, - )} ${ptauFile} ${zkeyOutput}`, - ); + const { stdout: pkOut, stderr: pkErr } = await execAsync(`npx snarkjs groth16 setup ${path.join(provingKeysRoot, `${circuit}.r1cs`)} ${ptauFile} ${zkeyOutput}`); if (verbose) { if (pkOut) { // log(circuit, "test proving key generation output:\n" + pkOut); } if (pkErr) { - log(circuit, "test proving key generation error:\n" + pkErr); + log(circuit, 'test proving key generation error:\n' + pkErr); } } log(circuit, `Exporting verification key`); - const { stdout: vkOut, stderr: vkErr } = await execAsync( - `npx snarkjs zkey export verificationkey ${zkeyOutput} ${path.join( - provingKeysRoot, - `${circuit}-vkey.json`, - )}`, - ); + const { stdout: vkOut, stderr: vkErr } = await execAsync(`npx snarkjs zkey export verificationkey ${zkeyOutput} ${path.join(provingKeysRoot, `${circuit}-vkey.json`)}`); if (verbose) { if (vkOut) { // log(circuit, "verification key export output:\n" + vkOut); } if (vkErr) { - log(circuit, "verification key export error:\n" + vkErr); + log(circuit, 'verification key export error:\n' + vkErr); } } - if (skipSolidityGenaration) { + if (skipSolidityGeneration) { log(circuit, `Skipping solidity verifier generation`); return; } log(circuit, `Generating solidity verifier`); - const solidityFile = path.join( - __dirname, - "..", - "..", - "..", - "solidity", - "contracts", - "verifiers", - `verifier_${circuit}.sol`, - ); - const { stdout: svOut, stderr: svErr } = await execAsync( - `npx snarkjs zkey export solidityverifier ${zkeyOutput} ${solidityFile}`, - ); + const solidityFile = path.join(__dirname, '..', '..', '..', 'solidity', 'contracts', 'verifiers', `verifier_${circuit}.sol`); + const { stdout: svOut, stderr: svErr } = await execAsync(`npx snarkjs zkey export solidityverifier ${zkeyOutput} ${solidityFile}`); if (verbose) { if (svOut) { - log(circuit, "solidity verifier export output:\n" + svOut); + log(circuit, 'solidity verifier export output:\n' + svOut); } if (svErr) { - log(circuit, "solidity verifier export error:\n" + svErr); + log(circuit, 'solidity verifier export error:\n' + svErr); } } log(circuit, `Modifying the contract name in the Solidity file`); const camelCaseCircuitName = toCamelCase(circuit); const solidityFileTmp = `${solidityFile}.tmp`; - const fileContent = fs.readFileSync(solidityFile, "utf8"); - const updatedContent = fileContent.replace( - " Groth16Verifier ", - ` Groth16Verifier_${camelCaseCircuitName} `, - ); + const fileContent = fs.readFileSync(solidityFile, 'utf8'); + const updatedContent = fileContent.replace(' Groth16Verifier ', ` Groth16Verifier_${camelCaseCircuitName} `); fs.writeFileSync(solidityFileTmp, updatedContent); fs.renameSync(solidityFileTmp, solidityFile); log(circuit, `Circuit process complete`); @@ -310,34 +274,32 @@ const run = async () => { const activePromises = new Set(); let snarkjsVersion; - // first check cirom version and snarkjs version matches the one in the package.json + // first check circom version and snarkjs version matches the one in the package.json try { - const { stdout: circomVersion } = await execAsync("circom --version"); + const { stdout: circomVersion } = await execAsync('circom --version'); // Trigger error to get snarkjs version try { - await execAsync("npx snarkjs --version"); + await execAsync('npx snarkjs --version'); } catch (error) { // Extract snarkjs version from error message snarkjsVersion = error.stdout.match(/snarkjs@([\d.]+)/)?.[1]; if (!snarkjsVersion) { - throw new Error("Failed to extract SnarkJS version from error output."); + throw new Error('Failed to extract SnarkJS version from error output.'); } } - const { stdout: packageJson } = await execAsync("cat package.json"); + const { stdout: packageJson } = await execAsync('cat package.json'); const packageJsonObj = JSON.parse(packageJson); const expectedCircomVersion = genConfig.circomVersion; // Sanitize and extract version numbers - const circomVersionTrimmed = circomVersion - .trim() - .replace("circom compiler ", ""); + const circomVersionTrimmed = circomVersion.trim().replace('circom compiler ', ''); let hasMismatch = false; if (circomVersionTrimmed !== expectedCircomVersion) { console.error( `Error: circom version mismatch with the version in gen-config.json :\n` + `\tExpected circom: ${expectedCircomVersion}, got: ${circomVersionTrimmed}\n` + - `\tFollow https://docs.circom.io/getting-started/installation/ to update your circom\n`, + `\tFollow https://docs.circom.io/getting-started/installation/ to update your circom\n` ); hasMismatch = true; } @@ -346,7 +308,7 @@ const run = async () => { console.error( `Error: snarkjs version mismatch with package.json:\n` + `\tExpected snarkjs: ${packageJsonObj.devDependencies.snarkjs}, got: ${snarkjsVersion}\n` + - `\tUse npm to update your snarkjs node module\n`, + `\tUse npm to update your snarkjs node module\n` ); hasMismatch = true; } @@ -354,7 +316,7 @@ const run = async () => { process.exit(1); } - console.log("Version check passed."); + console.log('Version check passed.'); } catch (error) { console.error(`An error occurred: ${error.message}`); process.exit(1); @@ -362,10 +324,7 @@ const run = async () => { // Download all PTAU files that we need var allPtaus = new Set(); - for (const [ - circuit, - { ptau, skipSolidityGenaration, batchPtau }, - ] of circuitsArray) { + for (const [circuit, { ptau, batchPtau }] of circuitsArray) { if (onlyCircuits && !onlyCircuits.includes(circuit)) { continue; } @@ -384,15 +343,12 @@ const run = async () => { await downloadAndVerifyPtau(p); } - for (const [ - circuit, - { ptau, skipSolidityGenaration, batchPtau }, - ] of circuitsArray) { + for (const [circuit, { ptau, skipSolidityGeneration, batchPtau }] of circuitsArray) { if (onlyCircuits && !onlyCircuits.includes(circuit)) { continue; } - const pcPromise = processCircuit(circuit, ptau, skipSolidityGenaration); + const pcPromise = processCircuit(circuit, ptau, skipSolidityGeneration); activePromises.add(pcPromise); if (activePromises.size >= parallelLimit) { @@ -400,11 +356,7 @@ const run = async () => { } if (batchPtau) { - const pcBatchPromise = processCircuit( - circuit + "_batch", - batchPtau, - skipSolidityGenaration, - ); + const pcBatchPromise = processCircuit(circuit + '_batch', batchPtau, skipSolidityGeneration); activePromises.add(pcBatchPromise); if (activePromises.size >= parallelLimit) { diff --git a/zkp/js/lib/util.js b/zkp/js/lib/util.js index ef541b7a..b4bfc70c 100644 --- a/zkp/js/lib/util.js +++ b/zkp/js/lib/util.js @@ -14,10 +14,10 @@ // See the License for the specific language governing permissions and // limitations under the License. -const { genRandomSalt } = require('maci-crypto'); -const { poseidon4: poseidon, poseidon2 } = require('poseidon-lite'); -const { solidityPackedKeccak256 } = require('ethers'); -const { createHash, randomBytes } = require('crypto'); +const { genRandomSalt } = require("maci-crypto"); +const { poseidon4: poseidon, poseidon2 } = require("poseidon-lite"); +const { solidityPackedKeccak256 } = require("ethers"); +const { createHash, randomBytes } = require("crypto"); // The ciphertext is produced inside the ZKP circuit. The following are // the index of the ciphertext in the witness array, which is dependent on the circuit. @@ -35,14 +35,16 @@ function newSalt() { // per the encryption scheme in ../circuits/lib/encrypt.circom, // the nonce must not be larger than 2^128 function newEncryptionNonce() { - const hex = randomBytes(16).toString('hex'); + const hex = randomBytes(16).toString("hex"); const nonce = BigInt(`0x${hex}`); return nonce; } -const two128 = BigInt('340282366920938463463374607431768211456'); +const two128 = BigInt("340282366920938463463374607431768211456"); // Field modulus for BN254 -const F = BigInt('21888242871839275222246405745257275088548364400416034343698204186575808495617'); +const F = BigInt( + "21888242871839275222246405745257275088548364400416034343698204186575808495617", +); // Implements the encryption and decryption functions using Poseidon hash // as described: https://drive.google.com/file/d/1EVrP3DzoGbmzkRmYnyEDcIQcXVU7GlOd/view @@ -118,10 +120,22 @@ function poseidonDecrypt(ciphertext, key, nonce, length) { // If length > 3, check if the last (3 - (l mod 3)) elements of the message are 0 if (length > 3) { if (length % 3 === 2) { - checkEqual(message[message.length - 1], 0n, 'The last element of the message must be 0'); + checkEqual( + message[message.length - 1], + 0n, + "The last element of the message must be 0", + ); } else if (length % 3 === 1) { - checkEqual(message[message.length - 1], 0n, 'The last element of the message must be 0'); - checkEqual(message[message.length - 2], 0n, 'The second to last element of the message must be 0'); + checkEqual( + message[message.length - 1], + 0n, + "The last element of the message must be 0", + ); + checkEqual( + message[message.length - 2], + 0n, + "The second to last element of the message must be 0", + ); } } @@ -129,7 +143,11 @@ function poseidonDecrypt(ciphertext, key, nonce, length) { state = poseidon(state, 4); // Check the last ciphertext element - checkEqual(ciphertext[ciphertext.length - 1], state[1], 'The last ciphertext element must match the second item of the permuted state'); + checkEqual( + ciphertext[ciphertext.length - 1], + state[1], + "The last ciphertext element must match the second item of the permuted state", + ); return message.slice(0, length); } @@ -153,24 +171,24 @@ function addMod(a, b) { function validateInputs(msg, key, nonce, length) { if (!Array.isArray(msg)) { - throw new Error('The message must be an array'); + throw new Error("The message must be an array"); } for (let i = 0; i < msg.length; i += 1) { - if (typeof msg[i] !== 'bigint') { - throw new Error('Each message element must be a BigInt'); + if (typeof msg[i] !== "bigint") { + throw new Error("Each message element must be a BigInt"); } } if (key.length !== 2) { - throw new Error('The key must be an array of two elements'); + throw new Error("The key must be an array of two elements"); } - if (typeof key[0] !== 'bigint' || typeof key[1] !== 'bigint') { - throw new Error('The key must be an array of two BigInts'); + if (typeof key[0] !== "bigint" || typeof key[1] !== "bigint") { + throw new Error("The key must be an array of two BigInts"); } - if (typeof nonce !== 'bigint') { - throw new Error('The nonce must be a BigInt'); + if (typeof nonce !== "bigint") { + throw new Error("The nonce must be a BigInt"); } if (length && length < 1) { - throw new Error('The length must be at least 1'); + throw new Error("The length must be at least 1"); } } @@ -198,15 +216,15 @@ function getProofHash(encodedProof) { BigInt(encodedProof.pC[0]), BigInt(encodedProof.pC[1]), ]; - const hash = solidityPackedKeccak256(['uint[8]'], [flat]); + const hash = solidityPackedKeccak256(["uint[8]"], [flat]); return hash; } function tokenUriHash(tokenUri) { - const hash = createHash('sha256').update(tokenUri).digest('hex'); + const hash = createHash("sha256").update(tokenUri).digest("hex"); // to fit the result within the range of the Finite Field used in the poseidon hash, // use 253 bit long numbers. we need to remove the most significant three bits. - return BigInt.asUintN(253, '0x' + hash); + return BigInt.asUintN(253, "0x" + hash); } function kycHash(bjjPublicKey) { diff --git a/zkp/js/test/anon_enc_nullifier_kyc.js b/zkp/js/test/anon_enc_nullifier_kyc.js index fb0e9b5d..5b4f1e6d 100644 --- a/zkp/js/test/anon_enc_nullifier_kyc.js +++ b/zkp/js/test/anon_enc_nullifier_kyc.js @@ -87,7 +87,8 @@ describe("main circuit tests for Zeto fungible tokens with encryption and anonym await smtKYC.add(identity2, identity2); }); - it("should succeed for valid witness and produce an encypted value", async () => { + it("should succeed for valid witness and produce an encypted value", async function() { + this.timeout(60000); const inputValues = [32, 40]; const outputValues = [20, 52]; @@ -352,7 +353,7 @@ describe("main circuit tests for Zeto fungible tokens with encryption and anonym err = e; } // console.log(err); - expect(err).to.match(/Error in template Zeto_267 line: 102/); + expect(err).to.match(/Error in template Zeto_267 line: 110/); expect(err).to.match(/Error in template CheckSMTProof_253 line: 38/); }); }); diff --git a/zkp/js/test/anon_enc_nullifier_non_repudiation.js b/zkp/js/test/anon_enc_nullifier_non_repudiation.js index 3423e403..4b1396ae 100644 --- a/zkp/js/test/anon_enc_nullifier_non_repudiation.js +++ b/zkp/js/test/anon_enc_nullifier_non_repudiation.js @@ -81,7 +81,8 @@ describe("main circuit tests for Zeto fungible tokens with encryption for non-re smtBob = new Merkletree(storage2, true, SMT_HEIGHT); }); - it("should succeed for valid witness, produce an encypted value and regulator is able to decrypt", async () => { + it("should succeed for valid witness, produce an encypted value and regulator is able to decrypt", async function() { + this.timeout(60000); const inputValues = [32, 40]; const outputValues = [20, 52]; diff --git a/zkp/js/test/anon_nullifier_qurrency.js b/zkp/js/test/anon_nullifier_qurrency.js index 90cc44dd..2a925e95 100644 --- a/zkp/js/test/anon_nullifier_qurrency.js +++ b/zkp/js/test/anon_nullifier_qurrency.js @@ -14,13 +14,18 @@ // See the License for the specific language governing permissions and // limitations under the License. -const { expect } = require('chai'); -const { join } = require('path'); -const crypto = require('crypto'); -const { wasm: wasm_tester } = require('circom_tester'); -const { genKeypair, formatPrivKeyForBabyJub } = require('maci-crypto'); -const { Merkletree, InMemoryDB, str2Bytes, ZERO_HASH } = require('@iden3/js-merkletree'); -const { Poseidon, newSalt } = require('../index.js'); +const { expect } = require("chai"); +const { join } = require("path"); +const crypto = require("crypto"); +const { wasm: wasm_tester } = require("circom_tester"); +const { genKeypair, formatPrivKeyForBabyJub } = require("maci-crypto"); +const { + Merkletree, + InMemoryDB, + str2Bytes, + ZERO_HASH, +} = require("@iden3/js-merkletree"); +const { Poseidon, newSalt } = require("../index.js"); const SMT_HEIGHT = 64; const poseidonHash = Poseidon.poseidon4; @@ -29,11 +34,18 @@ const poseidonHash3 = Poseidon.poseidon3; // a message is a 256-bit number, each as a separate signal // using 1665 instead of 1 as this is the constant used by Kyber const m = [ - 1665, 1665, 0, 1665, 0, 1665, 1665, 0, 1665, 0, 0, 1665, 1665, 1665, 1665, 0, 0, 1665, 0, 0, 0, 1665, 1665, 0, 1665, 0, 1665, 0, 0, 1665, 1665, 0, 0, 1665, 0, 0, 1665, 1665, 1665, 0, 0, 0, 0, 0, 0, - 1665, 0, 0, 1665, 0, 0, 1665, 0, 1665, 1665, 0, 1665, 1665, 0, 0, 1665, 1665, 1665, 0, 0, 0, 0, 0, 0, 1665, 0, 0, 1665, 1665, 0, 0, 0, 1665, 1665, 0, 1665, 1665, 1665, 1665, 0, 1665, 1665, 0, 1665, - 1665, 1665, 1665, 0, 1665, 1665, 0, 0, 0, 1665, 1665, 0, 1665, 1665, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 1665, 1665, 0, 1665, 0, 1665, 1665, 0, 1665, 0, 0, 1665, 1665, 1665, 1665, 0, + 0, 1665, 0, 0, 0, 1665, 1665, 0, 1665, 0, 1665, 0, 0, 1665, 1665, 0, 0, 1665, + 0, 0, 1665, 1665, 1665, 0, 0, 0, 0, 0, 0, 1665, 0, 0, 1665, 0, 0, 1665, 0, + 1665, 1665, 0, 1665, 1665, 0, 0, 1665, 1665, 1665, 0, 0, 0, 0, 0, 0, 1665, 0, + 0, 1665, 1665, 0, 0, 0, 1665, 1665, 0, 1665, 1665, 1665, 1665, 0, 1665, 1665, + 0, 1665, 1665, 1665, 1665, 0, 1665, 1665, 0, 0, 0, 1665, 1665, 0, 1665, 1665, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ]; // dummy randomness. keep this as is so that the circuit will generate the same @@ -41,36 +53,70 @@ const m = [ // ciphertext in the witness array. For real world usage, this should be replaced with // a random number generated by a proper random number generator. const randomness = [ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ]; // this is the encrypted result from the message above, using the dummy randomness // and the built-in Kyber public key inside the circuit (lib/kyber/kyber.circom) const hack = [ - 153, 180, 68, 235, 189, 233, 191, 4, 236, 89, 22, 35, 178, 239, 102, 163, 71, 123, 55, 19, 165, 82, 197, 168, 222, 159, 54, 198, 122, 202, 46, 61, 71, 249, 202, 155, 165, 186, 117, 41, 235, 141, 35, - 149, 53, 129, 42, 95, 212, 128, 192, 80, 112, 120, 127, 192, 205, 189, 251, 33, 173, 173, 209, 111, 0, 208, 195, 74, 118, 98, 48, 178, 40, 203, 127, 185, 133, 93, 106, 112, 154, 50, 56, 184, 51, 20, - 48, 2, 153, 106, 230, 56, 31, 252, 43, 23, 133, 140, 101, 183, 92, 250, 234, 28, 192, 208, 54, 250, 254, 120, 214, 74, 140, 53, 236, 105, 36, 182, 61, 100, 161, 226, 69, 83, 148, 134, 252, 102, 226, - 97, 203, 135, 10, 211, 251, 52, 154, 236, 218, 31, 236, 237, 252, 36, 25, 28, 150, 249, 52, 121, 152, 78, 9, 180, 23, 211, 126, 133, 153, 69, 197, 208, 190, 241, 118, 207, 183, 27, 127, 51, 78, 77, - 203, 153, 57, 21, 165, 163, 218, 41, 72, 219, 42, 130, 246, 112, 178, 196, 125, 46, 249, 103, 12, 28, 209, 111, 134, 22, 178, 180, 248, 88, 239, 238, 183, 191, 191, 235, 219, 239, 102, 91, 90, 37, - 218, 170, 234, 76, 91, 208, 38, 23, 74, 215, 14, 49, 149, 60, 145, 150, 3, 11, 251, 182, 73, 231, 14, 95, 217, 195, 182, 171, 2, 171, 19, 234, 75, 157, 205, 141, 181, 171, 227, 213, 212, 44, 159, - 98, 183, 226, 99, 144, 219, 130, 92, 110, 65, 184, 4, 2, 228, 3, 159, 193, 180, 197, 79, 248, 55, 139, 73, 238, 189, 48, 102, 251, 155, 199, 19, 14, 205, 136, 186, 253, 214, 230, 253, 171, 217, 157, - 23, 191, 73, 242, 132, 144, 134, 38, 255, 202, 79, 191, 124, 17, 103, 7, 55, 166, 5, 16, 82, 103, 169, 250, 141, 231, 235, 218, 185, 26, 125, 37, 95, 68, 72, 248, 78, 214, 49, 88, 204, 17, 106, 221, - 149, 143, 225, 254, 230, 120, 5, 166, 34, 200, 9, 60, 204, 9, 72, 205, 85, 231, 104, 186, 17, 172, 183, 67, 222, 23, 184, 112, 235, 253, 54, 150, 70, 42, 73, 68, 233, 174, 108, 200, 42, 240, 108, - 88, 54, 31, 217, 176, 29, 139, 231, 201, 132, 118, 104, 205, 47, 226, 184, 119, 199, 152, 49, 164, 123, 255, 16, 176, 83, 10, 140, 215, 228, 222, 202, 64, 88, 213, 123, 106, 246, 53, 208, 42, 2, 43, - 80, 203, 8, 155, 12, 216, 15, 221, 82, 20, 137, 22, 99, 66, 254, 146, 238, 82, 139, 25, 202, 33, 89, 156, 30, 48, 226, 103, 130, 148, 197, 126, 23, 131, 211, 75, 155, 62, 231, 73, 32, 151, 196, 231, - 226, 0, 249, 180, 140, 111, 18, 4, 60, 240, 76, 199, 81, 248, 84, 10, 117, 15, 191, 189, 209, 163, 146, 37, 185, 128, 54, 214, 175, 96, 215, 150, 138, 140, 228, 102, 60, 133, 11, 185, 130, 110, 160, - 121, 197, 129, 57, 150, 43, 222, 191, 64, 80, 107, 122, 33, 132, 67, 85, 141, 97, 124, 82, 173, 216, 224, 102, 220, 210, 24, 51, 192, 167, 135, 19, 212, 218, 170, 74, 105, 104, 58, 237, 203, 181, - 197, 77, 23, 92, 210, 143, 195, 129, 37, 205, 61, 98, 61, 112, 36, 245, 192, 225, 83, 81, 159, 134, 235, 86, 221, 172, 191, 213, 5, 131, 183, 118, 196, 78, 206, 255, 9, 32, 58, 10, 189, 63, 95, 45, - 85, 106, 74, 115, 51, 112, 123, 59, 45, 148, 13, 237, 84, 223, 249, 210, 176, 16, 228, 207, 248, 180, 91, 210, 71, 150, 167, 205, 123, 140, 39, 66, 3, 110, 249, 38, 86, 41, 181, 163, 96, 211, 181, - 98, 58, 133, 136, 250, 23, 117, 4, 207, 219, 168, 118, 85, 200, 123, 30, 143, 56, 117, 197, 242, 205, 130, 45, 200, 77, 51, 56, 31, 41, 151, 118, 118, 162, 204, 65, 112, 243, 109, 142, 224, 81, 250, - 103, 25, 91, 9, 189, 105, 23, 75, 95, 167, 149, 49, 103, 76, 105, 74, 67, 75, 3, 43, 103, 30, 157, 71, 34, 103, 136, 198, 229, 206, 182, 11, 255, 246, 247, 16, 221, 142, 40, 137, 89, 63, 23, 151, - 111, 31, 74, 70, 38, 210, 240, 18, 209, 62, 111, 84, 203, 151, 195, 212, 18, 203, 83, 2, 98, 120, 73, 251, 3, 220, 241, 162, 8, 76, 55, 163, 201, 118, 42, + 153, 180, 68, 235, 189, 233, 191, 4, 236, 89, 22, 35, 178, 239, 102, 163, 71, + 123, 55, 19, 165, 82, 197, 168, 222, 159, 54, 198, 122, 202, 46, 61, 71, 249, + 202, 155, 165, 186, 117, 41, 235, 141, 35, 149, 53, 129, 42, 95, 212, 128, + 192, 80, 112, 120, 127, 192, 205, 189, 251, 33, 173, 173, 209, 111, 0, 208, + 195, 74, 118, 98, 48, 178, 40, 203, 127, 185, 133, 93, 106, 112, 154, 50, 56, + 184, 51, 20, 48, 2, 153, 106, 230, 56, 31, 252, 43, 23, 133, 140, 101, 183, + 92, 250, 234, 28, 192, 208, 54, 250, 254, 120, 214, 74, 140, 53, 236, 105, 36, + 182, 61, 100, 161, 226, 69, 83, 148, 134, 252, 102, 226, 97, 203, 135, 10, + 211, 251, 52, 154, 236, 218, 31, 236, 237, 252, 36, 25, 28, 150, 249, 52, 121, + 152, 78, 9, 180, 23, 211, 126, 133, 153, 69, 197, 208, 190, 241, 118, 207, + 183, 27, 127, 51, 78, 77, 203, 153, 57, 21, 165, 163, 218, 41, 72, 219, 42, + 130, 246, 112, 178, 196, 125, 46, 249, 103, 12, 28, 209, 111, 134, 22, 178, + 180, 248, 88, 239, 238, 183, 191, 191, 235, 219, 239, 102, 91, 90, 37, 218, + 170, 234, 76, 91, 208, 38, 23, 74, 215, 14, 49, 149, 60, 145, 150, 3, 11, 251, + 182, 73, 231, 14, 95, 217, 195, 182, 171, 2, 171, 19, 234, 75, 157, 205, 141, + 181, 171, 227, 213, 212, 44, 159, 98, 183, 226, 99, 144, 219, 130, 92, 110, + 65, 184, 4, 2, 228, 3, 159, 193, 180, 197, 79, 248, 55, 139, 73, 238, 189, 48, + 102, 251, 155, 199, 19, 14, 205, 136, 186, 253, 214, 230, 253, 171, 217, 157, + 23, 191, 73, 242, 132, 144, 134, 38, 255, 202, 79, 191, 124, 17, 103, 7, 55, + 166, 5, 16, 82, 103, 169, 250, 141, 231, 235, 218, 185, 26, 125, 37, 95, 68, + 72, 248, 78, 214, 49, 88, 204, 17, 106, 221, 149, 143, 225, 254, 230, 120, 5, + 166, 34, 200, 9, 60, 204, 9, 72, 205, 85, 231, 104, 186, 17, 172, 183, 67, + 222, 23, 184, 112, 235, 253, 54, 150, 70, 42, 73, 68, 233, 174, 108, 200, 42, + 240, 108, 88, 54, 31, 217, 176, 29, 139, 231, 201, 132, 118, 104, 205, 47, + 226, 184, 119, 199, 152, 49, 164, 123, 255, 16, 176, 83, 10, 140, 215, 228, + 222, 202, 64, 88, 213, 123, 106, 246, 53, 208, 42, 2, 43, 80, 203, 8, 155, 12, + 216, 15, 221, 82, 20, 137, 22, 99, 66, 254, 146, 238, 82, 139, 25, 202, 33, + 89, 156, 30, 48, 226, 103, 130, 148, 197, 126, 23, 131, 211, 75, 155, 62, 231, + 73, 32, 151, 196, 231, 226, 0, 249, 180, 140, 111, 18, 4, 60, 240, 76, 199, + 81, 248, 84, 10, 117, 15, 191, 189, 209, 163, 146, 37, 185, 128, 54, 214, 175, + 96, 215, 150, 138, 140, 228, 102, 60, 133, 11, 185, 130, 110, 160, 121, 197, + 129, 57, 150, 43, 222, 191, 64, 80, 107, 122, 33, 132, 67, 85, 141, 97, 124, + 82, 173, 216, 224, 102, 220, 210, 24, 51, 192, 167, 135, 19, 212, 218, 170, + 74, 105, 104, 58, 237, 203, 181, 197, 77, 23, 92, 210, 143, 195, 129, 37, 205, + 61, 98, 61, 112, 36, 245, 192, 225, 83, 81, 159, 134, 235, 86, 221, 172, 191, + 213, 5, 131, 183, 118, 196, 78, 206, 255, 9, 32, 58, 10, 189, 63, 95, 45, 85, + 106, 74, 115, 51, 112, 123, 59, 45, 148, 13, 237, 84, 223, 249, 210, 176, 16, + 228, 207, 248, 180, 91, 210, 71, 150, 167, 205, 123, 140, 39, 66, 3, 110, 249, + 38, 86, 41, 181, 163, 96, 211, 181, 98, 58, 133, 136, 250, 23, 117, 4, 207, + 219, 168, 118, 85, 200, 123, 30, 143, 56, 117, 197, 242, 205, 130, 45, 200, + 77, 51, 56, 31, 41, 151, 118, 118, 162, 204, 65, 112, 243, 109, 142, 224, 81, + 250, 103, 25, 91, 9, 189, 105, 23, 75, 95, 167, 149, 49, 103, 76, 105, 74, 67, + 75, 3, 43, 103, 30, 157, 71, 34, 103, 136, 198, 229, 206, 182, 11, 255, 246, + 247, 16, 221, 142, 40, 137, 89, 63, 23, 151, 111, 31, 74, 70, 38, 210, 240, + 18, 209, 62, 111, 84, 203, 151, 195, 212, 18, 203, 83, 2, 98, 120, 73, 251, 3, + 220, 241, 162, 8, 76, 55, 163, 201, 118, 42, ]; -describe('main circuit tests for Zeto fungible tokens with anonymity using nullifiers and Kyber encryption for auditability', () => { +describe("main circuit tests for Zeto fungible tokens with anonymity using nullifiers and Kyber encryption for auditability", () => { let circuit, smtAlice, smtBob; const Alice = {}; @@ -80,7 +126,9 @@ describe('main circuit tests for Zeto fungible tokens with anonymity using nulli before(async function () { this.timeout(120000); - circuit = await wasm_tester(join(__dirname, '../../circuits/anon_nullifier_qurrency_transfer.circom')); + circuit = await wasm_tester( + join(__dirname, "../../circuits/anon_nullifier_qurrency_transfer.circom"), + ); let keypair = genKeypair(); Alice.privKey = keypair.privKey; @@ -92,15 +140,15 @@ describe('main circuit tests for Zeto fungible tokens with anonymity using nulli Bob.pubKey = keypair.pubKey; // initialize the local storage for Alice to manage her UTXOs in the Spart Merkle Tree - const storage1 = new InMemoryDB(str2Bytes('')); + const storage1 = new InMemoryDB(str2Bytes("")); smtAlice = new Merkletree(storage1, true, SMT_HEIGHT); // initialize the local storage for Bob to manage his UTXOs in the Spart Merkle Tree - const storage2 = new InMemoryDB(str2Bytes('')); + const storage2 = new InMemoryDB(str2Bytes("")); smtBob = new Merkletree(storage2, true, SMT_HEIGHT); }); - it('should succeed for valid witness - input size = 2', async function () { + it("should succeed for valid witness - input size = 2", async function () { this.timeout(120000); const inputValues = [32, 40]; @@ -108,15 +156,31 @@ describe('main circuit tests for Zeto fungible tokens with anonymity using nulli // create two input UTXOs, each has their own salt, but same owner const salt1 = newSalt(); - const input1 = poseidonHash([BigInt(inputValues[0]), salt1, ...Alice.pubKey]); + const input1 = poseidonHash([ + BigInt(inputValues[0]), + salt1, + ...Alice.pubKey, + ]); const salt2 = newSalt(); - const input2 = poseidonHash([BigInt(inputValues[1]), salt2, ...Alice.pubKey]); + const input2 = poseidonHash([ + BigInt(inputValues[1]), + salt2, + ...Alice.pubKey, + ]); const inputCommitments = [input1, input2]; const inputSalts = [salt1, salt2]; // create the nullifiers for the inputs - const nullifier1 = poseidonHash3([BigInt(inputValues[0]), salt1, senderPrivateKey]); - const nullifier2 = poseidonHash3([BigInt(inputValues[1]), salt2, senderPrivateKey]); + const nullifier1 = poseidonHash3([ + BigInt(inputValues[0]), + salt1, + senderPrivateKey, + ]); + const nullifier2 = poseidonHash3([ + BigInt(inputValues[1]), + salt2, + senderPrivateKey, + ]); const nullifiers = [nullifier1, nullifier2]; // calculate the root of the SMT @@ -124,14 +188,28 @@ describe('main circuit tests for Zeto fungible tokens with anonymity using nulli await smtAlice.add(input2, input2); // generate the merkle proof for the inputs - const proof1 = await smtAlice.generateCircomVerifierProof(input1, ZERO_HASH); - const proof2 = await smtAlice.generateCircomVerifierProof(input2, ZERO_HASH); + const proof1 = await smtAlice.generateCircomVerifierProof( + input1, + ZERO_HASH, + ); + const proof2 = await smtAlice.generateCircomVerifierProof( + input2, + ZERO_HASH, + ); // create two output UTXOs, they share the same salt, and different owner const salt3 = newSalt(); - const output1 = poseidonHash([BigInt(outputValues[0]), salt3, ...Bob.pubKey]); + const output1 = poseidonHash([ + BigInt(outputValues[0]), + salt3, + ...Bob.pubKey, + ]); const salt4 = newSalt(); - const output2 = poseidonHash([BigInt(outputValues[1]), salt4, ...Alice.pubKey]); + const output2 = poseidonHash([ + BigInt(outputValues[1]), + salt4, + ...Alice.pubKey, + ]); const outputCommitments = [output1, output2]; const outputSalts = [salt3, salt4]; const enabled = [1, 1]; @@ -144,7 +222,10 @@ describe('main circuit tests for Zeto fungible tokens with anonymity using nulli inputSalts: inputSalts, inputOwnerPrivateKey: senderPrivateKey, root: proof1.root.bigInt(), - merkleProof: [proof1.siblings.map((s) => s.bigInt()), proof2.siblings.map((s) => s.bigInt())], + merkleProof: [ + proof1.siblings.map((s) => s.bigInt()), + proof2.siblings.map((s) => s.bigInt()), + ], enabled, outputCommitments, outputValues, @@ -153,7 +234,7 @@ describe('main circuit tests for Zeto fungible tokens with anonymity using nulli randomness, m, }, - true + true, ); // console.log('witness[1-11]', witness.slice(1, 12)); @@ -197,7 +278,7 @@ describe('main circuit tests for Zeto fungible tokens with anonymity using nulli }); }); -describe('batch circuit tests for Zeto fungible tokens with anonymity using nullifiers and Kyber encryption for auditability', () => { +describe("batch circuit tests for Zeto fungible tokens with anonymity using nullifiers and Kyber encryption for auditability", () => { let circuit, smtAlice, smtBob; const Alice = {}; @@ -207,7 +288,12 @@ describe('batch circuit tests for Zeto fungible tokens with anonymity using null before(async function () { this.timeout(120000); - circuit = await wasm_tester(join(__dirname, '../../circuits/anon_nullifier_qurrency_transfer_batch.circom')); + circuit = await wasm_tester( + join( + __dirname, + "../../circuits/anon_nullifier_qurrency_transfer_batch.circom", + ), + ); let keypair = genKeypair(); Alice.privKey = keypair.privKey; @@ -219,15 +305,15 @@ describe('batch circuit tests for Zeto fungible tokens with anonymity using null Bob.pubKey = keypair.pubKey; // initialize the local storage for Alice to manage her UTXOs in the Spart Merkle Tree - const storage1 = new InMemoryDB(str2Bytes('')); + const storage1 = new InMemoryDB(str2Bytes("")); smtAlice = new Merkletree(storage1, true, SMT_HEIGHT); // initialize the local storage for Bob to manage his UTXOs in the Spart Merkle Tree - const storage2 = new InMemoryDB(str2Bytes('')); + const storage2 = new InMemoryDB(str2Bytes("")); smtBob = new Merkletree(storage2, true, SMT_HEIGHT); }); - it('should succeed for valid witness - input size = 10', async function () { + it("should succeed for valid witness - input size = 10", async function () { this.timeout(120000); const inputValues = [32, 40, 0, 0, 0, 0, 0, 0, 0, 0]; @@ -235,15 +321,31 @@ describe('batch circuit tests for Zeto fungible tokens with anonymity using null // create two input UTXOs, each has their own salt, but same owner const salt1 = newSalt(); - const input1 = poseidonHash([BigInt(inputValues[0]), salt1, ...Alice.pubKey]); + const input1 = poseidonHash([ + BigInt(inputValues[0]), + salt1, + ...Alice.pubKey, + ]); const salt2 = newSalt(); - const input2 = poseidonHash([BigInt(inputValues[1]), salt2, ...Alice.pubKey]); + const input2 = poseidonHash([ + BigInt(inputValues[1]), + salt2, + ...Alice.pubKey, + ]); const inputCommitments = [input1, input2, 0, 0, 0, 0, 0, 0, 0, 0]; const inputSalts = [salt1, salt2, 0, 0, 0, 0, 0, 0, 0, 0]; // create the nullifiers for the inputs - const nullifier1 = poseidonHash3([BigInt(inputValues[0]), salt1, senderPrivateKey]); - const nullifier2 = poseidonHash3([BigInt(inputValues[1]), salt2, senderPrivateKey]); + const nullifier1 = poseidonHash3([ + BigInt(inputValues[0]), + salt1, + senderPrivateKey, + ]); + const nullifier2 = poseidonHash3([ + BigInt(inputValues[1]), + salt2, + senderPrivateKey, + ]); const nullifiers = [nullifier1, nullifier2, 0, 0, 0, 0, 0, 0, 0, 0]; // calculate the root of the SMT @@ -251,14 +353,28 @@ describe('batch circuit tests for Zeto fungible tokens with anonymity using null await smtAlice.add(input2, input2); // generate the merkle proof for the inputs - const proof1 = await smtAlice.generateCircomVerifierProof(input1, ZERO_HASH); - const proof2 = await smtAlice.generateCircomVerifierProof(input2, ZERO_HASH); + const proof1 = await smtAlice.generateCircomVerifierProof( + input1, + ZERO_HASH, + ); + const proof2 = await smtAlice.generateCircomVerifierProof( + input2, + ZERO_HASH, + ); // create two output UTXOs, they share the same salt, and different owner const salt3 = newSalt(); - const output1 = poseidonHash([BigInt(outputValues[0]), salt3, ...Bob.pubKey]); + const output1 = poseidonHash([ + BigInt(outputValues[0]), + salt3, + ...Bob.pubKey, + ]); const salt4 = newSalt(); - const output2 = poseidonHash([BigInt(outputValues[1]), salt4, ...Alice.pubKey]); + const output2 = poseidonHash([ + BigInt(outputValues[1]), + salt4, + ...Alice.pubKey, + ]); const outputCommitments = [output1, output2, 0, 0, 0, 0, 0, 0, 0, 0]; const outputSalts = [salt3, salt4, 0, 0, 0, 0, 0, 0, 0, 0]; const enabled = [1, 1, 0, 0, 0, 0, 0, 0, 0, 0]; @@ -278,11 +394,22 @@ describe('batch circuit tests for Zeto fungible tokens with anonymity using null outputCommitments, outputValues, outputSalts: outputSalts, - outputOwnerPublicKeys: [Bob.pubKey, Alice.pubKey, Alice.pubKey, Alice.pubKey, Alice.pubKey, Alice.pubKey, Alice.pubKey, Alice.pubKey, Alice.pubKey, Alice.pubKey], + outputOwnerPublicKeys: [ + Bob.pubKey, + Alice.pubKey, + Alice.pubKey, + Alice.pubKey, + Alice.pubKey, + Alice.pubKey, + Alice.pubKey, + Alice.pubKey, + Alice.pubKey, + Alice.pubKey, + ], randomness, m, }, - true + true, ); ////// @@ -314,11 +441,11 @@ function hashCiphertext(ciphertext) { for (let i = 0; i < ciphertext.length; i++) { buff.writeUInt8(parseInt(ciphertext[i].toString()), i); } - const hash = crypto.createHash('sha256').update(buff).digest('hex'); + const hash = crypto.createHash("sha256").update(buff).digest("hex"); // compare this with the console.log printout in Solidity - console.log('ciphertext hash', hash); + console.log("ciphertext hash", hash); - const hashBuffer = Buffer.from(hash, 'hex'); + const hashBuffer = Buffer.from(hash, "hex"); const computed_pubSignals = [BigInt(0), BigInt(0)]; // Calculate h0: sum of the first 16 bytes for (let i = 0; i < 16; i++) { @@ -329,8 +456,8 @@ function hashCiphertext(ciphertext) { computed_pubSignals[1] += BigInt(hashBuffer[i] * 2 ** (8 * (i - 16))); } // compare these with the console.log printout in Solidity - console.log('computed_pubSignals[0]: ', computed_pubSignals[0]); - console.log('computed_pubSignals[1]: ', computed_pubSignals[1]); + console.log("computed_pubSignals[0]: ", computed_pubSignals[0]); + console.log("computed_pubSignals[1]: ", computed_pubSignals[1]); return computed_pubSignals; } diff --git a/zkp/js/test/burn.js b/zkp/js/test/burn.js index 54a01ef0..7a6dff2b 100644 --- a/zkp/js/test/burn.js +++ b/zkp/js/test/burn.js @@ -14,15 +14,15 @@ // See the License for the specific language governing permissions and // limitations under the License. -const { expect } = require('chai'); -const { join } = require('path'); -const { wasm: wasm_tester } = require('circom_tester'); -const { genKeypair, formatPrivKeyForBabyJub } = require('maci-crypto'); -const { Poseidon, newSalt } = require('../index.js'); +const { expect } = require("chai"); +const { join } = require("path"); +const { wasm: wasm_tester } = require("circom_tester"); +const { genKeypair, formatPrivKeyForBabyJub } = require("maci-crypto"); +const { Poseidon, newSalt } = require("../index.js"); const poseidonHash = Poseidon.poseidon4; -describe('burn circuit tests', () => { +describe("burn circuit tests", () => { let circuit; const Alice = {}; @@ -31,7 +31,7 @@ describe('burn circuit tests', () => { before(async function () { this.timeout(60000); - circuit = await wasm_tester(join(__dirname, '../../circuits/burn.circom')); + circuit = await wasm_tester(join(__dirname, "../../circuits/burn.circom")); let keypair = genKeypair(); Alice.privKey = keypair.privKey; @@ -39,7 +39,7 @@ describe('burn circuit tests', () => { senderPrivateKey = formatPrivKeyForBabyJub(Alice.privKey); }); - it('should succeed for valid witness', async () => { + it("should succeed for valid witness", async () => { const values = [32, 40]; // create two input UTXOs, each has their own salt, but same owner @@ -62,7 +62,7 @@ describe('burn circuit tests', () => { outputValue: 70, outputSalt: salt3, }, - true + true, ); // console.log('witness', witness.slice(0, 10)); @@ -74,7 +74,7 @@ describe('burn circuit tests', () => { expect(witness[2]).to.equal(BigInt(inputCommitments[1])); }); - it('should succeed for valid witness - single input', async () => { + it("should succeed for valid witness - single input", async () => { const values = [72, 0]; // create two input UTXOs, each has their own salt, but same owner @@ -95,14 +95,14 @@ describe('burn circuit tests', () => { outputValue: 70, outputSalt: salt3, }, - true + true, ); expect(witness[1]).to.equal(BigInt(inputCommitments[0])); expect(witness[2]).to.equal(BigInt(inputCommitments[1])); }); - it('should fail if output is greater than sum of the inputs', async () => { + it("should fail if output is greater than sum of the inputs", async () => { const values = [32, 40]; // create two input UTXOs, each has their own salt, but same owner @@ -127,12 +127,12 @@ describe('burn circuit tests', () => { outputValue: 80, outputSalt: salt3, }, - true + true, ); } catch (e) { // console.log(e); error = e; } - expect(error).to.match(/Error in template Burn_94 line: 66/); + expect(error).to.match(/Error in template Burn_94 line: 76/); }); }); diff --git a/zkp/js/test/burn_nullifier.js b/zkp/js/test/burn_nullifier.js index c0554e07..612c91d7 100644 --- a/zkp/js/test/burn_nullifier.js +++ b/zkp/js/test/burn_nullifier.js @@ -14,18 +14,23 @@ // See the License for the specific language governing permissions and // limitations under the License. -const { expect } = require('chai'); -const { join } = require('path'); -const { wasm: wasm_tester } = require('circom_tester'); -const { genKeypair, formatPrivKeyForBabyJub } = require('maci-crypto'); -const { Poseidon, newSalt } = require('../index.js'); -const { Merkletree, InMemoryDB, str2Bytes, ZERO_HASH } = require('@iden3/js-merkletree'); +const { expect } = require("chai"); +const { join } = require("path"); +const { wasm: wasm_tester } = require("circom_tester"); +const { genKeypair, formatPrivKeyForBabyJub } = require("maci-crypto"); +const { Poseidon, newSalt } = require("../index.js"); +const { + Merkletree, + InMemoryDB, + str2Bytes, + ZERO_HASH, +} = require("@iden3/js-merkletree"); const SMT_HEIGHT = 64; const poseidonHash = Poseidon.poseidon4; const poseidonHash3 = Poseidon.poseidon3; -describe('burn_nullifier circuit tests', () => { +describe("burn_nullifier circuit tests", () => { let circuit, smtAlice; const Alice = {}; @@ -34,7 +39,9 @@ describe('burn_nullifier circuit tests', () => { before(async function () { this.timeout(60000); - circuit = await wasm_tester(join(__dirname, '../../circuits/burn_nullifier.circom')); + circuit = await wasm_tester( + join(__dirname, "../../circuits/burn_nullifier.circom"), + ); let keypair = genKeypair(); Alice.privKey = keypair.privKey; @@ -42,11 +49,11 @@ describe('burn_nullifier circuit tests', () => { senderPrivateKey = formatPrivKeyForBabyJub(Alice.privKey); // initialize the local storage for Alice to manage her UTXOs in the Spart Merkle Tree - const storage1 = new InMemoryDB(str2Bytes('')); + const storage1 = new InMemoryDB(str2Bytes("")); smtAlice = new Merkletree(storage1, true, SMT_HEIGHT); }); - it('should succeed for valid witness', async () => { + it("should succeed for valid witness", async () => { const values = [32, 40]; // create two input UTXOs, each has their own salt, but same owner @@ -60,8 +67,16 @@ describe('burn_nullifier circuit tests', () => { const outputCommitment = poseidonHash([BigInt(70), salt3, ...Alice.pubKey]); // create the nullifiers for the inputs - const nullifier1 = poseidonHash3([BigInt(values[0]), salt1, senderPrivateKey]); - const nullifier2 = poseidonHash3([BigInt(values[1]), salt2, senderPrivateKey]); + const nullifier1 = poseidonHash3([ + BigInt(values[0]), + salt1, + senderPrivateKey, + ]); + const nullifier2 = poseidonHash3([ + BigInt(values[1]), + salt2, + senderPrivateKey, + ]); const nullifiers = [nullifier1, nullifier2]; // calculate the root of the SMT @@ -69,8 +84,14 @@ describe('burn_nullifier circuit tests', () => { await smtAlice.add(input2, input2); // generate the merkle proof for the inputs - const proof1 = await smtAlice.generateCircomVerifierProof(input1, ZERO_HASH); - const proof2 = await smtAlice.generateCircomVerifierProof(input2, ZERO_HASH); + const proof1 = await smtAlice.generateCircomVerifierProof( + input1, + ZERO_HASH, + ); + const proof2 = await smtAlice.generateCircomVerifierProof( + input2, + ZERO_HASH, + ); const witness = await circuit.calculateWitness( { @@ -80,13 +101,16 @@ describe('burn_nullifier circuit tests', () => { inputSalts: [salt1, salt2], ownerPrivateKey: senderPrivateKey, root: proof1.root.bigInt(), - merkleProof: [proof1.siblings.map((s) => s.bigInt()), proof2.siblings.map((s) => s.bigInt())], + merkleProof: [ + proof1.siblings.map((s) => s.bigInt()), + proof2.siblings.map((s) => s.bigInt()), + ], enabled: [1, 1], outputCommitment, outputValue: 70, outputSalt: salt3, }, - true + true, ); // console.log('witness', witness.slice(0, 10)); @@ -99,7 +123,7 @@ describe('burn_nullifier circuit tests', () => { expect(witness[2]).to.equal(BigInt(nullifiers[1])); }); - it('should succeed for valid witness - single input', async () => { + it("should succeed for valid witness - single input", async () => { const values = [72, 0]; // create two input UTXOs, each has their own salt, but same owner @@ -108,7 +132,11 @@ describe('burn_nullifier circuit tests', () => { const inputCommitments = [input1, 0]; // create the nullifiers for the inputs - const nullifier1 = poseidonHash3([BigInt(values[0]), salt1, senderPrivateKey]); + const nullifier1 = poseidonHash3([ + BigInt(values[0]), + salt1, + senderPrivateKey, + ]); const nullifiers = [nullifier1, 0]; const salt3 = newSalt(); @@ -118,7 +146,10 @@ describe('burn_nullifier circuit tests', () => { await smtAlice.add(input1, input1); // generate the merkle proof for the inputs - const proof1 = await smtAlice.generateCircomVerifierProof(input1, ZERO_HASH); + const proof1 = await smtAlice.generateCircomVerifierProof( + input1, + ZERO_HASH, + ); const proof2 = await smtAlice.generateCircomVerifierProof(0, ZERO_HASH); const witness = await circuit.calculateWitness( @@ -129,20 +160,23 @@ describe('burn_nullifier circuit tests', () => { inputSalts: [salt1, 0], ownerPrivateKey: senderPrivateKey, root: proof1.root.bigInt(), - merkleProof: [proof1.siblings.map((s) => s.bigInt()), proof2.siblings.map((s) => s.bigInt())], + merkleProof: [ + proof1.siblings.map((s) => s.bigInt()), + proof2.siblings.map((s) => s.bigInt()), + ], enabled: [1, 0], outputCommitment, outputValue: 70, outputSalt: salt3, }, - true + true, ); expect(witness[1]).to.equal(BigInt(nullifiers[0])); expect(witness[2]).to.equal(BigInt(nullifiers[1])); }); - it('should fail if the output UTXO has a bigger value', async () => { + it("should fail if the output UTXO has a bigger value", async () => { const values = [32, 40]; // create two input UTXOs, each has their own salt, but same owner @@ -156,8 +190,16 @@ describe('burn_nullifier circuit tests', () => { const outputCommitment = poseidonHash([BigInt(80), salt3, ...Alice.pubKey]); // create the nullifiers for the inputs - const nullifier1 = poseidonHash3([BigInt(values[0]), salt1, senderPrivateKey]); - const nullifier2 = poseidonHash3([BigInt(values[1]), salt2, senderPrivateKey]); + const nullifier1 = poseidonHash3([ + BigInt(values[0]), + salt1, + senderPrivateKey, + ]); + const nullifier2 = poseidonHash3([ + BigInt(values[1]), + salt2, + senderPrivateKey, + ]); const nullifiers = [nullifier1, nullifier2]; // calculate the root of the SMT @@ -165,8 +207,14 @@ describe('burn_nullifier circuit tests', () => { await smtAlice.add(input2, input2); // generate the merkle proof for the inputs - const proof1 = await smtAlice.generateCircomVerifierProof(input1, ZERO_HASH); - const proof2 = await smtAlice.generateCircomVerifierProof(input2, ZERO_HASH); + const proof1 = await smtAlice.generateCircomVerifierProof( + input1, + ZERO_HASH, + ); + const proof2 = await smtAlice.generateCircomVerifierProof( + input2, + ZERO_HASH, + ); let error; try { @@ -178,18 +226,21 @@ describe('burn_nullifier circuit tests', () => { inputSalts: [salt1, salt2], ownerPrivateKey: senderPrivateKey, root: proof1.root.bigInt(), - merkleProof: [proof1.siblings.map((s) => s.bigInt()), proof2.siblings.map((s) => s.bigInt())], + merkleProof: [ + proof1.siblings.map((s) => s.bigInt()), + proof2.siblings.map((s) => s.bigInt()), + ], enabled: [1, 1], outputCommitment, outputValue: 80, outputSalt: salt3, }, - true + true, ); } catch (e) { // console.log('error', e); error = e; } - expect(error).to.match(/Error in template BurnNullifiers_251 line: 83/); + expect(error).to.match(/Error in template BurnNullifiers_251 line: 93/); }); }); diff --git a/zkp/js/test/check_nullifiers.js b/zkp/js/test/check_nullifiers.js index 86efb235..97183edf 100644 --- a/zkp/js/test/check_nullifiers.js +++ b/zkp/js/test/check_nullifiers.js @@ -150,6 +150,6 @@ describe("check_nullifiers circuit tests", () => { err = e; } // console.log(err); - expect(err).to.match(/Error in template Zeto_159 line: 51/); + expect(err).to.match(/Error in template Zeto_159 line: 53/); }); }); diff --git a/zkp/js/test/circuits/check-hashes.circom b/zkp/js/test/circuits/check-hashes.circom index 9e07994e..15358792 100644 --- a/zkp/js/test/circuits/check-hashes.circom +++ b/zkp/js/test/circuits/check-hashes.circom @@ -17,4 +17,4 @@ pragma circom 2.2.2; include "../../../circuits/lib/check-hashes.circom"; -component main {public [ commitments, ownerPublicKeys ]} = CheckHashes(2); \ No newline at end of file +component main {public [ commitmentHashes ]} = CheckHashes(2); \ No newline at end of file diff --git a/zkp/js/test/deposit.js b/zkp/js/test/deposit.js index 06d7e2b6..af628755 100644 --- a/zkp/js/test/deposit.js +++ b/zkp/js/test/deposit.js @@ -133,7 +133,7 @@ describe("deposit circuit tests", () => { error = e; } // console.log(error); - expect(error).to.match(/Error in template CheckHashes_80 line: 47/); // hash check failed + expect(error).to.match(/Error in template CheckHashes_80 line: 45/); // hash check failed }); it("should fail to generate a witness because of negative values in output commitments", async () => { diff --git a/zkp/js/test/lib/check-hashes.js b/zkp/js/test/lib/check-hashes.js index cded1dcb..c40f0920 100644 --- a/zkp/js/test/lib/check-hashes.js +++ b/zkp/js/test/lib/check-hashes.js @@ -1,4 +1,4 @@ -// Copyright © 2024 Kaleido, Inc. +// Copyright © 2025 Kaleido, Inc. // // SPDX-License-Identifier: Apache-2.0 // @@ -15,7 +15,6 @@ // limitations under the License. const { expect } = require("chai"); -const { readFileSync } = require("fs"); const { join } = require("path"); const { wasm: wasm_tester } = require("circom_tester"); const { genKeypair } = require("maci-crypto"); @@ -52,25 +51,36 @@ describe("check-hashes circuit tests", () => { const input1 = poseidonHash([BigInt(values[0]), salt1, ...sender.pubKey]); const salt2 = newSalt(); const input2 = poseidonHash([BigInt(values[1]), salt2, ...sender.pubKey]); - const commitments = [input1, input2]; + const commitmentHashes = [input1, input2]; const witness = await circuit.calculateWitness( { - commitments, - values, - salts: [salt1, salt2], - ownerPublicKeys: [sender.pubKey, sender.pubKey], + commitmentHashes, + commitmentInputs: [ + BigInt(values[0]), + salt1, + ...sender.pubKey, + BigInt(values[1]), + salt2, + ...sender.pubKey, + ], }, true, ); // console.log(witness.slice(0, 10)); - // console.log('commitments', commitments); + // console.log('commitmentHashes', commitmentHashes); // console.log('sender public key', sender.pubKey); - expect(witness[1]).to.equal(BigInt(commitments[0])); - expect(witness[2]).to.equal(BigInt(commitments[1])); - expect(witness[3]).to.equal(BigInt(sender.pubKey[0])); - expect(witness[4]).to.equal(BigInt(sender.pubKey[1])); + expect(witness[1]).to.equal(BigInt(commitmentHashes[0])); + expect(witness[2]).to.equal(BigInt(commitmentHashes[1])); + expect(witness[3]).to.equal(BigInt(values[0])); + expect(witness[4]).to.equal(salt1); + expect(witness[5]).to.equal(BigInt(sender.pubKey[0])); + expect(witness[6]).to.equal(BigInt(sender.pubKey[1])); + expect(witness[7]).to.equal(BigInt(values[1])); + expect(witness[8]).to.equal(salt2); + expect(witness[9]).to.equal(BigInt(sender.pubKey[0])); + expect(witness[10]).to.equal(BigInt(sender.pubKey[1])); }); it("should return true for valid witness using a single input value", async () => { @@ -79,22 +89,28 @@ describe("check-hashes circuit tests", () => { // create two input UTXOs, each has their own salt, but same owner const salt1 = newSalt(); const input1 = poseidonHash([BigInt(values[0]), salt1, ...sender.pubKey]); - const commitments = [input1, 0]; + const commitmentHashes = [input1, 0]; const witness = await circuit.calculateWitness( { - commitments, - values, - salts: [salt1, 0], - ownerPublicKeys: [sender.pubKey, [0n, 0n]], + commitmentHashes, + commitmentInputs: [ + BigInt(values[0]), + salt1, + ...sender.pubKey, + BigInt(values[1]), + 0, + 0n, + 0n, + ], }, true, ); - expect(witness[1]).to.equal(BigInt(commitments[0])); - expect(witness[2]).to.equal(BigInt(commitments[1])); - expect(witness[3]).to.equal(BigInt(sender.pubKey[0])); - expect(witness[4]).to.equal(BigInt(sender.pubKey[1])); + expect(witness[1]).to.equal(BigInt(commitmentHashes[0])); + expect(witness[2]).to.equal(BigInt(commitmentHashes[1])); + expect(witness[5]).to.equal(BigInt(sender.pubKey[0])); + expect(witness[6]).to.equal(BigInt(sender.pubKey[1])); }); it("should return true for valid witness using a single input value", async () => { @@ -103,27 +119,35 @@ describe("check-hashes circuit tests", () => { // create two input UTXOs, each has their own salt, but same owner const salt1 = newSalt(); const input1 = poseidonHash([BigInt(values[1]), salt1, ...sender.pubKey]); - const commitments = [0n, input1]; + const commitmentHashes = [0n, input1]; const witness = await circuit.calculateWitness( { - commitments, - values, - salts: [0, salt1], - ownerPublicKeys: [[0n, 0n], sender.pubKey], + commitmentHashes, + commitmentInputs: [ + BigInt(values[0]), + 0, + 0n, + 0n, + BigInt(values[1]), + salt1, + ...sender.pubKey, + ], }, true, ); - expect(witness[1]).to.equal(BigInt(commitments[0])); - expect(witness[2]).to.equal(BigInt(commitments[1])); + expect(witness[1]).to.equal(BigInt(commitmentHashes[0])); + expect(witness[2]).to.equal(BigInt(commitmentHashes[1])); expect(witness[3]).to.equal(0n); expect(witness[4]).to.equal(0n); - expect(witness[5]).to.equal(BigInt(sender.pubKey[0])); - expect(witness[6]).to.equal(BigInt(sender.pubKey[1])); + expect(witness[5]).to.equal(0n); + expect(witness[6]).to.equal(0n); + expect(witness[9]).to.equal(BigInt(sender.pubKey[0])); + expect(witness[10]).to.equal(BigInt(sender.pubKey[1])); }); - it("should fail to generate a witness because of invalid input commitments", async () => { + it("should fail to generate a witness because of invalid input commitmentHashes", async () => { const inputValues = [25, 100]; // create two input UTXOs, each has their own salt, but same owner @@ -139,16 +163,21 @@ describe("check-hashes circuit tests", () => { salt2, ...sender.pubKey, ]); - const inputCommitments = [input1 + BigInt(1), input2]; + const commitmentHashes = [input1 + BigInt(1), input2]; let error; try { await circuit.calculateWitness( { - commitments: inputCommitments, - values: inputValues, - salts: [salt1, salt2], - ownerPublicKeys: [sender.pubKey, sender.pubKey], + commitmentHashes, + commitmentInputs: [ + BigInt(inputValues[0]), + salt1, + ...sender.pubKey, + BigInt(inputValues[1]), + salt2, + ...sender.pubKey, + ], }, true, ); @@ -156,6 +185,6 @@ describe("check-hashes circuit tests", () => { error = e; } // console.log(error); - expect(error).to.match(/Error in template CheckHashes_76 line: 47/); // hash check failed + expect(error).to.match(/Error in template CheckHashes_76 line: 45/); // hash check failed }); });