// RecoverEncodings returns the full affine output encoding of affine-encoded f at the given position, as well as the // input affine encodings for all neighboring bytes up to a key byte. Returns (out, []in) func RecoverEncodings(constr *chow.Construction, round, pos int) (encoding.ByteAffine, []encoding.ByteAffine) { Ps := make([]encoding.ByteAffine, 4) // Approximate input encodings. Ds := make([]number.ByteFieldElem, 4) // Array of gamma * MC coefficient q := byte(0x00) // The constant part of the output encoding. L := RecoverL(constr, round, pos) Atilde := FindAtilde(constr, L) AtildeInv, _ := Atilde.Invert() for i := 0; i < 4; i++ { j := pos/4*4 + i inEnc, _ := RecoverAffineEncoded(constr, encoding.IdentityByte{}, round-1, unshiftRows(j), unshiftRows(j)) _, f := RecoverAffineEncoded(constr, inEnc, round, j, pos) var c byte Ds[i], c, Ps[i] = FindPartialEncoding(constr, f, L, AtildeInv) q ^= c if i == 0 { q ^= f.Get(0x00) } } DInv, _ := DecomposeAffineEncoding(encoding.ByteMultiplication(FindDuplicate(Ds).Invert())) A := Atilde.Compose(DInv) return encoding.ByteAffine{encoding.ByteLinear(A), q}, Ps }
// FindPartialEncoding takes an affine encoded F and finds the values that strip its output encoding. It returns the // parameters it finds and the input encoding of f up to a key byte. func FindPartialEncoding(constr *chow.Construction, f table.Byte, L, AtildeInv matrix.Matrix) (number.ByteFieldElem, byte, encoding.ByteAffine) { fInv := table.Invert(f) id := encoding.ByteLinear(matrix.GenerateIdentity(8)) SInv := table.InvertibleTable(chow.InvTBox{saes.Construction{}, 0x00, 0x00}) S := table.Invert(SInv) // Brute force the constant part of the output encoding and the beta in Atilde = A_i <- D(beta) for c := 0; c < 256; c++ { for d := 1; d < 256; d++ { cand := encoding.ComposedBytes{ TableAsEncoding{f, fInv}, encoding.ByteAffine{id, byte(c)}, encoding.ByteLinear(AtildeInv), encoding.ByteMultiplication(byte(d)), // D below TableAsEncoding{SInv, S}, } if isAffine(cand) { a, b := DecomposeAffineEncoding(cand) return number.ByteFieldElem(d), byte(c), encoding.ByteAffine{encoding.ByteLinear(a), byte(b)} } } } panic("Failed to strip output encodings!") }
// FindAtilde calculates a non-trivial matrix Atilde s.t. L <- Atilde = Atilde <- D(beta), where // L = A_i <- D(beta) <- A_i^(-1) func FindAtilde(constr *chow.Construction, L matrix.Matrix) matrix.Matrix { beta := CharToBeta[FindCharacteristic(L)] D, _ := DecomposeAffineEncoding(encoding.ByteMultiplication(beta)) x := L.RightStretch().Add(D.LeftStretch()).NullSpace() m := matrix.Matrix(make([]matrix.Row, len(x))) for i, e := range x { m[i] = matrix.Row{e} } return m }
func TestFindAtilde(t *testing.T) { fastConstr := fastTestConstruction() L := RecoverL(fastConstr, 1, 0) Atilde := FindAtilde(fastConstr, L) beta := CharToBeta[FindCharacteristic(L)] D, _ := DecomposeAffineEncoding(encoding.ByteMultiplication(beta)) left, right := L.Compose(Atilde), Atilde.Compose(D) for i, _ := range left { if len(left[i]) != 1 || len(right[i]) != 1 || left[i][0] != right[i][0] { t.Fatalf("L * Atilde != Atilde * D(beta)!\nL = %x\nR = %x\n", left, right) } } }
func TestRecoverL(t *testing.T) { MC := [][]number.ByteFieldElem{ []number.ByteFieldElem{0x02, 0x01, 0x01, 0x03}, []number.ByteFieldElem{0x03, 0x02, 0x01, 0x01}, } constr, _ := testConstruction() fastConstr := fastTestConstruction() for i := 0; i < 16; i++ { L := RecoverL(fastConstr, 1, i) outAff := getOutputAffineEncoding(constr, fastConstr, 1, i) // L is supposed to equal A_i <- D(beta) <- A_i^(-1) // We strip the conjugation by A_i and check that D(beta) is multiplication by an element of GF(2^8). DEnc := encoding.ComposedBytes{ outAff, encoding.ByteLinear(L), encoding.InverseByte{outAff}, } D, _ := DecomposeAffineEncoding(DEnc) Dstr := fmt.Sprintf("%x", D) // Calculate what beta should be. pos0, pos1 := i%4, (i+1)%4 beta := MC[0][pos0].Mul(MC[1][pos1]).Mul(MC[0][pos1].Mul(MC[1][pos0]).Invert()) // Calculate the matrix of multiplication by beta and check that it equals what we derived in D. E, _ := DecomposeAffineEncoding(encoding.ByteMultiplication(beta)) Estr := fmt.Sprintf("%x", E) if Dstr != Estr { t.Fatalf("A_i^(-1) * L * A_i doesn't equal D(beta)! i = %v\nL = %2.2x\nD = %2.2x\nE = %2.2x\n", i, L, D, E) } } }