/** * 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 com.google.bitcoin.bouncycastle.crypto.digests.RIPEMD160Digest; import java.io.IOException; import java.io.OutputStream; import java.math.BigDecimal; import java.math.BigInteger; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; /** * A collection of various utility methods that are helpful for working with the BitCoin protocol. * To enable debug logging from the library, run with -Dbitcoinj.logging=true on your command line. */ @SuppressWarnings({"SameParameterValue"}) public class Utils { // TODO: Replace this nanocoins business with something better. /** * How many "nanocoins" there are in a BitCoin. * * A nanocoin is the smallest unit that can be transferred using BitCoin. * The term nanocoin is very misleading, though, because there are only 100 million * of them in a coin (whereas one would expect 1 billion. */ public static final BigInteger COIN = new BigInteger("100000000", 10); /** * How many "nanocoins" there are in 0.01 BitCoins. * * A nanocoin is the smallest unit that can be transferred using BitCoin. * The term nanocoin is very misleading, though, because there are only 100 million * of them in a coin (whereas one would expect 1 billion). */ public static final BigInteger CENT = new BigInteger("1000000", 10); /** Convert an amount expressed in the way humans are used to into nanocoins. */ public static BigInteger toNanoCoins(int coins, int cents) { assert cents < 100; BigInteger bi = BigInteger.valueOf(coins).multiply(COIN); bi = bi.add(BigInteger.valueOf(cents).multiply(CENT)); return bi; } /** * Convert an amount expressed in the way humans are used to into nanocoins.<p> * * This takes string in a format understood by {@link BigDecimal#BigDecimal(String)}, * for example "0", "1", "0.10", "1.23E3", "1234.5E-5". * * @throws ArithmeticException if you try to specify fractional nanocoins **/ public static BigInteger toNanoCoins(String coins){ return new BigDecimal(coins).movePointRight(8).toBigIntegerExact(); } public static void uint32ToByteArrayBE(long val, byte[] out, int offset) { out[offset + 0] = (byte) (0xFF & (val >> 24)); out[offset + 1] = (byte) (0xFF & (val >> 16)); out[offset + 2] = (byte) (0xFF & (val >> 8)); out[offset + 3] = (byte) (0xFF & (val >> 0)); } public static void uint32ToByteArrayLE(long val, byte[] out, int offset) { out[offset + 0] = (byte) (0xFF & (val >> 0)); out[offset + 1] = (byte) (0xFF & (val >> 8)); out[offset + 2] = (byte) (0xFF & (val >> 16)); out[offset + 3] = (byte) (0xFF & (val >> 24)); } public static void uint32ToByteStreamLE(long val, OutputStream stream) throws IOException { stream.write((int)(0xFF & (val >> 0))); stream.write((int)(0xFF & (val >> 8))); stream.write((int)(0xFF & (val >> 16))); stream.write((int)(0xFF & (val >> 24))); } public static void uint64ToByteStreamLE(BigInteger val, OutputStream stream) throws IOException { byte[] bytes = val.toByteArray(); if (bytes.length > 8) { throw new RuntimeException("Input too large to encode into a uint64"); } bytes = reverseBytes(bytes); stream.write(bytes); if (bytes.length < 8) { for (int i = 0; i < 8 - bytes.length; i++) stream.write(0); } } /** * See {@link Utils#doubleDigest(byte[],int,int)}. */ public static byte[] doubleDigest(byte[] input) { return doubleDigest(input, 0, input.length); } /** * Calculates the SHA-256 hash of the given byte range, and then hashes the resulting hash again. This is * standard procedure in BitCoin. The resulting hash is in big endian form. */ public static byte[] doubleDigest(byte[] input, int offset, int length) { try { MessageDigest digest = MessageDigest.getInstance("SHA-256"); digest.update(input, offset, length); byte[] first = digest.digest(); return digest.digest(first); } catch (NoSuchAlgorithmException e) { throw new RuntimeException(e); // Cannot happen. } } /** * Calculates SHA256(SHA256(byte range 1 + byte range 2)). */ public static byte[] doubleDigestTwoBuffers(byte[] input1, int offset1, int length1, byte[] input2, int offset2, int length2) { try { MessageDigest digest = MessageDigest.getInstance("SHA-256"); digest.update(input1, offset1, length1); digest.update(input2, offset2, length2); byte[] first = digest.digest(); return digest.digest(first); } catch (NoSuchAlgorithmException e) { throw new RuntimeException(e); // Cannot happen. } } /** Work around lack of unsigned types in Java. */ public static boolean isLessThanUnsigned(long n1, long n2) { return (n1 < n2) ^ ((n1 < 0) != (n2 < 0)); } /** Returns the given byte array hex encoded. */ public static String bytesToHexString(byte[] bytes) { StringBuffer buf = new StringBuffer(bytes.length * 2); for (byte b : bytes) { String s = Integer.toString(0xFF & b, 16); if (s.length() < 2) buf.append('0'); buf.append(s); } return buf.toString(); } /** Returns a copy of the given byte array in reverse order. */ public static byte[] reverseBytes(byte[] bytes) { // We could use the XOR trick here but it's easier to understand if we don't. If we find this is really a // performance issue the matter can be revisited. byte[] buf = new byte[bytes.length]; for (int i = 0; i < bytes.length; i++) buf[i] = bytes[bytes.length - 1 - i]; return buf; } public static long readUint32(byte[] bytes, int offset) { return ((bytes[offset++] & 0xFFL) << 0) | ((bytes[offset++] & 0xFFL) << 8) | ((bytes[offset++] & 0xFFL) << 16) | ((bytes[offset] & 0xFFL) << 24); } public static long readUint32BE(byte[] bytes, int offset) { return ((bytes[offset + 0] & 0xFFL) << 24) | ((bytes[offset + 1] & 0xFFL) << 16) | ((bytes[offset + 2] & 0xFFL) << 8) | ((bytes[offset + 3] & 0xFFL) << 0); } public static int readUint16BE(byte[] bytes, int offset) { return ((bytes[offset] & 0xff) << 8) | bytes[offset + 1] & 0xff; } /** * Calculates RIPEMD160(SHA256(input)). This is used in Address calculations. */ public static byte[] sha256hash160(byte[] input) { try { byte[] sha256 = MessageDigest.getInstance("SHA-256").digest(input); RIPEMD160Digest digest = new RIPEMD160Digest(); digest.update(sha256, 0, sha256.length); byte[] out = new byte[20]; digest.doFinal(out, 0); return out; } catch (NoSuchAlgorithmException e) { throw new RuntimeException(e); // Cannot happen. } } /** Returns the given value in nanocoins as a 0.12 type string. */ public static String bitcoinValueToFriendlyString(BigInteger value) { boolean negative = value.compareTo(BigInteger.ZERO) < 0; if (negative) value = value.negate(); BigInteger coins = value.divide(COIN); BigInteger cents = value.remainder(COIN); String centString = String.format("%08d", cents.intValue()); centString = centString.replaceFirst("0+$", ""); while(centString.length() < 2) centString += "0"; return String.format("%s%d.%s", negative ? "-" : "", coins.intValue(), centString); } /** * MPI encoded numbers are produced by the OpenSSL BN_bn2mpi function. They consist of * a 4 byte big endian length field, followed by the stated number of bytes representing * the number in big endian format. */ static BigInteger decodeMPI(byte[] mpi) { int length = (int) readUint32BE(mpi, 0); byte[] buf = new byte[length]; System.arraycopy(mpi, 4, buf, 0, length); return new BigInteger(buf); } // The representation of nBits uses another home-brew encoding, as a way to represent a large // hash value in only 32 bits. static BigInteger decodeCompactBits(long compact) { int size = ((int)(compact >> 24)) & 0xFF; byte[] bytes = new byte[4 + size]; bytes[3] = (byte) size; if (size >= 1) bytes[4] = (byte) ((compact >> 16) & 0xFF); if (size >= 2) bytes[5] = (byte) ((compact >> 8) & 0xFF); if (size >= 3) bytes[6] = (byte) ((compact >> 0) & 0xFF); return decodeMPI(bytes); } }