Skip to content

danielAsaboro/Joi

Repository files navigation

πŸ” Mina Privacy Framework

Privacy-First Application Framework combining Mina zkApps with Zcash Shielded Transactions

Tests TypeScript Mina Zcash

Built for the Privacy Infrastructure & Developer Tools Bounty ($3,000)


🎯 What We Built

A complete privacy-first application framework that combines:

  • Mina Protocol's zkApps for zero-knowledge proofs
  • Zcash's shielded transactions for private value transfers
  • Privacy primitives (Merkle trees, nullifiers, Semaphore)
  • Two working PoC applications with real ZK proofs

βœ… Bounty Requirements - All Met

Requirement Status Evidence
Privacy primitives (Merkle, nullifiers, Semaphore) βœ… Complete 9/9 tests passing
Framework for on-chain privacy apps βœ… Complete 2 zkApp contracts
Shielded Zcash + Mina zkApps integration βœ… Complete 11/11 tests passing
User data self-custody design βœ… Complete Commitment-nullifier patterns
At least 1 PoC application βœ… 2 PoCs Private Voting + Anonymous Credentials

πŸš€ Quick Start for Judges

1. Run All Tests (40/40 passing)

cd joi
npm install
npm test

Expected Output:

Test Suites: 6 passed, 6 total
Tests:       40 passed, 40 total
Time:        ~200 seconds

2. Test with Real Zcash Node (Required for Full Verification)

The framework includes real Zcash integration tested against an actual zcashd node. Here's how to set it up:

Step 1: Create Zcash Configuration

# Create config directory
mkdir -p /tmp/zcash-data

# Create config file with all required settings
cat > /tmp/zcash-data/zcash.conf << 'EOF'
regtest=1
rpcuser=zcashuser
rpcpassword=zcashpass
rpcallowip=0.0.0.0/0
rpcbind=0.0.0.0
nuparams=5ba81b19:1
nuparams=76b809bb:1
nuparams=2bb40e60:1
nuparams=f5b9230b:1
nuparams=e9ff75a6:1
nuparams=c2d6d0b4:1
i-am-aware-zcashd-will-be-replaced-by-zebrad-and-zallet-in-2025=1
allowdeprecated=z_getnewaddress
allowdeprecated=z_getbalance
allowdeprecated=getnewaddress
exportdir=/srv/zcashd/.zcash/exports
txindex=1
EOF

Step 2: Start Zcash Node in Docker

# Start zcashd container (regtest mode)
docker run -d --name zcashd-regtest \
  --platform linux/amd64 \
  -p 18232:18232 \
  -v /tmp/zcash-data:/srv/zcashd/.zcash \
  electriccoinco/zcashd:latest

# Wait for node to start (30-45 seconds)
echo "Waiting for zcashd to start..."
sleep 35

# Verify node is running
curl -s -X POST http://localhost:18232 \
  -u zcashuser:zcashpass \
  -H 'Content-Type: application/json' \
  -d '{"jsonrpc":"2.0","id":"1","method":"getblockchaininfo","params":[]}' | jq '.result.chain'
# Should output: "regtest"

Step 3: Initialize Blockchain and Get Funds

# Set transaction fee (required for NU5)
curl -s -X POST http://localhost:18232 \
  -u zcashuser:zcashpass \
  -H 'Content-Type: application/json' \
  -d '{"jsonrpc":"2.0","id":"1","method":"settxfee","params":[0.001]}'

# Mine 101 blocks to get mature coins (regtest only)
curl -s -X POST http://localhost:18232 \
  -u zcashuser:zcashpass \
  -H 'Content-Type: application/json' \
  -d '{"jsonrpc":"2.0","id":"1","method":"generate","params":[101]}' | jq '.result | length'
# Should output: 101

Step 4: Run Zcash Integration Tests

cd joi

# Set environment variables
export ZCASH_RPC_URL=http://localhost:18232
export ZCASH_RPC_USER=zcashuser
export ZCASH_RPC_PASSWORD=zcashpass

# Run Zcash-specific tests
npm test -- src/integration/zcash-rpc-integration.test.ts

# Expected: 11/11 tests passing

Step 5: Run Full Test Suite (Including Zcash)

# With Zcash node running, all 40 tests will pass
npm test

# Expected: 40/40 tests passing

Troubleshooting

If tests fail to connect:

  • Wait longer for zcashd to start (can take 45+ seconds on first run)
  • Check logs: docker logs zcashd-regtest
  • Verify RPC is accessible: curl http://localhost:18232 (should return error, not connection refused)

If you see "tx unpaid action limit exceeded":

  • The fee was already set in Step 3, but if needed:
    curl -X POST http://localhost:18232 \
      -u zcashuser:zcashpass \
      -d '{"method":"settxfee","params":[0.001]}'

For ARM64 Macs:

  • The --platform linux/amd64 flag enables x86 emulation (slower but works)

To stop the node:

docker stop zcashd-regtest
docker rm zcashd-regtest

3. Run the UI Demo

cd ui
npm install
npm run dev
# Open http://localhost:3000

πŸ“ Project Structure

mina/
β”œβ”€β”€ joi/           # Core Framework
β”‚   β”œβ”€β”€ src/
β”‚   β”‚   β”œβ”€β”€ primitives/          # Privacy building blocks
β”‚   β”‚   β”‚   β”œβ”€β”€ MerkleTree.ts    # 8-level Merkle trees with proofs
β”‚   β”‚   β”‚   β”œβ”€β”€ Nullifier.ts     # Poseidon-based nullifiers
β”‚   β”‚   β”‚   └── Semaphore.ts     # Full Semaphore protocol
β”‚   β”‚   β”œβ”€β”€ voting/              # PoC #1: Private Voting
β”‚   β”‚   β”‚   └── PrivateVoting.ts # zkApp with real proofs
β”‚   β”‚   β”œβ”€β”€ credentials/         # PoC #2: Anonymous Credentials
β”‚   β”‚   β”‚   └── AnonymousCredentials.ts
β”‚   β”‚   β”œβ”€β”€ zcash/               # Zcash Integration
β”‚   β”‚   β”‚   β”œβ”€β”€ ZcashRpcClient.ts    # Full RPC wrapper (277 lines)
β”‚   β”‚   β”‚   └── ShieldedPool.ts      # Shielded tx manager
β”‚   β”‚   └── integration/         # Integration tests with REAL proofs
β”‚   β”‚       β”œβ”€β”€ voting-integration.test.ts
β”‚   β”‚       β”œβ”€β”€ credentials-integration.test.ts
β”‚   β”‚       └── zcash-rpc-integration.test.ts
β”‚   └── INTEGRATION_TEST_RESULTS.md  # Detailed test evidence
β”‚
β”œβ”€β”€ ui/                          # Next.js Demo UI
β”‚   └── app/
β”‚       β”œβ”€β”€ page.tsx             # Landing page
β”‚       β”œβ”€β”€ voting/page.tsx      # Voting demo
β”‚       └── credentials/page.tsx # Credentials demo
β”‚
└── resources/
    └── bounty.md                # Bounty requirements

πŸ”§ Privacy Primitives

Merkle Trees

  • 8-level trees with efficient membership proofs
  • Prove membership without revealing position
  • Poseidon hash for zkSNARK compatibility
const tree = new SimpleMerkleTree(8);
tree.addLeaf(commitment);
tree.build();
const proof = tree.getProof(0); // Proves membership anonymously

Nullifiers

  • Prevent double-spending/voting
  • Collision-resistant via Poseidon
  • No identity linkage
const nullifier = generateNullifier(secret, pollId);
// Public nullifier, secret identity stays private

Semaphore Protocol

  • Anonymous group signaling
  • Identity commitments + nullifiers
  • External nullifier scope

πŸ—³οΈ PoC #1: Private Voting

Location: joi/src/voting/PrivateVoting.ts

Features

  • βœ… Anonymous voter registration
  • βœ… Merkle-proof eligibility verification
  • βœ… Nullifier-based double-vote prevention
  • βœ… Public results, private individual votes

How It Works

1. Voter creates identity commitment (secret stays private)
2. Admin adds commitment to voter Merkle tree
3. Voter generates Merkle proof of eligibility
4. Voter creates nullifier (prevents double-voting)
5. Vote is cast with ZK proof - no identity disclosed!

Test Evidence

npm run test:integration:voting
# Compilation: 43.26 seconds
# Full flow with 3 voters: 86 seconds
# All proofs are REAL (proofsEnabled: true)

🎫 PoC #2: Anonymous Credentials

Location: joi/src/credentials/AnonymousCredentials.ts

Features

  • βœ… Age verification (age β‰₯ 18) without revealing exact age
  • βœ… Threshold proofs for any attribute
  • βœ… Multiple credential holders
  • βœ… No identity disclosure

How It Works

1. User has credential with value (e.g., age = 25)
2. User proves value β‰₯ threshold (e.g., 18)
3. Verifier confirms eligibility
4. Exact value (25) is NEVER revealed

Test Evidence

npm run test:integration:credentials
# Compilation: 49.25 seconds
# 4/4 tests passing with real proofs

πŸŒ‰ Zcash Integration

Location: joi/src/zcash/

What's Implemented

  • ZcashRpcClient.ts (277 lines) - Full RPC wrapper

    • z_getnewaddress / z_getaddressforaccount
    • z_sendmany for shielded transactions
    • z_getbalance for balance queries
    • z_getoperationstatus for async tracking
  • ShieldedPool.ts - High-level shielded transaction manager

    • Address generation
    • Shield/unshield operations
    • Cross-chain proof structure

Real Transactions Tested

We executed real shielded transactions on zcashd regtest:

  1. Transparent β†’ Shielded (Shield)

    • Amount: 0.9 ZEC
    • TXID: 565d329a167730b8b70874cc793d81a63c66ba4153d4c3cd456ef85596e0333b
  2. Shielded β†’ Shielded (with memo)

    • Amount: 0.3 ZEC
    • Memo: "Test shielded tx from Mina Privacy Framework"
    • TXID: 0ae9ffaa6cb4fb49aaf0578313589cdaac442a53a124b8f8a7b13d616a20f887

πŸ§ͺ Test Suite Details

Test Breakdown

Suite Tests Description
Privacy Primitives 9 Merkle trees, nullifiers, Semaphore
Private Voting (Unit) 9 Contract logic tests
Anonymous Credentials 4 Threshold proof tests
Voting Integration 3 Real ZK proofs (~3 min)
Credentials Integration 4 Real ZK proofs (~3 min)
Zcash RPC Integration 11 Real zcashd node

Running Specific Tests

# All tests
npm test

# Just privacy primitives
npm test -- src/primitives/Primitives.test.ts

# Integration tests with real proofs (slower)
npm run test:integration:voting        # ~3 minutes
npm run test:integration:credentials   # ~3 minutes

# Zcash integration (requires running node)
npm test -- src/integration/zcash-rpc-integration.test.ts

πŸ—οΈ Architecture

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                    User Applications                         β”‚
β”‚       (Private Voting, Anonymous Credentials)                β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                         β”‚
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚              Privacy Framework Core                          β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”       β”‚
β”‚  β”‚  Primitives  β”‚  β”‚  Zcash Pool  β”‚  β”‚   zkApps     β”‚       β”‚
β”‚  β”‚  β€’ Merkle    β”‚  β”‚  β€’ Shielded  β”‚  β”‚  β€’ Voting    β”‚       β”‚
β”‚  β”‚  β€’ Nullifier β”‚  β”‚  β€’ RPC       β”‚  β”‚  β€’ Creds     β”‚       β”‚
β”‚  β”‚  β€’ Semaphore β”‚  β”‚  β€’ Bridge    β”‚  β”‚              β”‚       β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜       β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                         β”‚
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                   Blockchain Layer                           β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”           β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”        β”‚
β”‚  β”‚  Mina Protocol   │◄─────────►│  Zcash Network   β”‚        β”‚
β”‚  β”‚  (zkApps)        β”‚   Bridge  β”‚  (Shielded Pool) β”‚        β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜           β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜        β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

πŸ” Design Patterns

1. Commitment-Nullifier Pattern

User commits to identity β†’ Uses nullifier to act β†’ System prevents reuse
     (public)                   (public)             (no identity link)

2. Merkle Witness Pattern

User proves set membership β†’ Without revealing position β†’ Verifier confirms
     (zero-knowledge)            (anonymity)                 (trust)

3. Threshold Proof Pattern

User proves attribute β‰₯ threshold β†’ Without revealing exact value
        (age β‰₯ 18)                      (privacy preserved)

πŸ“‹ Setup Instructions

Prerequisites

  • Node.js 18+
  • npm
  • Docker (for Zcash testing)

Installation

git clone <repo>
cd mina/joi
npm install
npm run build

Running Demos

# Private Voting Demo
npm run demo

# Anonymous Credentials Demo
npm run demo:credentials

Web UI

cd ../ui
npm install
npm run dev
# Open http://localhost:3000

πŸ“„ Key Files for Review

File Lines Purpose
src/primitives/MerkleTree.ts 154 Merkle tree implementation
src/primitives/Nullifier.ts 55 Nullifier/commitment generation
src/voting/PrivateVoting.ts 148 Voting zkApp contract
src/credentials/AnonymousCredentials.ts 194 Credentials zkApp
src/zcash/ZcashRpcClient.ts 302 Zcash RPC wrapper
src/zcash/ShieldedPool.ts 481 Shielded pool manager
src/integration/*.test.ts ~400 Integration tests with real proofs

🎯 What Makes This Submission Strong

  1. Real ZK Proofs - Integration tests run with proofsEnabled: true (most projects mock this)

  2. Real Zcash Integration - Tested against actual zcashd node with real transactions

  3. Two PoC Applications - Exceeds requirement of "at least 1 PoC"

  4. 40/40 Tests Passing - No mocks, no stubs, no skipped tests

  5. Production-Quality Code - TypeScript, well-documented, clean architecture

  6. Working UI - Visual demo for judges


πŸ“œ License

Apache 2.0 - See LICENSE


Privacy by Design, Privacy by Default

Built with ❀️ for the Mina zkApps Hackathon

About

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors