signedby_sdk/verifier.rs
1//! Groth16 proof verifier
2//!
3//! Verification is fully local — no network calls required.
4//! The verification key (4KB) can be bundled with your application.
5
6use ark_bn254::Bn254;
7use ark_groth16::Groth16;
8use ark_snark::SNARK;
9
10use crate::error::SdkError;
11use crate::verification_key::VerificationKey;
12use crate::proof::{Groth16Proof, PublicInputs, VerificationResult};
13
14/// Groth16 proof verifier
15///
16/// Create once with a verification key, then verify multiple proofs.
17///
18/// # Example
19///
20/// ```rust,ignore
21/// use signedby_sdk::{Verifier, VerificationKey};
22///
23/// let vk = VerificationKey::from_json(vk_json)?;
24/// let verifier = Verifier::new(vk);
25///
26/// let result = verifier.verify(&proof, &public_inputs)?;
27/// assert!(result.valid);
28/// ```
29pub struct Verifier {
30 verification_key: VerificationKey,
31}
32
33impl Verifier {
34 /// Create a new verifier with the given verification key
35 pub fn new(vk: VerificationKey) -> Self {
36 Self { verification_key: vk }
37 }
38
39 /// Verify a Groth16 proof
40 ///
41 /// Returns a `VerificationResult` with:
42 /// - `valid`: whether the proof is cryptographically valid
43 /// - `npub`: the user's pseudonymous identifier (NOSTR public key)
44 /// - `merkle_root`: the group membership tree they proved membership in
45 /// - `session_binding`: prevents proof replay across sessions
46 pub fn verify(
47 &self,
48 proof: &Groth16Proof,
49 public_inputs: &PublicInputs,
50 ) -> Result<VerificationResult, SdkError> {
51 // Verify the Groth16 proof
52 let valid = Groth16::<Bn254>::verify(
53 &self.verification_key.inner,
54 &public_inputs.values,
55 &proof.inner,
56 ).map_err(|e| SdkError::VerificationFailed(format!("Verification error: {:?}", e)))?;
57
58 let npub = public_inputs.npub_bech32()?;
59
60 Ok(VerificationResult {
61 valid,
62 npub_hex: public_inputs.npub_hex.clone(),
63 npub,
64 merkle_root: public_inputs.merkle_root.clone(),
65 session_binding: public_inputs.session_binding.clone(),
66 })
67 }
68
69 /// Verify proof from JSON strings (convenience method)
70 pub fn verify_json(
71 &self,
72 proof_json: &str,
73 public_inputs_json: &str,
74 ) -> Result<VerificationResult, SdkError> {
75 let proof = Groth16Proof::from_json(proof_json)?;
76 let public_inputs = PublicInputs::from_json(public_inputs_json)?;
77 self.verify(&proof, &public_inputs)
78 }
79}
80
81#[cfg(test)]
82mod tests {
83 use super::*;
84
85 // Note: Full integration tests require actual proof data
86 // See examples/ for end-to-end verification demos
87
88 #[test]
89 fn test_verifier_creation() {
90 // This test would need a real verification key
91 // Just testing the API compiles correctly
92 }
93}