Bitcoin/public point to address: Difference between revisions
Content added Content deleted
(Crate ripemd160 is deprecated - Update) |
(New post.) |
||
Line 613: | Line 613: | ||
<pre>"6UwLL9Risc3QfPqBUvKofHmBQ7wMtjvM" |
<pre>"6UwLL9Risc3QfPqBUvKofHmBQ7wMtjvM" |
||
</pre> |
</pre> |
||
=={{header|Java}}== |
|||
This example uses the Java code from the SHA-256 and RIPEMD-160 tasks. This complicates the code because the two |
|||
previous tasks were designed to hash a string of ASCII characters rather than a byte array. However, it enables the |
|||
task to be completed without the use of any external libraries. |
|||
<syntaxhighlight lang="java"> |
|||
import java.math.BigInteger; |
|||
import java.nio.ByteBuffer; |
|||
import java.util.Arrays; |
|||
import java.util.stream.Collectors; |
|||
import java.util.stream.Stream; |
|||
public final class BitcoinPublicPointToAddess { |
|||
public static void main(String[] args) { |
|||
String x = "50863AD64A87AE8A2FE83C1AF1A8403CB53F53E486D8511DAD8A04887E5B2352"; |
|||
String y = "2CD470243453A299FA9E77237716103ABC11A1DF38855ED6F2EE187E9C582BA6"; |
|||
if ( areValidCoordinates(x, y) ) { |
|||
System.out.println(encodeAddress(x, y)); |
|||
} else { |
|||
System.out.println("Invalid Bitcoin public point coordinates"); |
|||
} |
|||
} |
|||
// Return the encoded address of the given coordinates. |
|||
private static String encodeAddress(String x, String y) { |
|||
String publicPoint = BITCOIN_SPECIAL_VALUE + x + y; |
|||
if ( publicPoint.length() != 130 ) { |
|||
throw new AssertionError("Invalid public point string: " + publicPoint); |
|||
} |
|||
byte[] messageBytes = computeMessageBytes(publicPoint); |
|||
byte[] checksum = computeChecksum(messageBytes); |
|||
byte[] addressBytes = new byte[messageBytes.length + 4]; |
|||
System.arraycopy(messageBytes, 0, addressBytes, 0, messageBytes.length); |
|||
System.arraycopy(checksum, 0, addressBytes, 21, checksum.length); |
|||
return encodeBase58(addressBytes); |
|||
} |
|||
// Return the given byte array encoded into a base58 starting with most one '1' |
|||
private static String encodeBase58(byte[] bytes) { |
|||
final String ALPHABET = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"; |
|||
final int ALPHABET_SIZE = ALPHABET.length(); |
|||
String[] temp = new String[34]; |
|||
for ( int n = temp.length - 1; n >= 0; n-- ) { |
|||
int c = 0; |
|||
for ( int i = 0; i < bytes.length; i++ ) { |
|||
c = c * 256 + (int) ( bytes[i] & 0xFF ); |
|||
bytes[i] = (byte) ( c / ALPHABET_SIZE ); |
|||
c %= ALPHABET_SIZE; |
|||
} |
|||
temp[n] = ALPHABET.substring(c, c + 1); |
|||
} |
|||
String result = Arrays.stream(temp).collect(Collectors.joining("")); |
|||
while ( result.startsWith("11") ) { |
|||
result = result.substring(1); |
|||
} |
|||
return result; |
|||
} |
|||
// Return whether the given coordinates are those of a point on the secp256k1 elliptic curve |
|||
private static boolean areValidCoordinates(String x, String y) { |
|||
BigInteger modulus = new BigInteger("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F", 16); |
|||
BigInteger X = new BigInteger(x, 16); |
|||
BigInteger Y = new BigInteger(y, 16); |
|||
return Y.multiply(Y).mod(modulus).equals(X.multiply(X).multiply(X).add(BigInteger.valueOf(7)).mod(modulus)); |
|||
} |
|||
private static byte[] computeMessageBytes(String text) { |
|||
// Convert the hexadecimal string 'text' into a suitable ASCII string for the SHA256 hash |
|||
byte[] bytesOne = hexToBytes(text); |
|||
String asciiOne = bytesToASCIIString(bytesOne); |
|||
String hexSHA256 = SHA256.messageDigest(asciiOne); |
|||
// Convert the hexadecimal string 'hexSHA256' into a suitable ASCII string for the RIPEMD160 hash |
|||
byte[] bytesTwo = hexToBytes(hexSHA256); |
|||
String asciiTwo = bytesToASCIIString(bytesTwo); |
|||
String hexRIPEMD160 = RIPEMD160.messageDigest(asciiTwo); |
|||
hexRIPEMD160 = BITCOIN_VERSION_NUMBER + hexRIPEMD160; |
|||
return hexToBytes(hexRIPEMD160); |
|||
} |
|||
private static byte[] computeChecksum(byte[] bytes) { |
|||
// Convert the given byte array into a suitable ASCII string for the first SHA256 hash |
|||
String ascii1 = bytesToASCIIString(bytes); |
|||
String hex1 = SHA256.messageDigest(ascii1); |
|||
// Convert the hexadecimal string 'hex1' into a suitable ASCII string for the second SHA256 hash |
|||
byte[] bytes1 = hexToBytes(hex1); |
|||
String ascii2 = bytesToASCIIString(bytes1); |
|||
String hex2 = SHA256.messageDigest(ascii2); |
|||
return Arrays.copyOfRange(hexToBytes(hex2), 0, 4); |
|||
} |
|||
private static byte[] hexToBytes(String text) { |
|||
byte[] bytes = new byte[text.length() / 2]; |
|||
for ( int i = 0; i < text.length(); i += 2 ) { |
|||
final int firstDigit = Character.digit(text.charAt(i), 16); |
|||
final int secondDigit = Character.digit(text.charAt(i + 1), 16); |
|||
bytes[i / 2] = (byte) ( ( firstDigit << 4 ) + secondDigit );; |
|||
} |
|||
return bytes; |
|||
} |
|||
private static String bytesToASCIIString(byte[] hash) { |
|||
ByteBuffer buffer = ByteBuffer.wrap(hash); |
|||
return Stream.generate( () -> buffer.get() ).limit(buffer.capacity()) |
|||
.map( bb -> String.valueOf((char) ( bb & 0xFF )) ).collect(Collectors.joining("")); |
|||
} |
|||
private static final String BITCOIN_SPECIAL_VALUE = "04"; |
|||
private static final String BITCOIN_VERSION_NUMBER = "00"; |
|||
} |
|||
</syntaxhighlight> |
|||
{{ out }} |
|||
<pre> |
|||
16UwLL9Risc3QfPqBUvKofHmBQ7wMtjvM |
|||
</pre> |
|||
=={{header|Julia}}== |
=={{header|Julia}}== |
||
{{works with|Julia|0.6}} |
{{works with|Julia|0.6}} |