Bitcoin/public point to address: Difference between revisions

Content added Content deleted
(Rename Perl 6 -> Raku, alphabetize, minor clean-up)
(Removed "base58" library which no longer works, added code for base58 encoding and added coordinates verification using "bignum" library.)
Line 374: Line 374:
=={{header|Nim}}==
=={{header|Nim}}==


{{libheader|base58|0.1.1}}
{{libheader|bignum|1.0.4}}
{{libheader|nimcrypto|0.3.8}}
{{libheader|nimcrypto|0.5.4}}
{{works with|Nim Compiler|0.19.4}}
{{works with|Nim Compiler|1.4.0}}


These libraries can be found on <code>nimble</code>.
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.


<lang nim>import parseutils
<lang nim>import parseutils
import base58 / bitcoin
import nimcrypto
import bignum
import nimcrypto / [hash, sha2, ripemd]

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] =
func hexToByteSeq(s: string): seq[byte] =
## Convert a hexadecimal string to a sequence of bytes.

var pos = 0
var pos = 0
while pos < s.len:
while pos < s.len:
Line 394: Line 420:
else:
else:
raise newException(ValueError, "Invalid hex string")
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 =
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
let pubPoint = 4u8 & x.hexToByteSeq & y.hexToByteSeq
if pubPoint.len != 65:
if pubPoint.len != 65:
raise newException(ValueError, "Invalid pubpoint string")
raise newException(ValueError, "Invalid pubpoint string")

var rmd = @(ripemd160.digest(sha256.digest(pubPoint).data).data)
var rmd = @(ripemd160.digest(sha256.digest(pubPoint).data).data)
rmd.insert 0u8
rmd.insert 0u8
rmd.add sha256.digest(sha256.digest(rmd).data).data[0..3]
rmd.add sha256.digest(sha256.digest(rmd).data).data[0..3]
result = encode cast[string](rmd)
result = base58Encode(rmd)


when isMainModule:
when isMainModule:
echo addrEncode("50863AD64A87AE8A2FE83C1AF1A8403CB53F53E486D8511DAD8A04887E5B2352",
let address = addrEncode("50863AD64A87AE8A2FE83C1AF1A8403CB53F53E486D8511DAD8A04887E5B2352",
"2CD470243453A299FA9E77237716103ABC11A1DF38855ED6F2EE187E9C582BA6")</lang>
"2CD470243453A299FA9E77237716103ABC11A1DF38855ED6F2EE187E9C582BA6")
echo "Coordinates are valid."
echo "Address is: ", address</lang>


{{out}}
{{out}}
<pre>Coordinates are valid.
<pre>16UwLL9Risc3QfPqBUvKofHmBQ7wMtjvM</pre>
Address is: 16UwLL9Risc3QfPqBUvKofHmBQ7wMtjvM</pre>


=={{header|Perl}}==
=={{header|Perl}}==