6
6
} ;
7
7
use {
8
8
crate :: {
9
- check_program_account,
9
+ check_elgamal_registry_program_account , check_program_account,
10
10
error:: TokenError ,
11
11
extension:: {
12
12
confidential_transfer:: { instruction:: * , verify_proof:: * , * } ,
22
22
instruction:: { decode_instruction_data, decode_instruction_type} ,
23
23
pod:: { PodAccount , PodMint } ,
24
24
processor:: Processor ,
25
- proof:: verify_and_extract_context,
26
25
} ,
27
26
solana_program:: {
28
27
account_info:: { next_account_info, AccountInfo } ,
33
32
pubkey:: Pubkey ,
34
33
sysvar:: Sysvar ,
35
34
} ,
35
+ spl_elgamal_registry:: state:: ElGamalRegistry ,
36
+ spl_pod:: bytemuck:: pod_from_bytes,
36
37
spl_token_confidential_transfer_proof_extraction:: {
37
38
transfer:: TransferProofContext , transfer_with_fee:: TransferWithFeeProofContext ,
39
+ verify_and_extract_context,
38
40
} ,
39
41
} ;
40
42
@@ -92,23 +94,59 @@ fn process_update_mint(
92
94
Ok ( ( ) )
93
95
}
94
96
97
+ /// Processes a [ConfigureAccount] instruction with the assumption that an
98
+ /// ElGamal registry is provided.
99
+ fn process_configure_account_from_registry (
100
+ program_id : & Pubkey ,
101
+ accounts : & [ AccountInfo ] ,
102
+ ) -> ProgramResult {
103
+ let elgamal_registry_account = accounts. get ( 2 ) . ok_or ( ProgramError :: NotEnoughAccountKeys ) ?;
104
+ check_elgamal_registry_program_account ( elgamal_registry_account. owner ) ?;
105
+
106
+ let elgamal_registry_account_data = & elgamal_registry_account. data . borrow ( ) ;
107
+ let elgamal_registry_account =
108
+ pod_from_bytes :: < ElGamalRegistry > ( elgamal_registry_account_data) ?;
109
+
110
+ let decryptable_zero_balance = PodAeCiphertext :: default ( ) ;
111
+ let maximum_pending_balance_credit_counter =
112
+ DEFAULT_MAXIMUM_PENDING_BALANCE_CREDIT_COUNTER . into ( ) ;
113
+
114
+ process_configure_account (
115
+ program_id,
116
+ accounts,
117
+ & decryptable_zero_balance,
118
+ & maximum_pending_balance_credit_counter,
119
+ None ,
120
+ Some ( elgamal_registry_account) ,
121
+ )
122
+ }
123
+
95
124
/// Processes a [ConfigureAccount] instruction.
96
125
fn process_configure_account (
97
126
program_id : & Pubkey ,
98
127
accounts : & [ AccountInfo ] ,
99
128
decryptable_zero_balance : & DecryptableBalance ,
100
129
maximum_pending_balance_credit_counter : & PodU64 ,
101
- proof_instruction_offset : i64 ,
130
+ proof_instruction_offset : Option < i64 > ,
131
+ elgamal_registry_account : Option < & ElGamalRegistry > ,
102
132
) -> ProgramResult {
103
133
let account_info_iter = & mut accounts. iter ( ) ;
104
134
let token_account_info = next_account_info ( account_info_iter) ?;
105
135
let mint_info = next_account_info ( account_info_iter) ?;
106
136
107
- // zero-knowledge proof certifies that the supplied ElGamal public key is valid
108
- let proof_context = verify_and_extract_context :: <
109
- PubkeyValidityProofData ,
110
- PubkeyValidityProofContext ,
111
- > ( account_info_iter, proof_instruction_offset, None ) ?;
137
+ let elgamal_pubkey = if let Some ( offset) = proof_instruction_offset {
138
+ // zero-knowledge proof certifies that the supplied ElGamal public key is valid
139
+ let proof_context = verify_and_extract_context :: <
140
+ PubkeyValidityProofData ,
141
+ PubkeyValidityProofContext ,
142
+ > ( account_info_iter, offset, None ) ?;
143
+ proof_context. pubkey
144
+ } else {
145
+ // if proof instruction offset is `None`, then assume that the proof
146
+ // was already verified in an ElGamal registry account
147
+ let _elgamal_registry_account = next_account_info ( account_info_iter) ?;
148
+ elgamal_registry_account. unwrap ( ) . elgamal_pubkey
149
+ } ;
112
150
113
151
let authority_info = next_account_info ( account_info_iter) ?;
114
152
let authority_info_data_len = authority_info. data_len ( ) ;
@@ -121,13 +159,21 @@ fn process_configure_account(
121
159
return Err ( TokenError :: MintMismatch . into ( ) ) ;
122
160
}
123
161
124
- Processor :: validate_owner (
125
- program_id,
126
- & token_account. base . owner ,
127
- authority_info,
128
- authority_info_data_len,
129
- account_info_iter. as_slice ( ) ,
130
- ) ?;
162
+ if let Some ( registry_account) = elgamal_registry_account {
163
+ // if ElGamal registry was provided, then just verify that the registry owner
164
+ // and the account match, then skip the signature verification check
165
+ if registry_account. owner != * authority_info. key {
166
+ return Err ( TokenError :: OwnerMismatch . into ( ) ) ;
167
+ }
168
+ } else {
169
+ Processor :: validate_owner (
170
+ program_id,
171
+ & token_account. base . owner ,
172
+ authority_info,
173
+ authority_info_data_len,
174
+ account_info_iter. as_slice ( ) ,
175
+ ) ?;
176
+ }
131
177
132
178
check_program_account ( mint_info. owner ) ?;
133
179
let mint_data = & mut mint_info. data . borrow ( ) ;
@@ -140,7 +186,7 @@ fn process_configure_account(
140
186
let confidential_transfer_account =
141
187
token_account. init_extension :: < ConfidentialTransferAccount > ( false ) ?;
142
188
confidential_transfer_account. approved = confidential_transfer_mint. auto_approve_new_accounts ;
143
- confidential_transfer_account. elgamal_pubkey = proof_context . pubkey ;
189
+ confidential_transfer_account. elgamal_pubkey = elgamal_pubkey ;
144
190
confidential_transfer_account. maximum_pending_balance_credit_counter =
145
191
* maximum_pending_balance_credit_counter;
146
192
@@ -1102,14 +1148,20 @@ pub(crate) fn process_instruction(
1102
1148
}
1103
1149
ConfidentialTransferInstruction :: ConfigureAccount => {
1104
1150
msg ! ( "ConfidentialTransferInstruction::ConfigureAccount" ) ;
1105
- let data = decode_instruction_data :: < ConfigureAccountInstructionData > ( input) ?;
1106
- process_configure_account (
1107
- program_id,
1108
- accounts,
1109
- & data. decryptable_zero_balance ,
1110
- & data. maximum_pending_balance_credit_counter ,
1111
- data. proof_instruction_offset as i64 ,
1112
- )
1151
+ if input. is_empty ( ) {
1152
+ // instruction data is empty, so assume an ElGamal registry is provided
1153
+ process_configure_account_from_registry ( program_id, accounts)
1154
+ } else {
1155
+ let data = decode_instruction_data :: < ConfigureAccountInstructionData > ( input) ?;
1156
+ process_configure_account (
1157
+ program_id,
1158
+ accounts,
1159
+ & data. decryptable_zero_balance ,
1160
+ & data. maximum_pending_balance_credit_counter ,
1161
+ Some ( data. proof_instruction_offset as i64 ) ,
1162
+ None ,
1163
+ )
1164
+ }
1113
1165
}
1114
1166
ConfidentialTransferInstruction :: ApproveAccount => {
1115
1167
msg ! ( "ConfidentialTransferInstruction::ApproveAccount" ) ;
0 commit comments