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