验证zkVerify是否支持worldId的零知识证明
从worldId的资料查看用的是SnarkJS的Groth16,而zkVerify也支持它,因此技术上应该是无缝支持的。
下面将进行验证worldId的proof信息是否可以提交至zkVerify。
tips:验证结果为:可以。
1. 接口约束
zkVerify的验证proofdata接口参数分别为vkey、proof和publicSignals。
2. 参数包装
需要在主网上找一条官方验证通过的交易去解析参数。示例采用的交易信息为https://polygonscan.com/tx/0x5b4faca67d37537575f34ffc9ca9d15cec2f9126b19cdc1c1375c895130a4eaf
2.1 Vkey
合约地址:https://vscode.blockscan.com/137/0xa6d85F3b3bE6Ff6DC52C3aaBe9A35d0ce252b79F
通过阅读代码VerificationKey memory vk = _getVerificationKey(30- 16);
找到对应的vkey信息如下:
{
"protocol": "groth16",
"curve": "bn128",
"nPublic": 1,
"vk_alpha_1": [
"20491192805390485299153009773594534940189261866228447918068658471970481763042",
"9383485363053290200918347156157836566562967994039712273449902621266178545958",
"1"
],
"vk_beta_2": [
[
"6375614351688725206403948262868962793625744043794305715222011528459656738731",
"4252822878758300859123897981450591353533073413197771768651442665752259397132"
],
[
"10505242626370262277552901082094356697409835680220590971873171140371331206856",
"21847035105528745403288232691147584728191162732299865338377159692350059136679"
],
[
"1",
"0"
]
],
"vk_gamma_2": [
[
"10857046999023057135944570762232829481370756359578518086990519993285655852781",
"11559732032986387107991004021392285783925812861821192530917403151452391805634"
],
[
"8495653923123431417604973247489272438418190587263600148770280649306958101930",
"4082367875863433681332203403145435568316851327593401208105741076214120093531"
],
[
"1",
"0"
]
],
"vk_delta_2": [
[
"15028154694713144242204861571552635520290993855826554325002991692907421516918",
"10202326166286888893675634318107715186834588694714750762952081034135561546271"
],
[
"12766289885372833812620582632847872978085960777075662988932200910695848591357",
"18486039841380105976272577521609866666900576498507352937328726490052296469859"
],
[
"1",
"0"
]
],
"IC": [
[
"1452272927738590248356371174422184656932731110936062990115610832462181634644",
"3608050114233210789542189629343107890943266759827387991788718454179833288695",
"1"
],
[
"14798240452388909327945424685903532333765637883272751382037716636327236955001",
"10773894897711848209682368488916121016695006898681985691467605219098835500201",
"1"
],
[
"17204267933132009093604099819536245144503489322639121825381131096467570698650",
"7704298975420304156332734115679983371345754866278811368869074990486717531131",
"1"
],
[
"8060465662017324080560848316478407038163145149983639907596180500095598669247",
"20475082166427284188002500222093571716651248980245637602667562336751029856573",
"1"
],
[
"7457566682692308112726332096733260585025339741083447785327706250123165087868",
"11904519443874922292602150685069370036383697877657723976244907400392778002614",
"1"
]
]
}
注:vk_alpha_1、vk_beta_2、vk_gamma_2的参数都一样,从vk_delta_2开始参数有改变。
2.2 Proof
同理根据上述的交易解析proof信息,包装后如下:
{
"pi_a": ["13854976072665683512875694823770713602187820700695689350251461484190678622777", "18799557382530648175973455419041717287155809457433735733081423863845533167035", "1"],
"pi_b": [
["21631033507770131063075234997873571580206312087443135082188407010890735573826","17284477071273727205307884885925514362528638567837502733476872336658245826667" ],
["21416090582919078253993061506868758708760849320693132617130552343228640816224","4331438738399797206841210679865661753887605911103646249109166935177875981680"],
["1", "0"]
],
"pi_c": ["6963197242267745453228534041057111262015907874139826882645803706173800617723", "21228315632900969810255945810651892392785324416813648206706599893327301572674", "1"],
"protocol": "groth16",
"curve": "bn128"
}
2.3 PublicSignals
同理根据上述的交易解析inputs信息,包装后如下:
["3061226360032517472274638926888854265068926881234476762304931412247737246919","6728982073551526785722952266936853582119478438086215932478760190917718952680","37938388892362834151584770384290207919364301626797345218722464515205243407","327931312179528553812809153503804462984186837247941235923454264438475220876"]
注:publicSignals的顺序与上述交易的入参顺序不一样,需要与合约方法“verifyProof”里的vk.IC的构造逻辑保持一致。
3. 验证proof data
向zkVerify发起验证proof data的交易。示例的代码如下:
import { zkVerifySession, Library, CurveType, ZkVerifyEvents } from "zkverifyjs";
import dotenv from 'dotenv';
dotenv.config();
import fs from "fs";
const proof = JSON.parse(fs.readFileSync("./data/proof.json"));
const publicInputs = JSON.parse(fs.readFileSync("./data/public.json"));
const key = JSON.parse(fs.readFileSync("./data/main.groth16.vkey.json"));
async function main() {
// Required code
const session = await zkVerifySession.start().Volta().withAccount(process.env.SEED_PHRASE);
let statement, aggregationId;
session.subscribe([
{
event: ZkVerifyEvents.NewAggregationReceipt,
callback: async (eventData) => {
console.log("New aggregation receipt:", eventData);
if (aggregationId == parseInt(eventData.data.aggregationId.replace(/,/g, ''))) {
let statementpath = await session.getAggregateStatementPath(
eventData.blockHash,
parseInt(eventData.data.domainId),
parseInt(eventData.data.aggregationId.replace(/,/g, '')),
statement
);
console.log("Statement path:", statementpath);
const statementproof = {
...statementpath,
domainId: parseInt(eventData.data.domainId),
aggregationId: parseInt(eventData.data.aggregationId.replace(/,/g, '')),
};
fs.writeFileSync("aggregation.json", JSON.stringify(statementproof));
}
},
options: { domainId: 0 },
},
]);
const { events } = await session.verify()
.groth16({ library: Library.snarkjs, curve: CurveType.bn128 })
.execute({
proofData: {
vk: key,
proof: proof,
publicSignals: publicInputs
}, domainId: 0
});
events.on(ZkVerifyEvents.IncludedInBlock, (eventData) => {
console.log("Included in block", eventData);
aggregationId = eventData.aggregationId;
statement = eventData.statement;
})
}
main();
交易成功后的日志如下:
D:/Work/Research/zkVerify/proof-submission-worldID> node ./index.js
2025-06-17 10:27:31 API/INIT: RPC methods not decorated: chainHead_v1_body, chainHead_v1_call, chainHead_v1_continue, chainHead_v1_follow, chainHead_v1_header, chainHead_v1_stopOperation, chainHead_v1_storage, chainHead_v1_unfollow, chainHead_v1_unpin, chainSpec_v1_chainName, chainSpec_v1_genesisHash, chainSpec_v1_properties, ismp_queryChallengePeriod, ismp_queryChildTrieProof, ismp_queryConsensusState, ismp_queryEvents, ismp_queryEventsWithMetadata, ismp_queryRequests, ismp_queryResponses, ismp_queryStateMachineLatestHeight, ismp_queryStateMachineUpdateTime, ismp_queryStateProof, transactionWatch_v1_submitAndWatch, transactionWatch_v1_unwatch, transaction_v1_broadcast, transaction_v1_stop
Included in block {
blockHash: '0x5619b52eb9b9bac6199520f42dcd333087580bd7da84db19979957a7766c37bf',
status: 'inBlock',
txHash: '0x2a2157ddbe5a5742b3fc2864c804324ad29a0f0871e1d075b3690812c2292bda',
proofType: 'groth16',
domainId: 0,
aggregationId: 27507,
statement: '0x97d53e32a3f539654455a9dac10a2a1823d004a057cb60f5455db6781f90eebf',
extrinsicIndex: 3,
feeInfo: {
payer: 'xpfFJrquqVjbFTDpQVxfkZcsAxs56Jpkuo3WEotHV36sm3nS3',
actualFee: '24468241160000000',
tip: '0',
paysFee: 'Yes'
},
weightInfo: { refTime: '4893646934', proofSize: '177995' },
txClass: 'Normal'
}
New aggregation receipt: {
event: 'newAggregationReceipt',
blockHash: '0x85a383ab7f9df13bc8e06612dea035095440864aad828c790f4dc389b65aa449',
data: {
domainId: '0',
aggregationId: '27,506',
receipt: '0x73d3bf8085e6d851c7f00c618a824afca45f33941f15422a7d2402654d9df03d'
},
phase: { applyExtrinsic: 2 }
}
New aggregation receipt: {
event: 'newAggregationReceipt',
blockHash: '0x77a5a0a0640bd04bdd719781cd4efe92f035b91b1ccec4de6fc40e89fd0c75a1',
data: {
domainId: '0',
aggregationId: '27,507',
receipt: '0xfd7c070309aa730f83ef20b7580a5ae1e90341cad2390badb424cff923fdfb30'
},
phase: { applyExtrinsic: 2 }
}
Statement path: {
root: '0xfd7c070309aa730f83ef20b7580a5ae1e90341cad2390badb424cff923fdfb30',
proof: [
'0x7b1eaacc3f921a3a3d00188b353a2b6021ea32bfac4599323f2f0aff642a8c3b',
'0xf7ed833f00e43a1e7b6c5809810cc19fca218d0f7eaf0522b224c3f2cb967f54'
],
numberOfLeaves: 4,
leafIndex: 1,
leaf: '0x97d53e32a3f539654455a9dac10a2a1823d004a057cb60f5455db6781f90eebf'
}
New aggregation receipt: {
event: 'newAggregationReceipt',
blockHash: '0x05eb5d39a3c2fd16fb18b68e9485e59c3abc167eb29879e3ad7dc21cd848315a',
data: {
domainId: '0',
aggregationId: '27,508',
receipt: '0x9c1d397094b6aa6a59e8d85f86c2206fa971707cba2f539529327672944329c5'
},
phase: { applyExtrinsic: 2 }
}
交易hash:https://zkverify-testnet.subscan.io/extrinsic/1141735-3
4. 注意点
- 包装时需要交换参数顺序
带有["1", "0"]标识的参数,都需要根据zkverify的规则,将两个参数的位置进行互换。 - 交易失败是的异常处理
- Error: settlementGroth16Pallet.InvalidVerificationKey: Provided an invalid verification key.
答:注意参数vk_delta_2的顺序 - Error: settlementGroth16Pallet.InvalidProofData: Provided data has not valid proof.
答:注意参数pi_b的顺序 - Error: settlementGroth16Pallet.InvalidInput: Provided data has not valid public inputs.
答:注意“verifyProof”里的vk.IC的构造顺序
共有 0 条评论