-
-
Notifications
You must be signed in to change notification settings - Fork 1.5k
Closed
Description
Range always use signed integer as the base type in the codegen.
Example:
type
BaseUint* = SomeUnsignedInt or byte
Ct*[T: BaseUint] = distinct T
## Constant-Time wrapper
## Only constant-time operations in particular the ternary operator equivalent
## condition: if true: a else: b
## are allowed
CTBool*[T: Ct] = distinct range[T(0)..T(1)]
## Constant-Time boolean wrapper
var x: array[8, CTBool[Ct[uint32]]]
x[0] = (CTBool[Ct[uint32]])(1)
echo x.reprC code
// [...]
typedef NI tyArray__tvxsR2G9chmuUgp9afapiQkg[8];
// [...]
N_LIB_PRIVATE N_NIMCALL(void, NimMainModule)(void) {
{
tyArray__nHXaesL0DJZHyVS07ARPRA T1_;
nimfr_("range_unsigned", "/home/beta/Programming/Nim/constantine/build/range_unsigned.nim");
nimln_(13, "/home/beta/Programming/Nim/constantine/build/range_unsigned.nim");
x__C3MQJCEokeOV37kXufP37g[(((NI) 0))- 0] = ((NI) 1);
nimln_(14, "/home/beta/Programming/Nim/constantine/build/range_unsigned.nim");
nimZeroMem((void*)T1_, sizeof(tyArray__nHXaesL0DJZHyVS07ARPRA));
T1_[0] = reprAny(x__C3MQJCEokeOV37kXufP37g, (&NTI__tvxsR2G9chmuUgp9afapiQkg_));
echoBinSafe(T1_, 1);
popFrame();
}
}
// [...]This causes the following issues, note that this is used in a cryptographic library for BigInt
- The CTBool should be the same size as the base word, if the base word is uint32 on a x86-64 CPU they are not.
- This causes issues for inline assembly, as with 32-bit word we expect
testl+cmovlto work
but they only work on 32-bit width operand.func mux*[T](ctl: CTBool[T], x, y: T): T {.inline.}= ## Multiplexer / selector ## Returns x if ctl is true ## else returns y ## So equivalent to ctl? x: y when defined(amd64) or defined(i386): when sizeof(T) == 8: var muxed = x asm """ testq %[ctl], %[ctl] cmovzq %[y], %[muxed] : [muxed] "+r" (`muxed`) : [ctl] "r" (`ctl`), [y] "r" (`y`) : "cc" """ muxed elif sizeof(T) == 4: var muxed = x asm """ testl %[ctl], %[ctl] cmovzl %[y], %[muxed] : [muxed] "+r" (`muxed`) : [ctl] "r" (`ctl`), [y] "r" (`y`) : "cc" """ muxed else: {.error: "Unsupported word size".} else: y xor (-T(ctl) and (x xor y))
- C compilers use the undefined behavior of signed int for optimization. As mentioned in
- https://www.cl.cam.ac.uk/~rja14/Papers/whatyouc.pdf
- https://github.com/veorq/cryptocoding
Cryptography requires preventing several compiler optimizations as they would often expose information on potentially secret data. This requires careful usage and representation of conditionals.
While Nimintinstead of the specifieduint32probably wouldn't lead to secret data leak in this case, it would be far better if the requested base type was used.
See also: https://github.com/veorq/cryptocoding#use-unsigned-bytes-to-represent-binary-data
- Functions that return or accept this CTBool will use 8 bytes instead of 4 bytes