LCOV - code coverage report
Current view: top level - flamenco/runtime/program/zksdk - fd_zksdk.c (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 0 161 0.0 %
Date: 2025-03-20 12:08:36 Functions: 0 2 0.0 %

          Line data    Source code
       1             : #include "fd_zksdk_private.h"
       2             : #include "../../fd_borrowed_account.h"
       3             : #include "../../fd_system_ids.h"
       4             : 
       5             : /* fd_zksdk_process_close_context_state is equivalent to process_close_proof_context()
       6             :    https://github.com/anza-xyz/agave/blob/v2.0.1/programs/zk-elgamal-proof/src/lib.rs#L127 */
       7             : int
       8           0 : fd_zksdk_process_close_context_state( fd_exec_instr_ctx_t * ctx ) {
       9           0 : #define ACC_IDX_PROOF (0UL)
      10           0 : #define ACC_IDX_DEST  (1UL)
      11           0 : #define ACC_IDX_OWNER (2UL)
      12             : 
      13           0 :   fd_pubkey_t owner_pubkey[1];
      14           0 :   fd_pubkey_t proof_pubkey[1];
      15           0 :   fd_pubkey_t dest_pubkey[1];
      16             : 
      17             :   /* Obtain the owner pubkey by borrowing the owner account in local scope
      18             :   https://github.com/anza-xyz/agave/blob/master/programs/zk-elgamal-proof/src/lib.rs#L133-L141 */
      19           0 :   do {
      20           0 :     fd_guarded_borrowed_account_t owner_acc;
      21           0 :     FD_TRY_BORROW_INSTR_ACCOUNT_DEFAULT_ERR_CHECK( ctx, ACC_IDX_OWNER, &owner_acc );
      22             : 
      23           0 :     if( FD_UNLIKELY( !fd_instr_acc_is_signer_idx( ctx->instr, ACC_IDX_OWNER ) ) ) {
      24           0 :       return FD_EXECUTOR_INSTR_ERR_MISSING_REQUIRED_SIGNATURE;
      25           0 :     }
      26           0 :     fd_memcpy( owner_pubkey, owner_acc.acct->pubkey, sizeof(fd_pubkey_t) );
      27             :     /* implicit drop of borrowed owner_acc */
      28           0 :   } while (0);
      29             : 
      30             :   /* Allocate space for borrowed accounts */
      31           0 :   fd_guarded_borrowed_account_t proof_acc;
      32           0 :   fd_guarded_borrowed_account_t dest_acc;
      33             : 
      34             :   /* Obtain the proof account pubkey by borrowing the proof account.
      35             :      https://github.com/anza-xyz/agave/blob/master/programs/zk-elgamal-proof/src/lib.rs#L143-L145 */
      36           0 :   FD_TRY_BORROW_INSTR_ACCOUNT_DEFAULT_ERR_CHECK(ctx, ACC_IDX_PROOF, &proof_acc );
      37           0 :   fd_memcpy( proof_pubkey, proof_acc.acct->pubkey, sizeof(fd_pubkey_t) );
      38           0 :   fd_borrowed_account_drop( &proof_acc );
      39             : 
      40             :   /* Obtain the dest account pubkey by borrowing the dest account.
      41             :      https://github.com/anza-xyz/agave/blob/master/programs/zk-elgamal-proof/src/lib.rs#L146-L148*/
      42           0 :   FD_TRY_BORROW_INSTR_ACCOUNT_DEFAULT_ERR_CHECK( ctx, ACC_IDX_DEST, &dest_acc );
      43           0 :   fd_memcpy( dest_pubkey, dest_acc.acct->pubkey, sizeof(fd_pubkey_t) );
      44           0 :   fd_borrowed_account_drop( &dest_acc );
      45             : 
      46           0 :   if( FD_UNLIKELY( fd_memeq( proof_pubkey, dest_pubkey, sizeof(fd_pubkey_t) ) ) ) {
      47           0 :     return FD_EXECUTOR_INSTR_ERR_INVALID_INSTR_DATA;
      48           0 :   }
      49             : 
      50             :   /* Re-borrow the proof account
      51             :      https://github.com/anza-xyz/agave/blob/master/programs/zk-elgamal-proof/src/lib.rs#L153-L154 */
      52           0 :   FD_TRY_BORROW_INSTR_ACCOUNT_DEFAULT_ERR_CHECK(ctx, ACC_IDX_PROOF, &proof_acc );
      53             : 
      54             :   /* https://github.com/anza-xyz/agave/blob/v2.0.1/programs/zk-elgamal-proof/src/lib.rs#L161-L162
      55             :       Note: data also contains context data, but we only need the initial 33 bytes. */
      56           0 :   if( FD_UNLIKELY( proof_acc.acct->const_meta->dlen < sizeof(fd_zksdk_proof_ctx_state_meta_t) ) ) {
      57           0 :     return FD_EXECUTOR_INSTR_ERR_INVALID_ACC_DATA;
      58           0 :   }
      59           0 :   fd_zksdk_proof_ctx_state_meta_t const * proof_ctx_state_meta = fd_type_pun_const( proof_acc.acct->const_data );
      60             : 
      61             :   /* https://github.com/anza-xyz/agave/blob/v2.0.1/programs/zk-elgamal-proof/src/lib.rs#L155 */
      62           0 :   fd_pubkey_t const * expected_owner_addr = &proof_ctx_state_meta->ctx_state_authority;
      63             : 
      64             :   /* https://github.com/anza-xyz/agave/blob/v2.0.1/programs/zk-elgamal-proof/src/lib.rs#L157-L159 */
      65           0 :   if( FD_UNLIKELY( !fd_memeq( owner_pubkey, expected_owner_addr, sizeof(fd_pubkey_t) ) ) ) {
      66           0 :     return FD_EXECUTOR_INSTR_ERR_INVALID_ACC_OWNER;
      67           0 :   }
      68             : 
      69             :   /* Re-borrow the dest account
      70             :      https://github.com/anza-xyz/agave/blob/v2.1.14/programs/zk-elgamal-proof/src/lib.rs#L162-L163 */
      71           0 :   FD_TRY_BORROW_INSTR_ACCOUNT_DEFAULT_ERR_CHECK( ctx, ACC_IDX_DEST, &dest_acc );
      72             : 
      73             :   /* https://github.com/anza-xyz/agave/blob/v2.0.1/programs/zk-elgamal-proof/src/lib.rs#L163-L166 */
      74           0 :   int err = 0;
      75           0 :   err = fd_borrowed_account_checked_add_lamports( &dest_acc, proof_acc.acct->const_meta->info.lamports );
      76           0 :   if( FD_UNLIKELY( err ) ) {
      77           0 :     return err;
      78           0 :   }
      79           0 :   err = fd_borrowed_account_set_lamports( &proof_acc, 0UL );
      80           0 :   if( FD_UNLIKELY( err ) ) {
      81           0 :     return err;
      82           0 :   }
      83           0 :   err = fd_borrowed_account_set_data_length( &proof_acc, 0UL );
      84           0 :   if( FD_UNLIKELY( err ) ) {
      85           0 :     return err;
      86           0 :   }
      87           0 :   err = fd_borrowed_account_set_owner( &proof_acc, &fd_solana_system_program_id );
      88           0 :   if( FD_UNLIKELY( err ) ) {
      89           0 :     return err;
      90           0 :   }
      91             : 
      92           0 :   return FD_EXECUTOR_INSTR_SUCCESS;
      93           0 : }
      94             : 
      95             : /* fd_zksdk_process_verify_proof is equivalent to process_verify_proof()
      96             :    and calls specific functions inside instructions/ to verify each
      97             :    individual ZKP.
      98             :    https://github.com/anza-xyz/agave/blob/v2.0.1/programs/zk-elgamal-proof/src/lib.rs#L32 */
      99             : int
     100           0 : fd_zksdk_process_verify_proof( fd_exec_instr_ctx_t * ctx ) {
     101           0 :   int err;
     102           0 :   uchar const * instr_data = ctx->instr->data;
     103           0 :   ulong instr_acc_cnt      = ctx->instr->acct_cnt;
     104           0 :   uchar instr_id = instr_data[0]; /* instr_data_sz already checked by the caller */
     105             : 
     106             :   /* ProofContextState "header" size, ie. 1 authority pubkey + 1 proof_type byte */
     107           0 : #define CTX_HEAD_SZ 33UL
     108             : 
     109             :   /* Aux memory buffer.
     110             :      When proof data is taken from ix data we can access it directly,
     111             :      but when it's taken from account data we need to copy it to release
     112             :      the borrow. The largest ZKP is for range_proof_u256.
     113             :      Moreover, when storing context to an account, we need to serialize
     114             :      the ProofContextState struct that has 33 bytes of header -- we include
     115             :      them here so we can do a single memcpy. */
     116           0 : #define MAX_SZ (sizeof(fd_zksdk_range_proof_u256_proof_t)+sizeof(fd_zksdk_batched_range_proof_context_t))
     117           0 :   uchar buffer[ CTX_HEAD_SZ+MAX_SZ ];
     118             : 
     119             :   /* Specific instruction function */
     120           0 :   int (*fd_zksdk_instr_verify_proof)( void const *, void const * ) = NULL;
     121           0 :   switch( instr_id ) {
     122           0 :   case FD_ZKSDK_INSTR_VERIFY_ZERO_CIPHERTEXT:
     123           0 :     fd_zksdk_instr_verify_proof = &fd_zksdk_instr_verify_proof_zero_ciphertext;
     124           0 :     break;
     125           0 :   case FD_ZKSDK_INSTR_VERIFY_CIPHERTEXT_CIPHERTEXT_EQUALITY:
     126           0 :     fd_zksdk_instr_verify_proof = &fd_zksdk_instr_verify_proof_ciphertext_ciphertext_equality;
     127           0 :     break;
     128           0 :   case FD_ZKSDK_INSTR_VERIFY_CIPHERTEXT_COMMITMENT_EQUALITY:
     129           0 :     fd_zksdk_instr_verify_proof = &fd_zksdk_instr_verify_proof_ciphertext_commitment_equality;
     130           0 :     break;
     131           0 :   case FD_ZKSDK_INSTR_VERIFY_PUBKEY_VALIDITY:
     132           0 :     fd_zksdk_instr_verify_proof = &fd_zksdk_instr_verify_proof_pubkey_validity;
     133           0 :     break;
     134           0 :   case FD_ZKSDK_INSTR_VERIFY_PERCENTAGE_WITH_CAP:
     135           0 :     fd_zksdk_instr_verify_proof = &fd_zksdk_instr_verify_proof_percentage_with_cap;
     136           0 :     break;
     137           0 :   case FD_ZKSDK_INSTR_VERIFY_BATCHED_RANGE_PROOF_U64:
     138           0 :     fd_zksdk_instr_verify_proof = &fd_zksdk_instr_verify_proof_batched_range_proof_u64;
     139           0 :     break;
     140           0 :   case FD_ZKSDK_INSTR_VERIFY_BATCHED_RANGE_PROOF_U128:
     141           0 :     fd_zksdk_instr_verify_proof = &fd_zksdk_instr_verify_proof_batched_range_proof_u128;
     142           0 :     break;
     143           0 :   case FD_ZKSDK_INSTR_VERIFY_BATCHED_RANGE_PROOF_U256:
     144           0 :     fd_zksdk_instr_verify_proof = &fd_zksdk_instr_verify_proof_batched_range_proof_u256;
     145           0 :     break;
     146           0 :   case FD_ZKSDK_INSTR_VERIFY_GROUPED_CIPHERTEXT_2_HANDLES_VALIDITY:
     147           0 :     fd_zksdk_instr_verify_proof = &fd_zksdk_instr_verify_proof_grouped_ciphertext_2_handles_validity;
     148           0 :     break;
     149           0 :   case FD_ZKSDK_INSTR_VERIFY_BATCHED_GROUPED_CIPHERTEXT_2_HANDLES_VALIDITY:
     150           0 :     fd_zksdk_instr_verify_proof = &fd_zksdk_instr_verify_proof_batched_grouped_ciphertext_2_handles_validity;
     151           0 :     break;
     152           0 :   case FD_ZKSDK_INSTR_VERIFY_GROUPED_CIPHERTEXT_3_HANDLES_VALIDITY:
     153           0 :     fd_zksdk_instr_verify_proof = &fd_zksdk_instr_verify_proof_grouped_ciphertext_3_handles_validity;
     154           0 :     break;
     155           0 :   case FD_ZKSDK_INSTR_VERIFY_BATCHED_GROUPED_CIPHERTEXT_3_HANDLES_VALIDITY:
     156           0 :     fd_zksdk_instr_verify_proof = &fd_zksdk_instr_verify_proof_batched_grouped_ciphertext_3_handles_validity;
     157           0 :     break;
     158           0 :   default:
     159           0 :     return FD_EXECUTOR_INSTR_ERR_INVALID_INSTR_DATA;
     160           0 :   }
     161             : 
     162             :   /* https://github.com/anza-xyz/agave/blob/v2.0.1/programs/zk-elgamal-proof/src/lib.rs#L42 */
     163           0 :   uint accessed_accounts = 0U;
     164           0 :   uchar const * context = NULL;
     165             :   /* Note: instr_id is guaranteed to be valid, to access values in the arrays. */
     166           0 :   ulong context_sz = fd_zksdk_context_sz[instr_id];
     167           0 :   ulong proof_data_sz = context_sz + fd_zksdk_proof_sz[instr_id];
     168             : 
     169             :   /* if instruction data is exactly 5 bytes, then read proof from an account
     170             :      https://github.com/anza-xyz/agave/blob/v2.1.14/programs/zk-elgamal-proof/src/lib.rs#L46 */
     171           0 :   if( ctx->instr->data_sz == 5UL ) {
     172             :     /* Case 1. Proof data from account data. */
     173             : 
     174             :     /* Borrow the proof data account.
     175             :       https://github.com/anza-xyz/agave/blob/v2.1.14/programs/zk-elgamal-proof/src/lib.rs#L47-L48 */
     176           0 :     fd_guarded_borrowed_account_t proof_data_acc;
     177           0 :     FD_TRY_BORROW_INSTR_ACCOUNT_DEFAULT_ERR_CHECK( ctx, 0UL, &proof_data_acc );
     178             : 
     179             :     /* https://github.com/anza-xyz/agave/blob/v2.0.1/programs/zk-elgamal-proof/src/lib.rs#L48 */
     180           0 :     accessed_accounts = 1U;
     181             : 
     182             :     /* https://github.com/anza-xyz/agave/blob/v2.0.1/programs/zk-elgamal-proof/src/lib.rs#L50-L61
     183             :         Note: it doesn't look like the ref code can throw any error. */
     184           0 :     uint proof_data_offset = fd_uint_load_4_fast(&instr_data[1]);
     185             : 
     186             :     /* https://github.com/anza-xyz/agave/blob/v2.0.1/programs/zk-elgamal-proof/src/lib.rs#L62-L65 */
     187           0 :     if( proof_data_offset+proof_data_sz > proof_data_acc.acct->const_meta->dlen ) {
     188           0 :       return FD_EXECUTOR_INSTR_ERR_INVALID_ACC_DATA;
     189           0 :     }
     190           0 :     context = fd_memcpy( buffer+CTX_HEAD_SZ, &proof_data_acc.acct->const_data[proof_data_offset], proof_data_sz );
     191           0 :   } else {
     192             :     /* Case 2. Proof data from ix data. */
     193             : 
     194             :     /* https://github.com/anza-xyz/agave/blob/v2.0.1/programs/zk-elgamal-proof/src/lib.rs#L78-L82
     195             :        Note: instr_id is guaranteed to be valid, to access values in the arrays. */
     196           0 :     if (ctx->instr->data_sz != 1 + proof_data_sz) {
     197           0 :       fd_log_collector_msg_literal( ctx, "invalid proof data" );
     198           0 :       return FD_EXECUTOR_INSTR_ERR_INVALID_INSTR_DATA;
     199           0 :     }
     200           0 :     context = instr_data + 1;
     201           0 :   }
     202             : 
     203             :   /* Verify individual ZKP
     204             :      https://github.com/anza-xyz/agave/blob/v2.0.1/programs/zk-elgamal-proof/src/lib.rs#L83-L86 */
     205           0 :   void const * proof = context + fd_zksdk_context_sz[instr_id];
     206           0 :   err = (*fd_zksdk_instr_verify_proof)( context, proof );
     207           0 :   if( FD_UNLIKELY( err ) ) {
     208             :     //TODO: full log, including err
     209           0 :     fd_log_collector_msg_literal( ctx, "proof_verification failed" );
     210           0 :     return FD_EXECUTOR_INSTR_ERR_INVALID_INSTR_DATA;
     211           0 :   }
     212             : 
     213             :   /* Create context state if accounts are provided with the instruction
     214             :      https://github.com/anza-xyz/agave/blob/v2.0.1/programs/zk-elgamal-proof/src/lib.rs#L92 */
     215           0 :   if( instr_acc_cnt > accessed_accounts ) {
     216           0 :     fd_pubkey_t                   context_state_authority[1];
     217             : 
     218             :     /* Obtain the context_state_authority by borrowing the account temporarily in a local scope.
     219             :        https://github.com/anza-xyz/agave/blob/v2.1.14/programs/zk-elgamal-proof/src/lib.rs#L94-L99 */
     220           0 :     do {
     221           0 :       fd_guarded_borrowed_account_t _acc;
     222           0 :       FD_TRY_BORROW_INSTR_ACCOUNT_DEFAULT_ERR_CHECK( ctx, accessed_accounts+1, &_acc );
     223           0 :       fd_memcpy( context_state_authority, _acc.acct->pubkey, sizeof(fd_pubkey_t) );
     224           0 :     } while(0);
     225             : 
     226             :     /* Borrow the proof context account
     227             :        https://github.com/anza-xyz/agave/blob/v2.1.14/programs/zk-elgamal-proof/src/lib.rs#L101-L102 */
     228           0 :     fd_guarded_borrowed_account_t proof_context_acc;
     229           0 :     FD_TRY_BORROW_INSTR_ACCOUNT_DEFAULT_ERR_CHECK( ctx, accessed_accounts, &proof_context_acc );
     230             : 
     231             :     /* https://github.com/anza-xyz/agave/blob/v2.0.1/programs/zk-elgamal-proof/src/lib.rs#L103-L105 */
     232           0 :     if( FD_UNLIKELY( !fd_memeq( proof_context_acc.acct->const_meta->info.owner, &fd_solana_zk_elgamal_proof_program_id, sizeof(fd_pubkey_t) ) ) ) {
     233           0 :       return FD_EXECUTOR_INSTR_ERR_INVALID_ACC_OWNER;
     234           0 :     }
     235             : 
     236             :     /* https://github.com/anza-xyz/agave/blob/v2.0.1/programs/zk-elgamal-proof/src/lib.rs#L107-L112 */
     237           0 :     if( FD_UNLIKELY( proof_context_acc.acct->const_meta->dlen >= CTX_HEAD_SZ && proof_context_acc.acct->const_data[32] != 0 ) ) {
     238           0 :       return FD_EXECUTOR_INSTR_ERR_ACC_ALREADY_INITIALIZED;
     239           0 :     }
     240             : 
     241             :     /* https://github.com/anza-xyz/agave/blob/v2.0.1/programs/zk-elgamal-proof/src/lib.rs#L114-L115
     242             :         Note: nothing to do. */
     243             : 
     244             :     /* https://github.com/anza-xyz/agave/blob/v2.0.1/programs/zk-elgamal-proof/src/lib.rs#L117-L119 */
     245           0 :     ulong context_data_sx = CTX_HEAD_SZ + context_sz;
     246           0 :     if( FD_UNLIKELY( proof_context_acc.acct->const_meta->dlen != context_data_sx ) ) {
     247           0 :       return FD_EXECUTOR_INSTR_ERR_INVALID_ACC_DATA;
     248           0 :     }
     249             : 
     250             :     /* https://github.com/anza-xyz/agave/blob/v2.0.1/programs/zk-elgamal-proof/src/lib.rs#L121 */
     251           0 :     fd_memcpy( buffer, context_state_authority, sizeof(fd_pubkey_t) ); // buffer[0..31]
     252           0 :     buffer[ 32 ] = instr_id;                                           // buffer[32]
     253           0 :     if( ctx->instr->data_sz != 5UL ) {                                  // buffer[33..]
     254           0 :       fd_memcpy( buffer+CTX_HEAD_SZ, context, context_sz );
     255           0 :     }
     256           0 :     err = fd_borrowed_account_set_data_from_slice( &proof_context_acc, buffer, context_data_sx );
     257           0 :     if( FD_UNLIKELY( err ) ) {
     258           0 :       return err;
     259           0 :     }
     260           0 :   }
     261             : 
     262           0 :   return FD_EXECUTOR_INSTR_SUCCESS;
     263           0 : }

Generated by: LCOV version 1.14