Skip to main content

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}