mirror of
https://github.com/TransparentLC/opencl_vanity_gpg.git
synced 2025-10-20 15:24:08 +00:00
Merge pull request #2 from mengguyi/master
feat: add future timestamp support and enhance OpenCL kernel for time…
This commit is contained in:
commit
5fd3a100d6
5 changed files with 164 additions and 43 deletions
58
README.md
58
README.md
|
@ -28,12 +28,15 @@ $ 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>
|
||||||
|
Cipher suite of the vanity key
|
||||||
ed25519, ecdsa-****, rsa**** => Primary key
|
ed25519, ecdsa-****, rsa**** => Primary key
|
||||||
cv25519, ecdh-**** => Subkey
|
cv25519, ecdh-**** => Subkey
|
||||||
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]
|
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]
|
||||||
-u, --user-id <USER_ID> OpenPGP compatible user ID [default: "Dummy <dummy@example.com>"]
|
-u, --user-id <USER_ID>
|
||||||
-p, --pattern <PATTERN> A pattern less than 40 chars for matching fingerprints
|
OpenPGP compatible user ID [default: "Dummy <dummy@example.com>"]
|
||||||
|
-p, --pattern <PATTERN>
|
||||||
|
A pattern less than 40 chars for matching fingerprints
|
||||||
> Format:
|
> Format:
|
||||||
* 0-9A-F are fixed, G-Z are wildcards
|
* 0-9A-F are fixed, G-Z are wildcards
|
||||||
* Other chars will be ignored
|
* Other chars will be ignored
|
||||||
|
@ -41,22 +44,47 @@ Options:
|
||||||
> Example:
|
> Example:
|
||||||
* 11XXXX** may output a fingerprint ends with 11222234 or 11AAAABF
|
* 11XXXX** may output a fingerprint ends with 11222234 or 11AAAABF
|
||||||
* 11XXYYZZ may output a fingerprint ends with 11223344 or 11AABBCC
|
* 11XXYYZZ may output a fingerprint ends with 11223344 or 11AABBCC
|
||||||
-f, --filter <FILTER> OpenCL kernel function for uint h[5] for matching fingerprints
|
-f, --filter <FILTER>
|
||||||
|
OpenCL kernel function for uint h[5] for matching fingerprints
|
||||||
Ignore the pattern and no estimate is given if this has been set
|
Ignore the pattern and no estimate is given if this has been set
|
||||||
> Example:
|
> Example:
|
||||||
* (h[4] & 0xFFFF) == 0x1234 outputs a fingerprint ends with 1234
|
* (h[4] & 0xFFFF) == 0x1234 outputs a fingerprint ends with 1234
|
||||||
* (h[0] & 0xFFFF0000) == 0xABCD0000 outputs a fingerprint starts with ABCD
|
* (h[0] & 0xFFFF0000) == 0xABCD0000 outputs a fingerprint starts with ABCD
|
||||||
-o, --output <OUTPUT> The dir where the vanity keys are saved
|
-o, --output <OUTPUT>
|
||||||
-d, --device <DEVICE> Device ID to use
|
The dir where the vanity keys are saved
|
||||||
-t, --thread <THREAD> Adjust it to maximum your device's usage
|
-d, --device <DEVICE>
|
||||||
-i, --iteration <ITERATION> Adjust it to maximum your device's usage [default: 512]
|
Device ID to use
|
||||||
--timeout <TIMEOUT> Exit after a specified time in seconds
|
-t, --thread <THREAD>
|
||||||
--oneshot Exit after getting a vanity key
|
Adjust it to maximum your device's usage
|
||||||
--no-progress Don't print progress
|
-i, --iteration <ITERATION>
|
||||||
--no-secret-key-logging Don't print armored secret key
|
Adjust it to maximum your device's usage [default: 512]
|
||||||
--list-device Show available OpenCL devices then exit
|
--timeout <TIMEOUT>
|
||||||
-h, --help Print help
|
Exit after a specified time in seconds
|
||||||
-V, --version Print version
|
--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
|
||||||
|
|
64
src/main.rs
64
src/main.rs
|
@ -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;
|
||||||
|
|
||||||
|
// Determine the starting timestamp
|
||||||
|
let start_timestamp = ARGS
|
||||||
|
.start_timestamp
|
||||||
|
.unwrap_or_else(|| chrono::Utc::now().timestamp());
|
||||||
|
|
||||||
|
// 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!(
|
info!(
|
||||||
"You will get vanity keys created after {}",
|
"Starting search from {} and going forward in time (up to {} seconds)",
|
||||||
chrono::Utc::now()
|
chrono::DateTime::from_timestamp(start_timestamp, 0)
|
||||||
.checked_sub_signed(chrono::TimeDelta::seconds((dimension * iteration) as i64))
|
.unwrap_or_else(chrono::Utc::now)
|
||||||
.unwrap()
|
|
||||||
.to_rfc3339_opts(chrono::SecondsFormat::Millis, true),
|
.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();
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
// 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;
|
if (data[1] > nonce) break;
|
||||||
|
}
|
||||||
|
|
||||||
uint h[] = {0x67452301, 0xEFCDAB89, 0x98BADCFE, 0x10325476, 0xC3D2E1F0};
|
uint h[] = {0x67452301, 0xEFCDAB89, 0x98BADCFE, 0x10325476, 0xC3D2E1F0};
|
||||||
|
|
||||||
|
|
|
@ -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,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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 => {
|
||||||
|
|
Loading…
Add table
Reference in a new issue