Skip to content

Commit 2c6220a

Browse files
committed
feat: optimize JWT circuit
1 parent 3007d96 commit 2c6220a

8 files changed

Lines changed: 2835 additions & 2629 deletions

File tree

wallet-unit-poc/circom/circuits.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
"jwt": {
33
"file": "jwt",
44
"template": "JWT",
5-
"params": [2048, 256, 2000, 3, 50, 128]
5+
"params": [2048, 2000, 4, 50, 128]
66
},
77
"ecdsa": {
88
"file": "ecdsa/ecdsa",

wallet-unit-poc/circom/circuits/ec-extractor.circom

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,3 +50,43 @@ template ECPublicKeyExtractor(maxPayloadLength, valueCharLen, expectedB64Len, co
5050
pubKeyX <== xToNumber.out;
5151
pubKeyY <== yToNumber.out;
5252
}
53+
54+
// Optimized version using bulk extraction (VarShiftLeft) instead of per-character selection
55+
template ECPublicKeyExtractor_Optimized(maxPayloadLength, coordinateByteLen) {
56+
signal input payload[maxPayloadLength];
57+
signal input xStartIndex;
58+
signal input yStartIndex;
59+
60+
signal output pubKeyX;
61+
signal output pubKeyY;
62+
63+
// Extract 44-char base64 strings in bulk
64+
component xExtractor = VarShiftLeft(maxPayloadLength, 44);
65+
xExtractor.in <== payload;
66+
xExtractor.shift <== xStartIndex;
67+
68+
component yExtractor = VarShiftLeft(maxPayloadLength, 44);
69+
yExtractor.in <== payload;
70+
yExtractor.shift <== yStartIndex;
71+
72+
signal xBase64[44] <== xExtractor.out;
73+
signal yBase64[44] <== yExtractor.out;
74+
75+
// Decode base64url -> bytes
76+
component decodeX = DecodeSD(44, coordinateByteLen);
77+
decodeX.sdBytes <== xBase64;
78+
decodeX.sdLen <== 43;
79+
80+
component decodeY = DecodeSD(44, coordinateByteLen);
81+
decodeY.sdBytes <== yBase64;
82+
decodeY.sdLen <== 43;
83+
84+
component xToNumber = BytesToNumberBE(coordinateByteLen);
85+
xToNumber.in <== decodeX.base64Out;
86+
87+
component yToNumber = BytesToNumberBE(coordinateByteLen);
88+
yToNumber.in <== decodeY.base64Out;
89+
90+
pubKeyX <== xToNumber.out;
91+
pubKeyY <== yToNumber.out;
92+
}

wallet-unit-poc/circom/circuits/jwt.circom

Lines changed: 12 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,13 @@ include "es256.circom";
44
include "keyless_zk_proofs/hashtofield.circom";
55
include "@zk-email/circuits/lib/sha.circom";
66
include "claim-decoder.circom";
7-
include "age-verifier.circom";
87
include "utils.circom";
98
include "payload_matcher.circom";
109
include "ec-extractor.circom";
1110

1211
// Prepare Circuit
1312
template JWT(
1413
maxMessageLength,
15-
maxB64HeaderLength,
1614
maxB64PayloadLength,
1715

1816
maxMatches,
@@ -45,40 +43,29 @@ template JWT(
4543
signal claimHashes[maxMatches][32] <== ClaimHasher(maxMatches, maxClaimsLength)(claims);
4644
ClaimComparator(maxMatches, maxSubstringLength)(claimHashes ,claimLengths, matchSubstring, matchLength);
4745

48-
component es256 = ES256(maxMessageLength);
49-
es256.message <== message;
50-
es256.messageLength <== messageLength;
51-
es256.sig_r <== sig_r;
52-
es256.sig_s_inverse <== sig_s_inverse;
53-
es256.pubKeyX <== pubKeyX;
54-
es256.pubKeyY <== pubKeyY;
55-
56-
component extractor = HeaderPayloadExtractor(maxMessageLength,maxB64HeaderLength, maxB64PayloadLength);
57-
extractor.message <== message;
58-
extractor.messageLength <== messageLength;
59-
extractor.periodIndex <== periodIndex;
46+
// Verify the signature
47+
ES256(maxMessageLength)(message, messageLength, sig_r, sig_s_inverse, pubKeyX, pubKeyY);
6048

49+
signal payload[maxPayloadLength] <== PayloadExtractor(maxMessageLength, maxB64PayloadLength)(message, messageLength, periodIndex);
6150

6251
signal payloadHash <== PayloadSubstringMatcher(maxPayloadLength, maxMatches, maxSubstringLength)(
63-
extractor.payload,
52+
payload,
6453
matchesCount,
6554
matchSubstring,
6655
matchLength,
6756
matchIndex
6857
);
6958

70-
signal xValueStart <== matchIndex[0] + matchLength[0];
71-
signal yValueStart <== matchIndex[1] + matchLength[1];
72-
73-
// 32-byte coordinate -> 44 base64 characters (padding optional -> 43 or 44)
74-
signal xValueEnd <== xValueStart + 43;
75-
signal yValueEnd <== yValueStart + 43;
59+
60+
component ecExtractor = ECPublicKeyExtractor_Optimized(maxPayloadLength, 32);
61+
ecExtractor.payload <== payload;
62+
ecExtractor.xStartIndex <== matchIndex[0] + matchLength[0];
63+
ecExtractor.yStartIndex <== matchIndex[1] + matchLength[1];
7664

77-
component ecExtractor = ECPublicKeyExtractor(maxPayloadLength, maxClaimsLength, 44, 32);
78-
ecExtractor.payload <== extractor.payload;
79-
ecExtractor.xStartIndex <== xValueStart;
80-
ecExtractor.yStartIndex <== yValueStart;
8165

8266
signal output KeyBindingX <== ecExtractor.pubKeyX;
8367
signal output KeyBindingY <== ecExtractor.pubKeyY;
68+
69+
signal output messages[maxMatches][decodedLen];
70+
messages <== decodedClaims;
8471
}

wallet-unit-poc/circom/circuits/main/jwt.circom

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,4 +3,4 @@ pragma circom 2.2.2;
33

44
include "../jwt.circom";
55

6-
component main = JWT(2048, 256, 2000, 3, 50, 128);
6+
component main = JWT(2048, 2000, 4, 50, 128);

0 commit comments

Comments
 (0)