From 96390041a6ea10c63664bbcd61afc159a9d91dcb Mon Sep 17 00:00:00 2001
From: Nesopie <87437291+Nesopie@users.noreply.github.com>
Date: Thu, 29 Jan 2026 12:40:50 +0530
Subject: [PATCH 1/7] Revert "fix: ecdsa (#1625)" (#1671)
This reverts commit 13d81c53bfb9b2514c178e59f7dec0e9b6cd1d24.
---
.../crypto/bigInt/bigIntComparators.circom | 24 +++++++++----------
1 file changed, 12 insertions(+), 12 deletions(-)
diff --git a/circuits/circuits/utils/crypto/bigInt/bigIntComparators.circom b/circuits/circuits/utils/crypto/bigInt/bigIntComparators.circom
index a90dafa26f..0d6c530032 100644
--- a/circuits/circuits/utils/crypto/bigInt/bigIntComparators.circom
+++ b/circuits/circuits/utils/crypto/bigInt/bigIntComparators.circom
@@ -17,13 +17,13 @@ include "../utils/switcher.circom";
// Can check for 2 bigints equality if in is sub of each chunk of those numbers
template BigIntIsZero(CHUNK_SIZE, MAX_CHUNK_SIZE, CHUNK_NUMBER) {
assert(CHUNK_NUMBER >= 2);
-
+
var EPSILON = 3;
-
+
assert(MAX_CHUNK_SIZE + EPSILON <= 253);
-
+
signal input in[CHUNK_NUMBER];
-
+
signal carry[CHUNK_NUMBER - 1];
component carryRangeChecks[CHUNK_NUMBER - 1];
for (var i = 0; i < CHUNK_NUMBER - 1; i++){
@@ -45,9 +45,9 @@ template BigIntIsZero(CHUNK_SIZE, MAX_CHUNK_SIZE, CHUNK_NUMBER) {
// Works with overflowed signed chunks
// To handle megative values we use sign
// Sign is var and can be changed, but it should be a problem
-// Sign change means that we can calculate for -in instead of in,
+// Sign change means that we can calculate for -in instead of in,
// But if in % p == 0 means that -in % p == 0 too, so no exploit here
-// Problem lies in other one:
+// Problem lies in other one:
// k - is result of div func, and can be anything (var)
// we check k * p - in === 0
// k * p is result of big multiplication
@@ -71,9 +71,9 @@ template BigIntIsZero(CHUNK_SIZE, MAX_CHUNK_SIZE, CHUNK_NUMBER) {
template BigIntIsZeroModP(CHUNK_SIZE, MAX_CHUNK_SIZE, CHUNK_NUMBER, MAX_CHUNK_NUMBER, CHUNK_NUMBER_MODULUS){
signal input in[CHUNK_NUMBER];
signal input modulus[CHUNK_NUMBER_MODULUS];
-
+
var CHUNK_NUMBER_DIV = MAX_CHUNK_NUMBER - CHUNK_NUMBER_MODULUS + 1;
-
+
var reduced[200] = reduce_overflow_signed_dl(CHUNK_SIZE, CHUNK_NUMBER, MAX_CHUNK_NUMBER, MAX_CHUNK_SIZE, in);
var div_result[2][200] = long_div_dl(CHUNK_SIZE, CHUNK_NUMBER_MODULUS, CHUNK_NUMBER_DIV - 1, reduced, modulus);
signal sign <-- reduced[199];
@@ -88,7 +88,7 @@ template BigIntIsZeroModP(CHUNK_SIZE, MAX_CHUNK_SIZE, CHUNK_NUMBER, MAX_CHUNK_NU
for (var i = 0; i < CHUNK_NUMBER_DIV; i++){
k[i] <-- div_result[0][i];
kRangeChecks[i] = Num2Bits(CHUNK_SIZE);
- kRangeChecks[i].in <== k[i];
+ kRangeChecks[i].in <-- k[i];
}
component mult;
@@ -101,7 +101,7 @@ template BigIntIsZeroModP(CHUNK_SIZE, MAX_CHUNK_SIZE, CHUNK_NUMBER, MAX_CHUNK_NU
mult.in1 <== modulus;
mult.in2 <== k;
}
-
+
component swicher[CHUNK_NUMBER];
component isZero = BigIntIsZero(CHUNK_SIZE, MAX_CHUNK_SIZE, MAX_CHUNK_NUMBER);
@@ -116,5 +116,5 @@ template BigIntIsZeroModP(CHUNK_SIZE, MAX_CHUNK_SIZE, CHUNK_NUMBER, MAX_CHUNK_NU
for (var i = CHUNK_NUMBER; i < MAX_CHUNK_NUMBER; i++){
isZero.in[i] <== mult.out[i];
}
-
-}
+
+}
\ No newline at end of file
From cae937b8ba41490d29787c800cc930cd687271a9 Mon Sep 17 00:00:00 2001
From: Nesopie <87437291+Nesopie@users.noreply.github.com>
Date: Thu, 29 Jan 2026 22:48:12 +0530
Subject: [PATCH 2/7] feat: add register_kyc and vc_and_disclose_kyc verifiers
(#1672)
---
.../disclose/Verifier_vc_and_disclose_kyc.sol | 364 ++++++++++++++++++
.../register_kyc/Verifier_register_kyc.sol | 189 +++++++++
2 files changed, 553 insertions(+)
create mode 100644 contracts/contracts/verifiers/disclose/Verifier_vc_and_disclose_kyc.sol
create mode 100644 contracts/contracts/verifiers/register_kyc/Verifier_register_kyc.sol
diff --git a/contracts/contracts/verifiers/disclose/Verifier_vc_and_disclose_kyc.sol b/contracts/contracts/verifiers/disclose/Verifier_vc_and_disclose_kyc.sol
new file mode 100644
index 0000000000..b8de45e2cc
--- /dev/null
+++ b/contracts/contracts/verifiers/disclose/Verifier_vc_and_disclose_kyc.sol
@@ -0,0 +1,364 @@
+// SPDX-License-Identifier: GPL-3.0
+/*
+ Copyright 2021 0KIMS association.
+
+ This file is generated with [snarkJS](https://github.com/iden3/snarkjs).
+
+ snarkJS is a free software: you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ snarkJS is distributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+ License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with snarkJS. If not, see .
+*/
+
+pragma solidity >=0.7.0 <0.9.0;
+
+contract Groth16Verifier {
+ // Scalar field size
+ uint256 constant r = 21888242871839275222246405745257275088548364400416034343698204186575808495617;
+ // Base field size
+ uint256 constant q = 21888242871839275222246405745257275088696311157297823662689037894645226208583;
+
+ // Verification Key data
+ uint256 constant alphax = 20491192805390485299153009773594534940189261866228447918068658471970481763042;
+ uint256 constant alphay = 9383485363053290200918347156157836566562967994039712273449902621266178545958;
+ uint256 constant betax1 = 4252822878758300859123897981450591353533073413197771768651442665752259397132;
+ uint256 constant betax2 = 6375614351688725206403948262868962793625744043794305715222011528459656738731;
+ uint256 constant betay1 = 21847035105528745403288232691147584728191162732299865338377159692350059136679;
+ uint256 constant betay2 = 10505242626370262277552901082094356697409835680220590971873171140371331206856;
+ uint256 constant gammax1 = 11559732032986387107991004021392285783925812861821192530917403151452391805634;
+ uint256 constant gammax2 = 10857046999023057135944570762232829481370756359578518086990519993285655852781;
+ uint256 constant gammay1 = 4082367875863433681332203403145435568316851327593401208105741076214120093531;
+ uint256 constant gammay2 = 8495653923123431417604973247489272438418190587263600148770280649306958101930;
+ uint256 constant deltax1 = 1022502948747070596300631872305350196366208813582081229292413330002410493735;
+ uint256 constant deltax2 = 8307404806875602039009979465400882149520343934575147532878670270259674144681;
+ uint256 constant deltay1 = 8725996148009629609617423651062395041554350094385944632997372312828608644955;
+ uint256 constant deltay2 = 19505227144542990355285832777856832082655385455315296491381347497982380087331;
+
+
+ uint256 constant IC0x = 16649376790350306128495410672000438222835355361873864679185308928608342391377;
+ uint256 constant IC0y = 1365830659239397567654193478106544803466926587095831397836882385286292210457;
+
+ uint256 constant IC1x = 12768368041823022971486465099843313755353560181066686496309262693573983752166;
+ uint256 constant IC1y = 8959643464054312389755875312066576344157543684040889350558798123653714759323;
+
+ uint256 constant IC2x = 8026951355325092256379108005740615512895662065129471323964253392093201472413;
+ uint256 constant IC2y = 17729685419344675830181571225504519401370157618831493299320871505193568194542;
+
+ uint256 constant IC3x = 13865750614916211164740113517816425481179265306761612472818567385469595810190;
+ uint256 constant IC3y = 6210007189067774389269573600168370223250403017805496113623335642264819992738;
+
+ uint256 constant IC4x = 16855313964021865460083277912281502340407051430688518561820294646056966683723;
+ uint256 constant IC4y = 15265407205922489364865678414919162208795257265772110915033785419192236363960;
+
+ uint256 constant IC5x = 18598823774356508040525215881560556738983729535652356395586704599152692518280;
+ uint256 constant IC5y = 18145817576163407281749708126167770321482159783050035647989919114769433256079;
+
+ uint256 constant IC6x = 7929686493832109041041190086485345905029205802382475316611421597823511641043;
+ uint256 constant IC6y = 19169046602940406351907027759303697432610627026407453208752335429425017694574;
+
+ uint256 constant IC7x = 2605668546149689485076733864456601989800612639397730351435615085329568572059;
+ uint256 constant IC7y = 2242419572125099587271391127551951332349827207830958146376081280864531825864;
+
+ uint256 constant IC8x = 17230061988111645534990582267868011734783232047326494254312685097544413153459;
+ uint256 constant IC8y = 10806577457667861555253433417098515955632524053970338643826272138544403320442;
+
+ uint256 constant IC9x = 3751984630395628299497200107740113530312143585224331604497180428031979981854;
+ uint256 constant IC9y = 15676455188720477849218254715359881022685281346012746362600653176819367175994;
+
+ uint256 constant IC10x = 9038868170600703467507268624782850799834426621476374278712452873055805013104;
+ uint256 constant IC10y = 9698587198888135369066906249654396893723648003242241945599284193157738042248;
+
+ uint256 constant IC11x = 6050467884563375668249040797272149300003806466909114026944043296882360309360;
+ uint256 constant IC11y = 15900287959991498727296171595521639394049115178198151794906977584504380285297;
+
+ uint256 constant IC12x = 11084322708760789175416300406920316493444723572225966905156819463716045081320;
+ uint256 constant IC12y = 11218515196222567596688687943809578734267033209068034707100619316839921252394;
+
+ uint256 constant IC13x = 10645041863169277188776881369692412104739148582039109401067090622235062084156;
+ uint256 constant IC13y = 5266268354502390834581900591132009542571872858584466937449333517597831148030;
+
+ uint256 constant IC14x = 12641747272597271663246870871466152965248117816492334493753291231347523232168;
+ uint256 constant IC14y = 19526003775802419962730302158408658198175393685733749794278416969198861577034;
+
+ uint256 constant IC15x = 6139284918750361257008863566645097867991292622068199456332000872393801256773;
+ uint256 constant IC15y = 7099084867504428315337895159166860608559331005995192184490932820607010680845;
+
+ uint256 constant IC16x = 9370432203154443644773178040475615441452364961035990256255996609230750218064;
+ uint256 constant IC16y = 17951757691776403072537537626795200133221243393670030429694486485017127221358;
+
+ uint256 constant IC17x = 21581607541319264321515681298226106781535771321110191776762670932817827595844;
+ uint256 constant IC17y = 7631049069535860061742036261740730390300464507981117501570404056719958498930;
+
+ uint256 constant IC18x = 16588935529361800732448688229721305142336631834288163321894359880448688608191;
+ uint256 constant IC18y = 4976649298929967469596409013742801233623738930274577396507275281714439091100;
+
+ uint256 constant IC19x = 13336088316263130029440976636885322206279122461816212975585641922353453096719;
+ uint256 constant IC19y = 668527371723708514830022396101506352277923231593513590339198147917179128262;
+
+ uint256 constant IC20x = 7911418535344866382682474453536883970529338904273675929069409842800763592456;
+ uint256 constant IC20y = 6722145715621557485364045815849938484983110008747946723738151730812429418202;
+
+ uint256 constant IC21x = 610873214241184085635414594211441831430912772471117234461302269567691174096;
+ uint256 constant IC21y = 16969907768023728182903317862310886370963194429698287724301462949165910596854;
+
+ uint256 constant IC22x = 659738555556673077218073955988504765951032248025470001896149485964044510568;
+ uint256 constant IC22y = 2124464077179769137643014583429957482256390408775774347541901875987080182668;
+
+ uint256 constant IC23x = 11040330531093768074742977048495269267038172161278331102262692904222746927915;
+ uint256 constant IC23y = 20387648111599243028561521301140310714164415003338654058061856932087967245514;
+
+ uint256 constant IC24x = 6937058621269922207815167233155518898032328662416059831807664411944661190679;
+ uint256 constant IC24y = 3779340684837021741207549471402298796167963069596080462551336236827030143602;
+
+ uint256 constant IC25x = 20956067714892758188531163534075112952656779768842660715243328162174316184647;
+ uint256 constant IC25y = 9697689335367034906644638465039998846629732846527791686651080885302279721947;
+
+ uint256 constant IC26x = 10803066158517027587330447158982829324243112587050865062666733319696533170000;
+ uint256 constant IC26y = 16966880529095588436103115659246637747363575619917237189424029126730846465979;
+
+ uint256 constant IC27x = 12430600018955874842029331801839308658974272583893366935707885910189427842476;
+ uint256 constant IC27y = 14602780957678176966948503351865628319039612308733335242961008886115024541985;
+
+ uint256 constant IC28x = 10923748125791784887614451982072899321420747436037959145471646494829305705731;
+ uint256 constant IC28y = 6050274667868774010280923182747429242888928748472706014853484883020658961073;
+
+ uint256 constant IC29x = 1170885743391113947515531032472753161485583617637753865725092942330476093342;
+ uint256 constant IC29y = 19204742121781488340297839383055704899252648836617466985181418250802660585322;
+
+
+ // Memory data
+ uint16 constant pVk = 0;
+ uint16 constant pPairing = 128;
+
+ uint16 constant pLastMem = 896;
+
+ function verifyProof(uint[2] calldata _pA, uint[2][2] calldata _pB, uint[2] calldata _pC, uint[29] calldata _pubSignals) public view returns (bool) {
+ assembly {
+ function checkField(v) {
+ if iszero(lt(v, r)) {
+ mstore(0, 0)
+ return(0, 0x20)
+ }
+ }
+
+ // G1 function to multiply a G1 value(x,y) to value in an address
+ function g1_mulAccC(pR, x, y, s) {
+ let success
+ let mIn := mload(0x40)
+ mstore(mIn, x)
+ mstore(add(mIn, 32), y)
+ mstore(add(mIn, 64), s)
+
+ success := staticcall(sub(gas(), 2000), 7, mIn, 96, mIn, 64)
+
+ if iszero(success) {
+ mstore(0, 0)
+ return(0, 0x20)
+ }
+
+ mstore(add(mIn, 64), mload(pR))
+ mstore(add(mIn, 96), mload(add(pR, 32)))
+
+ success := staticcall(sub(gas(), 2000), 6, mIn, 128, pR, 64)
+
+ if iszero(success) {
+ mstore(0, 0)
+ return(0, 0x20)
+ }
+ }
+
+ function checkPairing(pA, pB, pC, pubSignals, pMem) -> isOk {
+ let _pPairing := add(pMem, pPairing)
+ let _pVk := add(pMem, pVk)
+
+ mstore(_pVk, IC0x)
+ mstore(add(_pVk, 32), IC0y)
+
+ // Compute the linear combination vk_x
+
+ g1_mulAccC(_pVk, IC1x, IC1y, calldataload(add(pubSignals, 0)))
+
+ g1_mulAccC(_pVk, IC2x, IC2y, calldataload(add(pubSignals, 32)))
+
+ g1_mulAccC(_pVk, IC3x, IC3y, calldataload(add(pubSignals, 64)))
+
+ g1_mulAccC(_pVk, IC4x, IC4y, calldataload(add(pubSignals, 96)))
+
+ g1_mulAccC(_pVk, IC5x, IC5y, calldataload(add(pubSignals, 128)))
+
+ g1_mulAccC(_pVk, IC6x, IC6y, calldataload(add(pubSignals, 160)))
+
+ g1_mulAccC(_pVk, IC7x, IC7y, calldataload(add(pubSignals, 192)))
+
+ g1_mulAccC(_pVk, IC8x, IC8y, calldataload(add(pubSignals, 224)))
+
+ g1_mulAccC(_pVk, IC9x, IC9y, calldataload(add(pubSignals, 256)))
+
+ g1_mulAccC(_pVk, IC10x, IC10y, calldataload(add(pubSignals, 288)))
+
+ g1_mulAccC(_pVk, IC11x, IC11y, calldataload(add(pubSignals, 320)))
+
+ g1_mulAccC(_pVk, IC12x, IC12y, calldataload(add(pubSignals, 352)))
+
+ g1_mulAccC(_pVk, IC13x, IC13y, calldataload(add(pubSignals, 384)))
+
+ g1_mulAccC(_pVk, IC14x, IC14y, calldataload(add(pubSignals, 416)))
+
+ g1_mulAccC(_pVk, IC15x, IC15y, calldataload(add(pubSignals, 448)))
+
+ g1_mulAccC(_pVk, IC16x, IC16y, calldataload(add(pubSignals, 480)))
+
+ g1_mulAccC(_pVk, IC17x, IC17y, calldataload(add(pubSignals, 512)))
+
+ g1_mulAccC(_pVk, IC18x, IC18y, calldataload(add(pubSignals, 544)))
+
+ g1_mulAccC(_pVk, IC19x, IC19y, calldataload(add(pubSignals, 576)))
+
+ g1_mulAccC(_pVk, IC20x, IC20y, calldataload(add(pubSignals, 608)))
+
+ g1_mulAccC(_pVk, IC21x, IC21y, calldataload(add(pubSignals, 640)))
+
+ g1_mulAccC(_pVk, IC22x, IC22y, calldataload(add(pubSignals, 672)))
+
+ g1_mulAccC(_pVk, IC23x, IC23y, calldataload(add(pubSignals, 704)))
+
+ g1_mulAccC(_pVk, IC24x, IC24y, calldataload(add(pubSignals, 736)))
+
+ g1_mulAccC(_pVk, IC25x, IC25y, calldataload(add(pubSignals, 768)))
+
+ g1_mulAccC(_pVk, IC26x, IC26y, calldataload(add(pubSignals, 800)))
+
+ g1_mulAccC(_pVk, IC27x, IC27y, calldataload(add(pubSignals, 832)))
+
+ g1_mulAccC(_pVk, IC28x, IC28y, calldataload(add(pubSignals, 864)))
+
+ g1_mulAccC(_pVk, IC29x, IC29y, calldataload(add(pubSignals, 896)))
+
+
+ // -A
+ mstore(_pPairing, calldataload(pA))
+ mstore(add(_pPairing, 32), mod(sub(q, calldataload(add(pA, 32))), q))
+
+ // B
+ mstore(add(_pPairing, 64), calldataload(pB))
+ mstore(add(_pPairing, 96), calldataload(add(pB, 32)))
+ mstore(add(_pPairing, 128), calldataload(add(pB, 64)))
+ mstore(add(_pPairing, 160), calldataload(add(pB, 96)))
+
+ // alpha1
+ mstore(add(_pPairing, 192), alphax)
+ mstore(add(_pPairing, 224), alphay)
+
+ // beta2
+ mstore(add(_pPairing, 256), betax1)
+ mstore(add(_pPairing, 288), betax2)
+ mstore(add(_pPairing, 320), betay1)
+ mstore(add(_pPairing, 352), betay2)
+
+ // vk_x
+ mstore(add(_pPairing, 384), mload(add(pMem, pVk)))
+ mstore(add(_pPairing, 416), mload(add(pMem, add(pVk, 32))))
+
+
+ // gamma2
+ mstore(add(_pPairing, 448), gammax1)
+ mstore(add(_pPairing, 480), gammax2)
+ mstore(add(_pPairing, 512), gammay1)
+ mstore(add(_pPairing, 544), gammay2)
+
+ // C
+ mstore(add(_pPairing, 576), calldataload(pC))
+ mstore(add(_pPairing, 608), calldataload(add(pC, 32)))
+
+ // delta2
+ mstore(add(_pPairing, 640), deltax1)
+ mstore(add(_pPairing, 672), deltax2)
+ mstore(add(_pPairing, 704), deltay1)
+ mstore(add(_pPairing, 736), deltay2)
+
+
+ let success := staticcall(sub(gas(), 2000), 8, _pPairing, 768, _pPairing, 0x20)
+
+ isOk := and(success, mload(_pPairing))
+ }
+
+ let pMem := mload(0x40)
+ mstore(0x40, add(pMem, pLastMem))
+
+ // Validate that all evaluations ∈ F
+
+ checkField(calldataload(add(_pubSignals, 0)))
+
+ checkField(calldataload(add(_pubSignals, 32)))
+
+ checkField(calldataload(add(_pubSignals, 64)))
+
+ checkField(calldataload(add(_pubSignals, 96)))
+
+ checkField(calldataload(add(_pubSignals, 128)))
+
+ checkField(calldataload(add(_pubSignals, 160)))
+
+ checkField(calldataload(add(_pubSignals, 192)))
+
+ checkField(calldataload(add(_pubSignals, 224)))
+
+ checkField(calldataload(add(_pubSignals, 256)))
+
+ checkField(calldataload(add(_pubSignals, 288)))
+
+ checkField(calldataload(add(_pubSignals, 320)))
+
+ checkField(calldataload(add(_pubSignals, 352)))
+
+ checkField(calldataload(add(_pubSignals, 384)))
+
+ checkField(calldataload(add(_pubSignals, 416)))
+
+ checkField(calldataload(add(_pubSignals, 448)))
+
+ checkField(calldataload(add(_pubSignals, 480)))
+
+ checkField(calldataload(add(_pubSignals, 512)))
+
+ checkField(calldataload(add(_pubSignals, 544)))
+
+ checkField(calldataload(add(_pubSignals, 576)))
+
+ checkField(calldataload(add(_pubSignals, 608)))
+
+ checkField(calldataload(add(_pubSignals, 640)))
+
+ checkField(calldataload(add(_pubSignals, 672)))
+
+ checkField(calldataload(add(_pubSignals, 704)))
+
+ checkField(calldataload(add(_pubSignals, 736)))
+
+ checkField(calldataload(add(_pubSignals, 768)))
+
+ checkField(calldataload(add(_pubSignals, 800)))
+
+ checkField(calldataload(add(_pubSignals, 832)))
+
+ checkField(calldataload(add(_pubSignals, 864)))
+
+ checkField(calldataload(add(_pubSignals, 896)))
+
+
+ // Validate all evaluations
+ let isValid := checkPairing(_pA, _pB, _pC, _pubSignals, pMem)
+
+ mstore(0, isValid)
+ return(0, 0x20)
+ }
+ }
+ }
diff --git a/contracts/contracts/verifiers/register_kyc/Verifier_register_kyc.sol b/contracts/contracts/verifiers/register_kyc/Verifier_register_kyc.sol
new file mode 100644
index 0000000000..263f6efd9e
--- /dev/null
+++ b/contracts/contracts/verifiers/register_kyc/Verifier_register_kyc.sol
@@ -0,0 +1,189 @@
+// SPDX-License-Identifier: GPL-3.0
+/*
+ Copyright 2021 0KIMS association.
+
+ This file is generated with [snarkJS](https://github.com/iden3/snarkjs).
+
+ snarkJS is a free software: you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ snarkJS is distributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+ License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with snarkJS. If not, see .
+*/
+
+pragma solidity >=0.7.0 <0.9.0;
+
+contract Verifier_register_kyc {
+ // Scalar field size
+ uint256 constant r = 21888242871839275222246405745257275088548364400416034343698204186575808495617;
+ // Base field size
+ uint256 constant q = 21888242871839275222246405745257275088696311157297823662689037894645226208583;
+
+ // Verification Key data
+ uint256 constant alphax = 20491192805390485299153009773594534940189261866228447918068658471970481763042;
+ uint256 constant alphay = 9383485363053290200918347156157836566562967994039712273449902621266178545958;
+ uint256 constant betax1 = 4252822878758300859123897981450591353533073413197771768651442665752259397132;
+ uint256 constant betax2 = 6375614351688725206403948262868962793625744043794305715222011528459656738731;
+ uint256 constant betay1 = 21847035105528745403288232691147584728191162732299865338377159692350059136679;
+ uint256 constant betay2 = 10505242626370262277552901082094356697409835680220590971873171140371331206856;
+ uint256 constant gammax1 = 11559732032986387107991004021392285783925812861821192530917403151452391805634;
+ uint256 constant gammax2 = 10857046999023057135944570762232829481370756359578518086990519993285655852781;
+ uint256 constant gammay1 = 4082367875863433681332203403145435568316851327593401208105741076214120093531;
+ uint256 constant gammay2 = 8495653923123431417604973247489272438418190587263600148770280649306958101930;
+ uint256 constant deltax1 = 5096083179356499711134631633887324869705417987781707067448982643113793288629;
+ uint256 constant deltax2 = 21697837263794337150638011065730493662458737594964062811076864693347158601584;
+ uint256 constant deltay1 = 10401404284625717188368140886450294801087446278285114268746933223843924747393;
+ uint256 constant deltay2 = 21623976071772575613470418289568781837131470676146510317928308200173145329920;
+
+
+ uint256 constant IC0x = 3168135977548073774669686196671110956985263260631963004209946350111009871783;
+ uint256 constant IC0y = 19251271161827058925074199219712324559154387560340229136388386911360884273664;
+
+ uint256 constant IC1x = 10113211405751296270501192543847397464767605934439509015058826831045146327835;
+ uint256 constant IC1y = 20906232714001423808044993672348326367907746369031125809295685889757083482955;
+
+ uint256 constant IC2x = 6698755477482983343149024614634334433817620579582112164753380215391423709716;
+ uint256 constant IC2y = 19611748192038263311129103965451949878445716642076010695268731681711285170849;
+
+ uint256 constant IC3x = 14337814476916517064830141950947112575746971807933737544800387322677759596630;
+ uint256 constant IC3y = 20134363192770038065525691357184427373049635942597185153353604022941231384818;
+
+ uint256 constant IC4x = 11598465374717791235735036209864180918816853983932860910077820062417244512066;
+ uint256 constant IC4y = 10915386471964999341016166937952548568058036159601535214565672698374193076432;
+
+
+ // Memory data
+ uint16 constant pVk = 0;
+ uint16 constant pPairing = 128;
+
+ uint16 constant pLastMem = 896;
+
+ function verifyProof(uint[2] calldata _pA, uint[2][2] calldata _pB, uint[2] calldata _pC, uint[4] calldata _pubSignals) public view returns (bool) {
+ assembly {
+ function checkField(v) {
+ if iszero(lt(v, r)) {
+ mstore(0, 0)
+ return(0, 0x20)
+ }
+ }
+
+ // G1 function to multiply a G1 value(x,y) to value in an address
+ function g1_mulAccC(pR, x, y, s) {
+ let success
+ let mIn := mload(0x40)
+ mstore(mIn, x)
+ mstore(add(mIn, 32), y)
+ mstore(add(mIn, 64), s)
+
+ success := staticcall(sub(gas(), 2000), 7, mIn, 96, mIn, 64)
+
+ if iszero(success) {
+ mstore(0, 0)
+ return(0, 0x20)
+ }
+
+ mstore(add(mIn, 64), mload(pR))
+ mstore(add(mIn, 96), mload(add(pR, 32)))
+
+ success := staticcall(sub(gas(), 2000), 6, mIn, 128, pR, 64)
+
+ if iszero(success) {
+ mstore(0, 0)
+ return(0, 0x20)
+ }
+ }
+
+ function checkPairing(pA, pB, pC, pubSignals, pMem) -> isOk {
+ let _pPairing := add(pMem, pPairing)
+ let _pVk := add(pMem, pVk)
+
+ mstore(_pVk, IC0x)
+ mstore(add(_pVk, 32), IC0y)
+
+ // Compute the linear combination vk_x
+
+ g1_mulAccC(_pVk, IC1x, IC1y, calldataload(add(pubSignals, 0)))
+
+ g1_mulAccC(_pVk, IC2x, IC2y, calldataload(add(pubSignals, 32)))
+
+ g1_mulAccC(_pVk, IC3x, IC3y, calldataload(add(pubSignals, 64)))
+
+ g1_mulAccC(_pVk, IC4x, IC4y, calldataload(add(pubSignals, 96)))
+
+
+ // -A
+ mstore(_pPairing, calldataload(pA))
+ mstore(add(_pPairing, 32), mod(sub(q, calldataload(add(pA, 32))), q))
+
+ // B
+ mstore(add(_pPairing, 64), calldataload(pB))
+ mstore(add(_pPairing, 96), calldataload(add(pB, 32)))
+ mstore(add(_pPairing, 128), calldataload(add(pB, 64)))
+ mstore(add(_pPairing, 160), calldataload(add(pB, 96)))
+
+ // alpha1
+ mstore(add(_pPairing, 192), alphax)
+ mstore(add(_pPairing, 224), alphay)
+
+ // beta2
+ mstore(add(_pPairing, 256), betax1)
+ mstore(add(_pPairing, 288), betax2)
+ mstore(add(_pPairing, 320), betay1)
+ mstore(add(_pPairing, 352), betay2)
+
+ // vk_x
+ mstore(add(_pPairing, 384), mload(add(pMem, pVk)))
+ mstore(add(_pPairing, 416), mload(add(pMem, add(pVk, 32))))
+
+
+ // gamma2
+ mstore(add(_pPairing, 448), gammax1)
+ mstore(add(_pPairing, 480), gammax2)
+ mstore(add(_pPairing, 512), gammay1)
+ mstore(add(_pPairing, 544), gammay2)
+
+ // C
+ mstore(add(_pPairing, 576), calldataload(pC))
+ mstore(add(_pPairing, 608), calldataload(add(pC, 32)))
+
+ // delta2
+ mstore(add(_pPairing, 640), deltax1)
+ mstore(add(_pPairing, 672), deltax2)
+ mstore(add(_pPairing, 704), deltay1)
+ mstore(add(_pPairing, 736), deltay2)
+
+
+ let success := staticcall(sub(gas(), 2000), 8, _pPairing, 768, _pPairing, 0x20)
+
+ isOk := and(success, mload(_pPairing))
+ }
+
+ let pMem := mload(0x40)
+ mstore(0x40, add(pMem, pLastMem))
+
+ // Validate that all evaluations ∈ F
+
+ checkField(calldataload(add(_pubSignals, 0)))
+
+ checkField(calldataload(add(_pubSignals, 32)))
+
+ checkField(calldataload(add(_pubSignals, 64)))
+
+ checkField(calldataload(add(_pubSignals, 96)))
+
+
+ // Validate all evaluations
+ let isValid := checkPairing(_pA, _pB, _pC, _pubSignals, pMem)
+
+ mstore(0, isValid)
+ return(0, 0x20)
+ }
+ }
+ }
From 72c2b08334ef697f274517daf2e000acdf0af5b3 Mon Sep 17 00:00:00 2001
From: Nesopie <87437291+Nesopie@users.noreply.github.com>
Date: Fri, 30 Jan 2026 08:49:39 +0530
Subject: [PATCH 3/7] feat: add gcp jwt verifier (#1674)
---
.../verifiers/gcp/Verifier_gcp_jwt.sol | 301 ++++++++++++++++++
1 file changed, 301 insertions(+)
create mode 100644 contracts/contracts/verifiers/gcp/Verifier_gcp_jwt.sol
diff --git a/contracts/contracts/verifiers/gcp/Verifier_gcp_jwt.sol b/contracts/contracts/verifiers/gcp/Verifier_gcp_jwt.sol
new file mode 100644
index 0000000000..4d36ea61cd
--- /dev/null
+++ b/contracts/contracts/verifiers/gcp/Verifier_gcp_jwt.sol
@@ -0,0 +1,301 @@
+// SPDX-License-Identifier: GPL-3.0
+/*
+ Copyright 2021 0KIMS association.
+
+ This file is generated with [snarkJS](https://github.com/iden3/snarkjs).
+
+ snarkJS is a free software: you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ snarkJS is distributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+ License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with snarkJS. If not, see .
+*/
+
+pragma solidity >=0.7.0 <0.9.0;
+
+contract Verifier_gcp_jwt {
+ // Scalar field size
+ uint256 constant r = 21888242871839275222246405745257275088548364400416034343698204186575808495617;
+ // Base field size
+ uint256 constant q = 21888242871839275222246405745257275088696311157297823662689037894645226208583;
+
+ // Verification Key data
+ uint256 constant alphax = 20491192805390485299153009773594534940189261866228447918068658471970481763042;
+ uint256 constant alphay = 9383485363053290200918347156157836566562967994039712273449902621266178545958;
+ uint256 constant betax1 = 4252822878758300859123897981450591353533073413197771768651442665752259397132;
+ uint256 constant betax2 = 6375614351688725206403948262868962793625744043794305715222011528459656738731;
+ uint256 constant betay1 = 21847035105528745403288232691147584728191162732299865338377159692350059136679;
+ uint256 constant betay2 = 10505242626370262277552901082094356697409835680220590971873171140371331206856;
+ uint256 constant gammax1 = 11559732032986387107991004021392285783925812861821192530917403151452391805634;
+ uint256 constant gammax2 = 10857046999023057135944570762232829481370756359578518086990519993285655852781;
+ uint256 constant gammay1 = 4082367875863433681332203403145435568316851327593401208105741076214120093531;
+ uint256 constant gammay2 = 8495653923123431417604973247489272438418190587263600148770280649306958101930;
+ uint256 constant deltax1 = 1804222383802986733937376810902861143401033555807870231731929239915419049861;
+ uint256 constant deltax2 = 15902885537441599351050098769394227668772388058868388096316964244217496511682;
+ uint256 constant deltay1 = 4195707504005103778106485021796359604414786496137920116128130440872062477216;
+ uint256 constant deltay2 = 20513207510859042996645896574478474889840017920990203652675014165180462273668;
+
+
+ uint256 constant IC0x = 6972951741762339913362267428319005943611938060812676091174501911982947323821;
+ uint256 constant IC0y = 4968121098705797351946375443564156998686441710551907423285338106315203657372;
+
+ uint256 constant IC1x = 3969479803545901558882616933276060341612655312403217371718193775571328202698;
+ uint256 constant IC1y = 10796516354190443333590906104065573186594421836191093099894208495600273943382;
+
+ uint256 constant IC2x = 5282886783908067346990928387588210996099802199800176473402519317523182497411;
+ uint256 constant IC2y = 13420701105707643769706876856296866111708803407614711871170325095961081369695;
+
+ uint256 constant IC3x = 14105950545034420261862110084277090993607573654064743638564927148396262651666;
+ uint256 constant IC3y = 13354956139782865997977495342720245140716772080136555810660173122394181127180;
+
+ uint256 constant IC4x = 17223368406124250621460330134418760536341963146179581332507963390797809647912;
+ uint256 constant IC4y = 19015620010364835231555497011683709184643217460850880718542989960325995808017;
+
+ uint256 constant IC5x = 11415362657438949221591074018468802007898322076011964898865456054649179831908;
+ uint256 constant IC5y = 17459573325598515038912928408360066384367356809087828399079121874232360528478;
+
+ uint256 constant IC6x = 15574545936483334745596750909280550198515448424427848182054643607937078179213;
+ uint256 constant IC6y = 13006549512473282147197122913454973085866920937923147249375738521329287066222;
+
+ uint256 constant IC7x = 14645989050046479540147134517500433000682841795623944679511623689017979403245;
+ uint256 constant IC7y = 16002146776744341769994596125501558460157837756621333957158039132600774201665;
+
+ uint256 constant IC8x = 17447612904927318100653430764709204605475101707883725218472729377143326600248;
+ uint256 constant IC8y = 16892886274335002504909275077153679691684214526248560805118560019125943648821;
+
+ uint256 constant IC9x = 17653661950237194880278154054792568909474176263902202958186273149474358670533;
+ uint256 constant IC9y = 11669219494719975955790450067861506164332870357879984076098486608481987018857;
+
+ uint256 constant IC10x = 13289207501149959620194929372715676920560830325500657282490914929267428690980;
+ uint256 constant IC10y = 12465657438099014694334055521610703216229866770917539818266695642349007426072;
+
+ uint256 constant IC11x = 18446654622136293276199162514838693836980616816456314636743905193625590745253;
+ uint256 constant IC11y = 12876916821064374752505779861869326377989533450827838519593872009453598320656;
+
+ uint256 constant IC12x = 11001381773587677694421240176598022327285567125732057704900785068521955604564;
+ uint256 constant IC12y = 15721905323957520285870204323317542530315127175554829712351392669354944626115;
+
+ uint256 constant IC13x = 19526090904722047042773905186611760547729403485756211734248157863388135796357;
+ uint256 constant IC13y = 6872421404352779784414693997079152972445035104903743503355279949152744176183;
+
+ uint256 constant IC14x = 15194138441068760983236111544251338084740306295420897247383092303969333517280;
+ uint256 constant IC14y = 17571382599242644993857901274570230804168370452582601899367177574780143361956;
+
+ uint256 constant IC15x = 584870595147362727880838486101127854955042037369856345600359023707849233383;
+ uint256 constant IC15y = 12343643073139461156226272211050331809098122200356986708169739203244290558425;
+
+ uint256 constant IC16x = 14164891277783985284859197223195840777194061449283527719178608169082529731883;
+ uint256 constant IC16y = 5769361895392815047832493230313789373949187154386769492255962435984388734;
+
+ uint256 constant IC17x = 5526583431755874525920531779957581117218605045719526246142282984128225259812;
+ uint256 constant IC17y = 15582261976988135470726322969910254124942972597198825965150134549937865280024;
+
+ uint256 constant IC18x = 11933687532433713666089789805193821666211611847890385200532102102696090562695;
+ uint256 constant IC18y = 13768581020150988368938923899239734752213497676691170616636813895788587803927;
+
+ uint256 constant IC19x = 21039243000302785560612608554208434709650210545299036143304628975668975303432;
+ uint256 constant IC19y = 3072044020424624557872621541718589400992098528118783904368755425332969903054;
+
+ uint256 constant IC20x = 13029408846315391045768292892963336300734709802776968717851605403617397448869;
+ uint256 constant IC20y = 21441391199269244274037661931659719640029973634066921385003370500690694569608;
+
+
+ // Memory data
+ uint16 constant pVk = 0;
+ uint16 constant pPairing = 128;
+
+ uint16 constant pLastMem = 896;
+
+ function verifyProof(uint[2] calldata _pA, uint[2][2] calldata _pB, uint[2] calldata _pC, uint[20] calldata _pubSignals) public view returns (bool) {
+ assembly {
+ function checkField(v) {
+ if iszero(lt(v, r)) {
+ mstore(0, 0)
+ return(0, 0x20)
+ }
+ }
+
+ // G1 function to multiply a G1 value(x,y) to value in an address
+ function g1_mulAccC(pR, x, y, s) {
+ let success
+ let mIn := mload(0x40)
+ mstore(mIn, x)
+ mstore(add(mIn, 32), y)
+ mstore(add(mIn, 64), s)
+
+ success := staticcall(sub(gas(), 2000), 7, mIn, 96, mIn, 64)
+
+ if iszero(success) {
+ mstore(0, 0)
+ return(0, 0x20)
+ }
+
+ mstore(add(mIn, 64), mload(pR))
+ mstore(add(mIn, 96), mload(add(pR, 32)))
+
+ success := staticcall(sub(gas(), 2000), 6, mIn, 128, pR, 64)
+
+ if iszero(success) {
+ mstore(0, 0)
+ return(0, 0x20)
+ }
+ }
+
+ function checkPairing(pA, pB, pC, pubSignals, pMem) -> isOk {
+ let _pPairing := add(pMem, pPairing)
+ let _pVk := add(pMem, pVk)
+
+ mstore(_pVk, IC0x)
+ mstore(add(_pVk, 32), IC0y)
+
+ // Compute the linear combination vk_x
+
+ g1_mulAccC(_pVk, IC1x, IC1y, calldataload(add(pubSignals, 0)))
+
+ g1_mulAccC(_pVk, IC2x, IC2y, calldataload(add(pubSignals, 32)))
+
+ g1_mulAccC(_pVk, IC3x, IC3y, calldataload(add(pubSignals, 64)))
+
+ g1_mulAccC(_pVk, IC4x, IC4y, calldataload(add(pubSignals, 96)))
+
+ g1_mulAccC(_pVk, IC5x, IC5y, calldataload(add(pubSignals, 128)))
+
+ g1_mulAccC(_pVk, IC6x, IC6y, calldataload(add(pubSignals, 160)))
+
+ g1_mulAccC(_pVk, IC7x, IC7y, calldataload(add(pubSignals, 192)))
+
+ g1_mulAccC(_pVk, IC8x, IC8y, calldataload(add(pubSignals, 224)))
+
+ g1_mulAccC(_pVk, IC9x, IC9y, calldataload(add(pubSignals, 256)))
+
+ g1_mulAccC(_pVk, IC10x, IC10y, calldataload(add(pubSignals, 288)))
+
+ g1_mulAccC(_pVk, IC11x, IC11y, calldataload(add(pubSignals, 320)))
+
+ g1_mulAccC(_pVk, IC12x, IC12y, calldataload(add(pubSignals, 352)))
+
+ g1_mulAccC(_pVk, IC13x, IC13y, calldataload(add(pubSignals, 384)))
+
+ g1_mulAccC(_pVk, IC14x, IC14y, calldataload(add(pubSignals, 416)))
+
+ g1_mulAccC(_pVk, IC15x, IC15y, calldataload(add(pubSignals, 448)))
+
+ g1_mulAccC(_pVk, IC16x, IC16y, calldataload(add(pubSignals, 480)))
+
+ g1_mulAccC(_pVk, IC17x, IC17y, calldataload(add(pubSignals, 512)))
+
+ g1_mulAccC(_pVk, IC18x, IC18y, calldataload(add(pubSignals, 544)))
+
+ g1_mulAccC(_pVk, IC19x, IC19y, calldataload(add(pubSignals, 576)))
+
+ g1_mulAccC(_pVk, IC20x, IC20y, calldataload(add(pubSignals, 608)))
+
+
+ // -A
+ mstore(_pPairing, calldataload(pA))
+ mstore(add(_pPairing, 32), mod(sub(q, calldataload(add(pA, 32))), q))
+
+ // B
+ mstore(add(_pPairing, 64), calldataload(pB))
+ mstore(add(_pPairing, 96), calldataload(add(pB, 32)))
+ mstore(add(_pPairing, 128), calldataload(add(pB, 64)))
+ mstore(add(_pPairing, 160), calldataload(add(pB, 96)))
+
+ // alpha1
+ mstore(add(_pPairing, 192), alphax)
+ mstore(add(_pPairing, 224), alphay)
+
+ // beta2
+ mstore(add(_pPairing, 256), betax1)
+ mstore(add(_pPairing, 288), betax2)
+ mstore(add(_pPairing, 320), betay1)
+ mstore(add(_pPairing, 352), betay2)
+
+ // vk_x
+ mstore(add(_pPairing, 384), mload(add(pMem, pVk)))
+ mstore(add(_pPairing, 416), mload(add(pMem, add(pVk, 32))))
+
+
+ // gamma2
+ mstore(add(_pPairing, 448), gammax1)
+ mstore(add(_pPairing, 480), gammax2)
+ mstore(add(_pPairing, 512), gammay1)
+ mstore(add(_pPairing, 544), gammay2)
+
+ // C
+ mstore(add(_pPairing, 576), calldataload(pC))
+ mstore(add(_pPairing, 608), calldataload(add(pC, 32)))
+
+ // delta2
+ mstore(add(_pPairing, 640), deltax1)
+ mstore(add(_pPairing, 672), deltax2)
+ mstore(add(_pPairing, 704), deltay1)
+ mstore(add(_pPairing, 736), deltay2)
+
+
+ let success := staticcall(sub(gas(), 2000), 8, _pPairing, 768, _pPairing, 0x20)
+
+ isOk := and(success, mload(_pPairing))
+ }
+
+ let pMem := mload(0x40)
+ mstore(0x40, add(pMem, pLastMem))
+
+ // Validate that all evaluations ∈ F
+
+ checkField(calldataload(add(_pubSignals, 0)))
+
+ checkField(calldataload(add(_pubSignals, 32)))
+
+ checkField(calldataload(add(_pubSignals, 64)))
+
+ checkField(calldataload(add(_pubSignals, 96)))
+
+ checkField(calldataload(add(_pubSignals, 128)))
+
+ checkField(calldataload(add(_pubSignals, 160)))
+
+ checkField(calldataload(add(_pubSignals, 192)))
+
+ checkField(calldataload(add(_pubSignals, 224)))
+
+ checkField(calldataload(add(_pubSignals, 256)))
+
+ checkField(calldataload(add(_pubSignals, 288)))
+
+ checkField(calldataload(add(_pubSignals, 320)))
+
+ checkField(calldataload(add(_pubSignals, 352)))
+
+ checkField(calldataload(add(_pubSignals, 384)))
+
+ checkField(calldataload(add(_pubSignals, 416)))
+
+ checkField(calldataload(add(_pubSignals, 448)))
+
+ checkField(calldataload(add(_pubSignals, 480)))
+
+ checkField(calldataload(add(_pubSignals, 512)))
+
+ checkField(calldataload(add(_pubSignals, 544)))
+
+ checkField(calldataload(add(_pubSignals, 576)))
+
+ checkField(calldataload(add(_pubSignals, 608)))
+
+
+ // Validate all evaluations
+ let isValid := checkPairing(_pA, _pB, _pC, _pubSignals, pMem)
+
+ mstore(0, isValid)
+ return(0, 0x20)
+ }
+ }
+ }
From f11e8606594c89a5b3e735a62c26c1600893fa25 Mon Sep 17 00:00:00 2001
From: Nesopie <87437291+Nesopie@users.noreply.github.com>
Date: Fri, 30 Jan 2026 20:45:56 +0530
Subject: [PATCH 4/7] fix: use pubsignals length of 20 (#1675)
---
.../registry/IdentityRegistryKycImplV1.sol | 18 +++++++++---------
.../contracts/tests/MockGCPJWTVerifier.sol | 2 +-
contracts/test/v2/registerKyc.test.ts | 9 +++++++++
3 files changed, 19 insertions(+), 10 deletions(-)
diff --git a/contracts/contracts/registry/IdentityRegistryKycImplV1.sol b/contracts/contracts/registry/IdentityRegistryKycImplV1.sol
index 437925cd1d..feae4e1448 100644
--- a/contracts/contracts/registry/IdentityRegistryKycImplV1.sol
+++ b/contracts/contracts/registry/IdentityRegistryKycImplV1.sol
@@ -92,7 +92,7 @@ interface IGCPJWTVerifier {
uint256[2] calldata pA,
uint256[2][2] calldata pB,
uint256[2] calldata pC,
- uint256[19] calldata pubSignals
+ uint256[20] calldata pubSignals
) external view returns (bool);
}
@@ -450,7 +450,7 @@ contract IdentityRegistryKycImplV1 is IdentityRegistryKycStorageV1, IIdentityReg
uint256[2] calldata pA,
uint256[2][2] calldata pB,
uint256[2] calldata pC,
- uint256[19] calldata pubSignals
+ uint256[20] calldata pubSignals
) external onlyProxy onlyTEE {
// Check if the proof is valid
if (!IGCPJWTVerifier(_gcpJwtVerifier).verifyProof(pA, pB, pC, pubSignals)) revert INVALID_PROOF();
@@ -459,19 +459,19 @@ contract IdentityRegistryKycImplV1 is IdentityRegistryKycStorageV1, IIdentityReg
if (pubSignals[0] != _gcpRootCAPubkeyHash) revert INVALID_ROOT_CA();
// Check if the TEE image hash is valid
- bytes memory imageHash = GCPJWTHelper.unpackAndConvertImageHash(pubSignals[4], pubSignals[5], pubSignals[6]);
+ bytes memory imageHash = GCPJWTHelper.unpackAndConvertImageHash(pubSignals[5], pubSignals[6], pubSignals[7]);
if (!IPCR0Manager(_PCR0Manager).isPCR0Set(imageHash)) revert INVALID_IMAGE();
// Unpack the pubkey and register it
uint256 pubkeyCommitment = GCPJWTHelper.unpackAndDecodeHexPubkey(pubSignals[1], pubSignals[2], pubSignals[3]);
_isRegisteredPubkeyCommitment[pubkeyCommitment] = true;
- uint256 currentYear = 2000 + pubSignals[7] * 10 + pubSignals[8];
- uint256 currentMonth = pubSignals[9] * 10 + pubSignals[10];
- uint256 currentDay = pubSignals[11] * 10 + pubSignals[12];
- uint256 currentHour = pubSignals[13] * 10 + pubSignals[14];
- uint256 currentMinute = pubSignals[15] * 10 + pubSignals[16];
- uint256 currentSecond = pubSignals[17] * 10 + pubSignals[18];
+ uint256 currentYear = 2000 + pubSignals[8] * 10 + pubSignals[9];
+ uint256 currentMonth = pubSignals[10] * 10 + pubSignals[11];
+ uint256 currentDay = pubSignals[12] * 10 + pubSignals[13];
+ uint256 currentHour = pubSignals[14] * 10 + pubSignals[15];
+ uint256 currentMinute = pubSignals[16] * 10 + pubSignals[17];
+ uint256 currentSecond = pubSignals[18] * 10 + pubSignals[19];
uint256 currentTimestamp = Formatter.toTimeStampWithSeconds(
currentYear,
currentMonth,
diff --git a/contracts/contracts/tests/MockGCPJWTVerifier.sol b/contracts/contracts/tests/MockGCPJWTVerifier.sol
index 3183233521..81708a1857 100644
--- a/contracts/contracts/tests/MockGCPJWTVerifier.sol
+++ b/contracts/contracts/tests/MockGCPJWTVerifier.sol
@@ -29,7 +29,7 @@ contract MockGCPJWTVerifier {
uint256[2] calldata pA,
uint256[2][2] calldata pB,
uint256[2] calldata pC,
- uint256[19] calldata pubSignals
+ uint256[20] calldata pubSignals
) external view returns (bool) {
// Silence unused variable warnings
pA;
diff --git a/contracts/test/v2/registerKyc.test.ts b/contracts/test/v2/registerKyc.test.ts
index 96e3775bc3..42db8ba30e 100644
--- a/contracts/test/v2/registerKyc.test.ts
+++ b/contracts/test/v2/registerKyc.test.ts
@@ -128,6 +128,7 @@ describe("KYC Registration test", function () {
p0,
p1,
p2,
+ 0n,
testImageHash.p0,
testImageHash.p1,
testImageHash.p2,
@@ -242,6 +243,7 @@ describe("KYC Registration test", function () {
1n,
2n,
3n,
+ 0n,
4n,
5n,
6n,
@@ -273,6 +275,7 @@ describe("KYC Registration test", function () {
1n,
2n,
3n,
+ 0n,
4n,
5n,
6n,
@@ -322,6 +325,7 @@ describe("KYC Registration test", function () {
1n,
2n,
3n,
+ 0n,
4n,
5n,
6n,
@@ -356,6 +360,7 @@ describe("KYC Registration test", function () {
p0,
p1,
p2,
+ 0n,
177384435506496807268973340845468654286294928521500580044819492874465981028n,
175298970718174405520284770870231222447414486446296682893283627688949855078n,
13360n,
@@ -379,6 +384,7 @@ describe("KYC Registration test", function () {
p0,
p1,
p2,
+ 0n,
177384435506496807268973340845468654286294928521500580044819492874465981028n,
175298970718174405520284770870231222447414486446296682893283627688949855078n,
13360n,
@@ -417,6 +423,7 @@ describe("KYC Registration test", function () {
1n,
2n,
3n,
+ 0n,
4n,
5n,
6n,
@@ -434,6 +441,7 @@ describe("KYC Registration test", function () {
1n,
2n,
3n,
+ 0n,
4n,
5n,
6n,
@@ -451,6 +459,7 @@ describe("KYC Registration test", function () {
1n,
2n,
3n,
+ 0n,
4n,
5n,
6n,
From a6c84d80f7a3e58905ec367cb9e25b576b8a0655 Mon Sep 17 00:00:00 2001
From: Leszek Stachowski
Date: Fri, 30 Jan 2026 18:35:32 +0100
Subject: [PATCH 5/7] feat(kyc): register fcm token for sumsub verification
(#1673)
* feat(kyc): register fcm token for sumsub verification
* fix tests
* remove unused import
* fix lint
---
app/env.ts | 2 +-
app/src/navigation/index.tsx | 7 +-
app/src/providers/selfClientProvider.tsx | 4 +-
app/src/screens/kyc/KycSuccessScreen.tsx | 47 ++++-
.../notifications/notificationService.ts | 5 +
.../src/screens/kyc/KycSuccessScreen.test.tsx | 196 +++++++++++++++++-
6 files changed, 240 insertions(+), 21 deletions(-)
diff --git a/app/env.ts b/app/env.ts
index c5e041280e..52eacf5063 100644
--- a/app/env.ts
+++ b/app/env.ts
@@ -27,6 +27,7 @@ export const IS_TEST_BUILD = process.env.IS_TEST_BUILD === 'true';
export const MIXPANEL_NFC_PROJECT_TOKEN = undefined;
export const SEGMENT_KEY = process.env.SEGMENT_KEY;
+export const SELF_UUID_NAMESPACE = process.env.SELF_UUID_NAMESPACE;
export const SENTRY_DSN = process.env.SENTRY_DSN;
export const SUMSUB_TEE_URL =
process.env.SUMSUB_TEE_URL || 'http://localhost:8080';
@@ -34,6 +35,5 @@ export const SUMSUB_TEST_TOKEN = process.env.SUMSUB_TEST_TOKEN;
export const TURNKEY_AUTH_PROXY_CONFIG_ID =
process.env.TURNKEY_AUTH_PROXY_CONFIG_ID;
-
export const TURNKEY_GOOGLE_CLIENT_ID = process.env.TURNKEY_GOOGLE_CLIENT_ID;
export const TURNKEY_ORGANIZATION_ID = process.env.TURNKEY_ORGANIZATION_ID;
diff --git a/app/src/navigation/index.tsx b/app/src/navigation/index.tsx
index 17f90209bc..d7dfb4ed56 100644
--- a/app/src/navigation/index.tsx
+++ b/app/src/navigation/index.tsx
@@ -79,6 +79,7 @@ export type RootStackParamList = Omit<
| 'Home'
| 'IDPicker'
| 'IdDetails'
+ | 'KycSuccess'
| 'RegistrationFallback'
| 'Loading'
| 'Modal'
@@ -201,7 +202,11 @@ export type RootStackParamList = Omit<
// Onboarding screens
Disclaimer: undefined;
- KycSuccess: undefined;
+ KycSuccess:
+ | {
+ userId?: string;
+ }
+ | undefined;
// Dev screens
CreateMock: undefined;
diff --git a/app/src/providers/selfClientProvider.tsx b/app/src/providers/selfClientProvider.tsx
index 28f9abe5fa..6bfbc9c2e4 100644
--- a/app/src/providers/selfClientProvider.tsx
+++ b/app/src/providers/selfClientProvider.tsx
@@ -380,7 +380,9 @@ export const SelfClientProvider = ({ children }: PropsWithChildren) => {
// Success case: navigate to KYC success screen
if (navigationRef.isReady()) {
- navigationRef.navigate('KycSuccess');
+ navigationRef.navigate('KycSuccess', {
+ userId: accessToken.userId,
+ });
}
} catch (error) {
const safeInitError = sanitizeErrorMessage(
diff --git a/app/src/screens/kyc/KycSuccessScreen.tsx b/app/src/screens/kyc/KycSuccessScreen.tsx
index 22849692cd..3269da141e 100644
--- a/app/src/screens/kyc/KycSuccessScreen.tsx
+++ b/app/src/screens/kyc/KycSuccessScreen.tsx
@@ -2,37 +2,70 @@
// SPDX-License-Identifier: BUSL-1.1
// NOTE: Converts to Apache-2.0 on 2029-06-11 per LICENSE.
-import React from 'react';
+import React, { useCallback } from 'react';
import { StyleSheet, View } from 'react-native';
import { useSafeAreaInsets } from 'react-native-safe-area-context';
import { YStack } from 'tamagui';
+import { v5 as uuidv5 } from 'uuid';
+import type { StaticScreenProps } from '@react-navigation/native';
import { useNavigation } from '@react-navigation/native';
import type { NativeStackNavigationProp } from '@react-navigation/native-stack';
-import { DelayedLottieView } from '@selfxyz/mobile-sdk-alpha';
+import { DelayedLottieView, useSelfClient } from '@selfxyz/mobile-sdk-alpha';
import loadingAnimation from '@selfxyz/mobile-sdk-alpha/animations/loading/misc.json';
import {
AbstractButton,
Description,
Title,
} from '@selfxyz/mobile-sdk-alpha/components';
+import { ProofEvents } from '@selfxyz/mobile-sdk-alpha/constants/analytics';
import { black, white } from '@selfxyz/mobile-sdk-alpha/constants/colors';
import { buttonTap } from '@/integrations/haptics';
import type { RootStackParamList } from '@/navigation';
-import { requestNotificationPermission } from '@/services/notifications/notificationService';
+import {
+ getFCMToken,
+ getSelfUuidNamespace,
+ registerDeviceToken,
+ requestNotificationPermission,
+} from '@/services/notifications/notificationService';
+import { useSettingStore } from '@/stores/settingStore';
+
+type KycSuccessRouteParams = StaticScreenProps<
+ | {
+ userId?: string;
+ }
+ | undefined
+>;
-const KycSuccessScreen: React.FC = () => {
+const KycSuccessScreen: React.FC = ({
+ route: { params },
+}) => {
const navigation =
useNavigation>();
+ const userId = params?.userId;
const insets = useSafeAreaInsets();
+ const setFcmToken = useSettingStore(state => state.setFcmToken);
+ const selfClient = useSelfClient();
+ const { trackEvent } = selfClient;
- const handleReceiveUpdates = async () => {
+ const handleReceiveUpdates = useCallback(async () => {
buttonTap();
- await requestNotificationPermission();
+
+ if ((await requestNotificationPermission()) && userId) {
+ const token = await getFCMToken();
+ if (token) {
+ setFcmToken(token);
+ trackEvent(ProofEvents.FCM_TOKEN_STORED);
+
+ const sessionId = uuidv5(userId, getSelfUuidNamespace());
+ await registerDeviceToken(sessionId, token);
+ }
+ }
+
// Navigate to Home regardless of permission result
navigation.navigate('Home', {});
- };
+ }, [navigation, setFcmToken, trackEvent, userId]);
const handleCheckLater = () => {
buttonTap();
diff --git a/app/src/services/notifications/notificationService.ts b/app/src/services/notifications/notificationService.ts
index 87fe09ec60..159201e341 100644
--- a/app/src/services/notifications/notificationService.ts
+++ b/app/src/services/notifications/notificationService.ts
@@ -3,6 +3,7 @@
// NOTE: Converts to Apache-2.0 on 2029-06-11 per LICENSE.
import { PermissionsAndroid, Platform } from 'react-native';
+import { SELF_UUID_NAMESPACE } from '@env';
import type { FirebaseMessagingTypes } from '@react-native-firebase/messaging';
import messaging from '@react-native-firebase/messaging';
@@ -36,6 +37,10 @@ const error = (...args: unknown[]) => {
if (!isTestEnv) console.error(...args);
};
+export function getSelfUuidNamespace(): string {
+ return SELF_UUID_NAMESPACE ?? '';
+}
+
export { getStateMessage };
export async function isNotificationSystemReady(): Promise<{
diff --git a/app/tests/src/screens/kyc/KycSuccessScreen.test.tsx b/app/tests/src/screens/kyc/KycSuccessScreen.test.tsx
index ea8cc6c72d..48d37a7d72 100644
--- a/app/tests/src/screens/kyc/KycSuccessScreen.test.tsx
+++ b/app/tests/src/screens/kyc/KycSuccessScreen.test.tsx
@@ -3,8 +3,9 @@
// NOTE: Converts to Apache-2.0 on 2029-06-11 per LICENSE.
import React from 'react';
+import { v5 as uuidv5 } from 'uuid';
import { useNavigation } from '@react-navigation/native';
-import { render } from '@testing-library/react-native';
+import { fireEvent, render, waitFor } from '@testing-library/react-native';
import ErrorBoundary from '@/components/ErrorBoundary';
import KycSuccessScreen from '@/screens/kyc/KycSuccessScreen';
@@ -46,10 +47,6 @@ jest.mock('tamagui', () => ({
Text: ({ children, ...props }: any) => {children},
}));
-jest.mock('@selfxyz/mobile-sdk-alpha', () => ({
- DelayedLottieView: () => null,
-}));
-
jest.mock('@selfxyz/mobile-sdk-alpha/constants/colors', () => ({
black: '#000000',
white: '#FFFFFF',
@@ -57,17 +54,17 @@ jest.mock('@selfxyz/mobile-sdk-alpha/constants/colors', () => ({
jest.mock('@selfxyz/mobile-sdk-alpha/components', () => ({
AbstractButton: ({ children, onPress }: any) => (
-