Skip to main content
Nullis is a monorepo: a Soroban contract (Rust), a Noir circuit, and TypeScript packages (@nullis/core, @nullis/sdk, @nullis/issuer, @nullis/cli). You can evaluate the whole thing with one command, or reproduce a live testnet payment end to end.

Prerequisites

  • Node.js 20+ and npm
  • Rust with the wasm32v1-none target and the Soroban / Stellar CLI
  • Noir nargo 1.0.0-beta.9
  • Barretenberg bb 0.87.0
The deterministic test suite runs without these — it uses a mock-verifier build feature for the contract-logic tests, and committed proof artifacts for the real-ZK tests.

One-command evaluation

The fastest way to see everything is green:
1

Clone

git clone https://github.com/Enoch208/nullis.git
cd nullis
2

Run the full suite + print live evidence

npm run demo:e2e
This builds and runs the full deterministic test suite (Rust + TypeScript, including the cross-implementation hash gate) and prints the live Stellar testnet evidence — contract IDs and transaction links.
demo:e2e runs the real-ZK on-chain verification test, the 22-test contract-logic negative suite, and the TypeScript cross-impl hash tests. Green across all three means the ZK layer, the contract, and the SDK agree byte-for-byte.

Reproduce a live real-ZK payment

Generate a fresh proof and submit it to the deployed contract on testnet:
1

Build the tree, witness, and inputs

node scripts/live-real-zk.mjs
Produces the Merkle tree, witness, Prover.toml, and public_inputs.json / action.json.
2

Generate the proof (Noir + Barretenberg)

cd circuits/nullis && nargo execute && \
  bb prove --scheme ultra_honk --oracle_hash keccak \
    --bytecode_path target/nullis.json --witness_path target/nullis.gz \
    --output_path target --output_format bytes_and_fields
3

Verify and execute on-chain

stellar contract invoke --id <NULLIS> --source <you> --network testnet -- \
  verify_and_execute \
  --policy_id 1001 --proof-file-path circuits/nullis/target/proof \
  --public_inputs-file-path public_inputs.json --action-file-path action.json
The receipt returns result: VERIFIED, executed: true — the asset moved, gated by a real zero-knowledge proof.

Or use the SDK — one line

import { Nullis } from "@nullis/sdk";

const nullis = new Nullis({ contractId, secretKey });
const receipt = await nullis.verifyAndExecute({ policyId, publicInputs, proof, action });
// receipt.result === "VERIFIED", receipt.executed === true  → the asset moved

SDK reference

The full @nullis/sdk surface — read-only calls, request building, and verifyAndExecute.

Where to go next

How it works

The architecture and the atomic primitive.

The evidence

Every claim as a real, clickable testnet transaction.