Bitcoin/public point to address: Difference between revisions

Crate ripemd160 is deprecated - Update
(Crate ripemd160 is deprecated - Update)
 
(39 intermediate revisions by 20 users not shown)
Line 22:
 
''Extra credit:'' add a verification procedure about the public point, making sure it belongs to the secp256k1 elliptic curve
 
=={{header|C}}==
<langsyntaxhighlight lang="c">#include <stdio.h>
#include <string.h>
#include <ctype.h>
Line 98 ⟶ 97:
0));
return 0;
}</langsyntaxhighlight>
=={{header|Common Lisp}}==
{{libheader|Quicklisp}}
{{libheader|Ironclad}}
<syntaxhighlight lang="lisp">
;;;; This is a revised version, inspired by a throwaway script originally
;;;; published at http://deedbot.org/bundle-381528.txt by the same Adlai.
 
;;; package definition
(cl:defpackage :bitcoin-address-encoder
(:use :cl . #.(ql:quickload :ironclad))
(:shadowing-import-from :ironclad #:null)
(:import-from :ironclad #:simple-octet-vector))
(cl:in-package :bitcoin-address-encoder)
 
;;; secp256k1, as shown concisely in https://en.bitcoin.it/wiki/Secp256k1
;;; and officially defined by the SECG at http://www.secg.org/sec2-v2.pdf
(macrolet ((define-constants (&rest constants)
`(progn ,@(loop for (name value) on constants by #'cddr
collect `(defconstant ,name ,value)))))
(define-constants
;; these constants are only necessary for computing public keys
xg #x79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798
yg #x483ADA7726A3C4655DA4FBFC0E1108A8FD17B448A68554199C47D08FFB10D4B8
ng #xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141
 
;; this constant is necessary both for computation and validation
p #.`(- ,@(mapcar (lambda (n) (ash 1 n)) '(256 32 9 8 7 6 4 0)))
))
 
;;; operations within the field of positive integers modulo the prime p
(macrolet ((define-operations (&rest pairs)
`(progn ,@(loop for (op name) on pairs by #'cddr collect
`(defun ,name (x y) (mod (,op x y) p))))))
(define-operations + add - sub * mul))
 
;;; modular exponentiation by squaring, still in the same field
;;; THIS IS A VARIABLE-TIME ALGORITHM, BLIND REUSE IS INSECURE!
(defun pow (x n &optional (x^n 1)) ; (declare (notinline pow))
(do ((x x (mul x x)) (n n (ash n -1))) ((zerop n) x^n)
(when (oddp n) (setf x^n (mul x^n x)))))
 
;;; extended euclidean algorithm, still in the same field
;;; THIS IS A VARIABLE-TIME ALGORITHM, BLIND REUSE IS INSECURE!
(defun eea (a b &optional (x 0) (prevx 1) (y 1) (prevy 0))
(if (zerop b) (values prevx prevy)
(multiple-value-bind (q r) (floor a b)
(eea b r (sub prevx (mul q x)) x (sub prevy (mul q y)) y))))
 
;;; multiplicative inverse in the field of integers modulo the prime p
(defun inv (x) (nth-value 1 (eea p (mod x p))))
 
;;; operation, in the group of rational points over elliptic curve "SECP256K1"
;;; THIS IS A VARIABLE-TIME ALGORITHM, BLIND REUSE IS INSECURE!
(defun addp (xp yp xq yq) ; https://hyperelliptic.org/EFD/g1p/auto-shortw.html
(if (and xp yp xq yq) ; base case: avoid The Pothole At The End Of The Algebra
(macrolet ((ua (s r) `(let* ((s ,s) (x (sub (mul s s) ,r)))
(values x (sub 0 (add yp (mul s (sub x xp))))))))
(if (/= xp xq) (ua (mul (sub yp yq) (inv (- xp xq))) (add xp xq)) ; p+q
(if (zerop (add yp yq)) (values nil nil) ; p = -q, so p+q = infinity
(ua (mul (inv (* 2 yp)) (mul 3 (pow xp 2))) (mul 2 xp))))) ; 2*p
(if (and xp yp) (values xp yp) (values xq yq)))) ; pick the [in]finite one
 
;;; Scalar multiplication (by doubling)
;;; THIS IS A VARIABLE-TIME ALGORITHM, BLIND REUSE IS INSECURE!
(defun smulp (k xp yp)
(if (zerop k) (values nil nil)
(multiple-value-bind (xq yq) (addp xp yp xp yp)
(multiple-value-bind (xr yr) (smulp (ash k -1) xq yq)
(if (evenp k) (values xr yr) (addp xp yp xr yr))))))
 
;;; Tests if a point is on the curve
;;; THIS IS A VARIABLE-TIME ALGORITHM, BLIND REUSE IS INSECURE!
(defun e (x y) (= (mul y y) (add (pow x #o3) #o7)))
 
;;; "A horseshoe brings good luck even to those of little faith." - S. Nakamoto
(macrolet ((check-sanity (&rest checks)
`(progn ,@(loop for (test text) on checks by #'cddr
collect `(assert ,test () ,text)))))
(check-sanity (= 977 (sub (pow 2 256) (pow 2 32))) "mathematics has broken"
(e xg yg) "the generator isn't a rational point on the curve"
(not (smulp ng xg yg)) "the generator's order is incorrect"))
 
;;; dyslexia-friendly encoding, placed in public domain by Satoshi Nakamoto
(defun base58enc (bytes)
(loop with code = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"
for x = (octets-to-integer bytes) then (floor x #10R58) until (zerop x)
collect (char code (mod x #10R58)) into out finally
(return (coerce (nreverse (append out (loop for b across bytes
while (zerop b) collect #\1)))
'string))))
 
;;; encodes arbitrary coordinates into a Pay-To-Pubkey-Hash address
(defun pubkey-to-p2pkh (x y)
;; ... ok, the previous comment was a lie; the following line verifies that
;; the coordinates correspond to a rational point on the curve, and gives a
;; few chances to correct typos in either of the coordinates interactively.
(assert (e x y) (x y) "The point (~D, ~D) is off the curve secp256k1." x y)
(labels ((digest (hashes bytes)
(reduce 'digest-sequence hashes :from-end t :initial-value bytes))
(sovcat (&rest things)
(apply 'concatenate 'simple-octet-vector things))
(checksum (octets)
(sovcat octets (subseq (digest '(sha256 sha256) octets) 0 4))))
(let ((point (sovcat '(4) (integer-to-octets x) (integer-to-octets y))))
(base58enc (checksum (sovcat '(0) (digest '(ripemd-160 sha256) point)))))))
 
</syntaxhighlight>
 
Here's an example of how to feed a point into the functions defined above:
 
<syntaxhighlight lang="text">
 
;; ? (pubkey-to-p2pkh
;; #x50863AD64A87AE8A2FE83C1AF1A8403CB53F53E486D8511DAD8A04887E5B2352
;; #x2CD470243453A299FA9E77237716103ABC11A1DF38855ED6F2EE187E9C582BA6)
;;
;; "16UwLL9Risc3QfPqBUvKofHmBQ7wMtjvM"
 
</syntaxhighlight>
=={{header|D}}==
Requires the second D module from the SHA-256 task.
{{trans|C}}
{{trans|Go}}
<langsyntaxhighlight lang="d">import std.stdio, std.algorithm, std.digest.ripemd, sha_256_2;
 
// A Bitcoin public point.
Line 161 ⟶ 278:
 
p.bitcoinEncode.writeln;
}</langsyntaxhighlight>
{{out}}
<pre>16UwLL9Risc3QfPqBUvKofHmBQ7wMtjvM</pre>
=={{header|Delphi}}==
{{libheader| System.SysUtils}}
{{libheader| Winapi.Windows}}
{{libheader| DCPsha256}}
{{libheader| DCPripemd160}}
{{Trans|Go}}
<syntaxhighlight lang="delphi">
program Public_point_to_address;
 
{$APPTYPE CONSOLE}
 
uses
System.SysUtils,
Winapi.Windows,
DCPsha256,
DCPripemd160;
 
const
bitcoinVersion = 0;
 
type
TByteArray = array of Byte;
 
TA25 = TByteArray;
 
TPPoint = record
x, y: TByteArray;
constructor SetHex(xi, yi: ansistring);
end;
 
TA25Helper = record helper for TA25
public
constructor Create(p: TPPoint);
function DoubleSHA256(): TByteArray;
procedure UpdateChecksum();
procedure SetPoint(p: TPPoint);
function ToBase58: Ansistring;
end;
 
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 HashRipemd160(const Input: TByteArray): TByteArray;
var
Hasher: TDCP_ripemd160;
begin
Hasher := TDCP_ripemd160.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;
 
{ TPPoint }
 
constructor TPPoint.SetHex(xi, yi: ansistring);
 
function StrToHexArray(value: Ansistring): TByteArray;
var
b: ansistring;
h, i: integer;
begin
SetLength(Result, 32);
 
for i := 0 to 31 do
begin
b := '$' + copy(value, i * 2 + 1, 2);
if not TryStrToInt(b, h) then
raise Exception.CreateFmt('Error in TPPoint.SetHex.StrToHexArray: Invalid hex string in position %d of "x"',
[i * 2]);
Result[i] := h;
end;
end;
 
begin
if (Length(xi) <> 64) or (Length(yi) <> 64) then
raise Exception.Create('Error in TPPoint.SetHex: Invalid hex string length');
 
x := StrToHexArray(xi);
y := StrToHexArray(yi);
end;
 
{ TA25Helper }
 
constructor TA25Helper.Create(p: TPPoint);
begin
SetLength(self, 25);
SetPoint(p);
end;
 
function TA25Helper.DoubleSHA256: TByteArray;
begin
Result := HashSHA256(HashSHA256(copy(self, 0, 21)));
end;
 
procedure TA25Helper.SetPoint(p: TPPoint);
var
c, s: TByteArray;
begin
c := concat([4], p.x, p.y);
s := HashSHA256(c);
 
self := concat([self[0]], HashRipemd160(s));
SetLength(self, 25);
UpdateChecksum;
end;
 
function TA25Helper.ToBase58: Ansistring;
var
c, i, n: Integer;
const
Size = 34;
Alphabet: Ansistring = '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz';
begin
SetLength(Result, Size);
for n := Size - 1 downto 0 do
begin
c := 0;
for i := 0 to 24 do
begin
c := c * 256 + Self[i];
Self[i] := byte(c div 58);
c := c mod 58;
end;
Result[n + 1] := Alphabet[c + 1];
end;
 
i := 2;
while (i < Size) and (result[i] = '1') do
inc(i);
 
Result := copy(Result, i - 1, Size);
end;
 
procedure TA25Helper.UpdateChecksum;
begin
CopyMemory(@self[21], @self.DoubleSHA256[0], 4);
end;
 
var
p: TPPoint;
a: TA25;
 
const
x: Ansistring = '50863AD64A87AE8A2FE83C1AF1A8403CB53F53E486D8511DAD8A04887E5B2352';
y: Ansistring = '2CD470243453A299FA9E77237716103ABC11A1DF38855ED6F2EE187E9C582BA6';
 
begin
p.SetHex(x, y);
 
a := TA25.Create(p);
writeln(a.ToBase58);
readln;
end.</syntaxhighlight>
=={{header|Factor}}==
<syntaxhighlight lang="factor">USING: checksums checksums.ripemd checksums.sha io.binary kernel
math sequences ;
IN: rosetta-code.bitcoin.point-address
 
CONSTANT: ALPHABET "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"
 
: btc-checksum ( bytes -- checksum-bytes )
2 [ sha-256 checksum-bytes ] times 4 head ;
 
: bigint>base58 ( n -- str )
33 [ 58 /mod ALPHABET nth ] "" replicate-as reverse nip ;
 
: >base58 ( bytes -- str )
be> bigint>base58 ;
 
: point>address ( X Y -- address )
[ 32 >be ] bi@ append
0x4 prefix
sha-256 checksum-bytes
ripemd-160 checksum-bytes
dup 0 prefix btc-checksum
append 0 prefix >base58 ;
</syntaxhighlight>
{{out}}
<pre>
0x50863AD64A87AE8A2FE83C1AF1A8403CB53F53E486D8511DAD8A04887E5B2352
0x2CD470243453A299FA9E77237716103ABC11A1DF38855ED6F2EE187E9C582BA6
point>address . ! "16UwLL9Risc3QfPqBUvKofHmBQ7wMtjvM"
</pre>
=={{header|Go}}==
{{libheader|Go sub-repositories}}
<langsyntaxhighlight lang="go">package main
 
import (
Line 175 ⟶ 491:
"fmt"
 
"codegolang.google.comorg/px/go.crypto/ripemd160"
)
 
Line 267 ⟶ 583:
// show base58 representation
fmt.Println(string(a.A58()))
}</langsyntaxhighlight>
{{out}}
<pre>
16UwLL9Risc3QfPqBUvKofHmBQ7wMtjvM
</pre>
=={{header|Haskell}}==
<syntaxhighlight lang="haskell">import Numeric (showIntAtBase)
import Data.List (unfoldr)
import Data.Binary (Word8)
import Crypto.Hash.SHA256 as S (hash)
import Crypto.Hash.RIPEMD160 as R (hash)
import Data.ByteString (unpack, pack)
 
publicPointToAddress :: Integer -> Integer -> String
publicPointToAddress x y =
let toBytes x = reverse $ unfoldr (\b -> if b == 0 then Nothing else Just (fromIntegral $ b `mod` 256, b `div` 256)) x
ripe = 0 : unpack (R.hash $ S.hash $ pack $ 4 : toBytes x ++ toBytes y)
ripe_checksum = take 4 $ unpack $ S.hash $ S.hash $ pack ripe
addressAsList = ripe ++ ripe_checksum
address = foldl (\v b -> v * 256 + fromIntegral b) 0 addressAsList
base58Digits = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"
in showIntAtBase 58 (base58Digits !!) address ""
 
main = print $ publicPointToAddress
0x50863AD64A87AE8A2FE83C1AF1A8403CB53F53E486D8511DAD8A04887E5B2352
0x2CD470243453A299FA9E77237716103ABC11A1DF38855ED6F2EE187E9C582BA6
</syntaxhighlight>
{{out}}
<pre>"6UwLL9Risc3QfPqBUvKofHmBQ7wMtjvM"
</pre>
=={{header|Julia}}==
{{works with|Julia|0.6}}
{{trans|C}}
 
'''Main functions''':
<syntaxhighlight lang="julia">const digits = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"
function encodebase58(b::Vector{<:Integer})
out = Vector{Char}(34)
for j in endof(out):-1:1
local c::Int = 0
for i in eachindex(b)
c = c * 256 + b[i]
b[i] = c ÷ 58
c %= 58
end
out[j] = digits[c + 1]
end
local i = 1
while i < endof(out) && out[i] == '1'
i += 1
end
return join(out[i:end])
end
 
const COINVER = 0x00
function pubpoint2address(x::Vector{UInt8}, y::Vector{UInt8})
c = vcat(0x04, x, y)
c = vcat(COINVER, digest("ripemd160", sha256(c)))
d = sha256(sha256(c))
return encodebase58(vcat(c, d[1:4]))
end
pubpoint2address(x::AbstractString, y::AbstractString) =
pubpoint2address(hex2bytes(x), hex2bytes(y))</syntaxhighlight>
 
'''Main''':
<syntaxhighlight lang="julia">x = "50863AD64A87AE8A2FE83C1AF1A8403CB53F53E486D8511DAD8A04887E5B2352"
y = "2CD470243453A299FA9E77237716103ABC11A1DF38855ED6F2EE187E9C582BA6"
println(pubpoint2address(x, y)))</syntaxhighlight>
 
{{out}}
<pre>6UwLL9Risc3QfPqBUvKofHmBQ7wMtjvM</pre>
=={{header|Nim}}==
 
{{libheader|bignum|1.0.4}}
{{libheader|nimcrypto|0.5.4}}
{{works with|Nim Compiler|1.4.0}}
 
These libraries can be found on <code>nimble</code>.
 
The “bignum” library is used to check if the public point belongs to the “secp256k1” elliptic curve.
 
<syntaxhighlight lang="nim">import parseutils
import nimcrypto
import bignum
 
func base58Encode(data: seq[byte]): string =
## Encode data to base58 with at most one starting '1'.
 
var data = data
const Base = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"
result.setlen(34)
 
# Convert to base 58.
for j in countdown(result.high, 0):
var c = 0
for i, b in data:
c = c * 256 + b.int
data[i] = (c div 58).byte
c = c mod 58
result[j] = Base[c]
 
# Keep one starting '1' at most.
if result[0] == '1':
for idx in 1..result.high:
if result[idx] != '1':
result = result[(idx - 1)..^1]
break
 
func hexToByteSeq(s: string): seq[byte] =
## Convert a hexadecimal string to a sequence of bytes.
 
var pos = 0
while pos < s.len:
var tmp = 0
let parsed = parseHex(s, tmp, pos, 2)
if parsed > 0:
inc pos, parsed
result.add byte tmp
else:
raise newException(ValueError, "Invalid hex string")
 
func validCoordinates(x, y: string): bool =
## Return true if the coordinates are those of a point in the secp256k1 elliptic curve.
 
let p = newInt("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F", 16)
let x = newInt(x, 16)
let y = newInt(y, 16)
result = y^2 mod p == (x^3 + 7) mod p
 
func addrEncode(x, y: string): string =
## Encode x and y coordinates to an address.
 
if not validCoordinates(x, y):
raise newException(ValueError, "Invalid coordinates")
 
let pubPoint = 4u8 & x.hexToByteSeq & y.hexToByteSeq
if pubPoint.len != 65:
raise newException(ValueError, "Invalid pubpoint string")
 
var rmd = @(ripemd160.digest(sha256.digest(pubPoint).data).data)
rmd.insert 0u8
rmd.add sha256.digest(sha256.digest(rmd).data).data[0..3]
result = base58Encode(rmd)
 
when isMainModule:
let address = addrEncode("50863AD64A87AE8A2FE83C1AF1A8403CB53F53E486D8511DAD8A04887E5B2352",
"2CD470243453A299FA9E77237716103ABC11A1DF38855ED6F2EE187E9C582BA6")
echo "Coordinates are valid."
echo "Address is: ", address</syntaxhighlight>
 
{{out}}
<pre>Coordinates are valid.
Address is: 16UwLL9Risc3QfPqBUvKofHmBQ7wMtjvM</pre>
=={{header|Perl}}==
Here we'll use the standard Digest::SHA module, and the CPAN-available Crypt::RIPEMD160 and Encode::Base58::GMP.
<syntaxhighlight lang ="perl">use bigint;
use Crypt::RIPEMD160;
use Digest::SHA qw(sha256);
use Encode::Base58::GMP;
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 = qr/[@{[join '', @b58]}]/x;
 
sub encode { my $_ = shift; $_ < 58 ? $b58[$_] : encode($_/58) . $b58[$_%58] }
 
sub public_point_to_address {
my $ec = join '', '04', @_; # EC: concat x and y to one string and prepend '04' magic value
my ($x, $y) = @_;
my @byte;
for (1 .. 32) { push @byte, $y % 256; $y /= 256 }
for (1 .. 32) { push @byte, $x % 256; $x /= 256 }
@byte = (4, reverse @byte);
my $hash = Crypt::RIPEMD160->hash(sha256 join '', map { chr } @byte);
my $checksum = substr sha256(sha256 chr(0).$hash), 0, 4;
my $value = 0;
for ( (chr(0).$hash.$checksum) =~ /./gs ) { $value = $value * 256 + ord }
(sprintf "%33s", encode $value) =~ y/ /1/r;
}
 
my $octets = pack 'C*', map { hex } unpack('(a2)65', $ec); # transform the hex values string to octets
print public_point_to_address map {hex "0x$_"} <DATA>;
my $hash = chr(0) . Crypt::RIPEMD160->hash(sha256 $octets); # perform RIPEMD160(SHA256(octets)
my $checksum = substr sha256(sha256 $hash), 0, 4; # build the checksum
my $hex = join '', '0x', # build hex value of hash and checksum
map { sprintf "%02X", $_ }
unpack 'C*', $hash.$checksum;
return '1' . sprintf "%32s", encode_base58($hex, 'bitcoin'); # Do the Base58 encoding, prepend "1"
}
 
say public_point_to_address
__DATA__
'50863AD64A87AE8A2FE83C1AF1A8403CB53F53E486D8511DAD8A04887E5B2352',
'2CD470243453A299FA9E77237716103ABC11A1DF38855ED6F2EE187E9C582BA6'
;
</lang>
</syntaxhighlight>
{{out}}
<pre>16UwLL9Risc3QfPqBUvKofHmBQ7wMtjvM</pre>
=={{header|Phix}}==
<!--<syntaxhighlight lang="phix">(notonline)-->
<span style="color: #008080;">without</span> <span style="color: #008080;">javascript_semantics</span> <span style="color: #000080;font-style:italic;">-- no ripemd160.js as yet</span>
<span style="color: #008080;">include</span> <span style="color: #000000;">builtins</span><span style="color: #0000FF;">\</span><span style="color: #7060A8;">sha256</span><span style="color: #0000FF;">.</span><span style="color: #000000;">e</span>
<span style="color: #008080;">include</span> <span style="color: #000000;">builtins</span><span style="color: #0000FF;">\</span><span style="color: #000000;">ripemd160</span><span style="color: #0000FF;">.</span><span style="color: #000000;">e</span>
<span style="color: #008080;">constant</span> <span style="color: #000000;">b58</span> <span style="color: #0000FF;">=</span> <span style="color: #008000;">"123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"</span>
<span style="color: #008080;">function</span> <span style="color: #000000;">base58</span><span style="color: #0000FF;">(</span><span style="color: #004080;">string</span> <span style="color: #000000;">s</span><span style="color: #0000FF;">)</span>
<span style="color: #004080;">string</span> <span style="color: #000000;">out</span> <span style="color: #0000FF;">=</span> <span style="color: #008000;">""</span>
<span style="color: #008080;">if</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">s</span><span style="color: #0000FF;">)!=</span><span style="color: #000000;">25</span> <span style="color: #008080;">then</span> <span style="color: #0000FF;">?</span><span style="color: #000000;">9</span><span style="color: #0000FF;">/</span><span style="color: #000000;">0</span> <span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #008080;">for</span> <span style="color: #000000;">n</span><span style="color: #0000FF;">=</span><span style="color: #000000;">1</span> <span style="color: #008080;">to</span> <span style="color: #000000;">34</span> <span style="color: #008080;">do</span>
<span style="color: #004080;">integer</span> <span style="color: #000000;">c</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">0</span>
<span style="color: #008080;">for</span> <span style="color: #000000;">i</span><span style="color: #0000FF;">=</span><span style="color: #000000;">1</span> <span style="color: #008080;">to</span> <span style="color: #000000;">25</span> <span style="color: #008080;">do</span>
<span style="color: #000000;">c</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">c</span><span style="color: #0000FF;">*</span><span style="color: #000000;">256</span><span style="color: #0000FF;">+</span><span style="color: #000000;">s</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">]</span>
<span style="color: #000000;">s</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">]</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">floor</span><span style="color: #0000FF;">(</span><span style="color: #000000;">c</span><span style="color: #0000FF;">/</span><span style="color: #000000;">58</span><span style="color: #0000FF;">)</span>
<span style="color: #000000;">c</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">mod</span><span style="color: #0000FF;">(</span><span style="color: #000000;">c</span><span style="color: #0000FF;">,</span><span style="color: #000000;">58</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
<span style="color: #000000;">out</span> <span style="color: #0000FF;">&=</span> <span style="color: #000000;">b58</span><span style="color: #0000FF;">[</span><span style="color: #000000;">c</span><span style="color: #0000FF;">+</span><span style="color: #000000;">1</span><span style="color: #0000FF;">]</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">out</span><span style="color: #0000FF;">[$]=</span><span style="color: #008000;">'1'</span> <span style="color: #008080;">then</span>
<span style="color: #008080;">for</span> <span style="color: #000000;">i</span><span style="color: #0000FF;">=</span><span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">out</span><span style="color: #0000FF;">)-</span><span style="color: #000000;">1</span> <span style="color: #008080;">to</span> <span style="color: #000000;">1</span> <span style="color: #008080;">by</span> <span style="color: #0000FF;">-</span><span style="color: #000000;">1</span> <span style="color: #008080;">do</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">out</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">]!=</span><span style="color: #008000;">'1'</span> <span style="color: #008080;">then</span>
<span style="color: #000000;">out</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">out</span><span style="color: #0000FF;">[</span><span style="color: #000000;">1</span><span style="color: #0000FF;">..</span><span style="color: #000000;">i</span><span style="color: #0000FF;">+</span><span style="color: #000000;">1</span><span style="color: #0000FF;">]</span>
<span style="color: #008080;">exit</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #008080;">return</span> <span style="color: #7060A8;">reverse</span><span style="color: #0000FF;">(</span><span style="color: #000000;">out</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">function</span>
<span style="color: #008080;">function</span> <span style="color: #000000;">coin_encode</span><span style="color: #0000FF;">(</span><span style="color: #004080;">string</span> <span style="color: #000000;">x</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">y</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">if</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">x</span><span style="color: #0000FF;">)!=</span><span style="color: #000000;">32</span>
<span style="color: #008080;">or</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">y</span><span style="color: #0000FF;">)!=</span><span style="color: #000000;">32</span> <span style="color: #008080;">then</span>
<span style="color: #008080;">return</span> <span style="color: #008000;">"bad public point string"</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #004080;">string</span> <span style="color: #000000;">s</span> <span style="color: #0000FF;">=</span> <span style="color: #008000;">"\x04"</span> <span style="color: #0000FF;">&</span> <span style="color: #000000;">x</span> <span style="color: #0000FF;">&</span> <span style="color: #000000;">y</span>
<span style="color: #004080;">string</span> <span style="color: #000000;">rmd</span> <span style="color: #0000FF;">=</span> <span style="color: #008000;">'\0'</span><span style="color: #0000FF;">&</span><span style="color: #000000;">ripemd160</span><span style="color: #0000FF;">(</span><span style="color: #7060A8;">sha256</span><span style="color: #0000FF;">(</span><span style="color: #000000;">s</span><span style="color: #0000FF;">),</span><span style="color: #004600;">false</span><span style="color: #0000FF;">)</span>
<span style="color: #000000;">rmd</span> <span style="color: #0000FF;">&=</span> <span style="color: #7060A8;">sha256</span><span style="color: #0000FF;">(</span><span style="color: #7060A8;">sha256</span><span style="color: #0000FF;">(</span><span style="color: #000000;">rmd</span><span style="color: #0000FF;">))[</span><span style="color: #000000;">1</span><span style="color: #0000FF;">..</span><span style="color: #000000;">4</span><span style="color: #0000FF;">]</span>
<span style="color: #004080;">string</span> <span style="color: #000000;">res</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">base58</span><span style="color: #0000FF;">(</span><span style="color: #000000;">rmd</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">return</span> <span style="color: #000000;">res</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">function</span>
<span style="color: #0000FF;">?</span><span style="color: #000000;">coin_encode</span><span style="color: #0000FF;">(</span>x"<span style="color: #0000FF;">50863AD64A87AE8A2FE83C1AF1A8403CB53F53E486D8511DAD8A04887E5B2352</span>"<span style="color: #0000FF;">,</span>
x"<span style="color: #0000FF;">2CD470243453A299FA9E77237716103ABC11A1DF38855ED6F2EE187E9C582BA6</span>"<span style="color: #0000FF;">)</span>
<!--</syntaxhighlight>-->
There is actually an sha256.js included, not that I recommend it.<br>
You could probably get this to work in a browser if you provide a suitable ripemd160.js and tweak p2js to use it.
 
{{out}}
=={{header|Perl 6}}==
<pre>
{{trans|Perl}}
"16UwLL9Risc3QfPqBUvKofHmBQ7wMtjvM"
<lang perl6>use SSL::Digest;
</pre>
=={{header|PicoLisp}}==
<syntaxhighlight lang="picolisp">(load "ripemd160.l")
(load "sha256.l")
 
(setq *B58Alpha
constant BASE58 = <
(chop "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz") )
1 2 3 4 5 6 7 8 9
(de hex2L (H)
A B C D E F G H J K L M N P Q R S T U V W X Y Z
(make
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
(for (L (chop H) L (cddr L))
>;
(link (hex (pack (car L) (cadr L)))) ) ) )
(de b58enc (Lst)
(let
(P 1
Z 0
A
(sum
'((X)
(* X (swap 'P (>> -8 P))) )
(reverse Lst) ) )
(for L Lst
(T (n0 L))
(inc 'Z) )
(pack
(need Z "1")
(make
(while (gt0 A)
(yoke
(prog1
(get *B58Alpha (inc (% A 58)))
(setq A (/ A 58)) ) ) ) ) ) ) )
(de point2address (X Y)
(let L (conc (cons 4) (hex2L X) (hex2L Y))
(b58enc
(and
(conc (cons 0) (ripemd160 (sha256 L)))
(conc @ (head 4 (sha256 (sha256 @)))) ) ) ) )
(println
(point2address
"50863AD64A87AE8A2FE83C1AF1A8403CB53F53E486D8511DAD8A04887E5B2352"
"2CD470243453A299FA9E77237716103ABC11A1DF38855ED6F2EE187E9C582BA6" ) )</syntaxhighlight>
{{out}}
<pre>"16UwLL9Risc3QfPqBUvKofHmBQ7wMtjvM"</pre>
=={{header|Python}}==
<syntaxhighlight lang="python">#!/usr/bin/env python3
 
import binascii
sub encode(Int $n) {
import functools
$n < BASE58 ??
import hashlib
BASE58[$n] !!
encode($n div 58) ~ BASE58[$n % 58]
}
 
digits58 = b'123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz'
sub public_point_to_address(Int $x is copy, Int $y is copy) {
my @bytes;
for 1 .. 32 { push @bytes, $y % 256; $y div= 256 }
for 1 .. 32 { push @bytes, $x % 256; $x div= 256 }
my $hash = rmd160 sha256 Blob.new: 4, @bytes.reverse;
my $checksum = sha256(sha256 Blob.new: 0, $hash.list).subbuf: 0, 4;
encode reduce * * 256 + * , 0, ($hash, $checksum)».list
}
 
def b58(n):
return b58(n//58) + digits58[n%58:n%58+1] if n else b''
 
def public_point_to_address(x, y):
c = b'\x04' + binascii.unhexlify(x) + binascii.unhexlify(y)
r = hashlib.new('ripemd160')
r.update(hashlib.sha256(c).digest())
c = b'\x00' + r.digest()
d = hashlib.sha256(hashlib.sha256(c).digest()).digest()
return b58(functools.reduce(lambda n, b: n<<8|b, c + d[:4]))
 
if __name__ == '__main__':
print(public_point_to_address(
b'50863AD64A87AE8A2FE83C1AF1A8403CB53F53E486D8511DAD8A04887E5B2352',
b'2CD470243453A299FA9E77237716103ABC11A1DF38855ED6F2EE187E9C582BA6'))</syntaxhighlight>
{{out}}
<pre>
b'6UwLL9Risc3QfPqBUvKofHmBQ7wMtjvM'
</pre>
=={{header|Racket}}==
 
Uses code from [[SHA-256#Racket]] (which is isolated in a submodule).
 
<syntaxhighlight lang="racket">#lang racket/base
(module sha256 racket/base
;; define a quick SH256 FFI interface, similar to the Racket's default
;; SHA1 interface (from [[SHA-256#Racket]])
(provide sha256)
(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)
;; (bytes->hex-string result) -- not needed, we want bytes
result))
 
(require
;; On windows I needed to "raco planet install soegaard digetst.plt 1 2"
(only-in (planet soegaard/digest:1:2/digest) ripemd160-bytes)
(submod "." sha256))
 
;; Quick utility
(define << arithmetic-shift) ; a bit shorter
 
;; From: https://en.bitcoin.it/wiki/Technical_background_of_version_1_Bitcoin_addresses
;; Using Bitcoin's stage numbers:
 
;; 1 - Take the corresponding public key generated with it
;; (65 bytes, 1 byte 0x04, 32 bytes corresponding to X coordinate,
;; 32 bytes corresponding to Y coordinate)
(define (stage-1 X Y)
(define (integer->bytes! i B)
(define l (bytes-length B))
(for ((b (in-range 0 l))) (bytes-set! B (- l b 1) (bitwise-bit-field i (* b 8) (* (+ b 1) 8)))) B)
(integer->bytes! (+ (<< 4 (* 32 8 2)) (<< X (* 32 8)) Y) (make-bytes 65)))
 
;; 2 - Perform SHA-256 hashing on the public key
(define stage-2 sha256)
 
;; 3 - Perform RIPEMD-160 hashing on the result of SHA-256
(define stage-3 ripemd160-bytes)
 
;; 4 - Add version byte in front of RIPEMD-160 hash (0x00 for Main Network)
(define (stage-4 s3)
(bytes-append #"\0" s3))
 
;; 5 - Perform SHA-256 hash on the extended RIPEMD-160 result
;; 6 - Perform SHA-256 hash on the result of the previous SHA-256 hash
(define (stage-5+6 s4)
(values s4 (sha256 (sha256 s4))))
 
;; 7 - Take the first 4 bytes of the second SHA-256 hash. This is the address checksum
(define (stage-7 s4 s6)
(values s4 (subbytes s6 0 4)))
 
;; 8 - Add the 4 checksum bytes from stage 7 at the end of extended RIPEMD-160 hash from stage 4.
;; This is the 25-byte binary Bitcoin Address.
(define (stage-8 s4 s7)
(bytes-append s4 s7))
 
;; 9 - Convert the result from a byte string into a base58 string using Base58Check encoding.
;; This is the most commonly used Bitcoin Address format
(define stage-9 (base58-encode 33))
 
(define ((base58-encode l) B)
(define b58 #"123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz")
(define rv (make-bytes l (char->integer #\1))) ; already padded out with 1's
(define b-int (for/fold ((i 0)) ((b (in-bytes B))) (+ (<< i 8) b)))
(let loop ((b b-int) (l l))
(if (zero? b) rv
(let-values (((q r) (quotient/remainder b 58)))
(define l- (- l 1))
(bytes-set! rv l- (bytes-ref b58 r))
(loop q l-)))))
 
;; Takes two (rather large) ints for X and Y, returns base-58 PAP.
(define public-address-point
(compose stage-9 stage-8 stage-7 stage-5+6 stage-4 stage-3 stage-2 stage-1))
 
(public-address-point
#x50863AD64A87AE8A2FE83C1AF1A8403CB53F53E486D8511DAD8A04887E5B2352
#x2CD470243453A299FA9E77237716103ABC11A1DF38855ED6F2EE187E9C582BA6)
 
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(module+ test
(require tests/eli-tester (only-in openssl/sha1 bytes->hex-string))
(define bytes->HEX-STRING (compose string-upcase bytes->hex-string))
(test
((base58-encode 33)
(bytes-append #"\x00\x01\x09\x66\x77\x60\x06\x95\x3D\x55\x67\x43"
#"\x9E\x5E\x39\xF8\x6A\x0D\x27\x3B\xEE\xD6\x19\x67\xF6"))
=>
#"16UwLL9Risc3QfPqBUvKofHmBQ7wMtjvM")
(define-values (test-X test-Y)
(values #x50863AD64A87AE8A2FE83C1AF1A8403CB53F53E486D8511DAD8A04887E5B2352
#x2CD470243453A299FA9E77237716103ABC11A1DF38855ED6F2EE187E9C582BA6))
(define s1 (stage-1 test-X test-Y))
(define s2 (stage-2 s1))
(define s3 (stage-3 s2))
(define s4 (stage-4 s3))
(define-values (s4_1 s6) (stage-5+6 s4))
(define-values (s4_2 s7) (stage-7 s4 s6))
(define s8 (stage-8 s4 s7))
(define s9 (stage-9 s8))
(test
(bytes->HEX-STRING s1)
=> (string-append "0450863AD64A87AE8A2FE83C1AF1A8403CB53F53E486D8511DAD8A04887E5B23522CD470243453"
"A299FA9E77237716103ABC11A1DF38855ED6F2EE187E9C582BA6")
(bytes->HEX-STRING s2) => "600FFE422B4E00731A59557A5CCA46CC183944191006324A447BDB2D98D4B408"
(bytes->HEX-STRING s3) => "010966776006953D5567439E5E39F86A0D273BEE"
(bytes->HEX-STRING s4) => "00010966776006953D5567439E5E39F86A0D273BEE"
(bytes->HEX-STRING s6) => "D61967F63C7DD183914A4AE452C9F6AD5D462CE3D277798075B107615C1A8A30"
(bytes->HEX-STRING s7) => "D61967F6"
(bytes->HEX-STRING s8) => "00010966776006953D5567439E5E39F86A0D273BEED61967F6"
s9 => #"16UwLL9Risc3QfPqBUvKofHmBQ7wMtjvM"))</syntaxhighlight>
 
{{out}}
<pre>#"16UwLL9Risc3QfPqBUvKofHmBQ7wMtjvM"
1 test passed
8 tests passed</pre>
=={{header|Raku}}==
(formerly Perl 6)
 
<syntaxhighlight lang="raku" line>sub dgst(blob8 $b, Str :$dgst) returns blob8 {
given run «openssl dgst "-$dgst" -binary», :in, :out, :bin {
.in.write: $b;
.in.close;
return .out.slurp;
}
}
sub sha256($b) { dgst $b, :dgst<sha256> }
sub rmd160($b) { dgst $b, :dgst<rmd160> }
sub public_point_to_address( UInt $x, UInt $y ) {
my @bytes = flat ($y,$x).map: *.polymod( 256 xx * )[^32];
my $hash = rmd160 sha256 blob8.new: 4, @bytes.reverse;
my $checksum = sha256(sha256 blob8.new: 0, $hash.list).subbuf: 0, 4;
[R~] <
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
>[ .polymod: 58 xx * ] given
reduce * * 256 + * , flat 0, ($hash, $checksum)».list
}
say public_point_to_address
0x50863AD64A87AE8A2FE83C1AF1A8403CB53F53E486D8511DAD8A04887E5B2352,
0x2CD470243453A299FA9E77237716103ABC11A1DF38855ED6F2EE187E9C582BA6;</lang>
</syntaxhighlight>
{{out}}
<pre>6UwLL9Risc3QfPqBUvKofHmBQ7wMtjvM</pre>
 
=={{header|Ruby}}==
<langsyntaxhighlight lang="ruby">
# Translate public point to Bitcoin address
#
Line 363 ⟶ 1,068:
end
puts res.reverse
</syntaxhighlight>
</lang>
{{out}}
<pre>
6UwLL9Risc3QfPqBUvKofHmBQ7wMtjvM
</pre>
=={{header|Rust}}==
<syntaxhighlight lang="rust">
use ring::digest::{digest, SHA256};
use ripemd::{Digest, Ripemd160};
 
use hex::FromHex;
 
static X: &str = "50863AD64A87AE8A2FE83C1AF1A8403CB53F53E486D8511DAD8A04887E5B2352";
static Y: &str = "2CD470243453A299FA9E77237716103ABC11A1DF38855ED6F2EE187E9C582BA6";
static ALPHABET: [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 base58_encode(bytes: &mut [u8]) -> String {
let base = ALPHABET.len();
if bytes.is_empty() {
return String::from("");
}
let mut output: Vec<u8> = Vec::new();
let mut num: usize;
for _ in 0..33 {
num = 0;
for byte in bytes.iter_mut() {
num = num * 256 + *byte as usize;
*byte = (num / base) as u8;
num %= base;
}
output.push(num as u8);
}
let mut string = String::new();
for b in output.iter().rev() {
string.push(ALPHABET[*b as usize]);
}
string
}
 
// stolen from address-validation/src/main.rs
/// Hashes the input with the SHA-256 algorithm twice, and returns the output.
fn double_sha256(bytes: &[u8]) -> Vec<u8> {
let digest_1 = digest(&SHA256, bytes);
 
let digest_2 = digest(&SHA256, digest_1.as_ref());
digest_2.as_ref().to_vec()
}
 
fn point_to_address(x: &str, y: &str) -> String {
let mut addrv: Vec<u8> = Vec::with_capacity(65);
addrv.push(4u8);
addrv.append(&mut <Vec<u8>>::from_hex(x).unwrap());
addrv.append(&mut <Vec<u8>>::from_hex(y).unwrap());
// hash the addresses first using SHA256
let sha_digest = digest(&SHA256, &addrv);
let mut ripemd_digest = Ripemd160::digest(&sha_digest.as_ref()).as_slice().to_vec();
// prepend a 0 to the vector
ripemd_digest.insert(0, 0);
// calculate checksum of extended ripemd digest
let checksum = double_sha256(&ripemd_digest);
ripemd_digest.extend_from_slice(&checksum[..4]);
base58_encode(&mut ripemd_digest)
}
 
fn main() {
println!("{}", point_to_address(X, Y));
}
 
</syntaxhighlight>
{{out}}
<pre>
16UwLL9Risc3QfPqBUvKofHmBQ7wMtjvM
</pre>
 
=={{header|Seed7}}==
The Seed7 library [http://seed7.sourceforge.net/libraries/msgdigest.htm msgdigest.s7i] defines
the functions [http://seed7.sourceforge.net/libraries/msgdigest.htm#ripemd160(in_var_string) ripemd160] and
[http://seed7.sourceforge.net/libraries/msgdigest.htm#sha256(in_var_string) sha256].
The Seed7 library [http://seed7.sourceforge.net/libraries/encoding.htm encoding.s7i] defines
the function [http://seed7.sourceforge.net/libraries/encoding.htm#toBase58(in_string) toBase58],
which encodes a string with the Base58 encoding used by Bitcoin. No external library is needed.
 
<syntaxhighlight lang="seed7">$ include "seed7_05.s7i";
include "bytedata.s7i";
include "msgdigest.s7i";
include "encoding.s7i";
 
const func string: publicPointToAddress (in string: x, in string: y) is func
result
var string: address is "";
begin
address := "\4;" & hex2Bytes(x) & hex2Bytes(y);
address := "\0;" & ripemd160(sha256(address));
address &:= sha256(sha256(address))[.. 4];
address := toBase58(address);
end func;
 
const proc: main is func
begin
writeln(publicPointToAddress("50863AD64A87AE8A2FE83C1AF1A8403CB53F53E486D8511DAD8A04887E5B2352",
"2CD470243453A299FA9E77237716103ABC11A1DF38855ED6F2EE187E9C582BA6"));
end func;</syntaxhighlight>
 
{{out}}
<pre>
16UwLL9Risc3QfPqBUvKofHmBQ7wMtjvM
</pre>
=={{header|Tcl}}==
{{tcllib|ripemd160}}
{{tcllib|sha256}}
<langsyntaxhighlight lang="tcl">package require ripemd160
package require sha256
 
Line 400 ⟶ 1,211:
append addr [binary format "a4" [string range $hash 0 3]]
return [base58encode $addr]
}</langsyntaxhighlight>
Demonstrating
<langsyntaxhighlight lang="tcl">puts [bitcoin_mkaddr \
0x50863AD64A87AE8A2FE83C1AF1A8403CB53F53E486D8511DAD8A04887E5B2352 \
0x2CD470243453A299FA9E77237716103ABC11A1DF38855ED6F2EE187E9C582BA6]</langsyntaxhighlight>
{{out}}
<pre>
16UwLL9Risc3QfPqBUvKofHmBQ7wMtjvM
</pre>
=={{header|Wolfram Language}}/{{header|Mathematica}}==
<syntaxhighlight lang="mathematica">BlockchainKeyEncode[
PublicKey[
<|
"Type"->"EllipticCurve",
"PublicCurvePoint"-> {
16^^50863AD64A87AE8A2FE83C1AF1A8403CB53F53E486D8511DAD8A04887E5B2352,
16^^2CD470243453A299FA9E77237716103ABC11A1DF38855ED6F2EE187E9C582BA6
}
|>
],
"Address",
BlockchainBase-> "Bitcoin"
]</syntaxhighlight>
{{output}}
<pre>16UwLL9Risc3QfPqBUvKofHmBQ7wMtjvM</pre>
=={{header|Wren}}==
{{trans|Go}}
{{libheader|Wren-crypto}}
{{libheader|Wren-str}}
{{libheader|Wren-fmt}}
<syntaxhighlight lang="wren">import "./crypto" for Sha256, Ripemd160
import "./str" for Str
import "./fmt" for Conv
 
// converts an hexadecimal string to a byte list.
var HexToBytes = Fn.new { |s| Str.chunks(s, 2).map { |c| Conv.atoi(c, 16) }.toList }
 
// Point is a class for a bitcoin public point
class Point {
construct new() {
_x = List.filled(32, 0)
_y = List.filled(32, 0)
}
 
x { _x }
y { _y }
 
// setHex takes two hexadecimal strings and decodes them into the receiver.
setHex(s, t) {
if (s.count != 64 || t.count != 64) Fiber.abort("Invalid hex string length.")
_x = HexToBytes.call(s)
_y = HexToBytes.call(t)
}
}
 
// Represents a bitcoin address.
class Address {
static tmpl_ { "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz".bytes }
 
construct new() {
_a = List.filled(25, 0)
}
 
a { _a }
 
// returns a base58 encoded bitcoin address corresponding to the receiver.
a58 {
var out = List.filled(34, 0)
for (n in 33..0) {
var c = 0
for (i in 0..24) {
c = c * 256 + _a[i]
_a[i] = (c/58).floor
c = c % 58
}
out[n] = Address.tmpl_[c]
}
var i = 1
while (i < 34 && out[i] == 49) i = i + 1
return out[i-1..-1]
}
 
// doubleSHA256 computes a double sha256 hash of the first 21 bytes of the
// address, returning the full 32 byte sha256 hash.
doubleSHA256() {
var d = Sha256.digest(_a[0..20])
d = HexToBytes.call(d)
d = Sha256.digest(d)
return HexToBytes.call(d)
}
 
// updateChecksum computes the address checksum on the first 21 bytes and
// stores the result in the last 4 bytes.
updateCheckSum() {
var d = doubleSHA256()
for (i in 21..24) _a[i] = d[i-21]
}
 
// setPoint takes a public point and generates the corresponding address
// into the receiver, complete with valid checksum.
setPoint(p) {
var c = List.filled(65, 0)
c[0] = 4
for (i in 1..32) c[i] = p.x[i - 1]
for (i in 33..64) c[i] = p.y[i - 33]
var s = Sha256.digest(c)
s = HexToBytes.call(s)
var h = Ripemd160.digest(s)
h = HexToBytes.call(h)
for (i in 0...h.count) _a[i+1] = h[i]
updateCheckSum()
}
}
 
// parse hex into Point object
var p = Point.new()
p.setHex(
"50863AD64A87AE8A2FE83C1AF1A8403CB53F53E486D8511DAD8A04887E5B2352",
"2CD470243453A299FA9E77237716103ABC11A1DF38855ED6F2EE187E9C582BA6"
)
// generate Address object from Point
var a = Address.new()
a.setPoint(p)
// show base58 representation
System.print(a.a58.map { |b| String.fromByte(b) }.join())</syntaxhighlight>
 
{{out}}
<pre>
Line 412 ⟶ 1,344:
=={{header|zkl}}==
Uses shared library zklMsgHash.
<langsyntaxhighlight lang="zkl">var [const] MsgHash=Import.lib("zklMsgHash"); // SHA-256, etc
 
const symbols = "123456789" // 58 characters: no cap i,o; ell, zero
Line 434 ⟶ 1,366:
fcn coinEncode(x,y){ // throws if x or y not hex or (x+y) not even length
bytes:=(x+y).pump(Data,Void.Read,fcn(a,b){ (a+b).toInt(16) }).insert(0,4);
bytes=(MsgHash.SHA256(bytes,1,Falsebytes) : MsgHash.RIPEMD160(_,1,Falsebytes))
.insert(0,COIN_VER); // we are using bytes for in and out
d,chkSum := Data(), MsgHash.SHA256(bytes,1,Falsed) : MsgHash.SHA256(_,1,Falsed)[0,4];
base58Encode(bytes.append(chkSum.del(4,*))); // first 4 bytes of hashed hash
}</langsyntaxhighlight>
<langsyntaxhighlight lang="zkl">e:=coinEncode(
"50863AD64A87AE8A2FE83C1AF1A8403CB53F53E486D8511DAD8A04887E5B2352",
"2CD470243453A299FA9E77237716103ABC11A1DF38855ED6F2EE187E9C582BA6");
(e=="16UwLL9Risc3QfPqBUvKofHmBQ7wMtjvM").println();</langsyntaxhighlight>
{{out}}
<pre>True</pre>
 
 
{{omit from|Brlcad}}
{{omit from|GUISS}}
117

edits