Protocol Design

Murena's shielded transfers hide amounts and linkages while enforcing balance with zk proofs.

Primitives

  • Spend key (sk_spend) — authorizes spending of notes.
  • View key (vk_view) — optional, read-only; enables selective disclosure.
  • Commitment — opaque note commitment stored on-chain.
  • Nullifier — one-time marker that a note was spent.

Constraints (informal)

  1. Inputs exist in the current Merkle tree (membership proof).
  2. Inputs are owned by the prover (knows sk_spend).
  3. Inputs were not previously spent (nullifier uniqueness).
  4. Sum(inputs) = Sum(outputs) (conservation)
  5. Optional: range/amount padding to reduce leakage.

Pseudo-circuit sketch

Given: root, pathElements[], pathIndices[], inputNotes[], outputNotes[]
Prove:
  - For each input: MerklePath(root, commitment(inputNote)) == true
  - nullifier = H(sk_spend || note_id)
  - Σ input.value == Σ output.value
  - Bind memo_hash to outputNote (encrypted off-chain)
Public signals: root, nullifiers[], outputCommitments[]

On-chain verification (Rust sketch)

// NOT PRODUCTION — illustrative only
pub fn process_verify(ctx: Context<Verify>, proof: Vec<u8>, pub_signals: Vec<[u8;32]>) -> Result<()> {
    // 1) Verify zk proof (e.g., Groth16/altbn128) via builtin or custom crate
    require!(verify_groth16(&proof, &pub_signals)?, ErrorCode::InvalidProof);

    // 2) Extract root, nullifiers, outputs from pub_signals
    let root = PubSig::root(&pub_signals)?;
    let nullifiers = PubSig::nullifiers(&pub_signals)?;
    let outputs = PubSig::outputs(&pub_signals)?;

    // 3) Check root is known
    require!(ctx.accounts.global.roots.contains(&root), ErrorCode::UnknownRoot);

    // 4) Enforce nullifier uniqueness
    for n in nullifiers.iter() {
        require!(!ctx.accounts.nullifier_set.contains(n), ErrorCode::NullifierUsed);
        ctx.accounts.nullifier_set.insert(*n);
    }

    // 5) Append outputs to commitment tree (or event for off-chain tree updater)
    emit!(NewCommitments { commitments: outputs });

    Ok(())
}