nim-eth/tests/keys/test_keys.nim

278 lines
10 KiB
Nim

#
# Ethereum P2P
# (c) Copyright 2018
# Status Research & Development GmbH
#
# See the file "LICENSE", included in this
# distribution, for details about the copyright.
#
import unittest
import eth/keys
import nimcrypto/hash, nimcrypto/keccak, nimcrypto/utils
from strutils import toLowerAscii
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
const
pkbytes = "58d23b55bc9cdce1f18c2500f40ff4ab7245df9a89505e9b1fa4851f623d241d"
message = "message"
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 = initPrivateKey(person[0])
var pubkeyHex = $privkey.getPublicKey()
check:
pubkeyHex == stripSpaces(person[1])
test "Recover public key from message":
for person in [alice, bob, eve]:
let privkey = initPrivateKey(person[0])
let signature = privkey.signMessage(message)
let recoveredKey = signature.recoverKeyFromSignature(message)
check:
$privkey.getPublicKey() == $recoveredKey
test "Signature serialization and deserialization":
for person in [alice, bob, eve]:
let privkey = initPrivateKey(person[0])
let signature = privkey.signMessage(message)
let expectSignature = initSignature(person[2])
check:
$signature == $expectSignature
test "test_signing_from_private_key_obj":
var s = initPrivateKey(pkbytes)
var signature = s.signMessage(message)
var mhash = keccak256.digest(message)
check verifyMessage(signature.data, mhash) == true
test "test_recover_from_signature_obj":
var s = initPrivateKey(pkbytes)
var mhash = keccak256.digest(message)
var signature = s.signMessage(message)
var p = recoverKeyFromSignature(signature, mhash)
check:
s.getPublicKey() == p
test "test_to_address_from_public_key":
var s = initPrivateKey(pkbytes)
var chk = s.getPublicKey().toAddress()
var expect = "0x" & address
check chk == expect
test "test_to_canonical_address_from_public_key":
var s = initPrivateKey(pkbytes)
var chk = s.getPublicKey().toCanonicalAddress()
var expect = fromHex(stripSpaces(address))
check compare(chk, expect) == true
test "test_to_checksum_address_from_public_key":
var s = initPrivateKey(pkbytes)
var chk = s.getPublicKey().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 = newKeyPair()
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"
]
var secret: SharedSecret
for i in 0..1:
var s = privateKeys[i].initPrivateKey()
var p = publicKeys[i].initPublicKey()
let expect = fromHex(stripSpaces(sharedSecrets[i]))
check:
ecdhAgree(s, p, secret) == EthKeysStatus.Success
compare(expect, secret.data) == true
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 secret: SharedSecret
var s = initPrivateKey(keccak256.digest("ecdhAgree").data)
var p = s.getPublicKey()
let expect = fromHex(stripSpaces(expectm))
check:
ecdhAgree(s, p, secret) == EthKeysStatus.Success
compare(expect, secret.data) == true
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 secret: SharedSecret
var s = initPrivateKey(s0)
var p = initPublicKey(p0)
let expect = fromHex(stripSpaces(e0))
check:
ecdhAgree(s, p, secret) == Success
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 sig: Signature
var key: PublicKey
var s = initPrivateKey(keccak256.digest("sec").data)
var m = keccak256.digest("msg").data
check signRawMessage(m, s, sig) == Success
var sersig = sig.getRaw()
check recoverSignatureKey(sersig, m, key) == Success
var serkey = key.getRaw()
check:
compare(sersig, check1) == true
compare(serkey, check2) == true
test "ECDSA/100 signatures":
# signature test
var rkey: PublicKey
var sig: Signature
for i in 1..100:
var m = newPrivateKey().data
var s = newPrivateKey()
var key = s.getPublicKey()
check signRawMessage(m, s, sig) == Success
var sersig = sig.getRaw()
check:
recoverSignatureKey(sersig, m, rkey) == Success
key == rkey
test "KEYS/100 create/recovery keys":
# key create/recovery test
var rkey: PublicKey
for i in 1..100:
var s = newPrivateKey()
var key = s.getPublicKey()
check:
recoverPublicKey(key.getRaw(), rkey) == Success
key == rkey
test "ECDHE/100 shared secrets":
# ECDHE shared secret test
var secret1, secret2: SharedSecret
for i in 1..100:
var aliceSecret = newPrivateKey()
var alicePublic = aliceSecret.getPublicKey()
var bobSecret = newPrivateKey()
var bobPublic = bobSecret.getPublicKey()
check:
ecdhAgree(aliceSecret, bobPublic, secret1) == Success
ecdhAgree(bobSecret, alicePublic, secret2) == Success
secret1 == secret2
test "isZeroKey() checks":
var seckey1: PrivateKey
var pubkey1: PublicKey
var seckey2 = newPrivateKey()
var pubkey2 = seckey2.getPublicKey()
check:
seckey1.isZeroKey() == true
pubkey1.isZeroKey() == true
seckey2.isZeroKey() == false
pubkey2.isZeroKey() == false
test "Compressed public keys":
let pubkeyCompressed = "03CA634CAE0D49ACB401D8A4C6B6FE8C55B70D115BF400769CC1400F3258CD3138"
let s = initPublicKey(pubkeyCompressed)
check:
s.getRaw.toHex == """CA634CAE0D49ACB401D8A4C6B6FE8C55B70D115BF400769CC1400F3258
CD31387574077F301B421BC84DF7266C44E9E6D569FC56BE00812904767BF5CCD1FC7F""".stripSpaces
s.getRawCompressed.toHex == pubkeyCompressed