Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 5 additions & 3 deletions docs/content/en/docs/cli/index.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -46,16 +46,18 @@ maci registry check dora1abc...xyz
Given an aMACI round contract address, the CLI audits:

- All submitted proofs were **accepted by the smart contract** (`verifyResult = true`)
- On-chain **sign-up count** matches the indexed sign-up count
- On-chain `MSG_CHAIN_LENGTH` matches the count of **indexed messages**
- **Batch coverage**: total processed messageschain length
- **Message batch coverage**: `msgProofCount × batchSizeMSG_CHAIN_LENGTH`
- Last message proof's **state commitment** matches on-chain `QueryCurrentStateCommitment`
- Last tally proof's **tally commitment** matches on-chain `current_tally_commitment`

With `--recheck`, it additionally:

- Rebuilds the `MSG_HASHES` chain locally from indexed messages
- Reconstructs public signals (`input_hash`) from on-chain vkeys
- Runs `snarkjs.groth16.verify()` for **every** processMessage and tally proof
- Reconstructs public signals (`input_hash = SHA256(inputs) mod p`) from on-chain config (coordinatorHash, stateRoot, pollId, etc.)
- Fetches on-chain vkeys and runs `snarkjs.groth16.verify()` for **every** processMessage and tally proof
- **Tally batch coverage**: `tallyProofCount × 5^intStateTreeDepth ≥ numSignUps`

### Circuit Registry Verification (`maci registry check`)

Expand Down
8 changes: 5 additions & 3 deletions docs/content/zh/docs/cli/index.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -46,16 +46,18 @@ maci registry check dora1abc...xyz
给定一个 aMACI 轮次合约地址,CLI 将审计以下内容:

- 所有已提交的证明均被智能合约**接受**(`verifyResult = true`)
- 链上**报名数**与已索引报名数一致
- 链上 `MSG_CHAIN_LENGTH` 与**已索引消息数**一致
- **批次覆盖率**:已处理消息总数 ≥ 链长度
- **消息批次覆盖率**:`msgProofCount × batchSize ≥ MSG_CHAIN_LENGTH`
- 最后一条消息证明的**状态承诺**与链上 `QueryCurrentStateCommitment` 一致
- 最后一条 tally 证明的**计票承诺**与链上 `current_tally_commitment` 一致

启用 `--recheck` 时,还将额外执行:

- 从已索引消息本地重建 `MSG_HASHES` 链
- 从链上 vkeys 重新构造公开信号(`input_hash`)
- 对**每一条** processMessage 和 tally 证明运行 `snarkjs.groth16.verify()`
- 从链上配置(coordinatorHash、stateRoot、pollId 等)重新构造公开信号(`input_hash = SHA256(inputs) mod p`)
- 从链上读取 vkeys,对**每一条** processMessage 和 tally 证明运行 `snarkjs.groth16.verify()`
- **tally 批次覆盖率**:`tallyProofCount × 5^intStateTreeDepth ≥ numSignUps`

### 电路注册表验证(`maci registry check`)

Expand Down
2 changes: 1 addition & 1 deletion packages/cli/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@dorafactory/maci-cli",
"version": "0.1.0",
"version": "0.1.1",
"description": "Public CLI tool for MACI circuit registry and proof verification",
"type": "module",
"bin": {
Expand Down
2 changes: 1 addition & 1 deletion packages/cli/src/commands/verify.ts
Original file line number Diff line number Diff line change
Expand Up @@ -391,7 +391,7 @@ export const roundCommand: CommandModule = {
.option('recheck', {
type: 'boolean',
description:
'Layer 2: re-verify ZK proofs locally using snarkjs (experimental)',
'Layer 2: re-verify ZK proofs locally using snarkjs',
default: false,
}),
handler: (args) =>
Expand Down
46 changes: 42 additions & 4 deletions packages/cli/src/core/indexer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -99,16 +99,21 @@ export async function getProofs(
endpoint: string,
contractAddress: string
): Promise<ProofEntry[]> {
const data = await graphql<{
proofData: { nodes: ProofEntry[] };
const PAGE_SIZE = 500;
const proofs: ProofEntry[] = [];

const first = await graphql<{
proofData: { totalCount: number; nodes: ProofEntry[] };
}>(
endpoint,
`query {
proofData(
first: 10000
first: ${PAGE_SIZE}
offset: 0
filter: { contractAddress: { equalTo: "${contractAddress}" } }
orderBy: [TIMESTAMP_ASC]
) {
totalCount
nodes {
id
txHash
Expand All @@ -121,7 +126,40 @@ export async function getProofs(
}
}`
);
return data.proofData.nodes;

const total = first.proofData.totalCount;
proofs.push(...first.proofData.nodes);

let offset = PAGE_SIZE;
while (proofs.length < total) {
const page = await graphql<{
proofData: { nodes: ProofEntry[] };
}>(
endpoint,
`query {
proofData(
first: ${PAGE_SIZE}
offset: ${offset}
filter: { contractAddress: { equalTo: "${contractAddress}" } }
orderBy: [TIMESTAMP_ASC]
) {
nodes {
id
txHash
timestamp
actionType
commitment
proof
verifyResult
}
}
}`
);
proofs.push(...page.proofData.nodes);
offset += PAGE_SIZE;
}

return proofs;
}

export async function getMessageCount(
Expand Down
14 changes: 11 additions & 3 deletions packages/cli/src/core/recheck.ts
Original file line number Diff line number Diff line change
Expand Up @@ -269,9 +269,6 @@ export async function runLayer2(

// Next tally's prevTallyCommitment = this batch's newTallyCommitment
currentTallyCommitment = newTallyCommitment;

// tally batch size sanity check (informational)
void tallyBS;
} catch (err) {
results.push({
proofType: 'tally',
Expand All @@ -283,5 +280,16 @@ export async function runLayer2(
}
}

// Tally batch coverage: tallyBS × tallyProofCount must cover all sign-ups
const tallyBatchesCovered = tallyBS * BigInt(tallyProofs.length);
const tallyCoverageOk = tallyBatchesCovered >= chainCfg.numSignUps;
results.push({
proofType: 'tally',
proofIndex: -1,
batchLabel: `tally coverage (${tallyProofs.length}×${tallyBS})`,
passed: tallyCoverageOk,
detail: `${tallyBatchesCovered} ${tallyCoverageOk ? '≥' : '<'} ${chainCfg.numSignUps} sign-ups`,
});

return results;
}
Loading