rustywallet_batch/
fast_gen.rs1use rand::SeedableRng;
7use rand_chacha::ChaCha20Rng;
8use rayon::prelude::*;
9use rustywallet_keys::private_key::PrivateKey;
10use secp256k1::{Secp256k1, SecretKey};
11
12pub struct FastKeyGenerator {
17 count: usize,
19 parallel: bool,
21 chunk_size: usize,
23}
24
25impl FastKeyGenerator {
26 pub fn new(count: usize) -> Self {
28 Self {
29 count,
30 parallel: true,
31 chunk_size: 10_000,
32 }
33 }
34
35 pub fn parallel(mut self, enabled: bool) -> Self {
37 self.parallel = enabled;
38 self
39 }
40
41 pub fn chunk_size(mut self, size: usize) -> Self {
43 self.chunk_size = size;
44 self
45 }
46
47 pub fn generate(self) -> Vec<PrivateKey> {
49 if self.parallel {
50 self.generate_parallel()
51 } else {
52 self.generate_sequential()
53 }
54 }
55
56 fn generate_sequential(self) -> Vec<PrivateKey> {
58 let secp = Secp256k1::new();
59 let mut rng = ChaCha20Rng::from_entropy();
60
61 (0..self.count)
62 .map(|_| {
63 let (secret_key, _) = secp.generate_keypair(&mut rng);
64 secret_key_to_private_key(secret_key)
65 })
66 .collect()
67 }
68
69 fn generate_parallel(self) -> Vec<PrivateKey> {
71 let num_chunks = self.count.div_ceil(self.chunk_size);
72
73 (0..num_chunks)
74 .into_par_iter()
75 .flat_map(|chunk_idx| {
76 let start = chunk_idx * self.chunk_size;
77 let end = (start + self.chunk_size).min(self.count);
78 let chunk_count = end - start;
79
80 let secp = Secp256k1::new();
82 let mut seed = [0u8; 32];
84 seed[..8].copy_from_slice(&chunk_idx.to_le_bytes());
85 use rand::RngCore;
87 let mut temp_rng = rand::rngs::OsRng;
88 temp_rng.fill_bytes(&mut seed[8..]);
89
90 let mut rng = ChaCha20Rng::from_seed(seed);
91
92 (0..chunk_count)
93 .map(|_| {
94 let (secret_key, _) = secp.generate_keypair(&mut rng);
95 secret_key_to_private_key(secret_key)
96 })
97 .collect::<Vec<_>>()
98 })
99 .collect()
100 }
101}
102
103fn secret_key_to_private_key(secret_key: SecretKey) -> PrivateKey {
105 let bytes = secret_key.secret_bytes();
106 PrivateKey::from_bytes(bytes).expect("SecretKey should always be valid")
107}
108
109pub struct IncrementalKeyGenerator {
114 start: [u8; 32],
116 count: usize,
118 step: u64,
120}
121
122impl IncrementalKeyGenerator {
123 pub fn new(count: usize) -> Self {
125 let start_key = PrivateKey::random();
126 Self {
127 start: start_key.to_bytes(),
128 count,
129 step: 1,
130 }
131 }
132
133 pub fn from_key(key: &PrivateKey, count: usize) -> Self {
135 Self {
136 start: key.to_bytes(),
137 count,
138 step: 1,
139 }
140 }
141
142 pub fn step(mut self, step: u64) -> Self {
144 self.step = step;
145 self
146 }
147
148 pub fn generate(self) -> Vec<PrivateKey> {
150 let mut current = self.start;
151 let mut keys = Vec::with_capacity(self.count);
152
153 for _ in 0..self.count {
154 if let Ok(key) = PrivateKey::from_bytes(current) {
155 keys.push(key);
156 }
157 add_to_bytes(&mut current, self.step);
159 }
160
161 keys
162 }
163}
164
165fn add_to_bytes(bytes: &mut [u8; 32], value: u64) {
167 let value_bytes = value.to_be_bytes();
168 let mut carry: u64 = 0;
169
170 for i in (24..32).rev() {
172 let idx = 31 - i;
173 let v = if idx < 8 { value_bytes[7 - idx] } else { 0 };
174 let sum = bytes[i] as u64 + v as u64 + carry;
175 bytes[i] = sum as u8;
176 carry = sum >> 8;
177 }
178
179 for i in (0..24).rev() {
181 if carry == 0 {
182 break;
183 }
184 let sum = bytes[i] as u64 + carry;
185 bytes[i] = sum as u8;
186 carry = sum >> 8;
187 }
188
189 if carry > 0 || !PrivateKey::is_valid(bytes) {
191 *bytes = [0u8; 32];
192 bytes[31] = 1;
193 }
194}
195
196#[cfg(test)]
197mod tests {
198 use super::*;
199 use std::collections::HashSet;
200 use std::time::Instant;
201
202 #[test]
203 fn test_fast_generator_sequential() {
204 let keys = FastKeyGenerator::new(1000)
205 .parallel(false)
206 .generate();
207
208 assert_eq!(keys.len(), 1000);
209
210 let hex_keys: HashSet<_> = keys.iter().map(|k| k.to_hex()).collect();
212 assert_eq!(hex_keys.len(), 1000);
213 }
214
215 #[test]
216 fn test_fast_generator_parallel() {
217 let keys = FastKeyGenerator::new(10_000)
218 .parallel(true)
219 .chunk_size(1000)
220 .generate();
221
222 assert_eq!(keys.len(), 10_000);
223
224 let hex_keys: HashSet<_> = keys.iter().map(|k| k.to_hex()).collect();
226 assert_eq!(hex_keys.len(), 10_000);
227 }
228
229 #[test]
230 fn test_incremental_generator() {
231 let base = PrivateKey::from_hex(
232 "0000000000000000000000000000000000000000000000000000000000000001"
233 ).unwrap();
234
235 let keys = IncrementalKeyGenerator::from_key(&base, 5).generate();
236
237 assert_eq!(keys.len(), 5);
238 assert_eq!(keys[0].to_hex(), "0000000000000000000000000000000000000000000000000000000000000001");
239 assert_eq!(keys[1].to_hex(), "0000000000000000000000000000000000000000000000000000000000000002");
240 assert_eq!(keys[2].to_hex(), "0000000000000000000000000000000000000000000000000000000000000003");
241 }
242
243 #[test]
244 fn test_performance_comparison() {
245 let count = 10_000;
246
247 let start = Instant::now();
249 let keys = FastKeyGenerator::new(count)
250 .parallel(true)
251 .generate();
252 let fast_elapsed = start.elapsed();
253
254 assert_eq!(keys.len(), count);
255
256 let fast_rate = count as f64 / fast_elapsed.as_secs_f64();
257 println!("Fast generator: {:.0} keys/sec", fast_rate);
258
259 assert!(fast_rate > 500.0, "Fast generator should exceed 500 keys/sec in test mode");
261 }
262}