Hiding fields, removing ttmath from libsecp backend

This commit is contained in:
mratsim 2018-03-21 14:11:48 +01:00
parent 0c4bc995d2
commit 6383b00bc2
6 changed files with 112 additions and 73 deletions

View File

@ -20,13 +20,13 @@ proc `=destroy`(ctx: ptr secp256k1_context) =
ctx.secp256k1_context_destroy
type
Serialized_PubKey = ByteArrayBE[65]
Serialized_PubKey = array[65, byte]
proc asPtrPubKey(key: PublicKey): ptr secp256k1_pubkey =
cast[ptr secp256k1_pubkey](unsafeAddr key.raw_key)
cast[ptr secp256k1_pubkey](unsafeAddr key)
proc asPtrCuchar(key: PrivateKey): ptr cuchar =
cast[ptr cuchar](unsafeAddr key.raw_key)
cast[ptr cuchar](unsafeAddr key)
proc asPtrCuchar(key: Serialized_PubKey): ptr cuchar =
cast[ptr cuchar](unsafeAddr key)

View File

@ -7,22 +7,43 @@
#
# at your option. This file may not be copied, modified, or distributed except according to those terms.
import ./private/lowlevel_types
import ttmath
import ./private/conversion_bytes
export toHex, hexToByteArrayBE, hexToSeqByteBE
export lowlevel_types, ttmath
# Note: Fields are intentionally kept private
type
PublicKey* = object
raw_key*: ByteArrayBE[64]
Fraw_key: array[64, byte]
PrivateKey* = object
raw_key*: ByteArrayBE[32]
public_key*: PublicKey
BaseKey* = PrivateKey|PublicKey
Fraw_key: array[32, byte]
Fpublic_key: PublicKey
Signature* {.packed.}= object
r*: UInt256
s*: UInt256
v*: range[0.byte .. 1.byte]
Fr: array[32, byte]
Fs: array[32, byte]
Fv: range[0.byte .. 1.byte]
# "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)

View File

@ -7,13 +7,12 @@
#
# at your option. This file may not be copied, modified, or distributed except according to those terms.
import ./datatypes,
./datatypes_interface
import ./datatypes
export PublicKey, PrivateKey, Signature
import ./datatypes_interface
export datatypes_interface
export datatypes,
datatypes_interface
import ttmath
export ttmath
when defined(backend_native):
import ttmath
export ttmath

View File

@ -7,7 +7,7 @@
#
# at your option. This file may not be copied, modified, or distributed except according to those terms.
import ttmath, strutils
import strutils
# Note on endianness:
# - UInt256 uses host endianness
@ -19,24 +19,7 @@ import ttmath, 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]] = array[N, byte]
## A byte array that stores bytes in big-endian order
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, 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.}=
proc readHexChar*(c: char): byte {.noSideEffect.}=
## Converts an hex char to a byte
case c
of '0'..'9': result = byte(ord(c) - ord('0'))
@ -45,7 +28,7 @@ proc readHexChar(c: char): byte {.noSideEffect.}=
else:
raise newException(ValueError, $c & "is not a hexademical character")
proc skip0xPrefix(hexStr: string): int {.inline.} =
proc skip0xPrefix*(hexStr: string): int {.inline.} =
## Returns the index of the first meaningful char in `hexStr` by skipping
## "0x" prefix
if hexStr[0] == '0' and hexStr[1] in {'x', 'X'}:
@ -68,7 +51,7 @@ proc hexToByteArrayBE*(hexStr: string, output: var openArray[byte]) {.inline.} =
## Read a hex string and store it in a Byte Array `output` in Big-Endian order
hexToByteArrayBE(hexStr, output, 0, output.high)
proc hexToByteArrayBE*[N: static[int]](hexStr: string): ByteArrayBE[N] {.noSideEffect, noInit, inline.}=
proc hexToByteArrayBE*[N: static[int]](hexStr: string): array[N, byte] {.noSideEffect, noInit, inline.}=
## Read an hex string and store it in a Byte Array in Big-Endian order
hexToByteArrayBE(hexStr, result)
@ -83,33 +66,6 @@ proc hexToSeqByteBE*(hexStr: string): seq[byte] {.noSideEffect.}=
result[i] = hexStr[2*i].readHexChar shl 4 or hexStr[2*i+1].readHexChar
inc(i)
proc hexToUInt256*(hexStr: string): UInt256 {.noSideEffect.}=
## Read an hex string and store it in a UInt256
const N = 32
var i = skip0xPrefix(hexStr)
assert hexStr.len - i == 2*N
while i < 2*N:
result = result shl 4 or hexStr[i].readHexChar.uint.u256
inc(i)
proc toHex*(n: UInt256): string {.noSideEffect.}=
## Convert uint256 to its hex representation
## Output is in lowercase
var rem = n # reminder to encode
const
N = 32 # nb of bytes in n
hexChars = "0123456789abcdef"
result = newString(2*N)
for i in countdown(2*N - 1, 0):
result[i] = hexChars[(rem and 0xF.u256).getUInt.int]
rem = rem shr 4
proc toHexAux(ba: openarray[byte]): string {.noSideEffect.} =
## Convert a byte-array to its hex representation
## Output is in lowercase
@ -132,7 +88,7 @@ proc toHex*(ba: openarray[byte]): string {.noSideEffect, inline.} =
## - It is resistant against timing attack
toHexAux(ba)
proc toHex*(ba: ByteArrayBE): string {.noSideEffect, inline.} =
proc toHex*[N: static[int]](ba: array[N, byte]): string {.noSideEffect, inline.} =
## Convert a byte-array to its hex representation
## Output is in lowercase
##

View File

@ -0,0 +1,63 @@
# Nim Eth-keys
# Copyright (c) 2018 Status Research & Development GmbH
# Licensed under either of
#
# * Apache License, version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0)
# * MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT)
#
# at your option. This file may not be copied, modified, or distributed except according to those terms.
import ttmath, strutils,
conversion_bytes
# Note on endianness:
# - UInt256 uses host endianness
# - Libsecp256k1, Ethereum EVM expect Big Endian
# https://github.com/ethereum/evmjit/issues/91
# - Keccak expects least-significant byte first: http://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.202.pdf
# Appendix B.1 p37 and outputs a hash with the same endianness as input
# http://www.dianacoman.com/2018/02/08/eucrypt-chapter-9-byte-order-and-bit-disorder-in-keccak/
# 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.
proc toByteArrayBE*(num: UInt256): array[32, byte] {.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 readUint256BE*(ba: array[32, byte]): 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 hexToUInt256*(hexStr: string): UInt256 {.noSideEffect.}=
## Read an hex string and store it in a UInt256
const N = 32
var i = skip0xPrefix(hexStr)
assert hexStr.len - i == 2*N
while i < 2*N:
result = result shl 4 or hexStr[i].readHexChar.uint.u256
inc(i)
proc toHex*(n: UInt256): string {.noSideEffect.}=
## Convert uint256 to its hex representation
## Output is in lowercase
var rem = n # reminder to encode
const
N = 32 # nb of bytes in n
hexChars = "0123456789abcdef"
result = newString(2*N)
for i in countdown(2*N - 1, 0):
result[i] = hexChars[(rem and 0xF.u256).getUInt.int]
rem = rem shr 4

View File

@ -7,8 +7,8 @@
#
# at your option. This file may not be copied, modified, or distributed except according to those terms.
import ../src/private/lowlevel_types
import unittest, ttmath, strutils
import ../src/private/[conversion_bytes, conversion_ttmath]
import unittest, ttmath, strutils # TODO remove ttmath needs if backend libsecp256k1
suite "Testing conversion functions: Hex, Bytes, Endianness":