nim-eth/tests/keys/test_keys.nim

259 lines
9.6 KiB
Nim

#
# Ethereum P2P
# (c) Copyright 2018
# Status Research & Development GmbH
#
# See the file "LICENSE", included in this
# distribution, for details about the copyright.
#
{.used.}
import unittest
import eth/keys, bearssl
import nimcrypto/hash, nimcrypto/keccak, nimcrypto/utils
from strutils import toLowerAscii
import stew/byteutils
proc compare(x: openarray[byte], y: openarray[byte]): bool =
result = len(x) == len(y)
if result:
for i in 0..(len(x) - 1):
if x[i] != y[i]:
result = false
break
let message = "message".toBytes()
let rng = newRng()
const
pkbytes = "58d23b55bc9cdce1f18c2500f40ff4ab7245df9a89505e9b1fa4851f623d241d"
address = "dc544d1aa88ff8bbd2f2aec754b1f1e99e1812fd"
alice = [
"9c0257114eb9399a2985f8e75dad7600c5d89fe3824ffa99ec1c3eb8bf3b0501",
"""5eed5fa3a67696c334762bb4823e585e2ee579aba3558d9955296d6c04541b42
6078dbd48d74af1fd0c72aa1a05147cf17be6b60bdbed6ba19b08ec28445b0ca""",
"""b20e2ea5d3cbaa83c1e0372f110cf12535648613b479b64c1a8c1a20c5021f38
0434d07ec5795e3f789794351658e80b7faf47a46328f41e019d7b853745cdfd01"""
]
bob = [
"38e47a7b719dce63662aeaf43440326f551b8a7ee198cee35cb5d517f2d296a2",
"""347746ccb908e583927285fa4bd202f08e2f82f09c920233d89c47c79e48f937
d049130e3d1c14cf7b21afefc057f71da73dec8e8ff74ff47dc6a574ccd5d570""",
"""5c48ea4f0f2257fa23bd25e6fcb0b75bbe2ff9bbda0167118dab2bb6e31ba76e
691dbdaf2a231fc9958cd8edd99507121f8184042e075cf10f98ba88abff1f3601"""
]
eve = [
"876be0999ed9b7fc26f1b270903ef7b0c35291f89407903270fea611c85f515c",
"""c06641f0d04f64dba13eac9e52999f2d10a1ff0ca68975716b6583dee0318d91
e7c2aed363ed22edeba2215b03f6237184833fd7d4ad65f75c2c1d5ea0abecc0""",
"""babeefc5082d3ca2e0bc80532ab38f9cfb196fb9977401b2f6a98061f15ed603
603d0af084bf906b2cdf6cdde8b2e1c3e51a41af5e9adec7f3643b3f1aa2aadf00"""
]
suite "ECC/ECDSA/ECDHE tests suite":
test "Known private to known public keys (test data from Ethereum eth-keys)":
for person in [alice, bob, eve]:
let privkey = PrivateKey.fromHex(person[0])[]
var pubkeyHex = $privkey.toPublicKey()
check:
pubkeyHex == stripSpaces(person[1])
test "Recover public key from message":
for person in [alice, bob, eve]:
let privkey = PrivateKey.fromHex(person[0])[]
let signature = privkey.sign(message)
let recoveredKey = signature.recover(message)[]
check:
$privkey.toPublicKey() == $recoveredKey
test "Signature serialization and deserialization":
for person in [alice, bob, eve]:
let privkey = PrivateKey.fromHex(person[0])[]
let signature = privkey.sign(message)
let expectSignature = Signature.fromHex(stripSpaces(person[2]))[]
check:
$signature == $expectSignature
test "test_recover_from_signature_obj":
var s = PrivateKey.fromHex(pkbytes)[]
var mhash = keccak256.digest(message)
var signature = s.sign(message)
var p = recover(signature, SkMessage(mhash.data))[]
check:
s.toPublicKey() == p
test "test_to_address_from_public_key":
var s = PrivateKey.fromHex(pkbytes)[]
var chk = s.toPublicKey().toAddress()
var expect = "0x" & address
check chk == expect
test "test_to_canonical_address_from_public_key":
var s = PrivateKey.fromHex(pkbytes)[]
var chk = s.toPublicKey().toCanonicalAddress()
var expect = fromHex(stripSpaces(address))
check compare(chk, expect) == true
test "test_to_checksum_address_from_public_key":
var s = PrivateKey.fromHex(pkbytes)[]
var chk = s.toPublicKey().toChecksumAddress()
var expect = "0x" & address
check:
chk.toLowerAscii() == expect
test "EIP-55 checksum addresses test cases":
var checks = [
"0xfB6916095ca1df60bB79Ce92cE3Ea74c37c5d359",
"0x52908400098527886E0F7030069857D2E4169EE7",
"0x8617E340B3D01FA5F11F306F4090FD50E238070D",
"0xde709f2102306220921060314715629080e2fb77",
"0x27b1fdb04752bbc536007a920d24acb045561c26",
"0x5aAeb6053F3E94C9b9A09f33669435E7Ef1BeAed",
"0xfB6916095ca1df60bB79Ce92cE3Ea74c37c5d359",
"0xdbF03B407c01E7cD3CBea99509d93f8DDDC8C6FB",
"0xD1220A0cf47c7B9Be7A2E6BA89F429762e7b9aDb"
]
var badchecks = [
"",
"0xXB6916095ca1df60bB79Ce92cE3Ea74c37c5d359",
"0xfB6916095ca1df60bB79Ce92cE3Ea74c37c5d35X",
"0XfB6916095ca1df60bB79Ce92cE3Ea74c37c5d359",
"XXfB6916095ca1df60bB79Ce92cE3Ea74c37c5d359",
"0xfB6916095"
]
for item in checks:
check validateChecksumAddress(item) == true
for item in badchecks:
check validateChecksumAddress(item) == false
test "EIP-55 100 addresses":
for i in 1..100:
var kp = KeyPair.random(rng[])
var chaddress = kp.pubkey.toChecksumAddress()
var noaddress = kp.pubkey.toAddress()
if noaddress != chaddress:
check validateChecksumAddress(noaddress) == false
check validateChecksumAddress(chaddress) == true
test "ECDHE/py-evm test_ecies.py#L19":
# ECDHE test vectors
# Copied from
# https://github.com/ethereum/py-evm/blob/master/tests/p2p/test_ecies.py#L19
const privateKeys = [
"332143e9629eedff7d142d741f896258f5a1bfab54dab2121d3ec5000093d74b",
"7ebbc6a8358bc76dd73ebc557056702c8cfc34e5cfcd90eb83af0347575fd2ad"
]
const publicKeys = [
"""f0d2b97981bd0d415a843b5dfe8ab77a30300daab3658c578f2340308a2da1a07
f0821367332598b6aa4e180a41e92f4ebbae3518da847f0b1c0bbfe20bcf4e1""",
"""83ede0f19c3c98649265956a4193677b14c338a22de2086a08d84e4446fe37e4e
233478259ec90dbeef52f4f6c890f8c38660ec7b61b9d439b8a6d1c323dc025"""
]
const sharedSecrets = [
"ee1418607c2fcfb57fda40380e885a707f49000a5dda056d828b7d9bd1f29a08",
"167ccc13ac5e8a26b131c3446030c60fbfac6aa8e31149d0869f93626a4cdf62"
]
for i in 0..1:
var s = PrivateKey.fromHex(privateKeys[i])[]
var p = PublicKey.fromHex(stripSpaces(publicKeys[i]))[]
let expect = fromHex(stripSpaces(sharedSecrets[i]))
let secret = ecdhRaw(s, p)
check:
expect == secret.data
test "ECDHE/cpp-ethereum crypto.cpp#L394":
# ECDHE test vectors
# Copied from https://github.com/ethereum/cpp-ethereum/blob/develop/test/unittests/libdevcrypto/crypto.cpp#L394
var expectm = """
8ac7e464348b85d9fdfc0a81f2fdc0bbbb8ee5fb3840de6ed60ad9372e718977"""
var s = PrivateKey.fromRaw(keccak256.digest("ecdhAgree").data)[]
var p = s.toPublicKey()
let expect = fromHex(stripSpaces(expectm))
let secret = ecdhRaw(s, p)
check:
expect == secret.data
test "ECDHE/cpp-ethereum rlpx.cpp#L425":
# ECDHE test vectors
# Copied from https://github.com/ethereum/cpp-ethereum/blob/2409d7ec7d34d5ff5770463b87eb87f758e621fe/test/unittests/libp2p/rlpx.cpp#L425
var s0 = """
332143e9629eedff7d142d741f896258f5a1bfab54dab2121d3ec5000093d74b"""
var p0 = """
f0d2b97981bd0d415a843b5dfe8ab77a30300daab3658c578f2340308a2da1a0
7f0821367332598b6aa4e180a41e92f4ebbae3518da847f0b1c0bbfe20bcf4e1"""
var e0 = """
ee1418607c2fcfb57fda40380e885a707f49000a5dda056d828b7d9bd1f29a08"""
var s = PrivateKey.fromHex(stripSpaces(s0))[]
var p = PublicKey.fromHex(stripSpaces(p0))[]
let expect = fromHex(stripSpaces(e0))
let secret = ecdhRaw(s, p)
check:
compare(expect, secret.data) == true
test "ECDSA/cpp-ethereum crypto.cpp#L132":
# ECDSA test vectors
# Copied from https://github.com/ethereum/cpp-ethereum/blob/develop/test/unittests/libdevcrypto/crypto.cpp#L132
var signature = """
b826808a8c41e00b7c5d71f211f005a84a7b97949d5e765831e1da4e34c9b8295d
2a622eee50f25af78241c1cb7cfff11bcf2a13fe65dee1e3b86fd79a4e3ed000"""
var pubkey = """
e40930c838d6cca526795596e368d16083f0672f4ab61788277abfa23c3740e1cc
84453b0b24f49086feba0bd978bb4446bae8dff1e79fcc1e9cf482ec2d07c3"""
var check1 = fromHex(stripSpaces(signature))
var check2 = fromHex(stripSpaces(pubkey))
var s = PrivateKey.fromRaw(keccak256.digest("sec").data)[]
var m = keccak256.digest("msg")
var sig = sign(s, SkMessage(m.data))
var sersig = sig.toRaw()
var key = recover(sig, SkMessage(m.data))[]
var serkey = key.toRaw()
check:
compare(sersig, check1) == true
compare(serkey, check2) == true
test "ECDSA/100 signatures":
# signature test
for i in 1..100:
var m: array[32, byte]
brHmacDrbgGenerate(rng[], m)
var s = PrivateKey.random(rng[])
var key = s.toPublicKey()
let sig = sign(s, SkMessage(m))
let rkey = recover(sig, SkMessage(m))[]
check:
key == rkey
test "KEYS/100 create/recovery keys":
# key create/recovery test
for i in 1..100:
var s = PrivateKey.random(rng[])
var key = s.toPublicKey()
let rkey = PublicKey.fromRaw(key.toRaw())[]
check:
key == rkey
test "ECDHE/100 shared secrets":
# ECDHE shared secret test
for i in 1..100:
var aliceSecret = PrivateKey.random(rng[])
var alicePublic = aliceSecret.toPublicKey()
var bobSecret = PrivateKey.random(rng[])
var bobPublic = bobSecret.toPublicKey()
var secret1 = ecdhRaw(aliceSecret, bobPublic)
var secret2 = ecdhRaw(bobSecret, alicePublic)
check:
secret1 == secret2
test "Compressed public keys":
let pubkeyCompressed = "03CA634CAE0D49ACB401D8A4C6B6FE8C55B70D115BF400769CC1400F3258CD3138".toLowerAscii
let s = PublicKey.fromHex(pubkeyCompressed)[]
check:
s.toRaw.toHex == """CA634CAE0D49ACB401D8A4C6B6FE8C55B70D115BF400769CC1400F3258
CD31387574077F301B421BC84DF7266C44E9E6D569FC56BE00812904767BF5CCD1FC7F""".stripSpaces.toLowerAscii
s.toRawCompressed.toHex == pubkeyCompressed