pub use light_compressed_account::address::AddressSeed;
pub type CompressedAddress = [u8; 32];
pub mod v1 {
use light_hasher::{
hash_to_field_size::hashv_to_bn254_field_size_be_const_array, Hasher, Keccak,
};
use super::AddressSeed;
pub fn derive_address_seed(seeds: &[&[u8]], program_id: &[u8; 32]) -> AddressSeed {
let mut inputs: [&[u8]; 16] = [&[]; 16];
inputs[0] = program_id.as_slice();
for (i, seed) in seeds.iter().enumerate() {
inputs[i + 1] = seed;
}
let seed = hashv_to_bn254_field_size_be_legacy(inputs.as_slice());
AddressSeed(seed)
}
fn hashv_to_bn254_field_size_be_legacy(bytes: &[&[u8]]) -> [u8; 32] {
let mut hashed_value: [u8; 32] = Keccak::hashv(bytes)
.expect("Keccak::hashv should be infallible when keccak feature is enabled");
hashed_value[0] = 0;
hashed_value
}
pub(crate) fn derive_address_from_seed(
address_seed: &AddressSeed,
address_tree_pubkey: &[u8; 32],
) -> [u8; 32] {
let input = [address_tree_pubkey.as_slice(), address_seed.0.as_slice()];
hashv_to_bn254_field_size_be_const_array::<3>(input.as_slice()).unwrap()
}
pub fn derive_address(
seeds: &[&[u8]],
address_tree_pubkey: &[u8; 32],
program_id: &[u8; 32],
) -> ([u8; 32], AddressSeed) {
let address_seed = derive_address_seed(seeds, program_id);
let address = derive_address_from_seed(&address_seed, address_tree_pubkey);
(address, address_seed)
}
}
pub mod v2 {
use light_hasher::hash_to_field_size::hashv_to_bn254_field_size_be_const_array;
use super::AddressSeed;
pub fn derive_address_seed(seeds: &[&[u8]]) -> AddressSeed {
AddressSeed(hashv_to_bn254_field_size_be_const_array::<17>(seeds).unwrap())
}
pub fn derive_address_from_seed(
address_seed: &AddressSeed,
address_tree_pubkey: &[u8; 32],
program_id: &[u8; 32],
) -> [u8; 32] {
light_compressed_account::address::derive_address(
&address_seed.0,
address_tree_pubkey,
program_id,
)
}
pub fn derive_address(
seeds: &[&[u8]],
address_tree_pubkey: &[u8; 32],
program_id: &[u8; 32],
) -> ([u8; 32], AddressSeed) {
let address_seed = derive_address_seed(seeds);
let address = derive_address_from_seed(&address_seed, address_tree_pubkey, program_id);
(address, address_seed)
}
}
#[cfg(test)]
mod test {
use super::v1::*;
#[allow(dead_code)]
#[derive(Debug)]
struct AddressTreeInfo {
pub address_merkle_tree_pubkey: [u8; 32],
pub address_queue_pubkey: [u8; 32],
}
#[test]
fn test_derive_address_seed() {
use light_macros::pubkey_array;
let program_id = pubkey_array!("7yucc7fL3JGbyMwg4neUaenNSdySS39hbAk89Ao3t1Hz");
let address_seed = derive_address_seed(&[b"foo", b"bar"], &program_id);
assert_eq!(
address_seed,
[
0, 246, 150, 3, 192, 95, 53, 123, 56, 139, 206, 179, 253, 133, 115, 103, 120, 155,
251, 72, 250, 47, 117, 217, 118, 59, 174, 207, 49, 101, 201, 110
]
.into()
);
let address_seed = derive_address_seed(&[b"ayy", b"lmao"], &program_id);
assert_eq!(
address_seed,
[
0, 202, 44, 25, 221, 74, 144, 92, 69, 168, 38, 19, 206, 208, 29, 162, 53, 27, 120,
214, 152, 116, 15, 107, 212, 168, 33, 121, 187, 10, 76, 233
]
.into()
);
}
#[test]
fn test_derive_address() {
use light_macros::pubkey_array;
let address_tree_info = AddressTreeInfo {
address_merkle_tree_pubkey: [0; 32],
address_queue_pubkey: [0; 32],
};
let program_id = pubkey_array!("7yucc7fL3JGbyMwg4neUaenNSdySS39hbAk89Ao3t1Hz");
let seeds: &[&[u8]] = &[b"foo", b"bar"];
let expected_address_seed = [
0, 246, 150, 3, 192, 95, 53, 123, 56, 139, 206, 179, 253, 133, 115, 103, 120, 155, 251,
72, 250, 47, 117, 217, 118, 59, 174, 207, 49, 101, 201, 110,
];
let expected_address = [
0, 141, 60, 24, 250, 156, 15, 250, 237, 196, 171, 243, 182, 10, 8, 66, 147, 57, 27,
209, 222, 86, 109, 234, 161, 219, 142, 43, 121, 104, 16, 63,
];
let address_seed = derive_address_seed(seeds, &program_id);
assert_eq!(address_seed, expected_address_seed.into());
let (address, address_seed) = derive_address(
seeds,
&address_tree_info.address_merkle_tree_pubkey,
&program_id,
);
assert_eq!(address_seed, expected_address_seed.into());
assert_eq!(address, expected_address);
let seeds: &[&[u8]] = &[b"ayy", b"lmao"];
let expected_address_seed = [
0, 202, 44, 25, 221, 74, 144, 92, 69, 168, 38, 19, 206, 208, 29, 162, 53, 27, 120, 214,
152, 116, 15, 107, 212, 168, 33, 121, 187, 10, 76, 233,
];
let expected_address = [
0, 104, 207, 102, 176, 61, 126, 178, 11, 174, 213, 195, 17, 36, 71, 95, 0, 231, 179,
87, 218, 195, 114, 84, 47, 97, 176, 93, 106, 175, 72, 115,
];
let address_seed = derive_address_seed(seeds, &program_id);
assert_eq!(address_seed, expected_address_seed.into());
let (address, address_seed) = derive_address(
seeds,
&address_tree_info.address_merkle_tree_pubkey,
&program_id,
);
assert_eq!(address_seed, expected_address_seed.into());
assert_eq!(address, expected_address);
}
#[test]
fn test_v2_derive_address_seed() {
let seeds: &[&[u8]] = &[b"foo", b"bar"];
let address_seed = super::v2::derive_address_seed(seeds);
assert_eq!(
address_seed.0,
[
0, 177, 134, 198, 24, 76, 116, 207, 56, 127, 189, 181, 87, 237, 154, 181, 246, 54,
131, 21, 150, 248, 106, 75, 26, 80, 147, 245, 3, 23, 136, 56
]
);
let seeds: &[&[u8]] = &[b"ayy", b"lmao"];
let address_seed = super::v2::derive_address_seed(seeds);
assert_eq!(
address_seed.0,
[
0, 224, 206, 65, 137, 189, 70, 157, 163, 133, 247, 140, 198, 252, 169, 250, 18, 18,
16, 189, 164, 131, 225, 113, 197, 225, 64, 81, 175, 154, 221, 28
]
);
}
#[test]
fn test_v2_derive_address() {
use light_macros::pubkey_array;
let address_tree_pubkey = [0u8; 32];
let program_id = pubkey_array!("7yucc7fL3JGbyMwg4neUaenNSdySS39hbAk89Ao3t1Hz");
let seeds: &[&[u8]] = &[b"foo", b"bar"];
let expected_address_seed = [
0, 177, 134, 198, 24, 76, 116, 207, 56, 127, 189, 181, 87, 237, 154, 181, 246, 54, 131,
21, 150, 248, 106, 75, 26, 80, 147, 245, 3, 23, 136, 56,
];
let expected_address = [
0, 16, 227, 141, 38, 32, 23, 82, 252, 50, 202, 3, 183, 186, 236, 133, 86, 112, 59, 23,
128, 162, 11, 84, 91, 127, 179, 208, 25, 178, 1, 240,
];
let address_seed = super::v2::derive_address_seed(seeds);
assert_eq!(address_seed.0, expected_address_seed);
let (address, address_seed) =
super::v2::derive_address(seeds, &address_tree_pubkey, &program_id);
assert_eq!(address_seed.0, expected_address_seed);
assert_eq!(address, expected_address);
let seeds: &[&[u8]] = &[b"ayy", b"lmao"];
let expected_address_seed = [
0, 224, 206, 65, 137, 189, 70, 157, 163, 133, 247, 140, 198, 252, 169, 250, 18, 18, 16,
189, 164, 131, 225, 113, 197, 225, 64, 81, 175, 154, 221, 28,
];
let expected_address = [
0, 226, 28, 142, 199, 153, 126, 212, 37, 54, 82, 232, 244, 161, 108, 12, 67, 84, 111,
66, 107, 111, 8, 126, 153, 233, 239, 192, 83, 117, 25, 6,
];
let address_seed = super::v2::derive_address_seed(seeds);
assert_eq!(address_seed.0, expected_address_seed);
let (address, address_seed) =
super::v2::derive_address(seeds, &address_tree_pubkey, &program_id);
assert_eq!(address_seed.0, expected_address_seed);
assert_eq!(address, expected_address);
}
}