<div dir="ltr">I was recently pointed to <a href="https://trac.torproject.org/projects/tor/ticket/13538">https://trac.torproject.org/projects/tor/ticket/13538</a> and the patch to fix it, at <a href="https://github.com/teor2345/tor/commit/ced74e0144e967f838416e6af92cba65c007d89b">https://github.com/teor2345/tor/commit/ced74e0144e967f838416e6af92cba65c007d89b</a>.<br><br>The underlying algorithm stores 26-bit signed numbers in int64s, and tries to guarantee that its operations never overflow. However, because the numbers are signed and possibly negative, C++ insists that they never be left-shifted, even if the arithmetic result would fit in the range of the type, and so the programmers can&#39;t get undefined behavior (and the resulting -ftrapv errors) in the cases they want.<br><br>We could suggest that the programmers explicitly multiply by a power of 2 instead, but they&#39;re using the &lt;&lt;s at least partly to get constant-time operation, and relying on multiplication for this would depend even more on implementation details than they already are.<br><br>Separately, a related piece of code uses a signed right-shift to repeat the sign bit across all the bits of a number: <a href="https://boringssl.googlesource.com/boringssl/+/e18d821dfcc32532caeeb1a2d15090672f592ce3/crypto/internal.h#157">https://boringssl.googlesource.com/boringssl/+/e18d821dfcc32532caeeb1a2d15090672f592ce3/crypto/internal.h#157</a>. This is implementation-defined rather than undefined, so the programmers can probably use #if to check for the behavior they expect, as at <a href="https://github.com/teor2345/tor/blob/ced74e0144e967f838416e6af92cba65c007d89b/src/ext/curve25519_donna/curve25519-donna.c#L466">https://github.com/teor2345/tor/blob/ced74e0144e967f838416e6af92cba65c007d89b/src/ext/curve25519_donna/curve25519-donna.c#L466</a><br><br>Is there space to improve the situation here?<br><br>I&#39;ve pasted the entire contents of [expr.shift] from N4140 <span class=""></span><span class=""></span>below, for context:<br><br><div>5.8 Shift operators [expr.shift]</div><div><br></div><div>1 The shift operators &lt;&lt; and &gt;&gt; group left-to-right.</div><blockquote style="margin:0px 0px 0px 40px;border:none;padding:0px"><div><i>shift-expression:</i></div></blockquote><blockquote style="margin:0px 0px 0px 40px;border:none;padding:0px"><blockquote style="margin:0px 0px 0px 40px;border:none;padding:0px"><div><i>additive-expression</i></div></blockquote><blockquote style="margin:0px 0px 0px 40px;border:none;padding:0px"><div><i>shift-expression &lt;&lt; additive-expression</i></div></blockquote><blockquote style="margin:0px 0px 0px 40px;border:none;padding:0px"><div><i>shift-expression &gt;&gt; additive-expression</i></div></blockquote></blockquote><div>The operands shall be of integral or unscoped enumeration type and integral promotions are performed.
The type of the result is that of the promoted left operand. The behavior is undefined if the right operand
is negative, or greater than or equal to the length in bits of the promoted left operand.</div><div><br></div><div>2 The value of E1 &lt;&lt; E2 is E1 left-shifted E2 bit positions; vacated bits are zero-filled. If E1 has an unsigned
type, the value of the result is E1 ื 2^E2, reduced modulo one more than the maximum value representable
in the result type. Otherwise, if E1 has a signed type and non-negative value, and E1 ื 2^E2 is representable
in the corresponding unsigned type of the result type, then that value, converted to the result type, is the
resulting value; otherwise, the behavior is undefined.</div><div><br></div><div>3 The value of E1 &gt;&gt; E2 is E1 right-shifted E2 bit positions. If E1 has an unsigned type or if E1 has a signed
type and a non-negative value, the value of the result is the integral part of the quotient of E1/2^E2. If E1
has a signed type and a negative value, the resulting value is implementation-defined.<br></div></div>