diff --git a/mpint.nimble b/mpint.nimble index a5e2e14..f29e12f 100644 --- a/mpint.nimble +++ b/mpint.nimble @@ -7,4 +7,17 @@ srcDir = "src" ### Dependencies -requires "nim >= 0.17.2" \ No newline at end of file +requires "nim >= 0.17.2" + +proc test(name: string, lang: string = "cpp") = + if not dirExists "build": + mkDir "build" + if not dirExists "nimcache": + mkDir "nimcache" + --run + --nimcache: "nimcache" + switch("out", ("./build/" & name)) + setCommand lang, "tests/" & name & ".nim" + +task test, "Run all tests": + test "all_tests" \ No newline at end of file diff --git a/src/mpint.nim b/src/mpint.nim new file mode 100644 index 0000000..66e75aa --- /dev/null +++ b/src/mpint.nim @@ -0,0 +1,8 @@ +# Copyright (c) 2018 Status Research & Development GmbH +# Distributed under the MIT License (license terms are at http://opensource.org/licenses/MIT). + +import ./uint_type, + ./uint_init + +export uint_type, + uint_init \ No newline at end of file diff --git a/src/private/utils.nim b/src/private/utils.nim new file mode 100644 index 0000000..964dd0f --- /dev/null +++ b/src/private/utils.nim @@ -0,0 +1,24 @@ +# Copyright (c) 2018 Status Research & Development GmbH +# Distributed under the MIT License (license terms are at http://opensource.org/licenses/MIT). + +import ../uint_type + +proc bit_length*[T: BaseUint](n: T): int {.noSideEffect.}= + ## Calculates how many bits are necessary to represent the number + result = 1 + var y: T = n shr 1 + while y > 0.T: + y = y shr 1 + inc(result) + + +proc bit_length*[T: Natural](n: T): int {.noSideEffect.}= + ## Calculates how many bits are necessary to represent the number + # + # For some reason using "BaseUint or Natural" directly makes Nim compiler + # throw a type mismatch + result = 1 + var y: T = n shr 1 + while y > 0.T: + y = y shr 1 + inc(result) \ No newline at end of file diff --git a/src/uint_init.nim b/src/uint_init.nim new file mode 100644 index 0000000..cb17f9c --- /dev/null +++ b/src/uint_init.nim @@ -0,0 +1,29 @@ +# Copyright (c) 2018 Status Research & Development GmbH +# Distributed under the MIT License (license terms are at http://opensource.org/licenses/MIT). + +import typetraits + +import private/utils, + uint_type + +proc initMpUint*[T: BaseUint; U: BaseUInt](n: T, base_type: typedesc[U]): MpUint[U] {.noSideEffect.} = + let len = n.bit_length + const sizeU_bits = sizeof(U) * 8 + + when not (T is type result): + if len >= 2 * sizeU_bits: + # Todo print n + raise newException(ValueError, "Input cannot be stored in a multi-precision integer of base " & $T.name & + "\nIt requires at least " & $len & " bits of precision") + elif len < sizeU_bits: + result.lo = n.U # TODO: converter for MpInts + else: + raise newException(ValueError, "Unsupported at the moment: are you trying to build MpUint[uint32] from an uint64?") + else: + n + +proc u128*[T: BaseUInt](n: T): UInt128 {.noSideEffect, inline.}= + initMpUint(n, uint64) + +proc u256*[T: BaseUInt](n: T): UInt256 {.noSideEffect, inline.}= + initMpUint(n, UInt256) \ No newline at end of file diff --git a/src/uint_type.nim b/src/uint_type.nim new file mode 100644 index 0000000..bf0099a --- /dev/null +++ b/src/uint_type.nim @@ -0,0 +1,16 @@ +# Copyright (c) 2018 Status Research & Development GmbH +# Distributed under the MIT License (license terms are at http://opensource.org/licenses/MIT). + + +type + MpUint*{.packed.}[BaseUint] = object + when system.cpuEndian == littleEndian: + lo*, hi*: BaseUint + else: + hi*, lo*: BaseUint + + BaseUint* = SomeUnsignedInt or MpUint + + + UInt128* = MpUint[uint64] + UInt256* = MpUint[UInt128] \ No newline at end of file diff --git a/tests/all_tests.nim b/tests/all_tests.nim new file mode 100644 index 0000000..07c0632 --- /dev/null +++ b/tests/all_tests.nim @@ -0,0 +1,4 @@ +# Copyright (c) 2018 Status Research & Development GmbH +# Distributed under the MIT License (license terms are at http://opensource.org/licenses/MIT).$ + +import test_endianness \ No newline at end of file diff --git a/tests/test_endianness.nim b/tests/test_endianness.nim new file mode 100644 index 0000000..f693c19 --- /dev/null +++ b/tests/test_endianness.nim @@ -0,0 +1,14 @@ +# Copyright (c) 2018 Status Research & Development GmbH +# Distributed under the MIT License (license terms are at http://opensource.org/licenses/MIT). + +import ../src/mpint, unittest + +suite "Testing byte representation": + test "Byte representation conforms to the platform endianness": + let a = initMpUint(20182018, uint32) + let b = 20182018'u64 + + type AsBytes = array[8, byte] + + check cast[AsBytes](a) == cast[AsBytes](b) +