Rebol3 Code Examplex
Bitcoin address validation
Verify the correctness of Bitcoin addresses using checksum rules.
Rebol [
title: "Rosetta code: Bitcoin address validation"
file: %Bitcoin_address_validation.r3
url: https://rosettacode.org/wiki/Bitcoin/address_validation
]
decode-base58: function [
"Decodes a Base58-encoded string into a 25-byte binary value."
input [string!]
][
size: 25
alphabet: "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"
result: make binary! size
append/dup result 0 size
foreach c input [
;; Find character position (1-based). Returns none if not in alphabet.
i: index? find/case alphabet c
unless i [return none] ;; Invalid character found
i: i - 1 ;; Convert to 0-based index
;; Treat result as a base-256 big-endian number and multiply by 58,
;; adding the new digit. Work right-to-left to propagate carries.
for j size 1 -1 [
i: i + (58 * to integer! result/:j)
result/:j: i % 256 ;; Store the low byte
i: to integer! (i / 256) ;; Carry the remainder leftward
]
if i != 0 [return none] ;; Address too long
]
result
]
valid-bitcoin?: function [
"Returns true if a Bitcoin address has a valid checksum, false otherwise."
address [string!]
][
did all [
bin: decode-base58 address ;; Decode to 25 raw bytes (21 payload + 4 checksum)
sum: checksum/part bin 'sha256 21 ;; SHA256 over the first 21 bytes (payload only)
sum: checksum sum 'sha256 ;; SHA256 again (double-hash)
equal? (skip bin 21) (copy/part sum 4) ;; Compare last 4 bytes of address to first 4 of hash
]
]
foreach address [
"1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62i" ; VALID
"1Q1pE5vPGEEMqRcVRMbtBK842Y6Pzo6nK9" ; VALID
"1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62X" ; checksum changed, original data.
"1ANNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62i" ; data changed, original checksum.
"1A Na15ZQXAZUgFiqJ2i7Z2DPU2J6hW62i" ; invalid chars
][
print [address 'is pick ["valid." "invalid!"] valid-bitcoin? address]
]