示例#1
0
// 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
}
示例#2
0
// cleanLeft gets the last affine layer back to a matrix with 16-by-16 blocks along the diagonal, times ShiftRows, times
// MixColumns and returns the matrix on the input encoding that it used to do this.
func (al *affineLayer) cleanLeft() encoding.Block {
	inverse := matrix.GenerateEmpty(128, 128)
	mixcols := matrix.GenerateEmpty(128, 128)

	// Combine individual blocks of the inverse matrix into the full inverse matrix. Also build the matrix corresponding
	// to the full-block MixColumns operation.
	for block := 0; block < 4; block++ {
		inv := al.findBlockOfInverse(block)

		for row := 0; row < 32; row++ {
			copy(inverse[32*block+row][4*block:], inv[row])
			copy(mixcols[32*block+row][4*block:], mixColumn[row])
		}
	}

	out := encoding.NewBlockLinear(inverse.Compose(mixcols))
	al.leftCompose(out)
	return encoding.InverseBlock{out}
}
示例#3
0
// 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
}
示例#4
0
func maskSwap(rs *random.Source, size, round int) (out matrix.Matrix) {
	out = matrix.GenerateEmpty(128, 128)

	for row := 0; row < 128; row += size {
		col := row / 8
		m := common.MixingBijection(rs, size, round, row/size)

		for subRow := 0; subRow < size; subRow++ {
			copy(out[row+subRow][col:], m[subRow])
		}
	}

	return
}
示例#5
0
// blockOfInverse computes a block of the something something something.
func blockOfInverse(swap [2]int, eqs [4]int) matrix.Matrix {
	unmixcol := unMixColumn.Dup()

	// Swap chosen rows.
	for i, ok := range swap {
		if ok == 1 {
			for row := 16 * i; row < 16*i+8; row++ {
				unmixcol[row], unmixcol[8+row] = unmixcol[8+row], unmixcol[row]
			}
		}
	}

	// Generate matrix corresponding to self-equivalence noise from S-box.
	noise := matrix.GenerateEmpty(32, 32)

	for i, eq := range eqs {
		for row := 0; row < 8; row++ {
			noise[8*i+row][i] = equivalences[eq][row][0]
		}
	}

	return noise.Compose(unmixcol)
}