Use distinct range for Hardened booleans + first select test

This commit is contained in:
mratsim 2018-12-01 18:01:41 +01:00
parent 8d6e328397
commit d545147b0b
3 changed files with 23 additions and 7 deletions

View File

@ -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)
# ############################################################
#

View File

@ -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

View File

@ -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)