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 4161 : uchar out [ static 32 ] ) {
13 :
14 4161 : static char const pda_marker[] = {"ProgramDerivedAddress"};
15 :
16 4161 : if( seed_sz>MAX_SEED_LEN ) {
17 159 : ctx->txn_ctx->custom_err = FD_PUBKEY_ERR_MAX_SEED_LEN_EXCEEDED;
18 159 : return FD_EXECUTOR_INSTR_ERR_CUSTOM_ERR;
19 159 : }
20 :
21 4002 : if( 0==memcmp( owner+11UL, pda_marker, 21UL ) ) {
22 42 : ctx->txn_ctx->custom_err = FD_PUBKEY_ERR_ILLEGAL_OWNER;
23 42 : return FD_EXECUTOR_INSTR_ERR_CUSTOM_ERR;
24 42 : }
25 :
26 3960 : fd_sha256_t sha;
27 3960 : fd_sha256_init( &sha );
28 :
29 3960 : fd_sha256_append( &sha, base, 32UL );
30 3960 : fd_sha256_append( &sha, seed, seed_sz );
31 3960 : fd_sha256_append( &sha, owner, 32UL );
32 :
33 3960 : fd_sha256_fini( &sha, out );
34 :
35 3960 : return FD_EXECUTOR_INSTR_SUCCESS;
36 4002 : }
37 :
38 : /* https://github.com/anza-xyz/agave/blob/77daab497df191ef485a7ad36ed291c1874596e5/sdk/program/src/pubkey.rs#L578-L625 */
39 : int
40 : fd_pubkey_derive_pda( fd_exec_instr_ctx_t const * ctx,
41 : fd_pubkey_t const * program_id,
42 : ulong seeds_cnt,
43 : uchar ** seeds,
44 : ulong * seed_szs,
45 : uchar * bump_seed,
46 798 : fd_pubkey_t * out ) {
47 : /* https://github.com/anza-xyz/agave/blob/6ac4fe32e28d8ceb4085072b61fa0c6cb09baac1/sdk/program/src/pubkey.rs#L579-L581 */
48 798 : if( seeds_cnt + (bump_seed ? 1 : 0) > MAX_SEEDS ) { // In Agave, seeds_cnt includes the bump seed
49 0 : ctx->txn_ctx->custom_err = FD_PUBKEY_ERR_MAX_SEED_LEN_EXCEEDED;
50 0 : return FD_EXECUTOR_INSTR_ERR_CUSTOM_ERR;
51 0 : }
52 : /* TODO: This does not contain size checks for the seed as checked in
53 : https://github.com/anza-xyz/agave/blob/77daab497df191ef485a7ad36ed291c1874596e5/sdk/program/src/pubkey.rs#L586-L588 */
54 :
55 798 : fd_sha256_t sha = {0};
56 798 : fd_sha256_init( &sha );
57 1809 : for ( ulong i=0UL; i<seeds_cnt; i++ ) {
58 1011 : uchar * seed = *(seeds + i);
59 1011 : if( FD_UNLIKELY( !seed ) ) {
60 0 : break;
61 0 : }
62 1011 : fd_sha256_append( &sha, seed, seed_szs[i] );
63 1011 : }
64 :
65 798 : if( bump_seed ) {
66 798 : fd_sha256_append( &sha, bump_seed, 1UL );
67 798 : }
68 798 : fd_sha256_append( &sha, program_id, sizeof(fd_pubkey_t) );
69 798 : fd_sha256_append( &sha, "ProgramDerivedAddress", 21UL );
70 :
71 798 : fd_sha256_fini( &sha, out );
72 :
73 : /* A PDA is valid if it is not a valid ed25519 curve point.
74 : In most cases the user will have derived the PDA off-chain,
75 : or the PDA is a known signer.
76 : https://github.com/anza-xyz/agave/blob/6ac4fe32e28d8ceb4085072b61fa0c6cb09baac1/sdk/program/src/pubkey.rs#L599-L601 */
77 798 : if( FD_UNLIKELY( fd_ed25519_point_validate( out->key ) ) ) {
78 333 : ctx->txn_ctx->custom_err = FD_PUBKEY_ERR_INVALID_SEEDS;
79 333 : return FD_EXECUTOR_INSTR_ERR_CUSTOM_ERR;
80 333 : }
81 :
82 465 : return FD_PUBKEY_SUCCESS;
83 798 : }
84 :
85 : /* https://github.com/anza-xyz/agave/blob/77daab497df191ef485a7ad36ed291c1874596e5/sdk/program/src/pubkey.rs#L477-L534 */
86 : int
87 : fd_pubkey_find_program_address( fd_exec_instr_ctx_t const * ctx,
88 : fd_pubkey_t const * program_id,
89 : ulong seeds_cnt,
90 : uchar ** seeds,
91 : ulong * seed_szs,
92 : fd_pubkey_t * out,
93 162 : uchar * out_bump_seed ) {
94 162 : uchar bump_seed[ 1UL ];
95 423 : for ( ulong i=0UL; i<256UL; ++i ) {
96 423 : bump_seed[ 0UL ] = (uchar)(255UL - i);
97 :
98 423 : fd_pubkey_t derived[ 1UL ];
99 423 : int err = fd_pubkey_derive_pda( ctx, program_id, seeds_cnt, seeds, seed_szs, bump_seed, derived );
100 423 : if( err==FD_PUBKEY_SUCCESS ) {
101 : /* Stop looking if we have found a valid PDA */
102 162 : fd_memcpy( out, derived, sizeof(fd_pubkey_t) );
103 162 : fd_memcpy( out_bump_seed, bump_seed, 1UL );
104 162 : break;
105 261 : } else if( err==FD_EXECUTOR_INSTR_ERR_CUSTOM_ERR && ctx->txn_ctx->custom_err!=FD_PUBKEY_ERR_INVALID_SEEDS ) {
106 0 : return err;
107 0 : }
108 423 : }
109 :
110 : // Custom error may get set in fd_pubkey_derive_pda call
111 162 : ctx->txn_ctx->custom_err = UINT_MAX;
112 162 : return FD_PUBKEY_SUCCESS;
113 162 : }
|