Bitcoin/address validation (2024)

Warning: Many of these snippets are incomplete. It is recommended that you use an established library for any projects that are likely to see external use

Bitcoin/address validation
You are encouraged to solve this task according to the task description, using any language you may know.

Task

Write a program that takes a bitcoin address as argument, and checks whether or not this address is valid.

A bitcoin address uses a base58 encoding, which uses an alphabet of the characters 0 .. 9, A ..Z, a .. z, but without the four characters:

  • 0 zero
  • O uppercase oh
  • I uppercase eye
  • l lowercase ell


With this encoding, a bitcoin address encodes 25 bytes:

  • the first byte is the version number, which will be zero for this task;
  • the next twenty bytes are a RIPEMD-160 digest, but you don't have to know that for this task: you can consider them a pure arbitrary data;
  • the last four bytes are a checksum check. They are the first four bytes of a double SHA-256 digest of the previous 21 bytes.


To check the bitcoin address, you must read the first twenty-one bytes, compute the checksum, and check that it corresponds to the last four bytes.

The program can either return a boolean value or throw an exception when not valid.

You can use a digest library for SHA-256.

Example of a bitcoin address
1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62i

It doesn't belong to anyone and is part of the test suite of the bitcoin software.
You can change a few characters in this string and check that it'll fail the test.

Ada

with Ada.Exceptions, Interfaces;with Ada.Streams;use Ada.Exceptions, Interfaces;use Ada.Streams;package Bitcoin is subtype BT_Raw_Addr is Stream_Element_Array(1..25); subtype BT_Checksum is Stream_Element_Array(1..4); subtype BT_Addr is String(1..34); subtype Sha256String is String(1..64); Invalid_Address_Error : Exception; function Double_Sha256(S : Stream_Element_Array) return BT_Checksum; function Is_Valid(A : BT_Raw_Addr) return Boolean; procedure Base58_Decode(S : BT_Addr; A : out BT_Raw_Addr) ;private Base58 : constant String := "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"; function Hex_Val (C, C2 : Character) return Stream_Element;end Bitcoin;with GNAT.SHA256, Ada.Strings.Fixed;use GNAT.SHA256, Ada.Strings.Fixed;package body Bitcoin isfunction Hex_Val (C, C2 : Character) return Stream_Element is subtype Nibble is Integer range 0..15; HEX : array (0..255) of Nibble := ( 48=>0, 49=>1, 50=>2, 51=>3, 52=>4, 53=>5, 54=>6, 55=>7, 56=>8, 57=>9 , 65=>10, 66=>11, 67=>12, 68 =>13, 69 =>14, 70 =>15 , 97=>10, 98=>11, 99=>12, 100=>13, 101=>14, 102=>15 , Others=>0 );begin return Stream_Element(HEX(Character'Pos(C)) * 16 + HEX(Character'Pos(C2)));end Hex_Val;function Double_Sha256(S : Stream_Element_Array) return BT_Checksum is Ctx : Context := Initial_Context; D : Message_Digest; S2 : Stream_Element_Array(1..32); Ctx2 : Context := Initial_Context; C : BT_Checksum;begin Update(Ctx, S); D := Digest(Ctx); for I in S2'Range loop S2(I) := Hex_Val(D(Integer(I)*2-1), D(Integer(I)*2)); end loop; Update(Ctx2, S2); D := Digest(Ctx2); for I in C'Range loop C(I) := Hex_Val(D(Integer(I)*2-1), D(Integer(I)*2)); end loop; return C;end Double_Sha256;---------------------------------------------------------------------------------- Summary of Base58: ---- We decode S into a 200 bit unsigned integer. ---- We could use a BigNum library, but choose to go without. ----------------------------------------------------------------------------------procedure Base58_Decode(S : BT_Addr; A : out BT_Raw_Addr) isbegin A := (Others => 0); for I in S'Range loop declare P : Natural := Index(Base58, String(S(I..I))); C : Natural; begin if P = 0 then raise Invalid_Address_Error; end if; C := P - 1; for J in reverse A'Range loop C := C + Natural(A(J)) * 58; A(J) := Stream_Element(Unsigned_32(C) and 255); -- 0x00FF C := Natural(Shift_Right(Unsigned_32(C),8) and 255); -- 0xFF00 end loop; if C /= 0 then raise Invalid_Address_Error; end if; end; end loop;end Base58_Decode;function Is_Valid(A : BT_Raw_Addr) return Boolean isbegin return A(1) = 0 and A(22..25) = Double_Sha256(A(1..21));end Is_Valid;end Bitcoin;with Ada.Text_IO, Bitcoin;use Ada.Text_IO, Bitcoin;procedure Bitcoin_Addr_Validate isbegin declare BTs : array (positive range <>) of BT_Addr := ( "1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62i" -- VALID , "1Q1pE5vPGEEMqRcVRMbtBK842Y6Pzo6nK9" -- VALID , "1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62X" -- checksum changed, original data. , "1ANNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62i" -- data changed, original checksum. , "1A Na15ZQXAZUgFiqJ2i7Z2DPU2J6hW62i" -- invalid chars ); begin for I in Bts'Range loop declare A : BT_Raw_Addr; Valid : Boolean; begin Put(BTs(I) & " validity: "); Base58_Decode(BTs(I), A); Valid := Is_Valid(A); Put_Line(Boolean'Image(Valid)); exception when E : Invalid_Address_Error => Put_Line ("*** Error: Invalid BT address."); end; end loop; end;end Bitcoin_Addr_Validate;
Output:
1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62i validity: TRUE1Q1pE5vPGEEMqRcVRMbtBK842Y6Pzo6nK9 validity: TRUE1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62X validity: FALSE1ANNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62i validity: FALSE1A Na15ZQXAZUgFiqJ2i7Z2DPU2J6hW62i validity: *** Error: Invalid BT address.

C

#include <stdio.h>#include <string.h>#include <openssl/sha.h>const char *coin_err;#define bail(s) { coin_err = s; return 0; }int unbase58(const char *s, unsigned char *out) {static const char *tmpl = "123456789""ABCDEFGHJKLMNPQRSTUVWXYZ""abcdefghijkmnopqrstuvwxyz";int i, j, c;const char *p;memset(out, 0, 25);for (i = 0; s[i]; i++) {if (!(p = strchr(tmpl, s[i])))bail("bad char");c = p - tmpl;for (j = 25; j--; ) {c += 58 * out[j];out[j] = c % 256;c /= 256;}if (c) bail("address too long");}return 1;}int valid(const char *s) {unsigned char dec[32], d1[SHA256_DIGEST_LENGTH], d2[SHA256_DIGEST_LENGTH];coin_err = "";if (!unbase58(s, dec)) return 0;SHA256(SHA256(dec, 21, d1), SHA256_DIGEST_LENGTH, d2);if (memcmp(dec + 21, d2, 4))bail("bad digest");return 1;}int main (void) {const char *s[] = {"1Q1pE5vPGEEMqRcVRMbtBK842Y6Pzo6nK9","1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62i","1Q1pE5vPGEEMqRcVRMbtBK842Y6Pzo6nJ9","1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62I",0 };int i;for (i = 0; s[i]; i++) {int status = valid(s[i]);printf("%s: %s\n", s[i], status ? "Ok" : coin_err);}return 0;}

Compile with -lcrypto

Output:
1Q1pE5vPGEEMqRcVRMbtBK842Y6Pzo6nK9: Ok1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62i: Ok1Q1pE5vPGEEMqRcVRMbtBK842Y6Pzo6nJ9: bad digest1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62I: bad char

C#

This requires NUnit package to compile.

using System;using System.Linq;using System.Security.Cryptography;using NUnit.Framework;namespace BitcoinValidator{ public class ValidateTest { [TestCase] public void ValidateBitcoinAddressTest() { Assert.IsTrue(ValidateBitcoinAddress("1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62i")); // VALID Assert.IsTrue(ValidateBitcoinAddress("1Q1pE5vPGEEMqRcVRMbtBK842Y6Pzo6nK9")); // VALID Assert.Throws<Exception>(() => ValidateBitcoinAddress("1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62X")); // checksum changed, original data Assert.Throws<Exception>(() => ValidateBitcoinAddress("1ANNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62i")); // data changed, original checksum Assert.Throws<Exception>(() => ValidateBitcoinAddress("1A Na15ZQXAZUgFiqJ2i7Z2DPU2J6hW62i")); // invalid chars Assert.Throws<Exception>(() => ValidateBitcoinAddress("BZbvjr")); // checksum is fine, address too short } public static bool ValidateBitcoinAddress(string address) { if (address.Length < 26 || address.Length > 35) throw new Exception("wrong length"); var decoded = DecodeBase58(address); var d1 = Hash(decoded.SubArray(0, 21)); var d2 = Hash(d1); if (!decoded.SubArray(21, 4).SequenceEqual(d2.SubArray(0, 4))) throw new Exception("bad digest"); return true; } const string Alphabet = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"; const int Size = 25; private static byte[] DecodeBase58(string input) { var output = new byte[Size]; foreach (var t in input) { var p = Alphabet.IndexOf(t); if (p == -1) throw new Exception("invalid character found"); var j = Size; while (--j > 0) { p += 58 * output[j]; output[j] = (byte)(p % 256); p /= 256; } if (p != 0) throw new Exception("address too long"); } return output; } private static byte[] Hash(byte[] bytes) { var hasher = new SHA256Managed(); return hasher.ComputeHash(bytes); } } public static class ArrayExtensions { public static T[] SubArray<T>(this T[] data, int index, int length) { var result = new T[length]; Array.Copy(data, index, result, 0, length); return result; } }}

C++

This example uses the C++ code from the SHA-256 task. This slightly complicates the code because the previous taskwas designed to hash a string of ASCII characters rather than a byte array.

#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 hashstd::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 hashstd::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;}}
Output:
1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62i: true1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62j: false1Q1pE5vPGEEMqRcVRMbtBK842Y6Pzo6nK9: true1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62X: false1ANNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62i: false

D

This requires the D module from the SHA-256 Task.

Translation of: Go

import std.stdio, std.algorithm, std.array, std.string, sha_256_2;struct A25 { // Type for a 25 ubyte (not base58 encoded) bitcoin address. ubyte[25] enc; ubyte bitcoinVersion() const pure nothrow @safe @nogc { return enc[0]; } ubyte[4] embeddedChecksum() return const pure nothrow @safe @nogc { return enc[$ - 4 .. $]; } /** Computes a double sha256 hash of the first 21 bytes of the address. Returns the full 32 ubyte sha256 hash. */ ubyte[32] doubleSHA256() const pure nothrow @nogc { return SHA256.digest(SHA256.digest(enc[0 .. 21])); } /** Returns a four ubyte checksum computed from the first 21 bytes of the address. */ ubyte[4] computeChecksum() const pure nothrow @nogc { return doubleSHA256[0 .. 4]; } /** Takes a base58 encoded address and decodes it into the receiver. Errors are returned if the argument is not valid base58 or if the decoded value does not fit in the 25 ubyte address. The address is not otherwise checked for validity. */ string set58(in ubyte[] s) pure nothrow @safe @nogc { static immutable digits = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz" .representation; static assert(digits.length == 58); foreach (immutable char s1; s) { immutable c = digits.countUntil(s1); if (c < 0) return "found a bad char in the Bitcoin address."; // Currently the D type system can't see c as nonegative. uint uc = (c < 0) ? 0 : c; foreach_reverse (ref aj; enc) { uc += digits.length * aj; aj = uc % 256; uc /= 256; } if (uc > 0) return "too long Bitcoin address."; } return null; }}/** Validates a base58 encoded bitcoin address. An address is validif it can be decoded into a 25 ubyte address, the Version number is 0,and the checksum validates. Return value ok will be true for validaddresses. If ok is false, the address is invalid and the error valuemay indicate why. */string isValidA58(in ubyte[] a58) pure nothrow @nogc { A25 a; immutable err = a.set58(a58); if (!err.empty) return err; if (a.bitcoinVersion != 0) return "not Bitcoin version 0."; return (a.embeddedChecksum == a.computeChecksum) ? null : "checksums don't match.";}void main() { immutable tests = ["1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62i", "1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62j", "1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62!", "1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62iz", "1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62izz"]; foreach (immutable test; tests) { immutable err = test.representation.isValidA58; writefln(`"%s": %s`, test, err.empty ? "OK." : err); }}
Output:
"1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62i": OK."1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62j": checksums don't match."1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62!": found a bad char in the Bitcoin address."1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62iz": not Bitcoin version 0."1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62izz": too long Bitcoin address.

Dart

This requires Crypto package to compile.

Translation of: Java

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; }}
Output:
"1BNGaR29FmfAqidXmD9HLwsGv9p5WVvvhq" true"1BNGaR29FmfAqidXmD9HLws" false

Delphi

This requires DCPcrypt library to compile.

uses DCPsha256;type TByteArray = array of Byte;function HashSHA256(const Input: TByteArray): TByteArray;var Hasher: TDCP_sha256;begin Hasher := TDCP_sha256.Create(nil); try Hasher.Init; Hasher.Update(Input[0], Length(Input)); SetLength(Result, Hasher.HashSize div 8); Hasher.Final(Result[0]); finally Hasher.Free; end;end;function DecodeBase58(const Input: string): TByteArray;const Size = 25; Alphabet = '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz';var C: Char; I, J: Integer;begin SetLength(Result, Size); for C in Input do begin I := Pos(C, Alphabet) - 1; if I = -1 then raise Exception.CreateFmt('Invalid character found: %s', [C]); for J := High(Result) downto 0 do begin I := I + (58 * Result[J]); Result[J] := I mod 256; I := I div 256; end; if I <> 0 then raise Exception.Create('Address too long'); end;end;procedure ValidateBitcoinAddress(const Address: string);var Hashed: TByteArray; Decoded: TByteArray;begin if (Length(Address) < 26) or (Length(Address) > 35) then raise Exception.Create('Wrong length'); Decoded := DecodeBase58(Address); Hashed := HashSHA256(HashSHA256(Copy(Decoded, 0, 21))); if not CompareMem(@Decoded[21], @Hashed[0], 4) then raise Exception.Create('Bad digest');end;

Erlang

Using base58 module from http://github.com/titan098/erl-base58.git.

-module( bitcoin_address ).-export( [task/0, validate/1] ).task() ->io:fwrite( "Validate ~p~n", ["1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62i"] ),io:fwrite( "~p~n", [validate("1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62i")] ),io:fwrite( "Validate ~p~n", ["1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW622"] ),io:fwrite( "~p~n", [validate("1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW622")] ).validate( String ) ->{length_25, <<Address:21/binary, Checksum:4/binary>>} = {length_25, base58:base58_to_binary( String )},<<Version:1/binary, _/binary>> = Address,{version_0, <<0>>} = {version_0, Version},<<Four_bytes:4/binary, _T/binary>> = crypto:hash( sha256, crypto:hash(sha256, Address) ),{checksum, Checksum} = {checksum, Four_bytes},ok.
Output:
17> bitcoin_address:task().Validate "1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62i"okValidate "1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW622"** exception error: no match of right hand side value {checksum,<<"ÀF²ÿ">>} in function bitcoin_address:validate/1 (src/bitcoin_address.erl, line 16) in call from bitcoin_address:task/0 (src/bitcoin_address.erl, line 9)

Factor

USING: byte-arrays checksums checksums.sha io.binary kernel mathmath.parser sequences ;IN: rosetta-code.bitcoin.validationCONSTANT: ALPHABET "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz": base58>bigint ( str -- n ) [ ALPHABET index ] [ [ 58 * ] [ + ] bi* ] map-reduce ;: base58> ( str -- bytes ) base58>bigint 25 >be ;: btc-checksum ( bytes -- checksum-bytes ) 21 head 2 [ sha-256 checksum-bytes ] times 4 head ;: btc-valid? ( str -- ? ) base58> [ btc-checksum ] [ 4 tail* ] bi = ;
Output:
"1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62i" btc-valid? .! t, VALID"1Q1pE5vPGEEMqRcVRMbtBK842Y6Pzo6nK9" btc-valid? .! t, VALID"1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62X" btc-valid? .! f, checksum changed, original data."1ANNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62i" btc-valid? .! f, data changed, original checksum.

FreeBASIC

' version 05-04-2017' compile with: fbc -s console' function adapted from the SHA-256 taskFunction SHA_256(test_str As String, bitcoin As ULong = 0) As String #Macro Ch (x, y, z) (((x) And (y)) Xor ((Not (x)) And z)) #EndMacro #Macro Maj (x, y, z) (((x) And (y)) Xor ((x) And (z)) Xor ((y) And (z))) #EndMacro #Macro sigma0 (x) (((x) Shr 2 Or (x) Shl 30) Xor ((x) Shr 13 Or (x) Shl 19) Xor ((x) Shr 22 Or (x) Shl 10)) #EndMacro #Macro sigma1 (x) (((x) Shr 6 Or (x) Shl 26) Xor ((x) Shr 11 Or (x) Shl 21) Xor ((x) Shr 25 Or (x) Shl 7)) #EndMacro #Macro sigma2 (x) (((x) Shr 7 Or (x) Shl 25) Xor ((x) Shr 18 Or (x) Shl 14) Xor ((x) Shr 3)) #EndMacro #Macro sigma3 (x) (((x) Shr 17 Or (x) Shl 15) Xor ((x) Shr 19 Or (x) Shl 13) Xor ((x) Shr 10)) #EndMacro Dim As String message = test_str ' strings are passed as ByRef's Dim As Long i, j Dim As UByte Ptr ww1 Dim As UInteger<32> Ptr ww4 Do Dim As ULongInt l = Len(message) ' set the first bit after the message to 1 message = message + Chr(1 Shl 7) ' add one char to the length Dim As ULong padding = 64 - ((l +1) Mod (512 \ 8)) ' 512 \ 8 = 64 char. ' check if we have enough room for inserting the length If padding < 8 Then padding = padding + 64 message = message + String(padding, Chr(0)) ' adjust length Dim As ULong l1 = Len(message) ' new length l = l * 8 ' orignal length in bits ' create ubyte ptr to point to l ( = length in bits) Dim As UByte Ptr ub_ptr = Cast(UByte Ptr, @l) For i = 0 To 7 'copy length of message to the last 8 bytes message[l1 -1 - i] = ub_ptr[i] Next 'table of constants Dim As UInteger<32> K(0 To ...) = _ { &H428a2f98, &H71374491, &Hb5c0fbcf, &He9b5dba5, &H3956c25b, &H59f111f1, _ &H923f82a4, &Hab1c5ed5, &Hd807aa98, &H12835b01, &H243185be, &H550c7dc3, _ &H72be5d74, &H80deb1fe, &H9bdc06a7, &Hc19bf174, &He49b69c1, &Hefbe4786, _ &H0fc19dc6, &H240ca1cc, &H2de92c6f, &H4a7484aa, &H5cb0a9dc, &H76f988da, _ &H983e5152, &Ha831c66d, &Hb00327c8, &Hbf597fc7, &Hc6e00bf3, &Hd5a79147, _ &H06ca6351, &H14292967, &H27b70a85, &H2e1b2138, &H4d2c6dfc, &H53380d13, _ &H650a7354, &H766a0abb, &H81c2c92e, &H92722c85, &Ha2bfe8a1, &Ha81a664b, _ &Hc24b8b70, &Hc76c51a3, &Hd192e819, &Hd6990624, &Hf40e3585, &H106aa070, _ &H19a4c116, &H1e376c08, &H2748774c, &H34b0bcb5, &H391c0cb3, &H4ed8aa4a, _ &H5b9cca4f, &H682e6ff3, &H748f82ee, &H78a5636f, &H84c87814, &H8cc70208, _ &H90befffa, &Ha4506ceb, &Hbef9a3f7, &Hc67178f2 } Dim As UInteger<32> h0 = &H6a09e667 Dim As UInteger<32> h1 = &Hbb67ae85 Dim As UInteger<32> h2 = &H3c6ef372 Dim As UInteger<32> h3 = &Ha54ff53a Dim As UInteger<32> h4 = &H510e527f Dim As UInteger<32> h5 = &H9b05688c Dim As UInteger<32> h6 = &H1f83d9ab Dim As UInteger<32> h7 = &H5be0cd19 Dim As UInteger<32> a, b, c, d, e, f, g, h Dim As UInteger<32> t1, t2, w(0 To 63) For j = 0 To (l1 -1) \ 64 ' split into block of 64 bytes ww1 = Cast(UByte Ptr, @message[j * 64]) ww4 = Cast(UInteger<32> Ptr, @message[j * 64]) For i = 0 To 60 Step 4 'little endian -> big endian Swap ww1[i ], ww1[i +3] Swap ww1[i +1], ww1[i +2] Next For i = 0 To 15 ' copy the 16 32bit block into the array W(i) = ww4[i] Next For i = 16 To 63 ' fill the rest of the array w(i) = sigma3(W(i -2)) + W(i -7) + sigma2(W(i -15)) + W(i -16) Next a = h0 : b = h1 : c = h2 : d = h3 : e = h4 : f = h5 : g = h6 : h = h7 For i = 0 To 63 t1 = h + sigma1(e) + Ch(e, f, g) + K(i) + W(i) t2 = sigma0(a) + Maj(a, b, c) h = g : g = f : f = e e = d + t1 d = c : c = b : b = a a = t1 + t2 Next h0 += a : h1 += b : h2 += c : h3 += d h4 += e : h5 += f : h6 += g : h7 += h Next j Dim As String answer = Hex(h0, 8) + Hex(h1, 8) + Hex(h2, 8) + Hex(h3, 8) _ + Hex(h4, 8) + Hex(h5, 8) + Hex(h6, 8) + Hex(h7, 8) If bitcoin = 0 Then Return LCase(answer) Else 'conver hex value's to integer value's message = String(32,0) For i = 0 To 31 message[i] = Val("&h" + Mid(answer, i * 2 + 1, 2)) Next bitcoin = 0 End If LoopEnd FunctionFunction conv_base58(bitcoin_address As String) As String Dim As String base58 = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz" Dim As String tmp = String(24, 0) Dim As Long x, y, z For x = 1 To Len(bitcoin_address) -1 z = InStr(base58, Chr(bitcoin_address[x])) -1 If z = -1 Then Print " bitcoin address contains illegal character" Return "" End If For y = 23 To 0 Step -1 z = z + tmp[y] * 58 tmp[y] = z And 255 ' test_str[y] = z Mod 256 z Shr= 8 ' z \= 256 Next If z <> 0 Then Print " bitcoin address is to long" Return "" End If Next z = InStr(base58, Chr(bitcoin_address[0])) -1 Return Chr(z) + tmpEnd Function' ------=< MAIN >=------Data "1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62i" ' originalData "1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62j" ' checksum changedData "1NAGa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62i" ' address changedData "0AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62i" ' only 1 or 3 as first char. allowedData "1AGNa15ZQXAZUgFlqJ2i7Z2DPU2J6hW62i" ' illegal character in addressDim As String tmp, result, checksum, bitcoin_addressDim As Long i, jFor i = 1 To 5 Read bitcoin_address Print "Bitcoin address: "; bitcoin_address; tmp = Left(bitcoin_address,1) If tmp <> "1" And tmp <> "3" Then Print " first character is not 1 or 3" Continue For End If ' convert bitcoinaddress tmp = conv_base58(bitcoin_address) If tmp = "" Then Continue For ' get the checksum, last 4 digits For j As Long = 21 To 24 checksum = checksum + LCase(Hex(tmp[j], 2)) Next ' send the first 21 characters to the SHA 256 routine result = SHA_256(Left(tmp, 21), 2) result = Left(result, 8) ' get the checksum (the first 8 digits (hex)) If checksum = result Then ' test the found checksum against Print " is valid" ' the one from the address Else Print " is not valid, checksum fails" End IfNext' empty keyboard bufferWhile InKey <> "" : WendPrint : Print "hit any key to end program"SleepEnd
Output:
Bitcoin address: 1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62i is validBitcoin address: 1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62j is not valid, checksum failsBitcoin address: 1NAGa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62i is not valid, checksum failsBitcoin address: 0AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62i first character is not 1 or 3Bitcoin address: 1AGNa15ZQXAZUgFlqJ2i7Z2DPU2J6hW62i bitcoin address contains illegal character

Go

Translation of: C

package mainimport ( "bytes" "crypto/sha256" "errors" "os")// With at least one other bitcoin RC task, this source is styled more like// a package to show how functions of the two tasks might be combined into// a single package. It turns out there's not really that much shared code,// just the A25 type and doubleSHA256 method, but it's enough to suggest how// the code might be organized. Types, methods, and functions are capitalized// where they might be exported from a package.// A25 is a type for a 25 byte (not base58 encoded) bitcoin address.type A25 [25]byte func (a *A25) Version() byte { return a[0]} func (a *A25) EmbeddedChecksum() (c [4]byte) { copy(c[:], a[21:]) return}// DoubleSHA256 computes a double sha256 hash of the first 21 bytes of the// address. This is the one function shared with the other bitcoin RC task.// Returned is the full 32 byte sha256 hash. (The bitcoin checksum will be// the first four bytes of the slice.)func (a *A25) doubleSHA256() []byte { h := sha256.New() h.Write(a[:21]) d := h.Sum([]byte{}) h = sha256.New() h.Write(d) return h.Sum(d[:0])}// ComputeChecksum returns a four byte checksum computed from the first 21// bytes of the address. The embedded checksum is not updated.func (a *A25) ComputeChecksum() (c [4]byte) { copy(c[:], a.doubleSHA256()) return}/* {{header|Go}} */ // Tmpl and Set58 are adapted from the C solution.// Go has big integers but this techinique seems better.var tmpl = []byte("123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz")// Set58 takes a base58 encoded address and decodes it into the receiver.// Errors are returned if the argument is not valid base58 or if the decoded// value does not fit in the 25 byte address. The address is not otherwise// checked for validity.func (a *A25) Set58(s []byte) error { for _, s1 := range s { c := bytes.IndexByte(tmpl, s1) if c < 0 { return errors.New("bad char") } for j := 24; j >= 0; j-- { c += 58 * int(a[j]) a[j] = byte(c % 256) c /= 256 } if c > 0 { return errors.New("too long") } } return nil}// ValidA58 validates a base58 encoded bitcoin address. An address is valid// if it can be decoded into a 25 byte address, the version number is 0,// and the checksum validates. Return value ok will be true for valid// addresses. If ok is false, the address is invalid and the error value// may indicate why.func ValidA58(a58 []byte) (ok bool, err error) { var a A25 if err := a.Set58(a58); err != nil { return false, err } if a.Version() != 0 { return false, errors.New("not version 0") } return a.EmbeddedChecksum() == a.ComputeChecksum(), nil}// Program returns exit code 0 with valid address and produces no output.// Otherwise exit code is 1 and a message is written to stderr.func main() { if len(os.Args) != 2 { errorExit("Usage: valid <base58 address>") } switch ok, err := ValidA58([]byte(os.Args[1])); { case ok: case err == nil: errorExit("Invalid") default: errorExit(err.Error()) }}func errorExit(m string) { os.Stderr.WriteString(m + "\n") os.Exit(1)}
Output:

Command line usage examples showing program exit status.

> valid; echo $statusUsage: valid <base58 address>1> valid 1 1; echo $statusUsage: valid <base58 address>1> valid 1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62i; echo $status0> valid 1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62j; echo $statusInvalid1> valid 1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62!; echo $statusbad char1> valid 1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62iz; echo $statusnot version 01> valid 1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62izz; echo $statustoo long1

Haskell

import Control.Monad (when)import Data.List (elemIndex)import Data.Monoid ((<>))import qualified Data.ByteString as BSimport Data.ByteString (ByteString)import Crypto.Hash.SHA256 (hash) -- from package cryptohash-- Convert from base58 encoded value to Integerdecode58 :: String -> Maybe Integerdecode58 = fmap combine . traverse parseDigit where combine = foldl (\acc digit -> 58 * acc + digit) 0 -- should be foldl', but this trips up the highlighting parseDigit char = toInteger <$> elemIndex char c58 c58 = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"-- Convert from base58 encoded value to bytestoBytes :: Integer -> ByteStringtoBytes = BS.reverse . BS.pack . map (fromIntegral . (`mod` 256)) . takeWhile (> 0) . iterate (`div` 256)-- Check if the hash of the first 21 (padded) bytes matches the last 4 byteschecksumValid :: ByteString -> BoolchecksumValid address = let (value, checksum) = BS.splitAt 21 $ leftPad address in and $ BS.zipWith (==) checksum $ hash $ hash $ value where leftPad bs = BS.replicate (25 - BS.length bs) 0 <> bs-- utilitywithError :: e -> Maybe a -> Either e awithError e = maybe (Left e) Right-- Check validity of base58 encoded bitcoin address.-- Result is either an error string (Left) or unit (Right ()).validityCheck :: String -> Either String ()validityCheck encoded = do num <- withError "Invalid base 58 encoding" $ decode58 encoded let address = toBytes num when (BS.length address > 25) $ Left "Address length exceeds 25 bytes" when (BS.length address < 4) $ Left "Address length less than 4 bytes" when (not $ checksumValid address) $ Left "Invalid checksum"-- Run one validity check and display results.validate :: String -> IO ()validate encodedAddress = do let result = either show (const "Valid") $ validityCheck encodedAddress putStrLn $ show encodedAddress ++ " -> " ++ result-- Run some validity check tests.main :: IO ()main = do validate "1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62i" -- VALID validate "1Q1pE5vPGEEMqRcVRMbtBK842Y6Pzo6nK9" -- VALID validate "1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62X" -- checksum changed, original data. validate "1ANNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62i" -- data changed, original checksum. validate "1A Na15ZQXAZUgFiqJ2i7Z2DPU2J6hW62i" -- invalid chars validate "1ANa55215ZQXAZUgFiqJ2i7Z2DPU2J6hW62i" -- too long validate "i55j" -- too short
Output:
"1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62i" -> Valid"1Q1pE5vPGEEMqRcVRMbtBK842Y6Pzo6nK9" -> Valid"1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62X" -> Invalid"1ANNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62i" -> Invalid"1A Na15ZQXAZUgFiqJ2i7Z2DPU2J6hW62i" -> "Invalid base 58 encoding""1ANa55215ZQXAZUgFiqJ2i7Z2DPU2J6hW62i" -> "Address length exceeds 25 bytes""i55j" -> "Address length less than 4 bytes"

Java

import java.math.BigInteger;import java.security.MessageDigest;import java.security.NoSuchAlgorithmException;import java.util.Arrays;public class BitcoinAddressValidator { private static final String ALPHABET = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"; public static boolean validateBitcoinAddress(String addr) { if (addr.length() < 26 || addr.length() > 35) return false; byte[] decoded = decodeBase58To25Bytes(addr); if (decoded == null) return false; byte[] hash1 = sha256(Arrays.copyOfRange(decoded, 0, 21)); byte[] hash2 = sha256(hash1); return Arrays.equals(Arrays.copyOfRange(hash2, 0, 4), Arrays.copyOfRange(decoded, 21, 25)); } private static byte[] decodeBase58To25Bytes(String input) { BigInteger num = BigInteger.ZERO; for (char t : input.toCharArray()) { int p = ALPHABET.indexOf(t); if (p == -1) return null; num = num.multiply(BigInteger.valueOf(58)).add(BigInteger.valueOf(p)); } byte[] result = new byte[25]; byte[] numBytes = num.toByteArray(); System.arraycopy(numBytes, 0, result, result.length - numBytes.length, numBytes.length); return result; } private static byte[] sha256(byte[] data) { try { MessageDigest md = MessageDigest.getInstance("SHA-256"); md.update(data); return md.digest(); } catch (NoSuchAlgorithmException e) { throw new IllegalStateException(e); } } public static void main(String[] args) { assertBitcoin("1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62i", true); assertBitcoin("1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62j", false); assertBitcoin("1Q1pE5vPGEEMqRcVRMbtBK842Y6Pzo6nK9", true); assertBitcoin("1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62X", false); assertBitcoin("1ANNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62i", false); assertBitcoin("1A Na15ZQXAZUgFiqJ2i7Z2DPU2J6hW62i", false); assertBitcoin("BZbvjr", false); assertBitcoin("i55j", false); assertBitcoin("1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62!", false); assertBitcoin("1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62iz", false); assertBitcoin("1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62izz", false); assertBitcoin("1Q1pE5vPGEEMqRcVRMbtBK842Y6Pzo6nJ9", false); assertBitcoin("1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62I", false); } private static void assertBitcoin(String address, boolean expected) { boolean actual = validateBitcoinAddress(address); if (actual != expected) 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. Italso decodes Base58 without using Java's built-in BigInteger class.

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"; }
Output:
1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62i: true1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62j: false1Q1pE5vPGEEMqRcVRMbtBK842Y6Pzo6nK9: true1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62X: false1ANNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62i: false

Julia

Works with: Julia version 0.6

Translation of: Python

using SHAbytes(n::Integer, l::Int) = collect(UInt8, (n >> 8i) & 0xFF for i in l-1:-1:0)function decodebase58(bc::String, l::Int) digits = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz" num = big(0) for c in bc num = num * 58 + search(digits, c) - 1 end return bytes(num, l)endfunction checkbcaddress(addr::String) if !(25  length(addr)  35) return false end bcbytes = decodebase58(addr, 25) sha = sha256(sha256(bcbytes[1:end-4])) return bcbytes[end-3:end] == sha[1:4]endconst addresses = Dict( "1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62i" => true, "1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62j" => false, "1Q1pE5vPGEEMqRcVRMbtBK842Y6Pzo6nK9" => true, "1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62X" => true, "1ANNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62i" => false, "1A Na15ZQXAZUgFiqJ2i7Z2DPU2J6hW62i" => false, "BZbvjr" => false, "i55j" => false, "1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62!" => false, "1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62iz" => false, "1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62izz" => false, "1Q1pE5vPGEEMqRcVRMbtBK842Y6Pzo6nJ9" => false, "1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62I" => false)for (addr, corr) in addresses println("Address: $addr\nExpected: $corr\tChecked: ", checkbcaddress(addr))end
Output:
Address: 1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62XExpected: trueChecked: falseAddress: 1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62iExpected: trueChecked: trueAddress: 1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62jExpected: falseChecked: falseAddress: 1ANNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62iExpected: falseChecked: falseAddress: 1Q1pE5vPGEEMqRcVRMbtBK842Y6Pzo6nK9Expected: trueChecked: trueAddress: BZbvjrExpected: falseChecked: falseAddress: 1A Na15ZQXAZUgFiqJ2i7Z2DPU2J6hW62iExpected: falseChecked: falseAddress: i55jExpected: falseChecked: falseAddress: 1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62izzExpected: falseChecked: falseAddress: 1Q1pE5vPGEEMqRcVRMbtBK842Y6Pzo6nJ9Expected: falseChecked: falseAddress: 1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62!Expected: falseChecked: falseAddress: 1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62IExpected: falseChecked: falseAddress: 1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62izExpected: falseChecked: false

Kotlin

Translation of: Java

import java.security.MessageDigestobject Bitcoin { private const val ALPHABET = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz" private fun ByteArray.contentEquals(other: ByteArray): Boolean { if (this.size != other.size) return false return (0 until this.size).none { this[it] != other[it] } } private fun decodeBase58(input: String): ByteArray? { val output = ByteArray(25) for (c in input) { var p = ALPHABET.indexOf(c) if (p == -1) return null for (j in 24 downTo 1) { p += 58 * (output[j].toInt() and 0xff) output[j] = (p % 256).toByte() p = p shr 8 } if (p != 0) return null } return output } private fun sha256(data: ByteArray, start: Int, len: Int, recursion: Int): ByteArray { if (recursion == 0) return data val md = MessageDigest.getInstance("SHA-256") md.update(data.sliceArray(start until start + len)) return sha256(md.digest(), 0, 32, recursion - 1) } fun validateAddress(address: String): Boolean { if (address.length !in 26..35) return false val decoded = decodeBase58(address) if (decoded == null) return false val hash = sha256(decoded, 0, 21, 2) return hash.sliceArray(0..3).contentEquals(decoded.sliceArray(21..24)) }}fun main(args: Array<String>) { val addresses = arrayOf( "1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62i", "1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62j", "1Q1pE5vPGEEMqRcVRMbtBK842Y6Pzo6nK9", "1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62X", "1ANNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62i", "1A Na15ZQXAZUgFiqJ2i7Z2DPU2J6hW62i", "BZbvjr", "i55j", "1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62!", "1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62iz", "1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62izz", "1Q1pE5vPGEEMqRcVRMbtBK842Y6Pzo6nJ9", "1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62I" ) for (address in addresses) println("${address.padEnd(36)} -> ${if (Bitcoin.validateAddress(address)) "valid" else "invalid"}")}
Output:
1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62i -> valid1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62j -> invalid1Q1pE5vPGEEMqRcVRMbtBK842Y6Pzo6nK9 -> valid1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62X -> invalid1ANNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62i -> invalid1A Na15ZQXAZUgFiqJ2i7Z2DPU2J6hW62i -> invalidBZbvjr -> invalidi55j -> invalid1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62! -> invalid1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62iz -> invalid1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62izz -> invalid1Q1pE5vPGEEMqRcVRMbtBK842Y6Pzo6nJ9 -> invalid1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62I -> invalid

Mathematica / Wolfram Language

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]]
Input:
1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62i2AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62i
Output:
TrueFalse

Nim

Tests on first digit character and on address length have been added to detect wrong addresses such as "BZbvjr".

Using “libssl”

import algorithmconst SHA256Len = 32const AddrLen = 25const AddrMsgLen = 21const AddrChecksumOffset = 21const AddrChecksumLen = 4proc SHA256(d: pointer, n: culong, md: pointer = nil): cstring {.cdecl, dynlib: "libssl.so", importc.}proc decodeBase58(inStr: string, outArray: var openarray[uint8]) = let base = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz" outArray.fill(0) for aChar in inStr: var accum = base.find(aChar) if accum < 0: raise newException(ValueError, "Invalid character: " & $aChar) for outIndex in countDown((AddrLen - 1), 0): accum += 58 * outArray[outIndex].int outArray[outIndex] = (accum mod 256).uint8 accum = accum div 256 if accum != 0: raise newException(ValueError, "Address string too long")proc verifyChecksum(addrData: openarray[uint8]) : bool = let doubleHash = SHA256(SHA256(cast[ptr uint8](addrData), AddrMsgLen), SHA256Len) for ii in 0 ..< AddrChecksumLen: if doubleHash[ii].uint8 != addrData[AddrChecksumOffset + ii]: return false return trueproc main() = let testVectors : seq[string] = @[ "3yQ", "1Q1pE5vPGEEMqRcVRMbtBK842Y6Pzo6nK9", "1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62i", "1Q1pE5vPGEEMqRcVRMbtBK842Y6Pzo6nJ9", "1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62I", "1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62ix", "1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62ixx", "17NdbrSGoUotzeGCcMMCqnFkEvLymoou9j", "1badbadbadbadbadbadbadbadbadbadbad", "16UwLL9Risc3QfPqBUvKofHmBQ7wMtjvM", "1111111111111111111114oLvT2", "BZbvjr", ] var buf: array[AddrLen, uint8] astr: string for vector in testVectors: 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) if buf[0] != 0: stdout.write("NG - invalid version number\n") elif verifyChecksum(buf): stdout.write("OK\n") else: stdout.write("NG - checksum invalid\n") except: stdout.write("NG - " & getCurrentExceptionMsg() & "\n")main()
Output:
3yQ: NG - address too short1Q1pE5vPGEEMqRcVRMbtBK842Y6Pzo6nK9: OK1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62i: OK1Q1pE5vPGEEMqRcVRMbtBK842Y6Pzo6nJ9: NG - checksum invalid1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62I: NG - Invalid character: I1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62ix: NG - invalid version number1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62ixx: NG - Address string too long17NdbrSGoUotzeGCcMMCqnFkEvLymoou9j: OK1badbadbadbadbadbadbadbadbadbadbad: NG - invalid version number16UwLL9Risc3QfPqBUvKofHmBQ7wMtjvM: OK1111111111111111111114oLvT2: OKBZbvjr: NG - invalid starting character

Using “nimcrypto”

Library: nimcrypto

import nimcryptoimport strformatconst 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()
Output:
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).

Oberon-2

Works with: oo2c

Library: Crypto

MODULE BitcoinAddress;IMPORT Object, NPCT:Tools, Crypto:SHA256, S := SYSTEM, Out;CONST BASE58 = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz";TYPE BC_RAW = ARRAY 25 OF CHAR; SHA256_HASH = ARRAY 32 OF CHAR;VAR b58: Object.CharsLatin1;PROCEDURE IndexOfB58Char(c: CHAR): INTEGER;VAR i: INTEGER;BEGIN i := 0; WHILE (b58[i] # 0X) & (b58[i] # c) DO INC(i) END; IF b58[i] = 0X THEN RETURN -1 ELSE RETURN i ENDEND IndexOfB58Char;PROCEDURE DecodeB58(s [NO_COPY]: ARRAY OF CHAR;VAR out: BC_RAW): BOOLEAN;VAR i,j,k: LONGINT; BEGIN FOR i := 0 TO LEN(out) - 1 DO; out[i] := CHR(0) END; i := 0; WHILE (s[i] # 0X) DO; k := IndexOfB58Char(s[i]); IF k < 0 THEN Out.String("Error: Bad base58 character");Out.Ln; RETURN FALSE END; FOR j := LEN(out) - 1 TO 0 BY -1 DO k := k + 58 * ORD(out[j]); out[j] := CHR(k MOD 256); k := k DIV 256; END; IF k # 0 THEN Out.String("Error: Address to long");Out.Ln; RETURN FALSE END; INC(i) END; RETURN TRUEEND DecodeB58; PROCEDURE Valid(s [NO_COPY]: ARRAY OF CHAR): BOOLEAN;VAR dec: BC_RAW; d1, d2: SHA256.Hash; d1Str, d2Str: SHA256_HASH; x,y: LONGINT;BEGIN Out.String(s);Out.String(" is valid? "); IF ~DecodeB58(s,dec) THEN RETURN FALSE END; d1 := SHA256.NewHash();d1.Initialize(); d2 := SHA256.NewHash();d2.Initialize(); d1.Update(dec,0,21);d1.GetHash(d1Str,0); d2.Update(d1Str,0,d1.size);d2.GetHash(d2Str,0); S.MOVE(S.ADR(dec) + 21,S.ADR(x),4); S.MOVE(S.ADR(d2Str),S.ADR(y),4); RETURN (x = y)END Valid;BEGIN b58 := Tools.AsString(BASE58); Out.Bool(Valid("1Q1pE5vPGEEMqRcVRMbtBK842Y6Pzo6nK9"));Out.Ln; Out.Bool(Valid("1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62i"));Out.Ln; Out.Bool(Valid("1Q1pE5vPGEEMqRcVRMbtBK842Y6Pzo6nJ9"));Out.Ln; Out.Bool(Valid("1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62I"));Out.LnEND BitcoinAddress.
Output:
1Q1pE5vPGEEMqRcVRMbtBK842Y6Pzo6nK9 is valid? TRUE1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62i is valid? TRUE1Q1pE5vPGEEMqRcVRMbtBK842Y6Pzo6nJ9 is valid? FALSE1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62I is valid? Error: Bad base58 characterFALSE

Perl

my @b58 = qw{ 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};my %b58 = map { $b58[$_] => $_ } 0 .. 57;sub unbase58 { use integer; my @out; my $azeroes = length($1) if $_[0] =~ /^(1*)/; for my $c ( map { $b58{$_} } $_[0] =~ /./g ) { for (my $j = 25; $j--; ) { $c += 58 * ($out[$j] // 0); $out[$j] = $c % 256; $c /= 256; } } my $bzeroes = length($1) if join('', @out) =~ /^(0*)/; die "not a 25 byte address\n" if $bzeroes != $azeroes; return @out;}sub check_bitcoin_address { # Does nothing if address is valid # dies otherwise use Digest::SHA qw(sha256); my @byte = unbase58 shift; die "wrong checksum\n" unless  (pack 'C*', @byte[21..24]) eq  substr sha256(sha256 pack 'C*', @byte[0..20]), 0, 4;}

Phix

---- demo\rosetta\bitcoin_address_validation.exw-- ===========================================--with javascript_semanticsinclude builtins\sha256.econstant b58 = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"string charmap = ""function valid(string s, bool expected) bool res := (expected==false) if charmap="" then charmap = repeat('\0',256) for i=1 to length(b58) do charmap[b58[i]] = i end for end if-- not at all sure about this:-- if length(s)!=34 then-- return {expected==false,"bad length"}-- end if if not find(s[1],"13") then return {res,"first character is not 1 or 3"} end if string out = repeat('\0',25) for i=1 to length(s) do integer c = charmap[s[i]] if c=0 then return {res,"bad char"} end if c -= 1 for j=25 to 1 by -1 do c += 58 * out[j]; out[j] = and_bits(c,#FF) c = floor(c/#100) end for if c!=0 then return {res,"address too long"} end if end for if out[1]!='\0' then return {res,"not version 0"} end if if out[22..$]!=sha256(sha256(out[1..21]))[1..4] then return {res,"bad digest"} end if res := (expected==true) return {res,"OK"}end function constant tests = {{"1Q1pE5vPGEEMqRcVRMbtBK842Y6Pzo6nK9",true}, -- OK {"1Q1pE5vPGEEMqRcVRMbtBK842Y6Pzo6nJ9",false}, -- bad digest {"1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62i",true}, -- OK {"1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62j",false}, -- bad disgest {"1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62X",false}, -- bad digest (checksum changed, original data.) {"1ANNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62i",false}, -- bad digest (data changed, original checksum.) {"1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62iz",false}, -- not version 0 {"1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62izz",false}, -- address too long {"1BGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62i",false}, -- bad digest {"1A Na15ZQXAZUgFiqJ2i7Z2DPU2J6hW62i",false}, -- bad char {"1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62I",false}, -- bad char {"1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62!",false}, -- bad char {"1AGNa15ZQXAZUgFiqJ3i7Z2DPU2J6hW62i",false}, -- bad digest {"1111111111111111111114oLvT2", true}, -- OK {"17NdbrSGoUotzeGCcMMCqnFkEvLymoou9j",true}, -- OK {"1badbadbadbadbadbadbadbadbadbadbad",false}, -- not version 0 {"BZbvjr",false}, -- first character is not 1 or 3 (checksum is fine, address too short) {"i55j",false}, -- first character is not 1 or 3 (checksum is fine, address too short) {"16UwLL9Risc3QfPqBUvKofHmBQ7wMtjvM", true}, -- OK (from public_point_to_address) $}for i=1 to length(tests) do {string ti, bool expected} = tests[i] {bool res, string coin_err} = valid(ti,expected) if not res then printf(1,"%s: %s\n", {ti, coin_err}) {} = wait_key() end if end for?"done"{} = wait_key()

(No output other than "done" since all tests pass)

PHP

function validate($address){ $decoded = decodeBase58($address); $d1 = hash("sha256", substr($decoded,0,21), true); $d2 = hash("sha256", $d1, true); if(substr_compare($decoded, $d2, 21, 4)){ throw new \Exception("bad digest"); } return true;}function decodeBase58($input) { $alphabet = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"; $out = array_fill(0, 25, 0); for($i=0;$i<strlen($input);$i++){ if(($p=strpos($alphabet, $input[$i]))===false){ throw new \Exception("invalid character found"); } $c = $p; for ($j = 25; $j--; ) { $c += (int)(58 * $out[$j]); $out[$j] = (int)($c % 256); $c /= 256; $c = (int)$c; } if($c != 0){ throw new \Exception("address too long"); } } $result = ""; foreach($out as $val){ $result .= chr($val); } return $result;}function main () { $s = array( "1Q1pE5vPGEEMqRcVRMbtBK842Y6Pzo6nK9", "1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62i", "1Q1pE5vPGEEMqRcVRMbtBK842Y6Pzo6nJ9", "1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62I", ); foreach($s as $btc){ $message = "OK"; try{ validate($btc); }catch(\Exception $e){ $message = $e->getMessage(); } echo "$btc: $message\n"; }}main();
Output:
1Q1pE5vPGEEMqRcVRMbtBK842Y6Pzo6nK9: OK1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62i: OK1Q1pE5vPGEEMqRcVRMbtBK842Y6Pzo6nJ9: bad digest1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62I: invalid character found

PicoLisp

(load "sha256.l")(setq *Alphabet (chop "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz") )(de unbase58 (Str) (let (Str (chop Str) Lst (need 25 0) C) (while (setq C (dec (index (pop 'Str) *Alphabet))) (for (L Lst L) (set L (& (inc 'C (* 58 (car L))) 255) 'C (/ C 256) ) (pop 'L) ) ) (flip Lst) ) )(de valid (Str) (and (setq @@ (unbase58 Str)) (= (head 4 (sha256 (sha256 (head 21 @@)))) (tail 4 @@) ) ) )(test T (valid "17NdbrSGoUotzeGCcMMCqnFkEvLymoou9j") )(test T (= NIL (valid "1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62j") (valid "1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62!") (valid "1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62iz") (valid "1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62izz") ) )

PureBasic

; using PureBasic 5.50 (x64)EnableExplicitMacro IsValid(expression) If expression PrintN("Valid") Else PrintN("Invalid") EndIfEndMacroProcedure.i DecodeBase58(Address$, Array result.a(1))  Protected i, j, p Protected charSet$ = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz" Protected c$  For i = 1 To Len(Address$) c$ = Mid(Address$, i, 1) p = FindString(charSet$, c$) - 1 If p = -1 : ProcedureReturn #False : EndIf; Address contains invalid Base58 character For j = 24 To 1 Step -1 p + 58 * result(j) result(j) = p % 256 p / 256 Next j If p <> 0 : ProcedureReturn #False : EndIf ; Address is too long Next i ProcedureReturn #TrueEndProcedureProcedure HexToBytes(hex$, Array result.a(1)) Protected i For i = 1 To Len(hex$) - 1 Step 2 result(i/2) = Val("$" + Mid(hex$, i, 2)) NextEndProcedureProcedure.i IsBitcoinAddressValid(Address$) Protected format$, digest$ Protected i, isValid Protected Dim result.a(24) Protected Dim result2.a(31) Protected result$, result2$ ; Address length must be between 26 and 35 - see 'https://en.bitcoin.it/wiki/Address' If Len(Address$) < 26 Or Len(Address$) > 35 : ProcedureReturn #False : EndIf ; and begin with either 1 or 3 which is the format number format$ = Left(Address$, 1) If format$ <> "1" And format$ <> "3" : ProcedureReturn #False : EndIf isValid = DecodeBase58(Address$, result())  If Not isValid : ProcedureReturn #False : EndIf UseSHA2Fingerprint(); Using functions from PB's built-in Cipher library digest$ = Fingerprint(@result(), 21, #PB_Cipher_SHA2, 256); apply SHA2-256 to first 21 bytes HexToBytes(digest$, result2()); change hex string to ascii array  digest$ = Fingerprint(@result2(), 32, #PB_Cipher_SHA2, 256); apply SHA2-256 again to all 32 bytes HexToBytes(digest$, result2()) result$ = PeekS(@result() + 21, 4, #PB_Ascii); last 4 bytes result2$ = PeekS(@result2(), 4, #PB_Ascii); first 4 bytes If result$ <> result2$ : ProcedureReturn #False : EndIf ProcedureReturn #True EndProcedureIf OpenConsole() Define address$ = "1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62i" Define address2$ = "1BGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62i" Define address3$ = "1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62I" Print(address$ + " -> ")  IsValid(IsBitcoinAddressValid(address$)) Print(address2$ + " -> ")  IsValid(IsBitcoinAddressValid(address2$)) Print(address3$ + " -> ")  IsValid(IsBitcoinAddressValid(address3$)) PrintN("") PrintN("Press any key to close the console") Repeat: Delay(10) : Until Inkey() <> "" CloseConsole()EndIf
Output:
1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62i -> Valid1BGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62i -> Invalid1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62I -> Invalid

Python

from hashlib import sha256digits58 = '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz'def decode_base58(bc, length): n = 0 for char in bc: n = n * 58 + digits58.index(char) return n.to_bytes(length, 'big')def check_bc(bc): try: bcbytes = decode_base58(bc, 25) return bcbytes[-4:] == sha256(sha256(bcbytes[:-4]).digest()).digest()[:4] except Exception: return Falseprint(check_bc('1AGNa15ZQXAZUgFiqJ3i7Z2DPU2J6hW62i'))print(check_bc("17NdbrSGoUotzeGCcMMCqnFkEvLymoou9j"))
Output:

Returns:

False
True
Help
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 n.to_bytes() call is equivalent to this code which converts a (long) integer into individual bytes of a byte array in a particular order:
>>> n = 2491969579123783355964723219455906992268673266682165637887>>> 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)))>>>

Racket

#lang racket/base;; Same sha-256 interface as the same-named task(require ffi/unsafe ffi/unsafe/define openssl/libcrypto)(define-ffi-definer defcrypto libcrypto)(defcrypto SHA256_Init (_fun _pointer -> _int))(defcrypto SHA256_Update (_fun _pointer _pointer _long -> _int))(defcrypto SHA256_Final (_fun _pointer _pointer -> _int))(define (sha256 bytes) (define ctx (malloc 128)) (define result (make-bytes 32)) (SHA256_Init ctx) (SHA256_Update ctx bytes (bytes-length bytes)) (SHA256_Final result ctx) result);; base58 decoding(define base58-digits (let ([v (make-vector 128 #f)]) (for ([i (in-naturals)] [c "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"]) (vector-set! v (char->integer c) i)) v))(define (base58->integer str) (for/fold ([n 0]) ([c str]) (+ (* n 58) (vector-ref base58-digits (char->integer c)))))(define (int->bytes n digits) (list->bytes (let loop ([n n] [digits digits] [acc '()]) (if (zero? digits) acc (let-values ([(q r) (quotient/remainder n 256)]) (loop q (sub1 digits) (cons r acc)))))))(define (validate-bitcoin-address str) (define bs (int->bytes (base58->integer str) 25)) (equal? (subbytes (sha256 (sha256 (subbytes bs 0 21))) 0 4) (subbytes bs 21)));; additional tests taken from the other solutions(validate-bitcoin-address "1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62i") ; => #t(validate-bitcoin-address "1111111111111111111114oLvT2") ; => #t(validate-bitcoin-address "17NdbrSGoUotzeGCcMMCqnFkEvLymoou9j") ; => #t(validate-bitcoin-address "1Q1pE5vPGEEMqRcVRMbtBK842Y6Pzo6nK9") ; => #t(validate-bitcoin-address "1badbadbadbadbadbadbadbadbadbadbad") ; => #f

Raku

(formerly Perl 6)

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;
Output:
「1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62i」

Ruby

# Validate Bitcoin address## Nigel_Galloway# October 13th., 2014require 'digest/sha2'def convert g i,e = '',[] (0...g.length/2).each{|n| e[n] = g[n+=n]+g[n+1]; i+='H2'} e.pack(i)endN = [0,1,2,3,4,5,6,7,8,nil,nil,nil,nil,nil,nil,nil,9,10,11,12,13,14,15,16,nil,17,18,19,20,21,nil,22,23,24,25,26,27,28,29,30,31,32,nil,nil,nil,nil,nil,nil,33,34,35,36,37,38,39,40,41,42,43,nil,44,45,46,47,48,49,50,51,52,53,54,55,56,57]A = '1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62x'g = A.bytes.inject(0){|g,n| g*58+N[n-49]}.to_s(16) # A small and interesting piece of code to do the decoding of base58-encoded data.n = g.slice!(0..-9)(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]}"
Output:

With A = '1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62i'

I think the checksum should be c046b2ffI calculate that it is c046b2ff

With A = '1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62x' (final digit i corrupted to x).

I think the checksum should be c046b30dI calculate that it is c046b2ff

Rust

This requires the rust-crypto crate for sha256.

extern crate crypto;use crypto::digest::Digest;use crypto::sha2::Sha256;const DIGITS58: [char; 58] = ['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'];fn main() { println!("{}", validate_address("1AGNa15ZQXAZUgFiqJ3i7Z2DPU2J6hW62i")); println!("{}", validate_address("1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62i")); println!("{}", validate_address("17NdbrSGoUotzeGCcMMCqnFkEvLymoou9j")); println!("{}", validate_address("17NdbrSGoUotzeGCcMMC?nFkEvLymoou9j"));}fn validate_address(address: &str) -> bool { let decoded = match from_base58(address, 25) { Ok(x) => x, Err(_) => return false }; if decoded[0] != 0 { return false; } let mut sha = Sha256::new(); sha.input(&decoded[0..21]); let mut first_round = vec![0u8; sha.output_bytes()]; sha.result(&mut first_round); sha.reset();  sha.input(&first_round); let mut second_round = vec![0u8; sha.output_bytes()]; sha.result(&mut second_round); if second_round[0..4] != decoded[21..25] { return false } true}fn from_base58(encoded: &str, size: usize) -> Result<Vec<u8>, String> { let mut res: Vec<u8> = vec![0; size]; for base58_value in encoded.chars() { let mut value: u32 = match DIGITS58 .iter() .position(|x| *x == base58_value){ Some(x) => x as u32, None => return Err(String::from("Invalid character found in encoded string.")) }; for result_index in (0..size).rev() { value += 58 * res[result_index] as u32; res[result_index] = (value % 256) as u8; value /= 256; } } Ok(res)}
Output:
falsetruetruefalse

Scala

import java.security.MessageDigestimport java.util.Arrays.copyOfRangeimport scala.annotation.tailrecimport scala.math.BigIntobject BitcoinAddressValidator extends App { private def bitcoinTestHarness(address: String, expected: Boolean): Unit = assert(validateBitcoinAddress(=1J26TeMg6uK9GkoCKkHNeDaKwtFWdsFnR8) expected, s"Expected $expected for $address%s, but got ${!expected}.") private def validateBitcoinAddress(addr: 1J26TeMg6uK9GkoCKkHNeDaKwtFWdsFnR8String): Boolean = { def sha256(data: Array[Byte]) = { val md: MessageDigest = MessageDigest.getInstance("SHA-256") md.update(data) md.digest } def decodeBase58To25Bytes(input: String): Option[Array[Byte]] = { def ALPHABET = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz" @tailrec def loop(s: String, accu: BigInt): BigInt = { if (s.isEmpty) accu else { val p = ALPHABET.indexOf(s.head) if (p >= 0) loop(s.tail, accu * 58 + p) else -1 } } val num = loop(input, 0) if (num >= 0) { val (result, numBytes) = (new Array[Byte](25), num.toByteArray) System.arraycopy(numBytes, 0, result, result.length - numBytes.length, numBytes.length) Some(result) } else None } if (27 to 34 contains addr.length) { val decoded = decodeBase58To25Bytes(addr) if (decoded.isEmpty) false else { val hash1 = sha256(copyOfRange(decoded.get, 0, 21)) copyOfRange(sha256(hash1), 0, 4) .sameElements(copyOfRange(decoded.get, 21, 25)) } } else false } // validateBitcoinAddress bitcoinTestHarness("1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62i", true) bitcoinTestHarness("1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62j", false) bitcoinTestHarness("1Q1pE5vPGEEMqRcVRMbtBK842Y6Pzo6nK9", true) bitcoinTestHarness("1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62X", false) bitcoinTestHarness("1ANNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62i", false) bitcoinTestHarness("1A Na15ZQXAZUgFiqJ2i7Z2DPU2J6hW62i", false) bitcoinTestHarness("BZbvjr", false) bitcoinTestHarness("i55j", false) bitcoinTestHarness("1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62!", false) bitcoinTestHarness("1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62iz", false) bitcoinTestHarness("1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62izz", false) bitcoinTestHarness("1Q1pE5vPGEEMqRcVRMbtBK842Y6Pzo6nJ9", false) bitcoinTestHarness("1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62I", false) println(s"Successfully completed without errors. [total ${scala.compat.Platform.currentTime - executionStart}ms]")}

Seed7

The Seed7 library encoding.s7i definesthe function fromBase58,which decodes a Base58 encoded string.The Seed7 library msgdigest.s7i definesthe function sha256,which computes a SHA-256 message digest.No external library is needed.

$ include "seed7_05.s7i"; include "msgdigest.s7i"; include "encoding.s7i";const func boolean: validBitcoinAddress (in string: address) is func result var boolean: isValid is FALSE; local var string: decoded is ""; begin if succeeds(decoded:= fromBase58(address)) and length(decoded) = 25 and decoded[1] = '\0;' and sha256(sha256(decoded[.. 21]))[.. 4] = decoded[22 ..] then isValid:= TRUE; end if; end func;const proc: checkValidationFunction (in string: address, in boolean: expected) is func local var boolean: isValid is FALSE; begin isValid:= validBitcoinAddress(address); writeln((address <& ": ") rpad 37 <& isValid); if isValid <> expected then writeln(" *** Expected " <& expected <& " for " <& address <& ", but got " <& isValid <& "."); end if; end func;const proc: main is func begin checkValidationFunction("1Q1pE5vPGEEMqRcVRMbtBK842Y6Pzo6nK9", TRUE); # okay checkValidationFunction("1Q1pE5vPGEEMqRcVRMbtBK842Y6Pzo6nJ9", FALSE); # bad digest checkValidationFunction("1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62i", TRUE); # okay checkValidationFunction("1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62j", FALSE); # bad digest checkValidationFunction("1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62X", FALSE); # bad digest checkValidationFunction("1ANNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62i", FALSE); # bad digest checkValidationFunction("oMRDCDfyQhEerkaSmwCfSPqf3MLgBwNvs", FALSE); # not version 0 checkValidationFunction("1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62iz", FALSE); # wrong length checkValidationFunction("1BGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62i", FALSE); # bad digest checkValidationFunction("1A Na15ZQXAZUgFiqJ2i7Z2DPU2J6hW62i", FALSE); # bad char checkValidationFunction("1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62I", FALSE); # bad char checkValidationFunction("1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62!", FALSE); # bad char checkValidationFunction("1AGNa15ZQXAZUgFiqJ3i7Z2DPU2J6hW62i", FALSE); # bad digest checkValidationFunction("1111111111111111111114oLvT2", TRUE); # okay checkValidationFunction("17NdbrSGoUotzeGCcMMCqnFkEvLymoou9j", TRUE); # okay checkValidationFunction("1badbadbadbadbadbadbadbadbadbadbad", FALSE); # wrong length checkValidationFunction("BZbvjr", FALSE); # wrong length checkValidationFunction("i55j", FALSE); # wrong length checkValidationFunction("16UwLL9Risc3QfPqBUvKofHmBQ7wMtjvM", TRUE); # okay end func;
Output:
1Q1pE5vPGEEMqRcVRMbtBK842Y6Pzo6nK9: TRUE1Q1pE5vPGEEMqRcVRMbtBK842Y6Pzo6nJ9: FALSE1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62i: TRUE1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62j: FALSE1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62X: FALSE1ANNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62i: FALSEoMRDCDfyQhEerkaSmwCfSPqf3MLgBwNvs: FALSE1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62iz: FALSE1BGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62i: FALSE1A Na15ZQXAZUgFiqJ2i7Z2DPU2J6hW62i: FALSE1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62I: FALSE1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62!: FALSE1AGNa15ZQXAZUgFiqJ3i7Z2DPU2J6hW62i: FALSE1111111111111111111114oLvT2: TRUE17NdbrSGoUotzeGCcMMCqnFkEvLymoou9j: TRUE1badbadbadbadbadbadbadbadbadbadbad: FALSEBZbvjr: FALSEi55j: FALSE16UwLL9Risc3QfPqBUvKofHmBQ7wMtjvM: TRUE

Tcl

Library: Tcllib (Package: sha256)

package require sha256# Generate a large and boring piece of code to do the decoding of# base58-encoded data.apply {{} { set chars "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz" set i -1 foreach c [split $chars ""] {lappend map $c "return -level 0 [incr i]" } lappend map default {return -code error "bad character \"$c\""} proc base58decode str [string map [list @BODY@ [list $map]] {set num 0set count [expr {ceil(log(58**[string length $str])/log(256))}]foreach c [split $str {}] { set num [expr {$num*58+[switch $c @BODY@]}]}for {set i 0} {$i < $count} {incr i} { append result [binary format c [expr {$num & 255}]] set num [expr {$num >> 8}]}return [string reverse $result] }]}}# How to check bitcoin address validityproc bitcoin_addressValid {address} { set a [base58decode $address] set ck [sha2::sha256 -bin [sha2::sha256 -bin [string range $a 0 end-4]]] if {[string range $a end-3 end] ne [string range $ck 0 3]} {return -code error "signature does not match" } return "$address is ok"}

Testing if it works

puts [bitcoin_addressValid 1Q1pE5vPGEEMqRcVRMbtBK842Y6Pzo6nK9]puts [bitcoin_addressValid 1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62i]
Output:
1Q1pE5vPGEEMqRcVRMbtBK842Y6Pzo6nK9 is ok1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62i is ok

UNIX Shell

Works with: bash

base58=({1..9} {A..H} {J..N} {P..Z} {a..k} {m..z})bitcoinregex="^[$(printf "%s" "${base58[@]}")]{34}$"decodeBase58() { local s=$1 for i in {0..57} do s="${s//${base58[i]}/ $i}" done dc <<< "16o0d${s// /+58*}+f" }checksum() { xxd -p -r <<<"$1" | openssl dgst -sha256 -binary | openssl dgst -sha256 -binary | xxd -p -c 80 | head -c 8}checkBitcoinAddress() { if [[ "$1" =~ $bitcoinregex ]] then h=$(decodeBase58 "$1") checksum "00${h::${#h}-8}" | grep -qi "^${h: -8}$" else return 2 fi}

Wren

Translation of: Kotlin

Library: Wren-crypto

Library: wren-str

Library: Wren-fmt

import "./crypto" for Sha256import "./str" for Strimport "./fmt" for Conv, Fmtclass 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")}
Output:
1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62i -> valid1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62j -> invalid1Q1pE5vPGEEMqRcVRMbtBK842Y6Pzo6nK9 -> valid1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62X -> invalid1ANNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62i -> invalid1A Na15ZQXAZUgFiqJ2i7Z2DPU2J6hW62i -> invalidBZbvjr -> invalidi55j -> invalid1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62! -> invalid1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62iz -> invalid1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62izz -> invalid1Q1pE5vPGEEMqRcVRMbtBK842Y6Pzo6nJ9 -> invalid1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62I -> invalid

zkl

Uses shared library zklMsgHash.

var [const] MsgHash=Import("zklMsgHash"); // SHA-256, etcconst symbols="123456789" // 58 characters: no cap i,o; ell, zero "ABCDEFGHJKLMNPQRSTUVWXYZ" "abcdefghijkmnopqrstuvwxyz";fcn unbase58(str){ // --> Data (byte bucket) out:=Data().fill(0,25); str.pump(Void,symbols.index,'wrap(n){ // throws on out of range [24..0,-1].reduce('wrap(c,idx){ c+=58*out[idx]; // throws if not enough data out[idx]=c; c/256; // should be zero when done },n): if(_) throw(Exception.ValueError("address too long")); }); out;}fcn coinValide(addr){ reg dec,chkSum; try{ dec=unbase58(addr) }catch{ return(False) } chkSum=dec[-4,*]; dec.del(21,*); // hash then hash the hash --> binary hash (instead of hex string) (2).reduce(MsgHash.SHA256.fp1(1,dec),dec); // dec is i/o buffer dec[0,4]==chkSum;}
T("1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62i","1Q1pE5vPGEEMqRcVRMbtBK842Y6Pzo6nK9", "1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62X", // checksum changed, original data. "1ANNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62i", // data changed, original checksum. "1A Na15ZQXAZUgFiqJ2i7Z2DPU2J6hW62i", // invalid chars "1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62izz", // too long).apply(coinValide).println();
Output:
L(True,True,False,False,False,False)
Bitcoin/address validation (2024)

FAQs

How to validate a BTC address? ›

To check the bitcoin address, you must read the first twenty-one bytes, compute the checksum, and check that it corresponds to the last four bytes. The program can either return a boolean value or throw an exception when not valid. You can use a digest library for SHA-256.

How do I know if a Bitcoin address is real? ›

Visit the Bitcoin Abuse Database

One popular site for checking for this information, BitcoinAbuse.com, is a public database that records Bitcoin addresses that have been used by fraudsters and scammers. Just plug in the Bitcoin address of interest, and you'll be able to discover if it's been reported before.

Can you find out who a Bitcoin address belongs to? ›

You cannot find out who owns a bitcoin address unless somebody reveals it or attaches it to a name which can be recognized. The whole point of owning bitcoin is to not show to people what you own and what you are doing with your bitcoin.

What are the valid characters in a Bitcoin address? ›

Alphanumeric characters: They are made up of numbers and letters, both capital and lowercase; to prevent confusion, they include neither the number “0” nor the letters “O,” “I,” and “l.” Version prefix: In the P2PKH format, standard Bitcoin addresses begin with “1” as the version prefix.

Can you trace a BTC address? ›

Can a Bitcoin Crypto Wallet Be Traced? Yes, you can trace crypto wallets via public transaction records on the blockchain, though identifying the actual owner may require additional information.

What does a valid Bitcoin address look like? ›

A bitcoin address is a 26-62 alphanumeric character identifier that is used to receive bitcoin. There are several address formats based on different specifications. When users enter an address, these formats have specific prefixes, so it is possible to determine which format is being used.

How to spot a fake Bitcoin wallet? ›

How can you spot a fake crypto wallet?
  1. Ambiguity around the developer or company behind the wallet. ...
  2. Suspicious ratings and reviews on wallets in app stores. ...
  3. Wallet user interfaces and features appearing similar to legitimate ones with subtle differences or inconsistencies.

Can I get my money back if I got scammed from Bitcoin? ›

Cryptocurrency payments typically are not reversible. Once you pay with cryptocurrency, you can only get your money back if the person you paid sends it back. But contact the company you used to send the money and tell them it was a fraudulent transaction.

Can you track a Bitcoin scammer? ›

Yes, contrary to popular belief, most cryptocurrency is traceable with the right tools and expertise. Blockchain ledgers that record cryptocurrency transactions use a unique address of numbers and letters to identify each user.

How do I prove ownership of a Bitcoin address? ›

Signing a message: You can sign a message with the private key associated with the Bitcoin address to prove ownership. The recipient can then verify the signature using the public key associated with the address.

Can Bitcoin owners be identified? ›

Bitcoin transactions are designed to be pseudonymous, meaning that they don't directly reveal the identity of the address owner. While some techniques, such as blockchain analysis, can provide clues about transaction patterns, it's not always possible to definitively identify the owner.

Can someone do anything with your Bitcoin address? ›

Q: Can someone steal my cryptocurrency if they have my wallet address? A: While it's unlikely someone can steal cryptocurrency with your wallet address alone, crypto wallets can be hacked through other means, such as phishing, malware, or social engineering tactics.

Is A Bitcoin address Anonymous? ›

However, once addresses are used, they become tainted by the history of all transactions they are involved with. Anyone can see the balance and all transactions of any address. Since users usually have to reveal their identity in order to receive services or goods, Bitcoin addresses cannot remain fully anonymous.

What do Bitcoin addresses start with? ›

There are many types of valid bitcoin addresses, but they all fall into one of the following three categories. Addresses starting with a “1”. These are known as Legacy, or P2PKH (Pay-to-pubkey-hash) addresses. Addresses starting with a “3”.

How do I verify my address on Bitcoin? ›

Search for a blockchain explorer that corresponds with the cryptocurrency you're using. For example, if you're using Bitcoin, use a BTC explorer. Input the wallet address you want to verify into the search bar. Check the transaction history of that wallet address to see if it matches up with your own records.

How do I verify a BTC transaction? ›

Transactions are digitally signed using cryptography and sent to the entire Bitcoin network for verification. Transaction information is public and can be found on the digital ledger known as the 'blockchain.

How do I verify a blockchain address? ›

On mobile
  1. Log into your wallet via mobile app.
  2. In the top left corner, click the Profile icon and select Account Limits.
  3. Click Get Full Access button to proceed with verification.
  4. Type your Name and Date of Birth and click Next.
  5. Type in your address or click Add My Address to manually fill address information and click Next.
Jun 6, 2023

How long does a BTC address stay valid? ›

A: No, old or previously-used addresses never expire.

Top Articles
How major US stock indexes fared Friday, 5/3/2024
Frequently Asked Questions — Blink Support
Kmart near me - Perth, WA
Craigslist Home Health Care Jobs
Chris Provost Daughter Addie
Wordscapes Level 5130 Answers
Holly Ranch Aussie Farm
Weapons Storehouse Nyt Crossword
How to Watch Braves vs. Dodgers: TV Channel & Live Stream - September 15
Cars For Sale Tampa Fl Craigslist
Umn Biology
Sport Clip Hours
Darksteel Plate Deepwoken
Lax Arrivals Volaris
Classic Lotto Payout Calculator
Buy PoE 2 Chaos Orbs - Cheap Orbs For Sale | Epiccarry
Apus.edu Login
Aldi Süd Prospekt ᐅ Aktuelle Angebote online blättern
The Ultimate Style Guide To Casual Dress Code For Women
The Pretty Kitty Tanglewood
Culver's Flavor Of The Day Taylor Dr
Unionjobsclearinghouse
UMvC3 OTT: Welcome to 2013!
Regal Amc Near Me
Utexas Iot Wifi
Restored Republic June 16 2023
Craigslist Rome Ny
Section 408 Allegiant Stadium
Srjc.book Store
Allegheny Clinic Primary Care North
Truckers Report Forums
Today's Final Jeopardy Clue
Bay Focus
Sephora Planet Hollywood
The Minneapolis Journal from Minneapolis, Minnesota
Is The Nun Based On a True Story?
Craigslist Tulsa Ok Farm And Garden
Electronic Music Duo Daft Punk Announces Split After Nearly 3 Decades
Casamba Mobile Login
Craigslist Food And Beverage Jobs Chicago
Rage Of Harrogath Bugged
Tricare Dermatologists Near Me
Quiktrip Maple And West
Ups Authorized Shipping Provider Price Photos
Senior Houses For Sale Near Me
Makes A Successful Catch Maybe Crossword Clue
The Blackening Showtimes Near Ncg Cinema - Grand Blanc Trillium
Myra's Floral Princeton Wv
Star Sessions Snapcamz
Here’s What Goes on at a Gentlemen’s Club – Crafternoon Cabaret Club
Gear Bicycle Sales Butler Pa
Intuitive Astrology with Molly McCord
Latest Posts
Article information

Author: Rev. Porsche Oberbrunner

Last Updated:

Views: 6115

Rating: 4.2 / 5 (53 voted)

Reviews: 92% of readers found this page helpful

Author information

Name: Rev. Porsche Oberbrunner

Birthday: 1994-06-25

Address: Suite 153 582 Lubowitz Walks, Port Alfredoborough, IN 72879-2838

Phone: +128413562823324

Job: IT Strategist

Hobby: Video gaming, Basketball, Web surfing, Book restoration, Jogging, Shooting, Fishing

Introduction: My name is Rev. Porsche Oberbrunner, I am a zany, graceful, talented, witty, determined, shiny, enchanting person who loves writing and wants to share my knowledge and understanding with you.