/**
* EdDSA-Java by str4d
*
* To the extent possible under law, the person who associated CC0 with
* EdDSA-Java has waived all copyright and related or neighboring rights
* to EdDSA-Java.
*
* You should have received a copy of the CC0 legalcode along with this
* work. If not, see
* Reviewed/commented by Bloody Rookie (nemproject@gmx.de) */ public class Ed25519LittleEndianEncoding extends Encoding { /** * Encodes a given field element in its 32 byte representation. This is done in two steps: *
* The idea for the modulo $p$ reduction algorithm is as follows: *
** Then $q = [2^{-255} * (h + 19 * 2^{-25} * h_9 + 1/2)]$ where $[x] = floor(x)$. *
** We begin with some very raw estimation for the bounds of some expressions: *
* $$ * \begin{equation} * |h| \lt 2^{230} * 2^{30} = 2^{260} \Rightarrow |r + q * p| \lt 2^{260} \Rightarrow |q| \lt 2^{10}. \\ * \Rightarrow -1/4 \le a := 19^2 * 2^{-255} * q \lt 1/4. \\ * |h - 2^{230} * h_9| = |h_0 + \dots + 2^{204} * h_8| \lt 2^{204} * 2^{30} = 2^{234}. \\ * \Rightarrow -1/4 \le b := 19 * 2^{-255} * (h - 2^{230} * h_9) \lt 1/4 * \end{equation} * $$ *
* Therefore $0 \lt 1/2 - a - b \lt 1$. *
* Set $x := r + 19 * 2^{-255} * r + 1/2 - a - b$. Then: *
* $$ * 0 \le x \lt 255 - 20 + 19 + 1 = 2^{255} \\ * \Rightarrow 0 \le 2^{-255} * x \lt 1. * $$ *
* Since $q$ is an integer we have *
* $$ * [q + 2^{-255} * x] = q \quad (1) * $$ *
* Have a closer look at $x$: *
* $$ * \begin{align} * x &= h - q * (2^{255} - 19) + 19 * 2^{-255} * (h - q * (2^{255} - 19)) + 1/2 - 19^2 * 2^{-255} * q - 19 * 2^{-255} * (h - 2^{230} * h_9) \\ * &= h - q * 2^{255} + 19 * q + 19 * 2^{-255} * h - 19 * q + 19^2 * 2^{-255} * q + 1/2 - 19^2 * 2^{-255} * q - 19 * 2^{-255} * h + 19 * 2^{-25} * h_9 \\ * &= h + 19 * 2^{-25} * h_9 + 1/2 - q^{255}. * \end{align} * $$ *
* Inserting the expression for $x$ into $(1)$ we get the desired expression for $q$. */ public byte[] encode(FieldElement x) { int[] h = ((Ed25519FieldElement)x).t; int h0 = h[0]; int h1 = h[1]; int h2 = h[2]; int h3 = h[3]; int h4 = h[4]; int h5 = h[5]; int h6 = h[6]; int h7 = h[7]; int h8 = h[8]; int h9 = h[9]; int q; int carry0; int carry1; int carry2; int carry3; int carry4; int carry5; int carry6; int carry7; int carry8; int carry9; // Step 1: // Calculate q q = (19 * h9 + (1 << 24)) >> 25; q = (h0 + q) >> 26; q = (h1 + q) >> 25; q = (h2 + q) >> 26; q = (h3 + q) >> 25; q = (h4 + q) >> 26; q = (h5 + q) >> 25; q = (h6 + q) >> 26; q = (h7 + q) >> 25; q = (h8 + q) >> 26; q = (h9 + q) >> 25; // r = h - q * p = h - 2^255 * q + 19 * q // First add 19 * q then discard the bit 255 h0 += 19 * q; carry0 = h0 >> 26; h1 += carry0; h0 -= carry0 << 26; carry1 = h1 >> 25; h2 += carry1; h1 -= carry1 << 25; carry2 = h2 >> 26; h3 += carry2; h2 -= carry2 << 26; carry3 = h3 >> 25; h4 += carry3; h3 -= carry3 << 25; carry4 = h4 >> 26; h5 += carry4; h4 -= carry4 << 26; carry5 = h5 >> 25; h6 += carry5; h5 -= carry5 << 25; carry6 = h6 >> 26; h7 += carry6; h6 -= carry6 << 26; carry7 = h7 >> 25; h8 += carry7; h7 -= carry7 << 25; carry8 = h8 >> 26; h9 += carry8; h8 -= carry8 << 26; carry9 = h9 >> 25; h9 -= carry9 << 25; // Step 2 (straight forward conversion): byte[] s = new byte[32]; s[0] = (byte) h0; s[1] = (byte) (h0 >> 8); s[2] = (byte) (h0 >> 16); s[3] = (byte) ((h0 >> 24) | (h1 << 2)); s[4] = (byte) (h1 >> 6); s[5] = (byte) (h1 >> 14); s[6] = (byte) ((h1 >> 22) | (h2 << 3)); s[7] = (byte) (h2 >> 5); s[8] = (byte) (h2 >> 13); s[9] = (byte) ((h2 >> 21) | (h3 << 5)); s[10] = (byte) (h3 >> 3); s[11] = (byte) (h3 >> 11); s[12] = (byte) ((h3 >> 19) | (h4 << 6)); s[13] = (byte) (h4 >> 2); s[14] = (byte) (h4 >> 10); s[15] = (byte) (h4 >> 18); s[16] = (byte) h5; s[17] = (byte) (h5 >> 8); s[18] = (byte) (h5 >> 16); s[19] = (byte) ((h5 >> 24) | (h6 << 1)); s[20] = (byte) (h6 >> 7); s[21] = (byte) (h6 >> 15); s[22] = (byte) ((h6 >> 23) | (h7 << 3)); s[23] = (byte) (h7 >> 5); s[24] = (byte) (h7 >> 13); s[25] = (byte) ((h7 >> 21) | (h8 << 4)); s[26] = (byte) (h8 >> 4); s[27] = (byte) (h8 >> 12); s[28] = (byte) ((h8 >> 20) | (h9 << 6)); s[29] = (byte) (h9 >> 2); s[30] = (byte) (h9 >> 10); s[31] = (byte) (h9 >> 18); return s; } static int load_3(byte[] in, int offset) { int result = in[offset++] & 0xff; result |= (in[offset++] & 0xff) << 8; result |= (in[offset] & 0xff) << 16; return result; } static long load_4(byte[] in, int offset) { int result = in[offset++] & 0xff; result |= (in[offset++] & 0xff) << 8; result |= (in[offset++] & 0xff) << 16; result |= in[offset] << 24; return ((long)result) & 0xffffffffL; } /** * Decodes a given field element in its 10 byte $2^{25.5}$ representation. * * @param in The 32 byte representation. * @return The field element in its $2^{25.5}$ bit representation. */ public FieldElement decode(byte[] in) { long h0 = load_4(in, 0); long h1 = load_3(in, 4) << 6; long h2 = load_3(in, 7) << 5; long h3 = load_3(in, 10) << 3; long h4 = load_3(in, 13) << 2; long h5 = load_4(in, 16); long h6 = load_3(in, 20) << 7; long h7 = load_3(in, 23) << 5; long h8 = load_3(in, 26) << 4; long h9 = (load_3(in, 29) & 0x7FFFFF) << 2; long carry0; long carry1; long carry2; long carry3; long carry4; long carry5; long carry6; long carry7; long carry8; long carry9; // Remember: 2^255 congruent 19 modulo p carry9 = (h9 + (long) (1<<24)) >> 25; h0 += carry9 * 19; h9 -= carry9 << 25; carry1 = (h1 + (long) (1<<24)) >> 25; h2 += carry1; h1 -= carry1 << 25; carry3 = (h3 + (long) (1<<24)) >> 25; h4 += carry3; h3 -= carry3 << 25; carry5 = (h5 + (long) (1<<24)) >> 25; h6 += carry5; h5 -= carry5 << 25; carry7 = (h7 + (long) (1<<24)) >> 25; h8 += carry7; h7 -= carry7 << 25; carry0 = (h0 + (long) (1<<25)) >> 26; h1 += carry0; h0 -= carry0 << 26; carry2 = (h2 + (long) (1<<25)) >> 26; h3 += carry2; h2 -= carry2 << 26; carry4 = (h4 + (long) (1<<25)) >> 26; h5 += carry4; h4 -= carry4 << 26; carry6 = (h6 + (long) (1<<25)) >> 26; h7 += carry6; h6 -= carry6 << 26; carry8 = (h8 + (long) (1<<25)) >> 26; h9 += carry8; h8 -= carry8 << 26; int[] h = new int[10]; h[0] = (int) h0; h[1] = (int) h1; h[2] = (int) h2; h[3] = (int) h3; h[4] = (int) h4; h[5] = (int) h5; h[6] = (int) h6; h[7] = (int) h7; h[8] = (int) h8; h[9] = (int) h9; return new Ed25519FieldElement(f, h); } /** * Is the FieldElement negative in this encoding? *
* Return true if $x$ is in $\{1,3,5,\dots,q-2\}$
* Return false if $x$ is in $\{0,2,4,\dots,q-1\}$
*
* Preconditions: *