/** * Copyright 2011 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.bitcoin.core; import java.util.Arrays; /** * A BitCoin address is fundamentally derived from an elliptic curve public key and a set of network parameters. * It has several possible representations:<p> * * <ol> * <li>The raw public key bytes themselves. * <li>RIPEMD160 hash of the public key bytes. * <li>A base58 encoded "human form" that includes a version and check code, to guard against typos. * </ol><p> * * One may question whether the base58 form is really an improvement over the hash160 form, given * they are both very unfriendly for typists. More useful representations might include qrcodes * and identicons.<p> * * Note that an address is specific to a network because the first byte is a discriminator value. */ public class Address { private byte[] hash160; private NetworkParameters params; /** * Construct an address from parameters and the hash160 form. Example:<p> * * <pre>new Address(NetworkParameters.prodNet(), Hex.decode("4a22c3c4cbb31e4d03b15550636762bda0baf85a"));</pre> */ public Address(NetworkParameters params, byte[] hash160) { assert hash160.length == 20; this.hash160 = hash160; this.params = params; } /** * Construct an address from parameters and the standard "human readable" form. Example:<p> * * <pre>new Address(NetworkParameters.prodNet(), "17kzeh4N8g49GFvdDzSf8PjaPfyoD1MndL");</pre> */ public Address(NetworkParameters params, String address) throws AddressFormatException { this.params = params; this.hash160 = strToHash160(address); } /** The (big endian) 20 byte hash that is the core of a BitCoin address. */ public byte[] getHash160() { assert hash160 != null; return hash160; } private byte[] strToHash160(String address) throws AddressFormatException { byte[] bytes = Base58.decode(address); if (bytes.length != 25) { // Zero pad the result. byte[] tmp = new byte[25]; System.arraycopy(bytes, 0, tmp, tmp.length - bytes.length, bytes.length); bytes = tmp; } if (bytes[0] != params.addressHeader) throw new AddressFormatException(); byte[] check = Utils.doubleDigest(bytes, 0, 21); if (check[0] != bytes[21] || check[1] != bytes[22] || check[2] != bytes[23] || check[3] != bytes[24]) throw new AddressFormatException(); byte[] hash160 = new byte[20]; System.arraycopy(bytes, 1, hash160, 0, 20); return hash160; } @Override public boolean equals(Object o) { if (!(o instanceof Address)) return false; Address a = (Address) o; return Arrays.equals(a.getHash160(), getHash160()); } @Override public int hashCode() { return Arrays.hashCode(getHash160()); } @Override public String toString() { byte[] input = hash160; // A stringified address is: // 1 byte version + 20 bytes hash + 4 bytes check code (itself a truncated hash) byte[] addressBytes = new byte[1 + 20 + 4]; addressBytes[0] = params.addressHeader; System.arraycopy(input, 0, addressBytes, 1, 20); byte[] check = Utils.doubleDigest(addressBytes, 0, 21); System.arraycopy(check, 0, addressBytes, 21, 4); return Base58.encode(addressBytes); } public byte[] asBytes() { byte[] input = hash160; // A stringified address is: // 1 byte version + 20 bytes hash + 4 bytes check code (itself a truncated hash) byte[] addressBytes = new byte[1 + 20 + 4]; addressBytes[0] = params.addressHeader; System.arraycopy(input, 0, addressBytes, 1, 20); byte[] check = Utils.doubleDigest(addressBytes, 0, 21); System.arraycopy(check, 0, addressBytes, 21, 4); return addressBytes; } }