示例#1
0
// 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
}
示例#2
0
// blockMaskEncoding concatenates all the mask encodings for InputMask or TBoxOutputMask into a block encoding, so that
// it can easily be put on the output of one of the Block tables.
//
// position is the index of the Block table and shift is the permutation that will be applied between this round and the
// next or noshift if this is an input encoding; the other parameters are explained in MaskEncoding documentation.
func blockMaskEncoding(rs *random.Source, position int, surface common.Surface, shift func(int) int) encoding.Block {
	out := encoding.ConcatenatedBlock{}

	for i := 0; i < 16; i++ {
		out[i] = encoding.ConcatenatedByte{
			maskEncoding(rs, surface)(position, 2*i+0),
			maskEncoding(rs, surface)(position, 2*i+1),
		}

		if surface == common.Inside {
			out[i] = encoding.ComposedBytes{
				encoding.NewByteLinear(common.MixingBijection(rs, 8, -1, shift(i))),
				out[i],
			}
		}
	}

	return out
}
示例#3
0
// blockParasites returns the input parasite of the block at the given row and column of the linear part of al, or nil
// if the block is zero.
func (al *affineLayer) blockParasite(row, col int) (input *parasite) {
	block := al.getBlock(row, col)
	if toString(block) == "0000000000000000" {
		return nil
	}
	enc := encoding.NewByteLinear(block)

	for _, input = range parasites {
		cand, _ := encoding.DecomposeByteLinear(encoding.ComposedBytes{
			encoding.InverseByte{subBytes}, encoding.InverseByte{input}, enc,
		})
		_, ok := parasites[toString(cand.Forwards)]
		if ok {
			return
		}
	}

	panic("unable to determine input parasite")
}
示例#4
0
// inputParasite returns the non-GF(2^8) part of the parasite on the output at position col.
func (al *affineLayer) inputParasite(col int) encoding.Byte {
	block := col / 4
	row := 4 * (col / 4)

	row0, col0 := row%4, col%4
	row1, col1 := (row0+1)%4, (col0+1)%4

	rowT, colT := row1+(4*block), col1+(4*block)

	blockAA, blockAB := al.getBlock(row, col), al.getBlock(row, colT)
	blockBA, blockBB := al.getBlock(rowT, col), al.getBlock(rowT, colT)

	blockAA, _ = blockAA.Invert()
	blockBB, _ = blockBB.Invert()

	B := blockAA.Compose(blockAB).Compose(blockBB).Compose(blockBA)
	lambda := unMixColumns[row0][col0].Compose(mixColumns[row0][col1]).
		Compose(unMixColumns[row1][col1]).Compose(mixColumns[row1][col0])

	return encoding.NewByteLinear(findMatrix(
		B.LeftStretch().Add(lambda.RightStretch()).NullSpace(),
	))
}
示例#5
0
func generateKeys(rs *random.Source, opts common.KeyGenerationOpts, out *Construction, inputMask, outputMask *matrix.Matrix, shift func(int) int, skinny func(int) table.Byte, wide func(int, int) table.Word) {
	// Generate input and output encodings.
	common.GenerateMasks(rs, opts, inputMask, outputMask)

	// Generate the Input Mask slices and XOR tables.
	for pos := 0; pos < 16; pos++ {
		out.InputMask[pos] = encoding.BlockTable{
			encoding.IdentityByte{},
			blockMaskEncoding(rs, pos, common.Inside, shift),
			common.BlockMatrix{Linear: *inputMask, Position: pos},
		}
	}

	out.InputXORTables = common.BlockNibbleXORTables(
		maskEncoding(rs, common.Inside),
		xorEncoding(rs, 10, common.Inside),
		roundEncoding(rs, -1, common.Outside, shift),
	)

	// Generate round material.
	for round := 0; round < 9; round++ {
		for pos := 0; pos < 16; pos++ {
			// Generate a word-sized mixing bijection and stick it on the end of the T-Box/Tyi Table.
			mb := common.MixingBijection(rs, 32, round, pos/4)

			// Build the T-Box and Tyi Table for this round and position in the state matrix.
			out.TBoxTyiTable[round][pos] = encoding.WordTable{
				encoding.ComposedBytes{
					encoding.NewByteLinear(common.MixingBijection(rs, 8, round-1, pos)),
					byteRoundEncoding(rs, round-1, pos, common.Outside, common.NoShift),
				},
				encoding.ComposedWords{
					encoding.ConcatenatedWord{
						encoding.NewByteLinear(common.MixingBijection(rs, 8, round, shift(pos/4*4+0))),
						encoding.NewByteLinear(common.MixingBijection(rs, 8, round, shift(pos/4*4+1))),
						encoding.NewByteLinear(common.MixingBijection(rs, 8, round, shift(pos/4*4+2))),
						encoding.NewByteLinear(common.MixingBijection(rs, 8, round, shift(pos/4*4+3))),
					},
					encoding.NewWordLinear(mb),
					wordStepEncoding(rs, round, pos, common.Inside),
				},
				wide(round, pos),
			}

			// Encode the inverse of the mixing bijection from above in the MB^(-1) table for this round and position.
			mbInv, _ := mb.Invert()

			out.MBInverseTable[round][pos] = encoding.WordTable{
				byteRoundEncoding(rs, round, pos, common.Inside, common.NoShift),
				wordStepEncoding(rs, round, pos, common.Outside),
				mbInverseTable{mbInv, uint(pos) % 4},
			}
		}
	}

	// Generate the High and Low XOR Tables for reach round.
	out.HighXORTable = xorTables(rs, common.Inside, common.NoShift)
	out.LowXORTable = xorTables(rs, common.Outside, shift)

	// Generate the 10th T-Box/Output Mask slices and XOR tables.
	for pos := 0; pos < 16; pos++ {
		out.TBoxOutputMask[pos] = encoding.BlockTable{
			encoding.ComposedBytes{
				encoding.NewByteLinear(common.MixingBijection(rs, 8, 8, pos)),
				byteRoundEncoding(rs, 8, pos, common.Outside, common.NoShift),
			},
			blockMaskEncoding(rs, pos, common.Outside, shift),
			table.ComposedToBlock{
				Heads: skinny(pos),
				Tails: common.BlockMatrix{Linear: *outputMask, Position: pos},
			},
		}
	}

	out.OutputXORTables = common.BlockNibbleXORTables(
		maskEncoding(rs, common.Outside),
		xorEncoding(rs, 10, common.Outside),
		func(position int) encoding.Nibble { return encoding.IdentityByte{} },
	)
}
示例#6
0
package toy

import (
	"github.com/OpenWhiteBox/primitives/encoding"
	"github.com/OpenWhiteBox/primitives/gfmatrix"
	"github.com/OpenWhiteBox/primitives/matrix"
	"github.com/OpenWhiteBox/primitives/number"
)

var (
	// subBytes is the linear part of of AES's SubBytes transformation.
	subBytes = encoding.NewByteLinear(matrix.Matrix{
		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
	})

	// blocks maps an 8-by-8 matrix to its MixColumns coefficient, c. The matrix is $[c] \circ subBytes$ (from above).
	// This is used for compressing affine layers to matrices over F_{2^8}.
	blocks = map[string]number.ByteFieldElem{
		"0000000000000000": 0,
		"f1e3c78f1f3e7cf8": 1,
		"f809e33f771f3e7c": 2,
		"09ea24b068214284": 3,
	}

	// smallRound is a compressed round matrix, without ShiftRows (so essentially just MixColumns four times). This is