Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Testing Confidential Voting

Pre-Alpha Disclaimer: This is an early pre-alpha release for exploring the SDK and starting development only. There is no real encryption — all data is completely public and stored as plaintext on-chain. Do not submit any sensitive or real data. Encryption keys and the trust model are not final; do not rely on any encryption guarantees or key material until mainnet. All interfaces, APIs, and data formats are subject to change without notice. The Solana program and all on-chain data will be wiped periodically and everything will be deleted when we transition to Encrypt Alpha 1. This software is provided “as is” without warranty of any kind; use is entirely at your own risk and dWallet Labs assumes no liability for any damages arising from its use.

What you’ll learn

  • Unit testing the cast_vote FHE graph
  • How conditional logic (Select) is tested
  • What each test case validates

Graph unit tests

The #[encrypt_fn] macro generates a function returning the graph bytecode. Test it with a mock evaluator:

#![allow(unused)]
fn main() {
#[test]
fn vote_yes_increments_yes_count() {
    let r = run_mock(
        cast_vote_graph,
        &[10, 5, 1],  // yes_count=10, no_count=5, vote=true
        &[FheType::EUint64, FheType::EUint64, FheType::EBool],
    );
    assert_eq!(r[0], 11);  // yes_count incremented
    assert_eq!(r[1], 5);   // no_count unchanged
}

#[test]
fn vote_no_increments_no_count() {
    let r = run_mock(
        cast_vote_graph,
        &[10, 5, 0],  // yes_count=10, no_count=5, vote=false
        &[FheType::EUint64, FheType::EUint64, FheType::EBool],
    );
    assert_eq!(r[0], 10);  // yes_count unchanged
    assert_eq!(r[1], 6);   // no_count incremented
}

#[test]
fn vote_from_zero() {
    let r = run_mock(
        cast_vote_graph,
        &[0, 0, 1],  // both counters at zero, vote yes
        &[FheType::EUint64, FheType::EUint64, FheType::EBool],
    );
    assert_eq!(r[0], 1);
    assert_eq!(r[1], 0);
}
}

The run_mock helper parses the graph bytecode and evaluates nodes using mock digest encoding. It handles the Select operation (op_type 60) which is what if vote { ... } else { ... } compiles to.

Test matrix

yes_countno_countvotenew_yesnew_noTest
105true115vote_yes_increments_yes_count
105false106vote_no_increments_no_count
00true10vote_from_zero

Graph shape test

#![allow(unused)]
fn main() {
#[test]
fn graph_shape() {
    let d = cast_vote_graph();
    let pg = parse_graph(&d).unwrap();
    assert_eq!(pg.header().num_inputs(), 3);  // yes_count, no_count, vote
    assert_eq!(pg.header().num_outputs(), 2); // new_yes, new_no
}
}

The graph has 3 inputs (two counters + one boolean vote) and 2 outputs (updated counters). This catches signature changes.

Running tests

# Unit tests only (no SBF build needed)
cargo test -p encrypt-voting-anchor

# All example tests
just test-examples

# E2E with LiteSVM
just build-sbf-examples
just test-examples-litesvm

E2E tests

The e2e/ directory contains integration tests that deploy the program, create a proposal, cast multiple votes, close, decrypt, and verify the tallies match. These require the SBF binary and exercise the full Encrypt CPI flow.