View Javadoc
1   /*
2    * License : The MIT License
3    * Copyright(c) 2022 Olyutorskii
4    */
5   
6   package io.github.olyutorskii.aletojio.bijection;
7   
8   /**
9    * Diffusion of parity information.
10   *
11   * <p>Take the XOR of all even-numbered input bytes to obtain the odd-parity byte.
12   * The output is the XOR of the parity byte and the original each byte value.
13   *
14   * <p>This conversion is bijection.
15   * Perform this operation an even number of times to return to the original value.
16   *
17   * <p>Used as a pre-processor for 8bit S-box conversion to improve confusion.
18   *
19   * <p>byte-length must be even.
20   *
21   * <p>If 1 bit of N bytes input array changes,
22   * N-1 bits of output array changes.
23   * Hamming distance is N-1 bits.
24   *
25   * <p>ex) Input I has 4 bytes (I0-I3)
26   * Output O has 4 bytes (O0-O3)
27   *
28   * <p>{@code X = I0 ^ I1 ^ I2 ^ I3}
29   *
30   * <p>{@code O0 = I0 ^ X, O1 = I1 ^ X, O2 = I3 ^ X, O3 = I3 ^ X}
31   */
32  public final class ParitySpreader {
33  
34      private static final String ERRMSG_ODDLEN   = "length must be even";
35      private static final String ERRMSG_TOOSMALL = "too small length";
36      private static final String ERRMSG_TOOLARGE = "too large length";
37  
38      private static final int MASK_BYTE = (1 << Byte.SIZE) - 1;
39  
40  
41      /**
42       * Hidden constructor.
43       */
44      private ParitySpreader() {
45          assert false;
46      }
47  
48  
49      /**
50       * Spread parity information.
51       *
52       * @param iVal int value
53       * @return result
54       */
55      public static int spread(int iVal) {
56          int i0 =  iVal                      & MASK_BYTE;
57          int i1 = (iVal >>> (Byte.SIZE * 1)) & MASK_BYTE;
58          int i2 = (iVal >>> (Byte.SIZE * 2)) & MASK_BYTE;
59          int i3 = (iVal >>> (Byte.SIZE * 3)) & MASK_BYTE;
60  
61          int xorVal = (i0 ^ i1) ^ (i2 ^ i3);
62  
63          int o0 =  i0 ^ xorVal;
64          int o1 = (i1 ^ xorVal) << (Byte.SIZE * 1);
65          int o2 = (i2 ^ xorVal) << (Byte.SIZE * 2);
66          int o3 = (i3 ^ xorVal) << (Byte.SIZE * 3);
67  
68          int result = (o0 ^ o1) ^ (o2 ^ o3);
69  
70          return result;
71      }
72  
73      /**
74       * Spread parity information.
75       *
76       * @param bytes input and output bytes array
77       * @param length length of input must be even and smaller than input array.
78       * @throws IndexOutOfBoundsException length is negative or too large
79       * @throws IllegalArgumentException length is odd number
80       */
81      public static void spread(byte[] bytes, int length)
82              throws IndexOutOfBoundsException, IllegalArgumentException {
83          if (length < 0) throw new IndexOutOfBoundsException(ERRMSG_TOOSMALL);
84          if ((length & 1) == 1) throw new IllegalArgumentException(ERRMSG_ODDLEN);
85          if (bytes.length < length) throw new IndexOutOfBoundsException(ERRMSG_TOOLARGE);
86  
87          byte xorVal = 0;
88          for (int idx = 0; idx < length; idx++) {
89              xorVal ^= bytes[idx];
90          }
91  
92          for (int idx = 0; idx < length; idx++) {
93              byte bVal = bytes[idx];
94              bVal ^= xorVal;
95              bytes[idx] = bVal;
96          }
97  
98          return;
99      }
100 
101 }