<div dir="ltr"><div dir="ltr"><div dir="ltr"><div dir="ltr"><div dir="ltr"><div dir="ltr"><div dir="ltr"><div dir="ltr"><div class="gmail_default" style="font-size:small">Perhaps some code will make the point clearer. I haven't run this yet, but this is the sort of thing I was looking for. I will run it later on when I have a test wrapper round it.</div><div class="gmail_default" style="font-size:small"><br></div><div class="gmail_default" style="font-size:small">The inputs and outputs are 64 bit unsigned integers. The permutation can be any number of bits from 1 up to 64. There isn't much point in randomly permuting very small blocks except to avoid creating a separate code path for them.</div><div class="gmail_default" style="font-size:small"><br></div><div class="gmail_default" style="font-size:small">The cipher action is coming from the combination of an integer addition, a rotate and an XOR. These are all efficiently implemented on modern machines. </div><div class="gmail_default" style="font-size:small"><br></div><div class="gmail_default" style="font-size:small">I once managed to break the 'MD5' algorithm from Scheier's Applied Crypto v1. Just before showing the result to Rivest whose office was 70 ft away from mine, I looked up the RFC and found that the printer had omitted the additive constants at the end of each round. They make all the difference in the world.</div><div class="gmail_default" style="font-size:small"><br></div><div class="gmail_default" style="font-size:small">You can think of this as an alternative to using a digest or a MAC on a 128 bit identifier to produce a pseudo-unique 256 bit identifier.</div><div class="gmail_default" style="font-size:small"><br></div><div class="gmail_default" style="font-size:small">I am not particularly bothered about the speed of this because I will be doing at least one X448 operation every time it is called.</div><div class="gmail_default" style="font-size:small"><br></div><div class="gmail_default" style="font-size:small">The number of rounds is almost certainly excessive. But I don't have the time or the specific skills to work out how to safely reduce it.</div><div class="gmail_default" style="font-size:small"><br></div><div class="gmail_default" style="font-size:small"><br></div><div class="gmail_default" style="font-size:small">This is limited to 64 bits. To extend beyond that, I would probably keep the cipher action focused on just one 64 bit block and expand the rotation function to work the key across all the blocks. </div><div class="gmail_default" style="font-size:small"><br></div><div class="gmail_default" style="font-size:small">(I did think about applying cipher text stealing approach but it isn't as nice as might be expected).</div><div class="gmail_default" style="font-size:small"><br></div><div class="gmail_default" style="font-size:small"><br></div><div class="gmail_default"><div class="gmail_default">    /// <summary></div><div class="gmail_default">    /// Short block permutation.</div><div class="gmail_default">    /// </summary></div><div class="gmail_default">    public class ShortBlockPermute {</div><div class="gmail_default">        #region // Properties</div><div class="gmail_default">        ///<summary>The bitmask masking the lower n bits of the data channel</summary> </div><div class="gmail_default">        public ulong Mask;</div><div class="gmail_default"><br></div><div class="gmail_default">        ///<summary>The number of bits to permute.</summary> </div><div class="gmail_default">        public int Bits;</div><div class="gmail_default"><br></div><div class="gmail_default">        ///<summary>The number of rounds to perform.</summary> </div><div class="gmail_default">        public int Rounds;</div><div class="gmail_default"><br></div><div class="gmail_default">        ///<summary>The key schedule, this is stored for reuse.</summary> </div><div class="gmail_default">        ulong[] keySchedule;</div><div class="gmail_default"><br></div><div class="gmail_default">        int[] rotateSchedule;</div><div class="gmail_default">        #endregion</div><div class="gmail_default"><br></div><div class="gmail_default">        #region // Constructors</div><div class="gmail_default"><br></div><div class="gmail_default">        /// <summary></div><div class="gmail_default">        /// Constructor, creates a permutation function mapping an input of </div><div class="gmail_default">        /// length <paramref name="bits"/> to an output of length <paramref name="bits"/></div><div class="gmail_default">        /// according to the value of <paramref name="key"/>.</div><div class="gmail_default">        /// <para>Once the key schedule is set up, calls to Permute will always return</div><div class="gmail_default">        /// a different output if the low order bits <paramref name="bits"/> are </div><div class="gmail_default">        /// different and the same otherwise.</para></div><div class="gmail_default">        /// </summary></div><div class="gmail_default">        /// <param name="key">The key.</param></div><div class="gmail_default">        /// <param name="bits">The number of bits to permute.</param></div><div class="gmail_default">        /// <param name="rounds">The number of permutation rounds to perform.</param></div><div class="gmail_default">        public ShortBlockPermute(byte[] key, int bits, int rounds=0) {</div><div class="gmail_default"><br></div><div class="gmail_default">            (bits <= 64).AssertTrue(NYI.Throw); ; // Block size is 64 bits or less.</div><div class="gmail_default">            Bits = bits;</div><div class="gmail_default"><br></div><div class="gmail_default">            // If not specified, set the number of rounds to be the number of bits plus 12</div><div class="gmail_default">            // This is arbitrary at this point.</div><div class="gmail_default">            Rounds = rounds > 0 ? rounds : Bits + 12;</div><div class="gmail_default">            (Rounds <= 255).AssertTrue(NYI.Throw); ; // Number of rounds is 255 or less.</div><div class="gmail_default"><br></div><div class="gmail_default">            // Create the bitmask</div><div class="gmail_default">            Mask = 1;</div><div class="gmail_default">            for (var i = 1; i < Bits; i++) {</div><div class="gmail_default">                Mask |= Mask >> 1;</div><div class="gmail_default">                }</div><div class="gmail_default"><br></div><div class="gmail_default">            // Create the key schedule. This is almost certainly more baroque than needed.</div><div class="gmail_default">            keySchedule = new ulong[Rounds];</div><div class="gmail_default">            rotateSchedule = new int[Rounds];</div><div class="gmail_default">            var kdf = new KeyDeriveHKDF(key, "ShortBlockPermute");</div><div class="gmail_default">            var info = new byte[1];</div><div class="gmail_default">            for (var i = 0; i < Rounds; i++) {</div><div class="gmail_default">                info[0] = (byte)i;</div><div class="gmail_default">                var bytes = kdf.Derive(info, 8).BigEndianInt(8);</div><div class="gmail_default">                keySchedule[i] = Mask & bytes ;</div><div class="gmail_default">                rotateSchedule[i] = (int) bytes % Bits;</div><div class="gmail_default">                }</div><div class="gmail_default">            }</div><div class="gmail_default">        #endregion</div><div class="gmail_default">        #region // Private methods </div><div class="gmail_default"><br></div><div class="gmail_default">        ulong Rotate(ulong input, int bits) =></div><div class="gmail_default">                input << bits | (input >> Bits - bits);</div><div class="gmail_default"><br></div><div class="gmail_default">        #endregion</div><div class="gmail_default">        #region // Public methods </div><div class="gmail_default"><br></div><div class="gmail_default">        /// <summary></div><div class="gmail_default">        /// Permute the lower n bits of <paramref name="input"/> according to the </div><div class="gmail_default">        /// schedule established by the constructor.</div><div class="gmail_default">        /// </summary></div><div class="gmail_default">        /// <param name="input"></param></div><div class="gmail_default">        /// <returns></returns></div><div class="gmail_default">        public ulong Permute(ulong input) {</div><div class="gmail_default">            var data = input & Mask;</div><div class="gmail_default"><br></div><div class="gmail_default"><div class="gmail_default">            unchecked {</div><div class="gmail_default">                // If I did this right, each of the three operations is reversible and no data is lost.</div><div class="gmail_default">                // The operations are chosen to provide non-linearity relative to each other while</div><div class="gmail_default">                // working the key at each step.</div><div class="gmail_default">                for (var i = 0; i < Rounds; i++) {</div><div class="gmail_default">                    data ^= keySchedule[i];</div><div class="gmail_default">                    data &= Mask;                   // for clarity, can remove</div><div class="gmail_default">                    data = Rotate(data, rotateSchedule[i]);</div><div class="gmail_default">                    data &= Mask;                   // for clarity, can remove</div><div class="gmail_default">                    data += keySchedule[i];</div><div class="gmail_default">                    data &= Mask;                   // This one is essential.</div><div class="gmail_default">                    }</div><div class="gmail_default">                }</div></div><div class="gmail_default"><br></div><div class="gmail_default">            return data;</div><div class="gmail_default">            }</div><div class="gmail_default"><br></div><div class="gmail_default">        /// <summary></div><div class="gmail_default">        /// A depermutation function could be implemented but that would encourage people</div><div class="gmail_default">        /// to use this for encrypting data.</div><div class="gmail_default">        /// </summary></div><div class="gmail_default">        /// <param name="input">The cipertext.</param></div><div class="gmail_default">        /// <returns>The function always returns an exception.</returns></div><div class="gmail_default">        public ulong Depermute(ulong input) => throw new Exception();</div><div class="gmail_default"><br></div><div class="gmail_default">        #endregion</div><div class="gmail_default">        }</div><div style="font-size:small"><br></div></div><div class="gmail_default" style="font-size:small"></div></div></div></div></div></div></div></div></div>