diff --git a/stew/ctops.nim b/stew/ctops.nim new file mode 100644 index 0000000..41b4b1f --- /dev/null +++ b/stew/ctops.nim @@ -0,0 +1,35 @@ +## Copyright (c) 2020 Status Research & Development GmbH +## Licensed under either of +## * Apache License, version 2.0, ([LICENSE-APACHE](LICENSE-APACHE)) +## * MIT license ([LICENSE-MIT](LICENSE-MIT)) +## at your option. +## This file may not be copied, modified, or distributed except according to +## those terms. + +## This module implements different operations which will execute in amount of +## time (or memory space) independent of the input size. + +type + CT* = object + AnyByte* = byte | char + +proc isEqual*[A: AnyByte, B: AnyByte](c: typedesc[CT], a: openArray[A], + b: openArray[B]): bool {. + raises: [Defect] .} = + ## Perform constant time comparison of two arrays ``a`` and ``b``. + ## + ## Please note that it only makes sense to compare arrays of the same length. + ## If length of arrays is not equal only part of array will be compared. + ## + ## Procedure returns ``true`` if arrays of same length are equal or + ## part of array's content is equal to another array's content if arrays + ## lengths are different. + ## + ## Beware that arrays ``a`` and ``b`` MUST NOT BE empty. + doAssert(len(a) > 0 and len(b) > 0) + var count = min(len(a), len(b)) + var res = 0 + while count > 0: + dec(count) + res = res or int(int(a[count]) xor int(b[count])) + (res == 0) diff --git a/tests/all_tests.nim b/tests/all_tests.nim index 1ff5867..f6c25ac 100644 --- a/tests/all_tests.nim +++ b/tests/all_tests.nim @@ -20,4 +20,5 @@ import test_objects, test_ptrops, test_results, - test_varints + test_varints, + test_ctops diff --git a/tests/test_ctops.nim b/tests/test_ctops.nim new file mode 100644 index 0000000..eaf0fc3 --- /dev/null +++ b/tests/test_ctops.nim @@ -0,0 +1,55 @@ +import unittest +import ../stew/ctops + +suite "Constant-time operations test suite": + test "isEqual() test": + let + charArr1 = ['T', 'E', 'S', 'T'] + charArr2 = ['A', 'B', 'C', 'D'] + charArr3 = ['B', 'I', 'G', 'M', 'E', 'S', 'S', 'A', 'G', 'E'] + charArr4 = ['T', 'E', 'S', 'T', 'B', 'I', 'G'] + charArr5 = ['B', 'I', 'G', 'T', 'E', 'S', 'T'] + byteArr1 = [0x54'u8, 0x45'u8, 0x53'u8, 0x54'u8] + byteArr2 = [0x41'u8, 0x42'u8, 0x43'u8, 0x44'u8] + byteArr3 = [0x42'u8, 0x49'u8, 0x47'u8, 0x4D'u8, 0x45'u8, + 0x53'u8, 0x53'u8, 0x41'u8, 0x47'u8, 0x45'u8] + byteArr4 = [0x54'u8, 0x45'u8, 0x53'u8, 0x54'u8, 0x42'u8, + 0x49'u8, 0x47'u8] + byteArr5 = [0x42'u8, 0x49'u8, 0x47'u8, 0x54'u8, 0x45'u8, + 0x53'u8, 0x54'u8] + str1 = "TEST" + str2 = "ABCD" + str3 = "BIGMESSAGE" + str4 = "TESTBIG" + str5 = "BIGTEST" + seq1 = @byteArr1 + seq2 = @byteArr2 + seq3 = @byteArr3 + seq4 = @byteArr4 + seq5 = @byteArr5 + + check: + CT.isEqual(charArr1, charArr1) == true + CT.isEqual(charArr1, byteArr1) == true + CT.isEqual(charArr1, str1) == true + CT.isEqual(charArr1, seq1) == true + + CT.isEqual(byteArr1, charArr2) == false + CT.isEqual(byteArr1, byteArr2) == false + CT.isEqual(byteArr1, str2) == false + CT.isEqual(byteArr1, seq2) == false + + CT.isEqual(str1, charArr3) == false + CT.isEqual(str1, byteArr3) == false + CT.isEqual(str1, str3) == false + CT.isEqual(str1, seq3) == false + + CT.isEqual(seq1, charArr4) == true + CT.isEqual(seq1, byteArr4) == true + CT.isEqual(seq1, str4) == true + CT.isEqual(seq1, seq4) == true + + CT.isEqual(byteArr1, charArr5) == false + CT.isEqual(str1, byteArr5) == false + CT.isEqual(seq1, str5) == false + CT.isEqual(charArr1, seq5) == false