From 92bdd416437c3f5f539864a796c2a8e9e89b1c2d Mon Sep 17 00:00:00 2001 From: mratsim Date: Wed, 21 Mar 2018 15:54:41 +0100 Subject: [PATCH] Remove ttmath and allow compilation to C, change "private" field names. --- eth_keys.nimble | 9 +++-- src/backend_libsecp256k1/libsecp256k1.nim | 2 +- src/datatypes.nim | 39 ++++--------------- src/datatypes_interface.nim | 8 ++-- tests/all_tests.nim | 10 ++++- tests/config.nim | 14 ++++--- .../test_key_and_signature_datastructures.nim | 22 +++++------ tests/test_private_public_key_consistency.nim | 4 +- ...m => test_ttmath_hex_bytes_conversion.nim} | 17 ++++++++ 9 files changed, 65 insertions(+), 60 deletions(-) rename tests/{test_hex_bytes_conversion.nim => test_ttmath_hex_bytes_conversion.nim} (53%) diff --git a/eth_keys.nimble b/eth_keys.nimble index 1f42757..3cc9939 100644 --- a/eth_keys.nimble +++ b/eth_keys.nimble @@ -9,7 +9,7 @@ srcDir = "src" requires "nim >= 0.18.0", "keccak_tiny >= 0.1.0", "ttmath >= 0.1.0", "nimSHA2", "secp256k1" -proc test(name: string, lang: string = "cpp") = +proc test(name: string, lang: string = "c") = if not dirExists "build": mkDir "build" if not dirExists "nimcache": @@ -19,9 +19,12 @@ proc test(name: string, lang: string = "cpp") = switch("out", ("./build/" & name)) setCommand lang, "tests/" & name & ".nim" -task test, "Run all tests - libsecp256k1 backend": +task test, "Run all tests - C & libsecp256k1 backend": test "all_tests" +task test_cpp, "Run all tests - C++ & libsecp256k1 backend": + test "all_tests", "cpp" + task test_backend_native, "Run all tests - pure Nim backend": switch("define", "backend_native") - test "all_tests" + test "all_tests", "cpp" diff --git a/src/backend_libsecp256k1/libsecp256k1.nim b/src/backend_libsecp256k1/libsecp256k1.nim index 718eade..20198e1 100644 --- a/src/backend_libsecp256k1/libsecp256k1.nim +++ b/src/backend_libsecp256k1/libsecp256k1.nim @@ -7,7 +7,7 @@ # # at your option. This file may not be copied, modified, or distributed except according to those terms. -import ../datatypes +import ../datatypes, ../private/conversion_bytes import secp256k1, keccak_tiny const SECP256K1_CONTEXT_ALL = SECP256K1_CONTEXT_VERIFY or SECP256K1_CONTEXT_SIGN diff --git a/src/datatypes.nim b/src/datatypes.nim index f885a21..9c07c1c 100644 --- a/src/datatypes.nim +++ b/src/datatypes.nim @@ -8,42 +8,19 @@ # at your option. This file may not be copied, modified, or distributed except according to those terms. import ./private/conversion_bytes -export toHex, hexToByteArrayBE, hexToSeqByteBE - -# Note: Fields are intentionally kept private +# Note: Fields F should be private, it is intentionally ugly to directly access them +# See private field access issue: https://github.com/nim-lang/Nim/issues/7390 type PublicKey* = object - Fraw_key: array[64, byte] + Fraw_key*: array[64, byte] PrivateKey* = object - Fraw_key: array[32, byte] - Fpublic_key: PublicKey + Fraw_key*: array[32, byte] + Fpublic_key*: PublicKey Signature* {.packed.}= object - Fr: array[32, byte] - Fs: array[32, byte] - Fv: range[0.byte .. 1.byte] + Fr*: array[32, byte] + Fs*: array[32, byte] + Fv*: range[0.byte .. 1.byte] # This should be 27..28 as per Ethereum but it's 0..1 in eth-keys ... - -# "Public" accessors, only exposed to internal modules - -template genAccessors(name: untyped, fieldType, objType: typedesc): untyped = - # Access - proc name*(obj: objType): fieldType {.noSideEffect, inline, noInit.} = - obj.`F name` - - # Assignement - proc `name=`*(obj: var objType, value: fieldType): fieldType {.noSideEffect, inline.} = - obj.`F name` = value - - # Mutable - proc `name`*(obj: var objType): var fieldType {.noSideEffect, inline.} = - obj.`F name` - -genAccessors(raw_key, array[64, byte], PublicKey) -genAccessors(raw_key, array[32, byte], PrivateKey) -genAccessors(public_key, PublicKey, PrivateKey) -genAccessors(s, array[32, byte], Signature) -genAccessors(r, array[32, byte], Signature) -genAccessors(v, range[0.byte .. 1.byte], Signature) diff --git a/src/datatypes_interface.nim b/src/datatypes_interface.nim index ea20d7d..494f396 100644 --- a/src/datatypes_interface.nim +++ b/src/datatypes_interface.nim @@ -13,7 +13,7 @@ # Note: for now only a native pure Nim backend is supported # In the future alternative, proven crypto backend will be added like libsecpk1 -import ./datatypes +import ./datatypes, ./private/conversion_bytes import keccak_tiny @@ -30,8 +30,8 @@ else: # Initialization proc initPrivateKey*(hexString: string): PrivateKey {.noInit.} = - hexToByteArrayBE(hexString, result.raw_key) - result.public_key = private_key_to_public_key(result) + hexToByteArrayBE(hexString, result.Fraw_key) + result.Fpublic_key = private_key_to_public_key(result) proc initPublicKey*(hexString: string): PublicKey {.noInit.} = var b: array[65, byte] @@ -67,4 +67,4 @@ proc sign_msg*(key: PrivateKey, message_hash: Hash[256]): Signature {.inline.} = ecdsa_sign(key, message_hash) proc `$`*(key: PrivateKey): string {.inline.} = - key.raw_key.toHex() + key.Fraw_key.toHex() diff --git a/tests/all_tests.nim b/tests/all_tests.nim index 0617698..65a7bc4 100644 --- a/tests/all_tests.nim +++ b/tests/all_tests.nim @@ -9,9 +9,15 @@ when defined(backend_native): echo "\nBackend tested: native\n" + when defined(c): + {.fatal: "The native backend require C++ compilation for ttmath.}".} else: echo "\nBackend tested: libsecp256k1\n" + when not defined(cpp): + echo "C backend chosen. Skipping ttmath_hex_bytes_conversion test" -import ./test_hex_bytes_conversion, - ./test_private_public_key_consistency, +when defined(cpp): + import ./test_ttmath_hex_bytes_conversion + +import ./test_private_public_key_consistency, ./test_key_and_signature_datastructures diff --git a/tests/config.nim b/tests/config.nim index 77d0e56..c956468 100644 --- a/tests/config.nim +++ b/tests/config.nim @@ -41,14 +41,16 @@ let MSG* = "message" MSGHASH* = keccak256(MSG) +# Conversion done through https://www.mobilefish.com/services/big_number/big_number.php + let alice* = testKeySig( privkey: "9c0257114eb9399a2985f8e75dad7600c5d89fe3824ffa99ec1c3eb8bf3b0501", pubkey: "5eed5fa3a67696c334762bb4823e585e2ee579aba3558d9955296d6c04541b426078dbd48d74af1fd0c72aa1a05147cf17be6b60bdbed6ba19b08ec28445b0ca", raw_sig: ( v: 1, - r: "80536744857756143861726945576089915884233437828013729338039544043241440681784", - s: "1902566422691403459035240420865094128779958320521066670269403689808757640701" + r: "B20E2EA5D3CBAA83C1E0372F110CF12535648613B479B64C1A8C1A20C5021F38", # Decimal "80536744857756143861726945576089915884233437828013729338039544043241440681784", + s: "434D07EC5795E3F789794351658E80B7FAF47A46328F41E019D7B853745CDFD" # Decimal "1902566422691403459035240420865094128779958320521066670269403689808757640701" ) ) @@ -57,8 +59,8 @@ let pubkey: "347746ccb908e583927285fa4bd202f08e2f82f09c920233d89c47c79e48f937d049130e3d1c14cf7b21afefc057f71da73dec8e8ff74ff47dc6a574ccd5d570", raw_sig: ( v: 1, - r: "41741612198399299636429810387160790514780876799439767175315078161978521003886", - s: "47545396818609319588074484786899049290652725314938191835667190243225814114102" + r: "5C48EA4F0F2257FA23BD25E6FCB0B75BBE2FF9BBDA0167118DAB2BB6E31BA76E", # Decimal "41741612198399299636429810387160790514780876799439767175315078161978521003886", + s: "691DBDAF2A231FC9958CD8EDD99507121F8184042E075CF10F98BA88ABFF1F36" # Decimal "47545396818609319588074484786899049290652725314938191835667190243225814114102" ) ) @@ -67,7 +69,7 @@ let pubkey: "c06641f0d04f64dba13eac9e52999f2d10a1ff0ca68975716b6583dee0318d91e7c2aed363ed22edeba2215b03f6237184833fd7d4ad65f75c2c1d5ea0abecc0", raw_sig: ( v: 0, - r: "84467545608142925331782333363288012579669270632210954476013542647119929595395", - s: "43529886636775750164425297556346136250671451061152161143648812009114516499167" + r: "BABEEFC5082D3CA2E0BC80532AB38F9CFB196FB9977401B2F6A98061F15ED603", # Decimal "84467545608142925331782333363288012579669270632210954476013542647119929595395", + s: "603D0AF084BF906B2CDF6CDDE8B2E1C3E51A41AF5E9ADEC7F3643B3F1AA2AADF" # Decimal "43529886636775750164425297556346136250671451061152161143648812009114516499167" ) ) diff --git a/tests/test_key_and_signature_datastructures.nim b/tests/test_key_and_signature_datastructures.nim index 3c30038..1561445 100644 --- a/tests/test_key_and_signature_datastructures.nim +++ b/tests/test_key_and_signature_datastructures.nim @@ -7,7 +7,7 @@ # # at your option. This file may not be copied, modified, or distributed except according to those terms. -import ../src/eth_keys, +import ../src/eth_keys, ../src/private/conversion_bytes, ./config import unittest @@ -19,9 +19,9 @@ suite "Test key and signature data structure": pk = initPrivateKey(person.privkey) signature = pk.sign_msg(MSG) - check: signature.v == person.raw_sig.v - check: signature.r == person.raw_sig.r.u256 - check: signature.s == person.raw_sig.s.u256 + check: signature.Fv == person.raw_sig.v + check: signature.Fr == hexToByteArrayBE[32](person.raw_sig.r) + check: signature.Fs == hexToByteArrayBE[32](person.raw_sig.s) test "Signing from private key object (ported from official eth-keys)": for person in [alice, bob, eve]: @@ -29,7 +29,7 @@ suite "Test key and signature data structure": pk = initPrivateKey(person.privkey) signature = pk.sign_msg(MSG) - check: verify_msg(pk.public_key, MSG, signature) + check: verify_msg(pk.Fpublic_key, MSG, signature) test "Hash signing from private key object": @@ -38,9 +38,9 @@ suite "Test key and signature data structure": pk = initPrivateKey(person.privkey) signature = pk.sign_msg(MSG) - check: signature.v == person.raw_sig.v - check: signature.r == person.raw_sig.r.u256 - check: signature.s == person.raw_sig.s.u256 + check: signature.Fv == person.raw_sig.v + check: signature.Fr == hexToByteArrayBE[32](person.raw_sig.r) + check: signature.Fs == hexToByteArrayBE[32](person.raw_sig.s) test "Hash signing from private key object (ported from official eth-keys)": for person in [alice, bob, eve]: @@ -48,7 +48,7 @@ suite "Test key and signature data structure": pk = initPrivateKey(person.privkey) signature = pk.sign_msg(MSGHASH) - check: verify_msg(pk.public_key, MSGHASH, signature) + check: verify_msg(pk.Fpublic_key, MSGHASH, signature) test "Recover public key from message": for person in [alice, bob, eve]: @@ -58,7 +58,7 @@ suite "Test key and signature data structure": recovered_pubkey = recover_pubkey_from_msg(MSG, signature) - check: pk.public_key == recovered_pubkey + check: pk.Fpublic_key == recovered_pubkey test "Recover public key from message hash": for person in [alice, bob, eve]: @@ -68,4 +68,4 @@ suite "Test key and signature data structure": recovered_pubkey = recover_pubkey_from_msg(MSGHASH, signature) - check: pk.public_key == recovered_pubkey + check: pk.Fpublic_key == recovered_pubkey diff --git a/tests/test_private_public_key_consistency.nim b/tests/test_private_public_key_consistency.nim index ad877ec..cb1945f 100644 --- a/tests/test_private_public_key_consistency.nim +++ b/tests/test_private_public_key_consistency.nim @@ -17,6 +17,6 @@ suite "Testing private -> public key conversion": for person in [alice, bob, eve]: let privkey = initPrivateKey(person.privkey) - let computed_pubkey = $privkey.public_key + let computed_pubkey = $privkey.Fpublic_key - check: computed_pubkey == person.pubkey \ No newline at end of file + check: computed_pubkey == person.pubkey diff --git a/tests/test_hex_bytes_conversion.nim b/tests/test_ttmath_hex_bytes_conversion.nim similarity index 53% rename from tests/test_hex_bytes_conversion.nim rename to tests/test_ttmath_hex_bytes_conversion.nim index ead4234..a4da43e 100644 --- a/tests/test_hex_bytes_conversion.nim +++ b/tests/test_ttmath_hex_bytes_conversion.nim @@ -10,6 +10,7 @@ import ../src/private/[conversion_bytes, conversion_ttmath] import unittest, ttmath, strutils # TODO remove ttmath needs if backend libsecp256k1 +import ./config suite "Testing conversion functions: Hex, Bytes, Endianness": let @@ -27,3 +28,19 @@ suite "Testing conversion functions: Hex, Bytes, Endianness": test "uint256 -> big-endian array -> hex": check: SECPK1_N.toByteArrayBE.toHex == SECPK1_N_HEX + +suite "Confirming consistency: hex vs decimal conversion": + # Conversion done through https://www.mobilefish.com/services/big_number/big_number.php + + test "Alice signature": + check: alice.raw_sig.r.hexToUInt256 == "80536744857756143861726945576089915884233437828013729338039544043241440681784".u256 + check: alice.raw_sig.s.hexToUInt256 == "1902566422691403459035240420865094128779958320521066670269403689808757640701".u256 + + test "Bob signature": + check: alice.raw_sig.r.hexToUInt256 == "41741612198399299636429810387160790514780876799439767175315078161978521003886".u256 + check: alice.raw_sig.s.hexToUInt256 == "47545396818609319588074484786899049290652725314938191835667190243225814114102".u256 + + test "Eve signature": + check: alice.raw_sig.r.hexToUInt256 == "84467545608142925331782333363288012579669270632210954476013542647119929595395".u256 + check: alice.raw_sig.s.hexToUInt256 == "43529886636775750164425297556346136250671451061152161143648812009114516499167".u256 +