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}}