What You’ll Learn
- Implementing password policies in the zkVM
- Using PBKDF2 for password hashing
- Privacy-preserving credential verification
- Working with password strength requirements
Overview
This example demonstrates how to:- Check password validity against a compiled policy
- Generate PBKDF2-SHA256 hashes securely
- Share only the hash while keeping the password private
- Produce verifiable receipts of password compliance
The password never leaves your machine and is never revealed in the receipt - only the PBKDF2 hash is public.
How It Works
use password_checker_core::PasswordRequest;
use pbkdf2::pbkdf2_hmac_array;
use risc0_zkvm::{guest::env, sha::Digest};
use sha2::Sha256;
/// Password policy compiled into the guest
const POLICY: PasswordPolicy = PasswordPolicy {
min_length: 3,
max_length: 64,
min_numeric: 2,
min_uppercase: 2,
min_lowercase: 2,
min_special_chars: 1,
};
const PBKDF2_SHA256_ITERATIONS: u32 = 10;
fn main() {
let request: PasswordRequest = env::read();
// Validate password against policy
if !POLICY.is_valid(&request.password) {
panic!("Password invalid. Please try again.");
}
// Generate PBKDF2 hash
let password_hash: Digest = pbkdf2_hmac_array::<Sha256, 32>(
&request.password.as_bytes(),
&request.salt,
PBKDF2_SHA256_ITERATIONS,
)
.into();
env::commit(&password_hash);
env::commit(&request.salt);
}
struct PasswordPolicy {
pub min_length: usize,
pub max_length: usize,
pub min_uppercase: usize,
pub min_lowercase: usize,
pub min_numeric: usize,
pub min_special_chars: usize,
}
impl PasswordPolicy {
pub fn is_valid(&self, pw: &str) -> bool {
let metrics = PasswordMetrics::new(pw);
self.correct_length(pw)
&& (metrics.numeric >= self.min_numeric)
&& (metrics.uppercase >= self.min_uppercase)
&& (metrics.lowercase >= self.min_lowercase)
&& (metrics.special >= self.min_special_chars)
}
}
struct PasswordMetrics {
pub numeric: usize,
pub special: usize,
pub uppercase: usize,
pub lowercase: usize,
}
impl PasswordMetrics {
pub fn new(password: &str) -> Self {
let mut numeric = 0;
let mut special = 0;
let mut uppercase = 0;
let mut lowercase = 0;
for ch in password.chars() {
if ch.is_ascii_digit() {
numeric += 1;
}
if ch.is_ascii_punctuation() {
special += 1;
}
if ch.is_ascii_uppercase() {
uppercase += 1;
}
if ch.is_ascii_lowercase() {
lowercase += 1;
}
}
PasswordMetrics { numeric, special, uppercase, lowercase }
}
}
Running the Example
- Generate a salt
- Validate the password against the policy
- Compute PBKDF2-SHA256 hash
- Produce a receipt with the hash and salt
What Gets Proven?
The receipt proves:-
Policy Compliance: The password meets all requirements:
- Length between 3-64 characters
- At least 2 numeric characters
- At least 2 uppercase letters
- At least 2 lowercase letters
- At least 1 special character
- Hash Validity: The PBKDF2 hash was correctly computed from a compliant password
- Policy Binding: The specific policy is encoded in the Image ID, preventing tampering
Why Use zkVM for This?
Traditional password validation requires trusting the server. With zkVM:- Local Execution: Password checking runs on your machine
- Privacy: The password never leaves your device
- Verifiability: The receipt proves compliance without revealing the password
- Trust Minimization: The recipient verifies the receipt, not the password
Workflow
Security Features
PBKDF2 Key Derivation
PBKDF2 (Password-Based Key Derivation Function 2) provides:- Salt: Prevents rainbow table attacks
- Iterations: Increases computational cost for attackers
- Standard: Widely used and well-tested
This demo uses only 10 iterations for speed. Production systems should use 10,000+ iterations.
Image ID Binding
Changing the policy changes the Image ID:Use Cases
User Registration
Prove your password meets requirements without sending it:Password Reset
Prove your new password is valid before submission:Compliance Auditing
Prove password policies are enforced:Decentralized Auth
Create password-based authentication without central servers:Integration Example
Educational Notice
This is example code for educational purposes. The password policy is intentionally simple. Production systems should:
- Use higher PBKDF2 iteration counts (10,000+)
- Implement comprehensive password policies
- Consider additional security measures
- Follow industry best practices
Video Tutorial
For a detailed walkthrough, see this excerpt from our workshop at ZK HACK III.Next Steps
- Explore JWT validation
- Learn about digital signatures
- Study cryptographic best practices