// generateAffineMasks creates the random external masks for the construction. func generateAffineMasks(rs *random.Source) (inputMask, outputMask *blockAffine) { var inputLinear, outputLinear matrix.Matrix common.GenerateMasks(rs, common.IndependentMasks{common.RandomMask, common.RandomMask}, &inputLinear, &outputLinear) reader := rs.Stream(make([]byte, 16)) inputConstant, outputConstant := matrix.NewRow(128), matrix.NewRow(128) reader.Read(inputConstant[:]) reader.Read(outputConstant[:]) inputMask = &blockAffine{linear: inputLinear, constant: inputConstant} outputMask = &blockAffine{linear: outputLinear, constant: outputConstant} return }
// isBlockOfInverse takes a candidate solution for the given block of the matrix and returns true if it is valid and // false if it isn't. func (al *affineLayer) isBlockOfInverse(block int, cand matrix.Matrix) bool { // Pad matrix. inv := matrix.GenerateEmpty(32*block, 32) for _, row := range cand { inv = append(inv, row) } for row := 0; row < 96-32*block; row++ { inv = append(inv, matrix.NewRow(32)) } // Test if this is consistent with inverse. res := (*al).BlockLinear.Forwards.Compose(inv).Transpose() for i := 0; i < 4; i++ { row, pos := res[8*i], blockPos[4*block+i] if h := row.Height(); !(16*pos <= h && h < 16*(pos+1)) { return false } if !row[2*(pos+1):].IsZero() { return false } } return true }
// generateSelfEquivalence returns a random self-equivalence of the S-box layer, defined by stateSize and compressSize. func generateSelfEquivalence(r io.Reader, stateSize, compressSize int) (a, bInv *blockAffine) { inSize, outSize := 8*(stateSize+compressSize), 8*stateSize in := &blockAffine{ linear: matrix.GenerateEmpty(inSize, inSize), constant: matrix.NewRow(inSize), } out := &blockAffine{ linear: matrix.GenerateEmpty(outSize, outSize), constant: matrix.NewRow(outSize), } // The S-box portion of the self-equivalence. forwards, backwards := generatePermutation(r, 8*compressSize) for i := 0; i < 8*compressSize; i++ { selfEq := generateSboxSelfEq(r) in.linear[2*forwards[i]+0].SetBit(2*i+0, selfEq[0]) in.linear[2*forwards[i]+0].SetBit(2*i+1, selfEq[1]) in.linear[2*forwards[i]+1].SetBit(2*i+0, selfEq[2]) in.linear[2*forwards[i]+1].SetBit(2*i+1, selfEq[3]) in.constant.SetBit(2*forwards[i]+0, selfEq[4]) in.constant.SetBit(2*forwards[i]+1, selfEq[5]) out.linear[backwards[i]].SetBit(i, true) } // The open portion of the self-equivalence. Fill it with a random, invertible matrix. ignoreAll := func(_ int) bool { return true } dense, denseInv := matrix.GenerateRandomPartial(r, 8*(stateSize-compressSize), matrix.IgnoreNoBytes, ignoreAll) for i := 0; i < 8*(stateSize-compressSize); i++ { copy(in.linear[8*2*compressSize+i][2*compressSize:], dense[i]) copy(out.linear[8*compressSize+i][compressSize:], denseInv[i]) } return in, out }