From d545147b0bc85e8b8de837c023f4319c33f5adef Mon Sep 17 00:00:00 2001 From: mratsim Date: Sat, 1 Dec 2018 18:01:41 +0100 Subject: [PATCH] Use distinct range for Hardened booleans + first select test --- hardy/ct_primitives.nim | 14 +++++++++----- hardy/datatypes.nim | 2 +- tests/all_tests.nim | 14 +++++++++++++- 3 files changed, 23 insertions(+), 7 deletions(-) diff --git a/hardy/ct_primitives.nim b/hardy/ct_primitives.nim index c27cac0..793b878 100644 --- a/hardy/ct_primitives.nim +++ b/hardy/ct_primitives.nim @@ -73,20 +73,24 @@ func isMsbSet*[T: HardBase](x: T): HardBool[T] {.inline.} = # # ############################################################ +template undistinct[T: HardBase](x: HardBool[T]): T = + T(x) + func `not`*(ctl: HardBool): HardBool {.inline.}= ## Negate a constant-time boolean - ctl xor 1 + (type result)(ctl.undistinct xor (type ctl.undistinct)(1)) -func select*[T: HardBase](ctl: HardBool[T], x, y: T): T {.inline.}= +template select*[T: HardBase](ctl: HardBool[T], x, y: T): T = ## Multiplexer / selector ## Returns x if ctl == 1 ## else returns y ## So equivalent to ctl? x: y + y xor (-T(ctl) and (x xor y)) + # TODO verify assembly generated # as mentionned in https://cryptocoding.net/index.php/Coding_rules - # the alternative `(x and ctl) or (y and -m)` + # the alternative `(x and ctl) or (y and -ctl)` # is optimized into a branch by Clang :/ - y xor (-ctl.T and (x xor y)) func noteq[T: HardBase](x, y: T): HardBool[T] {.inline.}= const msb = T.sizeof * 8 - 1 @@ -104,7 +108,7 @@ func `<`*[T: HardBase](x, y: T): HardBool[T] {.inline.}= ) func `<=`*[T: HardBase](x, y: T): HardBool[T] {.inline.}= - (y < x) xor 1 + not(y < x) # ############################################################ # diff --git a/hardy/datatypes.nim b/hardy/datatypes.nim index ee947bb..ceb12b3 100644 --- a/hardy/datatypes.nim +++ b/hardy/datatypes.nim @@ -10,7 +10,7 @@ type HardBase*[T: BaseUint] = distinct T - HardBool*[T: HardBase] = range[T(0)..T(1)] + HardBool*[T: HardBase] = distinct range[T(0)..T(1)] ## To avoid the compiler replacing bitwise boolean operations ## by conditional branches, we don't use booleans. ## We use an int to prevent compiler "optimization" and introduction of branches diff --git a/tests/all_tests.nim b/tests/all_tests.nim index d361491..7cacd56 100644 --- a/tests/all_tests.nim +++ b/tests/all_tests.nim @@ -50,7 +50,7 @@ suite "Hardened unsigned integers": not(hard(0'u32)).undistinct == not 0'u32 not(hard(1'u32)).undistinct == not 1'u32 not(hard(1234'u64)).undistinct == not 1234'u64 - not(hard(5678'u64)).undistinct == not 5678'u32 + not(hard(5678'u64)).undistinct == not 5678'u64 not(hard(x1)).undistinct == not x1 not(hard(x2)).undistinct == not x2 not(hard(x3)).undistinct == not x3 @@ -166,3 +166,15 @@ suite "Hardened booleans": bool(hard(10'u32) >= hard(20'u32)) == false bool(hard(10'u32) >= hard(5'u32)) == true bool(hard(10'u32) >= hard(0xFFFFFFFF'u32)) == false + + test "Multiplexer/selector - select(ctl, x, y) <=> ctl? x: y": + let u = 10'u32.hard + let v = 20'u32.hard + let w = 5'u32.hard + + let y = htrue(uint32) + let n = hfalse(uint32) + + check: + bool(select(y, u, v) == u) +