Generating Vanity Addresses

Discussing Vanity Addresses generation.
Follow up of Algorand Wallet - Open Source - #20 by scholtz

The question is the speed of generating vanity addresses.
Messages moved to keep topic focused.


The PureStake python code runs faster, appr. 10 thousand tries/sec/CPU core.
For four letters it is typically 10…20 sec.
But to match five letters takes a long time even with that…
e.g.

$ ./algo_vanity.py SCHOL
Detected 4 cpu(s)
Found a match for SCHOL after 15733226 tries in 422.53 seconds
Address:  SCHOLEJCKQ5L322NSZVECTUESR3Z5TG46SUZIWOMS6VOF3YXFO6RP7IPTE
Private key:  fix robot already recall digital punch kingdom boring spirit issue shaft seminar grape beef mixed assume entry when sweet soup venture duck flock abstract art

You can be much faster if you’re ok with multisig accounts.
You first generate a public key / secret key.
And then you generate 1-out-of-2 multisig accounts with the second account being a random public key (to be on the safe side, you may consider hashing a random value with SHA256).
This will cost you 1 or 2 SHA256 hash per try, as opposed to 1 ED25519 key generation.

Hi, @fabrice , I have a question connected with your suggestion about using 1-of-2 multisig for vanity address generation.

You proposed to use 1-of-2 multisig, where the first address has private and public key, (a “standard” account), but the second is a “fake” address, having a public key, chosen arbitrarily?

Then the multisig address is generated from these two addresses with a hash, like we can see in the code below, taken from js-sdk?

export function fromMultisigPreImg({
  version,
  threshold,
  pks,
}: Omit<MultisigMetadata, 'addrs'> & {
  pks: Uint8Array[];
}) {
  if (version !== 1 || version > 255 || version < 0) {
    // ^ a tad redundant, but in case in the future version != 1, still check for uint8
    throw new Error(INVALID_MSIG_VERSION_ERROR_MSG);
  }
  if (
    threshold === 0 ||
    pks.length === 0 ||
    threshold > pks.length ||
    threshold > 255
  ) {
    throw new Error(INVALID_MSIG_THRESHOLD_ERROR_MSG);
  }
  const pkLen = ALGORAND_ADDRESS_BYTE_LENGTH - ALGORAND_CHECKSUM_BYTE_LENGTH;
  if (pkLen !== nacl.PUBLIC_KEY_LENGTH) {
    throw new Error(UNEXPECTED_PK_LEN_ERROR_MSG);
  }
  const merged = new Uint8Array(
    MULTISIG_PREIMG2ADDR_PREFIX.length + 2 + pkLen * pks.length
  );
  merged.set(MULTISIG_PREIMG2ADDR_PREFIX, 0);
  merged.set([version], MULTISIG_PREIMG2ADDR_PREFIX.length);
  merged.set([threshold], MULTISIG_PREIMG2ADDR_PREFIX.length + 1);
  for (let i = 0; i < pks.length; i++) {
    if (pks[i].length !== pkLen) {
      throw new Error(INVALID_MSIG_PK_ERROR_MSG);
    }
    merged.set(pks[i], MULTISIG_PREIMG2ADDR_PREFIX.length + 2 + i * pkLen);
  }
  return new Uint8Array(nacl.genericHash(merged));
}

yes

You can directly call the JS function of the SDK.