|
|
@ -4,6 +4,8 @@ import java.io.IOException; |
|
|
|
import java.security.SecureRandom; |
|
|
|
import java.security.SecureRandom; |
|
|
|
import java.security.Security; |
|
|
|
import java.security.Security; |
|
|
|
import java.util.Random; |
|
|
|
import java.util.Random; |
|
|
|
|
|
|
|
import java.util.concurrent.ExecutorService; |
|
|
|
|
|
|
|
import java.util.concurrent.Executors; |
|
|
|
|
|
|
|
|
|
|
|
import org.bouncycastle.jce.provider.BouncyCastleProvider; |
|
|
|
import org.bouncycastle.jce.provider.BouncyCastleProvider; |
|
|
|
import org.bouncycastle.jsse.provider.BouncyCastleJsseProvider; |
|
|
|
import org.bouncycastle.jsse.provider.BouncyCastleJsseProvider; |
|
|
@ -16,37 +18,87 @@ import com.google.common.primitives.Bytes; |
|
|
|
|
|
|
|
|
|
|
|
public class VanityGen { |
|
|
|
public class VanityGen { |
|
|
|
|
|
|
|
|
|
|
|
public static void main(String argv[]) throws IOException { |
|
|
|
// From utils.Base58:
|
|
|
|
if (argv.length != 1) { |
|
|
|
private static final String ALPHABET_STR = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"; |
|
|
|
System.err.println("Usage: Vanitygen <leading-chars>"); |
|
|
|
|
|
|
|
System.err.println("Example: VanityGen Qcat"); |
|
|
|
private static String prefix = null; |
|
|
|
return; |
|
|
|
|
|
|
|
|
|
|
|
private static void usage() { |
|
|
|
|
|
|
|
System.err.println("Usage: Vanitygen [-t threads] <leading-chars>"); |
|
|
|
|
|
|
|
System.err.println("Example: VanityGen Qcat"); |
|
|
|
|
|
|
|
System.exit(1); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private static class Generator implements Runnable { |
|
|
|
|
|
|
|
public void run() { |
|
|
|
|
|
|
|
Random random = new SecureRandom(); |
|
|
|
|
|
|
|
byte[] entropy = new byte[16]; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
while (true) { |
|
|
|
|
|
|
|
// Generate entropy internally
|
|
|
|
|
|
|
|
random.nextBytes(entropy); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Use SHA256 to generate more bits
|
|
|
|
|
|
|
|
byte[] hash = Crypto.digest(entropy); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Append first 4 bits from hash to end. (Actually 8 bits but we only use 4).
|
|
|
|
|
|
|
|
byte checksum = (byte) (hash[0] & 0xf0); |
|
|
|
|
|
|
|
byte[] entropy132 = Bytes.concat(entropy, new byte[] { checksum }); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
String mnemonic = BIP39.encode(entropy132, "en"); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
PrivateKeyAccount account = new PrivateKeyAccount(null, hash); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (!account.getAddress().startsWith(prefix)) |
|
|
|
|
|
|
|
continue; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
System.out.println(String.format("Address: %s, public key: %s, private key: %s, mnemonic: %s", |
|
|
|
|
|
|
|
account.getAddress(), Base58.encode(account.getPublicKey()), Base58.encode(hash), mnemonic)); |
|
|
|
|
|
|
|
System.out.flush(); |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
Security.insertProviderAt(new BouncyCastleProvider(), 0); |
|
|
|
public static void main(String argv[]) throws IOException { |
|
|
|
Security.insertProviderAt(new BouncyCastleJsseProvider(), 1); |
|
|
|
if (argv.length == 0) |
|
|
|
|
|
|
|
usage(); |
|
|
|
|
|
|
|
|
|
|
|
Random random = new SecureRandom(); |
|
|
|
int threadCount = 1; |
|
|
|
byte[] entropy = new byte[16]; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
while (true) { |
|
|
|
int argIndex = 0; |
|
|
|
// Generate entropy internally
|
|
|
|
while (argIndex < argv.length) { |
|
|
|
random.nextBytes(entropy); |
|
|
|
String arg = argv[argIndex++]; |
|
|
|
|
|
|
|
|
|
|
|
// Use SHA256 to generate more bits
|
|
|
|
if (arg.equals("-t")) { |
|
|
|
byte[] hash = Crypto.digest(entropy); |
|
|
|
if (argIndex >= argv.length) |
|
|
|
|
|
|
|
usage(); |
|
|
|
|
|
|
|
|
|
|
|
// Append first 4 bits from hash to end. (Actually 8 bits but we only use 4).
|
|
|
|
try { |
|
|
|
byte checksum = (byte) (hash[0] & 0xf0); |
|
|
|
threadCount = Integer.parseInt(argv[argIndex++]); |
|
|
|
byte[] entropy132 = Bytes.concat(entropy, new byte[] { checksum }); |
|
|
|
} catch (NumberFormatException e) { |
|
|
|
|
|
|
|
usage(); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
String mnemonic = BIP39.encode(entropy132, "en"); |
|
|
|
continue; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
PrivateKeyAccount account = new PrivateKeyAccount(null, hash); |
|
|
|
if (prefix != null) |
|
|
|
|
|
|
|
usage(); |
|
|
|
|
|
|
|
|
|
|
|
if (account.getAddress().startsWith(argv[0])) |
|
|
|
prefix = arg; |
|
|
|
System.out.println(String.format("Address: %s, public key: %s, private key: %s, mnemonic: %s", account.getAddress(), Base58.encode(account.getPublicKey()), Base58.encode(hash), mnemonic)); |
|
|
|
if (!prefix.matches("[" + ALPHABET_STR + "]+")) { |
|
|
|
|
|
|
|
System.err.println("Only the following characters are allowed:\n" + ALPHABET_STR); |
|
|
|
|
|
|
|
System.exit(1); |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Security.insertProviderAt(new BouncyCastleProvider(), 0); |
|
|
|
|
|
|
|
Security.insertProviderAt(new BouncyCastleJsseProvider(), 1); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
ExecutorService executor = Executors.newFixedThreadPool(threadCount); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
for (int ti = 0; ti < threadCount; ++ti) |
|
|
|
|
|
|
|
executor.execute(new Generator()); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|