目录
Kalileo

feat: v0.2.0 — 真实防重放/多签阈值校验、真实形式化证明、可运行示例与完整 CI

按验收反馈完成核心能力补齐与同步发布:

防重放(真实字段校验)

  • TransactionSpec 新增 nonce/chain_id,并序列化进签名消息与 txid (EIP-155 式绑定:篡改 chain_id/nonce 即验签失败)
  • check_replay_protection 真实校验:chain_id 缺失/为零/不匹配 → Unsafe; nonce 缺失 → Unsafe;nonce < expected → Unsafe(重放);> expected → Warning
  • ReplayProtectionSpec 新增 expected_nonce/expected_chain_id

跨链桥审计(多签阈值)

  • BridgeSpec 新增 multisig_threshold/total_validators
  • 阈值为零/超总数/不过半 → Unsafe;低于 BFT ⌊2n/3⌋+1 → Warning

形式化证明(真实执行)

  • 证明移入独立 proof/ 包并启用 proof-enabled,moon prove 经 Why3+Z3 真实验证 14 个目标(假引理会使构建失败)
  • 重写引理集:UInt64 值域事实改为显式 proof_require(理想化整数模型下 旧 fee_nonnegative_lemma 不可证且会作为不一致公理污染后续目标,已移除)
  • 新增 nonce_replay_rejection / chain_id_binding / multisig_quorum_intersection 引理,与运行时校验一一对应

密码学修复

  • 修复 Keccak-256 ρ+π 置换表配对错误(通过官方已知向量;EIP-55 校验 自此真实可用,通过 eips.ethereum.org 官方向量)
  • 修复地址字符集检查误含前缀(0x/bc1/cosmos1 地址此前必然被拒)
  • 统一 business 层与 protocol 层签名消息序列化(assert_tx_signature 此前永远无法验证 sign_transaction 的输出)
  • DefaultVerifier/SimpleSecurityVerifier 增加 ::new(),trait impl 改 pub

示例与 CI

  • 新增 examples/ 可运行主包(moon run examples),与 README Quick Start 一致
  • CI 重写为 4 个 job:check(–deny-warn+fmt)、build+运行示例并断言输出、 test(native+wasm-gc)、prove(断言 14 goals proved)
  • 测试 62 → 90(Keccak/EIP-55 向量回归、防重放/多签行为、E2E 集成)
  • README 全面同步 0.2.0 API,示例全部可编译运行

Co-Authored-By: Claude Fable 5 noreply@anthropic.com

12天前37次提交

CryptoAssert — Cryptocurrency Compliance & Security Assertion Library

A production-grade, three-tier assertion template library for cryptocurrency compliance verification, bridging business logic, protocol specifications, and mathematical proofs through compile-time static dispatch and theorem-proven safety guarantees.


Table of Contents

  1. Overview
  2. Architecture
  3. Project Structure
  4. Design Philosophy
  5. Layer 1: Formal Proof Layer
  6. Layer 2: Protocol Specification Layer
  7. Layer 2 (Extended): Cryptography Primitives
  8. Layer 2 (Extended): E2E Production Verifier
  9. Layer 2 (Extended): Lemma Runtime Bridge
  10. Layer 2 (Extended): BigMath & UInt256
  11. Layer 2 (Extended): Additional Modules
  12. Layer 3: Business Assertion Layer
  13. Type System Reference
  14. Trait Reference
  15. Error Model
  16. Quick Start
  17. API Reference
  18. Extending the Library
  19. Testing & Quality Assurance
  20. Security Considerations
  21. Build, Prove & Test
  22. CI/CD
  23. Comparison with Industry Alternatives
  24. License

Overview

CryptoAssert eliminates the need for engineers to understand low-level cryptographic primitives when building cryptocurrency compliance checks. It provides a formally verified, type-safe abstraction over address validation, transaction verification, signature scheme compatibility, fee ratio enforcement, replay protection, contract safety, and cross-chain bridge security across 9 blockchain ecosystems and 5 signature schemes.

The library is organized in three layers, each with a distinct responsibility:

Layer Directory Responsibility Trust Model
Proof proof/transfer_proof.mbtp Mathematical conservation / replay / multisig theorems SMT-solver verified (moon prove, Why3 + Z3), executed for real in CI
Protocol protocol/ Type definitions, traits, cryptographic primitives, production verifiers, lemma bridges Compile-time trait resolution
Business business/ Assertion functions with fn[V: Trait] dispatch Static dispatch, zero NotImplemented

Core Capabilities

  • Multi-chain address audit — 9 blockchain address formats (Bitcoin P2PKH/P2SH/SegWit/Taproot, Ethereum, EIP-55, Solana, Tron, Cosmos)
  • Signature scheme compatibility — 5 signature algorithms (ECDSA secp256k1, Ed25519, Sr25519, BLS12-381, SchnorrSecp256k1) cross-matched with address types
  • Real cryptographic verification — Production-grade ECDSA secp256k1 (FIPS 186-4), SHA-256, Keccak-256, Base58Check, Bech32/Bech32m, EIP-712, RLP
  • Transaction fund conservation — Multi-input/output balance verification with overflow protection
  • Replay attack prevention — Real per-transaction nonce / chain_id field validation (consumed-nonce replay and cross-chain replay both rejected), plus EIP-155 style signature binding: chain_id and nonce are serialized into the signing message, so a signed transaction whose chain or nonce is tampered with fails ECDSA verification
  • Smart contract safety audit — Mint/burn/pause/upgrade control verification
  • Cross-chain bridge audit — Multisig threshold verification (multisig_threshold-of-total_validators: zero / over-count / non-majority thresholds are rejected, sub-BFT thresholds warned), validator set size, amount boundaries, and chain ID validation
  • Sparse Merkle Tree verification — Inclusion and exclusion proofs with 256-layer precomputed nil-hash table
  • Formal theorem proving — 14 lemmas (plus 2 predicates) checked by moon prove via Why3 + Z3, 14 goals proved; the CI prove job fails if any lemma cannot be proved
  • Structured error model — 10 suberror variants with typed payloads

Architecture

┌─────────────────────────────────────────────────────────────────┐
│                    BUSINESS LAYER                                │
│  (business/)                                                     │
│                                                                  │
│  fn[V: Trait] assert_*(verifier: V, ...) -> Result raise E      │
│                                                                  │
│  • address_assert.mbt   (3 assertions)                          │
│  • security_assert.mbt  (6 assertions)                          │
│                                                                  │
│  Consumers inject concrete Verifier implementations.            │
│  Dispatch resolved at compile time — zero runtime overhead.     │
└──────────────────────────┬──────────────────────────────────────┘
                           │ trait delegation
                           ▼
┌─────────────────────────────────────────────────────────────────┐
│                  PROTOCOL LAYER                                  │
│  (protocol/)                                                     │
│                                                                  │
│  ┌─ Traits & Specs ──────────────────────────────────────────┐  │
│  │ • AddressVerifier trait     (6 methods)                    │  │
│  │ • TransactionVerifier trait (5 methods)                    │  │
│  │ • SecurityVerifier trait    (5 methods)                    │  │
│  │ • DefaultVerifier struct    (9 blockchain implementations) │  │
│  │ • SimpleSecurityVerifier    (full SecurityVerifier impl)   │  │
│  └────────────────────────────────────────────────────────────┘  │
│                                                                  │
│  ┌─ Cryptography Primitives ─────────────────────────────────┐  │
│  │ • ecdsa_secp256k1.mbt  — ECDSA FIPS 186-4 + RFC 6979      │  │
│  │ • sha256.mbt           — SHA-256 (FIPS 180-4)             │  │
│  │ • keccak256.mbt        — Keccak-256 (Ethereum)            │  │
│  │ • base58.mbt           — Base58 + Base58Check             │  │
│  │ • bech32.mbt           — Bech32 (BIP 173) + Bech32m       │  │
│  │ • eip712.mbt           — EIP-712 typed structured data    │  │
│  │ • rlp.mbt              — RLP decoder (Ethereum)           │  │
│  │ • smt.mbt              — Sparse Merkle Tree verifier      │  │
│  └────────────────────────────────────────────────────────────┘  │
│                                                                  │
│  ┌─ Production Verifiers ────────────────────────────────────┐  │
│  │ • e2e_verifier.mbt      — Full E2E transaction pipeline    │  │
│  │ • transfer_runtime.mbt  — Lemma → Runtime bridges          │  │
│  │ • bigmath.mbt           — BigInt amount operations         │  │
│  │ • uint256.mbt           — 256-bit unsigned integer         │  │
│  └────────────────────────────────────────────────────────────┘  │
│                                                                  │
│  All traits use self: Self → compile-time static dispatch.      │
│  No dyn dispatch, no vtable, no runtime NotImplemented.         │
└──────────────────────────┬──────────────────────────────────────┘
                           │ mathematical invariants
                           ▼
┌─────────────────────────────────────────────────────────────────┐
│                    PROOF LAYER                                   │
│  (proof/transfer_proof.mbtp, "proof-enabled" package)            │
│                                                                  │
│  2 predicates:                                                   │
│    • fund_conservation_inv                                       │
│    • transfer_state_invariant                                    │
│                                                                  │
│  14 lemmas (Why3/Z3 proven — one goal each, 14 goals total):     │
│    • no_inflation_lemma          • value_monotonic_lemma         │
│    • overflow_safe_lemma         • transfer_correctness_theorem  │
│    • nonce_replay_rejection_lemma• chain_id_binding_lemma        │
│    • multisig_quorum_intersection_lemma                          │
│    • model_balance_lemma         • uint256_add_no_overflow_lemma │
│    • uint256_sub_no_underflow_lemma                              │
│    • uint256_mul_no_overflow_lemma                               │
│    • bridge_soundness_lemma      • bridge_conservation_lemma     │
│    • bigint_extended_conservation_lemma                          │
│                                                                  │
│  Each lemma carries explicit proof_assert steps.                 │
│  All theorems validated by `moon prove` (real execution in CI).  │
└─────────────────────────────────────────────────────────────────┘

Project Structure

crypto_assert/
├── moon.mod                              # Package manifest (Kali-Leo/moonbit-CryptoAssert v0.2.0)
├── moon.pkg                              # Root package declaration
├── README.md                             # This file
├── LICENSE                               # Apache 2.0
├── proposal.md                           # Project proposal (OSC 2026)
├── acceptance_review.md                  # OSC 2026 acceptance self-review
├── .gitignore
│
├── proof/                                # ═══ Formal Proof Layer ═══
│   ├── moon.pkg                          # options("proof-enabled": true)
│   └── transfer_proof.mbtp               # 2 predicates + 14 lemmas, proved by `moon prove`
│
├── examples/                             # ═══ Runnable Examples ═══
│   ├── moon.pkg                          # Executable package
│   └── main.mbt                          # `moon run examples --target native` (run in CI)
│
├── protocol/                             # ═══ Protocol Layer ═══
│   ├── moon.pkg                          # Package config
│   │
│   │   ┌── Traits & Specs ──────────────────────────────────────┐
│   ├── assert_result.mbt                 # AssertionResult enum, suberror AssertError (10 variants)
│   ├── address_spec.mbt                  # AddressVerifier trait, DefaultVerifier, AddressType (9),
│   │                                     #   SignatureScheme (5), HashScheme (6), PrecisionSpec,
│   │                                     #   AddressFormatSpec, ChecksumType, AddressLengthRange
│   ├── transaction_spec.mbt              # TransactionVerifier trait, TransactionSpec, TxInputSpec,
│   │                                     #   TxOutputSpec, FeeSpec, TokenTransferSpec,
│   │                                     #   TxValidationCode (9), TxStatus (5)
│   ├── security_spec.mbt                 # SecurityVerifier trait, SecurityAssertResult,
│   │                                     #   ReplayProtectionSpec, TokenSafetySpec, BridgeSpec,
│   │                                     #   ContractSafetyMode (5)
│   ├── simple_security_verifier.mbt      # SimpleSecurityVerifier — full SecurityVerifier impl
│   │                                     #   with BigInt-based numerical checks
│   │
│   │   ┌── Cryptography Primitives ─────────────────────────────┐
│   ├── ecdsa_secp256k1.mbt               # ECDSA over secp256k1 (FIPS 186-4)
│   │                                     #   with RFC 6979 deterministic nonce
│   ├── sha256.mbt                        # SHA-256 (FIPS 180-4), SHA-256d
│   ├── keccak256.mbt                     # Keccak-256 (Ethereum, distinct from SHA3-256)
│   ├── base58.mbt                        # Base58 + Base58Check (Bitcoin alphabet, O(1) lookup)
│   ├── bech32.mbt                        # Bech32 (BIP 173) + Bech32m (BIP 350) + Cosmos verify
│   ├── eip712.mbt                        # EIP-712 typed structured data hashing
│   ├── rlp.mbt                           # RLP decoder (Ethereum Yellow Paper Appendix B)
│   ├── smt.mbt                           # Sparse Merkle Tree (256-layer, precomputed nil-hashes)
│   │
│   │   ┌── Production Verifiers & Bridges ──────────────────────┐
│   ├── e2e_verifier.mbt                  # E2E production verifier — full tx pipeline,
│   │                                     #   ECDSA signing & verification, fund conservation,
│   │                                     #   replay protection, contract/bridge audit
│   ├── transfer_runtime.mbt              # Lemma → Runtime bridges (6 lemma-corresponding functions)
│   ├── bigmath.mbt                       # BigInt amount parsing & operations (4 functions)
│   ├── uint256.mbt                       # UInt256 — 256-bit unsigned integer (add/sub/mul/div)
│   │
│   │   ┌── Tests ───────────────────────────────────────────────┐
│   ├── spec_easy_test.mbt                # Unit tests
│   └── spec_difficult_test.mbt           # Integration tests
│
└── business/                             # ═══ Business Assertion Layer ═══
    ├── moon.pkg                           # Package config
    ├── address_assert.mbt                 # 3 assertion functions: address, sig-compat, tx-sig
    ├── security_assert.mbt                # 6 assertion functions: balance, replay, amount, fee,
    │                                      #   contract-safety, bridge-security
    └── business_test.mbt                  # QuickCheck property bombardment

Line counts (implementation only):

File Lines Purpose
protocol/e2e_verifier.mbt 656 E2E production verifier + TransactionVerifier impl
protocol/ecdsa_secp256k1.mbt 443 ECDSA secp256k1 FIPS 186-4 + RFC 6979
protocol/simple_security_verifier.mbt 439 SecurityVerifier full implementation
proof/transfer_proof.mbtp 432 Formal theorem proofs (2 predicates + 14 lemmas)
protocol/address_spec.mbt 376 9 address types, 5 sig schemes, 6 hash schemes + DefaultVerifier
protocol/uint256.mbt 325 UInt256 — 256-bit unsigned integer arithmetic
protocol/bech32.mbt 233 Bech32/Bech32m + Cosmos verify
protocol/eip712.mbt 229 EIP-712 typed structured data hashing
protocol/transfer_runtime.mbt 225 Lemma → Runtime bridges
examples/main.mbt 204 Runnable examples (executed by CI)
protocol/keccak256.mbt 193 Keccak-256 (Ethereum)
protocol/rlp.mbt 177 RLP decoder (Ethereum Yellow Paper)
protocol/smt.mbt 171 Sparse Merkle Tree verifier
protocol/sha256.mbt 169 SHA-256 (FIPS 180-4)
protocol/base58.mbt 161 Base58 + Base58Check
protocol/transaction_spec.mbt 104 Transaction trait + 6 struct types
protocol/bigmath.mbt 96 BigInt amount parsing & operations
protocol/security_spec.mbt 75 5 trait methods + 4 struct types
protocol/assert_result.mbt 22 Error domain model (10 suberror variants)
business/security_assert.mbt 157 6 security assertion functions
business/address_assert.mbt 150 3 address/signature assertion functions
Total (non-test) ~5,037

Design Philosophy

1. Static Dispatch over Dynamic Dispatch

All traits use self: Self parameters and fn[V: Trait] generic syntax. This guarantees the compiler resolves every method call at compile time. There is no vtable lookup, no dyn dispatch, and no runtime NotImplemented error state.

In a smart-contract context, a runtime “not implemented” branch is not a usability nuisance — it is a remote code execution vulnerability. By eliminating this class of errors entirely through the type system, CryptoAssert removes an entire attack surface.

2. Theorem-Proven Invariants

The proof/transfer_proof.mbtp file uses MoonBit’s first-class formal verification (.mbtp proof files in a proof-enabled package) to encode mathematical invariants about cryptocurrency transfers, replay protection, and bridge multisig quorums. Running moon prove translates them to WhyML and hands each goal to the Why3 platform backed by the Z3 SMT solver — 14 goals, all mechanically proved. The CI prove job runs this for real on every push and fails the build if any lemma cannot be proved.

Having a machine-checked proof obligation wired into CI is a capability that mainstream blockchain ecosystems (Solidity, Rust/CosmWasm, Go/Cosmos SDK) do not offer natively.

3. Trait-Based Extension

The library ships with DefaultVerifier, SimpleSecurityVerifier, and E2ETransactionVerifier, but users can implement their own verifiers by implementing the AddressVerifier, TransactionVerifier, and SecurityVerifier traits. The compiler enforces completeness — missing any method is a compilation error, not a runtime panic.

4. Structured Error Model

All errors use MoonBit’s suberror mechanism (checked error subtypes). Each error variant carries structured payload data that enables programmatic error handling without string parsing. The 10 error variants cover the entire error space of cryptocurrency assertion failures.

5. Separation of Proof and Runtime

The proof layer (proof/transfer_proof.mbtp) defines mathematical theorems, while the runtime bridge (protocol/transfer_runtime.mbt) provides corresponding verification functions. Each runtime function references its corresponding lemma via proof_require in docstrings, creating a traceable link between formal verification and production code. Facts that the proof model cannot supply for free (see the modeling note in Layer 1) are enforced at runtime with BigInt checks.


Layer 1: Formal Proof Layer

File: proof/transfer_proof.mbtp — a dedicated package enabled for proving via proof/moon.pkg:

options(
  "proof-enabled": true,
)

This layer defines and proves mathematical theorems about cryptocurrency transfers, replay protection, and bridge multisig quorums using moon prove, which translates the .mbtp file to WhyML and invokes the Why3 verification platform backed by an SMT solver (Z3, CVC5, or Alt-Ergo).

# Prerequisites: Why3 + at least one SMT solver on PATH
#   WHY3DATA / WHY3LIB   → why3 --print-datadir / --print-libdir
#   Z3PATH               → optional explicit z3 binary location
moon prove
# Kali-Leo/moonbit-CryptoAssert/proof
#   Succeeded: 14 goals proved
# Summary:
#   1 of 1 packages proved

The CI prove job executes exactly this and asserts 1 of 1 packages proved / 14 goals proved — a lemma that fails to prove fails the build. (Sanity-checked during development: adding a deliberately false lemma makes moon prove exit non-zero.)

Modeling Note (read this before trusting any proof)

MoonBit’s current proof prelude idealizes UInt64 as unbounded mathematical integers: the range fact 0 ≤ x ≤ 2⁶⁴−1 is not an implicit axiom. This file therefore follows two disciplines:

  1. Every lemma that depends on non-negativity or upper bounds states those facts as explicit proof_require premises — real input constraints, never the conclusion restated as a premise.
  2. Range facts are enforced at runtime by BigInt checks (check_fee_nonnegative_bigint, transfer_runtime.mbt, bigmath.mbt).

The earlier fee_nonnegative_lemma (⊢ fee ≥ 0 with no premises) is unprovable under this model, and worse, it entered the axiom stack of subsequent goals and could make them vacuously “provable”. It has been removed; fee non-negativity is a runtime BigInt check instead.

Predicates

Predicate Signature Mathematical Meaning
fund_conservation_inv (total_in, total_out, fee: UInt64) total_in ≡ total_out + fee
transfer_state_invariant (pre_total, post_total: UInt64) pre_total ≡ post_total

Lemmas & Theorems (14 goals, all proved)

All premises listed below are the actual proof_require clauses in proof/transfer_proof.mbtp.

Fund conservation family

Lemma Premises (proof_require) Conclusion (proof_ensure)
no_inflation_lemma fund_conservation_invfee ≥ 0 total_in ≥ total_out
value_monotonic_lemma in1 ≥ in2 ∧ both ≥ out + fee (in1 − out − fee) ≥ (in2 − out − fee)
overflow_safe_lemma a ≥ 0b ≥ 0a ≤ max − b a + b ≥ aa + b ≥ ba + b ≤ max
transfer_correctness_theorem fund_conservation_invfee ≥ 0 No inflation + state invariant

Replay protection family (backs check_replay_protection)

Lemma Premises Conclusion
nonce_replay_rejection_lemma expected == current + 1replayed ≤ current replayed ≠ expected — a consumed nonce can never pass the equality check
chain_id_binding_lemma expected_chain_id ≥ 1tx_chain_id == expected_chain_id tx_chain_id ≥ 1 — a tx that passes the chain-ID check is never chain-unbound

Bridge multisig family (backs check_bridge_security)

Lemma Premises Conclusion
multisig_quorum_intersection_lemma total ≥ 1threshold ≤ total3·threshold ≥ 2·total + 1 2·threshold ≥ total + 1threshold ≥ 1 — any two BFT quorums intersect, so the bridge cannot sign two conflicting messages

UInt256 limb bounds & account model

Lemma Premises Conclusion
model_balance_lemma locked ≥ 0available ≥ 0total == locked + available total ≥ lockedtotal ≥ available
uint256_add_no_overflow_lemma limbs ≥ 0 ∧ carry_in ≤ 1a3 ≤ (max−1) − b3 sum ≥ each addend ∧ sum ≤ max
uint256_sub_no_underflow_lemma a3 > b3 a3 ≥ b3
uint256_mul_no_overflow_lemma limbs ≥ 0 ∧ both ≤ 2³²−1 ∧ carry == 0 a3·b3 ≥ 0a3·b3 ≤ max

Proof ↔ runtime bridge family

Lemma Premises Conclusion
bridge_soundness_lemma fund_conservation_inv ∧ all values in [0, max] in == out + fee lifts losslessly to BigInt
bridge_conservation_lemma fund_conservation_invfee ≥ 0out ≤ max − fee in ≥ outin == out + fee
bigint_extended_conservation_lemma fund_conservation_invfee ≥ 0out ≤ max − fee in ≥ outin == out + fee

Each lemma body contains explicit proof_assert statements that guide the SMT solver through the logical derivation. The proofs are verifiable by running:

moon prove

Why This Matters in Production

Without formal proof, a developer writes assert(total_in == total_out + fee) and hopes it is correct. Here, the SMT solver checks each lemma for all values satisfying its stated premises — not for a finite sample of test inputs. The guarantee is exactly as strong as the premises are honest: range facts are stated explicitly (see the modeling note above), and the runtime BigInt bridges enforce them on real data. Together this eliminates entire categories of bugs — inflation attacks, conservation violations, nonce-replay acceptance, and under-thresholded bridge multisigs — before code reaches production.


Layer 2: Protocol Specification Layer

Directory: protocol/

The protocol layer defines what must be verified — the type contracts, trait interfaces, and the reference DefaultVerifier implementation.

AddressVerifier Trait

pub trait AddressVerifier {
  address_format_spec(self: Self, AddressType) -> AddressFormatSpec
  valid_address_length_range(self: Self, AddressType) -> AddressLengthRange
  validate_checksum(self: Self, AddressType, String) -> Bool
  address_precision(self: Self, SignatureScheme) -> PrecisionSpec
  hash_output_length(self: Self, HashScheme) -> UInt
  is_valid_hash_size(self: Self, Bytes, HashScheme) -> Bool
}

All 9 address types supported by DefaultVerifier:

Address Type Chain Prefix Length Range Checksum
BtcP2pkh Bitcoin 1 26–35 chars Base58Check
BtcP2sh Bitcoin 3 26–35 chars Base58Check
BtcBech32 Bitcoin SegWit bc1 26–42 chars Bech32
BtcBech32m Bitcoin Taproot bc1p 26–42 chars Bech32m
Eth Ethereum 0x 42 chars None
EthEip55 Ethereum (EIP-55) 0x 42 chars EIP-55
Solana Solana (none) 32–44 chars None
Tron Tron T 26–35 chars Base58Check
Cosmos Cosmos cosmos1 24–45 chars Bech32

TransactionVerifier Trait

pub trait TransactionVerifier {
  validate_transaction(self: Self, TransactionSpec) -> TxValidationCode
  verify_signature(self: Self, SignatureVerifySpec) -> Bool
  compute_txid(self: Self, TransactionSpec) -> String
  estimate_fee(self: Self, TransactionSpec, String) -> FeeSpec
  validate_token_transfer(self: Self, TokenTransferSpec) -> TxValidationCode
}

SecurityVerifier Trait

pub trait SecurityVerifier {
  check_replay_protection(self: Self, TransactionSpec, ReplayProtectionSpec) -> SecurityAssertResult
  check_contract_safety(self: Self, TokenSafetySpec) -> SecurityAssertResult
  check_bridge_security(self: Self, BridgeSpec) -> SecurityAssertResult
  validate_amount_range(self: Self, String, String, String) -> SecurityAssertResult
  check_fee_ratio(self: Self, String, String, String) -> SecurityAssertResult
}

Layer 2 (Extended): Cryptography Primitives

CryptoAssert includes production-grade implementations of core cryptographic primitives used across major blockchain ecosystems.

ECDSA secp256k1 — protocol/ecdsa_secp256k1.mbt (443 lines)

Full FIPS 186-4 ECDSA implementation over the secp256k1 curve:

  • Elliptic curve: y² = x³ + 7 over F_p with SEC 2 secp256k1 parameters
  • Key generation: Deterministic private key derivation via SHA-256
  • Signing: ECDSA signature with RFC 6979 deterministic nonce (HMAC-SHA256 based)
  • Verification: Full ECDSA verification with curve point validation
  • Low-s enforcement: BIP 62 compliant low-s values
  • Point operations: Point addition, doubling, scalar multiplication (double-and-add)
  • All big integer arithmetic uses MoonBit BigInt for arbitrary precision
// Generate a key pair — returns Option, unwrap with match
let (priv_hex, pub_hex) = match @protocol.generate_key_pair(seed_bytes) {
  Some(pair) => pair
  None => abort("key generation failed")
}

// Sign a message — returns Option
let signature = @protocol.ecdsa_sign(sha256(message), private_key_bytes)

// Verify a signature
let valid = @protocol.ecdsa_verify(message_hash, signature, public_key_bytes)

SHA-256 — protocol/sha256.mbt (169 lines)

FIPS 180-4 compliant SHA-256 implementation with explicit 32-bit masking for cross-platform consistency (wasm32, wasm64, native targets). Includes sha256d (double SHA-256, Bitcoin standard).

Keccak-256 — protocol/keccak256.mbt (193 lines)

Keccak-256 implementation for Ethereum compatibility. Keccak-256 is not SHA3-256 — they differ in padding. This implementation uses:

  • Keccak-f[1600] permutation (24 rounds)
  • State: 1600 bits = 25 × 64-bit lanes
  • Rate: 1088 bits = 136 bytes
  • FixedArray temporaries to minimize GC pressure inside the round loop
  • Includes keccak256_to_nibbles for EIP-55 address checksumming
  • Verified against official known-answer vectors (keccak256("") = c5d24601…, keccak256("abc") = 4e03657a…) in the test suite

Base58 / Base58Check — protocol/base58.mbt (161 lines)

Bitcoin-compatible Base58 encoding with:

  • Bitcoin alphabet (excludes 0, O, I, l)
  • O(1) character lookup via precomputed 128-slot table
  • base58_check_verify — full Base58Check checksum validation (SHA-256d)
  • base58_check_validate — address validation with version byte and payload length checks

Bech32 / Bech32m — protocol/bech32.mbt (233 lines)

BIP 173 and BIP 350 compliant Bech32/Bech32m implementation:

  • Bech32 (SegWit v0, checksum constant = 1)
  • Bech32m (Taproot, checksum constant = 0x2bc830a3)
  • BCH polynomial division with generator coefficients
  • cosmos_verify for Cosmos/IBC ecosystem addresses
  • Case-insensitive lookup with mixed-case rejection

EIP-712 — protocol/eip712.mbt (229 lines)

Ethereum EIP-712 typed structured data hashing:

  • compute_type_hash — keccak256(encodeType(def))
  • encode_and_hash_struct — structHash = keccak256(typeHash || padded fields)
  • compute_eip712_message_hash — messageHash = keccak256(\x19\x01 || domainHash || structHash)
  • Field type support: address, uint256, bytes32, string, bool
  • parse_type_definition with bracket-aware field splitting
  • Left-padding to 32 bytes per EIP-712 spec

RLP — protocol/rlp.mbt (177 lines)

Ethereum Yellow Paper Appendix B RLP decoder:

  • Single-pass cursor traversal (no redundant slicing)
  • Supports short/long strings and short/long lists
  • rlp_decode, rlp_as_string, rlp_as_list API
  • bytes_to_hex helper for RLP-to-hex conversion

Sparse Merkle Tree — protocol/smt.mbt (171 lines)

256-layer Sparse Merkle Tree verifier using Keccak-256:

  • SMTProof struct with side nodes, bit mask, and value
  • verify_smt_inclusion — verify key/value exists under root hash
  • verify_smt_exclusion — verify key does not exist in tree
  • Precomputed 257-entry nil-hash table (zero-leaf to depth-256)
  • Proof validation: checks that non-empty side nodes match expected nil-hashes

Layer 2 (Extended): E2E Production Verifier

File: protocol/e2e_verifier.mbt (656 lines)

The E2E production verifier provides a complete, production-ready transaction verification pipeline implementing the TransactionVerifier trait with real ECDSA secp256k1 operations.

Transaction Signing & Verification

// Sign a transaction with ECDSA secp256k1 — returns Option
let signed_tx = match @protocol.sign_transaction(tx, private_key_hex) {
  Some(t) => t
  None => abort("signing failed")
}

// Verify a signed transaction's signature.
// The signing message serializes txid, chain_id, nonce, inputs, outputs and
// fee — tampering with chain_id or nonce after signing invalidates the
// signature (EIP-155 style binding).
let valid = @protocol.verify_signed_transaction(signed_tx)

Fund Conservation

// BigInt-based fund conservation verification (no overflow limit)
let conserved = @protocol.verify_fund_conservation(tx)

Replay Protection

// verify_replay_protection(tx, expected_chain_id, min_locktime,
//                          expected_nonce? : UInt64? = None)
let result = @protocol.verify_replay_protection(
  tx,
  1, // expected_chain_id — tx.chain_id must equal this (0 disables the match)
  0, // min_locktime
  expected_nonce=Some(7UL), // next valid account nonce
)
// Returns: Safe | Warning(msg) | Unsafe(msg)
// Real field checks:
//   tx.chain_id missing / zero / ≠ expected_chain_id → Unsafe (cross-chain replay)
//   tx.nonce missing                                 → Unsafe
//   tx.nonce < expected_nonce                        → Unsafe (consumed-nonce replay)
//   tx.nonce > expected_nonce                        → Warning (nonce gap)

Contract Safety Audit

let result = @protocol.audit_contract_safety(
  has_mint, mint_controlled, has_pause, safety_modes
)

Bridge Security Audit

let result = @protocol.audit_bridge_security(
  contract_address,
  target_chain_id,
  min_amount,
  max_amount,
  min_validators,
  multisig_threshold, // required signatures
  total_validators,   // validator set size
)
// Multisig threshold rules (see multisig_quorum_intersection_lemma):
//   threshold == 0 / > total / not a majority (2t ≤ n) → Unsafe
//   below BFT quorum ⌊2n/3⌋+1 (3t < 2n+1)              → Warning

Full Transaction Validation Pipeline

let result = @protocol.full_tx_validation_pipeline(
  tx,
  expected_chain_id,
  min_locktime,
  amount_min,
  amount_max,
  fee_max_ratio,
  expected_nonce=Some(7UL), // optional
)
// Pipeline:
//   1. ECDSA signature verification
//   2. Fund conservation check
//   3. Replay protection (real chain_id / nonce checks)
//   4. Amount range validation (all outputs)
//   5. Fee ratio check

TransactionVerifier Trait Implementation

E2ETransactionVerifier implements all 5 TransactionVerifier methods:

Method Implementation
validate_transaction Signature → Fund conservation → Input/output validation
verify_signature ECDSA secp256k1 verification from SignatureVerifySpec
compute_txid SHA-256 of serialized tx (version, inputs, outputs, locktime, chain_id, nonce, fee)
estimate_fee Rate-per-vbyte × virtual size (low/medium/high/default strategies)
validate_token_transfer Non-empty from/to, positive amount, chain ID, precision check

Layer 2 (Extended): Lemma Runtime Bridge

File: protocol/transfer_runtime.mbt (225 lines)

The lemma runtime bridge maps each formal lemma from proof/transfer_proof.mbtp to a runtime-callable verification function. Each function:

  1. Implements a runtime check exactly equivalent to its corresponding lemma
  2. References the lemma name in docstrings via proof_require
  3. Uses BigInt internally for overflow-safe comparisons
Runtime Function Corresponding Lemma Description
check_fund_conservation fund_conservation_inv total_in == total_out + fee
check_overflow_safe overflow_safe_lemma a + b ≥ a and a + b ≥ b
check_fee_nonnegative (runtime-only — the old fee_nonnegative_lemma is unprovable under the idealized-integer model and was removed) fee ≥ 0 (BigInt version)
check_no_inflation no_inflation_lemma total_in ≥ total_out
check_value_monotonic value_monotonic_lemma Monotonicity of (in − out − fee)
check_transfer_state_invariant transfer_state_invariant pre_total == post_total
check_transfer_correctness transfer_correctness_theorem Composite: no inflation + state invariant
verify_transfer_balance_chain Conservation lemma family Multi-input/output balance chain with overflow guards
check_transfer_bigint Conservation lemma family BigInt version — recommended for production

Layer 2 (Extended): BigMath & UInt256

BigMath — protocol/bigmath.mbt (96 lines)

BigInt-based amount parsing and operations designed for Ethereum’s 18-decimal precision, where UInt64 overflows above ~18.44 ETH:

Function Description
parse_bigint_amount Parse decimal string to BigInt (arbitrary length)
bigint_fund_conservation total_in == total_out + fee
bigint_no_inflation total_in >= total_out after conservation check
bigint_transfer_correctness Composite correctness check
sum_bigint_amounts Accumulate amount strings with error propagation
bigint_verify_transfer_balance_chain Full multi-input/output verification

UInt256 — protocol/uint256.mbt (325 lines)

Full 256-bit unsigned integer implementation (4 × UInt64 limbs, little-endian):

Operation Signature Description
from_uint64 (UInt64) -> UInt256 Construct from 64-bit value
add (UInt256, UInt256) -> (UInt256, Bool) Addition with overflow flag
sub (UInt256, UInt256) -> (UInt256, Bool) Subtraction with underflow flag
mul (UInt256, UInt256) -> (UInt256, Bool) Long multiplication with overflow detection
div_mod (UInt256, UInt256) -> (UInt256, UInt256)? Division with remainder
to_string (UInt256) -> String Decimal string representation
from_string (String) -> UInt256? Parse from decimal string
is_zero (UInt256) -> Bool Zero check

Layer 2 (Extended): Additional Modules

SimpleSecurityVerifier — protocol/simple_security_verifier.mbt (439 lines)

A complete, production-ready SecurityVerifier implementation with BigInt-based numerical validation. Construct it with @protocol.SimpleSecurityVerifier::new().

  • Replay protection: real tx.chain_id validation (missing / zero / mismatch vs expected_chain_idUnsafe), real tx.nonce validation (missing → Unsafe; < expected_nonceUnsafe replay; > expected_nonceWarning gap), locktime requirement, nonce-reuse warning
  • Contract safety: Mint control audit, burn control verification, pause capability with ownership/timelock guards, single-owner pattern detection
  • Bridge security: multisig threshold verification (multisig_threshold-of-total_validators: zero / over-count / non-majority → Unsafe, sub-BFT ⌊2n/3⌋+1 → Warning, backed by multisig_quorum_intersection_lemma), validator set size analysis, amount range consistency, address format validation, chain ID validation
  • Amount range: BigInt-based min/max boundary checks with structured results
  • Fee ratio: Three-tier classification (Normal/Elevated/Excessive) with scaled BigInt comparison

All parse failures convert to SecurityAssertResult::Unsafe — no panics at runtime.


Layer 3: Business Assertion Layer

Directory: business/

The business layer provides how to verify — concrete assertion functions that consume trait implementations and return structured results or raise typed errors.

Address & Signature Assertions (address_assert.mbt)

Function Signature Description
assert_address_format fn[V: AddressVerifier](V, String, AddressType) -> AssertionResult raise AssertError Validates address string against chain format spec
assert_sig_scheme_compatible fn(SignatureScheme, AddressType) -> AssertionResult raise AssertError Pure function; checks mathematical compatibility
assert_tx_signature fn[V: TransactionVerifier](V, TransactionSpec) -> AssertionResult raise AssertError Delegates to verifier for full ECDSA signature check

Security Assertions (security_assert.mbt)

Function Signature Description
assert_transaction_balance fn(TransactionSpec) -> AssertionResult raise AssertError Fund conservation: Σinputs ≡ Σoutputs + fee
assert_replay_protection fn[V: SecurityVerifier](V, TransactionSpec, ReplayProtectionSpec) -> AssertionResult raise AssertError Real nonce/chain_id value checks + timestamp
assert_amount_in_range fn[V: SecurityVerifier](V, String, String, String) -> AssertionResult raise AssertError Validates amount ∈ [min, max]
assert_fee_within_ratio fn[V: SecurityVerifier](V, String, String, String) -> AssertionResult raise AssertError Validates fee/amount ≤ max_ratio
assert_contract_safety fn[V: SecurityVerifier](V, TokenSafetySpec) -> AssertionResult raise AssertError Checks mint/burn/pause/upgrade controls
assert_bridge_security fn[V: SecurityVerifier](V, BridgeSpec) -> AssertionResult raise AssertError Checks multisig threshold, validator set, amount bounds, chain ID

Balance Verification

The assert_transaction_balance function directly corresponds to the formally proven fund_conservation_inv predicate (proof/transfer_proof.mbtp). It performs:

  1. Parse all input/output amount strings with overflow detection.
  2. Accumulate with overflow guard: a + b ≥ a check at each addition.
  3. Verify total_in ≡ total_out + fee with overflow check on total_out + fee.
  4. Raise AmountImbalance with exact values if conservation fails.

This is the runtime embodiment of the compile-time-proven theorem.


Type System Reference

Enumerated Types

AddressType — 9 blockchain address formats

Variant Chain Description
BtcP2pkh Bitcoin Pay-to-Public-Key-Hash
BtcP2sh Bitcoin Pay-to-Script-Hash
BtcBech32 Bitcoin SegWit (native)
BtcBech32m Bitcoin Taproot
Eth Ethereum 40-char hex (lowercase)
EthEip55 Ethereum EIP-55 mixed-case checksum
Solana Solana Ed25519 base58
Tron Tron Base58Check
Cosmos Cosmos Bech32

SignatureScheme — 5 cryptographic signature algorithms

Variant Curve / Scheme Primary Use
EcdsaSecp256k1 secp256k1 Bitcoin, Ethereum, Tron
Ed25519 Edwards 25519 Solana, Cosmos, Tron
Sr25519 Schnorr/Ristretto Polkadot, Substrate
Bls12381 BLS12-381 Filecoin, Ethereum 2.0
SchnorrSecp256k1 secp256k1 Schnorr Bitcoin (BIP-340)

HashScheme — 6 hash algorithms

Variant Output (bytes) Common Use
Sha256 32 Bitcoin, general
Keccak256 32 Ethereum
Blake2b256 32 Zcash, general
Blake2s256 32 Lightweight
Ripemd160 20 Bitcoin addresses
Sha256d 32 Bitcoin (double SHA-256)

ChecksumType — 4 checksum strategies

Variant Description
None No checksum (e.g., raw Ethereum hex)
Base58Check Bitcoin-style 4-byte checksum
Bech32 BCH-encoded checksum
Eip55 Mixed-case hex (Ethereum)

TxStatus — 5 transaction lifecycle states

Pending, Confirmed, Failed, Dropped, Unknown

TxValidationCode — 9 transaction validation outcomes

Valid, InvalidSignature, InvalidInput, InvalidOutput, InsufficientFee, DoubleSpend, Expired, AmountMismatch, ChainIdMismatch

SecurityAssertResult — 3-tier security verdict

Safe, Warning(String), Unsafe(String)

ContractSafetyMode — 5 smart contract safety controls

Owned, TimeLock, Pausable, Upgradeable, RateLimited

Struct Types

Struct Fields Purpose
AddressLengthRange min_chars: UInt, max_chars: UInt, byte_len: UInt Character-level and byte-level length constraints
AddressFormatSpec ty, length, checksum_type, prefix_req, charset, description Complete address format descriptor
PrecisionSpec decimals: UInt, unit_vals: String, symbol: String Token decimal precision
TxInputSpec txid, vout, script_sig, amount_str Transaction input descriptor
TxOutputSpec address, amount_str, script_pubkey, is_change Transaction output descriptor
FeeSpec rate_str, total_str, unit_desc Fee rate and total
TransactionSpec version, inputs[], outputs[], locktime, fee, txid, nonce: UInt64?, chain_id: UInt?, sig_scheme, signature_hex?, public_key_hex? Complete transaction descriptor; nonce/chain_id are serialized into the signing message and txid
TokenTransferSpec from, to, contract, amount_str, chain_id, precision ERC-20 style token transfer
SignatureVerifySpec message_hex, signature_hex, public_key_hex, scheme Signature verification request
ReplayProtectionSpec require_nonce, expected_nonce: UInt64?, require_chain_id, expected_chain_id: UInt, require_timestamp, max_nonce_reuse Replay attack guard config with real expected-value checks
TokenSafetySpec has_mint, mint_controlled, has_burn, has_pause, safety_modes[] Token security audit spec
BridgeSpec contract_address, target_chain_id, min_amount_str, max_amount_str, has_validator_set, min_validators, multisig_threshold, total_validators Cross-chain bridge validator & multisig config
SMTProof side_nodes: Array[Bytes], bit_mask: FixedArray[Bool], value: Bytes Sparse Merkle Tree proof
Eip712Field name: String, ty: String EIP-712 typed data field
Eip712TypeDefinition name: String, fields: Array[Eip712Field] EIP-712 type definition
UInt256 v0, v1, v2, v3: UInt64 256-bit unsigned integer (4 × 64-bit limbs)
RlpItem String(Bytes) or List(Array[RlpItem]) RLP-encoded item
ECPoint x: BigInt, y: BigInt Elliptic curve point (secp256k1)

Trait Reference

AddressVerifier

Method Returns Description
address_format_spec(self, AddressType) AddressFormatSpec Get format spec for address type
valid_address_length_range(self, AddressType) AddressLengthRange Get char/byte length bounds
validate_checksum(self, AddressType, String) Bool Verify address checksum
address_precision(self, SignatureScheme) PrecisionSpec Get native currency precision
hash_output_length(self, HashScheme) UInt Get hash output byte length
is_valid_hash_size(self, Bytes, HashScheme) Bool Check hash size matches scheme

TransactionVerifier

Method Returns Description
validate_transaction(self, TransactionSpec) TxValidationCode Validate entire transaction
verify_signature(self, SignatureVerifySpec) Bool Verify cryptographic signature
compute_txid(self, TransactionSpec) String Compute transaction ID
estimate_fee(self, TransactionSpec, String) FeeSpec Estimate transaction fee
validate_token_transfer(self, TokenTransferSpec) TxValidationCode Validate token transfer

SecurityVerifier

Method Returns Description
check_replay_protection(self, TransactionSpec, ReplayProtectionSpec) SecurityAssertResult Check replay attack guards
check_contract_safety(self, TokenSafetySpec) SecurityAssertResult Audit token contract safety
check_bridge_security(self, BridgeSpec) SecurityAssertResult Audit cross-chain bridge config
validate_amount_range(self, String, String, String) SecurityAssertResult Check amount ∈ [min, max]
check_fee_ratio(self, String, String, String) SecurityAssertResult Check fee/amount ratio

Error Model

All errors use MoonBit’s suberror mechanism — checked error subtypes that the compiler enforces at call sites. Each variant carries domain-specific payload data.

suberror AssertError — 10 variants

Variant Payload When Raised
InvalidPrefix (String, String) — address, expected prefix Address prefix mismatch
InvalidLength (String, UInt, UInt) — address, min, max Address string length out of range
InvalidCharacter (String, Char) — address, illegal char Character not in allowed charset
ChecksumMismatch (String) — address Checksum validation failure
AmountImbalance (String, String, String) — total_in, total_out, fee Fund conservation violation
IncompatibleScheme (SignatureScheme, AddressType) Signature scheme incompatible with address type
SignatureVerificationFailed (String) — txid Cryptographic signature check failed
NumericParseError (String) — parse detail Amount string parsing or overflow
HashLengthMismatch (UInt, UInt) — actual, expected Hash output size mismatch
SecurityCheckFailed (String) — reason Generic security check failure

Handling Errors

let verifier = @protocol.DefaultVerifier::new()
let result = try @business.assert_address_format(
  verifier,
  "0x5aAeb6053F3E94C9b9A09f33669435E7Ef1BeAed", // official EIP-55 test vector
  @protocol.AddressType::EthEip55,
) catch {
  @protocol.AssertError::InvalidPrefix(address, expected_prefix) =>
    // wrong prefix — e.g., missing "0x"
    ...
  @protocol.AssertError::InvalidLength(address, min, max) =>
    // address too short or too long
    ...
  @protocol.AssertError::InvalidCharacter(address, c) =>
    // illegal character in address
    ...
  @protocol.AssertError::ChecksumMismatch(address) =>
    // checksum validation failed
    ...
  _ =>
    // unexpected error
    ...
}

Quick Start

Prerequisites

  • MoonBit toolchain (latest stable)
  • Why3 and Z3 (only required for moon prove; set WHY3DATA/WHY3LIB from why3 --print-datadir / why3 --print-libdir, optionally Z3PATH)

Run the Examples

Every snippet below is excerpted from the runnable example program in examples/main.mbt, which CI compiles and runs on every push (asserting on its output), so the documentation can never drift from the published API again:

moon run examples --target native

Adding CryptoAssert to Your Project

moon add Kali-Leo/moonbit-CryptoAssert

Or add to moon.mod manually:

import {
  "Kali-Leo/moonbit-CryptoAssert@0.2.0",
}

Then in your moon.pkg:

import {
  "Kali-Leo/moonbit-CryptoAssert/protocol",
  "Kali-Leo/moonbit-CryptoAssert/business",
}

Example 1: Address Format Validation

/// Validate an Ethereum EIP-55 checksummed address
/// (from examples/main.mbt, section [5])
let verifier = @protocol.DefaultVerifier::new()
try {
  let _ = @business.assert_address_format(
    verifier,
    "0x5aAeb6053F3E94C9b9A09f33669435E7Ef1BeAed", // official EIP-55 vector
    @protocol.AddressType::EthEip55,
  )
  println("checksummed address → Valid")
} catch {
  _ => println("checksummed address → rejected")
}
// A corrupted (all-lowercase) form of the same address is rejected with
// ChecksumMismatch. Note: the widely-circulated example address
// 0x742d35Cc… actually has an INVALID EIP-55 checksum — this library now
// correctly rejects it.

Example 2: Signature Scheme Compatibility (Pure Function)

/// ECDSA + Bitcoin P2PKH is compatible; BLS12-381 + Bitcoin is NOT
try {
  let ok = @business.assert_sig_scheme_compatible(
    @protocol.SignatureScheme::EcdsaSecp256k1,
    @protocol.AddressType::BtcP2pkh,
  )
  // ok == AssertionResult::Valid
  let _ = @business.assert_sig_scheme_compatible(
    @protocol.SignatureScheme::Bls12381,
    @protocol.AddressType::BtcP2pkh,
  )
} catch {
  @protocol.AssertError::IncompatibleScheme(_s, _a) =>
    // _s == Bls12381, _a == BtcP2pkh
    println("incompatible pair rejected")
  _ => println("unexpected error")
}

Example 3: E2E Production Transaction Pipeline

/// Full E2E validation: sign → verify sig → fund conservation → replay → fee
/// (from examples/main.mbt, section [4])
let result = @protocol.full_tx_validation_pipeline(
  signed_tx,
  1, // expected_chain_id
  0, // min_locktime
  "1", // amount_min
  "100000000000000000000", // amount_max
  "5", // fee_max_ratio (%)
  expected_nonce=Some(7UL),
)
// result == Safe | Warning(msg) | Unsafe(msg)

Example 4: ECDSA Signature Generation & Verification

/// (from examples/main.mbt, sections [1] and [4])
/// Generate key pair — Option, unwrap with match
let seed : Bytes = b"cryptoassert-demo-seed-32bytes!!"
let (priv_hex, pub_hex) = match @protocol.generate_key_pair(seed) {
  Some(pair) => pair
  None => abort("key generation failed")
}

/// Sign a transaction (tx carries nonce: Some(7UL), chain_id: Some(1)) — Option
let signed_tx = match @protocol.sign_transaction(tx, priv_hex) {
  Some(t) => t
  None => abort("signing failed")
}

/// Verify the signed transaction
let valid = @protocol.verify_signed_transaction(signed_tx)
// valid == true

/// The signature binds chain_id and nonce: re-targeting the same signed tx to
/// another chain makes verification fail
// verify_signed_transaction(tx_with_chain_id_56) == false

/// Verify fund conservation
let conserved = @protocol.verify_fund_conservation(signed_tx)
// conserved == true

Example 5: Replay Protection — Real nonce / chain ID Checks

/// (from examples/main.mbt, section [2]; signed_tx carries
///  nonce: Some(7UL), chain_id: Some(1))

/// Legitimate: chain matches, nonce equals the account's next nonce
let ok = @protocol.verify_replay_protection(
  signed_tx, 1, 0, expected_nonce=Some(7UL),
)
// ok == Safe

/// Replay attack: account nonce has advanced to 8 — replaying the old
/// nonce-7 transaction is rejected
let replayed = @protocol.verify_replay_protection(
  signed_tx, 1, 0, expected_nonce=Some(8UL),
)
// replayed == Unsafe("Nonce 7 already consumed (account nonce is 8) — replay detected")

/// Cross-chain replay: tx is bound to chain 1, submitted to chain 56
let wrong_chain = @protocol.verify_replay_protection(signed_tx, 56, 0)
// wrong_chain == Unsafe("Chain ID mismatch: tx carries 1, expected 56 — cross-chain replay")

Example 6: Bridge Multisig Audit

/// (from examples/main.mbt, section [3])
/// 7-of-9 satisfies the BFT quorum ⌊2n/3⌋+1 = 7 → Safe
let safe_bridge = @protocol.audit_bridge_security(
  "0x1234567890abcdef1234567890abcdef12345678",
  137, "1000", "100000000000",
  7, // min validators
  7, // multisig threshold
  9, // total validators
)
// safe_bridge == Safe

/// 5-of-9 is a majority but below the BFT quorum → Warning
/// 4-of-9 is not even a majority — minority collusion could move funds → Unsafe
/// BigInt version — no overflow limit, safe for Ethereum-scale amounts
/// check_transfer_bigint(input_amounts, output_amounts, fee_str) — positional
let conserved = @protocol.check_transfer_bigint(
  ["1000000000000000000000", "500000000000000000000"],
  ["1499000000000000000000", "1000000000000000000"],
  "1000000000000000000",
)
// conserved == true (1500 = 1499 + 1 + 1)

Example 8: Sparse Merkle Tree Verification

/// Verify inclusion proof
let valid = @protocol.verify_smt_inclusion(
  root_hash,
  key_bytes,
  value_bytes,
  proof,
)

/// Verify exclusion proof (key not in tree)
let absent = @protocol.verify_smt_exclusion(
  root_hash,
  key_bytes,
  proof,
)

API Reference

The sections above (Type System Reference, Trait Reference, and Layer 3: Business Assertion Layer) constitute the complete API catalog for this library. For an interactive HTML API reference with cross-linked types and search, run:

moon doc

This generates browsable documentation in the _build/doc/ directory.


Extending the Library

Implementing a Custom AddressVerifier

To add support for a new blockchain (e.g., Polkadot), implement all 6 methods of the AddressVerifier trait:

struct PolkadotVerifier {}

impl @protocol.AddressVerifier for PolkadotVerifier with
  address_format_spec(self, ty) {
    match ty {
      // ... implement all 9 AddressType variants
    }
  }

// Also required:
//   valid_address_length_range(self, ty)
//   validate_checksum(self, ty, address)
//   address_precision(self, scheme)
//   hash_output_length(self, scheme)
//   is_valid_hash_size(self, hash, scheme)

The compiler will not compile if any method is missing. This is enforced statically — no runtime NotImplemented error can ever occur.

Adding New Chain Support

The recommended workflow:

  1. Implement AddressVerifier for your chain’s address format.
  2. Implement TransactionVerifier for your chain’s transaction structure.
  3. Implement SecurityVerifier for your chain’s security model.
  4. Write QuickCheck property tests (see business/business_test.mbt for patterns).
  5. Optionally, extend transfer_proof.mbtp with chain-specific invariants and prove them with moon prove.

Testing & Quality Assurance

Test Coverage

Test File Description Category
protocol/spec_easy_test.mbt Enum counts, struct construction, SecurityAssertResult variants, Keccak-256 known-answer vectors Unit
protocol/spec_difficult_test.mbt Multi-input/output TX, ERC-20 transfer, BTC/SAT precision, security specs, bridge config, EIP-55/Cosmos address format, SignatureVerifySpec, replay-protection behavior (consumed nonce / nonce gap / chain-ID mismatch / zero chain-ID), bridge multisig thresholds (non-majority / sub-BFT / over-count / zero / BFT-pass), E2E sign→verify→pipeline integration incl. chain_id/nonce signature-binding Integration
business/business_test.mbt QuickCheck property bombardment on signature scheme × address type compatibility, EIP-55 official-vector validation Property

Test Execution Summary

  • 90 tests total across all test files
  • All 90 tests pass with moon test --target native and moon test --target wasm-gc
  • moon check --deny-warn passes with zero warnings

QuickCheck Property Bombardment

The business test suite uses moonbitlang/quickcheck@0.14.0 to systematically verify properties through randomized input generation:

Test Rounds Description
Compatible pairs 200 each All 11 compatible (scheme, address_type) pairs
Incompatible pairs 200 each All 34 incompatible pairs (5×9−11=34)
Error payload correctness Assertion Verify IncompatibleScheme carries correct (scheme, addr)
Deterministic / idempotence 500 Same input → same output (impurity guard)

Total: 9,100+ property check rounds across the full 5×9 compatibility matrix.

Test Execution

# Type checking
moon check

# Run all tests
moon test --target native

# Strict mode
moon test --deny-warn

# Update test snapshots
moon test --update

# Run formal theorem proofs (requires Why3 + Z3)
moon prove

Security Considerations

Compile-Time Guarantees

  1. Zero NotImplemented: All traits use self: Self with fn[V: Trait] syntax. The compiler rejects any incomplete trait implementation at compile time. This eliminates a class of vulnerabilities where runtime “not implemented” branches could be exploited in smart contract contexts.

  2. Overflow Protection: The overflow_safe_lemma is proven by Z3 (under its explicit non-negativity and bound premises — see the Layer 1 modeling note) and enforced at runtime in bridging functions. Every accumulation is guarded by overflow checks.

  3. Fund Conservation: The conservation lemmas are verified by the SMT solver for all values satisfying their stated proof_require premises. Both UInt64 and BigInt runtime implementations are provided; the BigInt path enforces the range premises on real data.

Numeric Domain: UInt64 vs BigInt

The current formal proofs operate on UInt64 (max ≈ 1.84 × 10¹⁹), which is sufficient for Bitcoin (Satoshi), Solana (Lamport), and most UTXO-based chains where individual UTXO values fit within 64 bits.

For Ethereum and EVM-compatible chains that use 256-bit integers, the library provides:

  • bigmath.mbt: BigInt-based amount operations (no overflow limit)
  • uint256.mbt: Full 256-bit unsigned integer (add/sub/mul/div)
  • check_transfer_bigint: Production-recommended BigInt verification

Supported Cryptographic Primitives

Primitive Implementation Standard
ECDSA secp256k1 450 lines, real curve ops FIPS 186-4
SHA-256 169 lines FIPS 180-4
Keccak-256 187 lines, Keccak-f[1600] Ethereum
Base58Check 161 lines, O(1) lookup Bitcoin
Bech32/Bech32m 233 lines, BCH polynomial BIP 173/350
EIP-712 230 lines, structHash + messageHash Ethereum
RLP 177 lines, single-pass cursor Ethereum Yellow Paper
SMT 171 lines, 256-layer, precomputed nil-hashes Sparse Merkle Tree

Attack Surface Analysis

Class Mitigation Mechanism
Integer overflow (inflation) Proven overflow_safe_lemma + Z3 + runtime guard
Integer overflow (fee bypass) Proven fund_conservation_inv + Z3
Incomplete trait impl Prevented Compile-time trait completeness check
Address spoofing (wrong prefix) Caught InvalidPrefix error
Address spoofing (invalid char) Caught InvalidCharacter error
Checksum bypass Caught ChecksumMismatch error
Signature scheme mismatch Caught IncompatibleScheme error
Double-spend Caught TxValidationCode::DoubleSpend
Replay attack (consumed nonce) Caught Real tx.nonce vs expected_nonce check + nonce_replay_rejection_lemma
Replay attack (cross-chain) Caught Real tx.chain_id vs expected_chain_id check + EIP-155 style signature binding
Cross-chain bridge exploit Caught multisig_threshold-of-total_validators verification (majority + BFT) + min_validators check
Fake signature (hash-as-sig) Prevented Real ECDSA secp256k1 verification

Production Hardening Recommendations

  1. Use BigInt for high-value transfers — Prefer check_transfer_bigint over UInt64-based functions for Ethereum and EVM-compatible chains.

  2. Use a secure random number generator — The QuickCheck LCG in tests is deterministic by design. Production key generation should use OS-provided CSPRNGs.

  3. Add chain-specific invariants — Extend proof/transfer_proof.mbtp with chain-specific theorems (e.g., staking conservation, slashing invariants).

  4. Audit custom verifiers — While the trait system guarantees completeness, the semantic correctness of custom SecurityVerifier implementations is the integrator’s responsibility.


Build, Prove & Test

Development Commands

# ─── Type Checking ──────────────────────────────────
moon check                           # Full project type check
moon check --deny-warn               # Strict mode

# ─── Testing ────────────────────────────────────────
moon test --target native            # Run all 90 tests
moon test --deny-warn                # Strict mode
moon test --update                   # Update test snapshots

# ─── Formal Theorem Proving (Why3 + Z3 required) ───
moon prove                           # Verify all 14 lemmas in proof/transfer_proof.mbtp

# ─── Build & Run Examples ───────────────────────────
moon build                           # Build the package
moon run examples --target native    # Run the executable examples
moon build --target wasm-gc          # Build for wasm-gc backend

# ─── Documentation ──────────────────────────────────
moon doc                             # Generate API documentation

# ─── Formatting ─────────────────────────────────────
moon fmt                             # Format all source files

# ─── Publishing ─────────────────────────────────────
moon publish --dry-run               # Check publish readiness

# ─── Full Validation Pipeline ───────────────────────
moon check --deny-warn && moon prove && moon test --target native && moon run examples --target native

CI/CD

The project uses GitHub Actions for continuous integration:

CI Pipeline (.github/workflows/ci.yml) — 4 jobs, all real

Job What it runs Failure condition
check moon check --deny-warn + moon fmt && git diff --exit-code Any warning or unformatted file
build moon build + moon run examples --target native, then greps the output for key results (signature valid: true, replayed old nonce → Unsafe, 7-of-9 (BFT quorum) → Safe, …) Build error, runtime error, or missing expected output
test moon test -v --target native + moon test --target wasm-gc Any of the 90 tests failing
prove Installs Why3 (apt) + Z3 4.15.3 (GitHub release), sets WHY3DATA/WHY3LIB/Z3PATH, runs moon prove and asserts 1 of 1 packages proved / 14 goals proved Any lemma failing to prove, or the proof run not actually executing

Published Package

  • Package: Kali-Leo/moonbit-CryptoAssert v0.2.0
  • Registry: mooncakes.io
  • Repository: GitHub
  • License: Apache 2.0

Comparison with Industry Alternatives

Feature CryptoAssert (MoonBit) OpenZeppelin (Solidity) CosmWasm (Rust) Cosmos SDK (Go)
Formal proof (SMT) moon prove (Why3/Z3) ✗ (requires Echidna/Certora) ✗ (external tools)
Compile-time trait completeness ✓ (zero NotImplemented) ✗ (runtime revert) ✓ (trait bounds) ✗ (interface checks)
Static dispatch ✗ (dynamic calls) ✓ (monomorphization) ✗ (interface dispatch)
Structured errors ✓ (10 suberror variants) Partial (custom errors) ✓ (thiserror/anyhow) ✗ (string errors)
Property-based testing ✓ (QuickCheck built-in) Partial (Foundry fuzz) ✓ (proptest)
Multi-chain coverage 9 chains Ethereum ecosystem Cosmos ecosystem Cosmos ecosystem
Proof-carrying code
Real ECDSA secp256k1 ✓ (450 lines, FIPS 186-4) ✓ (via precompiles) ✓ (k256 crate) ✓ (tendermint)
EIP-712 support
Sparse Merkle Tree ✓ (ICS-23)
Lemma→Runtime bridge
Gas optimization N/A (off-chain) Critical concern Moderate concern Moderate concern

Key differentiator: CryptoAssert ships proof-carrying code — mathematical theorems about fund conservation, replay protection, and bridge multisig quorums are verified by an SMT solver via moon prove on every CI run, with the honest modeling premises documented alongside. It also provides the broadest suite of built-in cryptographic primitives (ECDSA, SHA-256, Keccak-256, Base58, Bech32, EIP-712, RLP, SMT) among multi-chain assertion libraries.


Changelog

0.2.0 (2026-07-30)

Response to the OSC 2026 acceptance review — every finding addressed with code, proofs, and CI enforcement:

Core capability completion

  • Real replay protection: TransactionSpec gains nonce : UInt64? and chain_id : UInt?; ReplayProtectionSpec gains expected_nonce / expected_chain_id. check_replay_protection now validates the actual field values (missing/zero/mismatched chain ID → Unsafe; missing nonce → Unsafe; consumed nonce → Unsafe; nonce gap → Warning). chain_id and nonce are serialized into the signing message and txid, so signatures cryptographically bind chain and sequence number.
  • Real bridge multisig auditing: BridgeSpec gains multisig_threshold / total_validators; check_bridge_security rejects zero, over-count, and non-majority thresholds and warns below the BFT quorum ⌊2n/3⌋+1.

Formal proofs actually execute

  • Proofs moved to a dedicated proof-enabled package (proof/); moon prove translates them to WhyML and runs Why3 + Z3 for real — 14 goals proved, and a false lemma makes the build fail. The CI prove job asserts the goal count.
  • Lemma set made honest under the idealized-integer model (explicit range premises; unsound fee_nonnegative_lemma removed) and extended with nonce_replay_rejection_lemma, chain_id_binding_lemma, and multisig_quorum_intersection_lemma backing the new runtime checks.

Cryptography fixes

  • Fixed Keccak-256 ρ+π permutation table pairing — the implementation now passes official known-answer vectors, which makes EIP-55 checksum validation actually work (previously it rejected every valid address); validated against the official EIP-55 test vectors.
  • Fixed address charset validation incorrectly checking prefix characters (0x, bc1, cosmos1), which mis-rejected all prefixed addresses.
  • Unified the business-layer signing-message serialization with the protocol layer (previously assert_tx_signature could never verify a transaction signed by sign_transaction).

Docs, examples & CI

  • New runnable examples/ package mirroring the README Quick Start; CI builds and runs it and asserts on its output.
  • README fully synchronized with the published API (all snippets compile against 0.2.0).
  • CI expanded to 4 real jobs: strict check + format, build + run examples, test (native + wasm-gc), prove (Why3/Z3 with asserted goal count).
  • Test suite grown from 62 to 90 tests.

Breaking changes

  • TransactionSpec, ReplayProtectionSpec, BridgeSpec construction requires the new fields; verify_replay_protection, audit_bridge_security, and full_tx_validation_pipeline have new signatures (hence 0.2.0).

License

Apache 2.0 License — see LICENSE


Contributing

  1. Implement missing trait methods — the compiler will tell you which ones.
  2. Add new chain support by implementing all three traits.
  3. Extend proof/transfer_proof.mbtp with chain-specific invariants and prove them.
  4. Add tests for new compatibility pairs or cryptographic primitives.
  5. Run moon check --deny-warn && moon prove && moon test --target native before submitting.

Built with MoonBit · Proven with Why3/Z3 via moon prove · Tested with QuickCheck

Making cryptocurrency compliance verification accessible, provably safe, and production-ready.

关于

Production-grade assertion library for multi-chain crypto compliance and fund conservation, built on MoonBit with static dispatch and formal proofs.

2.6 MB
邀请码
    Gitlink(确实开源)
  • 加入我们
  • 官网邮箱:gitlink@ccf.org.cn
  • QQ群
  • QQ群
  • 公众号
  • 公众号

版权所有:中国计算机学会技术支持:开源发展技术委员会
京ICP备13000930号-9 京公网安备 11010802047560号