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 : }
|