mirror of
https://github.com/status-im/nim-eth-keys.git
synced 2025-02-17 19:56:25 +00:00
Fix native backend compilation (static types only) (#4)
* Fix types * Fix compilation of native backends (implementation tests still fails)
This commit is contained in:
parent
18b8617d37
commit
5e192ebec9
@ -19,5 +19,9 @@ proc test(name: string, lang: string = "cpp") =
|
||||
switch("out", ("./build/" & name))
|
||||
setCommand lang, "tests/" & name & ".nim"
|
||||
|
||||
task test, "Run all tests":
|
||||
task test, "Run all tests - libsecp256k1 backend":
|
||||
test "all_tests"
|
||||
|
||||
task test_backend_native, "Run all tests - pure Nim backend":
|
||||
switch("define", "backend_native")
|
||||
test "all_tests"
|
||||
|
@ -1,30 +1,55 @@
|
||||
# Copyright (c) 2018 Status Research & Development GmbH
|
||||
# Distributed under the MIT License (license terms are at http://opensource.org/licenses/MIT).
|
||||
|
||||
import ../datatypes, ../private/[array_utils, casting],
|
||||
import ../datatypes, ../private/[array_utils, lowlevel_types],
|
||||
./jacobian, ./mod_arithmetic, ./hmac, ./constants
|
||||
|
||||
import ttmath, keccak_tiny, strutils,
|
||||
nimsha2 # TODO: For SHA-256, use OpenSSL instead? (see https://rosettacode.org/wiki/SHA-256#Nim)
|
||||
|
||||
|
||||
proc decode_public_key(pubKey: ByteArrayBE[64]
|
||||
): array[2, UInt256] {.noInit,inline,noSideEffect.} =
|
||||
|
||||
# Slicing with "result[0] = readUint256BE pubKey[0 ..< 32]" would allocate an intermediary seq
|
||||
# See https://github.com/nim-lang/Nim/issues/5753#issuecomment-369597564
|
||||
|
||||
# Workaround: pointers
|
||||
var
|
||||
pk1, pk2: ptr array[32, byte]
|
||||
|
||||
shallowCopy(pk1, cast[type pk1](pubkey[0].unsafeAddr))
|
||||
shallowCopy(pk2, cast[type pk2](pubkey[32].unsafeAddr))
|
||||
|
||||
result[0] = readUint256BE pk1[]
|
||||
result[1] = readUint256BE pk2[]
|
||||
|
||||
proc encode_raw_public_key(pubKeyInt: array[2, Uint256]
|
||||
): ByteArrayBE[64] {.noInit,inline,noSideEffect.}=
|
||||
|
||||
result[0 ..< 32] = pubKeyInt[0].toByteArrayBE
|
||||
result[32 ..< 64] = pubKeyInt[1].toByteArrayBE
|
||||
|
||||
proc private_key_to_public_key*(key: PrivateKey): PublicKey {.noInit.}=
|
||||
# TODO: allow to switch implementation based on backend
|
||||
|
||||
if key.raw_key >= SECPK1_N: # TODO use ranged type
|
||||
let keyInt = key.raw_key.readUint256BE
|
||||
|
||||
if keyInt >= SECPK1_N: # TODO use ranged type
|
||||
raise newException(ValueError, "Invalid private key")
|
||||
|
||||
result.raw_key = fast_multiply(SECPK1_G, key.raw_key)
|
||||
result.raw_key = encode_raw_public_key fast_multiply(SECPK1_G, keyInt)
|
||||
|
||||
proc ecdsa_raw_verify*(msg_hash: Hash[256], vrs: Signature, key: PublicKey): bool =
|
||||
let
|
||||
w = invmod(vrs.s, SECPK1_N)
|
||||
z = msg_hash.toUInt256
|
||||
z = readUint256BE cast[ByteArrayBE[32]](msg_hash)
|
||||
|
||||
u1 = mulmod(z, w, SECPK1_N)
|
||||
u2 = mulmod(vrs.r, w, SECPK1_N)
|
||||
xy = fast_add(
|
||||
fast_multiply(SECPK1_G, u1),
|
||||
fast_multiply(key.raw_key, u2)
|
||||
fast_multiply(key.raw_key.decode_public_key, u2)
|
||||
)
|
||||
result = vrs.r == xy[0] and vrs.r.isOdd and vrs.s.isOdd
|
||||
|
||||
@ -35,23 +60,23 @@ proc deterministic_generate_k(msg_hash: Hash[256], key: PrivateKey): UInt256 =
|
||||
|
||||
let
|
||||
# TODO: avoid heap allocation
|
||||
k_1 = k_0.hmac_sha256(@v_0 & @[0x00.byte] & @(toByteArray(key.raw_key)) & @(msg_hash.data))
|
||||
k_1 = k_0.hmac_sha256(@v_0 & @[0x00.byte] & @(key.raw_key) & @(msg_hash.data))
|
||||
v_1 = cast[array[32, byte]](k_1.hmac_sha256(@v_0))
|
||||
k_2 = k_1.hmac_sha256(@v_1 & @[0x01.byte] & @(toByteArray(key.raw_key)) & @(msg_hash.data))
|
||||
k_2 = k_1.hmac_sha256(@v_1 & @[0x01.byte] & @(key.raw_key) & @(msg_hash.data))
|
||||
v_2 = k_2.hmac_sha256(@v_1)
|
||||
|
||||
kb = k_2.hmac_sha256(@v_2)
|
||||
|
||||
result = kb.toUInt256
|
||||
result = readUint256BE cast[ByteArrayBE[32]](kb)
|
||||
|
||||
proc ecdsa_raw_sign*(msg_hash: Hash[256], key: PrivateKey): Signature =
|
||||
proc ecdsa_sign*(key: PrivateKey, msg_hash: Hash[256]): Signature {.noInit.} =
|
||||
modulo(SECPK1_N):
|
||||
let
|
||||
z = msg_hash.toUInt256
|
||||
z = readUint256BE cast[ByteArrayBE[32]](msg_hash)
|
||||
k = deterministic_generate_k(msg_hash, key)
|
||||
|
||||
ry = fast_multiply(SECPK1_G, k)
|
||||
s_raw = invmod(k, SECPK1_N) * (z + ry[0] * key.raw_key)
|
||||
s_raw = invmod(k, SECPK1_N) * (z + ry[0] * key.raw_key.readUint256BE)
|
||||
|
||||
result.v = uint8 getUint `xor`(
|
||||
ry[1] mod 2.u256,
|
||||
@ -61,7 +86,7 @@ proc ecdsa_raw_sign*(msg_hash: Hash[256], key: PrivateKey): Signature =
|
||||
else: SECPK1_N - s_raw
|
||||
result.r = ry[0]
|
||||
|
||||
proc ecdsa_raw_recover*(msg_hash: Hash[256], vrs: Signature): PublicKey {.noInit.} =
|
||||
proc ecdsa_recover*(msg_hash: Hash[256], vrs: Signature): PublicKey {.noInit.} =
|
||||
modulo(SECPK1_P):
|
||||
let
|
||||
x = vrs.r
|
||||
@ -78,7 +103,7 @@ proc ecdsa_raw_recover*(msg_hash: Hash[256], vrs: Signature): PublicKey {.noInit
|
||||
raise newException(ValueError, "Bad signature")
|
||||
|
||||
let
|
||||
z = msg_hash.toUInt256
|
||||
z = readUint256BE cast[ByteArrayBE[32]](msg_hash)
|
||||
Gz = jacobian_multiply(
|
||||
[SECPK1_Gx, SECPK1_Gy,1.u256],
|
||||
submod(SECPK1_N, z, SECPK1_N)
|
||||
@ -90,4 +115,14 @@ proc ecdsa_raw_recover*(msg_hash: Hash[256], vrs: Signature): PublicKey {.noInit
|
||||
Qr = jacobian_add(Gz, XY)
|
||||
Q = jacobian_multiply(Qr, invmod(vrs.r, SECPK1_N))
|
||||
|
||||
result.raw_key = from_jacobian(Q)
|
||||
result.raw_key = encode_raw_public_key from_jacobian(Q)
|
||||
|
||||
proc serialize*(key: PublicKey): string {.noSideEffect.}=
|
||||
## Exports a publicKey to a hex string
|
||||
|
||||
result = "04"
|
||||
|
||||
let decoded = key.raw_key.decode_public_key
|
||||
|
||||
result.add decoded[0].toHex
|
||||
result.add decoded[1].toHex
|
||||
|
@ -13,6 +13,7 @@ import keccak_tiny
|
||||
|
||||
when defined(backend_native):
|
||||
import ./backend_native/ecdsa
|
||||
export ecdsa.serialize
|
||||
else:
|
||||
import ./backend_libsecp256k1/libsecp256k1
|
||||
export libsecp256k1.serialize
|
||||
|
@ -13,31 +13,21 @@ import ttmath, strutils, strutils
|
||||
# https://www.reddit.com/r/crypto/comments/6287my/explanations_on_the_keccaksha3_paddingbyte/
|
||||
# Note: Since Nim's Keccak-Tiny only accepts string as input, endianness does not matter.
|
||||
|
||||
type ByteArrayBE*[N: static[int]] = distinct array[N, byte]
|
||||
type ByteArrayBE*[N: static[int]] = array[N, byte]
|
||||
## A byte array that stores bytes in big-endian order
|
||||
|
||||
proc `[]`*[N: static[int], I: Ordinal](ba: ByteArrayBE[N], i: I): byte {.noSideEffect, inline.}=
|
||||
(array[N,byte])(ba)[i]
|
||||
|
||||
proc `[]`*[N: static[int], I: Ordinal](ba: var ByteArrayBE[N], i: I): var byte {.noSideEffect, inline.}=
|
||||
(array[N,byte])(ba)[i]
|
||||
|
||||
proc `[]=`*[N: static[int], I: Ordinal](ba: var ByteArrayBE[N], i: I, val: byte) {.noSideEffect, inline.}=
|
||||
(array[N,byte])(ba)[i] = val
|
||||
|
||||
proc `==`*[N: static[int]](a, b: ByteArrayBE[N]): bool {.noSideEffect, inline.} =
|
||||
(array[N, byte])(a) == (array[N, byte])(b)
|
||||
|
||||
proc readUint256BE*(ba: ByteArrayBE[32]): UInt256 {.noSideEffect.}=
|
||||
proc readUint256BE*(ba: ByteArrayBE[32]): UInt256 {.noSideEffect, inline.}=
|
||||
## Convert a big-endian array of Bytes to an UInt256 (in native host endianness)
|
||||
const N = 32
|
||||
for i in 0 ..< N:
|
||||
{.unroll: 4.}
|
||||
result = result shl 8 or ba[i].u256
|
||||
|
||||
proc toByteArrayBE*(num: UInt256): ByteArrayBE[32] {.noSideEffect, noInit.}=
|
||||
proc toByteArrayBE*(num: UInt256): ByteArrayBE[32] {.noSideEffect, noInit, inline.}=
|
||||
## Convert an UInt256 (in native host endianness) to a big-endian byte array
|
||||
const N = 32
|
||||
for i in 0 ..< N:
|
||||
{.unroll: 4.}
|
||||
result[i] = byte getUInt(num shr uint((N-1-i) * 8))
|
||||
|
||||
proc readHexChar(c: char): byte {.noSideEffect.}=
|
||||
|
Loading…
x
Reference in New Issue
Block a user