From ab7718eec0b21886b8116e63ead624db9d732218 Mon Sep 17 00:00:00 2001 From: Michael Taylor Date: Sun, 17 May 2026 17:23:48 -0700 Subject: [PATCH 1/3] CHIP: Parallel voting at scale: off-chain proofs, on-chain finality Adds draft CHIP and companion assets for large-scale on-chain elections using an Election Singleton with Registration, Ballot, and Voting Coins, Groth16 verification, and off-chain aggregation. --- CHIPs/chip-scaled-parallel-voting.md | 198 ++++++++++++++++++ assets/chip-scaled-parallel-voting/README.md | 20 ++ .../chip-ceremony.md | 65 ++++++ .../chip-election-coins.md | 101 +++++++++ .../chip-groth16-clvm.md | 107 ++++++++++ .../chip-protocol-flow.md | 101 +++++++++ .../chip-witnesses-encoding.md | 95 +++++++++ .../chip-scaled-parallel-voting/figure_1.png | Bin 0 -> 51038 bytes .../chip-scaled-parallel-voting/figure_2.png | Bin 0 -> 37654 bytes 9 files changed, 687 insertions(+) create mode 100644 CHIPs/chip-scaled-parallel-voting.md create mode 100644 assets/chip-scaled-parallel-voting/README.md create mode 100644 assets/chip-scaled-parallel-voting/chip-ceremony.md create mode 100644 assets/chip-scaled-parallel-voting/chip-election-coins.md create mode 100644 assets/chip-scaled-parallel-voting/chip-groth16-clvm.md create mode 100644 assets/chip-scaled-parallel-voting/chip-protocol-flow.md create mode 100644 assets/chip-scaled-parallel-voting/chip-witnesses-encoding.md create mode 100644 assets/chip-scaled-parallel-voting/figure_1.png create mode 100644 assets/chip-scaled-parallel-voting/figure_2.png diff --git a/CHIPs/chip-scaled-parallel-voting.md b/CHIPs/chip-scaled-parallel-voting.md new file mode 100644 index 00000000..3b7e55bc --- /dev/null +++ b/CHIPs/chip-scaled-parallel-voting.md @@ -0,0 +1,198 @@ + +| CHIP Number | | +| ------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| Title | Parallel voting at scale: off-chain proofs, on-chain finality | +| Description | Standard for large-scale on-chain elections on Chia: an Election Singleton orchestrates registration and ballot issuance; Registration, Ballot, and Voting Coins separate enrollment from parallel votes and from per-ballot finalize (Groth16 + `bls_verify` on the Ballot Coin) with off-chain aggregation and proving. | +| Author | Michael Taylor (on behalf of [DIG Network](https://github.com/DIG-Network)) | +| Editor | | +| Comments-URI | | +| Status | | +| Category | Standards Track | +| Sub-Category | Primitive | +| Created | 2026-05-04 | +| Requires | [CHIP-0011](https://github.com/Chia-Network/chips/blob/main/CHIPs/chip-0011.md) (CLVM BLS / curve operations for Groth16 verification); [CHIP-0050](https://github.com/Yakuhito/chips/blob/b23ed49e00164cbc62b9b6ae4d48071930c5b1d2/CHIPs/chip-0050.md) (action layer; see [PR #165](https://github.com/Chia-Network/chips/pull/165)) | +| Replaces | None | +| Superseded-By | | + + +**Reference implementation (open source):** This CHIP is implemented in **[DIG-Network/chia-parallel-voting](https://github.com/DIG-Network/chia-parallel-voting)** on branch **`main`** ([puzzles/](https://github.com/DIG-Network/chia-parallel-voting/tree/main/puzzles), [sdk/](https://github.com/DIG-Network/chia-parallel-voting/tree/main/sdk), [cli/](https://github.com/DIG-Network/chia-parallel-voting/tree/main/cli), [wasm/](https://github.com/DIG-Network/chia-parallel-voting/tree/main/wasm), [app/](https://github.com/DIG-Network/chia-parallel-voting/tree/main/app)). When this CHIP ships in the Chia chips repo, the Markdown **companion files** in the same directory are [README.md](./README.md), [chip-protocol-flow.md](./chip-protocol-flow.md), and the other `chip-*.md` files linked there; executable artifacts remain in the reference repository. + +## Abstract + +This CHIP defines a standard for decentralized, permissionless voting at scale on the Chia blockchain, with a practical target on the order of twenty thousand voters. There is no known theoretical upper bound; what you hit first in practice is off-chain computation and proving, not a hard chain limit. + +BLS is the workhorse for aggregating voter *signatures*, but BLS alone is not enough to aggregate *votes* in a trustless setting: it does not, by itself, bind the voter threshold, how many voters backed a given result, or how many voters were registered for the election. This CHIP requires all three kinds of commitment (BLS aggregate, quorum threshold, and the registered-voter bound) to line up at finalize. + +The novel piece here is the realization that Groth16 circuits can produce cryptographic commitments today’s CLVM can verify. For a **fixed circuit**, the proof the coin checks is **constant size in CLVM** (it does not grow with how many voters contributed off-chain), and it still binds threshold, registration scope, and the BLS aggregate. Whoever submits the aggregation for finalization cannot fake a passing proof. If the finalize spend proves the required threshold voted and the correct BLS aggregate is in the bundle, the vote finalizes on-chain. + +## Motivation + +On Chia, a naive voting design often hits a **singleton parallelization** problem: to make the vote outcome actionable inside CLVM, many designs force every voter update through the **Ballot Box Singleton** (one tally coin everyone has to spend). In a decentralized setup that behaves like **at most one tally step per block**, so counting twenty thousand votes can mean **twenty thousand blocks** of wall-clock time, and the problem gets worse as the quorum grows. + +The usual shortcut is **semi-permissioned**: one operator key aggregates off-chain and posts the result to the **Ballot Box Singleton**. That trades the bottleneck for **trust and uptime**: participants depend on that party to show up and behave; anything that might move serious value on the outcome inherits a **single point of failure**. + +This CHIP defines a **permissionless** pattern that keeps registration and ballot issuance on the **Election Singleton**’s **slow lane**, pushes per-voter work onto **parallel coins**, and runs **per-ballot finalize** (Groth16 + BLS verification on the **Ballot Coin**) without wedging the whole election behind a **Ballot Box Singleton** again. The goal is to make **large-scale on-chain elections** on Chia realistic enough that richer **governance** can be built on the base layer. + +The same shape is meant to support **DIG Network**: an L2-style stack on Chia where validators **attest** to L2 blocks and **anchor** them on L1 without a designated aggregator key. + +It also points toward **production DAO governance** (for example CAT-weighted votes) and, longer term, **Chia Vault** spend paths that can take an **announcement** from a finalized ballot and treat it as authorization for a vault action. + +## Backwards Compatibility + +This CHIP does not propose any changes to CLVM. + +## Specification + +This section defines the on-chain artifacts, state, and spend rules needed for interoperable implementations. Election and Ballot singletons **MUST** route inner actions through the [CHIP-0050](https://github.com/Yakuhito/chips/blob/b23ed49e00164cbc62b9b6ae4d48071930c5b1d2/CHIPs/chip-0050.md) action layer where applicable. Groth16 verification and `bls_verify` **MUST** use the capabilities and encodings described in [CHIP-0011](https://github.com/Chia-Network/chips/blob/main/CHIPs/chip-0011.md). **End-to-end phase ordering** (ceremony through exit): [chip-protocol-flow.md](./chip-protocol-flow.md). **Puzzle tables and encodings** live in the companion documents linked under **Companion documents** below. + +### Protocol partitioning + +Throughput is preserved by separating three classes of spends: + +1. **Election singleton**: Handles `register`, `createBallot`, and `deregister` only (Rue: [register.rue](https://github.com/DIG-Network/chia-parallel-voting/blob/main/puzzles/election/register.rue), [create_ballot.rue](https://github.com/DIG-Network/chia-parallel-voting/blob/main/puzzles/election/create_ballot.rue), [deregister.rue](https://github.com/DIG-Network/chia-parallel-voting/blob/main/puzzles/election/deregister.rue); action layer [action.rue](https://github.com/DIG-Network/chia-parallel-voting/blob/main/puzzles/action.rue)). Enrollment is intentionally singleton-bound; it occurs once per voter and is not on the hot path for each vote. +2. **Parallel voting**: `mint_voting_coin` ([mint_voting_coin.rue](https://github.com/DIG-Network/chia-parallel-voting/blob/main/puzzles/registration_coin/mint_voting_coin.rue)) and `update_vote` ([update_vote.rue](https://github.com/DIG-Network/chia-parallel-voting/blob/main/puzzles/voting_coin/update_vote.rue)) **MUST NOT** require spending the Election Singleton, so many voters can update distinct coins in the same block, within mempool and consensus limits. +3. **Ballot Coin**: Each ballot carries `finalize` ([finalize.rue](https://github.com/DIG-Network/chia-parallel-voting/blob/main/puzzles/ballot_coin/finalize.rue)), `oracle` ([oracle.rue](https://github.com/DIG-Network/chia-parallel-voting/blob/main/puzzles/ballot_coin/oracle.rue)), and `announce_finalization` ([announce_finalization.rue](https://github.com/DIG-Network/chia-parallel-voting/blob/main/puzzles/ballot_coin/announce_finalization.rue)). Ballot finalization **MUST NOT** spend the Election Singleton, so delayed or disputed finalization on one ballot does not block registration, ballot creation, or deregistration on the election. + +### Coin roles + +**Election-facing:** + +- **Election Singleton**: Orchestrates voter registration, mints Ballot Coin lineages via `createBallot` only, and authorizes `deregister` for collateral release. It does not perform vote finalization; that responsibility is entirely on the Ballot Coin. +- **Registration Coin**: Escrows the voter’s CAT, represents membership in the election registration Merkle tree, and maintains a per-registration sparse tree of ballot launcher ids to enforce one Voting Coin lineage per ballot. +- **Ballot Coin**: Per ballot: `vote_close_height`, `vote_options_root`, inherited VK/IC and threshold parameters, and state `(finalized, vote_outcome, agg_signers)`. +- **Voting Coin**: Carries `vote_data` and BLS material for aggregation for one (voter, ballot) pair; it is created and updated without spending the Election Singleton. + +**Ceremony-facing (separate lineage from elections):** + +- **Ceremony Singleton**: Accepts `contribute` during a configured height window, then `finalize` after the window closes. On-chain state includes `vk_hash`, `marker_root` (Merkle root over sorted contribution marker coin ids), and `finalized`. Reference: [puzzles/ceremony_singleton/](https://github.com/DIG-Network/chia-parallel-voting/tree/main/puzzles/ceremony_singleton). +- **Ceremony Marker Coin**: Created per accepted `contribute`; puzzle [marker.rue](https://github.com/DIG-Network/chia-parallel-voting/blob/main/puzzles/ceremony_coin/marker.rue). Curries launcher id, participant public key, contribution hash, and previous contribution hash. The puzzle may produce no conditions when spent, leaving an on-chain commitment until removed. +- **Ceremony Voucher Coin**: Created only in ceremony `finalize`; [ceremony_voucher.rue](https://github.com/DIG-Network/chia-parallel-voting/blob/main/puzzles/ceremony_singleton/ceremony_voucher.rue). Anyone-can-spend with self-recreation so multiple election deploys can anchor to the same ceremony. Election deploy **SHOULD** co-spend the voucher and assert its announcement to bind `vk_hash`, `max_voters`, and `ceremony_launcher_id`. +- **Finalize summary output**: Additional coin(s) or outputs with memos (including VK bytes) for indexers using launcher hints. + +**Election lineage (normative):** + +- Registration Coin **MUST** descend from `register` on the Election Singleton. +- Ballot Coin **MUST** descend from `createBallot` only. The reference implementation uses a 2-mojo launcher eve to satisfy singleton outer morph constraints; compatible implementations **SHOULD** match that pattern unless an equivalent approach is fully validated. +- Voting Coin **MUST** descend from `mint_voting_coin` on a Registration Coin that proves election membership. + +The ceremony graph is independent. Elections reference it through `ceremony_launcher_id`, `vk_hash`, and (recommended) voucher co-spend at deploy. + +### Companion documents (normative detail) + +Tables of inner actions, Merkle slot and leaf rules, announcement preimages, Groth16 public-input ordering, and pinned constants are maintained as **companion** Markdown files alongside this CHIP so the Specification stays readable as a protocol overview: + + +| Document | Contents | +| -------- | -------- | +| [chip-protocol-flow.md](./chip-protocol-flow.md) | Phases 0–5; *Implementation:* links into [puzzles/](https://github.com/DIG-Network/chia-parallel-voting/tree/main/puzzles), [sdk/](https://github.com/DIG-Network/chia-parallel-voting/tree/main/sdk), [cli/](https://github.com/DIG-Network/chia-parallel-voting/tree/main/cli) in the reference repo | +| [chip-ceremony.md](./chip-ceremony.md) | Ceremony marker, voucher, inner-action table (**Source** column), Rue / SDK cites | +| [chip-election-coins.md](./chip-election-coins.md) | Per-role Rue and actor links after each subsection | +| [chip-witnesses-encoding.md](./chip-witnesses-encoding.md) | Merkle rules, `vote_message`, public inputs; [merkle_utils.rue](https://github.com/DIG-Network/chia-parallel-voting/blob/main/puzzles/merkle_utils.rue), [circuit.rs](https://github.com/DIG-Network/chia-parallel-voting/blob/main/sdk/src/prover/circuit.rs), [finalize.rue](https://github.com/DIG-Network/chia-parallel-voting/blob/main/puzzles/ballot_coin/finalize.rue) | +| [chip-groth16-clvm.md](./chip-groth16-clvm.md) | CLVM Groth16 walkthrough tied to [finalize.rue](https://github.com/DIG-Network/chia-parallel-voting/blob/main/puzzles/ballot_coin/finalize.rue) and [circuit.rs](https://github.com/DIG-Network/chia-parallel-voting/blob/main/sdk/src/prover/circuit.rs); figures in reference [assets/](https://github.com/DIG-Network/chia-parallel-voting/tree/main/assets) | + +An implementation **MUST** conform to this Specification and to any **MUST** / **MUST NOT** requirement in those companions where the companion text is marked normative. **Companion index:** [README.md](./README.md). + +### Election and ballots (summary) + +The **Election Singleton** stores eight fields (`registration_merkle_root`, `registration_count`, `registration_vote_weight`, `election_start_height`, `ceremony_launcher_id`, `max_voters`, `vk_hash`, `vote_mode_lock`). Deploy-time curries carry VK, IC, threshold pack, `MAX_SIGNERS`, launcher ids, and CHIP-0050 action roots and **MUST** stay consistent on every Ballot Coin minted by `createBallot`. Inner actions are **`register`**, **`createBallot`**, and **`deregister`** only; **`createBallot`** is the **only** valid ancestry for a Ballot Coin and snapshots registration root and total weight for finalize-time proofs. **`finalize`**, **`oracle`**, and **`announce_finalization`** belong on the Ballot Coin, not the Election singleton. + +This CHIP does **not** specify an on-chain XCH registration fee on `register` or an `accumulated_fees` field on the singleton. Ballot end time is **`VOTE_CLOSE_HEIGHT`** on each Ballot Coin, not a single global election timer. Full state and action tables: [chip-election-coins.md](./chip-election-coins.md). + +### Ceremony (summary) + +The **Ceremony Singleton** accepts **`contribute`** during a configured height window, then **`finalize`** after the window when enough participants have contributed. It seals **`vk_hash`** and **`marker_root`**, mints a **Ceremony Voucher** (and summary outputs with VK material for indexers), and forms a lineage **independent** of elections. Elections bind to the ceremony via **`ceremony_launcher_id`** and **`vk_hash`**; election deploy **SHOULD** co-spend the voucher and assert **`CANONICAL_MSG`**. Full tables and preimage: [chip-ceremony.md](./chip-ceremony.md). + +### Witnesses, proofs, and encodings (summary) + +Off-chain actors enumerate registrations and Voting Coins, verify lineage, aggregate BLS over the canonical **`vote_message`**, and build a Groth16 witness. On-chain **`finalize`** on the Ballot Coin verifies Groth16 and BLS aggregate verification via [CHIP-0011](https://github.com/Chia-Network/chips/blob/main/CHIPs/chip-0011.md) pairing opcodes; any actor may submit a valid bundle. **`mint_voting_coin`** and **`update_vote`** assert the Ballot **`oracle`** so close height and vote mode are pinned where Groth16 public inputs do not carry them. For **how Groth16 meets CLVM**, **on-chain verification cost vs off-chain proving cost**, and an **informative note on BLS12-377 vs 381** (hypothetical future CLVM; not required today), see [chip-groth16-clvm.md](./chip-groth16-clvm.md). Sparse tree definitions, vote modes, the eight ordered public inputs, VK byte length, and announcement strings: [chip-witnesses-encoding.md](./chip-witnesses-encoding.md). + +The keywords **MUST**, **MUST NOT**, **SHOULD**, and **MAY** in this Specification and in the linked companion documents are to be interpreted as described in [RFC 2119](https://www.rfc-editor.org/rfc/rfc2119.html). + +## Test plan + +Interoperability is exercised by the open-source reference implementation ([DIG-Network/chia-parallel-voting](https://github.com/DIG-Network/chia-parallel-voting), branch `main`). Reviewers **SHOULD** treat failures there as specification or implementation drift until puzzles, circuit, and tests agree. + +**Automated tests** (Rust, under [`sdk/tests/`](https://github.com/DIG-Network/chia-parallel-voting/tree/main/sdk/tests)): + +| Area | Examples | +| ---- | -------- | +| Ceremony | `ceremony_contribute_e2e`, `ceremony_deploy_e2e`, `ceremony_5_contributions_e2e` | +| Deploy, registration, ballots | `register_action_e2e`, `voter_register_full_flow`, `create_ballot_e2e`, `create_ballot_action_isolated`, `launch_ballot_e2e` | +| Voting | `voter_cast_vote_e2e`, `voter_cast_vote_two_voters_e2e`, `voter_revote_e2e`, `voter_double_vote_e2e`, `voter_revote_oracle_required_e2e` | +| Finalize | `finalize_per_ballot_e2e`, `finalize_one_third_threshold_e2e` | +| Collateral / deregister | `voter_release_collateral_e2e`, `voter_release_after_cast_e2e`, `aggregator_sync_after_deregister_e2e` | +| Merkle / constants / parity | `m5r_merkle_gate_e2e`, `chip_spec_compliance`, `deployer_aggregator_eve_hash_parity_e2e`, `puzzle_constants` | +| Broader harness | `integration`, `live_orchestration_e2e`, `actor_functions_e2e`, `ballot_reader_e2e`, `find_current_singleton_propagation_lag_e2e` | + +**Bytecode fixtures:** After `build.sh` / `build.ps1`, compiled CLVM lives under [`puzzles/compiled/`](https://github.com/DIG-Network/chia-parallel-voting/tree/main/puzzles/compiled) and is loaded via [`sdk/src/puzzles.rs`](https://github.com/DIG-Network/chia-parallel-voting/blob/main/sdk/src/puzzles.rs). Groth16 proofs in tests are generated by the reference prover ([`sdk/src/prover/`](https://github.com/DIG-Network/chia-parallel-voting/tree/main/sdk/src/prover)), not from pinned hex blobs in this document set. + +**Live-chain integration:** [`cli/src/bin/live_integration_test.rs`](https://github.com/DIG-Network/chia-parallel-voting/blob/main/cli/src/bin/live_integration_test.rs) builds the `chip-voting-live-test` binary (full election lifecycle with on-chain confirmations). [`wasm/integration-tests/`](https://github.com/DIG-Network/chia-parallel-voting/tree/main/wasm/integration-tests) holds Node scripts that exercise the WASM bundle against a live node (notably [`live_integration.mjs`](https://github.com/DIG-Network/chia-parallel-voting/blob/main/wasm/integration-tests/live_integration.mjs)). + +## Reference Implementation + +Normative bytecode and the Groth16 circuit live in **[chia-parallel-voting](https://github.com/DIG-Network/chia-parallel-voting)** (`main`): + + +| Layer | Location | +| ------------------------------------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| Rue → CLVM puzzles | [puzzles/](https://github.com/DIG-Network/chia-parallel-voting/tree/main/puzzles); build [puzzles/compiled/](https://github.com/DIG-Network/chia-parallel-voting/tree/main/puzzles/compiled) via [build.sh](https://github.com/DIG-Network/chia-parallel-voting/blob/main/build.sh) / [build.ps1](https://github.com/DIG-Network/chia-parallel-voting/blob/main/build.ps1) | +| Puzzle hashes / hex loader | [sdk/src/puzzles.rs](https://github.com/DIG-Network/chia-parallel-voting/blob/main/sdk/src/puzzles.rs) | +| Actors (deployer, voter, aggregator, ballot, ceremony) | [sdk/src/actors/](https://github.com/DIG-Network/chia-parallel-voting/tree/main/sdk/src/actors) | +| Groth16 circuit + prover | [sdk/src/prover/circuit.rs](https://github.com/DIG-Network/chia-parallel-voting/blob/main/sdk/src/prover/circuit.rs), [sdk/src/prover/proof.rs](https://github.com/DIG-Network/chia-parallel-voting/blob/main/sdk/src/prover/proof.rs) | +| Merkle / witness helpers | [sdk/src/merkle.rs](https://github.com/DIG-Network/chia-parallel-voting/blob/main/sdk/src/merkle.rs) | +| CLI | [cli/](https://github.com/DIG-Network/chia-parallel-voting/tree/main/cli); binary `chip-voting`. **Live-chain:** `chip-voting-live-test` (see row below). | +| Live-chain integration (real network) | [cli/src/bin/live_integration_test.rs](https://github.com/DIG-Network/chia-parallel-voting/blob/main/cli/src/bin/live_integration_test.rs) (`cargo run --bin chip-voting-live-test`, full lifecycle with confirmations); [wasm/integration-tests/](https://github.com/DIG-Network/chia-parallel-voting/tree/main/wasm/integration-tests) (Node: [`live_integration.mjs`](https://github.com/DIG-Network/chia-parallel-voting/blob/main/wasm/integration-tests/live_integration.mjs) and related scripts against WASM + a live node) | +| WASM + browser UI | [wasm/](https://github.com/DIG-Network/chia-parallel-voting/tree/main/wasm), [app/](https://github.com/DIG-Network/chia-parallel-voting/tree/main/app) | +| Integration / E2E tests (simulator, in-repo) | [sdk/tests/](https://github.com/DIG-Network/chia-parallel-voting/tree/main/sdk/tests) | + + +Workspace: [Cargo.toml](https://github.com/DIG-Network/chia-parallel-voting/blob/main/Cargo.toml). Overview: [README.md](https://github.com/DIG-Network/chia-parallel-voting/blob/main/README.md). + +## Security + +### Security goals + +For a correctly deployed election, when the **configured quorum** (rational threshold over **registered weight**, as enforced in the reference circuit and Groth16 proof) is met by voters attesting to the same outcome, the protocol aims to ensure: + +- **Finalize soundness:** No one can produce an accepted **`finalize`** spend that claims an outcome and signer aggregate **unless** (i) the Groth16 verification equation passes for the curried VK and the public inputs reconstructed on-chain, and (ii) the aggregate BLS signature verifies for the canonical **`vote_message`** and the supplied **`agg_signers`** (see [chip-groth16-clvm.md](./chip-groth16-clvm.md)). +- **Binding to ballot and election context:** Public inputs and scalar bindings in [`finalize.rue`](https://github.com/DIG-Network/chia-parallel-voting/blob/main/puzzles/ballot_coin/finalize.rue) tie the proof to **`BALLOT_LAUNCHER_ID`**, snapshotted registration root and weight, threshold pack, and **`vote_message`** (which itself binds **`vote_outcome`**, ballot id, and election id). A valid proof for one ballot **cannot** be replayed as another without changing on-chain curried values and breaking verification. +- **Registration-gated voting:** **`mint_voting_coin`** and **`update_vote`** assert the Ballot **`oracle`** in its **open** form so **`VOTE_CLOSE_HEIGHT`** and **`vote_options_root`** are committed on-chain alongside spend-time checks; combined with registration and per-ballot trees (see [chip-witnesses-encoding.md](./chip-witnesses-encoding.md)), only voters enrolled in the election’s registration Merkle tree can obtain a valid voting lineage for a ballot. + +### Trust boundaries and assumptions + + +| Boundary | Assumption | +| -------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| **Chia base layer** | Validators execute CLVM correctly; block timestamps and inclusion rules behave as in Chia consensus. Standard mempool fees apply. | +| **CHIP-0011 / CHIP-0050** | Pairing-based opcodes and encodings are correct and stable as specified; action-layer routing on the Election and Ballot singletons is used as in this CHIP’s puzzles (see **Requires** in the preamble table). | +| **Groth16 SRS** | Soundness holds for the **published verification key** bound by **`vk_hash`** (and, when used, ceremony voucher binding per [chip-ceremony.md](./chip-ceremony.md)). If the ceremony is compromised or **`vk_hash`** does not match the intended circuit, **finalize soundness fails** independently of puzzle logic. | +| **Ceremony `finalize`** | The ceremony’s **`finalize`** spend is **not** authenticated by a designated on-chain key; the first valid spend wins. Operators **MUST** independently verify **`vk_hash`**, **`marker_root`**, and contribution transcripts against their security policy **before** trusting an election that references the ceremony. | +| **Off-chain aggregator** | **Anyone** may assemble and submit a **`finalize`** bundle. Safety does not rely on the aggregator being honest; an honest aggregator is a **liveness / UX** convenience. A malicious aggregator cannot forge a passing **`finalize`** without breaking Groth16 or BLS assumptions above. | +| **Deploy-time parameters** | **`VOTE_THRESHOLD_NUM` / `DEN`**, **`MAX_SIGNERS`**, **`vote_mode_lock`**, CAT policy, and ceremony caps are chosen by deployers; buggy or adversarial **configuration** (e.g. threshold ≥ 1, wrong VK) is **out of scope** for puzzle soundness. | + + +### Threats and mitigations (selected) + +- **Forged finalization**: Mitigated by on-chain Groth16 + aggregate **BLS** verification and scalar re-derivation in **`finalize`** (see [chip-groth16-clvm.md](./chip-groth16-clvm.md)). +- **Cross-ballot or cross-election replay of proofs**: Mitigated by **`ballot_launcher_id`**, snapshotted roots, and **`vote_message`** binding **election** and **ballot** launcher ids in public inputs and hashes. +- **Voting after close or wrong vote options**: Mitigated by asserting the Ballot **`oracle`** announcement that pins **`VOTE_CLOSE_HEIGHT`** and **`VOTE_OPTIONS_ROOT`** for **`mint_voting_coin`** / **`update_vote`**; **`finalize`** enforces **height ≥ `VOTE_CLOSE_HEIGHT`**. +- **Registration spam**: Not fully prevented by this CHIP: mitigations are **economic** (CAT collateral, fees) and **operational** (issuer policy). There is **no** normative on-chain XCH registration fee in this CHIP. +- **Censorship**: Block producers or mempools can delay any spend; **`finalize`** is permissionless, so **censorship of finalization** is a **liveness** risk, not a soundness gap. **Registration** and ballot creation are singleton-bound and more exposed to ordering / censorship. +- **Privacy**: Votes and outcomes are **visible on-chain** (coins, memos, announcements). This CHIP does **not** provide ballot secrecy or receipt-freeness. +- **Wallet / signing layer**: Incorrect client software, weak key storage, or wallets that do not expose required signing APIs (e.g. unsafe / CHIP-0002-style spends for full dApp flows) can strand users or leak keys; that layer is **not** specified here. + +### Dependency surface + +Implementations rely on [CHIP-0011](https://github.com/Chia-Network/chips/blob/main/CHIPs/chip-0011.md) for curve arithmetic underlying Groth16 and BLS verification in CLVM, and on [CHIP-0050](https://github.com/Yakuhito/chips/blob/b23ed49e00164cbc62b9b6ae4d48071930c5b1d2/CHIPs/chip-0050.md) for structured inner spends on singletons. Changes or bugs in those standards affect this protocol in the same way as for other CHIP-0050 coins. + +### Residual risks and review notes + +- **Circuit–puzzle drift:** The R1CS in [`sdk/src/prover/circuit.rs`](https://github.com/DIG-Network/chia-parallel-voting/blob/main/sdk/src/prover/circuit.rs) **MUST** stay aligned with [`finalize.rue`](https://github.com/DIG-Network/chia-parallel-voting/blob/main/puzzles/ballot_coin/finalize.rue) public-input ordering; shipping a mismatched pair breaks all finalizations for that VK. +- **Ceremony transparency:** Organizations **SHOULD** publish ceremony parameters, participant lists, and reproducible **`vk_hash`** checks where governance requires it. +- **Proving time, emulation, future 377:** Large electorates mostly stress **off-chain proof generation**; that is a **liveness / ops** concern, not finalize soundness. The expensive pattern is **emulating heavier BLS12-381 arithmetic inside the BLS12-381 scalar circuit** (**field emulation**; **k = 10** as shorthand for a deep emulation tower in this stack), so proving can be **slow** while **`finalize`** stays a short on-chain check. **Informative only:** **BLS12-377** pairings in CLVM alongside **381** could allow **Groth16 on 377** with **`bls_verify`** still on **381**; the **377/381 cycle** supports **L2-style anchoring** without **381-inside-381** emulation. Details: [chip-groth16-clvm.md](./chip-groth16-clvm.md). + +**Out of scope for this CHIP:** Incentive design for aggregators, bridge or L2 composition, formal verification of the circuit, and legal or regulatory classification of votes. + +## Copyright + +Copyright and related rights waived via [CC0](https://creativecommons.org/publicdomain/zero/1.0/). \ No newline at end of file diff --git a/assets/chip-scaled-parallel-voting/README.md b/assets/chip-scaled-parallel-voting/README.md new file mode 100644 index 00000000..5c6b7d15 --- /dev/null +++ b/assets/chip-scaled-parallel-voting/README.md @@ -0,0 +1,20 @@ +# Parallel voting CHIP: companion documents + +**Purpose:** These Markdown files accompany **[chip-scaled-parallel-voting.md](../../CHIPs/chip-scaled-parallel-voting.md)** in `CHIPs/`. They live here under **`assets/chip-scaled-parallel-voting/`** with the pedagogical PNG figures (`figure_1.png`, `figure_2.png`) so everything ships as one CHIP asset bundle. + +**Reference implementation (executable spec):** [DIG-Network/chia-scaled-parallel-voting](https://github.com/DIG-Network/chia-scaled-parallel-voting), branch `main` (Rue puzzles, compiled CLVM, SDK, CLI, WASM, tests). + +--- + +## Document map + +| Document | Contents | +| -------- | -------- | +| [chip-scaled-parallel-voting.md](../../CHIPs/chip-scaled-parallel-voting.md) | Main CHIP text: preamble, abstract, motivation, specification summary, reference implementation, security, copyright | +| [chip-protocol-flow.md](./chip-protocol-flow.md) | Phases 0–5 (ceremony through exit); *Implementation* pointers into the reference repo | +| [chip-ceremony.md](./chip-ceremony.md) | Ceremony singleton, marker coin, voucher, inner-action table | +| [chip-election-coins.md](./chip-election-coins.md) | Election, Ballot, Registration, and Voting coins; inner actions and lineage | +| [chip-witnesses-encoding.md](./chip-witnesses-encoding.md) | Merkle rules, vote modes, `vote_message`, eight public inputs, announcements | +| [chip-groth16-clvm.md](./chip-groth16-clvm.md) | Groth16 + CLVM finalize path, soundness intuition, **informative** BLS12-377 note, figures | + +**Tests and vectors:** see **Test plan** in [chip-scaled-parallel-voting.md](../../CHIPs/chip-scaled-parallel-voting.md) and [`sdk/tests/`](https://github.com/DIG-Network/chia-scaled-parallel-voting/tree/main/sdk/tests) in the reference implementation. diff --git a/assets/chip-scaled-parallel-voting/chip-ceremony.md b/assets/chip-scaled-parallel-voting/chip-ceremony.md new file mode 100644 index 00000000..f6f19b97 --- /dev/null +++ b/assets/chip-scaled-parallel-voting/chip-ceremony.md @@ -0,0 +1,65 @@ +# Ceremony layer (companion to CHIP draft) + +**What this doc is:** the **Ceremony Singleton** and its helper coins (marker, voucher): state, deploy fields, and what **`contribute`** / **`finalize`** actually require. High-level flow is [chip-protocol-flow.md](./chip-protocol-flow.md) Phase 0; election binding is summarized in [chip-scaled-parallel-voting.md](../../CHIPs/chip-scaled-parallel-voting.md) (Specification). + +**Code:** [DIG-Network/chia-scaled-parallel-voting](https://github.com/DIG-Network/chia-scaled-parallel-voting) on `main`. + +--- + +## State (`CeremonyState`) + +**Five on-chain fields** (see [`puzzles/ceremony_singleton/shared.rue`](https://github.com/DIG-Network/chia-scaled-parallel-voting/blob/main/puzzles/ceremony_singleton/shared.rue) and `CeremonyState` in [`sdk/src/state.rs`](https://github.com/DIG-Network/chia-scaled-parallel-voting/blob/main/sdk/src/state.rs)): + +| Field | Meaning | +|--------|---------| +| `contribution_count` | Number of accepted `contribute` spends. | +| `last_contribution_hash` | Hash of latest public contribution payload; equals `vk_seed` before first contribution. | +| `finalized` | Set by `finalize`; further `contribute` rejected. | +| `vk_hash` | `sha256(VK bytes)`; zero until finalize. | +| `marker_root` | Merkle root over **sorted** per-contribution marker coin ids; zero until finalize. | + +--- + +## Deploy curries (minimum) + +**You need at least:** `START_BLOCK_HEIGHT`, `CEREMONY_LENGTH_BLOCKS`, `MIN_PARTICIPANTS`, `MAX_VOTERS`, `vk_seed`, `CEREMONY_COIN_MOD_HASH`, `CEREMONY_VOUCHER_MOD_HASH`. Exact layouts live under [`puzzles/ceremony_singleton/`](https://github.com/DIG-Network/chia-scaled-parallel-voting/tree/main/puzzles/ceremony_singleton); the two inner spend paths are [`contribute.rue`](https://github.com/DIG-Network/chia-scaled-parallel-voting/blob/main/puzzles/ceremony_singleton/contribute.rue) and [`finalize.rue`](https://github.com/DIG-Network/chia-scaled-parallel-voting/blob/main/puzzles/ceremony_singleton/finalize.rue). + +--- + +## Inner actions + +| Action | Requirements | Source (`main`) | +|--------|----------------|-----------------| +| **`contribute`** | Rejected if `finalized` is set. Allowed only while `START_BLOCK_HEIGHT ≤ height < START_BLOCK_HEIGHT + CEREMONY_LENGTH_BLOCKS`. `prev_contribution_hash` **MUST** equal current `last_contribution_hash` (first contributor uses `vk_seed`). `AggSigUnsafe` **MUST** bind the domain-separated ceremony contribution message (string **MUST** match reference implementation). Creates a **Ceremony Marker Coin** with **even** output amount so the singleton outer has exactly one odd `CreateCoin` (recreation). Increments `contribution_count` and updates `last_contribution_hash`. Large parameters: committed by hash on-chain; payloads recovered off-chain from spends and memos. | [`contribute.rue`](https://github.com/DIG-Network/chia-scaled-parallel-voting/blob/main/puzzles/ceremony_singleton/contribute.rue) | +| **`finalize`** | Only after `height ≥ START_BLOCK_HEIGHT + CEREMONY_LENGTH_BLOCKS`. Requires `finalized` unset and `contribution_count ≥ MIN_PARTICIPANTS`. Sets `finalized`, `vk_hash`, `marker_root` from solution. Mints **Ceremony Voucher** and summary marker(s) with VK-related memos. **Not** authenticated by a designated key: first valid spend wins. Verifiers **SHOULD** independently derive or verify `vk_hash` and `marker_root` from marker chain before relying on an election. | [`finalize.rue`](https://github.com/DIG-Network/chia-scaled-parallel-voting/blob/main/puzzles/ceremony_singleton/finalize.rue) | + +**Off-chain / tests:** [`sdk/src/actors/ceremony.rs`](https://github.com/DIG-Network/chia-scaled-parallel-voting/blob/main/sdk/src/actors/ceremony.rs), [`sdk/src/ceremony/`](https://github.com/DIG-Network/chia-scaled-parallel-voting/tree/main/sdk/src/ceremony). Examples: [`sdk/tests/ceremony_contribute_e2e.rs`](https://github.com/DIG-Network/chia-scaled-parallel-voting/blob/main/sdk/tests/ceremony_contribute_e2e.rs), [`sdk/tests/ceremony_deploy_e2e.rs`](https://github.com/DIG-Network/chia-scaled-parallel-voting/blob/main/sdk/tests/ceremony_deploy_e2e.rs), more under [`sdk/tests/`](https://github.com/DIG-Network/chia-scaled-parallel-voting/tree/main/sdk/tests). + +--- + +## Ceremony Marker Coin + +- **Source:** [`puzzles/ceremony_coin/marker.rue`](https://github.com/DIG-Network/chia-scaled-parallel-voting/blob/main/puzzles/ceremony_coin/marker.rue). +- **Curried:** `CEREMONY_LAUNCHER_ID`, `PARTICIPANT_PUBKEY`, `CONTRIBUTION_HASH`, `PREV_CONTRIBUTION_HASH`. +- **Created by** ceremony `contribute` only. Even amount (reference: 2 mojos) for singleton morph rules. +- **Spend:** may return no conditions; coin remains an on-chain commitment until removed. +- **Discovery:** launcher id as hint for indexers. + +--- + +## Ceremony Voucher Coin + +- **Source:** [`puzzles/ceremony_singleton/ceremony_voucher.rue`](https://github.com/DIG-Network/chia-scaled-parallel-voting/blob/main/puzzles/ceremony_singleton/ceremony_voucher.rue). +- **Minted only** from ceremony [`finalize.rue`](https://github.com/DIG-Network/chia-scaled-parallel-voting/blob/main/puzzles/ceremony_singleton/finalize.rue). +- Anyone-can-spend with self-recreation at same puzzle hash and amount so **many** election deploys can reuse one ceremony. +- **`CANONICAL_MSG`:** + +`sha256("chip:ceremony:voucher" || vk_hash || max_voters_u64_be8 || ceremony_launcher_id)` + +Election deploy **SHOULD** co-spend the voucher and assert this announcement. + +**Contributions MUST NOT** be voucher-gated; the contribution window is **permissionless** at the puzzle level. Allow-lists are deployment policy only. + +--- + +Companion index: [README.md](./README.md). diff --git a/assets/chip-scaled-parallel-voting/chip-election-coins.md b/assets/chip-scaled-parallel-voting/chip-election-coins.md new file mode 100644 index 00000000..35a759cb --- /dev/null +++ b/assets/chip-scaled-parallel-voting/chip-election-coins.md @@ -0,0 +1,101 @@ +# Election, Ballot, Registration, and Voting coins (companion to CHIP draft) + +**What this doc is:** **puzzle-level** detail for election-facing coins: fields, inner actions, and where **`finalize`** is *not* allowed. Lifecycle order lives in [chip-protocol-flow.md](./chip-protocol-flow.md). CHIP-0050 routing for singleton inners: [`puzzles/action.rue`](https://github.com/DIG-Network/chia-scaled-parallel-voting/blob/main/puzzles/action.rue). + +**Code:** [DIG-Network/chia-scaled-parallel-voting](https://github.com/DIG-Network/chia-scaled-parallel-voting) on `main`. + +--- + +## Election state (`ElectionState`) + +| Field | Description | +|--------|-------------| +| `registration_merkle_root` | Root of registration sparse Merkle tree (voters + weights). | +| `registration_count` | Registered voter count. | +| `registration_vote_weight` | Sum of locked CAT weight. | +| `election_start_height` | Block height at election genesis. | +| `ceremony_launcher_id` | Ceremony Singleton launcher for this VK. | +| `max_voters` | Capacity upper bound (with `TREE_DEPTH`). | +| `vk_hash` | SHA-256 of Groth16 verification key bytes. | +| `vote_mode_lock` | `0xFF…FF` (32 bytes): each ballot chooses `vote_options_root`; otherwise all ballots **MUST** use that fixed restricted root. | + +Shared types and election constants: [`puzzles/election/shared.rue`](https://github.com/DIG-Network/chia-scaled-parallel-voting/blob/main/puzzles/election/shared.rue). + +**Deploy curries** (VK, IC, threshold pack, `MAX_SIGNERS`, `election_launcher_id`, CHIP-0050 action roots) **MUST** stay consistent across all Ballot Coins from `createBallot`. + +This CHIP does **not** specify an on-chain XCH fee in `register` or `accumulated_fees` on the singleton. + +**Ballot close time** is **`VOTE_CLOSE_HEIGHT`** on each Ballot Coin, not one global election timer. + +--- + +## Election Singleton: inner actions + +| Action | Behavior | +|--------|----------| +| **`register`** | Empty SPT slot proof; leaf `sha256(pubkey || locked_cat_mojos_be8)` (8-byte BE mojos); voter signature; increment counts and weight; mint Registration CAT with empty per-ballot tree; `release_destination` unset. | +| **`createBallot`** | **Only** path for valid Ballot Coin lineage. Forward VK, IC, threshold, `MAX_SIGNERS`, ids; **snapshot** `registration_merkle_root` and `registration_vote_weight` for Groth16 public inputs; set `vote_close_height`, `vote_options_root`, outcome domain. `ElectionState` counts do not change solely from creating a ballot. Reference: **2-mojo** launcher eve for morph safety. | +| **`deregister`** | Leaf → `EMPTY_LEAF_HASH`; deregister announcement; decrement counts and weight. | + +*Rue:* [`register.rue`](https://github.com/DIG-Network/chia-scaled-parallel-voting/blob/main/puzzles/election/register.rue), [`create_ballot.rue`](https://github.com/DIG-Network/chia-scaled-parallel-voting/blob/main/puzzles/election/create_ballot.rue), [`deregister.rue`](https://github.com/DIG-Network/chia-scaled-parallel-voting/blob/main/puzzles/election/deregister.rue). *Deploy / orchestration:* [`sdk/src/actors/deployer.rs`](https://github.com/DIG-Network/chia-scaled-parallel-voting/blob/main/sdk/src/actors/deployer.rs). + +`finalize`, `oracle`, `announce_finalization` **MUST NOT** appear on the Election Singleton; they belong on the Ballot Coin. + +--- + +## Ballot Coin + +**State:** `(finalized, vote_outcome, agg_signers)`. + +Inner action Merkle **MUST** be exactly `{ finalize, oracle, announce_finalization }` (helpers in [`puzzles/ballot_coin/shared.rue`](https://github.com/DIG-Network/chia-scaled-parallel-voting/blob/main/puzzles/ballot_coin/shared.rue)). + +**`finalize` curries:** VK, IC, `BALLOT_LAUNCHER_ID`, `ELECTION_LAUNCHER_ID`, `VOTE_CLOSE_HEIGHT`, `VOTE_OPTIONS_ROOT`, `VOTE_THRESHOLD_NUM`, `VOTE_THRESHOLD_DEN`, `REGISTRATION_MERKLE_ROOT_SNAPSHOT`, `REGISTRATION_VOTE_WEIGHT_SNAPSHOT`. **8** public inputs; **9** IC points. + +| Action | Behavior | +|--------|----------| +| **`finalize`** | `height ≥ VOTE_CLOSE_HEIGHT`; Groth16 on eight scalars; `bls_verify` on canonical `vote_message`; recreate with `finalized = true` and outcome fields. | +| **`oracle`** | Recreate unchanged; **open** announcement binds `VOTE_CLOSE_HEIGHT` and `VOTE_OPTIONS_ROOT`; **closed** includes `vote_outcome`, `agg_signers`. `mint_voting_coin` / `update_vote` **MUST** assert oracle (Groth16 does not bind close height). | +| **`announce_finalization`** | After finalize, permissionless re-announce for late consumers. | + +*Rue:* [`finalize.rue`](https://github.com/DIG-Network/chia-scaled-parallel-voting/blob/main/puzzles/ballot_coin/finalize.rue), [`oracle.rue`](https://github.com/DIG-Network/chia-scaled-parallel-voting/blob/main/puzzles/ballot_coin/oracle.rue), [`announce_finalization.rue`](https://github.com/DIG-Network/chia-scaled-parallel-voting/blob/main/puzzles/ballot_coin/announce_finalization.rue). *Ballot actor:* [`sdk/src/actors/ballot.rs`](https://github.com/DIG-Network/chia-scaled-parallel-voting/blob/main/sdk/src/actors/ballot.rs). + +--- + +## Registration Coin + +**State:** `(voter_pubkey, election_launcher_id, voted_ballots_root, release_destination)`. + +| Action | Behavior | +|--------|----------| +| **`mint_voting_coin`** | Assert Ballot `oracle` (open). Restricted mode: prove `vote_data` ∈ `vote_options_root`. Non-membership + insert `sha256(ballot_launcher_id)` in per-ballot tree; mint 1-mojo Voting CAT. Fail if `release_destination` set. | +| **`release`** | Assert Election `deregister` announcement; set `release_destination`. Gated by deregister, **not** ballot finalize. | + +*Rue:* [`mint_voting_coin.rue`](https://github.com/DIG-Network/chia-scaled-parallel-voting/blob/main/puzzles/registration_coin/mint_voting_coin.rue), [`release.rue`](https://github.com/DIG-Network/chia-scaled-parallel-voting/blob/main/puzzles/registration_coin/release.rue); shared: [`registration_coin/shared.rue`](https://github.com/DIG-Network/chia-scaled-parallel-voting/blob/main/puzzles/registration_coin/shared.rue). + +--- + +## Voting Coin + +**State:** `(voter_pubkey, ballot_launcher_id, vote_data, registration_coin_id)`; 1 mojo lineage token; stake on Registration Coin. + +| Action | Behavior | +|--------|----------| +| **`update_vote`** | Assert Ballot `oracle` (open); height checks per reference; restricted mode proofs if needed; BLS memo for `vote_message`; **does not** spend Election Singleton. | + +*Rue:* [`update_vote.rue`](https://github.com/DIG-Network/chia-scaled-parallel-voting/blob/main/puzzles/voting_coin/update_vote.rue), [`voting_coin/shared.rue`](https://github.com/DIG-Network/chia-scaled-parallel-voting/blob/main/puzzles/voting_coin/shared.rue) (`vote_message` preimage). *Voter actor:* [`sdk/src/actors/voter.rs`](https://github.com/DIG-Network/chia-scaled-parallel-voting/blob/main/sdk/src/actors/voter.rs). + +Witness builders **MUST** use the **current** Voting Coin tip per `(registration_coin_id, ballot_launcher_id)`. + +--- + +## Lineage (normative) + +- Registration ← `register` (Election Singleton). +- Ballot ← `createBallot` only. +- Voting ← `mint_voting_coin` (Registration Coin). + +**Compiled bytecode** (run [`build.sh`](https://github.com/DIG-Network/chia-scaled-parallel-voting/blob/main/build.sh) / [`build.ps1`](https://github.com/DIG-Network/chia-scaled-parallel-voting/blob/main/build.ps1)): [`puzzles/compiled/election/`](https://github.com/DIG-Network/chia-scaled-parallel-voting/tree/main/puzzles/compiled/election), [`ballot_coin/`](https://github.com/DIG-Network/chia-scaled-parallel-voting/tree/main/puzzles/compiled/ballot_coin), [`registration_coin/`](https://github.com/DIG-Network/chia-scaled-parallel-voting/tree/main/puzzles/compiled/registration_coin), [`voting_coin/`](https://github.com/DIG-Network/chia-scaled-parallel-voting/tree/main/puzzles/compiled/voting_coin). **Loader:** [`sdk/src/puzzles.rs`](https://github.com/DIG-Network/chia-scaled-parallel-voting/blob/main/sdk/src/puzzles.rs). **Finalize bundles:** [`sdk/src/actors/aggregator.rs`](https://github.com/DIG-Network/chia-scaled-parallel-voting/blob/main/sdk/src/actors/aggregator.rs). + +--- + +Companion index: [README.md](./README.md). diff --git a/assets/chip-scaled-parallel-voting/chip-groth16-clvm.md b/assets/chip-scaled-parallel-voting/chip-groth16-clvm.md new file mode 100644 index 00000000..25815ab9 --- /dev/null +++ b/assets/chip-scaled-parallel-voting/chip-groth16-clvm.md @@ -0,0 +1,107 @@ +# Groth16, CLVM, and ballot finalization (companion to CHIP draft) + +**What this doc is:** how **Ballot Coin `finalize`** checks a Groth16 proof plus aggregate **BLS** in CLVM ([CHIP-0011](https://github.com/Chia-Network/chips/blob/main/CHIPs/chip-0011.md)), **why** that combination is sound, and **informative** context on prover cost and a possible **BLS12-377** future. **Threshold intuition:** PNG figures below (`figure_1.png`, `figure_2.png`) sit in this same `assets/chip-scaled-parallel-voting/` folder (mirrored in the reference repo’s [`assets/`](https://github.com/DIG-Network/chia-scaled-parallel-voting/tree/main/assets)); they are **not** literal CRS diagrams. + +**Code:** [DIG-Network/chia-scaled-parallel-voting](https://github.com/DIG-Network/chia-scaled-parallel-voting) on `main`. **Public-input order and Merkle rules:** [chip-witnesses-encoding.md](./chip-witnesses-encoding.md). **Spec overview:** [chip-scaled-parallel-voting.md](../../CHIPs/chip-scaled-parallel-voting.md). + +--- + +## What CLVM contributes + +**CLVM is not a general ZK virtual machine.** Under [CHIP-0011](https://github.com/Chia-Network/chips/blob/main/CHIPs/chip-0011.md) it exposes **BLS12-381** curve opcodes: enough for the **Groth16 verifier** as a fixed pairing-product check, and for **`bls_verify`** on aggregated signatures. + +**Ballot `finalize`** ([`puzzles/ballot_coin/finalize.rue`](https://github.com/DIG-Network/chia-scaled-parallel-voting/blob/main/puzzles/ballot_coin/finalize.rue)) does the following in order: + +1. Rebuilds the **Groth16 instance** from the proof \((A,B,C)\), the **verification key** \((\alpha,\beta,\gamma,\delta)\) and **input commitment** points **IC[0..8]** curried at deploy. +2. Derives eight **scalar inputs** \(s_1,\ldots,s_8\) from **on-chain-visible** data (registration snapshot, weights, `vote_message`, threshold pack, ballot id, num/den) and compares them to scalars supplied in the spend, so the proof cannot be replayed against a different ballot or election snapshot. +3. Computes **vk_input** \(= \mathrm{IC}_0 + \sum_{i=1}^{8} \mathrm{IC}_i \cdot s_i\) in G1 (same linear structure as standard Groth16 IC). +4. Uses **`bls_pairing_identity`** to assert the usual Groth16 pairing product holds for \((A,B,C)\), **vk_input**, and **VK** (i.e. the CLVM checks a **constant-size proof** in time that depends on **pairing cost**, not on the number of voters). +5. Separately runs **`bls_pairing_identity`** with **`g2_map`** on **`vote_message`** so the aggregate signature is bound to the same outcome message the circuit and announcements use. + +**Bottom line:** Groth16 proves off-chain that the voting R1CS holds for those public inputs; CLVM reruns the verifier equation on the VK and scalars reconstructed from chain state. + +--- + +## What the circuit proves (off-chain) vs what the chain checks (on-chain) + +| Layer | Responsibility | +|--------|----------------| +| **R1CS + Groth16 (prover)** | Produces a proof that the circuit’s constraints are satisfied for the **committed** public inputs (e.g. that a **quorum / majority** relation over registered weight and the claimed signer set is consistent with the circuit definition (see comments in [`sdk/src/prover/circuit.rs`](https://github.com/DIG-Network/chia-scaled-parallel-voting/blob/main/sdk/src/prover/circuit.rs)). **Proof bytes ↔ arkworks:** [`sdk/src/prover/proof.rs`](https://github.com/DIG-Network/chia-scaled-parallel-voting/blob/main/sdk/src/prover/proof.rs). | +| **Ballot `finalize` (CLVM)** | Verifies the Groth16 proof with **CHIP-0011** pairings in [`finalize.rue`](https://github.com/DIG-Network/chia-scaled-parallel-voting/blob/main/puzzles/ballot_coin/finalize.rue); **re-derives** \(s_1..s_8\) from curried and solution fields; verifies **BLS aggregation** over **`vote_message`**. | +| **Registration / Voting puzzles** | Enroll voters in the registration SPT ([`register.rue`](https://github.com/DIG-Network/chia-scaled-parallel-voting/blob/main/puzzles/election/register.rue)), pin per-ballot **oracle** ([`oracle.rue`](https://github.com/DIG-Network/chia-scaled-parallel-voting/blob/main/puzzles/ballot_coin/oracle.rue); mint/update: [`mint_voting_coin.rue`](https://github.com/DIG-Network/chia-scaled-parallel-voting/blob/main/puzzles/registration_coin/mint_voting_coin.rue), [`update_vote.rue`](https://github.com/DIG-Network/chia-scaled-parallel-voting/blob/main/puzzles/voting_coin/update_vote.rue)), and keep voting state off the Election singleton’s hot path. | + +**Why both Groth16 and `bls_verify`?** BLS aggregation gives a compact signature over **`vote_message`** tied to **`agg_signers`**. It does not, by itself, prove statements about **global** registration roots, **weights**, or **threshold arithmetic** inside a single cheap opcode. The circuit is where those predicates live as R1CS; Groth16 compresses that check to **three curve points and a handful of pairings** on-chain. The **oracle** spend on the Ballot Coin is still needed where the proof does not encode every pin (e.g. **`VOTE_CLOSE_HEIGHT`** and **`VOTE_OPTIONS_ROOT`** for mint/update). + +**Finalize bundle assembly (off-chain):** [`sdk/src/actors/aggregator.rs`](https://github.com/DIG-Network/chia-scaled-parallel-voting/blob/main/sdk/src/actors/aggregator.rs). Example tests: [`sdk/tests/finalize_per_ballot_e2e.rs`](https://github.com/DIG-Network/chia-scaled-parallel-voting/blob/main/sdk/tests/finalize_per_ballot_e2e.rs), [`finalize_one_third_threshold_e2e.rs`](https://github.com/DIG-Network/chia-scaled-parallel-voting/blob/main/sdk/tests/finalize_one_third_threshold_e2e.rs). + +--- + +## Why proving hurts today, and what BLS12-377 could change (informative) + +**Informative only.** This section does not change interoperability requirements: ballot **`finalize`** still **MUST** verify Groth16 and **`bls_verify`** on **BLS12-381** per [CHIP-0011](https://github.com/Chia-Network/chips/blob/main/CHIPs/chip-0011.md). Discussion of **BLS12-377** below is **not** part of that requirement set. + +**On-chain verification is the small, predictable part.** The puzzle takes a proof bundle and runs the pairing checks. That work stays **flat** for scale in the usual sense: `finalize` is not replaying tens of thousands of per-voter updates on chain. + +**Off-chain proving is usually the expensive part.** The circuit stays in the **BLS12-381** Groth16 world, but many statements do not **fit** the scalar field natively, so the R1CS ends up **emulating heavier BLS12-381 arithmetic inside the BLS12-381 scalar circuit**. That pattern is called **field emulation**; in this protocol’s circuit stack it shows up as **tower-style** gadgets, with **k = 10** used here as shorthand for “deep emulation tower,” not as a normative constant for implementations. **Result:** proof generation can be **slow**, while **checking** the proof on chain stays comparatively cheap. + +**BLS12-377 is the “what if CLVM grew a second pairing?” case.** **BLS12-377** and **BLS12-381** form a **cycle**: the curves are set up so a proof system can move between them instead of emulating **381** inside **381** forever. **If** consensus ever added **BLS12-377** pairing opcodes alongside today’s **381** surface, a plausible layout is **Groth16 verification on 377** in `finalize` with **voter BLS and `bls_verify` still on 381**. That split is the usual pattern people point at for **recursive proofs** and **L2-style consensus**: do the heavy batch proof on one side of the cycle, anchor the result on L1 on the other. + +**Not part of this CHIP:** nothing here **requires** **377**. The goal is to document **where prover time goes today** and **what extra CLVM curve support could change later**. + +--- + +## Why the on-chain scalar bindings matter + +**The VK fixes the circuit; the public inputs fix the election/ballot instance.** If the prover’s scalars do not match what the puzzle recomputes from chain fields, **vk_input** is wrong and the pairing check fails. + +Groth16’s **verification key** is tied to a **fixed circuit shape** and a **ceremony-produced** structured reference string. In [`finalize.rue`](https://github.com/DIG-Network/chia-scaled-parallel-voting/blob/main/puzzles/ballot_coin/finalize.rue), the prover supplies **Scalars** \(s_1,\ldots,s_8\); the puzzle **recomputes** the expected scalars from: + +- `REGISTRATION_MERKLE_ROOT_SNAPSHOT`, `REGISTRATION_VOTE_WEIGHT_SNAPSHOT` (snapshotted at `createBallot`; [`create_ballot.rue`](https://github.com/DIG-Network/chia-scaled-parallel-voting/blob/main/puzzles/election/create_ballot.rue)), +- `agg_signers`, `vote_message`, `threshold_pack(VOTE_THRESHOLD_NUM, VOTE_THRESHOLD_DEN)`, `BALLOT_LAUNCHER_ID`, +- and the raw field encodings for num/den, + +and **asserts equality** with the proof’s public scalars (hashes mod \(r\) where specified in the puzzle). Any mismatch means **vk_input** does not match what the prover used, and **pairing verification fails**. That is what prevents **cross-ballot replay** or **changing** the registration commitment **after** the ballot was created. + +--- + +## Trusted setup and `vk_hash` + +**Groth16 needs a circuit-specific CRS / VK.** This CHIP assumes a **multi-party ceremony** (see [chip-ceremony.md](./chip-ceremony.md); puzzles [`puzzles/ceremony_singleton/`](https://github.com/DIG-Network/chia-scaled-parallel-voting/tree/main/puzzles/ceremony_singleton)) yields a **verification key** whose **SHA-256** is **`vk_hash`** on the Election Singleton. Implementations **must** treat **`vk_hash`** and voucher binding as part of the trust model: a malicious VK breaks soundness regardless of CLVM correctness. + +--- + +## Figures (pedagogical intuition) + +**Not protocol diagrams.** The PNGs hosted with the reference implementation (`figure_1.png`, `figure_2.png` under [`assets/`](https://github.com/DIG-Network/chia-scaled-parallel-voting/tree/main/assets)) are **not** literal CLVM opcode or Groth16 CRS pictures. They illustrate **why a threshold can pin an outcome** before one talks about pairings: with **too few** contributions, many “curves” are still consistent with the observed data; with **enough** contributions, the aggregate constraint set can **lock** the relevant commitment. **τ** in the figures (“where the proof value is read”) is a visual stand-in for **evaluating a committed polynomial / SRS at a secret point** (the same *flavor* of idea that makes polynomial-based SNARKs work) without replacing the formal definition of Groth16. + +### Figure 1: below threshold (ambiguous) + +
+ Diagram: Agreement curve (2 of 5 signers, below threshold); V1 and V2 signed; dashed orange curves show ambiguous fits through the points; vertical dashed line at τ marks the proof anchor +
Figure 1: Too few signers leave the curve ambiguous (pedagogical).
+
+ +*Interpretation:* Until enough voters (by weight / quorum rule) are committed inside the proof’s statement, an adversary could still be consistent with **multiple** outcomes or weights, analogous to **many** degree-(\(n\)-1) curves through **too few** points. + +### Figure 2: threshold met (curve locked) + +
+ Diagram: Agreement curve (4 of 5 signers, threshold met); solid blue curve locked through V1 V2 V3 V5; V4 silent; vertical dashed line at τ where proof value is read +
Figure 2: Enough signers lock a single curve; τ is where the proof value is read (pedagogical).
+
+ +*Interpretation:* Once the threshold relation enforced in the circuit holds, the **public inputs** pin down the instance; Groth16 then proves that instance in zero knowledge (witness privacy is secondary here; **soundness** of the vote outcome + quorum claim is primary). + +--- + +Companion index: [README.md](./README.md). diff --git a/assets/chip-scaled-parallel-voting/chip-protocol-flow.md b/assets/chip-scaled-parallel-voting/chip-protocol-flow.md new file mode 100644 index 00000000..26110c69 --- /dev/null +++ b/assets/chip-scaled-parallel-voting/chip-protocol-flow.md @@ -0,0 +1,101 @@ +# Protocol flow (companion to CHIP draft) + +**What this doc is:** the **end-to-end story** in order: ceremony, deploy, register, vote, finalize, exit. [chip-scaled-parallel-voting.md](../../CHIPs/chip-scaled-parallel-voting.md) stays the spec summary; here you get **which lane each spend lives in** and **where to read code** in [**chia-scaled-parallel-voting**](https://github.com/DIG-Network/chia-scaled-parallel-voting) on `main`. + +**Related:** deeper tables live in [chip-ceremony.md](./chip-ceremony.md), [chip-election-coins.md](./chip-election-coins.md), [chip-witnesses-encoding.md](./chip-witnesses-encoding.md), [chip-groth16-clvm.md](./chip-groth16-clvm.md). + +--- + +## Lanes (reminder) + +**Three spend classes** keep registration and per-ballot finality from blocking each other. + +| Lane | Spends | Role | +|------|--------|------| +| **Election singleton** | `register`, `createBallot`, `deregister` | Enrollment, ballot issuance, collateral release authorization. Serialized by design for registration. | +| **Parallel voting** | `mint_voting_coin`, `update_vote` | Do **not** require the Election Singleton; many voters can progress in the same block (within chain limits). | +| **Per-ballot** | Ballot Coin: `oracle`, `finalize`, `announce_finalization` | Vote mechanics and finality; does **not** spend the Election Singleton. | + +--- + +## Phase 0: Ceremony (trusted setup) + +**Goal:** produce a Groth16 **VK** the election can bind to (`vk_hash`), with on-chain markers so people can audit contributions. + +1. Deploy the **Ceremony Singleton** with window, `MIN_PARTICIPANTS`, `MAX_VOTERS`, `vk_seed`, and mod hashes for marker / voucher puzzles (see [chip-ceremony.md](./chip-ceremony.md)). +2. During `[start, start + length)`, participants submit **`contribute`** spends. Each accepted contribution creates a **Ceremony Marker Coin** and advances linear `last_contribution_hash` state. +3. After the window closes, **`finalize`** may run when `contribution_count ≥ MIN_PARTICIPANTS`. This seals `vk_hash`, `marker_root`, mints the **Ceremony Voucher** and summary outputs with VK material in memos. +4. Off-chain, verifiers walk markers / spends, verify contribution proofs, and derive the Groth16 VK. Before trusting an election, **independently check** `vk_hash` (and related) against chain data; `finalize` has no single designated signer. + +*Implementation:* [`puzzles/ceremony_singleton/contribute.rue`](https://github.com/DIG-Network/chia-scaled-parallel-voting/blob/main/puzzles/ceremony_singleton/contribute.rue), [`finalize.rue`](https://github.com/DIG-Network/chia-scaled-parallel-voting/blob/main/puzzles/ceremony_singleton/finalize.rue); marker [`puzzles/ceremony_coin/marker.rue`](https://github.com/DIG-Network/chia-scaled-parallel-voting/blob/main/puzzles/ceremony_coin/marker.rue); voucher [`ceremony_voucher.rue`](https://github.com/DIG-Network/chia-scaled-parallel-voting/blob/main/puzzles/ceremony_singleton/ceremony_voucher.rue). Rust: [`sdk/src/actors/ceremony.rs`](https://github.com/DIG-Network/chia-scaled-parallel-voting/blob/main/sdk/src/actors/ceremony.rs), [`sdk/src/ceremony/`](https://github.com/DIG-Network/chia-scaled-parallel-voting/tree/main/sdk/src/ceremony). + +--- + +## Phase 1: Election deploy + +**Goal:** spin up the **Election Singleton** bound to the ceremony’s VK (and ideally the voucher message). + +5. Launch the **Election Singleton** with eight-field `ElectionState`, curried VK/IC, threshold pack, `MAX_SIGNERS`, CHIP-0050 action Merkle roots, etc. +6. **Recommended:** co-spend the **Ceremony Voucher** in the deploy bundle and assert its `CANONICAL_MSG` so the election is bound to `(vk_hash, max_voters, ceremony_launcher_id)` (see [chip-ceremony.md](./chip-ceremony.md)). + +*Implementation:* [`sdk/src/actors/deployer.rs`](https://github.com/DIG-Network/chia-scaled-parallel-voting/blob/main/sdk/src/actors/deployer.rs); election puzzles [`puzzles/election/`](https://github.com/DIG-Network/chia-scaled-parallel-voting/tree/main/puzzles/election); CHIP-0050 routing [`puzzles/action.rue`](https://github.com/DIG-Network/chia-scaled-parallel-voting/blob/main/puzzles/action.rue). + +--- + +## Phase 2: Registration and ballots (slow lane) + +**Goal:** add voters to the registration tree and mint **Ballot Coins** with snapshotted roots for finalize. + +7. Voters call **`register`** on the Election Singleton (one registration coin per voter, CAT staked, registration SPT updated). +8. The operator calls **`createBallot`** to mint each **Ballot Coin** (2-mojo launcher pattern in reference). Ballots carry `vote_close_height`, `vote_options_root`, and **snapshots** of registration root + total weight for Groth16 public inputs at finalize. + +*Implementation:* [`puzzles/election/register.rue`](https://github.com/DIG-Network/chia-scaled-parallel-voting/blob/main/puzzles/election/register.rue), [`create_ballot.rue`](https://github.com/DIG-Network/chia-scaled-parallel-voting/blob/main/puzzles/election/create_ballot.rue). Actors: [`sdk/src/actors/voter.rs`](https://github.com/DIG-Network/chia-scaled-parallel-voting/blob/main/sdk/src/actors/voter.rs), [`ballot.rs`](https://github.com/DIG-Network/chia-scaled-parallel-voting/blob/main/sdk/src/actors/ballot.rs). + +--- + +## Phase 3: Voting (parallel lane) + +**Goal:** cast or change votes without touching the Election Singleton. + +9. To cast or change a vote: **`mint_voting_coin`** (first time for that ballot from this registration) or **`update_vote`** on the **Voting Coin**. Both assert the Ballot Coin **`oracle`** (open) so close height and vote mode are pinned on-chain. +10. BLS signatures over the canonical **`vote_message`** are supplied for off-chain aggregation (e.g. memos); see [chip-witnesses-encoding.md](./chip-witnesses-encoding.md). + +*Implementation:* [`puzzles/registration_coin/mint_voting_coin.rue`](https://github.com/DIG-Network/chia-scaled-parallel-voting/blob/main/puzzles/registration_coin/mint_voting_coin.rue), [`puzzles/voting_coin/update_vote.rue`](https://github.com/DIG-Network/chia-scaled-parallel-voting/blob/main/puzzles/voting_coin/update_vote.rue); open oracle spend [`puzzles/ballot_coin/oracle.rue`](https://github.com/DIG-Network/chia-scaled-parallel-voting/blob/main/puzzles/ballot_coin/oracle.rue). + +--- + +## Phase 4: Finalize (per-ballot lane) + +**Goal:** prove quorum / threshold off-chain; verify Groth16 + aggregate BLS on the **Ballot Coin**. + +11. Off-chain: an **aggregator** collects Voting Coins and registrations, builds witness, runs **Groth16** prover, aggregates BLS (`sdk`: [`sdk/src/actors/aggregator.rs`](https://github.com/DIG-Network/chia-scaled-parallel-voting/blob/main/sdk/src/actors/aggregator.rs), [`sdk/src/prover/circuit.rs`](https://github.com/DIG-Network/chia-scaled-parallel-voting/blob/main/sdk/src/prover/circuit.rs), [`proof.rs`](https://github.com/DIG-Network/chia-scaled-parallel-voting/blob/main/sdk/src/prover/proof.rs)). +12. On-chain: **`finalize`** on the Ballot Coin checks Groth16 and aggregate BLS via [CHIP-0011](https://github.com/Chia-Network/chips/blob/main/CHIPs/chip-0011.md) pairing opcodes ([`puzzles/ballot_coin/finalize.rue`](https://github.com/DIG-Network/chia-scaled-parallel-voting/blob/main/puzzles/ballot_coin/finalize.rue)), then commits `vote_outcome` and `agg_signers`. Intuition and the **informative** 377 note: [chip-groth16-clvm.md](./chip-groth16-clvm.md). +13. Optionally **`announce_finalization`** ([`announce_finalization.rue`](https://github.com/DIG-Network/chia-scaled-parallel-voting/blob/main/puzzles/ballot_coin/announce_finalization.rue)) so downstream logic can assert finality in a later block. + +Example tests: [`sdk/tests/finalize_per_ballot_e2e.rs`](https://github.com/DIG-Network/chia-scaled-parallel-voting/blob/main/sdk/tests/finalize_per_ballot_e2e.rs), [`finalize_one_third_threshold_e2e.rs`](https://github.com/DIG-Network/chia-scaled-parallel-voting/blob/main/sdk/tests/finalize_one_third_threshold_e2e.rs). + +--- + +## Phase 5: Exit (slow lane) + +**Goal:** clear registration and unlock collateral; **not** the same thing as ballot finalize. + +14. **`deregister`** on the Election Singleton clears the voter from the registration SPT and emits the deregister announcement ([`puzzles/election/deregister.rue`](https://github.com/DIG-Network/chia-scaled-parallel-voting/blob/main/puzzles/election/deregister.rue)). +15. **`release`** on the **Registration Coin** (typically same bundle) consumes that announcement and sets `release_destination`; collateral unlock follows puzzle finalizer rules; **not** tied to ballot finalization ([`puzzles/registration_coin/release.rue`](https://github.com/DIG-Network/chia-scaled-parallel-voting/blob/main/puzzles/registration_coin/release.rue)). + +**Full-network E2E harness:** [`cli/src/bin/live_integration_test.rs`](https://github.com/DIG-Network/chia-scaled-parallel-voting/blob/main/cli/src/bin/live_integration_test.rs). + +--- + +## Cross-reference + +| Topic | Document | +|--------|----------| +| Ceremony puzzles, voucher, markers | [chip-ceremony.md](./chip-ceremony.md) | +| Election / Ballot / Registration / Voting coins and inner actions | [chip-election-coins.md](./chip-election-coins.md) | +| Merkle trees, vote modes, `vote_message`, public inputs, announcements | [chip-witnesses-encoding.md](./chip-witnesses-encoding.md) | +| Groth16 + CLVM / CHIP-0011, finalize soundness, `assets/` figures | [chip-groth16-clvm.md](./chip-groth16-clvm.md) | + +--- + +Companion index: [README.md](./README.md). diff --git a/assets/chip-scaled-parallel-voting/chip-witnesses-encoding.md b/assets/chip-scaled-parallel-voting/chip-witnesses-encoding.md new file mode 100644 index 00000000..78ba9926 --- /dev/null +++ b/assets/chip-scaled-parallel-voting/chip-witnesses-encoding.md @@ -0,0 +1,95 @@ +# Witnesses, Merkle trees, vote modes, and encodings (companion to CHIP draft) + +**What this doc is:** the **bytes and hashes** everything agrees on: registration SPT, per-ballot trees, `vote_message`, the **eight** public inputs in order, and announcement strings. Overview stays in [chip-scaled-parallel-voting.md](../../CHIPs/chip-scaled-parallel-voting.md) § Specification. **Groth16 vs CLVM (and why proving can hurt):** [chip-groth16-clvm.md](./chip-groth16-clvm.md). + +**Code:** [DIG-Network/chia-scaled-parallel-voting](https://github.com/DIG-Network/chia-scaled-parallel-voting) on `main`. + +--- + +## Sparse Merkle trees + +**Puzzle and SDK both use the same hashing rules**; see [`puzzles/merkle_utils.rue`](https://github.com/DIG-Network/chia-scaled-parallel-voting/blob/main/puzzles/merkle_utils.rue) and shared headers ([`election/shared.rue`](https://github.com/DIG-Network/chia-scaled-parallel-voting/blob/main/puzzles/election/shared.rue), [`registration_coin/shared.rue`](https://github.com/DIG-Network/chia-scaled-parallel-voting/blob/main/puzzles/registration_coin/shared.rue)). Off-chain construction: [`sdk/src/merkle.rs`](https://github.com/DIG-Network/chia-scaled-parallel-voting/blob/main/sdk/src/merkle.rs). + +### Registration tree (reference `TREE_DEPTH = 32`) + +- **Slot:** first four bytes of `sha256(pubkey)` as big-endian `u32`. +- **Occupied leaf:** `sha256(pubkey || locked_cat_mojos_be8)`. +- **Empty leaf:** `EMPTY_LEAF_HASH = sha256(0x00 × 48)` = **0x17b0761f87b081d5cf10757ccc89f12be355c70e2e29df288b65b30710dcbcd1**. +- **Internal node:** `sha256(left || right)`; **not** the CLVM `0x02` serialized-tree prefix. + +### Per-registration ballot tree + +- **Leaf:** `sha256(ballot_launcher_id)`. +- **Slot (reference):** `sha256(ballot_launcher_id) mod 2^32`. +- **Depth:** **32** in reference. Any change requires matching the Groth16 circuit ([`sdk/src/prover/circuit.rs`](https://github.com/DIG-Network/chia-scaled-parallel-voting/blob/main/sdk/src/prover/circuit.rs)) and puzzle definitions under [`puzzles/registration_coin/`](https://github.com/DIG-Network/chia-scaled-parallel-voting/tree/main/puzzles/registration_coin), [`puzzles/election/`](https://github.com/DIG-Network/chia-scaled-parallel-voting/tree/main/puzzles/election). + +--- + +## Vote modes + +- **Unrestricted:** `vote_options_root` is 32 zero bytes; any `vote_data` subject to other checks. +- **Restricted:** `vote_options_root` is root of sorted Merkle tree of allowed outcomes; [`mint_voting_coin.rue`](https://github.com/DIG-Network/chia-scaled-parallel-voting/blob/main/puzzles/registration_coin/mint_voting_coin.rue) and [`update_vote.rue`](https://github.com/DIG-Network/chia-scaled-parallel-voting/blob/main/puzzles/voting_coin/update_vote.rue) **MUST** include inclusion proofs when restricted. + +If `vote_mode_lock` on the Election Singleton is not all `0xFF`, every ballot **MUST** use that locked root. + +--- + +## Canonical vote message + +`vote_message = sha256(vote_outcome || ballot_launcher_id || election_launcher_id)` + +All implementations (puzzles, aggregator, circuit) **MUST** use this exact preimage order. The voting puzzle defines the same ordering in [`voting_coin/shared.rue`](https://github.com/DIG-Network/chia-scaled-parallel-voting/blob/main/puzzles/voting_coin/shared.rue); the ballot finalize verifier recomputes it in [`ballot_coin/finalize.rue`](https://github.com/DIG-Network/chia-scaled-parallel-voting/blob/main/puzzles/ballot_coin/finalize.rue). + +--- + +## Groth16 public inputs (ordered) + +**Eight scalars** committed as public inputs to the circuit ([`sdk/src/prover/circuit.rs`](https://github.com/DIG-Network/chia-scaled-parallel-voting/blob/main/sdk/src/prover/circuit.rs)); **ordering MUST match** the header comments in [`finalize.rue`](https://github.com/DIG-Network/chia-scaled-parallel-voting/blob/main/puzzles/ballot_coin/finalize.rue): + +1. `registration_merkle_root` (witness-time) +2. `registration_vote_weight` +3. `agg_signers` +4. `vote_message` +5. `threshold_pack` +6. `ballot_launcher_id` +7. `vote_threshold_num` (field element) +8. `vote_threshold_den` (field element) + +Threshold **num** / **den** as public inputs allow one VK (fixed `MAX_SIGNERS`) to support multiple rational quorum fractions. + +**VK size (reference):** **768** bytes (`336 + 9 × 48`). Proof serialization: [`sdk/src/prover/proof.rs`](https://github.com/DIG-Network/chia-scaled-parallel-voting/blob/main/sdk/src/prover/proof.rs). + +--- + +## Off-chain vs on-chain + +- **Off-chain:** Enumerate registrations and Voting Coins; verify lineage; weighted quorum; BLS aggregation; Groth16 witness and proof (aggregator: [`sdk/src/actors/aggregator.rs`](https://github.com/DIG-Network/chia-scaled-parallel-voting/blob/main/sdk/src/actors/aggregator.rs)). +- **On-chain:** Ballot `finalize` in [`finalize.rue`](https://github.com/DIG-Network/chia-scaled-parallel-voting/blob/main/puzzles/ballot_coin/finalize.rue) verifies Groth16 and `bls_verify`. Any actor may submit a valid finalize bundle; incentives are out of scope for this CHIP. + +--- + +## Pinned constants (reference interop) + +- `TREE_DEPTH = 32` +- `MAX_SIGNERS = 20_000` +- `PUBLIC_INPUT_COUNT = 8` +- `EMPTY_LEAF_HASH` as above + +These align with the circuit and [`sdk/src/puzzles.rs`](https://github.com/DIG-Network/chia-scaled-parallel-voting/blob/main/sdk/src/puzzles.rs). **Bytecode** is emitted under [`puzzles/compiled/`](https://github.com/DIG-Network/chia-scaled-parallel-voting/tree/main/puzzles/compiled) after [`build.sh`](https://github.com/DIG-Network/chia-scaled-parallel-voting/blob/main/build.sh) / [`build.ps1`](https://github.com/DIG-Network/chia-scaled-parallel-voting/blob/main/build.ps1). + +--- + +## Announcement preimages + +String layouts and helpers appear in [`puzzles/ballot_coin/shared.rue`](https://github.com/DIG-Network/chia-scaled-parallel-voting/blob/main/puzzles/ballot_coin/shared.rue) and the oracle spend [`oracle.rue`](https://github.com/DIG-Network/chia-scaled-parallel-voting/blob/main/puzzles/ballot_coin/oracle.rue). + +| Source | Preimage | +|--------|----------| +| Ballot oracle (open) | `"ballot_oracle_open" || ballot_launcher_id || vote_close_height_u32_be || vote_options_root` | +| Ballot oracle (closed) | open preimage || `vote_outcome || agg_signers` | +| Ballot finalized | `"ballot_finalized" || ballot_launcher_id || vote_outcome || agg_signers` | +| Deregister | `"deregister" || voter_pubkey` | + +--- + +Companion index: [README.md](./README.md). diff --git a/assets/chip-scaled-parallel-voting/figure_1.png b/assets/chip-scaled-parallel-voting/figure_1.png new file mode 100644 index 0000000000000000000000000000000000000000..4ad5f699ccd5fe36ac5c9569ddb3185d8800d5cc GIT binary patch literal 51038 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 literal 0 HcmV?d00001 From 09d89a7f88334680912e8f00fe6fec054a0b8ccd Mon Sep 17 00:00:00 2001 From: danieljperry Date: Mon, 18 May 2026 10:57:54 +0800 Subject: [PATCH 2/3] Open CHIP-58 as a Draft --- ...scaled-parallel-voting.md => chip-0058.md} | 71 ++++++++---------- .../README.md | 6 +- .../chip-ceremony.md | 2 +- .../chip-election-coins.md | 0 .../chip-groth16-clvm.md | 4 +- .../chip-protocol-flow.md | 2 +- .../chip-witnesses-encoding.md | 2 +- .../figure_1.png | Bin .../figure_2.png | Bin 9 files changed, 40 insertions(+), 47 deletions(-) rename CHIPs/{chip-scaled-parallel-voting.md => chip-0058.md} (83%) rename assets/{chip-scaled-parallel-voting => chip-0058}/README.md (56%) rename assets/{chip-scaled-parallel-voting => chip-0058}/chip-ceremony.md (96%) rename assets/{chip-scaled-parallel-voting => chip-0058}/chip-election-coins.md (100%) rename assets/{chip-scaled-parallel-voting => chip-0058}/chip-groth16-clvm.md (97%) rename assets/{chip-scaled-parallel-voting => chip-0058}/chip-protocol-flow.md (96%) rename assets/{chip-scaled-parallel-voting => chip-0058}/chip-witnesses-encoding.md (96%) rename assets/{chip-scaled-parallel-voting => chip-0058}/figure_1.png (100%) rename assets/{chip-scaled-parallel-voting => chip-0058}/figure_2.png (100%) diff --git a/CHIPs/chip-scaled-parallel-voting.md b/CHIPs/chip-0058.md similarity index 83% rename from CHIPs/chip-scaled-parallel-voting.md rename to CHIPs/chip-0058.md index 3b7e55bc..0013c3ab 100644 --- a/CHIPs/chip-scaled-parallel-voting.md +++ b/CHIPs/chip-0058.md @@ -1,12 +1,11 @@ - -| CHIP Number | | +| CHIP Number | 0058 | | ------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | Title | Parallel voting at scale: off-chain proofs, on-chain finality | | Description | Standard for large-scale on-chain elections on Chia: an Election Singleton orchestrates registration and ballot issuance; Registration, Ballot, and Voting Coins separate enrollment from parallel votes and from per-ballot finalize (Groth16 + `bls_verify` on the Ballot Coin) with off-chain aggregation and proving. | | Author | Michael Taylor (on behalf of [DIG Network](https://github.com/DIG-Network)) | -| Editor | | -| Comments-URI | | -| Status | | +| Editor | [Dan Perry](https://github.com/danieljperry) | +| Comments-URI | [CHIPs repo, PR #202](https://github.com/Chia-Network/chips/pull/202) | +| Status | Draft | | Category | Standards Track | | Sub-Category | Primitive | | Created | 2026-05-04 | @@ -14,14 +13,13 @@ | Replaces | None | | Superseded-By | | - **Reference implementation (open source):** This CHIP is implemented in **[DIG-Network/chia-parallel-voting](https://github.com/DIG-Network/chia-parallel-voting)** on branch **`main`** ([puzzles/](https://github.com/DIG-Network/chia-parallel-voting/tree/main/puzzles), [sdk/](https://github.com/DIG-Network/chia-parallel-voting/tree/main/sdk), [cli/](https://github.com/DIG-Network/chia-parallel-voting/tree/main/cli), [wasm/](https://github.com/DIG-Network/chia-parallel-voting/tree/main/wasm), [app/](https://github.com/DIG-Network/chia-parallel-voting/tree/main/app)). When this CHIP ships in the Chia chips repo, the Markdown **companion files** in the same directory are [README.md](./README.md), [chip-protocol-flow.md](./chip-protocol-flow.md), and the other `chip-*.md` files linked there; executable artifacts remain in the reference repository. ## Abstract This CHIP defines a standard for decentralized, permissionless voting at scale on the Chia blockchain, with a practical target on the order of twenty thousand voters. There is no known theoretical upper bound; what you hit first in practice is off-chain computation and proving, not a hard chain limit. -BLS is the workhorse for aggregating voter *signatures*, but BLS alone is not enough to aggregate *votes* in a trustless setting: it does not, by itself, bind the voter threshold, how many voters backed a given result, or how many voters were registered for the election. This CHIP requires all three kinds of commitment (BLS aggregate, quorum threshold, and the registered-voter bound) to line up at finalize. +BLS is the workhorse for aggregating voter _signatures_, but BLS alone is not enough to aggregate _votes_ in a trustless setting: it does not, by itself, bind the voter threshold, how many voters backed a given result, or how many voters were registered for the election. This CHIP requires all three kinds of commitment (BLS aggregate, quorum threshold, and the registered-voter bound) to line up at finalize. The novel piece here is the realization that Groth16 circuits can produce cryptographic commitments today’s CLVM can verify. For a **fixed circuit**, the proof the coin checks is **constant size in CLVM** (it does not grow with how many voters contributed off-chain), and it still binds threshold, registration scope, and the BLS aggregate. Whoever submits the aggregation for finalization cannot fake a passing proof. If the finalize spend proves the required threshold voted and the correct BLS aggregate is in the bundle, the vote finalizes on-chain. @@ -39,7 +37,7 @@ It also points toward **production DAO governance** (for example CAT-weighted vo ## Backwards Compatibility -This CHIP does not propose any changes to CLVM. +This CHIP does not propose any changes to CLVM. ## Specification @@ -81,14 +79,13 @@ The ceremony graph is independent. Elections reference it through `ceremony_laun Tables of inner actions, Merkle slot and leaf rules, announcement preimages, Groth16 public-input ordering, and pinned constants are maintained as **companion** Markdown files alongside this CHIP so the Specification stays readable as a protocol overview: - -| Document | Contents | -| -------- | -------- | -| [chip-protocol-flow.md](./chip-protocol-flow.md) | Phases 0–5; *Implementation:* links into [puzzles/](https://github.com/DIG-Network/chia-parallel-voting/tree/main/puzzles), [sdk/](https://github.com/DIG-Network/chia-parallel-voting/tree/main/sdk), [cli/](https://github.com/DIG-Network/chia-parallel-voting/tree/main/cli) in the reference repo | -| [chip-ceremony.md](./chip-ceremony.md) | Ceremony marker, voucher, inner-action table (**Source** column), Rue / SDK cites | -| [chip-election-coins.md](./chip-election-coins.md) | Per-role Rue and actor links after each subsection | +| Document | Contents | +| ---------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | +| [chip-protocol-flow.md](./chip-protocol-flow.md) | Phases 0–5; _Implementation:_ links into [puzzles/](https://github.com/DIG-Network/chia-parallel-voting/tree/main/puzzles), [sdk/](https://github.com/DIG-Network/chia-parallel-voting/tree/main/sdk), [cli/](https://github.com/DIG-Network/chia-parallel-voting/tree/main/cli) in the reference repo | +| [chip-ceremony.md](./chip-ceremony.md) | Ceremony marker, voucher, inner-action table (**Source** column), Rue / SDK cites | +| [chip-election-coins.md](./chip-election-coins.md) | Per-role Rue and actor links after each subsection | | [chip-witnesses-encoding.md](./chip-witnesses-encoding.md) | Merkle rules, `vote_message`, public inputs; [merkle_utils.rue](https://github.com/DIG-Network/chia-parallel-voting/blob/main/puzzles/merkle_utils.rue), [circuit.rs](https://github.com/DIG-Network/chia-parallel-voting/blob/main/sdk/src/prover/circuit.rs), [finalize.rue](https://github.com/DIG-Network/chia-parallel-voting/blob/main/puzzles/ballot_coin/finalize.rue) | -| [chip-groth16-clvm.md](./chip-groth16-clvm.md) | CLVM Groth16 walkthrough tied to [finalize.rue](https://github.com/DIG-Network/chia-parallel-voting/blob/main/puzzles/ballot_coin/finalize.rue) and [circuit.rs](https://github.com/DIG-Network/chia-parallel-voting/blob/main/sdk/src/prover/circuit.rs); figures in reference [assets/](https://github.com/DIG-Network/chia-parallel-voting/tree/main/assets) | +| [chip-groth16-clvm.md](./chip-groth16-clvm.md) | CLVM Groth16 walkthrough tied to [finalize.rue](https://github.com/DIG-Network/chia-parallel-voting/blob/main/puzzles/ballot_coin/finalize.rue) and [circuit.rs](https://github.com/DIG-Network/chia-parallel-voting/blob/main/sdk/src/prover/circuit.rs); figures in reference [assets/](https://github.com/DIG-Network/chia-parallel-voting/tree/main/assets) | An implementation **MUST** conform to this Specification and to any **MUST** / **MUST NOT** requirement in those companions where the companion text is marked normative. **Companion index:** [README.md](./README.md). @@ -114,15 +111,15 @@ Interoperability is exercised by the open-source reference implementation ([DIG- **Automated tests** (Rust, under [`sdk/tests/`](https://github.com/DIG-Network/chia-parallel-voting/tree/main/sdk/tests)): -| Area | Examples | -| ---- | -------- | -| Ceremony | `ceremony_contribute_e2e`, `ceremony_deploy_e2e`, `ceremony_5_contributions_e2e` | -| Deploy, registration, ballots | `register_action_e2e`, `voter_register_full_flow`, `create_ballot_e2e`, `create_ballot_action_isolated`, `launch_ballot_e2e` | -| Voting | `voter_cast_vote_e2e`, `voter_cast_vote_two_voters_e2e`, `voter_revote_e2e`, `voter_double_vote_e2e`, `voter_revote_oracle_required_e2e` | -| Finalize | `finalize_per_ballot_e2e`, `finalize_one_third_threshold_e2e` | -| Collateral / deregister | `voter_release_collateral_e2e`, `voter_release_after_cast_e2e`, `aggregator_sync_after_deregister_e2e` | -| Merkle / constants / parity | `m5r_merkle_gate_e2e`, `chip_spec_compliance`, `deployer_aggregator_eve_hash_parity_e2e`, `puzzle_constants` | -| Broader harness | `integration`, `live_orchestration_e2e`, `actor_functions_e2e`, `ballot_reader_e2e`, `find_current_singleton_propagation_lag_e2e` | +| Area | Examples | +| ----------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------- | +| Ceremony | `ceremony_contribute_e2e`, `ceremony_deploy_e2e`, `ceremony_5_contributions_e2e` | +| Deploy, registration, ballots | `register_action_e2e`, `voter_register_full_flow`, `create_ballot_e2e`, `create_ballot_action_isolated`, `launch_ballot_e2e` | +| Voting | `voter_cast_vote_e2e`, `voter_cast_vote_two_voters_e2e`, `voter_revote_e2e`, `voter_double_vote_e2e`, `voter_revote_oracle_required_e2e` | +| Finalize | `finalize_per_ballot_e2e`, `finalize_one_third_threshold_e2e` | +| Collateral / deregister | `voter_release_collateral_e2e`, `voter_release_after_cast_e2e`, `aggregator_sync_after_deregister_e2e` | +| Merkle / constants / parity | `m5r_merkle_gate_e2e`, `chip_spec_compliance`, `deployer_aggregator_eve_hash_parity_e2e`, `puzzle_constants` | +| Broader harness | `integration`, `live_orchestration_e2e`, `actor_functions_e2e`, `ballot_reader_e2e`, `find_current_singleton_propagation_lag_e2e` | **Bytecode fixtures:** After `build.sh` / `build.ps1`, compiled CLVM lives under [`puzzles/compiled/`](https://github.com/DIG-Network/chia-parallel-voting/tree/main/puzzles/compiled) and is loaded via [`sdk/src/puzzles.rs`](https://github.com/DIG-Network/chia-parallel-voting/blob/main/sdk/src/puzzles.rs). Groth16 proofs in tests are generated by the reference prover ([`sdk/src/prover/`](https://github.com/DIG-Network/chia-parallel-voting/tree/main/sdk/src/prover)), not from pinned hex blobs in this document set. @@ -132,19 +129,17 @@ Interoperability is exercised by the open-source reference implementation ([DIG- Normative bytecode and the Groth16 circuit live in **[chia-parallel-voting](https://github.com/DIG-Network/chia-parallel-voting)** (`main`): - -| Layer | Location | -| ------------------------------------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| Rue → CLVM puzzles | [puzzles/](https://github.com/DIG-Network/chia-parallel-voting/tree/main/puzzles); build [puzzles/compiled/](https://github.com/DIG-Network/chia-parallel-voting/tree/main/puzzles/compiled) via [build.sh](https://github.com/DIG-Network/chia-parallel-voting/blob/main/build.sh) / [build.ps1](https://github.com/DIG-Network/chia-parallel-voting/blob/main/build.ps1) | -| Puzzle hashes / hex loader | [sdk/src/puzzles.rs](https://github.com/DIG-Network/chia-parallel-voting/blob/main/sdk/src/puzzles.rs) | -| Actors (deployer, voter, aggregator, ballot, ceremony) | [sdk/src/actors/](https://github.com/DIG-Network/chia-parallel-voting/tree/main/sdk/src/actors) | -| Groth16 circuit + prover | [sdk/src/prover/circuit.rs](https://github.com/DIG-Network/chia-parallel-voting/blob/main/sdk/src/prover/circuit.rs), [sdk/src/prover/proof.rs](https://github.com/DIG-Network/chia-parallel-voting/blob/main/sdk/src/prover/proof.rs) | -| Merkle / witness helpers | [sdk/src/merkle.rs](https://github.com/DIG-Network/chia-parallel-voting/blob/main/sdk/src/merkle.rs) | -| CLI | [cli/](https://github.com/DIG-Network/chia-parallel-voting/tree/main/cli); binary `chip-voting`. **Live-chain:** `chip-voting-live-test` (see row below). | +| Layer | Location | +| ------------------------------------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| Rue → CLVM puzzles | [puzzles/](https://github.com/DIG-Network/chia-parallel-voting/tree/main/puzzles); build [puzzles/compiled/](https://github.com/DIG-Network/chia-parallel-voting/tree/main/puzzles/compiled) via [build.sh](https://github.com/DIG-Network/chia-parallel-voting/blob/main/build.sh) / [build.ps1](https://github.com/DIG-Network/chia-parallel-voting/blob/main/build.ps1) | +| Puzzle hashes / hex loader | [sdk/src/puzzles.rs](https://github.com/DIG-Network/chia-parallel-voting/blob/main/sdk/src/puzzles.rs) | +| Actors (deployer, voter, aggregator, ballot, ceremony) | [sdk/src/actors/](https://github.com/DIG-Network/chia-parallel-voting/tree/main/sdk/src/actors) | +| Groth16 circuit + prover | [sdk/src/prover/circuit.rs](https://github.com/DIG-Network/chia-parallel-voting/blob/main/sdk/src/prover/circuit.rs), [sdk/src/prover/proof.rs](https://github.com/DIG-Network/chia-parallel-voting/blob/main/sdk/src/prover/proof.rs) | +| Merkle / witness helpers | [sdk/src/merkle.rs](https://github.com/DIG-Network/chia-parallel-voting/blob/main/sdk/src/merkle.rs) | +| CLI | [cli/](https://github.com/DIG-Network/chia-parallel-voting/tree/main/cli); binary `chip-voting`. **Live-chain:** `chip-voting-live-test` (see row below). | | Live-chain integration (real network) | [cli/src/bin/live_integration_test.rs](https://github.com/DIG-Network/chia-parallel-voting/blob/main/cli/src/bin/live_integration_test.rs) (`cargo run --bin chip-voting-live-test`, full lifecycle with confirmations); [wasm/integration-tests/](https://github.com/DIG-Network/chia-parallel-voting/tree/main/wasm/integration-tests) (Node: [`live_integration.mjs`](https://github.com/DIG-Network/chia-parallel-voting/blob/main/wasm/integration-tests/live_integration.mjs) and related scripts against WASM + a live node) | -| WASM + browser UI | [wasm/](https://github.com/DIG-Network/chia-parallel-voting/tree/main/wasm), [app/](https://github.com/DIG-Network/chia-parallel-voting/tree/main/app) | -| Integration / E2E tests (simulator, in-repo) | [sdk/tests/](https://github.com/DIG-Network/chia-parallel-voting/tree/main/sdk/tests) | - +| WASM + browser UI | [wasm/](https://github.com/DIG-Network/chia-parallel-voting/tree/main/wasm), [app/](https://github.com/DIG-Network/chia-parallel-voting/tree/main/app) | +| Integration / E2E tests (simulator, in-repo) | [sdk/tests/](https://github.com/DIG-Network/chia-parallel-voting/tree/main/sdk/tests) | Workspace: [Cargo.toml](https://github.com/DIG-Network/chia-parallel-voting/blob/main/Cargo.toml). Overview: [README.md](https://github.com/DIG-Network/chia-parallel-voting/blob/main/README.md). @@ -160,7 +155,6 @@ For a correctly deployed election, when the **configured quorum** (rational thre ### Trust boundaries and assumptions - | Boundary | Assumption | | -------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | **Chia base layer** | Validators execute CLVM correctly; block timestamps and inclusion rules behave as in Chia consensus. Standard mempool fees apply. | @@ -170,7 +164,6 @@ For a correctly deployed election, when the **configured quorum** (rational thre | **Off-chain aggregator** | **Anyone** may assemble and submit a **`finalize`** bundle. Safety does not rely on the aggregator being honest; an honest aggregator is a **liveness / UX** convenience. A malicious aggregator cannot forge a passing **`finalize`** without breaking Groth16 or BLS assumptions above. | | **Deploy-time parameters** | **`VOTE_THRESHOLD_NUM` / `DEN`**, **`MAX_SIGNERS`**, **`vote_mode_lock`**, CAT policy, and ceremony caps are chosen by deployers; buggy or adversarial **configuration** (e.g. threshold ≥ 1, wrong VK) is **out of scope** for puzzle soundness. | - ### Threats and mitigations (selected) - **Forged finalization**: Mitigated by on-chain Groth16 + aggregate **BLS** verification and scalar re-derivation in **`finalize`** (see [chip-groth16-clvm.md](./chip-groth16-clvm.md)). @@ -195,4 +188,4 @@ Implementations rely on [CHIP-0011](https://github.com/Chia-Network/chips/blob/m ## Copyright -Copyright and related rights waived via [CC0](https://creativecommons.org/publicdomain/zero/1.0/). \ No newline at end of file +Copyright and related rights waived via [CC0](https://creativecommons.org/publicdomain/zero/1.0/). diff --git a/assets/chip-scaled-parallel-voting/README.md b/assets/chip-0058/README.md similarity index 56% rename from assets/chip-scaled-parallel-voting/README.md rename to assets/chip-0058/README.md index 5c6b7d15..36cc372c 100644 --- a/assets/chip-scaled-parallel-voting/README.md +++ b/assets/chip-0058/README.md @@ -1,6 +1,6 @@ # Parallel voting CHIP: companion documents -**Purpose:** These Markdown files accompany **[chip-scaled-parallel-voting.md](../../CHIPs/chip-scaled-parallel-voting.md)** in `CHIPs/`. They live here under **`assets/chip-scaled-parallel-voting/`** with the pedagogical PNG figures (`figure_1.png`, `figure_2.png`) so everything ships as one CHIP asset bundle. +**Purpose:** These Markdown files accompany **[chip-0058.md](../../CHIPs/chip-0058.md)** in `CHIPs/`. They live here under **`assets/chip-0058/`** with the pedagogical PNG figures (`figure_1.png`, `figure_2.png`) so everything ships as one CHIP asset bundle. **Reference implementation (executable spec):** [DIG-Network/chia-scaled-parallel-voting](https://github.com/DIG-Network/chia-scaled-parallel-voting), branch `main` (Rue puzzles, compiled CLVM, SDK, CLI, WASM, tests). @@ -10,11 +10,11 @@ | Document | Contents | | -------- | -------- | -| [chip-scaled-parallel-voting.md](../../CHIPs/chip-scaled-parallel-voting.md) | Main CHIP text: preamble, abstract, motivation, specification summary, reference implementation, security, copyright | +| [chip-0058.md](../../CHIPs/chip-0058.md) | Main CHIP text: preamble, abstract, motivation, specification summary, reference implementation, security, copyright | | [chip-protocol-flow.md](./chip-protocol-flow.md) | Phases 0–5 (ceremony through exit); *Implementation* pointers into the reference repo | | [chip-ceremony.md](./chip-ceremony.md) | Ceremony singleton, marker coin, voucher, inner-action table | | [chip-election-coins.md](./chip-election-coins.md) | Election, Ballot, Registration, and Voting coins; inner actions and lineage | | [chip-witnesses-encoding.md](./chip-witnesses-encoding.md) | Merkle rules, vote modes, `vote_message`, eight public inputs, announcements | | [chip-groth16-clvm.md](./chip-groth16-clvm.md) | Groth16 + CLVM finalize path, soundness intuition, **informative** BLS12-377 note, figures | -**Tests and vectors:** see **Test plan** in [chip-scaled-parallel-voting.md](../../CHIPs/chip-scaled-parallel-voting.md) and [`sdk/tests/`](https://github.com/DIG-Network/chia-scaled-parallel-voting/tree/main/sdk/tests) in the reference implementation. +**Tests and vectors:** see **Test plan** in [chip-0058.md](../../CHIPs/chip-0058.md) and [`sdk/tests/`](https://github.com/DIG-Network/chia-scaled-parallel-voting/tree/main/sdk/tests) in the reference implementation. diff --git a/assets/chip-scaled-parallel-voting/chip-ceremony.md b/assets/chip-0058/chip-ceremony.md similarity index 96% rename from assets/chip-scaled-parallel-voting/chip-ceremony.md rename to assets/chip-0058/chip-ceremony.md index f6f19b97..8ffcd928 100644 --- a/assets/chip-scaled-parallel-voting/chip-ceremony.md +++ b/assets/chip-0058/chip-ceremony.md @@ -1,6 +1,6 @@ # Ceremony layer (companion to CHIP draft) -**What this doc is:** the **Ceremony Singleton** and its helper coins (marker, voucher): state, deploy fields, and what **`contribute`** / **`finalize`** actually require. High-level flow is [chip-protocol-flow.md](./chip-protocol-flow.md) Phase 0; election binding is summarized in [chip-scaled-parallel-voting.md](../../CHIPs/chip-scaled-parallel-voting.md) (Specification). +**What this doc is:** the **Ceremony Singleton** and its helper coins (marker, voucher): state, deploy fields, and what **`contribute`** / **`finalize`** actually require. High-level flow is [chip-protocol-flow.md](./chip-protocol-flow.md) Phase 0; election binding is summarized in [chip-0058.md](../../CHIPs/chip-0058.md) (Specification). **Code:** [DIG-Network/chia-scaled-parallel-voting](https://github.com/DIG-Network/chia-scaled-parallel-voting) on `main`. diff --git a/assets/chip-scaled-parallel-voting/chip-election-coins.md b/assets/chip-0058/chip-election-coins.md similarity index 100% rename from assets/chip-scaled-parallel-voting/chip-election-coins.md rename to assets/chip-0058/chip-election-coins.md diff --git a/assets/chip-scaled-parallel-voting/chip-groth16-clvm.md b/assets/chip-0058/chip-groth16-clvm.md similarity index 97% rename from assets/chip-scaled-parallel-voting/chip-groth16-clvm.md rename to assets/chip-0058/chip-groth16-clvm.md index 25815ab9..5b6add10 100644 --- a/assets/chip-scaled-parallel-voting/chip-groth16-clvm.md +++ b/assets/chip-0058/chip-groth16-clvm.md @@ -1,8 +1,8 @@ # Groth16, CLVM, and ballot finalization (companion to CHIP draft) -**What this doc is:** how **Ballot Coin `finalize`** checks a Groth16 proof plus aggregate **BLS** in CLVM ([CHIP-0011](https://github.com/Chia-Network/chips/blob/main/CHIPs/chip-0011.md)), **why** that combination is sound, and **informative** context on prover cost and a possible **BLS12-377** future. **Threshold intuition:** PNG figures below (`figure_1.png`, `figure_2.png`) sit in this same `assets/chip-scaled-parallel-voting/` folder (mirrored in the reference repo’s [`assets/`](https://github.com/DIG-Network/chia-scaled-parallel-voting/tree/main/assets)); they are **not** literal CRS diagrams. +**What this doc is:** how **Ballot Coin `finalize`** checks a Groth16 proof plus aggregate **BLS** in CLVM ([CHIP-0011](https://github.com/Chia-Network/chips/blob/main/CHIPs/chip-0011.md)), **why** that combination is sound, and **informative** context on prover cost and a possible **BLS12-377** future. **Threshold intuition:** PNG figures below (`figure_1.png`, `figure_2.png`) sit in this same `assets/chip-0058/` folder (mirrored in the reference repo’s [`assets/`](https://github.com/DIG-Network/chia-scaled-parallel-voting/tree/main/assets)); they are **not** literal CRS diagrams. -**Code:** [DIG-Network/chia-scaled-parallel-voting](https://github.com/DIG-Network/chia-scaled-parallel-voting) on `main`. **Public-input order and Merkle rules:** [chip-witnesses-encoding.md](./chip-witnesses-encoding.md). **Spec overview:** [chip-scaled-parallel-voting.md](../../CHIPs/chip-scaled-parallel-voting.md). +**Code:** [DIG-Network/chia-scaled-parallel-voting](https://github.com/DIG-Network/chia-scaled-parallel-voting) on `main`. **Public-input order and Merkle rules:** [chip-witnesses-encoding.md](./chip-witnesses-encoding.md). **Spec overview:** [chip-0058.md](../../CHIPs/chip-0058.md). --- diff --git a/assets/chip-scaled-parallel-voting/chip-protocol-flow.md b/assets/chip-0058/chip-protocol-flow.md similarity index 96% rename from assets/chip-scaled-parallel-voting/chip-protocol-flow.md rename to assets/chip-0058/chip-protocol-flow.md index 26110c69..0ba389e4 100644 --- a/assets/chip-scaled-parallel-voting/chip-protocol-flow.md +++ b/assets/chip-0058/chip-protocol-flow.md @@ -1,6 +1,6 @@ # Protocol flow (companion to CHIP draft) -**What this doc is:** the **end-to-end story** in order: ceremony, deploy, register, vote, finalize, exit. [chip-scaled-parallel-voting.md](../../CHIPs/chip-scaled-parallel-voting.md) stays the spec summary; here you get **which lane each spend lives in** and **where to read code** in [**chia-scaled-parallel-voting**](https://github.com/DIG-Network/chia-scaled-parallel-voting) on `main`. +**What this doc is:** the **end-to-end story** in order: ceremony, deploy, register, vote, finalize, exit. [chip-0058.md](../../CHIPs/chip-0058.md) stays the spec summary; here you get **which lane each spend lives in** and **where to read code** in [**chia-scaled-parallel-voting**](https://github.com/DIG-Network/chia-scaled-parallel-voting) on `main`. **Related:** deeper tables live in [chip-ceremony.md](./chip-ceremony.md), [chip-election-coins.md](./chip-election-coins.md), [chip-witnesses-encoding.md](./chip-witnesses-encoding.md), [chip-groth16-clvm.md](./chip-groth16-clvm.md). diff --git a/assets/chip-scaled-parallel-voting/chip-witnesses-encoding.md b/assets/chip-0058/chip-witnesses-encoding.md similarity index 96% rename from assets/chip-scaled-parallel-voting/chip-witnesses-encoding.md rename to assets/chip-0058/chip-witnesses-encoding.md index 78ba9926..20a5d5a9 100644 --- a/assets/chip-scaled-parallel-voting/chip-witnesses-encoding.md +++ b/assets/chip-0058/chip-witnesses-encoding.md @@ -1,6 +1,6 @@ # Witnesses, Merkle trees, vote modes, and encodings (companion to CHIP draft) -**What this doc is:** the **bytes and hashes** everything agrees on: registration SPT, per-ballot trees, `vote_message`, the **eight** public inputs in order, and announcement strings. Overview stays in [chip-scaled-parallel-voting.md](../../CHIPs/chip-scaled-parallel-voting.md) § Specification. **Groth16 vs CLVM (and why proving can hurt):** [chip-groth16-clvm.md](./chip-groth16-clvm.md). +**What this doc is:** the **bytes and hashes** everything agrees on: registration SPT, per-ballot trees, `vote_message`, the **eight** public inputs in order, and announcement strings. Overview stays in [chip-0058.md](../../CHIPs/chip-0058.md) § Specification. **Groth16 vs CLVM (and why proving can hurt):** [chip-groth16-clvm.md](./chip-groth16-clvm.md). **Code:** [DIG-Network/chia-scaled-parallel-voting](https://github.com/DIG-Network/chia-scaled-parallel-voting) on `main`. diff --git a/assets/chip-scaled-parallel-voting/figure_1.png b/assets/chip-0058/figure_1.png similarity index 100% rename from assets/chip-scaled-parallel-voting/figure_1.png rename to assets/chip-0058/figure_1.png diff --git a/assets/chip-scaled-parallel-voting/figure_2.png b/assets/chip-0058/figure_2.png similarity index 100% rename from assets/chip-scaled-parallel-voting/figure_2.png rename to assets/chip-0058/figure_2.png From bee04f111bd9f559d659f5b4bab171b5597e3fd6 Mon Sep 17 00:00:00 2001 From: danieljperry Date: Fri, 5 Jun 2026 09:39:00 +0800 Subject: [PATCH 3/3] Move CHIP-58 to Review status --- CHIPs/chip-0058.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHIPs/chip-0058.md b/CHIPs/chip-0058.md index 0013c3ab..9247eee1 100644 --- a/CHIPs/chip-0058.md +++ b/CHIPs/chip-0058.md @@ -5,7 +5,7 @@ | Author | Michael Taylor (on behalf of [DIG Network](https://github.com/DIG-Network)) | | Editor | [Dan Perry](https://github.com/danieljperry) | | Comments-URI | [CHIPs repo, PR #202](https://github.com/Chia-Network/chips/pull/202) | -| Status | Draft | +| Status | Review | | Category | Standards Track | | Sub-Category | Primitive | | Created | 2026-05-04 |