commit c0c595db51bcebdf13e6b0b08b050dc67f66a1af Author: videogame hacker Date: Wed Nov 3 07:34:48 2021 +0000 Initial commit diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..3003e78 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,9 @@ +root = true + +[*] +indent_style = space +indent_size = 4 +end_of_line = crlf +charset = utf-8 +trim_trailing_whitespace = false +insert_final_newline = true diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..ea8c4bf --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +/target diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 0000000..d9e5d47 --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,102 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "base64" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "904dfeac50f3cdaba28fc6f57fdcddb75f49ed61346676a78c4ffe55877802fd" + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "getrandom" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7fcd999463524c52659517fe2cea98493cfe485d10565e7b0fb07dbba7ad2753" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + +[[package]] +name = "libc" +version = "0.2.106" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a60553f9a9e039a333b4e9b20573b9e9b9c0bb3a11e201ccc48ef4283456d673" + +[[package]] +name = "ppv-lite86" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed0cfbc8191465bed66e1718596ee0b0b35d5ee1f41c5df2189d0fe8bde535ba" + +[[package]] +name = "rand" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e7573632e6454cf6b99d7aac4ccca54be06da05aca2ef7423d22d27d4d4bcd8" +dependencies = [ + "libc", + "rand_chacha", + "rand_core", + "rand_hc", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d34f1408f55294453790c48b2f1ebbb1c5b4b7563eb1f418bcfcfdbb06ebb4e7" +dependencies = [ + "getrandom", +] + +[[package]] +name = "rand_hc" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d51e9f596de227fda2ea6c84607f5558e196eeaf43c986b724ba4fb8fdf497e7" +dependencies = [ + "rand_core", +] + +[[package]] +name = "rand_xoshiro" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f97cdb2a36ed4183de61b2f824cc45c9f1037f28afe0a322e9fff4c108b5aaa" +dependencies = [ + "rand_core", +] + +[[package]] +name = "wasi" +version = "0.10.2+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6" + +[[package]] +name = "wireguard-vanity-key" +version = "0.1.0" +dependencies = [ + "base64", + "rand", + "rand_xoshiro", +] diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..1e4fcbd --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,11 @@ +[package] +name = "wireguard-vanity-key" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +base64 = "0.13.0" +rand = "0.8.4" +rand_xoshiro = "0.6.0" diff --git a/README.md b/README.md new file mode 100644 index 0000000..735e033 --- /dev/null +++ b/README.md @@ -0,0 +1,7 @@ +# wireguard-vanity-key + +A vanity key generator for WireGuard. Supports prefix & suffix search. + +## Requirements + +- OpenCL diff --git a/src/cpu/mod.rs b/src/cpu/mod.rs new file mode 100644 index 0000000..e62371c --- /dev/null +++ b/src/cpu/mod.rs @@ -0,0 +1,33 @@ +mod x25519; + +use self::x25519::x25519_shared_key; + +use crate::Key; +use rand::RngCore; + +#[inline] +pub fn generate_psk(rng: &mut impl RngCore) -> Key { + let mut key: Key = [0; 32]; + rng.fill_bytes(&mut key); + key +} + +#[inline] +pub fn generate_privkey(rng: &mut impl RngCore) -> Key { + let mut k = generate_psk(rng); + + // curve25519_clamp_secret + k[0] &= 0xF8; + k[31] = (k[31] & 127) | 64; + k +} + +#[inline] +pub fn get_pubkey(private_key: &Key) -> Key { + let u = [ + 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, + ]; + + x25519_shared_key(&u, private_key) +} diff --git a/src/cpu/x25519.rs b/src/cpu/x25519.rs new file mode 100644 index 0000000..d4ae6de --- /dev/null +++ b/src/cpu/x25519.rs @@ -0,0 +1,551 @@ +// Ripped from boringtun lmao + +// Copyright (c) 2019 Cloudflare, Inc. All rights reserved. +// SPDX-License-Identifier: BSD-3-Clause + +//! Elliptic-curve Diffie-Hellman exchange over Curve25519. + +use crate::Key; + +use std::ops::Add; +use std::ops::Mul; +use std::ops::Sub; + +#[inline(always)] +fn make_array(slice: &[T]) -> A +where + A: Sized + Default + AsMut<[T]> + std::borrow::Borrow<[T]>, + T: Copy, +{ + let mut arr: A = Default::default(); + let arr_len = arr.borrow().len(); + >::as_mut(&mut arr).copy_from_slice(&slice[0..arr_len]); + arr +} + +const MASK_63BITS: u128 = 0x7fff_ffff_ffff_ffff; +const MASK_64BITS: u128 = 0xffff_ffff_ffff_ffff; + +#[derive(Clone, Copy)] +// Internal structs for fast arithmetic +struct Felem([u64; 4]); +struct Felem2([u64; 8]); + +#[cfg_attr(feature = "cargo-clippy", allow(clippy::suspicious_arithmetic_impl))] +impl Add for Felem { + type Output = Felem; + #[inline(always)] + // Addition modulo 2^255 - 19 + fn add(self, other: Felem) -> Felem { + let x0 = u128::from(self.0[0]); + let x1 = u128::from(self.0[1]); + let x2 = u128::from(self.0[2]); + let x3 = u128::from(self.0[3]); + + let y0 = u128::from(other.0[0]); + let y1 = u128::from(other.0[1]); + let y2 = u128::from(other.0[2]); + let y3 = u128::from(other.0[3]); + + let mut acc0 = x0.wrapping_add(y0); + let mut acc1 = x1.wrapping_add(y1).wrapping_add(acc0 >> 64); + let mut acc2 = x2.wrapping_add(y2).wrapping_add(acc1 >> 64); + let mut acc3 = x3.wrapping_add(y3).wrapping_add(acc2 >> 64); + + let mut top = (acc3 >> 63) & 0xffff_ffff_ffff_ffff; + acc0 &= 0xffff_ffff_ffff_ffff; + acc1 &= 0xffff_ffff_ffff_ffff; + acc2 &= 0xffff_ffff_ffff_ffff; + acc3 &= 0x7fff_ffff_ffff_ffff; + + top = top.wrapping_mul(19); + acc0 = acc0.wrapping_add(top); + acc1 = acc1.wrapping_add(acc0 >> 64); + acc2 = acc2.wrapping_add(acc1 >> 64); + acc3 = acc3.wrapping_add(acc2 >> 64); + + Felem([acc0 as u64, acc1 as u64, acc2 as u64, acc3 as u64]) + } +} + +#[cfg_attr(feature = "cargo-clippy", allow(clippy::suspicious_arithmetic_impl))] +impl Sub for Felem { + type Output = Felem; + #[inline(always)] + // Subtraction modulo 2^255 - 19 + fn sub(self, other: Felem) -> Felem { + static POLY_X4: [u128; 4] = [ + 0x1_ffff_ffff_ffff_ffb4, + 0x1_ffff_ffff_ffff_fffe, + 0x1_ffff_ffff_ffff_fffe, + 0x1_ffff_ffff_ffff_fffe, + ]; + + let x0 = u128::from(self.0[0]); + let x1 = u128::from(self.0[1]); + let x2 = u128::from(self.0[2]); + let x3 = u128::from(self.0[3]); + + let y0 = u128::from(other.0[0]); + let y1 = u128::from(other.0[1]); + let y2 = u128::from(other.0[2]); + let y3 = u128::from(other.0[3]); + + let mut acc0 = POLY_X4[0].wrapping_sub(y0).wrapping_add(x0); + let mut acc1 = POLY_X4[1] + .wrapping_sub(y1) + .wrapping_add(x1) + .wrapping_add(acc0 >> 64); + let mut acc2 = POLY_X4[2] + .wrapping_sub(y2) + .wrapping_add(x2) + .wrapping_add(acc1 >> 64); + let mut acc3 = POLY_X4[3] + .wrapping_sub(y3) + .wrapping_add(x3) + .wrapping_add(acc2 >> 64); + + let mut top = (acc3 >> 63) & 0xffff_ffff_ffff_ffff; + acc0 &= 0xffff_ffff_ffff_ffff; + acc1 &= 0xffff_ffff_ffff_ffff; + acc2 &= 0xffff_ffff_ffff_ffff; + acc3 &= 0x7fff_ffff_ffff_ffff; + + top = top.wrapping_mul(19); + acc0 = acc0.wrapping_add(top); + acc1 = acc1.wrapping_add(acc0 >> 64); + acc2 = acc2.wrapping_add(acc1 >> 64); + acc3 = acc3.wrapping_add(acc2 >> 64); + + Felem([acc0 as u64, acc1 as u64, acc2 as u64, acc3 as u64]) + } +} + +#[cfg_attr(feature = "cargo-clippy", allow(clippy::suspicious_arithmetic_impl))] +impl Mul for Felem { + type Output = Felem; + #[inline(always)] + // Multiplication modulo 2^255 - 19 + fn mul(self, other: Felem) -> Felem { + let x0 = u128::from(self.0[0]); + let x1 = u128::from(self.0[1]); + let x2 = u128::from(self.0[2]); + let x3 = u128::from(self.0[3]); + + // y0 + let y0 = u128::from(other.0[0]); + let mut t = x0.wrapping_mul(y0); + let acc0 = t & 0xffff_ffff_ffff_ffff; + let mut acc1 = t >> 64; + + t = x1.wrapping_mul(y0); + acc1 = acc1.wrapping_add(t); + let mut acc2 = acc1 >> 64; + acc1 &= 0xffff_ffff_ffff_ffff; + + t = x2.wrapping_mul(y0); + acc2 = acc2.wrapping_add(t); + let mut acc3 = acc2 >> 64; + acc2 &= 0xffff_ffff_ffff_ffff; + + t = x3.wrapping_mul(y0); + acc3 = acc3.wrapping_add(t); + let mut acc4 = acc3 >> 64; + acc3 &= 0xffff_ffff_ffff_ffff; + + // y1 + let y1 = u128::from(other.0[1]); + t = x0.wrapping_mul(y1); + acc1 = acc1.wrapping_add(t); + let mut top = acc1 >> 64; + acc1 &= 0xffff_ffff_ffff_ffff; + + t = x1.wrapping_mul(y1); + acc2 = acc2.wrapping_add(top); + acc2 = acc2.wrapping_add(t); + top = acc2 >> 64; + acc2 &= 0xffff_ffff_ffff_ffff; + + t = x2.wrapping_mul(y1); + acc3 = acc3.wrapping_add(top); + acc3 = acc3.wrapping_add(t); + top = acc3 >> 64; + acc3 &= 0xffff_ffff_ffff_ffff; + + t = x3.wrapping_mul(y1); + acc4 = acc4.wrapping_add(top); + acc4 = acc4.wrapping_add(t); + let mut acc5 = acc4 >> 64; + acc4 &= 0xffff_ffff_ffff_ffff; + + // y2 + let y2 = u128::from(other.0[2]); + t = x0.wrapping_mul(y2); + acc2 = acc2.wrapping_add(t); + top = acc2 >> 64; + acc2 &= 0xffff_ffff_ffff_ffff; + + t = x1.wrapping_mul(y2); + acc3 = acc3.wrapping_add(top); + acc3 = acc3.wrapping_add(t); + top = acc3 >> 64; + acc3 &= 0xffff_ffff_ffff_ffff; + + t = x2.wrapping_mul(y2); + acc4 = acc4.wrapping_add(top); + acc4 = acc4.wrapping_add(t); + top = acc4 >> 64; + acc4 &= 0xffff_ffff_ffff_ffff; + + t = x3.wrapping_mul(y2); + acc5 = acc5.wrapping_add(top); + acc5 = acc5.wrapping_add(t); + let mut acc6 = acc5 >> 64; + acc5 &= 0xffff_ffff_ffff_ffff; + + // y3 + let y3 = u128::from(other.0[3]); + t = x0.wrapping_mul(y3); + acc3 = acc3.wrapping_add(t); + top = acc3 >> 64; + acc3 &= 0xffff_ffff_ffff_ffff; + + t = x1.wrapping_mul(y3); + acc4 = acc4.wrapping_add(top); + acc4 = acc4.wrapping_add(t); + top = acc4 >> 64; + acc4 &= 0xffff_ffff_ffff_ffff; + + t = x2.wrapping_mul(y3); + acc5 = acc5.wrapping_add(top); + acc5 = acc5.wrapping_add(t); + top = acc5 >> 64; + acc5 &= 0xffff_ffff_ffff_ffff; + + t = x3.wrapping_mul(y3); + acc6 = acc6.wrapping_add(top); + acc6 = acc6.wrapping_add(t); + let acc7 = acc6 >> 64; + acc6 &= 0xffff_ffff_ffff_ffff; + + // Modulo + mod_25519(Felem2([ + acc0 as u64, + acc1 as u64, + acc2 as u64, + acc3 as u64, + acc4 as u64, + acc5 as u64, + acc6 as u64, + acc7 as u64, + ])) + } +} + +impl Felem { + #[inline(always)] + // Repeatedly square modulo 2^255 - 19 + fn sqr(self, mut rep: u32) -> Felem { + let mut ret = self; + while rep > 0 { + ret = mod_25519(sqr_256(ret)); + rep -= 1; + } + ret + } +} + +#[inline(always)] +// Square modulo 2^255 - 19 +fn sqr_256(x: Felem) -> Felem2 { + let x0 = u128::from(x.0[0]); + let x1 = u128::from(x.0[1]); + let x2 = u128::from(x.0[2]); + let x3 = u128::from(x.0[3]); + + // y0 + let mut acc1 = x1.wrapping_mul(x0); + let mut acc2 = x2.wrapping_mul(x0); + let mut acc3 = x3.wrapping_mul(x0); + + acc2 = acc2.wrapping_add(acc1 >> 64); + acc3 = acc3.wrapping_add(acc2 >> 64); + let mut acc4 = acc3 >> 64; + + acc1 &= 0xffff_ffff_ffff_ffff; + acc2 &= 0xffff_ffff_ffff_ffff; + acc3 &= 0xffff_ffff_ffff_ffff; + + // y1 + let mut t = x2.wrapping_mul(x1); + acc3 = acc3.wrapping_add(t); + + t = x3.wrapping_mul(x1); + acc4 = acc4.wrapping_add(acc3 >> 64).wrapping_add(t); + + let mut acc5 = acc4 >> 64; + + acc3 &= 0xffff_ffff_ffff_ffff; + acc4 &= 0xffff_ffff_ffff_ffff; + + // y2 + t = x3.wrapping_mul(x2); + acc5 = acc5.wrapping_add(t); + + let mut acc6 = acc5 >> 64; + acc5 &= 0xffff_ffff_ffff_ffff; + + acc6 = acc6 << 1 | acc5 >> 63; + acc5 = acc5 << 1 | acc4 >> 63; + acc4 = acc4 << 1 | acc3 >> 63; + acc3 = acc3 << 1 | acc2 >> 63; + acc2 = acc2 << 1 | acc1 >> 63; + acc1 <<= 1; + + let mut acc7 = acc6 >> 64; + acc1 &= 0xffff_ffff_ffff_ffff; + acc2 &= 0xffff_ffff_ffff_ffff; + acc3 &= 0xffff_ffff_ffff_ffff; + acc4 &= 0xffff_ffff_ffff_ffff; + acc5 &= 0xffff_ffff_ffff_ffff; + acc6 &= 0xffff_ffff_ffff_ffff; + + let acc0 = x0.wrapping_mul(x0); + acc1 = acc1.wrapping_add(acc0 >> 64); + + t = x1.wrapping_mul(x1); + acc2 = acc2.wrapping_add(acc1 >> 64).wrapping_add(t); + acc3 = acc3.wrapping_add(acc2 >> 64); + + t = x2.wrapping_mul(x2); + acc4 = acc4.wrapping_add(acc3 >> 64).wrapping_add(t); + acc5 = acc5.wrapping_add(acc4 >> 64); + + t = x3.wrapping_mul(x3); + acc6 = acc6.wrapping_add(acc5 >> 64).wrapping_add(t); + acc7 = acc7.wrapping_add(acc6 >> 64); + + Felem2([ + acc0 as u64, + acc1 as u64, + acc2 as u64, + acc3 as u64, + acc4 as u64, + acc5 as u64, + acc6 as u64, + acc7 as u64, + ]) + + // Modulo +} + +#[inline(always)] +fn mod_25519(x: Felem2) -> Felem { + let c38 = 38_u128; + + let mut acc0 = u128::from(x.0[0]); + let mut acc1 = u128::from(x.0[1]); + let mut acc2 = u128::from(x.0[2]); + let mut acc3 = u128::from(x.0[3]); + let mut acc4 = u128::from(x.0[4]); + let mut acc5 = u128::from(x.0[5]); + let mut acc6 = u128::from(x.0[6]); + let mut acc7 = u128::from(x.0[7]); + + acc4 = acc4.wrapping_mul(c38); + acc5 = acc5.wrapping_mul(c38); + acc6 = acc6.wrapping_mul(c38); + acc7 = acc7.wrapping_mul(c38); + + acc0 = acc0.wrapping_add(acc4); + + acc1 = acc1.wrapping_add(acc0 >> 64); + acc1 = acc1.wrapping_add(acc5); + + acc2 = acc2.wrapping_add(acc1 >> 64); + acc2 = acc2.wrapping_add(acc6); + + acc3 = acc3.wrapping_add(acc2 >> 64); + acc3 = acc3.wrapping_add(acc7); + + let mut top = (acc3 >> 63) & 0xffff_ffff_ffff_ffff; + + acc0 &= 0xffff_ffff_ffff_ffff; + acc1 &= 0xffff_ffff_ffff_ffff; + acc2 &= 0xffff_ffff_ffff_ffff; + acc3 &= 0x7fff_ffff_ffff_ffff; + + top = top.wrapping_mul(19); + + acc0 = acc0.wrapping_add(top); + acc1 = acc1.wrapping_add(acc0 >> 64); + acc2 = acc2.wrapping_add(acc1 >> 64); + acc3 = acc3.wrapping_add(acc2 >> 64); + + Felem([acc0 as u64, acc1 as u64, acc2 as u64, acc3 as u64]) +} + +fn mod_final_25519(x: Felem) -> Felem { + let mut acc0 = u128::from(x.0[0]); + let mut acc1 = u128::from(x.0[1]); + let mut acc2 = u128::from(x.0[2]); + let mut acc3 = u128::from(x.0[3]); + + let mut top = acc3 >> 63; + acc3 &= MASK_63BITS; + top = top.wrapping_mul(19); + acc0 = acc0.wrapping_add(top); + acc1 = acc1.wrapping_add(acc0 >> 64); + acc2 = acc2.wrapping_add(acc1 >> 64); + acc3 = acc3.wrapping_add(acc2 >> 64); + + // Mask + acc0 &= MASK_64BITS; + acc1 &= MASK_64BITS; + acc2 &= MASK_64BITS; + acc3 &= MASK_64BITS; + + // At this point, acc{0-3} is in the range between 0 and 2^255 + 18, inclusively. It's not + // under 2^255 - 19 yet. So we are doing another round of modulo operation. + + top = acc0.wrapping_add(19) >> 64; + top = acc1.wrapping_add(top) >> 64; + top = acc2.wrapping_add(top) >> 64; + top = acc3.wrapping_add(top) >> 63; + top = top.wrapping_mul(19); + + // top is 19 if acc{0-3} is between 2^255 - 19 and 2^255 + 18, inclusively. Otherwise, it's + // zero. + + acc0 = acc0.wrapping_add(top); + acc1 = acc1.wrapping_add(acc0 >> 64); + acc2 = acc2.wrapping_add(acc1 >> 64); + acc3 = acc3.wrapping_add(acc2 >> 64); + acc3 &= MASK_63BITS; + + // Now acc{0-3} is between 0 and 2^255 - 20, inclusively. + + Felem([acc0 as u64, acc1 as u64, acc2 as u64, acc3 as u64]) +} + +// Modular inverse +fn mod_inv_25519(x: Felem) -> Felem { + let m1 = x; + let m10 = x.sqr(1); + let m1001 = m10.sqr(2) * m1; + let m1011 = m1001 * m10; + + let x5 = m1011.sqr(1) * m1001; + let x10 = x5.sqr(5) * x5; + let x20 = x10.sqr(10) * x10; + let x40 = x20.sqr(20) * x20; + let x50 = x40.sqr(10) * x10; + let x100 = x50.sqr(50) * x50; + + let t = x100.sqr(100) * x100; + let t2 = t.sqr(50) * x50; + t2.sqr(5) * m1011 +} + +#[inline(always)] +// Swap two values a and b in constant time iff swap == 1 +fn constant_time_swap(a: Felem, b: Felem, swap: u64) -> (Felem, Felem) { + let mask = 0_u64.wrapping_sub(swap); + + let mut v = [0_u64; 4]; + let mut a_out = [0_u64; 4]; + let mut b_out = [0_u64; 4]; + + v[0] = mask & (a.0[0] ^ b.0[0]); + v[1] = mask & (a.0[1] ^ b.0[1]); + v[2] = mask & (a.0[2] ^ b.0[2]); + v[3] = mask & (a.0[3] ^ b.0[3]); + + a_out[0] = v[0] ^ a.0[0]; + a_out[1] = v[1] ^ a.0[1]; + a_out[2] = v[2] ^ a.0[2]; + a_out[3] = v[3] ^ a.0[3]; + + b_out[0] = v[0] ^ b.0[0]; + b_out[1] = v[1] ^ b.0[1]; + b_out[2] = v[2] ^ b.0[2]; + b_out[3] = v[3] ^ b.0[3]; + + (Felem(a_out), Felem(b_out)) +} + +#[inline] +pub fn x25519_shared_key(peer_key: &[u8], secret_key: &[u8]) -> Key { + if peer_key.len() != 32 || secret_key.len() != 32 { + panic!("Illegal values for x25519"); + } + + let mut scalar = [0_u8; 32]; + let mut shared_key = [0_u8; 32]; + scalar[..].copy_from_slice(secret_key); + + assert!(peer_key.len() == 32); + let u = Felem([ + u64::from_le_bytes(make_array(&peer_key[0..])), + u64::from_le_bytes(make_array(&peer_key[8..])), + u64::from_le_bytes(make_array(&peer_key[16..])), + u64::from_le_bytes(make_array(&peer_key[24..])), + ]); + + scalar[0] &= 248; + scalar[31] &= 127; + scalar[31] |= 64; + + let x_1 = u; + let mut x_2 = Felem([1, 0, 0, 0]); + let mut z_2 = Felem([0, 0, 0, 0]); + let mut x_3 = u; + let mut z_3 = Felem([1, 0, 0, 0]); + let a24 = Felem([121_666, 0, 0, 0]); + let mut swap = 0; + + for pos in (0..=254).rev() { + let bit_val = u64::from((scalar[pos / 8] >> (pos & 7)) & 1); + + swap ^= bit_val; + let (mut x2, mut x3) = constant_time_swap(x_2, x_3, swap); + let (mut z2, mut z3) = constant_time_swap(z_2, z_3, swap); + swap = bit_val; + + let mut tmp0 = x3 - z3; + let mut tmp1 = x2 - z2; + x2 = x2 + z2; + z2 = x3 + z3; + + z3 = x2 * tmp0; + z2 = z2 * tmp1; + + tmp0 = tmp1.sqr(1); + tmp1 = x2.sqr(1); + x3 = z3 + z2; + z2 = z3 - z2; + + x_2 = tmp1 * tmp0; + tmp1 = tmp1 - tmp0; + z2 = z2.sqr(1); + + z3 = a24 * tmp1; + x_3 = x3.sqr(1); + tmp0 = tmp0 + z3; + + z_3 = x_1 * z2; + z_2 = tmp1 * tmp0; + } + + let (x2, _) = constant_time_swap(x_2, x_3, swap); + let (z2, _) = constant_time_swap(z_2, z_3, swap); + + let key = mod_final_25519(x2 * mod_inv_25519(z2)); + + shared_key[0..8].copy_from_slice(&key.0[0].to_le_bytes()); + shared_key[8..16].copy_from_slice(&key.0[1].to_le_bytes()); + shared_key[16..24].copy_from_slice(&key.0[2].to_le_bytes()); + shared_key[24..32].copy_from_slice(&key.0[3].to_le_bytes()); + + shared_key +} diff --git a/src/main.rs b/src/main.rs new file mode 100644 index 0000000..f6dd92c --- /dev/null +++ b/src/main.rs @@ -0,0 +1,73 @@ +use std::{ + pin::Pin, + thread::{spawn, JoinHandle}, + time::Duration, +}; + +mod cpu; +pub type Key = [u8; 32]; + +struct ProgressCounter(pub *mut u64); +unsafe impl Send for ProgressCounter {} +unsafe impl Sync for ProgressCounter {} +impl ProgressCounter { + fn incr(&mut self) { + unsafe { + *self.0 += 1; + } + } +} + +fn work(mut progress: ProgressCounter) -> JoinHandle<()> { + spawn(move || { + let mut rng = { + use rand::SeedableRng; + rand_xoshiro::Xoshiro256StarStar::from_rng(rand::thread_rng()).unwrap() + }; + + loop { + let key = cpu::generate_privkey(&mut rng); + let pub_key = cpu::get_pubkey(&key); + + progress.incr(); + + // b64(pub_key).starts_with("char/") + if pub_key[0] == 0x72 && pub_key[1] == 0x16 && pub_key[2] == 0xab && pub_key[3] >= 0xfc + { + let key_str = base64::encode(key); + let pub_key_str = base64::encode(pub_key); + println!("{} -> {}", key_str, pub_key_str); + } + } + }) +} + +const NUM_THREADS: usize = 32; + +struct Progress([u64; NUM_THREADS]); +impl Progress { + fn new() -> Self { + Progress([0; NUM_THREADS]) + } +} + +fn main() { + let mut progress = Box::pin(Progress::new()); + let _handles: Vec<_> = (0..NUM_THREADS) + .map(|id| { + let ptr = unsafe { progress.0.as_mut_ptr().add(id) }; + let progress = ProgressCounter(ptr); + work(progress) + }) + .collect(); + + let mut last_total_progress = 0; + loop { + let total_progress = progress.0.iter().sum(); + let delta = total_progress - last_total_progress; + last_total_progress = total_progress; + + println!("Guess/sec ≈ {}", delta); + std::thread::sleep(Duration::from_millis(1000)); + } +}