In order to outsource the generation of a desired vanity address, say with the prefix 1Love
, we generate a key pair p, P. We then share P with the seller, who will find the public key of our final vanity address. He will then go through many values of a partial private key x, until P + x*G yields a public key P', the address of which will contain our desired prefix. He then shares this key x, so we can assemble the private key of P', by calculating k = (p + x) * G.
import "ec.scrypt";
import "util.scrypt";
import "base58.scrypt";
contract VanityAddr {
PubKey P;
bytes pattern;
Ripemd160 cancelPubKeyHash;
public function cancel(Sig sig, PubKey pubKey) {
require(hash160(pubKey) == this.cancelPubKeyHash);
require(checkSig(sig, pubKey));
}
public function offerVanityAddr(PrivKey x,
PubKey X,
PubKey derP,
int lambda,
SigHashPreimage txPreimage) {
// Check if x is private key of X.
require(Tx.checkPreimageAdvanced(txPreimage, x, X, Tx.invK, Tx.r, Tx.rBigEndian, SigHashType(SigHash.ALL | SigHash.FORKID)));
// Check if P' = P + X.
require(EC.isPubKeySum(this.P, X, lambda, derivedPubKey));
// Check if P' produces desired address.
PubKey derivedPubKeyCompressed = compressPubKey(derivedPubKey);
require(matchPattern(derivedPubKeyCompressed, this.pattern));
}
// Check if public key's address matches the given pattern.
static function matchPattern(PubKey pubKey, bytes pattern) : bool {
// Derive the address.
bytes addr = hash160(pubKey);
// Encode to base58check.
bytes addrB58 = Base58.base58EncodeCheckAddr(addr, Base58.P2PKH_verbyte_mainnet);
// Prefix match.
int l = len(pattern);
return addrB58[:l] == pattern;
}
static function compressPubKey(PubKey pk) : PubKey {
// Check if y-coord is even or odd
bool isEven = (pk[63:64] & b'01') != b'01';
bytes prefix = isEven ? b'02' : b'03';
return PubKey(prefix + pk[1:33]);
}
}