thru_base/
crypto_utils.rs1use crate::tn_tools::Pubkey;
4use sha2::{Digest, Sha256};
5
6const TN_UPLOADER_PROGRAM_SEED_SIZE: usize = 32;
7
8pub fn derive_uploader_program_accounts(
20 seed: &[u8],
21 program_id: &Pubkey,
22) -> Result<(Pubkey, Pubkey), Box<dyn std::error::Error>> {
23 if seed.is_empty() {
24 return Err("Seed cannot be empty".into());
25 }
26 if seed.len() > TN_UPLOADER_PROGRAM_SEED_SIZE {
27 return Err("Seed cannot be greater than 32 bytes".into());
28 }
29 let mut padded_seed = [0u8; TN_UPLOADER_PROGRAM_SEED_SIZE];
31 padded_seed[..seed.len()].copy_from_slice(seed);
32
33 let meta_account = derive_program_address(&padded_seed, program_id, true)?;
35
36 let meta_bytes = meta_account.to_bytes()?;
38 let buffer_account = derive_program_address(&meta_bytes, program_id, true)?;
39
40 Ok((meta_account, buffer_account))
41}
42
43pub fn derive_manager_program_accounts(
56 seed: &[u8],
57 program_id: &Pubkey,
58 is_ephemeral: bool,
59) -> Result<(Pubkey, Pubkey), Box<dyn std::error::Error>> {
60 if seed.is_empty() {
61 return Err("Seed cannot be empty".into());
62 }
63 if seed.len() > TN_UPLOADER_PROGRAM_SEED_SIZE {
64 return Err("Seed cannot be greater than 32 bytes".into());
65 }
66 let mut padded_seed = [0u8; TN_UPLOADER_PROGRAM_SEED_SIZE];
68 padded_seed[..seed.len()].copy_from_slice(seed);
69
70 let meta_account = derive_program_address(&padded_seed, program_id, is_ephemeral)?;
72
73 let meta_bytes = meta_account.to_bytes()?;
75 let program_account = derive_program_address(&meta_bytes, program_id, is_ephemeral)?;
76
77 Ok((meta_account, program_account))
78}
79
80pub fn derive_program_address(
96 seed: &[u8; 32],
97 program_id: &Pubkey,
98 is_ephemeral: bool,
99) -> Result<Pubkey, Box<dyn std::error::Error>> {
100 let program_bytes = program_id
102 .to_bytes()
103 .map_err(|e| format!("Failed to convert program_id to bytes: {}", e))?;
104
105 let mut hasher = Sha256::new();
107 hasher.update(&program_bytes);
108
109 hasher.update(&[if is_ephemeral { 1u8 } else { 0u8 }]); hasher.update(seed);
114
115 let hash = hasher.finalize();
116
117 let mut derived_bytes = [0u8; 32];
119 derived_bytes.copy_from_slice(&hash[..32]);
120
121 Ok(Pubkey::from_bytes(&derived_bytes))
122}
123
124#[cfg(test)]
125mod tests {
126 use super::*;
127
128 #[test]
129 fn test_derive_uploader_program_accounts() {
130 let program_bytes = [1u8; 32];
132 let program_id = Pubkey::from_bytes(&program_bytes);
133
134 let seed = b"test_seed";
136 let result = derive_uploader_program_accounts(seed, &program_id);
137 assert!(result.is_ok());
138
139 let (meta_account, buffer_account) = result.unwrap();
140 assert_ne!(meta_account, buffer_account);
141
142 let result2 = derive_uploader_program_accounts(seed, &program_id);
144 let (meta_account2, buffer_account2) = result2.unwrap();
145 assert_eq!(meta_account, meta_account2);
146 assert_eq!(buffer_account, buffer_account2);
147 }
148
149 #[test]
150 fn test_derive_uploader_program_accounts_empty_seed() {
151 let program_bytes = [1u8; 32];
152 let program_id = Pubkey::from_bytes(&program_bytes);
153
154 let empty_seed = b"";
156 let result = derive_uploader_program_accounts(empty_seed, &program_id);
157 assert!(result.is_err());
158 assert_eq!(result.unwrap_err().to_string(), "Seed cannot be empty");
159 }
160
161 #[test]
162 fn test_derive_program_address_different_seeds() {
163 let program_bytes = [1u8; 32];
164 let program_id = Pubkey::from_bytes(&program_bytes);
165
166 let mut seed1 = [0u8; 32];
167 seed1[..4].copy_from_slice(b"test");
168 let mut seed2 = [0u8; 32];
169 seed2[..4].copy_from_slice(b"seed");
170
171 let pubkey1 = derive_program_address(&seed1, &program_id, false).unwrap();
172 let pubkey2 = derive_program_address(&seed2, &program_id, false).unwrap();
173
174 assert_ne!(pubkey1, pubkey2);
176 }
177}