Skip to main content

cougr_core/zk/
traits.rs

1//! Generic trait for game circuits and shared scalar encoding helpers.
2
3use soroban_sdk::{BytesN, Env};
4
5use super::error::ZKError;
6use super::groth16::verify_groth16;
7use super::types::{Groth16Proof, Scalar, VerificationKey};
8
9/// Generic trait for game circuits that verify ZK proofs on-chain.
10///
11/// Implementors provide a verification key. The default `verify_with_inputs`
12/// method handles the common Groth16 verification flow.
13///
14/// # Example
15/// ```no_run
16/// use cougr_core::zk::{G1Point, G2Point, Scalar};
17/// use cougr_core::zk::experimental::{GameCircuit, Groth16Proof, MovementCircuit, VerificationKey};
18/// use soroban_sdk::{BytesN, Env, Vec};
19///
20/// let env = Env::default();
21/// let g1 = G1Point { bytes: BytesN::from_array(&env, &[0u8; 64]) };
22/// let g2 = G2Point { bytes: BytesN::from_array(&env, &[0u8; 128]) };
23/// let vk = VerificationKey {
24///     alpha: g1.clone(),
25///     beta: g2.clone(),
26///     gamma: g2.clone(),
27///     delta: g2,
28///     ic: Vec::from_array(&env, [g1.clone()]),
29/// };
30/// let proof = Groth16Proof { a: g1.clone(), b: vk.beta.clone(), c: g1 };
31/// let public_inputs: [Scalar; 0] = [];
32/// let circuit = MovementCircuit::new(vk, 10);
33/// let _result = circuit.verify_with_inputs(&env, &proof, &public_inputs)?;
34/// # Ok::<(), cougr_core::zk::ZKError>(())
35/// ```
36pub trait GameCircuit {
37    /// Get the verification key for this circuit.
38    fn verification_key(&self) -> &VerificationKey;
39
40    /// Verify a proof against this circuit's VK and the given public inputs.
41    ///
42    /// Default implementation delegates to `verify_groth16`.
43    fn verify_with_inputs(
44        &self,
45        env: &Env,
46        proof: &Groth16Proof,
47        public_inputs: &[Scalar],
48    ) -> Result<bool, ZKError> {
49        verify_groth16(env, self.verification_key(), proof, public_inputs)
50    }
51}
52
53/// Convert a `u32` value to a BN254 scalar (little-endian, zero-padded to 32 bytes).
54pub fn u32_to_scalar(env: &Env, val: u32) -> Scalar {
55    let mut bytes = [0u8; 32];
56    bytes[..4].copy_from_slice(&val.to_le_bytes());
57    Scalar {
58        bytes: BytesN::from_array(env, &bytes),
59    }
60}
61
62/// Convert an `i32` value to a BN254 scalar (little-endian, zero-padded to 32 bytes).
63pub fn i32_to_scalar(env: &Env, val: i32) -> Scalar {
64    let mut bytes = [0u8; 32];
65    bytes[..4].copy_from_slice(&val.to_le_bytes());
66    Scalar {
67        bytes: BytesN::from_array(env, &bytes),
68    }
69}
70
71/// Convert a `u64` value to a BN254 scalar (little-endian, zero-padded to 32 bytes).
72pub fn u64_to_scalar(env: &Env, val: u64) -> Scalar {
73    let mut bytes = [0u8; 32];
74    bytes[..8].copy_from_slice(&val.to_le_bytes());
75    Scalar {
76        bytes: BytesN::from_array(env, &bytes),
77    }
78}
79
80/// Convert a `BytesN<32>` directly to a `Scalar` (identity mapping).
81pub fn bytes32_to_scalar(val: &BytesN<32>) -> Scalar {
82    Scalar { bytes: val.clone() }
83}
84
85#[cfg(test)]
86mod tests {
87    use super::*;
88    use soroban_sdk::Env;
89
90    #[test]
91    fn test_u32_to_scalar() {
92        let env = Env::default();
93        let s = u32_to_scalar(&env, 42);
94        assert_eq!(s.bytes.len(), 32);
95        let arr = s.bytes.to_array();
96        assert_eq!(arr[0], 42);
97        assert_eq!(arr[1], 0);
98    }
99
100    #[test]
101    fn test_i32_to_scalar_positive() {
102        let env = Env::default();
103        let s = i32_to_scalar(&env, 100);
104        assert_eq!(s.bytes.len(), 32);
105        let arr = s.bytes.to_array();
106        assert_eq!(arr[0], 100);
107    }
108
109    #[test]
110    fn test_i32_to_scalar_negative() {
111        let env = Env::default();
112        let s = i32_to_scalar(&env, -1);
113        let arr = s.bytes.to_array();
114        // -1 in little-endian i32 = [0xFF, 0xFF, 0xFF, 0xFF]
115        assert_eq!(arr[0], 0xFF);
116        assert_eq!(arr[1], 0xFF);
117        assert_eq!(arr[2], 0xFF);
118        assert_eq!(arr[3], 0xFF);
119    }
120
121    #[test]
122    fn test_bytes32_to_scalar() {
123        let env = Env::default();
124        let b = BytesN::from_array(&env, &[7u8; 32]);
125        let s = bytes32_to_scalar(&b);
126        assert_eq!(s.bytes, b);
127    }
128
129    #[test]
130    fn test_u64_to_scalar() {
131        let env = Env::default();
132        let s = u64_to_scalar(&env, 0x0102_0304_0506_0708);
133        let arr = s.bytes.to_array();
134        assert_eq!(arr[..8], [0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01]);
135    }
136}