src/crypto/aes/sbox.bend checks
raw source on the hub · import 0xd9a2fae439ac7ff9e21e0853948f94fe/src/crypto/aes/sbox.bend as Sbox
1 import
import Base
Definitions
def sbox_word source · line 14 · raw
@+x:U32 -> U32
The AES S-box and the GF(2^8) doublings MixColumns needs, computed with U32 bit operations only: no table and no branch reads a secret byte.
The S-box is the depth-16, 113-gate (+ 4 NOT) circuit of Boyar and Peralta ("A depth-16 circuit for the AES S-box", 2011; the gate list BearSSL's aes_ct uses), evaluated on one byte with one bit per U32 (values 0 or 1). Its input x0..x7 is the byte's bit 7..0 and its output s0..s7 the result's bit 7..0. proofs/crypto/aes/sbox.bend proves it equal, on every input, to FIPS 197's S-box (the inverse in GF(2^8) followed by the affine map). Every mask is the first operand of U32.and, so the bits above the low eight of an input never reach the result.
def sbox source · line 142 · raw
@x:U32 -> U32
The S-box. (The one-constructor match only opens the U32, no branch: it keeps a proof about an unknown word from expanding the 117 gates.)
def xtime_word source · line 148 · raw
@+x:U32 -> U32
{02} * x in GF(2^8) (FIPS 197 section 4.2.1, xtime): shift left and, when bit 7 was set, add x^8 = {1b}; the reduction mask is 0 - bit7, not a branch.
def xtime source · line 151 · raw
@x:U32 -> U32
def mul3_word source · line 156 · raw
@+x:U32 -> U32
{03} * x = {02} * x + x.
def mul3 source · line 159 · raw
@x:U32 -> U32