LCOV - code coverage report
Current view: top level - flamenco/runtime - fd_pubkey_utils.c (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 53 68 77.9 %
Date: 2026-03-19 18:19:27 Functions: 3 3 100.0 %

          Line data    Source code
       1             : #include "fd_pubkey_utils.h"
       2             : #include "fd_executor_err.h"
       3             : #include "../vm/syscall/fd_vm_syscall.h"
       4             : #include "../../ballet/ed25519/fd_curve25519.h"
       5             : 
       6             : int
       7             : fd_pubkey_create_with_seed( fd_exec_instr_ctx_t const * ctx,
       8             :                             uchar const                 base [ static 32 ],
       9             :                             char const *                seed,
      10             :                             ulong                       seed_sz,
      11             :                             uchar const                 owner[ static 32 ],
      12        1224 :                             uchar                       out  [ static 32 ] ) {
      13             : 
      14        1224 :   static char const pda_marker[] = {"ProgramDerivedAddress"};
      15             : 
      16        1224 :   if( seed_sz>MAX_SEED_LEN ) {
      17           4 :     ctx->txn_out->err.custom_err = FD_PUBKEY_ERR_MAX_SEED_LEN_EXCEEDED;
      18           4 :     return FD_EXECUTOR_INSTR_ERR_CUSTOM_ERR;
      19           4 :   }
      20             : 
      21        1220 :   if( 0==memcmp( owner+11UL, pda_marker, 21UL ) ) {
      22          13 :     ctx->txn_out->err.custom_err = FD_PUBKEY_ERR_ILLEGAL_OWNER;
      23          13 :     return FD_EXECUTOR_INSTR_ERR_CUSTOM_ERR;
      24          13 :   }
      25             : 
      26        1207 :   fd_sha256_t sha;
      27        1207 :   fd_sha256_init( &sha );
      28             : 
      29        1207 :   fd_sha256_append( &sha, base,  32UL    );
      30        1207 :   fd_sha256_append( &sha, seed,  seed_sz );
      31        1207 :   fd_sha256_append( &sha, owner, 32UL    );
      32             : 
      33        1207 :   fd_sha256_fini( &sha, out );
      34             : 
      35        1207 :   return FD_EXECUTOR_INSTR_SUCCESS;
      36        1220 : }
      37             : 
      38             : /* https://github.com/anza-xyz/solana-sdk/blob/address%40v2.1.0/address/src/syscalls.rs#L391-L442 */
      39             : int
      40             : fd_pubkey_derive_pda( fd_pubkey_t const *   program_id,
      41             :                       ulong                 seeds_cnt,
      42             :                       uchar const * const * seeds,
      43             :                       ulong const *         seed_szs,
      44             :                       uchar *               bump_seed,
      45             :                       fd_pubkey_t *         out,
      46           2 :                       uint *                custom_err ) {
      47             :   /* https://github.com/anza-xyz/solana-sdk/blob/address%40v2.1.0/address/src/syscalls.rs#L397-L399 */
      48           2 :   if( seeds_cnt + (bump_seed ? 1 : 0) > MAX_SEEDS ) { // In Agave, seeds_cnt includes the bump seed
      49           0 :     *custom_err = FD_PUBKEY_ERR_MAX_SEED_LEN_EXCEEDED;
      50           0 :     return FD_EXECUTOR_INSTR_ERR_CUSTOM_ERR;
      51           0 :   }
      52             :   /* https://github.com/anza-xyz/solana-sdk/blob/address%40v2.1.0/address/src/syscalls.rs#L400-L403 */
      53           4 :   for( ulong i=0UL; i<seeds_cnt; i++ ) {
      54           2 :     if( seed_szs[i]>MAX_SEED_LEN ) {
      55           0 :       *custom_err = FD_PUBKEY_ERR_MAX_SEED_LEN_EXCEEDED;
      56           0 :       return FD_EXECUTOR_INSTR_ERR_CUSTOM_ERR;
      57           0 :     }
      58           2 :   }
      59             : 
      60           2 :   fd_sha256_t sha = {0};
      61           2 :   fd_sha256_init( &sha );
      62           4 :   for ( ulong i=0UL; i<seeds_cnt; i++ ) {
      63           2 :     uchar const * seed = *(seeds + i);
      64           2 :     if( FD_UNLIKELY( !seed ) ) {
      65           0 :       break;
      66           0 :     }
      67           2 :     fd_sha256_append( &sha, seed, seed_szs[i] );
      68           2 :   }
      69             : 
      70           2 :   if( bump_seed ) {
      71           2 :     fd_sha256_append( &sha, bump_seed, 1UL );
      72           2 :   }
      73           2 :   fd_sha256_append( &sha, program_id,              sizeof(fd_pubkey_t) );
      74           2 :   fd_sha256_append( &sha, "ProgramDerivedAddress", 21UL                );
      75             : 
      76           2 :   fd_sha256_fini( &sha, out );
      77             : 
      78             :   /* A PDA is valid if it is not a valid ed25519 curve point.
      79             :      In most cases the user will have derived the PDA off-chain,
      80             :      or the PDA is a known signer.
      81             :      https://github.com/anza-xyz/solana-sdk/blob/address%40v2.1.0/address/src/syscalls.rs#L417-L419 */
      82           2 :   if( FD_UNLIKELY( fd_ed25519_point_validate( out->key ) ) ) {
      83           0 :     *custom_err = FD_PUBKEY_ERR_INVALID_SEEDS;
      84           0 :     return FD_EXECUTOR_INSTR_ERR_CUSTOM_ERR;
      85           0 :   }
      86             : 
      87           2 :   return FD_PUBKEY_SUCCESS;
      88           2 : }
      89             : 
      90             : /* https://github.com/anza-xyz/solana-sdk/blob/address%40v2.1.0/address/src/syscalls.rs#L299-L343
      91             : 
      92             :    Agave try_find_program_address iterates bump seeds 255 down to 1
      93             :    (255 iterations via 0..u8::MAX). It returns None if no valid PDA
      94             :    is found. */
      95             : int
      96             : fd_pubkey_find_program_address( fd_pubkey_t const *   program_id,
      97             :                                 ulong                 seeds_cnt,
      98             :                                 uchar const * const * seeds,
      99             :                                 ulong const *         seed_szs,
     100             :                                 fd_pubkey_t *         out,
     101             :                                 uchar *               out_bump_seed,
     102           2 :                                 uint *                custom_err ) {
     103           2 :   uchar bump_seed[ 1UL ];
     104           2 :   for ( ulong i=0UL; i<255UL; ++i ) {
     105           2 :     bump_seed[ 0UL ] = (uchar)(255UL - i);
     106             : 
     107           2 :     fd_pubkey_t derived[ 1UL ];
     108           2 :     int err = fd_pubkey_derive_pda( program_id, seeds_cnt, seeds, seed_szs, bump_seed, derived, custom_err );
     109           2 :     if( err==FD_PUBKEY_SUCCESS ) {
     110             :       /* Stop looking if we have found a valid PDA */
     111           2 :       fd_memcpy( out, derived, sizeof(fd_pubkey_t) );
     112           2 :       fd_memcpy( out_bump_seed, bump_seed, 1UL );
     113           2 :       *custom_err = UINT_MAX;
     114           2 :       return FD_PUBKEY_SUCCESS;
     115           2 :     } else if( err==FD_EXECUTOR_INSTR_ERR_CUSTOM_ERR && *custom_err!=FD_PUBKEY_ERR_INVALID_SEEDS ) {
     116           0 :       return err;
     117           0 :     }
     118           2 :   }
     119             : 
     120             :   /* No valid PDA found (equivalent to Agave returning None) */
     121           0 :   *custom_err = FD_PUBKEY_ERR_INVALID_SEEDS;
     122           0 :   return FD_EXECUTOR_INSTR_ERR_CUSTOM_ERR;
     123           2 : }

Generated by: LCOV version 1.14