@kornel @varkor @djzin My initial vehicle for learning Rust (late last year) was to code variants of a strong cryptographic algorithm that is lightweight enough for retrofit embedded use. The lack of lexemes for
-
add
,sub
, andmul
for unsigned finite-ring arithmetic (e.g., u32) - as well as
rotate_left
androtate_right
- and the assign variants for these five operators
led me to delve into the compiler and work out the many changes that would be needed to add such lexemes and their associated trait language items.
The lexemes I considered for finite-ring arithmetic were +%
, -%
, *%
, +%=
, -%=
, and *%=
; those for rotate were <<<
, >>>
, <<<=
, and >>>=
. For Rust, I saw some advantages for using the trailing %
rather than Swift’s leading &
:
-
the trailing
%
expresses the order of operation: firstadd
/sub
/mul
, then take the remainder of the result (as an unsigned integer) modulo the representation size, then optionally assign that value to the first operand; -
lexeme augmentation with the
%
suffix makes less jarring the potential inclusion of Euclidian modulo and associated Euclidian divide operators (%%
and\%
, respectively). -
the
&
sigil used in Swift’s finite-ring operators is already used heavily in Rust, more than other languages, due to its use as theref
operator, so not using it for the finite-ringadd
/sub
/mul
operators reduces potential confusion
I personally feel that Swift’s &+
, &-
, and &*
operators emphasize the “bit-fiddling” aspects of the operations while suppressing awareness that the underlying arithmetic has moved from the infinite ring of all integers to the finite ring of all integers with a given representation. For the same reason, I looked at what it would take to limit the new lexemes to unsigned arithmetic, so that applying the existing wrapping operators to signed integers (which are operations in a very different finite ring) would always require more-verbose programming effort. (Unfortunately, I concluded that tracking known signedness of integer expressions would require extensive changes to the compiler. That conclusion also implied that new lints for distinguishing use of wrapping and rotation operators on signed values would also be difficult.)
FWIW, I eventually decided that cryptographic primitives should use the approach found in the octavo crate, declaring the needed finite-ring types as wN
(rather than using uN
), together with the mathematically-appropriate traditional +
, -
, and *
operators and the W
type-conversion operator for constants.