From 12cc5dcad8d2bc37f833057c7fcffe5686031193 Mon Sep 17 00:00:00 2001 From: mratsim Date: Sun, 5 Aug 2018 15:07:35 +0200 Subject: [PATCH] Fix primitive types, add bitwise, shift, add, sub and constant time comparison --- hardy/bool_primitives.nim | 45 --------------------- hardy/ct_primitives.nim | 84 +++++++++++++++++++++++++++++++++++++++ hardy/datatypes.nim | 4 +- 3 files changed, 87 insertions(+), 46 deletions(-) delete mode 100644 hardy/bool_primitives.nim create mode 100644 hardy/ct_primitives.nim diff --git a/hardy/bool_primitives.nim b/hardy/bool_primitives.nim deleted file mode 100644 index 168fc4e..0000000 --- a/hardy/bool_primitives.nim +++ /dev/null @@ -1,45 +0,0 @@ -# Hardy -# Copyright (c) 2018 Status Research & Development GmbH -# Licensed and distributed under either of -# * MIT license (license terms in the root directory or at http://opensource.org/licenses/MIT). -# * Apache v2 license (license terms in the root directory or at http://www.apache.org/licenses/LICENSE-2.0). -# at your option. This file may not be copied, modified, or distributed except according to those terms. - -import ./datatypes - -# ################################ -# -# Constant-time boolean primitives -# -# ################################ - -# The main challenge is to prevent conditional branch/jump -# in the generated assembly. -# -# Note: -# let x = if true: 1 else: 2 -# -# does not guarantee a constant-time conditional move -# The compiler might introduce branching. - -# These primitives are internal to Hardy. -# We don't want to pollute unsuspecting users -# with `not` and `-` on unsigned ints - -func high*(T: typedesc[HardBase]): T {.inline.}= - result = not T(0) - -func `not`*[T: HardBase](ctl: HardBool[T]): HardBool[T] {.inline.}= - ## Negate a constant-time boolean - result = ctl xor 1.T - -func `-`*(x: HardBase): HardBase {.inline.}= - ## Unary minus returns the two-complement representation - ## of an unsigned integer - const max = high(type x) - result = (max xor x) + 1 - -func mux*[T: HardBase](ctl: HardBool[T], x, y: T): T {.inline.}= - ## Returns x if ctl == 1 - ## else returns y - result = y xor (-ctl.HardBase and (x xor y)) diff --git a/hardy/ct_primitives.nim b/hardy/ct_primitives.nim new file mode 100644 index 0000000..79a13c3 --- /dev/null +++ b/hardy/ct_primitives.nim @@ -0,0 +1,84 @@ +# Hardy +# Copyright (c) 2018 Status Research & Development GmbH +# Licensed and distributed under either of +# * MIT license (license terms in the root directory or at http://opensource.org/licenses/MIT). +# * Apache v2 license (license terms in the root directory or at http://www.apache.org/licenses/LICENSE-2.0). +# at your option. This file may not be copied, modified, or distributed except according to those terms. + +import ./datatypes + +# ######################### +# +# Constant-time primitives +# +# ######################### + +# The main challenge is to prevent conditional branch/jump +# in the generated assembly. +# +# Note: +# let x = if true: 1 else: 2 +# +# does not guarantee a constant-time conditional move +# The compiler might introduce branching. + +# These primitives are distinct type and internal to Hardy. +# We don't want to pollute unsuspecting users +# with `not` and `-` on unsigned ints + +# ################################################################# +# Hard base borrows +# We should use {.borrow.} instead of {.magic.} but pending: +# - https://github.com/nim-lang/Nim/pull/8531 +# - https://github.com/nim-lang/Nim/issues/4121 (can be workaround with #8531) + +func high*(T: typedesc[HardBase]): T {.inline.}= + not T(0) + + +func `and`*[T: HardBase](x, y: T): T {.magic: "BitandI".} +func `or`*[T: HardBase](x, y: T): T {.magic: "BitorI".} +func `xor`*[T: HardBase](x, y: T): T {.magic: "BitxorI".} +func `not`*[T: HardBase](x: T): T {.magic: "BitnotI".} +func `+`*[T: HardBase](x, y: T): T {.magic: "AddU".} +func `-`*[T: HardBase](x, y: T): T {.magic: "SubU".} +func `shr`*[T: HardBase](x: T, y: SomeInteger): T {.magic: "ShrI".} +func `shl`*[T: HardBase](x: T, y: SomeInteger): T {.magic: "ShlI".} + +# ################################################################# + +func `not`*(ctl: HardBool): HardBool {.inline.}= + ## Negate a constant-time boolean + result = ctl xor 1 + +func `-`*(x: HardBase): HardBase {.inline.}= + ## Unary minus returns the two-complement representation + ## of an unsigned integer + {.emit:"`result` = -`x`;".} + +func mux*[T: HardBase](ctl: HardBool[T], x, y: T): T {.inline.}= + ## Multiplexer / selector + ## Returns x if ctl == 1 + ## else returns y + result = y xor (-ctl.T and (x xor y)) + +func `!=`*[T: HardBase](x, y: T): HardBool[T] {.inline.}= + const msb = T.sizeof * 8 - 1 + let z = x xor y + result = (type result)((z or -z) shr msb) + +func `==`*[T: HardBase](x, y: T): HardBool[T] {.inline.}= + result = not(x != y) + +func `<`*[T: HardBase](x, y: T): HardBool[T] {.inline.}= + const msb = T.sizeof * 8 - 1 + result = (type result)( + ( + x xor ( + (x xor y) or ((x - y) xor y) + ) + ) shr msb + ) + +func `<=`*[T: HardBase](x, y: T): HardBool[T] {.inline.}= + (y < x) xor 1 diff --git a/hardy/datatypes.nim b/hardy/datatypes.nim index 7115afb..673c74d 100644 --- a/hardy/datatypes.nim +++ b/hardy/datatypes.nim @@ -6,7 +6,9 @@ # at your option. This file may not be copied, modified, or distributed except according to those terms. type - HardBase* = SomeUnsignedInt or byte + BaseUint* = SomeUnsignedInt or byte + + HardBase*[T: BaseUint] = distinct T HardBool*[T: HardBase] = range[T(0)..T(1)] ## To avoid the compiler replacing bitwise boolean operations