Bitcoin/address validation: Difference between revisions
New post showing an alternative version of an existing example which was retained.
(New post showing an alternative version of an existing example which was retained.) |
|||
(18 intermediate revisions by 7 users not shown) | |||
Line 1:
[[Category:Checksums]]
{{alertbox|#ffff70|'''<big>Warning:</big>''' Many of these snippets are [[{{TALKPAGENAME}}#C-based_code_.28and_possibly_others.29_improperly_validates|incomplete]]. It is recommended that you use an established [https://en.bitcoin.it/wiki/Software#Libraries library] for any projects that are likely to see external use}}
{{task}}
Line 38 ⟶ 36:
<br>You can change a few characters in this string and check that it'll fail the test.
<br><br>
=={{header|Ada}}==
<
with Ada.Streams;
use Ada.Exceptions, Interfaces;
Line 168 ⟶ 165:
end;
end Bitcoin_Addr_Validate;
</syntaxhighlight>
{{out}}
Line 177 ⟶ 174:
1A Na15ZQXAZUgFiqJ2i7Z2DPU2J6hW62i validity: *** Error: Invalid BT address.
</pre>
=={{header|C}}==
<
#include <string.h>
#include <openssl/sha.h>
Line 239 ⟶ 235:
return 0;
}</
Compile with -lcrypto
{{out}}
Line 248 ⟶ 244:
1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62I: bad char
</pre>
=={{header|C sharp|C#}}==
This requires [https://www.nuget.org/packages/NUnit/ NUnit package] to compile.
<
using System;
using System.Linq;
Line 321 ⟶ 316:
}
}
</syntaxhighlight>
=={{header|C++}}==
This example uses the C++ code from the SHA-256 task. This slightly complicates the code because the previous task
was designed to hash a string of ASCII characters rather than a byte array.
<syntaxhighlight lang="c++">
#include <algorithm>
#include <cstdint>
#include <iostream>
#include <map>
#include <stdexcept>
#include <string>
#include <vector>
#include "SHA256.cpp"
SHA256 sha256{ };
const std::string ALPHABET = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz";
std::map<char, uint32_t> base_map =
{ { '0', 0 }, { '1', 1 }, { '2', 2 }, { '3', 3 }, { '4', 4 }, { '5', 5 }, { '6', 6 }, { '7', 7 },
{ '8', 8 }, { '9', 9 }, { 'a', 10 }, { 'b', 11 }, { 'c', 12 }, { 'd', 13 }, { 'e', 14 }, { 'f', 15 },
{ 'A', 10 }, { 'B', 11 }, { 'C', 12 }, { 'D', 13 }, { 'E', 14 }, { 'F', 15 } };
std::vector<uint32_t> hex_to_bytes(const std::string& text) {
std::vector<uint32_t> bytes(text.size() / 2, 0);
for ( uint64_t i = 0; i < text.size(); i += 2 ) {
const uint32_t first_digit = base_map[text[i]];
const uint32_t second_digit = base_map[text[i + 1]];
bytes[i / 2] = ( first_digit << 4 ) + second_digit;
}
return bytes;
}
std::string vector_to_ascii_string(const std::vector<uint32_t>& bytes) {
std::string result = "";
for ( uint32_t i = 0; i < bytes.size(); ++i ) {
result += static_cast<char>(bytes[i]);
}
return result;
}
std::vector<uint32_t> decode_base_58(const std::string& text) {
std::vector<uint32_t> result(25, 0);
for ( const char& ch : text ) {
std::string::size_type index = ALPHABET.find(ch);
if ( index == static_cast<uint64_t>(-1) ) {
throw std::invalid_argument("Invalid character found in bitcoin address");
}
for ( uint64_t i = result.size() - 1; i > 0; i-- ) {
index += 58 * result[i];
result[i] = index & 0xFF;
index >>= 8;
}
if ( index != 0 ) {
throw std::invalid_argument("Bitcoin address is too long");
}
}
return result;
}
bool is_valid(const std::string& address) {
if ( address.size() < 26 || address.size() > 35 ) {
throw std::invalid_argument("Invalid length of bitcoin address");
}
std::vector<uint32_t> decoded = decode_base_58(address);
std::vector first21(decoded.begin(), decoded.begin() + 21);
// Convert the 'first21' into a suitable ASCII string for the first SHA256 hash
std::string text = vector_to_ascii_string(first21);
std::string hash_1 = sha256.message_digest(text);
// Convert 'hashOne' into a suitable ASCII string for the second SHA256 hash
std::vector<uint32_t> bytes_1 = hex_to_bytes(hash_1);
std::string ascii_1 = vector_to_ascii_string(bytes_1);
std::string hash_2 = sha256.message_digest(ascii_1);
std::vector<uint32_t> bytes_2 = hex_to_bytes(hash_2);
std::vector<uint32_t> checksum(bytes_2.begin(), bytes_2.begin() + 4);
std::vector<uint32_t> last4(decoded.begin() + 21, decoded.begin() + 25);
return checksum == last4;
}
int main() {
const std::vector<std::string> addresses = { "1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62i",
"1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62j",
"1Q1pE5vPGEEMqRcVRMbtBK842Y6Pzo6nK9",
"1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62X",
"1ANNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62i" };
for ( const std::string& address : addresses ) {
std::cout << address << " : " << std::boolalpha << is_valid(address) << std::endl;
}
}
</syntaxhighlight>
{{ out }}
<pre>
1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62i : true
1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62j : false
1Q1pE5vPGEEMqRcVRMbtBK842Y6Pzo6nK9 : true
1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62X : false
1ANNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62i : false
</pre>
=={{header|D}}==
This requires the D module from the SHA-256 Task.
{{trans|Go}}
<
struct A25 {
Line 410 ⟶ 507:
writefln(`"%s": %s`, test, err.empty ? "OK." : err);
}
}</
{{out}}
<pre>"1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62i": OK.
Line 417 ⟶ 514:
"1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62iz": not Bitcoin version 0.
"1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62izz": too long Bitcoin address.</pre>
=={{header|dart}}==
This requires [https://pub.dev/packages/crypto Crypto package] to compile.
{{trans|Java}}
<syntaxhighlight lang="dart">import 'package:crypto/crypto.dart';
class Bitcoin {
final String ALPHABET =
"123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz";
List<int> bigIntToByteArray(BigInt data) {
String str;
bool neg = false;
if (data < BigInt.zero) {
str = (~data).toRadixString(16);
neg = true;
} else str = data.toRadixString(16);
int p = 0;
int len = str.length;
int blen = (len + 1) ~/ 2;
int boff = 0;
List bytes;
if (neg) {
if (len & 1 == 1) {
p = -1;
}
int byte0 = ~int.parse(str.substring(0, p + 2), radix: 16);
if (byte0 < -128) byte0 += 256;
if (byte0 >= 0) {
boff = 1;
bytes = new List<int>(blen + 1);
bytes[0] = -1;
bytes[1] = byte0;
} else {
bytes = new List<int>(blen);
bytes[0] = byte0;
}
for (int i = 1; i < blen; ++i) {
int byte = ~int.parse(str.substring(p + (i << 1), p + (i << 1) + 2),
radix: 16);
if (byte < -128) byte += 256;
bytes[i + boff] = byte;
}
} else {
if (len & 1 == 1) {
p = -1;
}
int byte0 = int.parse(str.substring(0, p + 2), radix: 16);
if (byte0 > 127) byte0 -= 256;
if (byte0 < 0) {
boff = 1;
bytes = new List<int>(blen + 1);
bytes[0] = 0;
bytes[1] = byte0;
} else {
bytes = new List<int>(blen);
bytes[0] = byte0;
}
for (int i = 1; i < blen; ++i) {
int byte =
int.parse(str.substring(p + (i << 1), p + (i << 1) + 2), radix: 16);
if (byte > 127) byte -= 256;
bytes[i + boff] = byte;
}
}
return bytes;
}
List<int> arrayCopy(bytes, srcOffset, result, destOffset, bytesLength) {
for (int i = srcOffset; i < bytesLength; i++) {
result[destOffset + i] = bytes[i];
}
return result;
}
List<int> decodeBase58To25Bytes(String input) {
BigInt number = BigInt.zero;
for (String t in input.split('')) {
int p = ALPHABET.indexOf(t);
if (p == (-1))
return null;
number = number * (BigInt.from(58)) + (BigInt.from(p));
}
List<int> result = new List<int>(24);
List<int> numBytes = bigIntToByteArray(number);
return arrayCopy(
numBytes, 0, result, result.length - numBytes.length, numBytes.length);
}
validateAddress(String address) {
List<int> decoded = new List.from(decodeBase58To25Bytes(address));
List<int> temp = new List<int>.from(decoded);
temp.insert(0, 0);
List<int> hash1 = sha256.convert(temp.sublist(0, 21)).bytes;
List<int> hash2 = sha256.convert(hash1).bytes;
if (hash2[0] != decoded[20] ||
hash2[1] != decoded[21] ||
hash2[2] != decoded[22] ||
hash2[3] != decoded[23]) return false;
return true;
}
}</syntaxhighlight>
{{out}}
<pre>"1BNGaR29FmfAqidXmD9HLwsGv9p5WVvvhq" true
"1BNGaR29FmfAqidXmD9HLws" false
</pre>
=={{header|Delphi}}==
This requires [http://www.cityinthesky.co.uk/opensource/DCPcrypt/ DCPcrypt library] to compile.
<
uses
DCPsha256;
Line 485 ⟶ 687:
raise Exception.Create('Bad digest');
end;
</syntaxhighlight>
=={{header|Erlang}}==
Using base58 module from http://github.com/titan098/erl-base58.git.
<syntaxhighlight lang="erlang">
-module( bitcoin_address ).
Line 508 ⟶ 709:
{checksum, Checksum} = {checksum, Four_bytes},
ok.
</syntaxhighlight>
{{out}}
<pre>
Line 520 ⟶ 721:
</pre>
=={{header|Factor}}==
<
math.parser sequences ;
IN: rosetta-code.bitcoin.validation
Line 536 ⟶ 737:
: btc-valid? ( str -- ? ) base58> [ btc-checksum ] [ 4 tail* ] bi = ;
</syntaxhighlight>
{{out}}
Line 544 ⟶ 745:
"1ANNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62i" btc-valid? . ! f, data changed, original checksum.
</pre>
=={{header|FreeBASIC}}==
<
' compile with: fbc -s console
Line 751 ⟶ 951:
Print : Print "hit any key to end program"
Sleep
End</
{{out}}
<pre>Bitcoin address: 1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62i is valid
Line 758 ⟶ 958:
Bitcoin address: 0AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62i first character is not 1 or 3
Bitcoin address: 1AGNa15ZQXAZUgFlqJ2i7Z2DPU2J6hW62i bitcoin address contains illegal character</pre>
=={{header|Go}}==
{{trans|C}}
<
import (
Line 869 ⟶ 1,068:
os.Stderr.WriteString(m + "\n")
os.Exit(1)
}</
{{out}}
Command line usage examples showing program exit status.
Line 895 ⟶ 1,094:
</pre>
=={{header|Haskell}}==
<
import Data.List (elemIndex)
import Data.Monoid ((<>))
Line 953 ⟶ 1,152:
validate "1ANa55215ZQXAZUgFiqJ2i7Z2DPU2J6hW62i" -- too long
validate "i55j" -- too short
</syntaxhighlight>
{{out}}
<pre style="font-size:80%">"1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62i" -> Valid
Line 962 ⟶ 1,161:
"1ANa55215ZQXAZUgFiqJ2i7Z2DPU2J6hW62i" -> "Address length exceeds 25 bytes"
"i55j" -> "Address length less than 4 bytes"</pre>
=={{header|Java}}==
<
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
Line 1,051 ⟶ 1,230:
throw new AssertionError(String.format("Expected %s for %s, but got %s.", expected, address, actual));
}
}</
===Alternative Version===
This example uses the Java code from the SHA-256 task as an alternative to using Java's built-in SHA256 method. It
also decodes Base58 without using Java's built-in BigInteger class.
<syntaxhighlight lang="java">
import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import java.util.List;
public final class BitcoinAddressValidation {
public static void main(String[] args) {
List<String> addresses = List.of ( "1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62i",
"1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62j",
"1Q1pE5vPGEEMqRcVRMbtBK842Y6Pzo6nK9",
"1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62X",
"1ANNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62i" );
for ( String address : addresses ) {
System.out.println(address + " : " + isValid(address));
}
}
private static boolean isValid(String address) {
if ( address.length() < 26 || address.length() > 35 ) {
throw new AssertionError("Invalid length of bitcoin address");
}
byte[] decoded = decodeBase58(address);
byte[] first21 = Arrays.copyOfRange(decoded, 0, 21);
// Convert 'first21' into an ASCII string for the first SHA256 hash
String text = new String(first21, StandardCharsets.ISO_8859_1);
String hashOne = SHA256.messageDigest(text);
// Convert 'hashOne' into an ASCII string for the second SHA256 hash
byte[] bytesOne = hexToBytes(hashOne);
String asciiOne = new String(bytesOne, StandardCharsets.ISO_8859_1);
String hashTwo = SHA256.messageDigest(asciiOne);
byte[] bytesTwo = hexToBytes(hashTwo);
byte[] checksum = Arrays.copyOfRange(bytesTwo, 0, 4);
byte[] last4 = Arrays.copyOfRange(decoded, 21, 25);
return Arrays.equals(last4, checksum);
}
private static byte[] decodeBase58(String text) {
byte[] result = new byte[25];
for ( char ch : text.toCharArray() ) {
int index = ALPHABET.indexOf(ch);
if ( index == -1 ) {
throw new AssertionError("Invalid character found in bitcoin address: " + ch);
}
for ( int i = result.length - 1; i > 0; i-- ) {
index += 58 * (int) ( result[i] & 0xFF );
result[i] = (byte) ( index & 0xFF );
index >>= 8;
}
if ( index != 0 ) {
throw new AssertionError("Bitcoin address is too long");
}
}
return result;
}
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 final String ALPHABET = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz";
}
</syntaxhighlight>
{{ out }}
<pre>
1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62i : true
1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62j : false
1Q1pE5vPGEEMqRcVRMbtBK842Y6Pzo6nK9 : true
1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62X : false
1ANNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62i : false
</pre>
=={{header|Julia}}==
{{works with|Julia|0.6}}
{{trans|Python}}
<
bytes(n::Integer, l::Int) = collect(UInt8, (n >> 8i) & 0xFF for i in l-1:-1:0)
Line 1,093 ⟶ 1,357:
for (addr, corr) in addresses
println("Address: $addr\nExpected: $corr\tChecked: ", checkbcaddress(addr))
end</
{{out}}
Line 1,122 ⟶ 1,386:
Address: 1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62iz
Expected: false Checked: false</pre>
=={{header|Kotlin}}==
{{trans|Java}}
<
object Bitcoin {
Line 1,184 ⟶ 1,447:
for (address in addresses)
println("${address.padEnd(36)} -> ${if (Bitcoin.validateAddress(address)) "valid" else "invalid"}")
}</
{{out}}
Line 1,202 ⟶ 1,465:
1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62I -> invalid
</pre>
=={{header|Mathematica}} / {{header|Wolfram Language}}==
<syntaxhighlight lang="mathematica">chars = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"; data =
IntegerDigits[
FromDigits[
StringPosition[chars, #][[1]] - 1 & /@ Characters[InputString[]],
58], 256, 25];
data[[-4 ;;]] ==
IntegerDigits[
Hash[FromCharacterCode[
IntegerDigits[Hash[FromCharacterCode[data[[;; -5]]], "SHA256"],
256, 32]], "SHA256"], 256, 32][[;; 4]]</syntaxhighlight>
{{in}}
<pre>1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62i
2AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62i</pre>
{{out}}
<pre>True
False</pre>
=={{header|Nim}}==
Tests on first digit character and on address length have been added to detect wrong addresses such as "BZbvjr".
===Using “libssl”===
<
const SHA256Len = 32
Line 1,269 ⟶ 1,549:
stdout.write(vector & " : ")
try:
if vector[0] notin {'1', '3'}:
raise newException(ValueError, "invalid starting character")
if vector.len < 26:
raise newException(ValueError, "address too short")
decodeBase58(vector, buf)
Line 1,282 ⟶ 1,567:
main()
</syntaxhighlight>
{{out}}
<pre>3yQ : NG - address too short
1Q1pE5vPGEEMqRcVRMbtBK842Y6Pzo6nK9 : OK
1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62i : OK
Line 1,297 ⟶ 1,581:
16UwLL9Risc3QfPqBUvKofHmBQ7wMtjvM : OK
1111111111111111111114oLvT2 : OK
BZbvjr : NG - invalid starting character</pre>
===Using “nimcrypto”===
{{libheader|nimcrypto}}
<syntaxhighlight lang="nim">import nimcrypto
import strformat
const
DecodedLength = 25 # Decoded address length.
CheckSumLength = 4 # Checksum length in address.
# Representation of a decoded address.
type Bytes25 = array[DecodedLength, byte]
#---------------------------------------------------------------------------------------------------
proc base58Decode(input: string): Bytes25 =
## Decode a base58 encoded bitcoin address.
const Base = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"
for ch in input:
var n = Base.find(ch)
if n < 0:
raise newException(ValueError, "invalid character: " & ch)
for i in countdown(result.high, 0):
n += 58 * result[i].int
result[i] = byte(n and 255)
n = n div 256
if n != 0:
raise newException(ValueError, "decoded address is too long")
#---------------------------------------------------------------------------------------------------
proc verifyChecksum(data: Bytes25) =
## Verify that data has the expected checksum.
var digest = sha256.digest(data.toOpenArray(0, data.high - CheckSumLength))
digest = sha256.digest(digest.data)
if digest.data[0..<CheckSumLength] != data[^CheckSumLength..^1]:
raise newException(ValueError, "wrong checksum")
#---------------------------------------------------------------------------------------------------
proc checkValidity(address: string) =
## Check the validity of a bitcoin address.
try:
if address[0] notin {'1', '3'}:
raise newException(ValueError, "starting character is not 1 or 3")
if address.len < 26:
raise newException(ValueError, "address too short")
address.base58Decode().verifyChecksum()
echo fmt"Address “{address}” is valid."
except ValueError:
echo fmt"Address “{address}” is invalid ({getCurrentExceptionMsg()})."
#———————————————————————————————————————————————————————————————————————————————————————————————————
const testVectors : seq[string] = @[
"3yQ", # Invalid.
"1Q1pE5vPGEEMqRcVRMbtBK842Y6Pzo6nK9", # Valid.
"1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62i", # Valid.
"1Q1pE5vPGEEMqRcVRMbtBK842Y6Pzo6nJ9", # Invalid.
"1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62I", # Invalid.
"1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62ix", # Invalid.
"1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62ixx", # Invalid.
"17NdbrSGoUotzeGCcMMCqnFkEvLymoou9j", # Valid.
"1badbadbadbadbadbadbadbadbadbadbad", # Invalid.
"16UwLL9Risc3QfPqBUvKofHmBQ7wMtjvM", # Valid.
"1111111111111111111114oLvT2", # Valid.
"BZbvjr"] # Invalid.
for vector in testVectors:
vector.checkValidity()</syntaxhighlight>
{{out}}
<pre>Address “3yQ” is invalid (address too short).
Address “1Q1pE5vPGEEMqRcVRMbtBK842Y6Pzo6nK9” is valid.
Address “1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62i” is valid.
Address “1Q1pE5vPGEEMqRcVRMbtBK842Y6Pzo6nJ9” is invalid (wrong checksum).
Address “1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62I” is invalid (invalid character: I).
Address “1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62ix” is invalid (wrong checksum).
Address “1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62ixx” is invalid (decoded address is too long).
Address “17NdbrSGoUotzeGCcMMCqnFkEvLymoou9j” is valid.
Address “1badbadbadbadbadbadbadbadbadbadbad” is invalid (wrong checksum).
Address “16UwLL9Risc3QfPqBUvKofHmBQ7wMtjvM” is valid.
Address “1111111111111111111114oLvT2” is valid.
Address “BZbvjr” is invalid (starting character is not 1 or 3).</pre>
=={{header|Oberon-2}}==
{{works with|oo2c}}{{libheader|Crypto}}
<
MODULE BitcoinAddress;
IMPORT
Line 1,386 ⟶ 1,761:
Out.Bool(Valid("1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62I"));Out.Ln
END BitcoinAddress.
</syntaxhighlight>
{{out}}
<pre>
Line 1,395 ⟶ 1,770:
FALSE
</pre>
=={{header|Perl}}==
<
1 2 3 4 5 6 7 8 9
A B C D E F G H J K L M N P Q R S T U V W X Y Z
Line 1,428 ⟶ 1,802:
(pack 'C*', @byte[21..24]) eq
substr sha256(sha256 pack 'C*', @byte[0..20]), 0, 4;
}</
=={{header|Phix}}==
<!--<syntaxhighlight lang="phix">(phixonline)-->
<span style="color: #000080;font-style:italic;">--
-- demo\rosetta\bitcoin_address_validation.exw
-- ===========================================
--</span>
<span style="color: #008080;">with</span> <span style="color: #008080;">javascript_semantics</span>
<span style="color: #008080;">include</span> <span style="color: #000000;">builtins</span><span style="color: #0000FF;">\</span><span style="color: #7060A8;">sha256</span><span style="color: #0000FF;">.</span><span style="color: #000000;">e</span>
<span style="color: #008080;">constant</span> <span style="color: #000000;">b58</span> <span style="color: #0000FF;">=</span> <span style="color: #008000;">"123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"</span>
<span style="color: #004080;">string</span> <span style="color: #000000;">charmap</span> <span style="color: #0000FF;">=</span> <span style="color: #008000;">""</span>
<span style="color: #008080;">function</span> <span style="color: #000000;">valid</span><span style="color: #0000FF;">(</span><span style="color: #004080;">string</span> <span style="color: #000000;">s</span><span style="color: #0000FF;">,</span> <span style="color: #004080;">bool</span> <span style="color: #000000;">expected</span><span style="color: #0000FF;">)</span>
<span style="color: #004080;">bool</span> <span style="color: #000000;">res</span> <span style="color: #0000FF;">:=</span> <span style="color: #0000FF;">(</span><span style="color: #000000;">expected</span><span style="color: #0000FF;">==</span><span style="color: #004600;">false</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">charmap</span><span style="color: #0000FF;">=</span><span style="color: #008000;">""</span> <span style="color: #008080;">then</span>
<span style="color: #000000;">charmap</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">repeat</span><span style="color: #0000FF;">(</span><span style="color: #008000;">'\0'</span><span style="color: #0000FF;">,</span><span style="color: #000000;">256</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">for</span> <span style="color: #000000;">i</span><span style="color: #0000FF;">=</span><span style="color: #000000;">1</span> <span style="color: #008080;">to</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">b58</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">do</span>
<span style="color: #000000;">charmap</span><span style="color: #0000FF;">[</span><span style="color: #000000;">b58</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">]]</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">i</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #000080;font-style:italic;">-- not at all sure about this:
-- if length(s)!=34 then
-- return {expected==false,"bad length"}
-- end if</span>
<span style="color: #008080;">if</span> <span style="color: #008080;">not</span> <span style="color: #7060A8;">find</span><span style="color: #0000FF;">(</span><span style="color: #000000;">s</span><span style="color: #0000FF;">[</span><span style="color: #000000;">1</span><span style="color: #0000FF;">],</span><span style="color: #008000;">"13"</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">then</span>
<span style="color: #008080;">return</span> <span style="color: #0000FF;">{</span><span style="color: #000000;">res</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"first character is not 1 or 3"</span><span style="color: #0000FF;">}</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #004080;">string</span> <span style="color: #000000;">out</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">repeat</span><span style="color: #0000FF;">(</span><span style="color: #008000;">'\0'</span><span style="color: #0000FF;">,</span><span style="color: #000000;">25</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">for</span> <span style="color: #000000;">i</span><span style="color: #0000FF;">=</span><span style="color: #000000;">1</span> <span style="color: #008080;">to</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">s</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">do</span>
<span style="color: #004080;">integer</span> <span style="color: #000000;">c</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">charmap</span><span style="color: #0000FF;">[</span><span style="color: #000000;">s</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">]]</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">c</span><span style="color: #0000FF;">=</span><span style="color: #000000;">0</span> <span style="color: #008080;">then</span>
<span style="color: #008080;">return</span> <span style="color: #0000FF;">{</span><span style="color: #000000;">res</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"bad char"</span><span style="color: #0000FF;">}</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #000000;">c</span> <span style="color: #0000FF;">-=</span> <span style="color: #000000;">1</span>
<span style="color: #008080;">for</span> <span style="color: #000000;">j</span><span style="color: #0000FF;">=</span><span style="color: #000000;">25</span> <span style="color: #008080;">to</span> <span style="color: #000000;">1</span> <span style="color: #008080;">by</span> <span style="color: #0000FF;">-</span><span style="color: #000000;">1</span> <span style="color: #008080;">do</span>
<span style="color: #000000;">c</span> <span style="color: #0000FF;">+=</span> <span style="color: #000000;">58</span> <span style="color: #0000FF;">*</span> <span style="color: #000000;">out</span><span style="color: #0000FF;">[</span><span style="color: #000000;">j</span><span style="color: #0000FF;">];</span>
<span style="color: #000000;">out</span><span style="color: #0000FF;">[</span><span style="color: #000000;">j</span><span style="color: #0000FF;">]</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">and_bits</span><span style="color: #0000FF;">(</span><span style="color: #000000;">c</span><span style="color: #0000FF;">,</span><span style="color: #000000;">#FF</span><span style="color: #0000FF;">)</span>
<span style="color: #000000;">c</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">floor</span><span style="color: #0000FF;">(</span><span style="color: #000000;">c</span><span style="color: #0000FF;">/</span><span style="color: #000000;">#100</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">c</span><span style="color: #0000FF;">!=</span><span style="color: #000000;">0</span> <span style="color: #008080;">then</span>
<span style="color: #008080;">return</span> <span style="color: #0000FF;">{</span><span style="color: #000000;">res</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"address too long"</span><span style="color: #0000FF;">}</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">out</span><span style="color: #0000FF;">[</span><span style="color: #000000;">1</span><span style="color: #0000FF;">]!=</span><span style="color: #008000;">'\0'</span> <span style="color: #008080;">then</span>
<span style="color: #008080;">return</span> <span style="color: #0000FF;">{</span><span style="color: #000000;">res</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"not version 0"</span><span style="color: #0000FF;">}</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">out</span><span style="color: #0000FF;">[</span><span style="color: #000000;">22</span><span style="color: #0000FF;">..$]!=</span><span style="color: #7060A8;">sha256</span><span style="color: #0000FF;">(</span><span style="color: #7060A8;">sha256</span><span style="color: #0000FF;">(</span><span style="color: #000000;">out</span><span style="color: #0000FF;">[</span><span style="color: #000000;">1</span><span style="color: #0000FF;">..</span><span style="color: #000000;">21</span><span style="color: #0000FF;">]))[</span><span style="color: #000000;">1</span><span style="color: #0000FF;">..</span><span style="color: #000000;">4</span><span style="color: #0000FF;">]</span> <span style="color: #008080;">then</span>
<span style="color: #008080;">return</span> <span style="color: #0000FF;">{</span><span style="color: #000000;">res</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"bad digest"</span><span style="color: #0000FF;">}</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #000000;">res</span> <span style="color: #0000FF;">:=</span> <span style="color: #0000FF;">(</span><span style="color: #000000;">expected</span><span style="color: #0000FF;">==</span><span style="color: #004600;">true</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">return</span> <span style="color: #0000FF;">{</span><span style="color: #000000;">res</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"OK"</span><span style="color: #0000FF;">}</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">function</span>
<span style="color: #008080;">constant</span> <span style="color: #000000;">tests</span> <span style="color: #0000FF;">=</span> <span style="color: #0000FF;">{{</span><span style="color: #008000;">"1Q1pE5vPGEEMqRcVRMbtBK842Y6Pzo6nK9"</span><span style="color: #0000FF;">,</span><span style="color: #004600;">true</span><span style="color: #0000FF;">},</span> <span style="color: #000080;font-style:italic;">-- OK</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">"1Q1pE5vPGEEMqRcVRMbtBK842Y6Pzo6nJ9"</span><span style="color: #0000FF;">,</span><span style="color: #004600;">false</span><span style="color: #0000FF;">},</span> <span style="color: #000080;font-style:italic;">-- bad digest</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">"1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62i"</span><span style="color: #0000FF;">,</span><span style="color: #004600;">true</span><span style="color: #0000FF;">},</span> <span style="color: #000080;font-style:italic;">-- OK</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">"1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62j"</span><span style="color: #0000FF;">,</span><span style="color: #004600;">false</span><span style="color: #0000FF;">},</span> <span style="color: #000080;font-style:italic;">-- bad disgest</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">"1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62X"</span><span style="color: #0000FF;">,</span><span style="color: #004600;">false</span><span style="color: #0000FF;">},</span> <span style="color: #000080;font-style:italic;">-- bad digest (checksum changed, original data.)</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">"1ANNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62i"</span><span style="color: #0000FF;">,</span><span style="color: #004600;">false</span><span style="color: #0000FF;">},</span> <span style="color: #000080;font-style:italic;">-- bad digest (data changed, original checksum.)</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">"1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62iz"</span><span style="color: #0000FF;">,</span><span style="color: #004600;">false</span><span style="color: #0000FF;">},</span> <span style="color: #000080;font-style:italic;">-- not version 0</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">"1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62izz"</span><span style="color: #0000FF;">,</span><span style="color: #004600;">false</span><span style="color: #0000FF;">},</span> <span style="color: #000080;font-style:italic;">-- address too long</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">"1BGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62i"</span><span style="color: #0000FF;">,</span><span style="color: #004600;">false</span><span style="color: #0000FF;">},</span> <span style="color: #000080;font-style:italic;">-- bad digest</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">"1A Na15ZQXAZUgFiqJ2i7Z2DPU2J6hW62i"</span><span style="color: #0000FF;">,</span><span style="color: #004600;">false</span><span style="color: #0000FF;">},</span> <span style="color: #000080;font-style:italic;">-- bad char</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">"1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62I"</span><span style="color: #0000FF;">,</span><span style="color: #004600;">false</span><span style="color: #0000FF;">},</span> <span style="color: #000080;font-style:italic;">-- bad char</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">"1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62!"</span><span style="color: #0000FF;">,</span><span style="color: #004600;">false</span><span style="color: #0000FF;">},</span> <span style="color: #000080;font-style:italic;">-- bad char</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">"1AGNa15ZQXAZUgFiqJ3i7Z2DPU2J6hW62i"</span><span style="color: #0000FF;">,</span><span style="color: #004600;">false</span><span style="color: #0000FF;">},</span> <span style="color: #000080;font-style:italic;">-- bad digest</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">"1111111111111111111114oLvT2"</span><span style="color: #0000FF;">,</span> <span style="color: #004600;">true</span><span style="color: #0000FF;">},</span> <span style="color: #000080;font-style:italic;">-- OK</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">"17NdbrSGoUotzeGCcMMCqnFkEvLymoou9j"</span><span style="color: #0000FF;">,</span><span style="color: #004600;">true</span><span style="color: #0000FF;">},</span> <span style="color: #000080;font-style:italic;">-- OK</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">"1badbadbadbadbadbadbadbadbadbadbad"</span><span style="color: #0000FF;">,</span><span style="color: #004600;">false</span><span style="color: #0000FF;">},</span> <span style="color: #000080;font-style:italic;">-- not version 0</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">"BZbvjr"</span><span style="color: #0000FF;">,</span><span style="color: #004600;">false</span><span style="color: #0000FF;">},</span> <span style="color: #000080;font-style:italic;">-- first character is not 1 or 3 (checksum is fine, address too short)</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">"i55j"</span><span style="color: #0000FF;">,</span><span style="color: #004600;">false</span><span style="color: #0000FF;">},</span> <span style="color: #000080;font-style:italic;">-- first character is not 1 or 3 (checksum is fine, address too short)</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">"16UwLL9Risc3QfPqBUvKofHmBQ7wMtjvM"</span><span style="color: #0000FF;">,</span> <span style="color: #004600;">true</span><span style="color: #0000FF;">},</span> <span style="color: #000080;font-style:italic;">-- OK (from public_point_to_address)</span>
<span style="color: #0000FF;">$}</span>
<span style="color: #008080;">for</span> <span style="color: #000000;">i</span><span style="color: #0000FF;">=</span><span style="color: #000000;">1</span> <span style="color: #008080;">to</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">tests</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">do</span>
<span style="color: #0000FF;">{</span><span style="color: #004080;">string</span> <span style="color: #000000;">ti</span><span style="color: #0000FF;">,</span> <span style="color: #004080;">bool</span> <span style="color: #000000;">expected</span><span style="color: #0000FF;">}</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">tests</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">]</span>
<span style="color: #0000FF;">{</span><span style="color: #004080;">bool</span> <span style="color: #000000;">res</span><span style="color: #0000FF;">,</span> <span style="color: #004080;">string</span> <span style="color: #000000;">coin_err</span><span style="color: #0000FF;">}</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">valid</span><span style="color: #0000FF;">(</span><span style="color: #000000;">ti</span><span style="color: #0000FF;">,</span><span style="color: #000000;">expected</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">if</span> <span style="color: #008080;">not</span> <span style="color: #000000;">res</span> <span style="color: #008080;">then</span>
<span style="color: #7060A8;">printf</span><span style="color: #0000FF;">(</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"%s: %s\n"</span><span style="color: #0000FF;">,</span> <span style="color: #0000FF;">{</span><span style="color: #000000;">ti</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">coin_err</span><span style="color: #0000FF;">})</span>
<span style="color: #0000FF;">{}</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">wait_key</span><span style="color: #0000FF;">()</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
<span style="color: #0000FF;">?</span><span style="color: #008000;">"done"</span>
<span style="color: #0000FF;">{}</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">wait_key</span><span style="color: #0000FF;">()</span>
<!--</syntaxhighlight>-->
(No output other than "done" since all tests pass)
=={{header|PHP}}==
<
function validate($address){
$decoded = decodeBase58($address);
Line 1,589 ⟶ 1,949:
main();
</syntaxhighlight>
{{out}}
Line 1,598 ⟶ 1,958:
1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62I: invalid character found
</pre>
=={{header|PicoLisp}}==
<
(setq *Alphabet
Line 1,629 ⟶ 1,988:
(valid "1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62!")
(valid "1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62iz")
(valid "1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62izz") ) )</
=={{header|PureBasic}}==
<syntaxhighlight lang="purebasic">
; using PureBasic 5.50 (x64)
EnableExplicit
Line 1,710 ⟶ 2,068:
EndIf
</syntaxhighlight>
{{out}}
Line 1,718 ⟶ 2,076:
1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62I -> Invalid
</pre>
=={{header|Python}}==
<
digits58 = '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz'
Line 1,737 ⟶ 2,094:
print(check_bc('1AGNa15ZQXAZUgFiqJ3i7Z2DPU2J6hW62i'))
print(check_bc("17NdbrSGoUotzeGCcMMCqnFkEvLymoou9j"))</
{{out}}
Line 1,747 ⟶ 2,104:
:Yuuki-chan edit: Delete this help if it's not needed anymore
:For those looking at examples here to try and work out what is required, the <code>n.to_bytes()</code> call is equivalent to this code which converts a (long) integer into individual bytes of a byte array in a particular order:
:<
>>> length = 25
>>> list( reversed(range(length)) )
[24, 23, 22, 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0]
>>> assert n.to_bytes(length, 'big') == bytes( (n >> i*8) & 0xff for i in reversed(range(length)))
>>> </
=={{header|Racket}}==
<
#lang racket/base
Line 1,800 ⟶ 2,156:
(validate-bitcoin-address "1Q1pE5vPGEEMqRcVRMbtBK842Y6Pzo6nK9") ; => #t
(validate-bitcoin-address "1badbadbadbadbadbadbadbadbadbadbad") ; => #f
</syntaxhighlight>
=={{header|Raku}}==
(formerly Perl 6)
<syntaxhighlight lang="raku" line>sub sha256(blob8 $b) returns blob8 {
given run <openssl dgst -sha256 -binary>, :in, :out, :bin {
.in.write: $b;
.in.close;
return .out.slurp;
}
}
my $bitcoin-address = rx/
<< <+alnum-[0IOl]> ** 26..* >> # an address is at least 26 characters long
<?{
.subbuf(21, 4) eq sha256(sha256 .subbuf(0, 21)).subbuf(0, 4) given
blob8.new: <
1 2 3 4 5 6 7 8 9
A B C D E F G H J K L M N P Q R S T U V W X Y Z
a b c d e f g h i j k m n o p q r s t u v w x y z
>.pairs.invert.hash{$/.comb}
.reduce(* * 58 + *)
.polymod(256 xx 24)
.reverse;
}>
/;
say "Here is a bitcoin address: 1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62i" ~~ $bitcoin-address;</syntaxhighlight>
{{out}}
<pre>「1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62i」</pre>
=={{header|Ruby}}==
<
# Validate Bitcoin address
#
Line 1,820 ⟶ 2,203:
(n.length...42).each{n.insert(0,'0')}
puts "I think the checksum should be #{g}\nI calculate that it is #{Digest::SHA256.hexdigest(Digest::SHA256.digest(convert(n)))[0,8]}"
</syntaxhighlight>
{{out}}
With A = '1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62i'
Line 1,832 ⟶ 2,215:
I calculate that it is c046b2ff
</pre>
=={{header|Rust}}==
This requires the [https://crates.io/crates/rust-crypto rust-crypto] crate for sha256.
<syntaxhighlight lang="rust">
extern crate crypto;
Line 1,891 ⟶ 2,273:
Ok(res)
}
</syntaxhighlight>
{{out}}
<pre>
Line 1,899 ⟶ 2,281:
false
</pre>
=={{header|Scala}}==
<
import java.util.Arrays.copyOfRange
Line 1,967 ⟶ 2,348:
println(s"Successfully completed without errors. [total ${scala.compat.Platform.currentTime - executionStart}ms]")
}</
=={{header|Seed7}}==
The Seed7 library [http://seed7.sourceforge.net/libraries/encoding.htm encoding.s7i] defines
Line 1,978 ⟶ 2,358:
No external library is needed.
<
include "msgdigest.s7i";
include "encoding.s7i";
Line 2,027 ⟶ 2,407:
checkValidationFunction("i55j", FALSE); # wrong length
checkValidationFunction("16UwLL9Risc3QfPqBUvKofHmBQ7wMtjvM", TRUE); # okay
end func;</
{{out}}
Line 2,051 ⟶ 2,431:
16UwLL9Risc3QfPqBUvKofHmBQ7wMtjvM: TRUE
</pre>
=={{header|Tcl}}==
{{tcllib|sha256}}
<
# Generate a large and boring piece of code to do the decoding of
Line 2,087 ⟶ 2,466:
}
return "$address is ok"
}</
Testing if it works
<
puts [bitcoin_addressValid 1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62i]</
{{out}}
<pre>
Line 2,096 ⟶ 2,475:
1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62i is ok
</pre>
=={{header|UNIX Shell}}==
{{works with|bash}}
<
bitcoinregex="^[$(printf "%s" "${base58[@]}")]{34}$"
Line 2,126 ⟶ 2,504:
else return 2
fi
}</
=={{header|Wren}}==
{{trans|Kotlin}}
{{libheader|Wren-crypto}}
{{libheader|wren-str}}
{{libheader|Wren-fmt}}
<syntaxhighlight lang="wren">import "./crypto" for Sha256
import "./str" for Str
import "./fmt" for Conv, Fmt
class Bitcoin {
static alphabet_ { "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz" }
static contentEquals_(ba1, ba2) {
if (ba1.count != ba2.count) return false
return !(0...ba1.count).any { |i| ba1[i] != ba2[i] }
}
static decodeBase58_(input) {
var output = List.filled(25, 0)
for (c in input) {
var p = alphabet_.indexOf(c)
if (p == -1) return null
for (j in 24..1) {
p = p + 58 * output[j]
output[j] = p % 256
p = p >> 8
}
if (p != 0) return null
}
return output
}
static sha256_(data, start, len, recursion) {
if (recursion == 0) return data
var md = Sha256.digest(data[start...start+len])
md = Str.chunks(md, 2).map { |x| Conv.atoi(x, 16) }.toList
return sha256_(md, 0, 32, recursion-1)
}
static validateAddress(address) {
var len = address.count
if (len < 26 || len > 35) return false
var decoded = decodeBase58_(address)
if (!decoded) return false
var hash = sha256_(decoded, 0, 21, 2)
return contentEquals_(hash[0..3], decoded[21..24])
}
}
var addresses = [
"1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62i",
"1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62j",
"1Q1pE5vPGEEMqRcVRMbtBK842Y6Pzo6nK9",
"1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62X",
"1ANNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62i",
"1A Na15ZQXAZUgFiqJ2i7Z2DPU2J6hW62i",
"BZbvjr",
"i55j",
"1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62!",
"1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62iz",
"1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62izz",
"1Q1pE5vPGEEMqRcVRMbtBK842Y6Pzo6nJ9",
"1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62I"
]
for (address in addresses) {
Fmt.print("$-36s -> $s", address, Bitcoin.validateAddress(address) ? "valid" : "invalid")
}</syntaxhighlight>
{{out}}
<pre>
1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62i -> valid
1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62j -> invalid
1Q1pE5vPGEEMqRcVRMbtBK842Y6Pzo6nK9 -> valid
1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62X -> invalid
1ANNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62i -> invalid
1A Na15ZQXAZUgFiqJ2i7Z2DPU2J6hW62i -> invalid
BZbvjr -> invalid
i55j -> invalid
1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62! -> invalid
1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62iz -> invalid
1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62izz -> invalid
1Q1pE5vPGEEMqRcVRMbtBK842Y6Pzo6nJ9 -> invalid
1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62I -> invalid
</pre>
=={{header|zkl}}==
Uses shared library zklMsgHash.
<
const symbols="123456789" // 58 characters: no cap i,o; ell, zero
"ABCDEFGHJKLMNPQRSTUVWXYZ"
Line 2,154 ⟶ 2,616:
(2).reduce(MsgHash.SHA256.fp1(1,dec),dec); // dec is i/o buffer
dec[0,4]==chkSum;
}</
<
"1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62X", // checksum changed, original data.
"1ANNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62i", // data changed, original checksum.
"1A Na15ZQXAZUgFiqJ2i7Z2DPU2J6hW62i", // invalid chars
"1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62izz", // too long
).apply(coinValide).println();</
{{out}}
<pre>L(True,True,False,False,False,False)</pre>
{{omit from|Brlcad}}
{{omit from|GUISS}}
|