Docs Examples Whitepaper Explorer GitHub →
Documentation

CURS3D Developer Docs

Everything you need to build on, operate, and understand the CURS3D quantum-resistant blockchain with smart contracts.

Getting Started

CURS3D is a quantum-resistant Layer 1 blockchain written entirely in Rust from scratch. It is not a fork of any existing blockchain. Every component -- consensus, cryptography, networking, storage, smart contracts, and APIs -- is implemented from zero.

The project currently has 20 modules, 67 tests, and ships with a full REST API, block explorer, Docker support, and CI pipeline.

Rust edition 2024. Minimum toolchain: stable 1.94+. All amounts are in microtokens (1 CUR = 1,000,000 microtokens).

Quick Start

terminal
# Clone and build
git clone https://github.com/Pazificateur69/curs3d.git
cd curs3d
cargo build --release

# Create a wallet
./target/release/curs3d wallet --output my_wallet.json

# Start a node
./target/release/curs3d node --validator-wallet my_wallet.json

# Run all 67 tests
cargo test

Installation

Prerequisites

  • Rust 1.94+ (edition 2024)
  • A C compiler (for pqcrypto-dilithium native bindings)
  • Git

Build Commands

terminal
cargo build --release    # Build optimized binary
cargo test               # Run all 67 tests
cargo clippy             # Lint (must pass with no warnings)
cargo fmt --check        # Format check

CLI: node

Start a full CURS3D node with optional validator mode, custom data directory, bootnodes, and genesis configuration.

terminal
curs3d node [OPTIONS]
FlagDefaultDescription
-p, --port4337P2P listen port
-d, --data-dircurs3d_dataData directory for sled storage
--validator-walletNonePath to wallet file (enables validator mode)
--bootnode[]Multiaddr of bootnodes (repeatable)
--rpc-addr127.0.0.1:9545TCP RPC listen address
--genesis-configNonePath to genesis config JSON
When a node starts, it binds the TCP RPC on port 9545 (for CLI) and the HTTP REST API on port 8080 (for browsers/apps). Gossipsub + mDNS discovery activate automatically.

CLI: wallet

Create a new CURS3D wallet with CRYSTALS-Dilithium Level 5 keypair, encrypted with AES-256-GCM using an Argon2-derived key.

terminal
curs3d wallet [OPTIONS]
FlagDefaultDescription
-o, --outputwallet.jsonOutput file path for the encrypted wallet

The wallet file is encrypted at rest. You will be prompted for a password. Addresses follow the format CUR + 40 hex characters (derived from SHA-3 of the public key, first 20 bytes).

CLI: info

Display wallet address and public key from an encrypted wallet file.

terminal
curs3d info --wallet my_wallet.json
FlagDefaultDescription
-w, --walletwallet.jsonPath to wallet file

CLI: send

Send CUR tokens to another address via RPC.

terminal
curs3d send --wallet sender.json --to CUR7f3a...9c2d --amount 100 --fee 1000
FlagDefaultDescription
-w, --walletwallet.jsonSender wallet file
-t, --torequiredRecipient address (CUR + 40 hex)
-a, --amountrequiredAmount in CUR
-f, --fee1000Transaction fee (microtokens)
--data-dircurs3d_dataData directory
--rpc-addr127.0.0.1:9545RPC address

CLI: stake

Stake CUR tokens to become a validator. Minimum stake: 1,000 CUR (1,000,000,000 microtokens).

terminal
curs3d stake --wallet validator.json --amount 1000 --fee 1000
FlagDefaultDescription
-w, --walletwallet.jsonWallet file
-a, --amountrequiredStake amount in CUR
-f, --fee1000Transaction fee (microtokens)
--data-dircurs3d_dataData directory
--rpc-addr127.0.0.1:9545RPC address

CLI: status

Query the chain status from a running node via RPC.

terminal
curs3d status --data-dir curs3d_data
FlagDefaultDescription
-s, --data-dircurs3d_dataData directory
--rpc-addrNoneOptional RPC address for remote status

Architecture: 20 Modules

CURS3D is organized into the following module structure:

src/
src/
  main.rs              # CLI entry point (clap)
  lib.rs               # Module declarations
  api/mod.rs           # HTTP REST API (hyper 1.x, port 8080)
  consensus/mod.rs     # BFT PoS, FinalityVote, FinalityTracker, slashing
  core/
    block.rs           # BlockHeader, Block, genesis, signatures
    blocktree.rs       # BlockTree, fork choice, pruning
    chain.rs           # Blockchain struct, state, validation, reorg
    receipt.rs         # Transaction receipts with logs
    transaction.rs     # Transaction, TransactionKind (6 types)
  crypto/
    dilithium.rs       # CRYSTALS-Dilithium Level 5
    hash.rs            # SHA-3, double_hash, merkle_root
  network/mod.rs       # libp2p P2P, Gossipsub, mDNS, sync
  rpc/mod.rs           # TCP JSON RPC (port 9545)
  storage/mod.rs       # sled DB with schema versioning
  vm/
    mod.rs             # WASM VM (Wasmer), contract execution
    gas.rs             # Gas cost constants (15 operations)
    state.rs           # ContractState (per-contract storage)
  wallet/mod.rs        # AES-256-GCM + Argon2 encrypted wallets

State Model

CURS3D uses an account-based state model. Every address has an AccountState:

AccountState
pub struct AccountState {
    pub balance: u64,
    pub nonce: u64,
    pub staked_balance: u64,
    pub public_key: Option<Vec<u8>>,
}

Every block contains a state root -- the Merkle root of all accounts and contract storage. Block hashes use double-SHA3: sha3(sha3(bincode(header))).

Addresses are 20 bytes internally, displayed as CUR + 40 hex characters. The address is derived from SHA-3(public_key)[0..20].

Smart Contracts: WASM VM

CURS3D runs a deterministic WebAssembly virtual machine powered by the Wasmer runtime. Contracts are compiled to WASM and deployed on-chain.

Transaction Types

  • DeployContract -- Deploy WASM bytecode. The data field contains the bytecode. A new contract address is derived from the deployer and nonce.
  • CallContract -- Call a deployed contract. The to field is the contract address. The data field contains the function selector and arguments.

Host Functions

Contracts can call the following host functions provided by the VM:

  • storage_read(key_ptr, key_len) -- Read from contract storage (200 gas)
  • storage_write(key_ptr, key_len, val_ptr, val_len) -- Write to contract storage (5,000 gas)
  • emit_log(data_ptr, data_len) -- Emit a log entry (375 gas)
  • get_caller() -- Get the caller address
  • get_input() -- Get the input data
  • set_return(data_ptr, data_len) -- Set the return data

Contract Storage

Each contract has its own key-value storage namespace. Keys and values are arbitrary byte arrays. Storage is persisted in the sled database and included in the state root calculation.

Gas Model

Every operation in the VM consumes gas. The block gas limit is 10,000,000 (configurable in genesis). Base fee follows an EIP-1559-style adjustment mechanism.

OperationGas CostConstant
GAS_BASE_TX21,000Base cost per transaction
GAS_DEPLOY32,000Additional cost for contract deployment
GAS_CALL2,600Additional cost for contract call
GAS_STORAGE_READ200Read from contract storage
GAS_STORAGE_WRITE5,000Write to contract storage
GAS_LOG375Emit a log entry
GAS_PER_BYTE16Per byte of transaction data
GAS_MEMORY_READ_BYTE3Read byte from WASM memory
GAS_MEMORY_WRITE_BYTE6Write byte to WASM memory
GAS_HOST_CALL_OVERHEAD40Overhead per host function call
GAS_WASM_DEFAULT_OP2Default WASM instruction cost
GAS_WASM_MEMORY_OP8Memory-related WASM ops
GAS_WASM_CONTROL_OP4Control flow WASM ops
GAS_WASM_CALL_OP12WASM call/call_indirect
GAS_WASM_NUMERIC_OP3Numeric WASM ops

Transaction Receipts

Every transaction that executes produces a Receipt containing:

  • status -- Success or failure with error message
  • gas_used -- Total gas consumed
  • logs -- Array of LogEntry objects (contract_id, data)
  • return_data -- Bytes returned by the contract (if any)

Receipts are stored alongside the block and accessible via the REST API when querying transactions.

Consensus: BFT Proof of Stake

CURS3D uses Byzantine Fault Tolerant Proof of Stake consensus. The protocol guarantees safety as long as fewer than 1/3 of the staked tokens are controlled by malicious actors.

Validator Selection

Validators are selected from the epoch snapshot -- a frozen set of validators captured at epoch boundaries. Selection is stake-weighted and deterministic: given the same block height and epoch snapshot, every node computes the same proposer.

Finality

Blocks achieve finality through the FinalityVote and CheckpointVote system. When 2/3 of the stake in the current epoch votes for a block, it becomes finalized. Finalized blocks cannot be reverted.

Epoch Snapshots

The validator set is frozen at epoch boundaries (every 32 blocks by default). This ensures consistent proposer selection within an epoch, even if stake changes occur mid-epoch.

Each EpochSnapshot records the active validators and their stakes at the start of the epoch. The snapshot is used for all block production and finality voting within that epoch.

Provable Slashing

If a validator signs two different blocks at the same height (equivocation), anyone can submit an EquivocationEvidence containing both signed block headers.

  • The evidence is cryptographically verified using the validator's Dilithium public key
  • 33% of the validator's stake is slashed (burned)
  • The validator is jailed for a configurable duration (default: 64 blocks)
  • Jailed validators cannot propose blocks or vote during the jail period

Fork Choice

CURS3D uses a BlockTree that tracks all known blocks, including forks. The fork choice rule selects the heaviest chain by cumulative proposer stake.

  • Automatic reorg when a heavier fork is detected
  • Finality boundary prevents reorganizations below finalized height
  • Non-canonical branches are pruned after finalization
  • Common ancestor calculation for efficient chain comparison

Cryptography

Signatures

All signatures use CRYSTALS-Dilithium Level 5 (NIST FIPS 204), the highest security level of the NIST post-quantum digital signature standard. This includes block signatures, transaction signatures, and finality votes.

Hashing

SHA-3 Keccak-256 is used for all hashing operations. Blocks use double-hashing: sha3(sha3(bincode(header))). Merkle trees are computed over accounts and contract storage for the state root.

Wallet Encryption

Wallet files at rest are encrypted with AES-256-GCM. The encryption key is derived from the user's password using Argon2 (memory-hard KDF). Legacy plaintext wallets are auto-migrated to encrypted format on first load.

Networking

CURS3D uses libp2p for peer-to-peer communication with the following components:

  • Gossipsub -- Publish/subscribe protocol for broadcasting blocks, transactions, and votes
  • mDNS -- Automatic local peer discovery
  • Bootnodes -- Configurable bootstrap nodes for initial connection

Network Messages

The following message types are exchanged over the network:

  • NewBlock -- Broadcast a newly produced block
  • NewTransaction -- Broadcast a new transaction
  • RequestBlocks / BlockResponse -- Block sync (batches of 50)
  • HeightAnnounce -- Signed height announcement (every 30s) with protocol version
  • SlashingEvidence -- Broadcast equivocation proof
  • FinalityVote -- Validator finality attestation
  • RequestSnapshot / SnapshotManifest / SnapshotChunk -- State sync

Sync Protocol

Blocks are synced in batches of 50 with a 15-second timeout and 3 retries. Block deduplication prevents processing the same block twice. Incompatible peers (different protocol version) are detected and disconnected.

Storage

CURS3D uses sled as its embedded key-value database with schema-versioned storage and automatic migration support.

The following data is persisted:

  • Blocks (by height and hash)
  • Account states
  • Contract storage (per-contract key-value namespaces)
  • Pending transactions
  • Equivocation evidence
  • Chain metadata (height, genesis hash, schema version, genesis config)

REST API

The HTTP REST API runs on port 8080 with full CORS support. All responses follow the format:

response.json
{ "ok": true, "data": { ... } }
{ "ok": false, "error": "message" }

GET /api/status

Returns chain status including chain_id, chain_name, epoch, epoch_start_height, height, finalized_height, latest_hash, genesis_hash, pending_transactions, active_validators, and protocol_version.

terminal
curl http://localhost:8080/api/status

GET /api/blocks?from=0&limit=20

Returns recent blocks with pagination. Maximum limit is 100.

terminal
curl "http://localhost:8080/api/blocks?from=0&limit=20"

GET /api/block/:height

Returns full block detail including all transactions, state root, and merkle root.

terminal
curl http://localhost:8080/api/block/42

GET /api/account/:address

Returns balance, nonce, and staked_balance for any address. Accepts addresses with or without the CUR prefix.

terminal
curl http://localhost:8080/api/account/CUR7f3a1b2c...9c2d

GET /api/tx/:hash

Look up a transaction by its hex-encoded hash. Returns kind, from, to, amount, fee, and receipt.

GET /api/pending

Returns all pending transactions in the mempool.

GET /api/validators

Returns the active validator set with address, public_key, and stake for each validator.

GET /api/faucet/:address

Testnet faucet endpoint. Behavior depends on chain configuration (may be disabled in favor of genesis allocations).

POST /api/tx/submit

Submit a signed transaction as a JSON body. Supports optional Authorization header for auth-token-gated access. Maximum body size: 1 MB.

terminal
curl -X POST http://localhost:8080/api/tx/submit \
  -H "Content-Type: application/json" \
  -d '{"chain_id":"curs3d-devnet","kind":"Transfer",...}'

Genesis Configuration

The genesis block is configured via a JSON file passed to the node with --genesis-config. All fields have sensible defaults.

FieldDefaultDescription
chain_id"curs3d-devnet"Unique chain identifier
chain_name"curs3d-devnet"Human-readable chain name
block_reward50,000,000Block reward in microtokens (50 CUR)
minimum_stake1,000,000,000Min stake in microtokens (1000 CUR)
unstake_delay_blocks10Blocks before unstake completes
epoch_length32Blocks per epoch
jail_duration_blocks64Blocks a slashed validator is jailed
block_gas_limit10,000,000Max gas per block
initial_base_fee_per_gas1Starting base fee
base_fee_change_denominator8Base fee adjustment rate
allocations[]Initial balance and stake allocations
upgrades[]Protocol upgrade schedule
genesis.json
{
  "chain_id": "curs3d-devnet",
  "chain_name": "My Local Chain",
  "block_reward": 50000000,
  "minimum_stake": 1000000000,
  "epoch_length": 32,
  "block_gas_limit": 10000000,
  "allocations": [
    {
      "public_key": "<hex_encoded_dilithium5_pk>",
      "balance": 100000000000,
      "staked_balance": 1000000000
    }
  ],
  "upgrades": [
    {
      "height": 1000,
      "version": 2,
      "description": "Enable feature X"
    }
  ]
}

State Sync

New nodes can fast-sync from a checkpoint instead of replaying the entire chain history.

  • SnapshotManifest -- Describes a state snapshot: height, state root, chunk count, and chunk hashes
  • StateChunks -- Individual pieces of the state, each with a Merkle proof for verification
  • The syncing node requests the manifest, then downloads and verifies each chunk
  • Once all chunks are verified against the state root, the node resumes normal sync from that height

Protocol Governance

CURS3D supports protocol versioning with upgrade-at-height activation.

  • Each ProtocolUpgrade specifies a height, version, and description
  • Upgrades are defined in the genesis config and activate automatically at the specified height
  • Nodes running an older protocol version are detected via HeightAnnounce messages and warned
  • The current protocol version is reported in the /api/status response

Docker

CURS3D ships with a multi-stage Dockerfile and docker-compose configuration for running multi-node networks.

terminal
# Build the Docker image
docker build -t curs3d .

# Run a 2-node network with docker-compose
docker-compose up

# Or run a single node
docker run -p 4337:4337 -p 8080:8080 -p 9545:9545 curs3d \
  curs3d node --validator-wallet /data/wallet.json

The docker-compose setup creates two nodes that automatically discover each other via mDNS and begin syncing.

CI Pipeline

GitHub Actions runs on every push and pull request:

  • cargo check -- Compilation check
  • cargo test -- All 67 tests
  • cargo clippy -- Zero warnings required
  • cargo fmt --check -- Format verification