How can I generate an address with some string on it, which will check as correct? I don't want to necessarily have the private key for that address, but I want to be able to send money to it.
-
Asker: It would be helpful if you could tell us whether the linked duplicate suggestion actually addresses the problem you were asking about or whether you wanted to ask about a different topic.– Murch ♦Commented Mar 4, 2017 at 11:38
-
1@Munch Not really, but the answer here does.– MaiaVictorCommented Mar 4, 2017 at 16:34
1 Answer
Note that while your question is interesting as a learning exercise, writing messages into the blockchain in this way is not recommended as you are increasing the UTXO set. You are encouraged to use 'OP_RETURN' instead. There is a thread to which your question is related, but it does not seem to focus on the aim of creating an address with a specific message in it.
A bitcoin address (of type 'P2PKH', i.e. 'pay to public key hash') is simply a 25 bytes number, where the leading byte is 0x00
and the last four bytes (low order bytes) constitute some checksum which guarantees the address has no 'typing' error. Specifically, the last four bytes of the address are the first four bytes of the hash (specifically the double Sha256 hash) of the first 21 bytes (highest order) of the address. So in big-endian representation, a bitcoin address looks as follows:
address (25 bytes) = [0x00][20 bytes][checksum (4 bytes)]
As it turns out, since you are not concerned about recovering any fund sent to your address, you have complete freedom on how to choose the 20 bytes (normally those 20 bytes would be some hash of a valid public key). The only constraints you have are the leading byte 0x00
and the last 4 bytes which will depend on how you chose the 20 bytes.
Now suppose you wish to send the message "HelloWorldHowAreYouIamOk".
One naive approach consists in focusing on the number 1HeLLoWorLdHowAreYouiAmok111 (expressed in base 58) which is of length 21 bytes with a leading 0x00
byte, calculate the hash (double Sha256) of these 21 bytes, keep the first 4 bytes of the hash and append these 4 bytes to the 21 bytes. However, the operation of appending 4 bytes to the right means you are effectively multiplying your 21 bytes number by 256^4 and then add the 4 bytes number. This will completely mess up the Base58 digits of your initial number.
So what you need to do instead is focus on the number 1HeLLoWorLdHowAreYouiAmok111111111 (expressed in Base58, add enough padding so your number is 25 bytes), keep the high order 21 bytes of this number, compute the double hash of these 21 bytes and append the first 4 bytes of the hash to the 21 bytes. In our example, we obtain 1HeLLoWorLdHowAreYouiAmojzzzzu7udH.
As you can see, this is not quite what we were hoping, as the 'k' Base58 digit of 'iAmok' has been replaced by 'j', due to the interference of the last 4 bytes. We should have chosen a shorter message.
I attach some java code to illustrate the procedure:
import org.bitcoinj.core.Base58;
import org.bitcoinj.core.Sha256Hash;
import org.bitcoinj.params.MainNetParams;
import org.bitcoinj.core.NetworkParameters;
import org.bitcoinj.core.Address;
class Test {
public static void main(String[] args)
{
NetworkParameters main = MainNetParams.get(); // main bitcoin network
// alphabet is "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz";
// This is where we decide what we want to say. The base 58 alphabet
// does not allow us to use 'l', 'I', 'O' or '0' but that's fine.
// We are trying to obtain a number which is 25 bytes long with a leading
// byte of 0x00. So we probably need to start with a leading '1', and
// we need to add some padding to the right.
String target="1HeLLoWorLdHowAreYouiAmok111111111";
// Let us express this number as an array of bytes (big-endian)
byte[] bytes25 = Base58.decode(target);
// let us check our number has the correct size
System.out.println("Size = " + bytes25.length); // 25 , good
// let us check the leading byte is indeed 0x00
System.out.println("bytes25[0] = " + bytes25[0]); // yes it is !
// retrieving the first 21 bytes
byte[] bytes21 = new byte[21];
System.arraycopy(bytes25, 0, bytes21, 0, 21);
// Let us get the double Sha256 hash of these 21 bytes
byte[] hash = Sha256Hash.hashTwice(bytes21);
// Let us create the bytes of the address
byte[] addr = new byte[25];
// copying first 21 bytes to address
System.arraycopy(bytes21, 0, addr, 0, 21);
// appending first 4 bytes of hash to address
System.arraycopy(hash, 0, addr, 21, 4);
// encoding this 25 bytes address in Base 58
String strAddr = Base58.encode(addr);
// Address = "1HeLLoWorLdHowAreYouiAmojzzzzu7udH" , almost perfect !
System.out.println("Address = " + strAddr);
// let us check address is a valid bitcoin address
Address address = Address.fromBase58(main, strAddr); // no errors, good
}
}