ParitySpreader.java
/*
* License : The MIT License
* Copyright(c) 2022 Olyutorskii
*/
package io.github.olyutorskii.aletojio.bijection;
/**
* Diffusion of parity information.
*
* <p>Take the XOR of all even-numbered input bytes to obtain the odd-parity byte.
* The output is the XOR of the parity byte and the original each byte value.
*
* <p>This conversion is bijection.
* Perform this operation an even number of times to return to the original value.
*
* <p>Used as a pre-processor for 8bit S-box conversion to improve confusion.
*
* <p>byte-length must be even.
*
* <p>If 1 bit of N bytes input array changes,
* N-1 bits of output array changes.
* Hamming distance is N-1 bits.
*
* <p>ex) Input I has 4 bytes (I0-I3)
* Output O has 4 bytes (O0-O3)
*
* <p>{@code X = I0 ^ I1 ^ I2 ^ I3}
*
* <p>{@code O0 = I0 ^ X, O1 = I1 ^ X, O2 = I3 ^ X, O3 = I3 ^ X}
*/
public final class ParitySpreader {
private static final String ERRMSG_ODDLEN = "length must be even";
private static final String ERRMSG_TOOSMALL = "too small length";
private static final String ERRMSG_TOOLARGE = "too large length";
private static final int MASK_BYTE = (1 << Byte.SIZE) - 1;
/**
* Hidden constructor.
*/
private ParitySpreader() {
assert false;
}
/**
* Spread parity information.
*
* @param iVal int value
* @return result
*/
public static int spread(int iVal) {
int i0 = iVal & MASK_BYTE;
int i1 = (iVal >>> (Byte.SIZE * 1)) & MASK_BYTE;
int i2 = (iVal >>> (Byte.SIZE * 2)) & MASK_BYTE;
int i3 = (iVal >>> (Byte.SIZE * 3)) & MASK_BYTE;
int xorVal = (i0 ^ i1) ^ (i2 ^ i3);
int o0 = i0 ^ xorVal;
int o1 = (i1 ^ xorVal) << (Byte.SIZE * 1);
int o2 = (i2 ^ xorVal) << (Byte.SIZE * 2);
int o3 = (i3 ^ xorVal) << (Byte.SIZE * 3);
int result = (o0 ^ o1) ^ (o2 ^ o3);
return result;
}
/**
* Spread parity information.
*
* @param bytes input and output bytes array
* @param length length of input must be even and smaller than input array.
* @throws IndexOutOfBoundsException length is negative or too large
* @throws IllegalArgumentException length is odd number
*/
public static void spread(byte[] bytes, int length)
throws IndexOutOfBoundsException, IllegalArgumentException {
if (length < 0) throw new IndexOutOfBoundsException(ERRMSG_TOOSMALL);
if ((length & 1) == 1) throw new IllegalArgumentException(ERRMSG_ODDLEN);
if (bytes.length < length) throw new IndexOutOfBoundsException(ERRMSG_TOOLARGE);
byte xorVal = 0;
for (int idx = 0; idx < length; idx++) {
xorVal ^= bytes[idx];
}
for (int idx = 0; idx < length; idx++) {
byte bVal = bytes[idx];
bVal ^= xorVal;
bytes[idx] = bVal;
}
return;
}
}