1/*
2 Ignores top bit of h.
3 */
4
5void
6fe25519_frombytes(fe25519 h, const unsigned char *s)
7{
8    const uint64_t mask = 0x7ffffffffffffULL;
9    uint64_t h0, h1, h2, h3, h4;
10
11    h0 = (LOAD64_LE(s     )      ) & mask;
12    h1 = (LOAD64_LE(s +  6) >>  3) & mask;
13    h2 = (LOAD64_LE(s + 12) >>  6) & mask;
14    h3 = (LOAD64_LE(s + 19) >>  1) & mask;
15    h4 = (LOAD64_LE(s + 24) >> 12) & mask;
16
17    h[0] = h0;
18    h[1] = h1;
19    h[2] = h2;
20    h[3] = h3;
21    h[4] = h4;
22}
23
24static void
25fe25519_reduce(fe25519 h, const fe25519 f)
26{
27    const uint64_t mask = 0x7ffffffffffffULL;
28    uint128_t t[5];
29
30    t[0] = f[0];
31    t[1] = f[1];
32    t[2] = f[2];
33    t[3] = f[3];
34    t[4] = f[4];
35
36    t[1] += t[0] >> 51;
37    t[0] &= mask;
38    t[2] += t[1] >> 51;
39    t[1] &= mask;
40    t[3] += t[2] >> 51;
41    t[2] &= mask;
42    t[4] += t[3] >> 51;
43    t[3] &= mask;
44    t[0] += 19 * (t[4] >> 51);
45    t[4] &= mask;
46
47    t[1] += t[0] >> 51;
48    t[0] &= mask;
49    t[2] += t[1] >> 51;
50    t[1] &= mask;
51    t[3] += t[2] >> 51;
52    t[2] &= mask;
53    t[4] += t[3] >> 51;
54    t[3] &= mask;
55    t[0] += 19 * (t[4] >> 51);
56    t[4] &= mask;
57
58    /* now t is between 0 and 2^255-1, properly carried. */
59    /* case 1: between 0 and 2^255-20. case 2: between 2^255-19 and 2^255-1. */
60
61    t[0] += 19ULL;
62
63    t[1] += t[0] >> 51;
64    t[0] &= mask;
65    t[2] += t[1] >> 51;
66    t[1] &= mask;
67    t[3] += t[2] >> 51;
68    t[2] &= mask;
69    t[4] += t[3] >> 51;
70    t[3] &= mask;
71    t[0] += 19ULL * (t[4] >> 51);
72    t[4] &= mask;
73
74    /* now between 19 and 2^255-1 in both cases, and offset by 19. */
75
76    t[0] += 0x8000000000000 - 19ULL;
77    t[1] += 0x8000000000000 - 1ULL;
78    t[2] += 0x8000000000000 - 1ULL;
79    t[3] += 0x8000000000000 - 1ULL;
80    t[4] += 0x8000000000000 - 1ULL;
81
82    /* now between 2^255 and 2^256-20, and offset by 2^255. */
83
84    t[1] += t[0] >> 51;
85    t[0] &= mask;
86    t[2] += t[1] >> 51;
87    t[1] &= mask;
88    t[3] += t[2] >> 51;
89    t[2] &= mask;
90    t[4] += t[3] >> 51;
91    t[3] &= mask;
92    t[4] &= mask;
93
94    h[0] = t[0];
95    h[1] = t[1];
96    h[2] = t[2];
97    h[3] = t[3];
98    h[4] = t[4];
99}
100
101void
102fe25519_tobytes(unsigned char *s, const fe25519 h)
103{
104    fe25519  t;
105    uint64_t t0, t1, t2, t3;
106
107    fe25519_reduce(t, h);
108    t0 = t[0] | (t[1] << 51);
109    t1 = (t[1] >> 13) | (t[2] << 38);
110    t2 = (t[2] >> 26) | (t[3] << 25);
111    t3 = (t[3] >> 39) | (t[4] << 12);
112    STORE64_LE(s +  0, t0);
113    STORE64_LE(s +  8, t1);
114    STORE64_LE(s + 16, t2);
115    STORE64_LE(s + 24, t3);
116}
117