This is a submission for the Midnight Network "Privacy First" Challenge - Enhance the Ecosystem prompt
📌 Summary:
An interactive playground that helps developers first test out Midnight zero-knowledge proof circuits with mock circuits that replicate real-world use cases around privacy.
🔎 Scenarios:
The Playground has 3 scenarios:
- Confidential Voting - Demonstrate private voter credentials while proving eligibility.
- Sealed Bid Auction - Show how bid amounts remain secret until reveal phase.
- Anonymous Identity Verification - Prove age/eligibility without revealing personal data.
Each scenario comes with a step-by-step proof generation with detailed explanations.
🔑 Key Features Implementation:
1. Private Input Handling & Double-Entry Prevention -
This code implements a nullifier system - a cryptographic mechanism used to prevent duplicate actions or "double-spending" type problems in various scenarios.
Generates unique identifiers (nullifiers) that can be publicly checked to ensure someone hasn't already performed a specific action, without revealing their actual identity.
client/src/hooks/useProofGeneration.ts
// Comprehensive nullifier system preventing double submissions
const nullifierCheck = (scenario: string, inputs: Record<string, string>) => {
switch (scenario) {
case 'voting':
// Prevents same voter ID from voting twice
nullifier = `voting_${inputs.voter_id}_${inputs.private_credentials}`;
errorMessage = 'This voter ID has already cast a vote. Double voting is not allowed.';
break;
case 'auction':
// Prevents same bidder from bidding multiple times
nullifier = `auction_${inputs.bidder_secret}_${inputs.private_bidder_identity}`;
errorMessage = 'This bidder has already submitted a bid. Multiple bids not allowed.';
break;
case 'identity':
// Prevents duplicate identity verifications
nullifier = `identity_${inputs.private_ssn}_${inputs.birth_cert_hash}`;
errorMessage = 'This identity has already been verified. Duplicate attempts blocked.';
break;
}
return { nullifier, errorMessage };
};
2. Interactive Circuit Animation -
This is a functional React component that takes data as props and renders a visual node with connection handles.
- Animation System:
- - Conditionally applies animate-pulse and ring styling when data.isAnimated is true
- - Creates a pulsing effect with a glowing ring around animated nodes
- - Uses Tailwind CSS for smooth transitions (transition-all duration-300)
- Privacy Indicators:
- - Red dot badge: Small circular indicator in top-right corner with "P" label.
- - Text label: Shows "Private Input" below the node content.
- - Both only appear when data.isPrivate is true.
- - Uses red color scheme to visually distinguish private data.
client/src/components/CircuitDesigner.tsx
// Circuit nodes with privacy indicators and animation support
const CircuitNode: React.FC<CircuitNodeProps> = ({ data }) => {
return (
<Card className={`circuit-node transition-all duration-300
${data.isAnimated ? 'animate-pulse ring-2 ring-primary/50' : ''}`}>
<Handle type="target" position={Position.Left} />
<Handle type="source" position={Position.Right} />
{/* Private data indicator */}
{data.isPrivate && (
<div className="absolute -top-1 -right-1 w-3 h-3 bg-red-500 rounded-full">
<span className="text-[8px] text-white font-bold">P</span>
</div>
)}
{/* Privacy labels */}
{data.isPrivate && (
<div className="text-[10px] text-red-500 font-medium mt-1">Private Input</div>
)}
</Card>
);
};
3. Privacy-Emphasized UI Components -
The privacy-aware input fields for cryptographic applications automatically masks private text inputs as password fields (showing dots instead of plain text), apply distinctive red styling to visually distinguish sensitive data and include explanatory text reassuring users that their private information "remains encrypted and hidden during proof generation."
client/src/components/ScenarioSidebar.tsx
// Private inputs with visual encryption
<Input
type={input.isPrivate && input.type === 'text' ? 'password' : input.type}
className={input.isPrivate ? 'border-red-500 bg-red-50 dark:bg-red-950/20' : ''}
placeholder={input.isPrivate ? 'Private data - encrypted' : ''}
/>
{/* Privacy explanation for each private input */}
{input.isPrivate && (
<div className="text-xs text-red-500 mt-1 flex items-center">
<span className="w-2 h-2 bg-red-500 rounded-full mr-1"></span>
This data remains encrypted and hidden during proof generation
</div>
)}
4. Zero-Knowledge Scenarios with Real Privacy Examples -
The scenario configuration file exports an array of three privacy-preserving use cases, each containing complete UI and circuit specifications.
Each scenario includes multiple components: visual circuit representation with nodes and edges showing data flow through cryptographic operations, step-by-step proof generation process with timing and status updates, circuit code written in Midnight Compact Language demonstrating the actual cryptographic logic, and input field definitions distinguishing between public and private data fields.
The Confidential Voting scenario demonstrates anonymous voting where private voter credentials and choices are processed through hash functions and nullifier checks to prevent double-voting while maintaining ballot secrecy.
The Sealed Bid Auction scenario shows how bidders can submit private bids with commitments and range proofs to ensure minimum bid requirements without revealing actual amounts until the reveal phase.
The Anonymous Identity scenario enables age verification and registry membership checks without exposing personal details like exact age or SSN, using Merkle proofs for membership verification.
client/src/data/scenarios.ts
// Confidential Voting - Real privacy protection
{
id: 'voting',
name: 'Confidential Voting',
inputs: [
{ label: 'Voter ID', key: 'voter_id', type: 'text', defaultValue: 'voter_12345' },
{ label: 'Private Credentials', key: 'private_credentials', type: 'text',
defaultValue: 'SSN:***-**-1234', isPrivate: true },
{ label: 'Secret Nullifier', key: 'secret_nullifier', type: 'text',
defaultValue: 'secret_nonce_abc123', isPrivate: true },
{ label: 'Candidate Choice', key: 'choice', type: 'select',
options: ['Candidate A', 'Candidate B', 'Candidate C'] }
],
code: `// Midnight Compact Language
circuit ConfidentialVote {
private input voter_id: Field;
private input choice: Field;
private input nullifier_secret: Field;
public input nullifier_hash: Field;
public output commitment: Field;
// Privacy-preserving computations
let vote_hash = hash(voter_id, choice);
let nullifier = hash(voter_id, nullifier_secret);
assert(nullifier == nullifier_hash);
commitment = hash(vote_hash, nullifier);
}`
}
// Anonymous Identity Verification - Age proof without revealing exact age
{
id: 'identity',
name: 'Anonymous Identity Verification',
inputs: [
{ label: 'Private Age', key: 'age', type: 'number', defaultValue: '25', isPrivate: true },
{ label: 'Private SSN', key: 'private_ssn', type: 'text',
defaultValue: '***-**-5678', isPrivate: true },
{ label: 'Private Birth Certificate Hash', key: 'birth_cert_hash', type: 'text',
defaultValue: '0x8a7f...b3c2', isPrivate: true }
],
code: `circuit AnonymousIdentity {
private input age: Field;
private input identity_hash: Field;
// Verify age >= 18 WITHOUT revealing actual age
assert(age >= 18);
// Generate anonymous verification token
anonymous_token = hash(identity_hash, age);
}`
}
🎓 Educational Impact:
This Playground demonstrates real-world zero-knowledge applications:
- Confidential Voting: Proves vote validity without revealing choice or voter identity.
- Private Auctions: Enables fair bidding while keeping amounts secret.
- Anonymous Identity: Verifies age/credentials without exposing personal data.
- Anti-Replay Protection: Prevents double submissions across all scenarios.
Top comments (0)