Rust workspace with 5 crates (mesh-types, mesh-crypto, mesh-network, mesh-validator, mesh-wallet), PROJECT_CONSTITUTION.md for CHORUS automated ingestion, and the full MESH protocol specification suite. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
20 KiB
Project: MESH
Repository: https://gitea.reset.org/tony/mesh (TBC) Language: Rust (edition 2024, toolchain 1.85.0) License: Apache 2.0 Created: 2026-03-23 Status: Constitution Phase
Overview
MESH (Minimal-Exchange Settlement Hypergraph) is a decentralised payment protocol that settles retail transactions in under 300ms using Byzantine Consistent Broadcast — without a blockchain, without a native token, and with confidential amounts via Pedersen commitments and Bulletproofs+ range proofs. This constitution covers the Tier 1 MVP: a 4-validator local testnet with a CLI wallet that can send and receive confidential payments.
Constraints
- Single model: All agents run the same LLM backend. No role-to-model mapping is available.
- MVP scope only: Tier 1 (consensusless settlement) only. No Tier 2 DAG-BFT, no Tier 3 aBFT, no multi-currency routing, no connectors, no stealth addresses. These are specified but deferred.
- No external network: Agents work against a local Gitea repo. No public APIs, no npm/PyPI fetches during agent sessions.
- Deterministic serialisation: No serde. All encode/decode is hand-written per SPEC-002 §2.8. This is a hard constraint from the spec — agents must not introduce serde-based serialisation.
- Constant-time crypto: All secret-dependent operations must use constant-time implementations. Agents must use the dalek crate family, not roll their own.
- Pinned dependencies: Exact crate versions are specified in the Dev Environment Specification. Agents must not upgrade or substitute crates without a gate approval.
Councils
Council: types
Scope: Core data structures and deterministic binary serialisation (SPEC-002) Agents: 2 builders, 1 reviewer File area: crates/mesh-types/** Depends on: none Spec refs: SPEC-002 §2.2–2.8 (primitive types, AccountState, Transition, Recipient, SettlementCertificate, ValidatorVote, EquivocationProof, Value Semiring, serialisation rules)
Task: Define primitive types and enums
Implement all primitive types from SPEC-002 §2.2: u8, u32, u64, u128, Hash (32-byte SHA3-256 output), PublicKey (32-byte Ed25519), Signature (64-byte Ed25519), Commitment (32-byte compressed Edwards point), AssetID (32-byte hash). Define enums: TransitionType (Send, Receive, Exchange, OnRamp, OffRamp), NodeType (Validator, Client, Connector). File area: crates/mesh-types/src/primitives.rs
- All types defined with correct byte sizes
AssetIDcomputed asSHA3-256(asset_name || issuer_pubkey || precision)- No floating-point types anywhere in the crate
Task: Implement AccountState and Transition structures
Define AccountState (owner, sequence, balances map, state_hash,
last_cert, created_at) and Transition (version, type, sender,
sequence, recipients, asset_id, amount, range_proof, fee, fee_proof,
causal_deps, expiry, memo, signature) per SPEC-002 §2.3–2.4.
File area: crates/mesh-types/src/structures.rs
AccountStatestruct withMap<AssetID, Commitment>for balancesTransitionstruct with all 14 fields from SPEC-002 §2.4.1Recipientstruct (address, amount commitment, range_proof)SettlementCertificatestruct (transition_hash, epoch, votes)ValidatorVotestruct (validator_id, signature)EquivocationProofstruct (two conflicting transitions + votes)
Task: Deterministic binary serialisation
Hand-write encode/decode functions for every type. Rules per SPEC-002 §2.8: little-endian integers, length-prefixed Vec, presence-flag optionals, declaration-order struct fields, sorted-key maps. No serde. File area: crates/mesh-types/src/codec.rs
encode()anddecode()for every struct- Round-trip property tests (encode then decode = identity) for every type
- Canonical form: identical data always produces identical bytes
- Malformed input returns errors, never panics
Task: Value Semiring implementation
Implement the Value Semiring from SPEC-002 §2.7: aggregation (⊕) for same-asset addition, exchange (⊗) for currency conversion with floor-division and remainder per Security Addendum AV-005. All arithmetic in u128, no floating point. File area: crates/mesh-types/src/value.rs
⊕aggregation for same-AssetID values⊗exchange with floor division, remainder returned to sender- Overflow checked:
ERR_OVERFLOWon u128 overflow in multiplication - ValueSet type for multi-asset aggregation
Council: crypto
Scope: Cryptographic operations — keys, signatures, commitments, range proofs (SPEC-006, SPEC-007) Agents: 2 builders, 1 reviewer File area: crates/mesh-crypto/** Depends on: types Spec refs: SPEC-006 §6.4.1 (key derivation), SPEC-007 §7.2–7.3 (Pedersen commitments, Bulletproofs+), Security Addendum AV-002 (fee range proofs), AV-007 (ephemeral key handling)
Task: Key generation and domain-separated hashing
Ed25519 key pair generation via ed25519-dalek. Derive view key per
SPEC-006 §6.4.1. Domain-separated SHA3-256 hashing (each usage context
gets a unique prefix to prevent cross-domain collisions).
File area: crates/mesh-crypto/src/keys.rs
generate_keypair()from CSPRNGderive_view_key()per SPEC-006 §6.4.1- Domain-separated hash function with context tags
- All secret keys implement
Zeroizeon drop
Task: Pedersen commitments
Implement Commit(value, blinding) = value·G + blinding·H using
curve25519-dalek Ristretto operations. Generator H from
nothing-up-my-sleeve construction per SPEC-007 §7.2. Homomorphic
verification: Σ(C_recipient_i) + C_fee = C_amount.
File area: crates/mesh-crypto/src/pedersen.rs
commit(value, blinding)returns Commitment- Generator H derived from hash-to-point (nothing-up-my-sleeve)
verify_conservation(inputs, outputs)using point arithmetic- Blinding factor addition/subtraction for balance updates
Task: Bulletproofs+ range proofs
Generate and verify range proofs for values in [0, 2^64) using dalek bulletproofs with Merlin transcripts. Proofs must bind to transaction
hash per SPEC-007 §7.3.2. Fee commitments MUST have range proofs per
Security Addendum AV-002.
File area: crates/mesh-crypto/src/rangeproof.rs
prove_range(value, blinding, transcript)returns RangeProofverify_range(commitment, proof, transcript)returns bool- Proof bound to transaction hash via Merlin transcript
- Zero-value commitments produce valid range proofs
- Negative/overflow values produce proofs that fail verification
Task: Transaction construction and validation
Build complete Transition with committed amounts and range proofs.
Implement all 9 validation rules from SPEC-002 §2.4.3 with Security
Addendum amendments (AV-002 fee range proofs, AV-003 causal dependency
relevance check).
File area: crates/mesh-crypto/src/validation.rs
build_transition()constructs a fully signed Transition- All 9 validation rules implemented in order
- Each rule returns the specified error code on failure
- AV-002: fee range proof required (including zero-fee)
- AV-003: causal deps checked for existence AND relevance
- Test vectors for each validation rule (valid + each failure mode)
Gate: Cryptographic implementation review — verify Pedersen generator derivation, Bulletproofs+ transcript binding, and constant-time properties before downstream councils consume mesh-crypto.
Council: network
Scope: QUIC transport layer, message framing, handshake protocol (SPEC-009) Agents: 2 builders, 1 reviewer File area: crates/mesh-network/** Depends on: types Spec refs: SPEC-009 §9.2–9.5, §9.8–9.9 (QUIC transport, framing, handshake, stream multiplexing, rate limiting, keepalive)
Task: QUIC server and client
QUIC transport using quinn with TLS 1.3 via rustls. Self-signed
certificates for testnet. Server accepts connections on configurable
address. Client connects with ALPN identifier "mesh/0".
File area: crates/mesh-network/src/transport.rs
- QUIC server binds and accepts connections
- QUIC client connects with ALPN "mesh/0"
- TLS 1.3 with self-signed certs (via
rcgen) - Connection errors handled gracefully (no panics)
Task: Message framing and dispatch
Length-prefixed message framing: [length: u32][type: u8][payload] per
SPEC-009 §9.4. Maximum frame size 4MB. Message type dispatch to
handlers. Implement all message type IDs from SPEC-009 §9.4.1 (MVP
subset: 0x01–0x04, 0x40–0x42, 0xF0–0xF1, 0xFF).
File area: crates/mesh-network/src/framing.rs
- Encode/decode framed messages
- Reject frames exceeding 4MB
- Dispatch by message type to handler callbacks
- Malformed frames rejected (tested with fuzzy input)
Task: Handshake protocol
MESH HandshakeMessage exchange per SPEC-009 §9.3: protocol version, cipher suites, node type, public key, epoch, signature proof of key ownership. Verify remote node's identity. File area: crates/mesh-network/src/handshake.rs
- HandshakeMessage struct with all fields from SPEC-009 §9.3.2
- Signature verification of remote node's public key
- Validator nodes checked against current epoch's validator set
- Connection closed on any handshake failure
Task: Stream multiplexing and keepalive
Dedicated QUIC streams per message category per SPEC-009 §9.5: streams 0–3 for handshake/keepalive, 4–7 for Tier 1, 20–23 for queries. PING/PONG keepalive every 30s per SPEC-009 §9.9. File area: crates/mesh-network/src/streams.rs
- Stream ID ranges assigned per SPEC-009 §9.5
- PING sent every 30s if no other traffic
- PONG response within 5s
- Connection closed after 3 missed PINGs
Council: validator
Scope: Validator node binary — state store, vote handling, equivocation detection, certificate processing (SPEC-003) Agents: 3 builders, 1 reviewer File area: crates/mesh-validator/** Depends on: types, crypto, network Spec refs: SPEC-003 §3.3 (vote/certificate protocol), SPEC-002 §2.4.3 (validation rules), Security Addendum AV-003 (causal deps), AV-004 (sharding), AV-006 (epoch boundary)
Task: Account state store
Embedded key-value store using sled for AccountState keyed by
PublicKey. CRUD operations. Certificate store keyed by transition hash.
Equivocation record store keyed by (sender, sequence).
File area: crates/mesh-validator/src/store.rs
get_account(pubkey)returns Optionput_account(pubkey, state)persists atomicallyget_certificate(hash)for causal dependency lookupsput_equivocation(sender, seq, proof)for detection records
Task: VOTE_REQUEST handler
Receive a Transition, run all 9 validation rules from SPEC-002 §2.4.3 (with Security Addendum amendments). If valid, sign a vote per SPEC-003 §3.3.1. If invalid, return VOTE_REJECT with error code. Record (sender, sequence, hash) for equivocation detection. File area: crates/mesh-validator/src/vote.rs
- All 9 validation rules applied in order
- Vote signature:
Sign(validator_key, transition_hash || epoch) - VOTE_RESPONSE sent on success, VOTE_REJECT on failure
- Equivocation lock: reject second transition for same (sender, seq)
Task: Equivocation detection and proof
Maintain map of (sender, sequence) → transition_hash. On conflict,
produce EquivocationProof containing both conflicting transitions and
their votes. Broadcast proof to all connected validators.
File area: crates/mesh-validator/src/equivocation.rs
- Detect conflicting transitions for same (sender, sequence)
- Produce EquivocationProof with both transitions
- Broadcast proof to peers
- Reject both transitions once equivocation detected
Task: SETTLEMENT_CERTIFICATE handler
Receive a certificate. Verify ≥ 2f+1 valid votes from current epoch's validator set (with one-epoch grace period per Security Addendum AV-006). Apply state transition: debit sender, credit recipients. Store certificate. File area: crates/mesh-validator/src/certificate.rs
- Verify vote count ≥ 2f+1
- Verify all vote signatures against correct epoch's validator set
- AV-006: accept current epoch and epoch-1, reject epoch-2 and future
- Apply state transition atomically (debit + credit + sequence bump)
- Store certificate in permanent record
Task: Account query handler and validator config
Respond to QUERY_ACCOUNT with current account state. TOML configuration file for validator: listen address, peer addresses, validator set (public keys), epoch number, shard assignment. File area: crates/mesh-validator/src/query.rs, crates/mesh-validator/src/config.rs
- QUERY_ACCOUNT returns current AccountState
- TOML config loaded at startup
- Validator key loaded from file (generated on first run)
Council: wallet
Scope: CLI wallet binary — key management, payment flow, balance tracking (SPEC-003 client side) Agents: 2 builders, 1 reviewer File area: crates/mesh-wallet/** Depends on: types, crypto, network Spec refs: SPEC-003 §3.3 (client-side protocol), SPEC-007 §7.2 (balance decryption via blinding factors), MVP Roadmap §Milestone 4
Task: Key management
mesh-wallet keygen generates Ed25519 key pair + derives view key.
Saves to encrypted file. mesh-wallet show-address prints public key.
Blinding factor store (sled DB keyed by transaction hash) — this is
the wallet's most sensitive data.
File area: crates/mesh-wallet/src/keys.rs
keygencommand generates and saves key pairshow-addressprints public key in hex- Blinding factors stored locally per transaction
- Secret keys zeroized on drop
Task: Send payment flow
mesh-wallet send --to <pubkey> --amount <value> --asset <id>.
Constructs a Transition with Pedersen-committed amount and Bulletproofs+
range proof. Broadcasts VOTE_REQUEST to all configured validators.
Collects 2f+1 votes. Assembles SettlementCertificate. Broadcasts
certificate. Prints certificate hash.
File area: crates/mesh-wallet/src/send.rs
- Constructs valid Transition with committed amounts
- Sends VOTE_REQUEST to all validators
- Collects 2f+1 votes (tolerates slow/failed validators)
- Assembles and broadcasts SettlementCertificate
- Stores blinding factors for sent transaction
Task: Receive and balance commands
mesh-wallet receive --cert <hash> submits a Receive transition
referencing the certificate. mesh-wallet balance queries a validator
and decrypts committed balance using stored blinding factors.
mesh-wallet history lists all settlements with certificate hashes.
File area: crates/mesh-wallet/src/receive.rs, crates/mesh-wallet/src/balance.rs
receivecommand submits Receive transition with causal depbalancecommand queries validator, decrypts locallyhistorylists sent and received settlements- Handles case where blinding factors are missing (display "encrypted")
Council: testnet
Scope: 4-validator testnet orchestration, crash recovery, end-to-end integration (MVP Roadmap §Milestone 5) Agents: 1 builder, 1 reviewer File area: config/, docker-compose.yml, Dockerfile, tests/integration/ Depends on: validator, wallet Spec refs: MVP Roadmap §Milestone 5, Dev Environment Specification §5
Task: Docker Compose testnet
docker-compose.yml starting 4 validators on a bridge network. Per-validator TOML config. Shared volume for validator key distribution. Genesis validator credits initial test accounts. File area: docker-compose.yml, Dockerfile, config/**
docker compose upstarts 4 validators- Each validator has unique config (listen addr, peers, keys)
- Genesis mechanism credits initial accounts with test tokens
docker compose down -vcleanly wipes all state
Task: End-to-end integration test
Automated test: Alice creates account, receives genesis credit, sends
500 tokens to Bob, Bob receives, both check balances. Confidential
amounts throughout — validators never see plaintext. Run as cargo test
in the workspace root.
File area: tests/integration/**
- Alice→Bob send/receive completes successfully
- Balances correct after transfer (Alice: 9500, Bob: 500)
- All amounts are Pedersen-committed (no plaintext in validator logs)
- Test passes against 4-validator docker testnet
Task: Crash recovery test
Kill one validator. Verify system continues (3/4 = 2f+1). Restart killed validator. It catches up by requesting missed certificates. All 4 validators converge to identical state. File area: tests/integration/**
- Transactions succeed with 3/4 validators
- Restarted validator syncs missed certificates
- All 4 validators have identical account state after sync
Council: infra
Scope: Project scaffolding, CI pipeline, build configuration, benchmarks (MVP Roadmap §Milestone 0, §Milestone 6) Agents: 1 builder, 1 reviewer File area: Cargo.toml, .cargo/, .github/, rust-toolchain.toml, benches/**, deny.toml Depends on: none Spec refs: Dev Environment Specification §2.3–2.4 (Rust toolchain, cargo config), §6 (CI pipeline), §7 (crate dependencies)
Task: Workspace scaffolding
Cargo workspace with crates: mesh-types, mesh-crypto, mesh-network, mesh-validator, mesh-wallet. Root Cargo.toml. rust-toolchain.toml pinned to 1.85.0. .cargo/config.toml with mold linker. deny.toml for license compliance (Apache 2.0 compatible only, no GPL). File area: Cargo.toml, .cargo/config.toml, rust-toolchain.toml, deny.toml
cargo buildsucceeds on empty workspace- Rust 1.85.0 pinned via rust-toolchain.toml
- mold linker configured in .cargo/config.toml
cargo deny check licensespasses
Task: CI pipeline
GitHub Actions workflow: format check (rustfmt), lint (clippy -D warnings), build all targets, test all targets, audit dependencies (cargo-audit), license compliance (cargo-deny). Runs on push and PR. File area: .github/workflows/ci.yml
- CI runs on every push and PR
- rustfmt, clippy, build, test, audit, deny all pass
- Uses
rust:1.85.0-bookwormcontainer image - Cargo registry cached across runs
Task: Benchmarks
Criterion benchmarks for: Bulletproofs+ prove/verify time, Ed25519 sign/verify, Pedersen commit, serialisation round-trips, end-to-end Tier 1 latency. File area: benches/**
cargo benchruns all benchmarks- Range proof generation and verification benchmarked
- Signature operations benchmarked
- Results written to stdout in criterion format
Cross-Cutting Concerns
Coding standards:
cargo fmt --allenforced. Unformatted code is rejected by CI.cargo clippy -- -D warningsenforced. All warnings are errors.- No
unsafecode without a// SAFETY:comment explaining why. - No
unwrap()orexpect()in library code. UseResulttypes. - All public functions have doc comments.
Error handling:
- Every validation failure returns the specific error code from SPEC-002 §2.4.3 (ERR_UNSUPPORTED_VERSION, ERR_INVALID_SIGNATURE, etc.).
- Network errors are logged and retried with backoff, never panicked.
Security:
- All secret key material uses
zeroizecrate for secure erasure. - Constant-time operations for all secret-dependent code paths (use
subtlecrate for comparisons where needed). - No logging of secret keys, blinding factors, or plaintext amounts.
- Security Addendum amendments (AV-001 through AV-007) are mandatory for all relevant code paths.
Testing:
- Property-based tests via
proptestfor serialisation round-trips. - Every validation rule has a positive test and a negative test.
- Integration tests run against the 4-validator docker testnet.
Acceptance Criteria
The coordinator evaluates these as exit triggers via
ov coordinator check-complete:
- All 5 crates compile with zero warnings (
cargo clippy -- -D warnings) - All unit tests pass (
cargo test --all-targets) - Serialisation round-trip property tests pass for every type
- Cryptographic test vectors pass (key gen, sign/verify, commit, range proof)
- 4-validator testnet starts via
docker compose up - End-to-end confidential payment: Alice sends 500 tokens to Bob through 4 validators, both balances correct
- Crash recovery: kill 1 validator, transact, restart, state converges
- Benchmarks run and produce results (range proof < 500ms, verify < 10ms target)
cargo auditreports no known vulnerabilitiescargo deny check licensespasses (Apache 2.0 compatible only)