Example #1
0
// 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},
		}
}
Example #2
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
}