def inv_shift_rows(state): """ Transformation in the Inverse Cipher that is the inverse of ShiftRows(). """ state = state.reshape(4, 4, 8) return fcat(state[0][0], state[3][1], state[2][2], state[1][3], state[1][0], state[0][1], state[3][2], state[2][3], state[2][0], state[1][1], state[0][2], state[3][3], state[3][0], state[2][1], state[1][2], state[0][3])
def multiply(a, col): """Multiply a matrix by one column.""" a = a.reshape(4, 4, 4) col = col.reshape(4, 8) return fcat( rowxcol(a[0], col), rowxcol(a[1], col), rowxcol(a[2], col), rowxcol(a[3], col), )
def shift_rows(state): """ Transformation in the Cipher that processes the State by cyclically shifting the last three rows of the State by different offsets. """ state = state.reshape(4, 4, 8) return fcat(state[0][0], state[1][1], state[2][2], state[3][3], state[1][0], state[2][1], state[3][2], state[0][3], state[2][0], state[3][1], state[0][2], state[1][3], state[3][0], state[0][1], state[1][2], state[2][3])
def inv_mix_columns(state): """ Transformation in the Inverse Cipher that is the inverse of MixColumns(). """ state = state.reshape(4, 4, 8) return fcat( multiply(IMA, state[0]), multiply(IMA, state[1]), multiply(IMA, state[2]), multiply(IMA, state[3]), )
def inv_sub_bytes(state): """ Transformation in the Inverse Cipher that is the inverse of SubBytes(). """ state = state.reshape(4, 32) return fcat( invsubword(state[0]), invsubword(state[1]), invsubword(state[2]), invsubword(state[3]), )
def inv_shift_rows(state): """ Transformation in the Inverse Cipher that is the inverse of ShiftRows(). """ state = state.reshape(4, 4, 8) return fcat( state[0][0], state[3][1], state[2][2], state[1][3], state[1][0], state[0][1], state[3][2], state[2][3], state[2][0], state[1][1], state[0][2], state[3][3], state[3][0], state[2][1], state[1][2], state[0][3] )
def mix_columns(state): """ Transformation in the Cipher that takes all of the columns of the State and mixes their data (independently of one another) to produce new columns. """ state = state.reshape(4, 4, 8) return fcat( multiply(MA, state[0]), multiply(MA, state[1]), multiply(MA, state[2]), multiply(MA, state[3]), )
def shift_rows(state): """ Transformation in the Cipher that processes the State by cyclically shifting the last three rows of the State by different offsets. """ state = state.reshape(4, 4, 8) return fcat( state[0][0], state[1][1], state[2][2], state[3][3], state[1][0], state[2][1], state[3][2], state[0][3], state[2][0], state[3][1], state[0][2], state[1][3], state[3][0], state[0][1], state[1][2], state[2][3] )
def sub_bytes(state): """ Transformation in the Cipher that processes the State using a nonlinear byte substitution table (S-box) that operates on each of the State bytes independently. """ state = state.reshape(4, 32) return fcat( subword(state[0]), subword(state[1]), subword(state[2]), subword(state[3]), )
def add_round_key(state, rkey): """ Transformation in the Cipher and Inverse Cipher in which a Round Key is added to the State using an XOR operation. The length of a Round Key equals the size of the State (i.e., for Nb = 4, the Round Key length equals 128 bits/16 bytes). """ state = state.reshape(4, 32) rkey = rkey.reshape(4, 32) return fcat( state[0] ^ rkey[0], state[1] ^ rkey[1], state[2] ^ rkey[2], state[3] ^ rkey[3], )
def test_unsigned_add(): N = 9 A = exprvars('A', N) B = exprvars('B', N) for adder in (rca, ksa, bka): S, C = adder(A, B) S = fcat(S, C[-1]) # 0 + 0 = 0 assert uadd(S, A, B, 0, 0) == 0 # 255 + 255 = 510 assert uadd(S, A, B, 2**N - 1, 2**N - 1) == (2**(N + 1) - 2) # 255 + 1 = 256 assert uadd(S, A, B, 2**N - 1, 1) == 2**N # unsigned random vectors for i in range(NVECS): ra = random.randint(0, 2**N - 1) rb = random.randint(0, 2**N - 1) assert uadd(S, A, B, ra, rb) == ra + rb
def test_unsigned_add(): N = 9 A = exprvars('A', N) B = exprvars('B', N) for adder in (rca, ksa, bka): S, C = adder(A, B) S = fcat(S, C[-1]) # 0 + 0 = 0 assert uadd(S, A, B, 0, 0) == 0 # 255 + 255 = 510 assert uadd(S, A, B, 2**N-1, 2**N-1) == (2**(N+1)-2) # 255 + 1 = 256 assert uadd(S, A, B, 2**N-1, 1) == 2**N # unsigned random vectors for i in range(NVECS): ra = random.randint(0, 2**N-1) rb = random.randint(0, 2**N-1) assert uadd(S, A, B, ra, rb) == ra + rb
def bin2gray(B): """Convert a binary-coded vector into a gray-coded vector.""" return fcat(B[:-1] ^ B[1:], B[-1])
_MA = [ 0x2311, 0x1231, 0x1123, 0x3112, ] _IMA = [ 0xebd9, 0x9ebd, 0xd9eb, 0xbd9e, ] # 16x16x8 SBOX = fcat(*[uint2exprs(x, 8) for x in _SBOX]).reshape(256, 8) ISBOX = fcat(*[uint2exprs(x, 8) for x in _ISBOX]).reshape(256, 8) # 255 RCON = fcat(*[uint2exprs(x, 8) for x in _RCON]).reshape(255, 8) # 4x16 MA = fcat(*[uint2exprs(x, 16) for x in _MA]).reshape(4, 16) IMA = fcat(*[uint2exprs(x, 16) for x in _IMA]).reshape(4, 16) def subword(w): """ Function used in the Key Expansion routine that takes a four-byte input word and applies an S-box to each of the four bytes to produce an output word. """
def test_fcat(): # expected Function or farray assert_raises(TypeError, fcat, X, Y, 0) assert str(fcat(X[0], X[2:], Y[3], Y[:-2])) == "farray([x[0], x[2], x[3], y[3], y[0], y[1]])"
_MA = [ 0x2311, 0x1231, 0x1123, 0x3112, ] _IMA = [ 0xebd9, 0x9ebd, 0xd9eb, 0xbd9e, ] # 16x16x8 SBOX = fcat(*[uint2exprs(x, 8) for x in _SBOX]).reshape(256, 8) ISBOX = fcat(*[uint2exprs(x, 8) for x in _ISBOX]).reshape(256, 8) # 255 RCON = fcat(*[uint2exprs(x, 8) for x in _RCON]).reshape(255, 8) # 4x16 MA = fcat(*[uint2exprs(x, 16) for x in _MA]).reshape(4, 16) IMA = fcat(*[uint2exprs(x, 16) for x in _IMA]).reshape(4, 16) def subword(w): """ Function used in the Key Expansion routine that takes a four-byte input word and applies an S-box to each of the four bytes to produce an output word. """ w = w.reshape(4, 8)