Movatterモバイル変換


[0]ホーム

URL:


Jump to content
Rosetta Code
Search

Bitcoin/address validation

From Rosetta Code
Warning: Many of these snippets areincomplete. It is recommended that you use an establishedlibrary for any projects that are likely to see external use
Task
Bitcoin/address validation
You are encouraged tosolve this task according to the task description, using any language you may know.


Task

Write a program that takes abitcoin 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 aRIPEMD-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 doubleSHA-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 forSHA-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

withAda.Exceptions,Interfaces;withAda.Streams;useAda.Exceptions,Interfaces;useAda.Streams;packageBitcoinissubtypeBT_Raw_AddrisStream_Element_Array(1..25);subtypeBT_ChecksumisStream_Element_Array(1..4);subtypeBT_AddrisString(1..34);subtypeSha256StringisString(1..64);Invalid_Address_Error:Exception;functionDouble_Sha256(S:Stream_Element_Array)returnBT_Checksum;functionIs_Valid(A:BT_Raw_Addr)returnBoolean;procedureBase58_Decode(S:BT_Addr;A:outBT_Raw_Addr);privateBase58:constantString:="123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz";functionHex_Val(C,C2:Character)returnStream_Element;endBitcoin;withGNAT.SHA256,Ada.Strings.Fixed;useGNAT.SHA256,Ada.Strings.Fixed;packagebodyBitcoinisfunctionHex_Val(C,C2:Character)returnStream_ElementissubtypeNibbleisIntegerrange0..15;HEX:array(0..255)ofNibble:=(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);beginreturnStream_Element(HEX(Character'Pos(C))*16+HEX(Character'Pos(C2)));endHex_Val;functionDouble_Sha256(S:Stream_Element_Array)returnBT_ChecksumisCtx:Context:=Initial_Context;D:Message_Digest;S2:Stream_Element_Array(1..32);Ctx2:Context:=Initial_Context;C:BT_Checksum;beginUpdate(Ctx,S);D:=Digest(Ctx);forIinS2'RangeloopS2(I):=Hex_Val(D(Integer(I)*2-1),D(Integer(I)*2));endloop;Update(Ctx2,S2);D:=Digest(Ctx2);forIinC'RangeloopC(I):=Hex_Val(D(Integer(I)*2-1),D(Integer(I)*2));endloop;returnC;endDouble_Sha256;---------------------------------------------------------------------------------- Summary of Base58:                                                         ---- We decode S into a 200 bit unsigned integer.                               ---- We could use a BigNum library, but choose to go without.                   ----------------------------------------------------------------------------------procedureBase58_Decode(S:BT_Addr;A:outBT_Raw_Addr)isbeginA:=(Others=>0);forIinS'RangeloopdeclareP:Natural:=Index(Base58,String(S(I..I)));C:Natural;beginifP=0thenraiseInvalid_Address_Error;endif;C:=P-1;forJinreverseA'RangeloopC:=C+Natural(A(J))*58;A(J):=Stream_Element(Unsigned_32(C)and255);-- 0x00FFC:=Natural(Shift_Right(Unsigned_32(C),8)and255);-- 0xFF00endloop;ifC/=0thenraiseInvalid_Address_Error;endif;end;endloop;endBase58_Decode;functionIs_Valid(A:BT_Raw_Addr)returnBooleanisbeginreturnA(1)=0andA(22..25)=Double_Sha256(A(1..21));endIs_Valid;endBitcoin;withAda.Text_IO,Bitcoin;useAda.Text_IO,Bitcoin;procedureBitcoin_Addr_ValidateisbegindeclareBTs:array(positiverange<>)ofBT_Addr:=("1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62i"-- VALID,"1Q1pE5vPGEEMqRcVRMbtBK842Y6Pzo6nK9"-- VALID,"1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62X"-- checksum changed, original data.,"1ANNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62i"-- data changed, original checksum.,"1A Na15ZQXAZUgFiqJ2i7Z2DPU2J6hW62i"-- invalid chars);beginforIinBts'RangeloopdeclareA:BT_Raw_Addr;Valid:Boolean;beginPut(BTs(I)&" validity: ");Base58_Decode(BTs(I),A);Valid:=Is_Valid(A);Put_Line(Boolean'Image(Valid));exceptionwhenE:Invalid_Address_Error=>Put_Line("*** Error: Invalid BT address.");end;endloop;end;endBitcoin_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>constchar*coin_err;#define bail(s) { coin_err = s; return 0; }intunbase58(constchar*s,unsignedchar*out){staticconstchar*tmpl="123456789""ABCDEFGHJKLMNPQRSTUVWXYZ""abcdefghijkmnopqrstuvwxyz";inti,j,c;constchar*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");}return1;}intvalid(constchar*s){unsignedchardec[32],d1[SHA256_DIGEST_LENGTH],d2[SHA256_DIGEST_LENGTH];coin_err="";if(!unbase58(s,dec))return0;SHA256(SHA256(dec,21,d1),SHA256_DIGEST_LENGTH,d2);if(memcmp(dec+21,d2,4))bail("bad digest");return1;}intmain(void){constchar*s[]={"1Q1pE5vPGEEMqRcVRMbtBK842Y6Pzo6nK9","1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62i","1Q1pE5vPGEEMqRcVRMbtBK842Y6Pzo6nJ9","1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62I",0};inti;for(i=0;s[i];i++){intstatus=valid(s[i]);printf("%s: %s\n",s[i],status?"Ok":coin_err);}return0;}

Compile with -lcrypto

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

C#

This requiresNUnit package to compile.

usingSystem;usingSystem.Linq;usingSystem.Security.Cryptography;usingNUnit.Framework;namespaceBitcoinValidator{publicclassValidateTest{[TestCase]publicvoidValidateBitcoinAddressTest(){Assert.IsTrue(ValidateBitcoinAddress("1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62i"));// VALIDAssert.IsTrue(ValidateBitcoinAddress("1Q1pE5vPGEEMqRcVRMbtBK842Y6Pzo6nK9"));// VALIDAssert.Throws<Exception>(()=>ValidateBitcoinAddress("1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62X"));// checksum changed, original dataAssert.Throws<Exception>(()=>ValidateBitcoinAddress("1ANNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62i"));// data changed, original checksumAssert.Throws<Exception>(()=>ValidateBitcoinAddress("1A Na15ZQXAZUgFiqJ2i7Z2DPU2J6hW62i"));// invalid charsAssert.Throws<Exception>(()=>ValidateBitcoinAddress("BZbvjr"));// checksum is fine, address too short}publicstaticboolValidateBitcoinAddress(stringaddress){if(address.Length<26||address.Length>35)thrownewException("wrong length");vardecoded=DecodeBase58(address);vard1=Hash(decoded.SubArray(0,21));vard2=Hash(d1);if(!decoded.SubArray(21,4).SequenceEqual(d2.SubArray(0,4)))thrownewException("bad digest");returntrue;}conststringAlphabet="123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz";constintSize=25;privatestaticbyte[]DecodeBase58(stringinput){varoutput=newbyte[Size];foreach(vartininput){varp=Alphabet.IndexOf(t);if(p==-1)thrownewException("invalid character found");varj=Size;while(--j>0){p+=58*output[j];output[j]=(byte)(p%256);p/=256;}if(p!=0)thrownewException("address too long");}returnoutput;}privatestaticbyte[]Hash(byte[]bytes){varhasher=newSHA256Managed();returnhasher.ComputeHash(bytes);}}publicstaticclassArrayExtensions{publicstaticT[]SubArray<T>(thisT[]data,intindex,intlength){varresult=newT[length];Array.Copy(data,index,result,0,length);returnresult;}}}

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"SHA256sha256{};conststd::stringALPHABET="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(conststd::string&text){std::vector<uint32_t>bytes(text.size()/2,0);for(uint64_ti=0;i<text.size();i+=2){constuint32_tfirst_digit=base_map[text[i]];constuint32_tsecond_digit=base_map[text[i+1]];bytes[i/2]=(first_digit<<4)+second_digit;}returnbytes;}std::stringvector_to_ascii_string(conststd::vector<uint32_t>&bytes){std::stringresult="";for(uint32_ti=0;i<bytes.size();++i){result+=static_cast<char>(bytes[i]);}returnresult;}std::vector<uint32_t>decode_base_58(conststd::string&text){std::vector<uint32_t>result(25,0);for(constchar&ch:text){std::string::size_typeindex=ALPHABET.find(ch);if(index==static_cast<uint64_t>(-1)){throwstd::invalid_argument("Invalid character found in bitcoin address");}for(uint64_ti=result.size()-1;i>0;i--){index+=58*result[i];result[i]=index&0xFF;index>>=8;}if(index!=0){throwstd::invalid_argument("Bitcoin address is too long");}}returnresult;}boolis_valid(conststd::string&address){if(address.size()<26||address.size()>35){throwstd::invalid_argument("Invalid length of bitcoin address");}std::vector<uint32_t>decoded=decode_base_58(address);std::vectorfirst21(decoded.begin(),decoded.begin()+21);// Convert the 'first21' into a suitable ASCII string for the first SHA256 hashstd::stringtext=vector_to_ascii_string(first21);std::stringhash_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::stringascii_1=vector_to_ascii_string(bytes_1);std::stringhash_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);returnchecksum==last4;}intmain(){conststd::vector<std::string>addresses={"1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62i","1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62j","1Q1pE5vPGEEMqRcVRMbtBK842Y6Pzo6nK9","1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62X","1ANNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62i"};for(conststd::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
importstd.stdio,std.algorithm,std.array,std.string,sha_256_2;structA25{// Type for a 25 ubyte (not base58 encoded) bitcoin address.ubyte[25]enc;ubytebitcoinVersion()constpurenothrow@safe@nogc{returnenc[0];}ubyte[4]embeddedChecksum()returnconstpurenothrow@safe@nogc{returnenc[$-4..$];}/** Computes a double sha256 hash of the first 21 bytes of    the address. Returns the full 32 ubyte sha256 hash. */ubyte[32]doubleSHA256()constpurenothrow@nogc{returnSHA256.digest(SHA256.digest(enc[0..21]));}/** Returns a four ubyte checksum computed from the first 21    bytes of the address. */ubyte[4]computeChecksum()constpurenothrow@nogc{returndoubleSHA256[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. */stringset58(inubyte[]s)purenothrow@safe@nogc{staticimmutabledigits="123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz".representation;staticassert(digits.length==58);foreach(immutablechars1;s){immutablec=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.uintuc=(c<0)?0:c;foreach_reverse(refaj;enc){uc+=digits.length*aj;aj=uc%256;uc/=256;}if(uc>0)return"too long Bitcoin address.";}returnnull;}}/** 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. */stringisValidA58(inubyte[]a58)purenothrow@nogc{A25a;immutableerr=a.set58(a58);if(!err.empty)returnerr;if(a.bitcoinVersion!=0)return"not Bitcoin version 0.";return(a.embeddedChecksum==a.computeChecksum)?null:"checksums don't match.";}voidmain(){immutabletests=["1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62i","1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62j","1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62!","1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62iz","1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62izz"];foreach(immutabletest;tests){immutableerr=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 requiresCrypto package to compile.

Translation of:Java
import'package:crypto/crypto.dart';classBitcoin{finalStringALPHABET="123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz";List<int>bigIntToByteArray(BigIntdata){Stringstr;boolneg=false;if(data<BigInt.zero){str=(~data).toRadixString(16);neg=true;}elsestr=data.toRadixString(16);intp=0;intlen=str.length;intblen=(len+1)~/2;intboff=0;Listbytes;if(neg){if(len&1==1){p=-1;}intbyte0=~int.parse(str.substring(0,p+2),radix:16);if(byte0<-128)byte0+=256;if(byte0>=0){boff=1;bytes=newList<int>(blen+1);bytes[0]=-1;bytes[1]=byte0;}else{bytes=newList<int>(blen);bytes[0]=byte0;}for(inti=1;i<blen;++i){intbyte=~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;}intbyte0=int.parse(str.substring(0,p+2),radix:16);if(byte0>127)byte0-=256;if(byte0<0){boff=1;bytes=newList<int>(blen+1);bytes[0]=0;bytes[1]=byte0;}else{bytes=newList<int>(blen);bytes[0]=byte0;}for(inti=1;i<blen;++i){intbyte=int.parse(str.substring(p+(i<<1),p+(i<<1)+2),radix:16);if(byte>127)byte-=256;bytes[i+boff]=byte;}}returnbytes;}List<int>arrayCopy(bytes,srcOffset,result,destOffset,bytesLength){for(inti=srcOffset;i<bytesLength;i++){result[destOffset+i]=bytes[i];}returnresult;}List<int>decodeBase58To25Bytes(Stringinput){BigIntnumber=BigInt.zero;for(Stringtininput.split('')){intp=ALPHABET.indexOf(t);if(p==(-1))returnnull;number=number*(BigInt.from(58))+(BigInt.from(p));}List<int>result=newList<int>(24);List<int>numBytes=bigIntToByteArray(number);returnarrayCopy(numBytes,0,result,result.length-numBytes.length,numBytes.length);}validateAddress(Stringaddress){List<int>decoded=newList.from(decodeBase58To25Bytes(address));List<int>temp=newList<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])returnfalse;returntrue;}}
Output:
"1BNGaR29FmfAqidXmD9HLwsGv9p5WVvvhq" true"1BNGaR29FmfAqidXmD9HLws" false

Delphi

This requiresDCPcrypt library to compile.

usesDCPsha256;typeTByteArray=arrayofByte;functionHashSHA256(constInput:TByteArray):TByteArray;varHasher:TDCP_sha256;beginHasher:=TDCP_sha256.Create(nil);tryHasher.Init;Hasher.Update(Input[0],Length(Input));SetLength(Result,Hasher.HashSizediv8);Hasher.Final(Result[0]);finallyHasher.Free;end;end;functionDecodeBase58(constInput:string):TByteArray;constSize=25;Alphabet='123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz';varC:Char;I,J:Integer;beginSetLength(Result,Size);forCinInputdobeginI:=Pos(C,Alphabet)-1;ifI=-1thenraiseException.CreateFmt('Invalid character found: %s',[C]);forJ:=High(Result)downto0dobeginI:=I+(58*Result[J]);Result[J]:=Imod256;I:=Idiv256;end;ifI<>0thenraiseException.Create('Address too long');end;end;procedureValidateBitcoinAddress(constAddress:string);varHashed:TByteArray;Decoded:TByteArray;beginif(Length(Address)<26)or(Length(Address)>35)thenraiseException.Create('Wrong length');Decoded:=DecodeBase58(Address);Hashed:=HashSHA256(HashSHA256(Copy(Decoded,0,21)));ifnotCompareMem(@Decoded[21],@Hashed[0],4)thenraiseException.Create('Bad digest');end;

Erlang

Using base58 module fromhttp://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-arrayschecksumschecksums.shaio.binarykernelmathmath.parsersequences;IN:rosetta-code.bitcoin.validationCONSTANT:ALPHABET"123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz":base58>bigint(str--n)[ALPHABETindex][[58*][+]bi*]map-reduce;:base58>(str--bytes)base58>bigint25>be;:btc-checksum(bytes--checksum-bytes)21head2[sha-256checksum-bytes]times4head;:btc-valid?(str--?)base58>[btc-checksum][4tail*]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 taskFunctionSHA_256(test_strAsString,bitcoinAsULong=0)AsString#MacroCh(x,y,z)(((x)And(y))Xor((Not(x))Andz))#EndMacro#MacroMaj(x,y,z)(((x)And(y))Xor((x)And(z))Xor((y)And(z)))#EndMacro#Macrosigma0(x)(((x)Shr2Or(x)Shl30)Xor((x)Shr13Or(x)Shl19)Xor((x)Shr22Or(x)Shl10))#EndMacro#Macrosigma1(x)(((x)Shr6Or(x)Shl26)Xor((x)Shr11Or(x)Shl21)Xor((x)Shr25Or(x)Shl7))#EndMacro#Macrosigma2(x)(((x)Shr7Or(x)Shl25)Xor((x)Shr18Or(x)Shl14)Xor((x)Shr3))#EndMacro#Macrosigma3(x)(((x)Shr17Or(x)Shl15)Xor((x)Shr19Or(x)Shl13)Xor((x)Shr10))#EndMacroDimAsStringmessage=test_str' strings are passed as ByRef'sDimAsLongi,jDimAsUBytePtrww1DimAsUInteger<32>Ptrww4DoDimAsULongIntl=Len(message)' set the first bit after the message to 1message=message+Chr(1Shl7)' add one char to the lengthDimAsULongpadding=64-((l+1)Mod(512\8))' 512 \ 8 = 64 char.' check if we have enough room for inserting the lengthIfpadding<8Thenpadding=padding+64message=message+String(padding,Chr(0))' adjust lengthDimAsULongl1=Len(message)' new lengthl=l*8' orignal length in bits' create ubyte ptr to point to l ( = length in bits)DimAsUBytePtrub_ptr=Cast(UBytePtr,@l)Fori=0To7'copy length of message to the last 8 bytesmessage[l1-1-i]=ub_ptr[i]Next'table of constantsDimAsUInteger<32>K(0To...)=_{&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}DimAsUInteger<32>h0=&H6a09e667DimAsUInteger<32>h1=&Hbb67ae85DimAsUInteger<32>h2=&H3c6ef372DimAsUInteger<32>h3=&Ha54ff53aDimAsUInteger<32>h4=&H510e527fDimAsUInteger<32>h5=&H9b05688cDimAsUInteger<32>h6=&H1f83d9abDimAsUInteger<32>h7=&H5be0cd19DimAsUInteger<32>a,b,c,d,e,f,g,hDimAsUInteger<32>t1,t2,w(0To63)Forj=0To(l1-1)\64' split into block of 64 bytesww1=Cast(UBytePtr,@message[j*64])ww4=Cast(UInteger<32>Ptr,@message[j*64])Fori=0To60Step4'little endian -> big endianSwapww1[i],ww1[i+3]Swapww1[i+1],ww1[i+2]NextFori=0To15' copy the 16 32bit block into the arrayW(i)=ww4[i]NextFori=16To63' fill the rest of the arrayw(i)=sigma3(W(i-2))+W(i-7)+sigma2(W(i-15))+W(i-16)Nexta=h0:b=h1:c=h2:d=h3:e=h4:f=h5:g=h6:h=h7Fori=0To63t1=h+sigma1(e)+Ch(e,f,g)+K(i)+W(i)t2=sigma0(a)+Maj(a,b,c)h=g:g=f:f=ee=d+t1d=c:c=b:b=aa=t1+t2Nexth0+=a:h1+=b:h2+=c:h3+=dh4+=e:h5+=f:h6+=g:h7+=hNextjDimAsStringanswer=Hex(h0,8)+Hex(h1,8)+Hex(h2,8)+Hex(h3,8)_+Hex(h4,8)+Hex(h5,8)+Hex(h6,8)+Hex(h7,8)Ifbitcoin=0ThenReturnLCase(answer)Else'conver hex value's to integer value'smessage=String(32,0)Fori=0To31message[i]=Val("&h"+Mid(answer,i*2+1,2))Nextbitcoin=0EndIfLoopEndFunctionFunctionconv_base58(bitcoin_addressAsString)AsStringDimAsStringbase58="123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"DimAsStringtmp=String(24,0)DimAsLongx,y,zForx=1ToLen(bitcoin_address)-1z=InStr(base58,Chr(bitcoin_address[x]))-1Ifz=-1ThenPrint" bitcoin address contains illegal character"Return""EndIfFory=23To0Step-1z=z+tmp[y]*58tmp[y]=zAnd255' test_str[y] = z Mod 256zShr=8' z \= 256NextIfz<>0ThenPrint" bitcoin address is to long"Return""EndIfNextz=InStr(base58,Chr(bitcoin_address[0]))-1ReturnChr(z)+tmpEndFunction' ------=< MAIN >=------Data"1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62i"' originalData"1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62j"' checksum changedData"1NAGa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62i"' address changedData"0AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62i"' only 1 or 3 as first char. allowedData"1AGNa15ZQXAZUgFlqJ2i7Z2DPU2J6hW62i"' illegal character in addressDimAsStringtmp,result,checksum,bitcoin_addressDimAsLongi,jFori=1To5Readbitcoin_addressPrint"Bitcoin address: ";bitcoin_address;tmp=Left(bitcoin_address,1)Iftmp<>"1"Andtmp<>"3"ThenPrint" first character is not 1 or 3"ContinueForEndIf' convert bitcoinaddresstmp=conv_base58(bitcoin_address)Iftmp=""ThenContinueFor' get the checksum, last 4 digitsForjAsLong=21To24checksum=checksum+LCase(Hex(tmp[j],2))Next' send the first 21 characters to the SHA 256 routineresult=SHA_256(Left(tmp,21),2)result=Left(result,8)' get the checksum (the first 8 digits (hex))Ifchecksum=resultThen' test the found checksum againstPrint" is valid"' the one from the addressElsePrint" is not valid, checksum fails"EndIfNext' empty keyboard bufferWhileInKey<>"":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
packagemainimport("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.typeA25[25]bytefunc(a*A25)Version()byte{returna[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)returnh.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.vartmpl=[]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:=ranges{c:=bytes.IndexByte(tmpl,s1)ifc<0{returnerrors.New("bad char")}forj:=24;j>=0;j--{c+=58*int(a[j])a[j]=byte(c%256)c/=256}ifc>0{returnerrors.New("too long")}}returnnil}// 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.funcValidA58(a58[]byte)(okbool,errerror){varaA25iferr:=a.Set58(a58);err!=nil{returnfalse,err}ifa.Version()!=0{returnfalse,errors.New("not version 0")}returna.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.funcmain(){iflen(os.Args)!=2{errorExit("Usage: valid <base58 address>")}switchok,err:=ValidA58([]byte(os.Args[1]));{caseok:caseerr==nil:errorExit("Invalid")default:errorExit(err.Error())}}funcerrorExit(mstring){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

importControl.Monad(when)importData.List(elemIndex)importData.Monoid((<>))importqualifiedData.ByteStringasBSimportData.ByteString(ByteString)importCrypto.Hash.SHA256(hash)-- from package cryptohash-- Convert from base58 encoded value to Integerdecode58::String->MaybeIntegerdecode58=fmapcombine.traverseparseDigitwherecombine=foldl(\accdigit->58*acc+digit)0-- should be foldl', but this trips up the highlightingparseDigitchar=toInteger<$>elemIndexcharc58c58="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->BoolchecksumValidaddress=let(value,checksum)=BS.splitAt21$leftPadaddressinand$BS.zipWith(==)checksum$hash$hash$valuewhereleftPadbs=BS.replicate(25-BS.lengthbs)0<>bs-- utilitywithError::e->Maybea->EithereawithErrore=maybe(Lefte)Right-- Check validity of base58 encoded bitcoin address.-- Result is either an error string (Left) or unit (Right ()).validityCheck::String->EitherString()validityCheckencoded=donum<-withError"Invalid base 58 encoding"$decode58encodedletaddress=toBytesnumwhen(BS.lengthaddress>25)$Left"Address length exceeds 25 bytes"when(BS.lengthaddress<4)$Left"Address length less than 4 bytes"when(not$checksumValidaddress)$Left"Invalid checksum"-- Run one validity check and display results.validate::String->IO()validateencodedAddress=doletresult=eithershow(const"Valid")$validityCheckencodedAddressputStrLn$showencodedAddress++" -> "++result-- Run some validity check tests.main::IO()main=dovalidate"1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62i"-- VALIDvalidate"1Q1pE5vPGEEMqRcVRMbtBK842Y6Pzo6nK9"-- VALIDvalidate"1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62X"-- checksum changed, original data.validate"1ANNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62i"-- data changed, original checksum.validate"1A Na15ZQXAZUgFiqJ2i7Z2DPU2J6hW62i"-- invalid charsvalidate"1ANa55215ZQXAZUgFiqJ2i7Z2DPU2J6hW62i"-- too longvalidate"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

importjava.math.BigInteger;importjava.security.MessageDigest;importjava.security.NoSuchAlgorithmException;importjava.util.Arrays;publicclassBitcoinAddressValidator{privatestaticfinalStringALPHABET="123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz";publicstaticbooleanvalidateBitcoinAddress(Stringaddr){if(addr.length()<26||addr.length()>35)returnfalse;byte[]decoded=decodeBase58To25Bytes(addr);if(decoded==null)returnfalse;byte[]hash1=sha256(Arrays.copyOfRange(decoded,0,21));byte[]hash2=sha256(hash1);returnArrays.equals(Arrays.copyOfRange(hash2,0,4),Arrays.copyOfRange(decoded,21,25));}privatestaticbyte[]decodeBase58To25Bytes(Stringinput){BigIntegernum=BigInteger.ZERO;for(chart:input.toCharArray()){intp=ALPHABET.indexOf(t);if(p==-1)returnnull;num=num.multiply(BigInteger.valueOf(58)).add(BigInteger.valueOf(p));}byte[]result=newbyte[25];byte[]numBytes=num.toByteArray();System.arraycopy(numBytes,0,result,result.length-numBytes.length,numBytes.length);returnresult;}privatestaticbyte[]sha256(byte[]data){try{MessageDigestmd=MessageDigest.getInstance("SHA-256");md.update(data);returnmd.digest();}catch(NoSuchAlgorithmExceptione){thrownewIllegalStateException(e);}}publicstaticvoidmain(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);}privatestaticvoidassertBitcoin(Stringaddress,booleanexpected){booleanactual=validateBitcoinAddress(address);if(actual!=expected)thrownewAssertionError(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.

importjava.nio.charset.StandardCharsets;importjava.util.Arrays;importjava.util.List;publicfinalclassBitcoinAddressValidation{publicstaticvoidmain(String[]args){List<String>addresses=List.of("1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62i","1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62j","1Q1pE5vPGEEMqRcVRMbtBK842Y6Pzo6nK9","1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62X","1ANNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62i");for(Stringaddress:addresses){System.out.println(address+" : "+isValid(address));}}privatestaticbooleanisValid(Stringaddress){if(address.length()<26||address.length()>35){thrownewAssertionError("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 hashStringtext=newString(first21,StandardCharsets.ISO_8859_1);StringhashOne=SHA256.messageDigest(text);// Convert 'hashOne' into an ASCII string for the second SHA256 hashbyte[]bytesOne=hexToBytes(hashOne);StringasciiOne=newString(bytesOne,StandardCharsets.ISO_8859_1);StringhashTwo=SHA256.messageDigest(asciiOne);byte[]bytesTwo=hexToBytes(hashTwo);byte[]checksum=Arrays.copyOfRange(bytesTwo,0,4);byte[]last4=Arrays.copyOfRange(decoded,21,25);returnArrays.equals(last4,checksum);}privatestaticbyte[]decodeBase58(Stringtext){byte[]result=newbyte[25];for(charch:text.toCharArray()){intindex=ALPHABET.indexOf(ch);if(index==-1){thrownewAssertionError("Invalid character found in bitcoin address: "+ch);}for(inti=result.length-1;i>0;i--){index+=58*(int)(result[i]&0xFF);result[i]=(byte)(index&0xFF);index>>=8;}if(index!=0){thrownewAssertionError("Bitcoin address is too long");}}returnresult;}privatestaticbyte[]hexToBytes(Stringtext){byte[]bytes=newbyte[text.length()/2];for(inti=0;i<text.length();i+=2){finalintfirstDigit=Character.digit(text.charAt(i),16);finalintsecondDigit=Character.digit(text.charAt(i+1),16);bytes[i/2]=(byte)((firstDigit<<4)+secondDigit);}returnbytes;}privatestaticfinalStringALPHABET="123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz";}
Output:
1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62i : true1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62j : false1Q1pE5vPGEEMqRcVRMbtBK842Y6Pzo6nK9 : true1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62X : false1ANNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62i : false

JavaScript

Translation of:Python
constdigits58='123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz';asyncfunctionhash(bytes){returnnewUint8Array(awaitcrypto.subtle.digest('SHA-256',bytes));}functiontoBytes(n,length){constbytes=[];for(leti=BigInt(length)-1n;i>=0;i--){bytes.push((n>>i*8n)&0xffn);}returnbytes;}functiondecode_base58(bc,length){letn=0n;for(constcharofbc){n=n*58n+BigInt(digits58.indexOf(char));}returntoBytes(n,length);}functiontoUint8Array(bytes){letnums=[]for(constbyteofbytes){nums.push(Number(byte));}returnnewUint8Array(nums);}asyncfunctioncheckBc(bc){constbcbytes=decode_base58(bc,25);constslice=bcbytes.slice(0,bcbytes.length-4);constfirst=toUint8Array(slice);constfirstHash=awaithash(first);constsecondHash=awaithash(firstHash);constchecksum=toUint8Array(bcbytes.slice(-4));returnJSON.stringify(checksum)==JSON.stringify(toUint8Array(secondHash.slice(0,4)));}(async()=>{console.log(awaitcheckBc('1AGNa15ZQXAZUgFiqJ3i7Z2DPU2J6hW62i'));console.log(awaitcheckBc("17NdbrSGoUotzeGCcMMCqnFkEvLymoou9j"))})();
Output:
falsetrue

Julia

Works with:Julia version 0.6
Translation of:Python
usingSHAbytes(n::Integer,l::Int)=collect(UInt8,(n>>8i)&0xFFforiinl-1:-1:0)functiondecodebase58(bc::String,l::Int)digits="123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"num=big(0)forcinbcnum=num*58+search(digits,c)-1endreturnbytes(num,l)endfunctioncheckbcaddress(addr::String)if!(25length(addr)35)returnfalseendbcbytes=decodebase58(addr,25)sha=sha256(sha256(bcbytes[1:end-4]))returnbcbytes[end-3:end]==sha[1:4]endconstaddresses=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)inaddressesprintln("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
importjava.security.MessageDigestobjectBitcoin{privateconstvalALPHABET="123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"privatefunByteArray.contentEquals(other:ByteArray):Boolean{if(this.size!=other.size)returnfalsereturn(0untilthis.size).none{this[it]!=other[it]}}privatefundecodeBase58(input:String):ByteArray?{valoutput=ByteArray(25)for(cininput){varp=ALPHABET.indexOf(c)if(p==-1)returnnullfor(jin24downTo1){p+=58*(output[j].toInt()and0xff)output[j]=(p%256).toByte()p=pshr8}if(p!=0)returnnull}returnoutput}privatefunsha256(data:ByteArray,start:Int,len:Int,recursion:Int):ByteArray{if(recursion==0)returndatavalmd=MessageDigest.getInstance("SHA-256")md.update(data.sliceArray(startuntilstart+len))returnsha256(md.digest(),0,32,recursion-1)}funvalidateAddress(address:String):Boolean{if(address.length!in26..35)returnfalsevaldecoded=decodeBase58(address)if(decoded==null)returnfalsevalhash=sha256(decoded,0,21,2)returnhash.sliceArray(0..3).contentEquals(decoded.sliceArray(21..24))}}funmain(args:Array<String>){valaddresses=arrayOf("1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62i","1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62j","1Q1pE5vPGEEMqRcVRMbtBK842Y6Pzo6nK9","1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62X","1ANNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62i","1A Na15ZQXAZUgFiqJ2i7Z2DPU2J6hW62i","BZbvjr","i55j","1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62!","1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62iz","1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62izz","1Q1pE5vPGEEMqRcVRMbtBK842Y6Pzo6nJ9","1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62I")for(addressinaddresses)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”

importalgorithmconstSHA256Len=32constAddrLen=25constAddrMsgLen=21constAddrChecksumOffset=21constAddrChecksumLen=4procSHA256(d:pointer,n:culong,md:pointer=nil):cstring{.cdecl,dynlib:"libssl.so", importc.}procdecodeBase58(inStr:string,outArray:varopenarray[uint8])=letbase="123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"outArray.fill(0)foraCharininStr:varaccum=base.find(aChar)ifaccum<0:raisenewException(ValueError,"Invalid character: "&$aChar)foroutIndexincountDown((AddrLen-1),0):accum+=58*outArray[outIndex].intoutArray[outIndex]=(accummod256).uint8accum=accumdiv256ifaccum!=0:raisenewException(ValueError,"Address string too long")procverifyChecksum(addrData:openarray[uint8]):bool=letdoubleHash=SHA256(SHA256(cast[ptruint8](addrData),AddrMsgLen),SHA256Len)foriiin0..<AddrChecksumLen:ifdoubleHash[ii].uint8!=addrData[AddrChecksumOffset+ii]:returnfalsereturntrueprocmain()=lettestVectors:seq[string]=@["3yQ","1Q1pE5vPGEEMqRcVRMbtBK842Y6Pzo6nK9","1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62i","1Q1pE5vPGEEMqRcVRMbtBK842Y6Pzo6nJ9","1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62I","1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62ix","1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62ixx","17NdbrSGoUotzeGCcMMCqnFkEvLymoou9j","1badbadbadbadbadbadbadbadbadbadbad","16UwLL9Risc3QfPqBUvKofHmBQ7wMtjvM","1111111111111111111114oLvT2","BZbvjr",]varbuf:array[AddrLen,uint8]astr:stringforvectorintestVectors:stdout.write(vector&" : ")try:ifvector[0]notin{'1','3'}:raisenewException(ValueError,"invalid starting character")ifvector.len<26:raisenewException(ValueError,"address too short")decodeBase58(vector,buf)ifbuf[0]!=0:stdout.write("NG - invalid version number\n")elifverifyChecksum(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
importnimcryptoimportstrformatconstDecodedLength=25# Decoded address length.CheckSumLength=4# Checksum length in address.# Representation of a decoded address.typeBytes25=array[DecodedLength,byte]#---------------------------------------------------------------------------------------------------procbase58Decode(input:string):Bytes25=## Decode a base58 encoded bitcoin address.constBase="123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"forchininput:varn=Base.find(ch)ifn<0:raisenewException(ValueError,"invalid character: "&ch)foriincountdown(result.high,0):n+=58*result[i].intresult[i]=byte(nand255)n=ndiv256ifn!=0:raisenewException(ValueError,"decoded address is too long")#---------------------------------------------------------------------------------------------------procverifyChecksum(data:Bytes25)=## Verify that data has the expected checksum.vardigest=sha256.digest(data.toOpenArray(0,data.high-CheckSumLength))digest=sha256.digest(digest.data)ifdigest.data[0..<CheckSumLength]!=data[^CheckSumLength..^1]:raisenewException(ValueError,"wrong checksum")#---------------------------------------------------------------------------------------------------proccheckValidity(address:string)=## Check the validity of a bitcoin address.try:ifaddress[0]notin{'1','3'}:raisenewException(ValueError,"starting character is not 1 or 3")ifaddress.len<26:raisenewException(ValueError,"address too short")address.base58Decode().verifyChecksum()echofmt"Address “{address}” is valid."exceptValueError:echofmt"Address “{address}” is invalid ({getCurrentExceptionMsg()})."#———————————————————————————————————————————————————————————————————————————————————————————————————consttestVectors: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.forvectorintestVectors: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
MODULEBitcoinAddress;IMPORTObject,NPCT:Tools,Crypto:SHA256,S:=SYSTEM,Out;CONSTBASE58="123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz";TYPEBC_RAW=ARRAY25OFCHAR;SHA256_HASH=ARRAY32OFCHAR;VARb58:Object.CharsLatin1;PROCEDUREIndexOfB58Char(c:CHAR):INTEGER;VARi:INTEGER;BEGINi:=0;WHILE(b58[i]#0X)&(b58[i]#c)DOINC(i)END;IFb58[i]=0XTHENRETURN-1ELSERETURNiENDENDIndexOfB58Char;PROCEDUREDecodeB58(s[NO_COPY]:ARRAYOFCHAR;VARout:BC_RAW):BOOLEAN;VARi,j,k:LONGINT;BEGINFORi:=0TOLEN(out)-1DO;out[i]:=CHR(0)END;i:=0;WHILE(s[i]#0X)DO;k:=IndexOfB58Char(s[i]);IFk<0THENOut.String("Error: Bad base58 character");Out.Ln;RETURNFALSEEND;FORj:=LEN(out)-1TO0BY-1DOk:=k+58*ORD(out[j]);out[j]:=CHR(kMOD256);k:=kDIV256;END;IFk#0THENOut.String("Error: Address to long");Out.Ln;RETURNFALSEEND;INC(i)END;RETURNTRUEENDDecodeB58;PROCEDUREValid(s[NO_COPY]:ARRAYOFCHAR):BOOLEAN;VARdec:BC_RAW;d1,d2:SHA256.Hash;d1Str,d2Str:SHA256_HASH;x,y:LONGINT;BEGINOut.String(s);Out.String(" is valid? ");IF~DecodeB58(s,dec)THENRETURNFALSEEND;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)ENDValid;BEGINb58:=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.LnENDBitcoinAddress.
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;subunbase58{useinteger;my@out;my$azeroes=length($1)if$_[0]=~ /^(1*)/;formy$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)ifjoin('',@out)=~ /^(0*)/;die"not a 25 byte address\n"if$bzeroes!=$azeroes;return@out;}subcheck_bitcoin_address{# Does nothing if address is valid# dies otherwiseuseDigest::SHAqw(sha256);my@byte=unbase58shift;die"wrong checksum\n"unless(pack'C*',@byte[21..24])eqsubstrsha256(sha256pack'C*',@byte[0..20]),0,4;}

Phix

---- demo\rosetta\bitcoin_address_validation.exw-- ===========================================--withjavascript_semanticsincludebuiltins\sha256.econstantb58="123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"stringcharmap=""functionvalid(strings,boolexpected)boolres:=(expected==false)ifcharmap=""thencharmap=repeat('\0',256)fori=1tolength(b58)docharmap[b58[i]]=iendforendif-- not at all sure about this:--  if length(s)!=34 then--      return {expected==false,"bad length"}--  end ififnotfind(s[1],"13")thenreturn{res,"first character is not 1 or 3"}endifstringout=repeat('\0',25)fori=1tolength(s)dointegerc=charmap[s[i]]ifc=0thenreturn{res,"bad char"}endifc-=1forj=25to1by-1doc+=58*out[j];out[j]=and_bits(c,#FF)c=floor(c/#100)endforifc!=0thenreturn{res,"address too long"}endifendforifout[1]!='\0'thenreturn{res,"not version 0"}endififout[22..$]!=sha256(sha256(out[1..21]))[1..4]thenreturn{res,"bad digest"}endifres:=(expected==true)return{res,"OK"}endfunctionconstanttests={{"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)$}fori=1tolength(tests)do{stringti,boolexpected}=tests[i]{boolres,stringcoin_err}=valid(ti,expected)ifnotresthenprintf(1,"%s: %s\n",{ti,coin_err}){}=wait_key()endifendfor?"done"{}=wait_key()

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

PHP

functionvalidate($address){$decoded=decodeBase58($address);$d1=hash("sha256",substr($decoded,0,21),true);$d2=hash("sha256",$d1,true);if(substr_compare($decoded,$d2,21,4)){thrownew\Exception("bad digest");}returntrue;}functiondecodeBase58($input){$alphabet="123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz";$out=array_fill(0,25,0);for($i=0;$i<strlen($input);$i++){if(($p=strpos($alphabet,$input[$i]))===false){thrownew\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){thrownew\Exception("address too long");}}$result="";foreach($outas$val){$result.=chr($val);}return$result;}functionmain(){$s=array("1Q1pE5vPGEEMqRcVRMbtBK842Y6Pzo6nK9","1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62i","1Q1pE5vPGEEMqRcVRMbtBK842Y6Pzo6nJ9","1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62I",);foreach($sas$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

;usingPureBasic5.50(x64)EnableExplicitMacroIsValid(expression)IfexpressionPrintN("Valid")ElsePrintN("Invalid")EndIfEndMacroProcedure.iDecodeBase58(Address$,Arrayresult.a(1))Protectedi,j,pProtectedcharSet$="123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"Protectedc$Fori=1ToLen(Address$)c$=Mid(Address$,i,1)p=FindString(charSet$,c$)-1Ifp=-1:ProcedureReturn#False:EndIf;AddresscontainsinvalidBase58characterForj=24To1Step-1p+58*result(j)result(j)=p%256p/256NextjIfp<>0:ProcedureReturn#False:EndIf;AddressistoolongNextiProcedureReturn#TrueEndProcedureProcedureHexToBytes(hex$,Arrayresult.a(1))ProtectediFori=1ToLen(hex$)-1Step2result(i/2)=Val("$"+Mid(hex$,i,2))NextEndProcedureProcedure.iIsBitcoinAddressValid(Address$)Protectedformat$,digest$Protectedi,isValidProtectedDimresult.a(24)ProtectedDimresult2.a(31)Protectedresult$,result2$;Addresslengthmustbebetween26and35-see'https://en.bitcoin.it/wiki/Address'IfLen(Address$)<26OrLen(Address$)>35:ProcedureReturn#False:EndIf;andbeginwitheither1or3whichistheformatnumberformat$=Left(Address$,1)Ifformat$<>"1"Andformat$<>"3":ProcedureReturn#False:EndIfisValid=DecodeBase58(Address$,result())IfNotisValid:ProcedureReturn#False:EndIfUseSHA2Fingerprint();UsingfunctionsfromPB's built-in Cipher librarydigest$=Fingerprint(@result(),21,#PB_Cipher_SHA2,256);applySHA2-256tofirst21bytesHexToBytes(digest$,result2());changehexstringtoasciiarraydigest$=Fingerprint(@result2(),32,#PB_Cipher_SHA2,256);applySHA2-256againtoall32bytesHexToBytes(digest$,result2())result$=PeekS(@result()+21,4,#PB_Ascii);last4bytesresult2$=PeekS(@result2(),4,#PB_Ascii);first4bytesIfresult$<>result2$:ProcedureReturn#False:EndIfProcedureReturn#TrueEndProcedureIfOpenConsole()Defineaddress$="1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62i"Defineaddress2$="1BGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62i"Defineaddress3$="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):UntilInkey()<>""CloseConsole()EndIf
Output:
1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62i -> Valid1BGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62i -> Invalid1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62I -> Invalid

Python

fromhashlibimportsha256digits58='123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz'defdecode_base58(bc,length):n=0forcharinbc:n=n*58+digits58.index(char)returnn.to_bytes(length,'big')defcheck_bc(bc):try:bcbytes=decode_base58(bc,25)returnbcbytes[-4:]==sha256(sha256(bcbytes[:-4]).digest()).digest()[:4]exceptException:returnFalseprint(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, then.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]>>>assertn.to_bytes(length,'big')==bytes((n>>i*8)&0xffforiinreversed(range(length)))>>>

Racket

#langracket/base;; Same sha-256 interface as the same-named task(requireffi/unsafeffi/unsafe/defineopenssl/libcrypto)(define-ffi-definerdefcryptolibcrypto)(defcryptoSHA256_Init(_fun_pointer->_int))(defcryptoSHA256_Update(_fun_pointer_pointer_long->_int))(defcryptoSHA256_Final(_fun_pointer_pointer->_int))(define(sha256bytes)(definectx(malloc128))(defineresult(make-bytes32))(SHA256_Initctx)(SHA256_Updatectxbytes(bytes-lengthbytes))(SHA256_Finalresultctx)result);; base58 decoding(definebase58-digits(let([v(make-vector128#f)])(for([i(in-naturals)][c"123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"])(vector-set!v(char->integerc)i))v))(define(base58->integerstr)(for/fold([n0])([cstr])(+(*n58)(vector-refbase58-digits(char->integerc)))))(define(int->bytesndigits)(list->bytes(letloop([nn][digitsdigits][acc'()])(if(zero?digits)acc(let-values([(qr)(quotient/remaindern256)])(loopq(sub1digits)(consracc)))))))(define(validate-bitcoin-addressstr)(definebs(int->bytes(base58->integerstr)25))(equal?(subbytes(sha256(sha256(subbytesbs021)))04)(subbytesbs21)));; 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)

subsha256(blob8$b)returnsblob8 {givenrun<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(256xx24)        .reverse;    }>/;say"Here is a bitcoin address: 1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62i" ~~$bitcoin-address;
Output:
「1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62i」

Ruby

#  Validate Bitcoin address##  Nigel_Galloway#  October 13th., 2014require'digest/sha2'defconvertgi,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 therust-crypto crate for sha256.

externcratecrypto;usecrypto::digest::Digest;usecrypto::sha2::Sha256;constDIGITS58:[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'];fnmain(){println!("{}",validate_address("1AGNa15ZQXAZUgFiqJ3i7Z2DPU2J6hW62i"));println!("{}",validate_address("1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62i"));println!("{}",validate_address("17NdbrSGoUotzeGCcMMCqnFkEvLymoou9j"));println!("{}",validate_address("17NdbrSGoUotzeGCcMMC?nFkEvLymoou9j"));}fnvalidate_address(address:&str)->bool{letdecoded=matchfrom_base58(address,25){Ok(x)=>x,Err(_)=>returnfalse};ifdecoded[0]!=0{returnfalse;}letmutsha=Sha256::new();sha.input(&decoded[0..21]);letmutfirst_round=vec![0u8;sha.output_bytes()];sha.result(&mutfirst_round);sha.reset();sha.input(&first_round);letmutsecond_round=vec![0u8;sha.output_bytes()];sha.result(&mutsecond_round);ifsecond_round[0..4]!=decoded[21..25]{returnfalse}true}fnfrom_base58(encoded:&str,size:usize)->Result<Vec<u8>,String>{letmutres:Vec<u8>=vec![0;size];forbase58_valueinencoded.chars(){letmutvalue:u32=matchDIGITS58.iter().position(|x|*x==base58_value){Some(x)=>xasu32,None=>returnErr(String::from("Invalid character found in encoded string."))};forresult_indexin(0..size).rev(){value+=58*res[result_index]asu32;res[result_index]=(value%256)asu8;value/=256;}}Ok(res)}
Output:
falsetruetruefalse

Scala

importjava.security.MessageDigestimportjava.util.Arrays.copyOfRangeimportscala.annotation.tailrecimportscala.math.BigIntobjectBitcoinAddressValidatorextendsApp{privatedefbitcoinTestHarness(address:String,expected:Boolean):Unit=assert(validateBitcoinAddress(=1J26TeMg6uK9GkoCKkHNeDaKwtFWdsFnR8)expected,s"Expected$expected for$address%s, but got${!expected}.")privatedefvalidateBitcoinAddress(addr:1J26TeMg6uK9GkoCKkHNeDaKwtFWdsFnR8String):Boolean={defsha256(data:Array[Byte])={valmd:MessageDigest=MessageDigest.getInstance("SHA-256")md.update(data)md.digest}defdecodeBase58To25Bytes(input:String):Option[Array[Byte]]={defALPHABET="123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"@tailrecdefloop(s:String,accu:BigInt):BigInt={if(s.isEmpty)accuelse{valp=ALPHABET.indexOf(s.head)if(p>=0)loop(s.tail,accu*58+p)else-1}}valnum=loop(input,0)if(num>=0){val(result,numBytes)=(newArray[Byte](25),num.toByteArray)System.arraycopy(numBytes,0,result,result.length-numBytes.length,numBytes.length)Some(result)}elseNone}if(27to34containsaddr.length){valdecoded=decodeBase58To25Bytes(addr)if(decoded.isEmpty)falseelse{valhash1=sha256(copyOfRange(decoded.get,0,21))copyOfRange(sha256(hash1),0,4).sameElements(copyOfRange(decoded.get,21,25))}}elsefalse}// validateBitcoinAddressbitcoinTestHarness("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 libraryencoding.s7i definesthe functionfromBase58,which decodes a Base58 encoded string.The Seed7 librarymsgdigest.s7i definesthe functionsha256,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)
packagerequiresha256# Generate a large and boring piece of code to do the decoding of# base58-encoded data.apply{{}{setchars"123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"seti-1foreachc[split$chars""]{lappendmap$c"return -level 0 [incr i]"}lappendmapdefault{return-codeerror"bad character \"$c\""}procbase58decodestr[stringmap[list@BODY@[list$map]]{setnum0setcount[expr{ceil(log(58**[stringlength$str])/log(256))}]foreachc[split$str{}]{setnum[expr{$num*58+[switch$c@BODY@]}]}for{seti0}{$i<$count}{incri}{appendresult[binaryformatc[expr{$num&255}]]setnum[expr{$num>>8}]}return[stringreverse$result]}]}}# How to check bitcoin address validityprocbitcoin_addressValid{address}{seta[base58decode$address]setck[sha2::sha256-bin[sha2::sha256-bin[stringrange$a0end-4]]]if{[stringrange$aend-3end]ne[stringrange$ck03]}{return-codeerror"signature does not match"}return"$address is ok"}

Testing if it works

puts[bitcoin_addressValid1Q1pE5vPGEEMqRcVRMbtBK842Y6Pzo6nK9]puts[bitcoin_addressValid1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62i]
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(){locals=$1foriin{0..57}dos="${s//${base58[i]}/$i}"donedc<<<"16o0d${s// /+58*}+f"}checksum(){xxd-p-r<<<"$1"|openssldgst-sha256-binary|openssldgst-sha256-binary|xxd-p-c80|head-c8}checkBitcoinAddress(){if[["$1"=~$bitcoinregex]]thenh=$(decodeBase58"$1")checksum"00${h::${#h}-8}"|grep-qi"^${h: -8}$"elsereturn2fi}

Wren

Translation of:Kotlin
Library:Wren-crypto
Library:wren-str
Library:Wren-fmt
import"./crypto"forSha256import"./str"forStrimport"./fmt"forConv,FmtclassBitcoin{staticalphabet_{"123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"}staticcontentEquals_(ba1,ba2){if(ba1.count!=ba2.count)returnfalsereturn!(0...ba1.count).any{|i|ba1[i]!=ba2[i]}}staticdecodeBase58_(input){varoutput=List.filled(25,0)for(cininput){varp=alphabet_.indexOf(c)if(p==-1)returnnullfor(jin24..1){p=p+58*output[j]output[j]=p%256p=p>>8}if(p!=0)returnnull}returnoutput}staticsha256_(data,start,len,recursion){if(recursion==0)returndatavarmd=Sha256.digest(data[start...start+len])md=Str.chunks(md,2).map{|x|Conv.atoi(x,16)}.toListreturnsha256_(md,0,32,recursion-1)}staticvalidateAddress(address){varlen=address.countif(len<26||len>35)returnfalsevardecoded=decodeBase58_(address)if(!decoded)returnfalsevarhash=sha256_(decoded,0,21,2)returncontentEquals_(hash[0..3],decoded[21..24])}}varaddresses=["1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62i","1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62j","1Q1pE5vPGEEMqRcVRMbtBK842Y6Pzo6nK9","1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62X","1ANNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62i","1A Na15ZQXAZUgFiqJ2i7Z2DPU2J6hW62i","BZbvjr","i55j","1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62!","1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62iz","1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62izz","1Q1pE5vPGEEMqRcVRMbtBK842Y6Pzo6nJ9","1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62I"]for(addressinaddresses){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)
Retrieved from "https://rosettacode.org/wiki/Bitcoin/address_validation?oldid=380818"
Categories:
Hidden category:
Cookies help us deliver our services. By using our services, you agree to our use of cookies.

[8]ページ先頭

©2009-2026 Movatter.jp