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 4155 : uchar out [ static 32 ] ) {
13 :
14 4155 : static char const pda_marker[] = {"ProgramDerivedAddress"};
15 :
16 4155 : 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 3996 : 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 3954 : fd_sha256_t sha;
27 3954 : fd_sha256_init( &sha );
28 :
29 3954 : fd_sha256_append( &sha, base, 32UL );
30 3954 : fd_sha256_append( &sha, seed, seed_sz );
31 3954 : fd_sha256_append( &sha, owner, 32UL );
32 :
33 3954 : fd_sha256_fini( &sha, out );
34 :
35 3954 : return FD_EXECUTOR_INSTR_SUCCESS;
36 3996 : }
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_pubkey_t const * program_id,
41 : ulong seeds_cnt,
42 : uchar ** seeds,
43 : ulong * seed_szs,
44 : uchar * bump_seed,
45 : fd_pubkey_t * out,
46 585 : uint * custom_err ) {
47 : /* https://github.com/anza-xyz/agave/blob/6ac4fe32e28d8ceb4085072b61fa0c6cb09baac1/sdk/program/src/pubkey.rs#L579-L581 */
48 585 : 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 : /* 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 585 : fd_sha256_t sha = {0};
56 585 : fd_sha256_init( &sha );
57 1170 : for ( ulong i=0UL; i<seeds_cnt; i++ ) {
58 585 : uchar * seed = *(seeds + i);
59 585 : if( FD_UNLIKELY( !seed ) ) {
60 0 : break;
61 0 : }
62 585 : fd_sha256_append( &sha, seed, seed_szs[i] );
63 585 : }
64 :
65 585 : if( bump_seed ) {
66 585 : fd_sha256_append( &sha, bump_seed, 1UL );
67 585 : }
68 585 : fd_sha256_append( &sha, program_id, sizeof(fd_pubkey_t) );
69 585 : fd_sha256_append( &sha, "ProgramDerivedAddress", 21UL );
70 :
71 585 : 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 585 : if( FD_UNLIKELY( fd_ed25519_point_validate( out->key ) ) ) {
78 261 : *custom_err = FD_PUBKEY_ERR_INVALID_SEEDS;
79 261 : return FD_EXECUTOR_INSTR_ERR_CUSTOM_ERR;
80 261 : }
81 :
82 324 : return FD_PUBKEY_SUCCESS;
83 585 : }
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_pubkey_t const * program_id,
88 : ulong seeds_cnt,
89 : uchar ** seeds,
90 : ulong * seed_szs,
91 : fd_pubkey_t * out,
92 : uchar * out_bump_seed,
93 162 : uint * custom_err ) {
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( program_id, seeds_cnt, seeds, seed_szs, bump_seed, derived, custom_err );
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 && *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 : *custom_err = UINT_MAX;
112 162 : return FD_PUBKEY_SUCCESS;
113 162 : }
|