Bitcoin/address validation: Difference between revisions

Added a test on the first address character in order to detect invalid addresses such as "BZbvjr".
(Rename Perl 6 -> Raku, alphabetize, minor clean-up)
(Added a test on the first address character in order to detect invalid addresses such as "BZbvjr".)
Line 1,312:
 
=={{header|Nim}}==
A test on first digit character has been added to detect wrong addresses such as "BZbvjr".
 
===Using “libssl”===
Requires libssl library to perform SHA256. Build with -d:ssl flag.
 
<lang nim>import algorithm
Line 1,377 ⟶ 1,378:
stdout.write(vector & " : ")
try:
if vector[0] notin {'1', '3'}:
raise newException(ValueError, "invalid starting character")
decodeBase58(vector, buf)
 
Line 1,405 ⟶ 1,408:
16UwLL9Risc3QfPqBUvKofHmBQ7wMtjvM : OK
1111111111111111111114oLvT2 : OK
BZbvjr : OKNG - invalid starting character
</pre>
 
===Using “nimcrypto”===
Note: The last two test addresses have valid checksums and conform to the specified address constraints.
<lang Nim>import nimcrypto
import strformat
 
const
 
DecodedLength = 25 # Decoded address length.
CheckSumLength = 4 # Checksum length in address.
 
# Representation of a decoded address.
type Bytes25 = array[DecodedLength, byte]
 
 
#---------------------------------------------------------------------------------------------------
 
proc base58Decode(input: string): Bytes25 =
## Decode a base58 encoded bitcoin address.
 
const Base = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"
 
for ch in input:
 
var n = Base.find(ch)
if n < 0:
raise newException(ValueError, "invalid character: " & ch)
 
for i in countdown(result.high, 0):
n += 58 * result[i].int
result[i] = byte(n and 255)
n = n div 256
 
if n != 0:
raise newException(ValueError, "decoded address is too long")
 
#---------------------------------------------------------------------------------------------------
 
proc verifyChecksum(data: Bytes25) =
## Verify that data has the expected checksum.
 
var digest = sha256.digest(data.toOpenArray(0, data.high - CheckSumLength))
digest = sha256.digest(digest.data)
if digest.data[0..<CheckSumLength] != data[^CheckSumLength..^1]:
raise newException(ValueError, "wrong checksum")
 
#---------------------------------------------------------------------------------------------------
 
proc checkValidity(address: string) =
## Check the validity of a bitcoin address.
 
try:
if address[0] notin {'1', '3'}:
raise newException(ValueError, "starting character is not 1 or 3")
echo base58Decode(address)
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()</lang>
 
{{out}}
<pre>Address “3yQ” is invalid (wrong checksum).
Address “1Q1pE5vPGEEMqRcVRMbtBK842Y6Pzo6nK9” is valid.
Address “1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62i” is valid.
Address “1Q1pE5vPGEEMqRcVRMbtBK842Y6Pzo6nJ9” is invalid (wrong checksum).
Address “1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62I” is invalid (invalid character: I).
Address “1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62ix” is invalid (wrong checksum).
Address “1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62ixx” is invalid (decoded address is too long).
Address “17NdbrSGoUotzeGCcMMCqnFkEvLymoou9j” is valid.
Address “1badbadbadbadbadbadbadbadbadbadbad” is invalid (wrong checksum).
Address “16UwLL9Risc3QfPqBUvKofHmBQ7wMtjvM” is valid.
Address “1111111111111111111114oLvT2” is valid.
Address “BZbvjr” is invalid (starting character is not 1 or 3).</pre>
 
=={{header|Oberon-2}}==
Anonymous user