1#[derive(Debug, PartialEq, Clone, Copy)]
2pub struct AddressSeed(pub [u8; 32]);
3
4impl From<[u8; 32]> for AddressSeed {
5 fn from(value: [u8; 32]) -> Self {
6 AddressSeed(value)
7 }
8}
9
10impl From<AddressSeed> for [u8; 32] {
11 fn from(address_seed: AddressSeed) -> Self {
12 address_seed.0
13 }
14}
15
16pub type CompressedAddress = [u8; 32];
17pub mod v1 {
18 use light_hasher::{
19 hash_to_field_size::hashv_to_bn254_field_size_be_const_array, Hasher, Keccak,
20 };
21
22 use super::AddressSeed;
23
24 pub fn derive_address_seed(seeds: &[&[u8]], program_id: &[u8; 32]) -> AddressSeed {
38 let mut inputs: [&[u8]; 16] = [&[]; 16];
39
40 inputs[0] = program_id.as_slice();
41
42 for (i, seed) in seeds.iter().enumerate() {
43 inputs[i + 1] = seed;
44 }
45
46 let seed = hashv_to_bn254_field_size_be_legacy(inputs.as_slice());
47 AddressSeed(seed)
48 }
49
50 fn hashv_to_bn254_field_size_be_legacy(bytes: &[&[u8]]) -> [u8; 32] {
51 let mut hashed_value: [u8; 32] = Keccak::hashv(bytes)
52 .expect("Keccak::hashv should be infallible when keccak feature is enabled");
53 hashed_value[0] = 0;
56 hashed_value
57 }
58
59 pub(crate) fn derive_address_from_seed(
62 address_seed: &AddressSeed,
63 address_tree_pubkey: &[u8; 32],
64 ) -> [u8; 32] {
65 let input = [address_tree_pubkey.as_slice(), address_seed.0.as_slice()];
66 hashv_to_bn254_field_size_be_const_array::<3>(input.as_slice()).unwrap()
67 }
68
69 pub fn derive_address(
88 seeds: &[&[u8]],
89 address_tree_pubkey: &[u8; 32],
90 program_id: &[u8; 32],
91 ) -> ([u8; 32], AddressSeed) {
92 let address_seed = derive_address_seed(seeds, program_id);
93 let address = derive_address_from_seed(&address_seed, address_tree_pubkey);
94
95 (address, address_seed)
96 }
97}
98
99pub mod v2 {
100 use light_hasher::hash_to_field_size::hashv_to_bn254_field_size_be_const_array;
101
102 use super::AddressSeed;
103
104 pub fn derive_address_seed(seeds: &[&[u8]]) -> AddressSeed {
117 AddressSeed(hashv_to_bn254_field_size_be_const_array::<17>(seeds).unwrap())
119 }
120
121 pub fn derive_address_from_seed(
124 address_seed: &AddressSeed,
125 address_tree_pubkey: &[u8; 32],
126 program_id: &[u8; 32],
127 ) -> [u8; 32] {
128 light_compressed_account::address::derive_address(
129 &address_seed.0,
130 address_tree_pubkey,
131 program_id,
132 )
133 }
134
135 pub fn derive_address(
154 seeds: &[&[u8]],
155 address_tree_pubkey: &[u8; 32],
156 program_id: &[u8; 32],
157 ) -> ([u8; 32], AddressSeed) {
158 let address_seed = derive_address_seed(seeds);
159 let address = derive_address_from_seed(&address_seed, address_tree_pubkey, program_id);
160 (address, address_seed)
161 }
162}
163
164#[cfg(test)]
165mod test {
166 use super::v1::*;
167
168 #[allow(dead_code)]
169 #[derive(Debug)]
170 struct AddressTreeInfo {
171 pub address_merkle_tree_pubkey: [u8; 32],
172 pub address_queue_pubkey: [u8; 32],
173 }
174
175 #[test]
176 fn test_derive_address_seed() {
177 use light_macros::pubkey_array;
178 let program_id = pubkey_array!("7yucc7fL3JGbyMwg4neUaenNSdySS39hbAk89Ao3t1Hz");
179
180 let address_seed = derive_address_seed(&[b"foo", b"bar"], &program_id);
181 assert_eq!(
182 address_seed,
183 [
184 0, 246, 150, 3, 192, 95, 53, 123, 56, 139, 206, 179, 253, 133, 115, 103, 120, 155,
185 251, 72, 250, 47, 117, 217, 118, 59, 174, 207, 49, 101, 201, 110
186 ]
187 .into()
188 );
189
190 let address_seed = derive_address_seed(&[b"ayy", b"lmao"], &program_id);
191 assert_eq!(
192 address_seed,
193 [
194 0, 202, 44, 25, 221, 74, 144, 92, 69, 168, 38, 19, 206, 208, 29, 162, 53, 27, 120,
195 214, 152, 116, 15, 107, 212, 168, 33, 121, 187, 10, 76, 233
196 ]
197 .into()
198 );
199 }
200
201 #[test]
202 fn test_derive_address() {
203 use light_macros::pubkey_array;
204 let address_tree_info = AddressTreeInfo {
205 address_merkle_tree_pubkey: [0; 32],
206 address_queue_pubkey: [0; 32],
207 };
208 let program_id = pubkey_array!("7yucc7fL3JGbyMwg4neUaenNSdySS39hbAk89Ao3t1Hz");
209
210 let seeds: &[&[u8]] = &[b"foo", b"bar"];
211 let expected_address_seed = [
212 0, 246, 150, 3, 192, 95, 53, 123, 56, 139, 206, 179, 253, 133, 115, 103, 120, 155, 251,
213 72, 250, 47, 117, 217, 118, 59, 174, 207, 49, 101, 201, 110,
214 ];
215 let expected_address = [
216 0, 141, 60, 24, 250, 156, 15, 250, 237, 196, 171, 243, 182, 10, 8, 66, 147, 57, 27,
217 209, 222, 86, 109, 234, 161, 219, 142, 43, 121, 104, 16, 63,
218 ];
219
220 let address_seed = derive_address_seed(seeds, &program_id);
221 assert_eq!(address_seed, expected_address_seed.into());
222 let (address, address_seed) = derive_address(
223 seeds,
224 &address_tree_info.address_merkle_tree_pubkey,
225 &program_id,
226 );
227 assert_eq!(address_seed, expected_address_seed.into());
228 assert_eq!(address, expected_address);
229
230 let seeds: &[&[u8]] = &[b"ayy", b"lmao"];
231 let expected_address_seed = [
232 0, 202, 44, 25, 221, 74, 144, 92, 69, 168, 38, 19, 206, 208, 29, 162, 53, 27, 120, 214,
233 152, 116, 15, 107, 212, 168, 33, 121, 187, 10, 76, 233,
234 ];
235 let expected_address = [
236 0, 104, 207, 102, 176, 61, 126, 178, 11, 174, 213, 195, 17, 36, 71, 95, 0, 231, 179,
237 87, 218, 195, 114, 84, 47, 97, 176, 93, 106, 175, 72, 115,
238 ];
239
240 let address_seed = derive_address_seed(seeds, &program_id);
241 assert_eq!(address_seed, expected_address_seed.into());
242 let (address, address_seed) = derive_address(
243 seeds,
244 &address_tree_info.address_merkle_tree_pubkey,
245 &program_id,
246 );
247 assert_eq!(address_seed, expected_address_seed.into());
248 assert_eq!(address, expected_address);
249 }
250
251 #[test]
252 fn test_v2_derive_address_seed() {
253 let seeds: &[&[u8]] = &[b"foo", b"bar"];
254 let address_seed = super::v2::derive_address_seed(seeds);
255
256 assert_eq!(
257 address_seed.0,
258 [
259 0, 177, 134, 198, 24, 76, 116, 207, 56, 127, 189, 181, 87, 237, 154, 181, 246, 54,
260 131, 21, 150, 248, 106, 75, 26, 80, 147, 245, 3, 23, 136, 56
261 ]
262 );
263
264 let seeds: &[&[u8]] = &[b"ayy", b"lmao"];
265 let address_seed = super::v2::derive_address_seed(seeds);
266
267 assert_eq!(
268 address_seed.0,
269 [
270 0, 224, 206, 65, 137, 189, 70, 157, 163, 133, 247, 140, 198, 252, 169, 250, 18, 18,
271 16, 189, 164, 131, 225, 113, 197, 225, 64, 81, 175, 154, 221, 28
272 ]
273 );
274 }
275
276 #[test]
277 fn test_v2_derive_address() {
278 use light_macros::pubkey_array;
279 let address_tree_pubkey = [0u8; 32];
280 let program_id = pubkey_array!("7yucc7fL3JGbyMwg4neUaenNSdySS39hbAk89Ao3t1Hz");
281
282 let seeds: &[&[u8]] = &[b"foo", b"bar"];
283
284 let expected_address_seed = [
285 0, 177, 134, 198, 24, 76, 116, 207, 56, 127, 189, 181, 87, 237, 154, 181, 246, 54, 131,
286 21, 150, 248, 106, 75, 26, 80, 147, 245, 3, 23, 136, 56,
287 ];
288 let expected_address = [
289 0, 16, 227, 141, 38, 32, 23, 82, 252, 50, 202, 3, 183, 186, 236, 133, 86, 112, 59, 23,
290 128, 162, 11, 84, 91, 127, 179, 208, 25, 178, 1, 240,
291 ];
292
293 let address_seed = super::v2::derive_address_seed(seeds);
294 assert_eq!(address_seed.0, expected_address_seed);
295
296 let (address, address_seed) =
297 super::v2::derive_address(seeds, &address_tree_pubkey, &program_id);
298 assert_eq!(address_seed.0, expected_address_seed);
299 assert_eq!(address, expected_address);
300
301 let seeds: &[&[u8]] = &[b"ayy", b"lmao"];
302
303 let expected_address_seed = [
304 0, 224, 206, 65, 137, 189, 70, 157, 163, 133, 247, 140, 198, 252, 169, 250, 18, 18, 16,
305 189, 164, 131, 225, 113, 197, 225, 64, 81, 175, 154, 221, 28,
306 ];
307 let expected_address = [
308 0, 226, 28, 142, 199, 153, 126, 212, 37, 54, 82, 232, 244, 161, 108, 12, 67, 84, 111,
309 66, 107, 111, 8, 126, 153, 233, 239, 192, 83, 117, 25, 6,
310 ];
311
312 let address_seed = super::v2::derive_address_seed(seeds);
313 assert_eq!(address_seed.0, expected_address_seed);
314
315 let (address, address_seed) =
316 super::v2::derive_address(seeds, &address_tree_pubkey, &program_id);
317 assert_eq!(address_seed.0, expected_address_seed);
318 assert_eq!(address, expected_address);
319 }
320}