A simple digital signature scheme that proves message authenticity and integrity using the RISC Zero zkVM.Documentation Index
Fetch the complete documentation index at: https://mintlify.com/risc0/risc0/llms.txt
Use this file to discover all available pages before exploring further.
What You’ll Learn
- How to build digital signature schemes with zkVM
- Using SHA-256 hashing in the guest
- Command-line argument parsing
- Verifying signatures with receipts
Overview
From Wikipedia:A digital signature is a mathematical scheme for verifying the authenticity of digital messages or documents. A valid digital signature gives a recipient very high confidence that the message was created by a known sender (authenticity), and that the message was not altered in transit (integrity).This example implements a simple signature scheme where:
- The signer’s identity is the SHA-256 hash of their passphrase
- The message is signed by proving knowledge of the passphrase
- The receipt proves both authenticity and integrity
How It Works
The guest receives the passphrase and message, computes the identity hash, and commits both to the journal:
use digital_signature_core::{SignMessageCommit, SigningRequest};
use risc0_zkvm::guest::env;
use risc0_zkvm::sha::{Impl, Sha256};
fn main() {
let request: SigningRequest = env::read();
env::commit(&SignMessageCommit {
identity: *Impl::hash_bytes(request.passphrase.as_bytes()),
msg: request.msg,
});
}
use clap::Parser;
use digital_signature::sign;
use sha2::{Digest, Sha256};
#[derive(Parser)]
struct Cli {
#[arg()]
message: String,
#[arg(long)]
passphrase: String,
}
fn main() {
let args = Cli::parse();
let signing_receipt = sign(&args.passphrase, &args.message).unwrap();
println!("Inputs");
println!("\tmessage: {:?}", args.message);
println!("Commitment:");
println!("\tmessage: {:?}", &signing_receipt.get_message().unwrap());
println!("\tidentity: {:?}", &signing_receipt.get_identity().unwrap());
// Verify the message hash matches
let message_hash = &signing_receipt.get_message().unwrap();
let expected_message_hash = Sha256::digest(args.message);
if message_hash.as_bytes() != expected_message_hash.as_slice() {
eprintln!("Message commitment does not match!");
std::process::exit(1);
}
println!("\tmessage: valid");
// Verify the receipt
if signing_receipt.verify().is_err() {
eprintln!("Receipt is invalid!");
std::process::exit(1);
}
println!("\treceipt: valid");
}
Running the Example
What Gets Proven?
The receipt proves:- Authenticity: The signer possesses the passphrase (without revealing it)
- Integrity: The message was signed by someone with that specific identity
- Non-repudiation: The signature cannot be forged without the passphrase
- Message hash: SHA-256 of the signed message
- Identity: SHA-256 of the passphrase (public key equivalent)
- Seal: Cryptographic proof of correct execution
Signature Components
Identity (Public Key)
Message Commitment
Receipt (Signature)
The zkVM receipt serves as the digital signature. It proves:- The identity was computed from a known passphrase
- The message hash corresponds to the signed message
- Both were processed by the zkVM correctly
Verification Process
Anyone can verify the signature by:- Checking the receipt verifies correctly
- Extracting the identity and message hash from the journal
- Confirming the message hash matches the message
- Trusting that the identity represents the claimed sender
Security Considerations
This is an educational example. Production systems should use established cryptographic schemes like Ed25519 or ECDSA.
- Passphrase strength determines security
- No key rotation mechanism
- Identity binding requires external PKI
- No forward secrecy
Use Cases
Document Signing
Prove you authored a document without exposing your signing key:API Authentication
Authenticate API requests with zero-knowledge proofs:Blockchain Transactions
Sign transactions with privacy-preserving signatures:Comparison to Traditional Signatures
| Feature | Traditional (ECDSA/Ed25519) | zkVM Signature |
|---|---|---|
| Key Generation | Specialized crypto | Any computation |
| Signature Size | ~64 bytes | ~128 KB (receipt) |
| Verification Speed | Microseconds | Milliseconds |
| Flexibility | Fixed algorithm | Arbitrary logic |
| Privacy | Public key visible | Can hide details |
Next Steps
- Learn about JWT validation
- Explore password checking
- Study ECDSA examples in the repository