func (tyi TyiTable) Get(i byte) (out [4]byte) { // Calculate dot product of i and [0x02 0x01 0x01 0x03] j := number.ByteFieldElem(i) a := byte(number.ByteFieldElem(0x02).Mul(j)) b := byte(number.ByteFieldElem(0x01).Mul(j)) c := byte(number.ByteFieldElem(0x03).Mul(j)) // Merge into one output and rotate according to column. res := [4]byte{a, b, b, c} copy(out[:], append(res[(4-tyi):], res[0:(4-tyi)]...)) return }
// generateSelfEquivalence returns a random self-equivalence of the S-box layer, so that \zeta(x) = bInv(\zeta(a(x))). func generateSelfEquivalence(r io.Reader) (a, bInv encoding.Block) { // Sample a byte-wise permutation to apply to the input. p := &permutation{encoding.GenerateShuffle(r)} // Sample one non-zero scalar for each byte. Each byte of the input is multiplied by this scalar. buff := make([]byte, 1) scalars := encoding.ConcatenatedBlock{} for pos := 0; pos < 16; { r.Read(buff) if buff[0] != 0x00 { scalars[pos] = encoding.NewByteMultiplication(number.ByteFieldElem(buff[0])) pos++ } } // Sample a random value in [0, 8) for each byte. This is the number of times to apply the Frobenius. frobs := encoding.ConcatenatedBlock{} for pos := 0; pos < 16; pos++ { r.Read(buff) frobs[pos] = frobenius(buff[0] & 0x7) } return encoding.ComposedBlocks{ frobs, scalars, p, }, encoding.ComposedBlocks{ encoding.InverseBlock{p}, scalars, encoding.InverseBlock{frobs}, } }
func unMixColumns(i, j byte) [4]byte { k, l := number.ByteFieldElem(i), number.ByteFieldElem(j) var a, b, c, d number.ByteFieldElem a = number.ByteFieldElem(0x0e).Mul(k) b = number.ByteFieldElem(0x09).Mul(k) c = number.ByteFieldElem(0x0d).Mul(k) d = number.ByteFieldElem(0x0b).Mul(k) a = number.ByteFieldElem(0x0b).Mul(l).Add(a) b = number.ByteFieldElem(0x0e).Mul(l).Add(b) c = number.ByteFieldElem(0x09).Mul(l).Add(c) d = number.ByteFieldElem(0x0d).Mul(l).Add(d) return [4]byte{byte(a), byte(b), byte(c), byte(d)} }
func (f frobenius) Encode(in byte) (out byte) { temp := number.ByteFieldElem(in) for i := 0; i < int(f); i++ { temp = temp.Mul(temp) } return byte(temp) }
func (f frobenius) Decode(in byte) (out byte) { temp := number.ByteFieldElem(in) g := (8 - int(f)) % 8 for i := 0; i < g; i++ { temp = temp.Mul(temp) } return byte(temp) }
// Decrypt decrypts the first block in src into dst. Dst and src may point at the same memory. func (constr Construction) Decrypt(dst, src []byte) { state := gfmatrix.NewRow(128) for pos := 0; pos < 128; pos++ { state[pos] = number.ByteFieldElem(src[pos]) } state = constr.decrypt(state) for pos := 0; pos < 128; pos++ { dst[pos] = byte(state[pos]) } }
// stripScalars gets rid of unknown scalars in each block of the affine layer. It leaves it exactly equal to MixColumns, // but there is an unknown scalar in each block that will move into the S-box layers. func (al *affineLayer) stripScalars() (encoding.ConcatenatedBlock, encoding.ConcatenatedBlock) { input, output := [16]encoding.ByteLinear{}, [16]encoding.ByteLinear{} for pos := 0; pos < 16; pos += 4 { found := false for guess := 1; guess < 256 && !found; guess++ { // Take a guess for the input scalar on the first column. input[pos], _ = encoding.DecomposeByteLinear(encoding.NewByteMultiplication(number.ByteFieldElem(guess))) // Given input scalar on first column, calculate output scalars on all rows. for i := pos; i < pos+4; i++ { mc, _ := mixColumns[i%4][0].Invert() output[i] = encoding.NewByteLinear( al.getBlock(i, pos).Compose(input[pos].Backwards).Compose(mc), ) } // Given output scalar on each row, calculate input scalars on all columns. for i := pos + 1; i < pos+4; i++ { mc, _ := mixColumns[0][i%4].Invert() input[i] = encoding.NewByteLinear( al.getBlock(pos, i).Compose(output[pos].Backwards).Compose(mc), ) } // Verify that guess is consistent. found = true for i := pos; i < pos+4 && found; i++ { for j := pos; j < pos+4 && found; j++ { cand := al.getBlock(i, j).Compose(output[i].Backwards).Compose(input[j].Backwards) real := mixColumns[i%4][j%4] if !cand.Equals(real) { found = false } } } } if !found { panic("Failed to disambiguate block affine layer!") } } in, out := encoding.ConcatenatedBlock{}, encoding.ConcatenatedBlock{} for pos := 0; pos < 16; pos++ { in[pos], out[pos] = input[pos], output[pos] } return in, out }
// Expand takes a value from AES's space and embeds it in BES's space. func Expand(in []byte) gfmatrix.Row { out := gfmatrix.NewRow(8 * len(in)) for k, v := range in { num := number.ByteFieldElem(v) for pos := 0; pos < 8; pos++ { out[8*k+pos] = num num = num.Mul(num) } } return out }
func mixColumns(i, j byte) [4]byte { k, l := number.ByteFieldElem(i), number.ByteFieldElem(j) var a, b, c, d number.ByteFieldElem a = number.ByteFieldElem(0x02).Mul(k) b = number.ByteFieldElem(0x01).Mul(k) d = number.ByteFieldElem(0x03).Mul(k) a = number.ByteFieldElem(0x03).Mul(l).Add(a) c = number.ByteFieldElem(0x01).Mul(l) d = c.Add(d) c = c.Add(b) b = number.ByteFieldElem(0x02).Mul(l).Add(b) return [4]byte{byte(a), byte(b), byte(c), byte(d)} }
// UnMixColumn is the inverse of MixColumn. func (constr *Construction) UnMixColumn(slice []byte) { column := number.ArrayRingElem{ number.ByteFieldElem(slice[0]), number.ByteFieldElem(slice[1]), number.ByteFieldElem(slice[2]), number.ByteFieldElem(slice[3]), }.Mul(number.ArrayRingElem{ number.ByteFieldElem(0x0e), number.ByteFieldElem(0x09), number.ByteFieldElem(0x0d), number.ByteFieldElem(0x0b), }) for i := 0; i < 4; i++ { if len(column) > i { slice[i] = byte(column[i]) } else { slice[i] = 0x00 } } }
// SubByte is AES' S-box. It is a bijection. func (constr *Construction) SubByte(e byte) byte { // AES S-Box m := matrix.Matrix{ // Linear component. matrix.Row{0xF1}, // 0b11110001 matrix.Row{0xE3}, // 0b11100011 matrix.Row{0xC7}, // 0b11000111 matrix.Row{0x8F}, // 0b10001111 matrix.Row{0x1F}, // 0b00011111 matrix.Row{0x3E}, // 0b00111110 matrix.Row{0x7C}, // 0b01111100 matrix.Row{0xF8}, // 0b11111000 } a := byte(0x63) // 0b01100011 - Affine component. return m.Mul(matrix.Row{byte(number.ByteFieldElem(e).Invert())})[0] ^ a }
// UnSubByte is the inverse of SubByte. It is a bijection. func (constr *Construction) UnSubByte(e byte) byte { // AES Inverse S-Box m := matrix.Matrix{ matrix.Row{0xA4}, matrix.Row{0x49}, matrix.Row{0x92}, matrix.Row{0x25}, matrix.Row{0x4a}, matrix.Row{0x94}, matrix.Row{0x29}, matrix.Row{0x52}, } a := byte(0x63) invVal := m.Mul(matrix.Row{e ^ a})[0] return byte(number.ByteFieldElem(invVal).Invert()) }