soroban_utils/
utils.rs

1use ark_bn254::{G1Affine as ArkG1Affine, G2Affine as ArkG2Affine};
2use ark_ff::{BigInteger, fields::PrimeField};
3use contract_types::VerificationKeyBytes;
4use soroban_sdk::{Address, BytesN, Env, IntoVal, TryFromVal, Val, Vec, contract, contractimpl};
5
6/// Update the contract administrator
7///
8/// Changes the admin address to a new address. Only the current admin
9/// can call this function.
10///
11/// # Arguments
12/// * `env` - The Soroban environment
13/// * `admin_key` - Storage key for the admin address (e.g., `DataKey::Admin`)
14/// * `new_admin` - Address of the new administrator
15///
16/// # Panics
17/// Panics if the caller is not the current admin
18pub fn update_admin<K>(env: &Env, admin_key: &K, new_admin: &Address)
19where
20    K: IntoVal<Env, Val> + TryFromVal<Env, Val> + Clone,
21{
22    let store = env.storage().persistent();
23    let admin: Address = store.get(admin_key).unwrap();
24    admin.require_auth();
25
26    // Update admin address
27    store.set(admin_key, new_admin);
28}
29
30/// Mock token contract for testing purposes
31#[contract]
32pub struct MockToken;
33
34#[contractimpl]
35impl MockToken {
36    pub fn balance(_env: Env, _id: Address) -> i128 {
37        0
38    }
39
40    pub fn transfer(_env: Env, _from: Address, _to: Address, _amount: i128) {}
41
42    pub fn transfer_from(_env: Env, _from: Address, _to: Address, _amount: i128) {}
43
44    pub fn approve(_env: Env, _from: Address, _spender: Address, _amount: i128) {}
45
46    pub fn allowance(_env: Env, _from: Address, _spender: Address) -> i128 {
47        0
48    }
49}
50
51pub fn g1_bytes_from_ark(p: ArkG1Affine) -> [u8; 64] {
52    let mut out = [0u8; 64];
53    let x_bytes: [u8; 32] = p.x.into_bigint().to_bytes_be().try_into().unwrap();
54    let y_bytes: [u8; 32] = p.y.into_bigint().to_bytes_be().try_into().unwrap();
55    out[..32].copy_from_slice(&x_bytes);
56    out[32..].copy_from_slice(&y_bytes);
57    out
58}
59
60pub fn g2_bytes_from_ark(p: ArkG2Affine) -> [u8; 128] {
61    let mut out = [0u8; 128];
62    let x0: [u8; 32] = p.x.c0.into_bigint().to_bytes_be().try_into().unwrap();
63    let x1: [u8; 32] = p.x.c1.into_bigint().to_bytes_be().try_into().unwrap();
64    let y0: [u8; 32] = p.y.c0.into_bigint().to_bytes_be().try_into().unwrap();
65    let y1: [u8; 32] = p.y.c1.into_bigint().to_bytes_be().try_into().unwrap();
66
67    // Imaginary component first, real component second
68    // According to Soroban G2Affine documentation
69    out[..32].copy_from_slice(&x1); // x.c1 (imaginary)
70    out[32..64].copy_from_slice(&x0); // x.c0 (real)
71    out[64..96].copy_from_slice(&y1); // y.c1 (imaginary)
72    out[96..].copy_from_slice(&y0); // y.c0 (real)
73    out
74}
75
76/// Convert an ark-groth16 VerifyingKey to Soroban VerificationKeyBytes
77///
78/// # Arguments
79/// * `env` - The Soroban environment
80/// * `vk` - The ark-groth16 VerifyingKey<Bn254>
81///
82/// # Returns
83/// A VerificationKeyBytes struct suitable for use with the
84/// CircomGroth16Verifier contract
85pub fn vk_bytes_from_ark(
86    env: &Env,
87    vk: &ark_groth16::VerifyingKey<ark_bn254::Bn254>,
88) -> VerificationKeyBytes {
89    let alpha_bytes = g1_bytes_from_ark(vk.alpha_g1);
90    let beta_bytes = g2_bytes_from_ark(vk.beta_g2);
91    let gamma_bytes = g2_bytes_from_ark(vk.gamma_g2);
92    let delta_bytes = g2_bytes_from_ark(vk.delta_g2);
93
94    let mut ic = Vec::new(env);
95    for ic_point in &vk.gamma_abc_g1 {
96        let ic_bytes = g1_bytes_from_ark(*ic_point);
97        ic.push_back(BytesN::from_array(env, &ic_bytes));
98    }
99
100    VerificationKeyBytes {
101        alpha: BytesN::from_array(env, &alpha_bytes),
102        beta: BytesN::from_array(env, &beta_bytes),
103        gamma: BytesN::from_array(env, &gamma_bytes),
104        delta: BytesN::from_array(env, &delta_bytes),
105        ic,
106    }
107}