1
0
Fork 0
mirror of https://github.com/TransparentLC/opencl_vanity_gpg.git synced 2025-10-20 07:14:09 +00:00

feat: add future timestamp support and enhance OpenCL kernel for time-based searches

This commit is contained in:
孟古一 2025-07-26 09:06:17 +08:00
parent 7c43505f54
commit ef3853bb22
No known key found for this signature in database
GPG key ID: 6183333333333333
5 changed files with 164 additions and 43 deletions

View file

@ -28,35 +28,63 @@ $ opencl_vanity_gpg -h
Usage: opencl_vanity_gpg [OPTIONS] Usage: opencl_vanity_gpg [OPTIONS]
Options: Options:
-c, --cipher-suite <CIPHER_SUITE> Cipher suite of the vanity key -c, --cipher-suite <CIPHER_SUITE>
ed25519, ecdsa-****, rsa**** => Primary key Cipher suite of the vanity key
cv25519, ecdh-**** => Subkey ed25519, ecdsa-****, rsa**** => Primary key
Use gpg CLI for further editing of the key. [default: ed25519] [possible values: ed25519, cv25519, rsa2048, rsa3072, rsa4096, ecdh-p256, ecdh-p384, ecdh-p521, ecdsa-p256, ecdsa-p384, ecdsa-p521] cv25519, ecdh-**** => Subkey
-u, --user-id <USER_ID> OpenPGP compatible user ID [default: "Dummy <dummy@example.com>"] Use gpg CLI for further editing of the key. [default: ed25519] [possible values: ed25519, cv25519, rsa2048, rsa3072, rsa4096, ecdh-p256, ecdh-p384, ecdh-p521, ecdsa-p256, ecdsa-p384, ecdsa-p521]
-p, --pattern <PATTERN> A pattern less than 40 chars for matching fingerprints -u, --user-id <USER_ID>
> Format: OpenPGP compatible user ID [default: "Dummy <dummy@example.com>"]
* 0-9A-F are fixed, G-Z are wildcards -p, --pattern <PATTERN>
* Other chars will be ignored A pattern less than 40 chars for matching fingerprints
* Case insensitive > Format:
> Example: * 0-9A-F are fixed, G-Z are wildcards
* 11XXXX** may output a fingerprint ends with 11222234 or 11AAAABF * Other chars will be ignored
* 11XXYYZZ may output a fingerprint ends with 11223344 or 11AABBCC * Case insensitive
-f, --filter <FILTER> OpenCL kernel function for uint h[5] for matching fingerprints > Example:
Ignore the pattern and no estimate is given if this has been set * 11XXXX** may output a fingerprint ends with 11222234 or 11AAAABF
> Example: * 11XXYYZZ may output a fingerprint ends with 11223344 or 11AABBCC
* (h[4] & 0xFFFF) == 0x1234 outputs a fingerprint ends with 1234 -f, --filter <FILTER>
* (h[0] & 0xFFFF0000) == 0xABCD0000 outputs a fingerprint starts with ABCD OpenCL kernel function for uint h[5] for matching fingerprints
-o, --output <OUTPUT> The dir where the vanity keys are saved Ignore the pattern and no estimate is given if this has been set
-d, --device <DEVICE> Device ID to use > Example:
-t, --thread <THREAD> Adjust it to maximum your device's usage * (h[4] & 0xFFFF) == 0x1234 outputs a fingerprint ends with 1234
-i, --iteration <ITERATION> Adjust it to maximum your device's usage [default: 512] * (h[0] & 0xFFFF0000) == 0xABCD0000 outputs a fingerprint starts with ABCD
--timeout <TIMEOUT> Exit after a specified time in seconds -o, --output <OUTPUT>
--oneshot Exit after getting a vanity key The dir where the vanity keys are saved
--no-progress Don't print progress -d, --device <DEVICE>
--no-secret-key-logging Don't print armored secret key Device ID to use
--list-device Show available OpenCL devices then exit -t, --thread <THREAD>
-h, --help Print help Adjust it to maximum your device's usage
-V, --version Print version -i, --iteration <ITERATION>
Adjust it to maximum your device's usage [default: 512]
--timeout <TIMEOUT>
Exit after a specified time in seconds
--oneshot
Exit after getting a vanity key
--no-progress
Don't print progress
--no-secret-key-logging
Don't print armored secret key
--list-device
Show available OpenCL devices then exit
--future-timestamp
Generate keys with future timestamps instead of past timestamps
When true: search from start_timestamp forward in time (start_timestamp + 0 to max_time_range)
When false: search from start_timestamp backward in time (start_timestamp - max_time_range to start_timestamp - 0)
--start-timestamp <START_TIMESTAMP>
Custom timestamp to start searching from (Unix timestamp)
This is the base time point from which the search begins
If not specified, uses current time as the starting point
Example: 1640995200 (Jan 1, 2022 00:00:00 UTC)
--max-time-range <MAX_TIME_RANGE>
Maximum time range to search in seconds (default: 86400000 = 1000 days)
future_timestamp=true: search from start_timestamp to (start_timestamp + max_time_range)
future_timestamp=false: search from (start_timestamp - max_time_range) to start_timestamp [default: 86400000]
-h, --help
Print help
-V, --version
Print version
$ opencl_vanity_gpg -p 11XXYYZZ --oneshot $ opencl_vanity_gpg -p 11XXYYZZ --oneshot
[2025-01-08T19:00:25Z INFO opencl_vanity_gpg] Using device: Apple M1 Pro [2025-01-08T19:00:25Z INFO opencl_vanity_gpg] Using device: Apple M1 Pro

View file

@ -26,7 +26,7 @@ fn main() -> anyhow::Result<()> {
if ARGS.list_device { if ARGS.list_device {
info!("Available OpenCL devices: \n"); info!("Available OpenCL devices: \n");
for (i, device) in device_list.iter().enumerate() { for (i, device) in device_list.iter().enumerate() {
println!("Device #{} - {:?}", i, device); println!("Device #{i} - {device:?}");
} }
return Ok(()); return Ok(());
} }
@ -51,13 +51,32 @@ fn main() -> anyhow::Result<()> {
}; };
let iteration = ARGS.iteration; let iteration = ARGS.iteration;
info!(
"You will get vanity keys created after {}", // Determine the starting timestamp
chrono::Utc::now() let start_timestamp = ARGS
.checked_sub_signed(chrono::TimeDelta::seconds((dimension * iteration) as i64)) .start_timestamp
.unwrap() .unwrap_or_else(|| chrono::Utc::now().timestamp());
.to_rfc3339_opts(chrono::SecondsFormat::Millis, true),
); // Use the user-specified time range instead of dimension * iteration
let max_search_offset = ARGS.max_time_range as i64;
if ARGS.future_timestamp {
info!(
"Starting search from {} and going forward in time (up to {} seconds)",
chrono::DateTime::from_timestamp(start_timestamp, 0)
.unwrap_or_else(chrono::Utc::now)
.to_rfc3339_opts(chrono::SecondsFormat::Millis, true),
max_search_offset
);
} else {
info!(
"Starting search from {} and going backward in time (up to {} seconds)",
chrono::DateTime::from_timestamp(start_timestamp, 0)
.unwrap_or_else(chrono::Utc::now)
.to_rfc3339_opts(chrono::SecondsFormat::Millis, true),
max_search_offset
);
}
if ARGS.output.is_none() { if ARGS.output.is_none() {
if ARGS.no_secret_key_logging { if ARGS.no_secret_key_logging {
@ -91,6 +110,31 @@ fn main() -> anyhow::Result<()> {
}; };
let mut vanity_key = VanitySecretKey::new(ARGS.cipher_suite, ARGS.user_id.clone(), &mut rng); let mut vanity_key = VanitySecretKey::new(ARGS.cipher_suite, ARGS.user_id.clone(), &mut rng);
// Set the initial timestamp for the key
// Ensure we use the full timestamp value, not truncated
let initial_timestamp = if start_timestamp > u32::MAX as i64 {
// If timestamp is too large for u32, we need to handle this carefully
// For now, use the current approach but ensure we're aware of the limitation
warn!(
"Timestamp {} is too large for u32, may cause unexpected behavior",
start_timestamp
);
start_timestamp as u32
} else {
start_timestamp as u32
};
info!(
"Using base timestamp: {} ({})",
initial_timestamp,
chrono::DateTime::from_timestamp(initial_timestamp as i64, 0)
.unwrap_or_else(chrono::Utc::now)
.to_rfc3339_opts(chrono::SecondsFormat::Millis, true)
);
vanity_key.edit_timestamp(initial_timestamp, &mut rng);
let mut hashdata = manually_prepare_sha1(vanity_key.hashdata()); let mut hashdata = manually_prepare_sha1(vanity_key.hashdata());
let (tx_hashdata, rx_hashdata) = channel::<Vec<u32>>(); let (tx_hashdata, rx_hashdata) = channel::<Vec<u32>>();
@ -106,6 +150,10 @@ fn main() -> anyhow::Result<()> {
&[ &[
format!("#define FILTER(h) ({filter})"), format!("#define FILTER(h) ({filter})"),
format!("#define CHUNK ({})", hashdata.len() / 16), format!("#define CHUNK ({})", hashdata.len() / 16),
format!(
"#define FUTURE_MODE ({})",
if ARGS.future_timestamp { 1 } else { 0 }
),
] ]
.join("\n"), .join("\n"),
), ),
@ -128,8 +176,11 @@ fn main() -> anyhow::Result<()> {
loop { loop {
debug!("Send key to OpenCL thread"); debug!("Send key to OpenCL thread");
tx_hashdata.send(hashdata)?; tx_hashdata.send(hashdata)?;
let vanity_key_next = let mut vanity_key_next =
VanitySecretKey::new(ARGS.cipher_suite, ARGS.user_id.clone(), &mut rng); VanitySecretKey::new(ARGS.cipher_suite, ARGS.user_id.clone(), &mut rng);
// Set the same initial timestamp for consistency
vanity_key_next.edit_timestamp(initial_timestamp, &mut rng);
let hashdata_next = manually_prepare_sha1(vanity_key_next.hashdata()); let hashdata_next = manually_prepare_sha1(vanity_key_next.hashdata());
debug!("Receive result from OpenCL thread"); debug!("Receive result from OpenCL thread");
@ -224,6 +275,7 @@ fn opencl_thread(
.arg(&buffer_hashdata) .arg(&buffer_hashdata)
.arg(&buffer_result) .arg(&buffer_result)
.arg(ARGS.iteration as u64) .arg(ARGS.iteration as u64)
.arg(ARGS.max_time_range as u32)
.build() .build()
.unwrap(); .unwrap();

View file

@ -4,15 +4,35 @@
#ifdef __INJECTS__ #ifdef __INJECTS__
#define CHUNK (0) #define CHUNK (0)
#define FILTER(h) (false) #define FILTER(h) (false)
#define FUTURE_MODE (0)
#endif #endif
__kernel void vanity_sha1(__constant uint *hashdata, __global uint *result, const ulong iter) { __kernel void vanity_sha1(__constant uint *hashdata, __global uint *result, const ulong iter, const uint max_time_range) {
uint data[CHUNK * 16]; uint data[CHUNK * 16];
for (uint i = 0; i < CHUNK * 16; i++) data[i] = hashdata[i]; for (uint i = 0; i < CHUNK * 16; i++) data[i] = hashdata[i];
uint nonce = data[1]; uint nonce = data[1];
uint thread_id = get_global_id(0);
for (uint i = 0; i < iter; i++) { for (uint i = 0; i < iter; i++) {
data[1] = nonce - get_global_id(0) * iter - i; // Use a simple sequential approach that searches close to base time first
if (data[1] > nonce) break; // Each thread gets a small sequential offset
uint offset = thread_id + i * get_global_size(0);
// Wrap around within max_time_range to avoid going too far
offset = offset % max_time_range;
if (FUTURE_MODE) {
// For future mode: increment timestamp within range
data[1] = nonce + offset;
// Check for overflow
if (data[1] < nonce) break;
} else {
// For past mode: decrement timestamp within range
data[1] = nonce - offset;
// Check for underflow
if (data[1] > nonce) break;
}
uint h[] = {0x67452301, 0xEFCDAB89, 0x98BADCFE, 0x10325476, 0xC3D2E1F0}; uint h[] = {0x67452301, 0xEFCDAB89, 0x98BADCFE, 0x10325476, 0xC3D2E1F0};

View file

@ -75,6 +75,25 @@ pub struct Args {
/// Show available OpenCL devices then exit /// Show available OpenCL devices then exit
#[arg(long, default_value_t = false)] #[arg(long, default_value_t = false)]
pub list_device: bool, pub list_device: bool,
/// Generate keys with future timestamps instead of past timestamps
/// When true: search from start_timestamp forward in time (start_timestamp + 0 to max_time_range)
/// When false: search from start_timestamp backward in time (start_timestamp - max_time_range to start_timestamp - 0)
#[arg(long, default_value_t = false, verbatim_doc_comment)]
pub future_timestamp: bool,
/// Custom timestamp to start searching from (Unix timestamp)
/// This is the base time point from which the search begins
/// If not specified, uses current time as the starting point
/// Example: 1640995200 (Jan 1, 2022 00:00:00 UTC)
#[arg(long, verbatim_doc_comment)]
pub start_timestamp: Option<i64>,
/// Maximum time range to search in seconds (default: 86400000 = 1000 days)
/// future_timestamp=true: search from start_timestamp to (start_timestamp + max_time_range)
/// future_timestamp=false: search from (start_timestamp - max_time_range) to start_timestamp
#[arg(long, default_value_t = 86400000, verbatim_doc_comment)]
pub max_time_range: u64,
} }
impl Default for Args { impl Default for Args {
@ -93,6 +112,9 @@ impl Default for Args {
no_progress: true, no_progress: true,
no_secret_key_logging: false, no_secret_key_logging: false,
list_device: false, list_device: false,
future_timestamp: false,
start_timestamp: None,
max_time_range: 86400000,
} }
} }
} }

View file

@ -7,9 +7,9 @@ use std::{fmt::Write, mem};
pub use args::*; pub use args::*;
pub use device::DeviceList; pub use device::DeviceList;
pub use pattern::HashPattern;
use indicatif::*; use indicatif::*;
use indicatif_log_bridge::LogWrapper; use indicatif_log_bridge::LogWrapper;
pub use pattern::HashPattern;
pub use vanity_key::VanitySecretKey; pub use vanity_key::VanitySecretKey;
/// Do SHA-1 padding manually /// Do SHA-1 padding manually
@ -98,7 +98,6 @@ pub fn init_progress_bar(estimate: Option<f64>) -> ProgressBar {
bar bar
} }
pub fn format_number(v: impl Into<f64>) -> String { pub fn format_number(v: impl Into<f64>) -> String {
match Into::<f64>::into(v) { match Into::<f64>::into(v) {
v if v >= 1e12f64 => { v if v >= 1e12f64 => {