user
|  |
| --- |
| **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 |

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.
assistant
(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｣
```