Skip to main content

cougr_core/zk/
interfaces.rs

1use soroban_sdk::{Bytes, BytesN, Env};
2
3use super::commitment::{pedersen_commit, pedersen_verify, PedersenCommitment, PedersenParams};
4use super::error::ZKError;
5use super::groth16::verify_groth16;
6use super::merkle::proof::{verify_inclusion, OnChainMerkleProof};
7use super::types::{Groth16Proof, Scalar, VerificationKey};
8
9/// Stable interface for commitment schemes used by privacy primitives.
10///
11/// The trait contract is intentionally narrow:
12/// - implementations must define exact parameter and opening semantics
13/// - malformed inputs must return `Err(ZKError)` rather than silently succeeding
14/// - `verify` must return `Ok(false)` only for a well-formed but invalid opening
15pub trait CommitmentScheme {
16    type Parameters;
17    type Value;
18    type Opening;
19    type Commitment;
20
21    fn commit(
22        &self,
23        env: &Env,
24        params: &Self::Parameters,
25        value: &Self::Value,
26        opening: &Self::Opening,
27    ) -> Result<Self::Commitment, ZKError>;
28
29    fn verify(
30        &self,
31        env: &Env,
32        params: &Self::Parameters,
33        commitment: &Self::Commitment,
34        value: &Self::Value,
35        opening: &Self::Opening,
36    ) -> Result<bool, ZKError>;
37}
38
39/// Stable interface for Merkle inclusion proof verification.
40///
41/// Implementations must reject malformed proofs with `Err(ZKError)` and
42/// return `Ok(false)` only when the proof is well-formed but does not match
43/// the expected root.
44pub trait MerkleProofVerifier {
45    type Proof;
46    type Root;
47
48    fn verify(
49        &self,
50        env: &Env,
51        proof: &Self::Proof,
52        expected_root: &Self::Root,
53    ) -> Result<bool, ZKError>;
54}
55
56/// Stable interface for hidden-state encoding.
57///
58/// Hidden-state codecs define the exact byte-level representation used before
59/// a caller commits to or stores private state metadata.
60pub trait HiddenStateCodec {
61    type State;
62
63    fn encode(&self, env: &Env, state: &Self::State) -> Result<Bytes, ZKError>;
64    fn decode(&self, env: &Env, encoded: &Bytes) -> Result<Self::State, ZKError>;
65}
66
67/// Stable interface for proof verifiers.
68///
69/// The interface itself is stable even when specific proof systems are not.
70/// This allows callers to depend on a narrow verification contract while
71/// choosing whether an implementation belongs to the stable or experimental
72/// privacy surface.
73pub trait ProofVerifier {
74    type VerificationKey;
75    type Proof;
76    type PublicInput;
77
78    fn verify(
79        &self,
80        env: &Env,
81        verification_key: &Self::VerificationKey,
82        proof: &Self::Proof,
83        public_inputs: &[Self::PublicInput],
84    ) -> Result<bool, ZKError>;
85}
86
87/// Stable Pedersen commitment scheme adapter.
88#[derive(Clone, Copy, Debug, Default)]
89pub struct PedersenCommitmentScheme;
90
91impl CommitmentScheme for PedersenCommitmentScheme {
92    type Parameters = PedersenParams;
93    type Value = Scalar;
94    type Opening = Scalar;
95    type Commitment = PedersenCommitment;
96
97    fn commit(
98        &self,
99        env: &Env,
100        params: &Self::Parameters,
101        value: &Self::Value,
102        opening: &Self::Opening,
103    ) -> Result<Self::Commitment, ZKError> {
104        pedersen_commit(env, params, value, opening)
105    }
106
107    fn verify(
108        &self,
109        env: &Env,
110        params: &Self::Parameters,
111        commitment: &Self::Commitment,
112        value: &Self::Value,
113        opening: &Self::Opening,
114    ) -> Result<bool, ZKError> {
115        pedersen_verify(env, params, commitment, value, opening)
116    }
117}
118
119/// Stable SHA256 Merkle inclusion verifier adapter.
120#[derive(Clone, Copy, Debug, Default)]
121pub struct Sha256MerkleProofVerifier;
122
123impl MerkleProofVerifier for Sha256MerkleProofVerifier {
124    type Proof = OnChainMerkleProof;
125    type Root = BytesN<32>;
126
127    fn verify(
128        &self,
129        env: &Env,
130        proof: &Self::Proof,
131        expected_root: &Self::Root,
132    ) -> Result<bool, ZKError> {
133        verify_inclusion(env, proof, expected_root)
134    }
135}
136
137/// Fixed-width hidden-state codec for 32-byte payloads.
138///
139/// This is intentionally conservative: it only accepts a `BytesN<32>` state,
140/// ensuring the encoded representation is deterministic and length-safe.
141#[derive(Clone, Copy, Debug, Default)]
142pub struct Bytes32HiddenStateCodec;
143
144impl HiddenStateCodec for Bytes32HiddenStateCodec {
145    type State = BytesN<32>;
146
147    fn encode(&self, env: &Env, state: &Self::State) -> Result<Bytes, ZKError> {
148        Ok(Bytes::from_slice(env, &state.to_array()))
149    }
150
151    fn decode(&self, env: &Env, encoded: &Bytes) -> Result<Self::State, ZKError> {
152        if encoded.len() != 32 {
153            return Err(ZKError::InvalidInput);
154        }
155
156        let mut bytes = [0u8; 32];
157        for i in 0..32u32 {
158            bytes[i as usize] = encoded.get(i).ok_or(ZKError::InvalidInput)?;
159        }
160        Ok(BytesN::from_array(env, &bytes))
161    }
162}
163
164/// Experimental Groth16 verifier adapter.
165///
166/// The interface is explicit, but the underlying proof system remains
167/// experimental until its assumptions and host-function behavior are hardened
168/// further for a stable contract claim.
169#[derive(Clone, Copy, Debug, Default)]
170pub struct Groth16ProofVerifier;
171
172impl ProofVerifier for Groth16ProofVerifier {
173    type VerificationKey = VerificationKey;
174    type Proof = Groth16Proof;
175    type PublicInput = Scalar;
176
177    fn verify(
178        &self,
179        env: &Env,
180        verification_key: &Self::VerificationKey,
181        proof: &Self::Proof,
182        public_inputs: &[Self::PublicInput],
183    ) -> Result<bool, ZKError> {
184        verify_groth16(env, verification_key, proof, public_inputs)
185    }
186}
187
188#[cfg(test)]
189mod tests {
190    use super::*;
191    use soroban_sdk::{BytesN, Env, Vec};
192
193    #[test]
194    fn test_bytes32_hidden_state_codec_roundtrip() {
195        let env = Env::default();
196        let codec = Bytes32HiddenStateCodec;
197        let state = BytesN::from_array(&env, &[0xAB; 32]);
198
199        let encoded = codec.encode(&env, &state).unwrap();
200        let decoded = codec.decode(&env, &encoded).unwrap();
201
202        assert_eq!(decoded, state);
203    }
204
205    #[test]
206    fn test_bytes32_hidden_state_codec_rejects_wrong_length() {
207        let env = Env::default();
208        let codec = Bytes32HiddenStateCodec;
209        let encoded = Bytes::from_slice(&env, &[1, 2, 3]);
210
211        let result = codec.decode(&env, &encoded);
212        assert_eq!(result, Err(ZKError::InvalidInput));
213    }
214
215    #[test]
216    fn test_sha256_merkle_verifier_rejects_malformed_proof() {
217        let env = Env::default();
218        let verifier = Sha256MerkleProofVerifier;
219        let proof = OnChainMerkleProof {
220            siblings: Vec::new(&env),
221            path_bits: 0,
222            leaf: BytesN::from_array(&env, &[1u8; 32]),
223            leaf_index: 0,
224            depth: 1,
225        };
226        let root = BytesN::from_array(&env, &[0u8; 32]);
227
228        let result = verifier.verify(&env, &proof, &root);
229        assert_eq!(result, Err(ZKError::InvalidProofLength));
230    }
231}