]> pd.if.org Git - zpackage/blob - crypto/ref10/fe_tobytes.c
ocb mode fixup
[zpackage] / crypto / ref10 / fe_tobytes.c
1 #include <stdint.h>
2
3 /*
4 Preconditions:
5   |h| bounded by 1.1*2^25,1.1*2^24,1.1*2^25,1.1*2^24,etc.
6
7 Write p=2^255-19; q=floor(h/p).
8 Basic claim: q = floor(2^(-255)(h + 19 2^(-25)h9 + 2^(-1))).
9
10 Proof:
11   Have |h|<=p so |q|<=1 so |19^2 2^(-255) q|<1/4.
12   Also have |h-2^230 h9|<2^230 so |19 2^(-255)(h-2^230 h9)|<1/4.
13
14   Write y=2^(-1)-19^2 2^(-255)q-19 2^(-255)(h-2^230 h9).
15   Then 0<y<1.
16
17   Write r=h-pq.
18   Have 0<=r<=p-1=2^255-20.
19   Thus 0<=r+19(2^-255)r<r+19(2^-255)2^255<=2^255-1.
20
21   Write x=r+19(2^-255)r+y.
22   Then 0<x<2^255 so floor(2^(-255)x) = 0 so floor(q+2^(-255)x) = q.
23
24   Have q+2^(-255)x = 2^(-255)(h + 19 2^(-25) h9 + 2^(-1))
25   so floor(2^(-255)(h + 19 2^(-25) h9 + 2^(-1))) = q.
26 */
27
28 void fe_tobytes(unsigned char *s, int32_t h[10]) {
29         int32_t h0 = h[0];
30         int32_t h1 = h[1];
31         int32_t h2 = h[2];
32         int32_t h3 = h[3];
33         int32_t h4 = h[4];
34         int32_t h5 = h[5];
35         int32_t h6 = h[6];
36         int32_t h7 = h[7];
37         int32_t h8 = h[8];
38         int32_t h9 = h[9];
39         int32_t q;
40         int32_t carry0;
41         int32_t carry1;
42         int32_t carry2;
43         int32_t carry3;
44         int32_t carry4;
45         int32_t carry5;
46         int32_t carry6;
47         int32_t carry7;
48         int32_t carry8;
49         int32_t carry9;
50
51         q = (19 * h9 + (((int32_t) 1) << 24)) >> 25;
52         q = (h0 + q) >> 26;
53         q = (h1 + q) >> 25;
54         q = (h2 + q) >> 26;
55         q = (h3 + q) >> 25;
56         q = (h4 + q) >> 26;
57         q = (h5 + q) >> 25;
58         q = (h6 + q) >> 26;
59         q = (h7 + q) >> 25;
60         q = (h8 + q) >> 26;
61         q = (h9 + q) >> 25;
62
63         /* Goal: Output h-(2^255-19)q, which is between 0 and 2^255-20. */
64         h0 += 19 * q;
65         /* Goal: Output h-2^255 q, which is between 0 and 2^255-20. */
66
67         carry0 = h0 >> 26; h1 += carry0; h0 -= carry0 << 26;
68         carry1 = h1 >> 25; h2 += carry1; h1 -= carry1 << 25;
69         carry2 = h2 >> 26; h3 += carry2; h2 -= carry2 << 26;
70         carry3 = h3 >> 25; h4 += carry3; h3 -= carry3 << 25;
71         carry4 = h4 >> 26; h5 += carry4; h4 -= carry4 << 26;
72         carry5 = h5 >> 25; h6 += carry5; h5 -= carry5 << 25;
73         carry6 = h6 >> 26; h7 += carry6; h6 -= carry6 << 26;
74         carry7 = h7 >> 25; h8 += carry7; h7 -= carry7 << 25;
75         carry8 = h8 >> 26; h9 += carry8; h8 -= carry8 << 26;
76         carry9 = h9 >> 25;               h9 -= carry9 << 25;
77         /* h10 = carry9 */
78
79         /*
80 Goal: Output h0+...+2^255 h10-2^255 q, which is between 0 and 2^255-20.
81 Have h0+...+2^230 h9 between 0 and 2^255-1;
82 evidently 2^255 h10-2^255 q = 0.
83 Goal: Output h0+...+2^230 h9.
84 */
85
86         s[0] = h0 >> 0;
87         s[1] = h0 >> 8;
88         s[2] = h0 >> 16;
89         s[3] = (h0 >> 24) | (h1 << 2);
90         s[4] = h1 >> 6;
91         s[5] = h1 >> 14;
92         s[6] = (h1 >> 22) | (h2 << 3);
93         s[7] = h2 >> 5;
94         s[8] = h2 >> 13;
95         s[9] = (h2 >> 21) | (h3 << 5);
96         s[10] = h3 >> 3;
97         s[11] = h3 >> 11;
98         s[12] = (h3 >> 19) | (h4 << 6);
99         s[13] = h4 >> 2;
100         s[14] = h4 >> 10;
101         s[15] = h4 >> 18;
102         s[16] = h5 >> 0;
103         s[17] = h5 >> 8;
104         s[18] = h5 >> 16;
105         s[19] = (h5 >> 24) | (h6 << 1);
106         s[20] = h6 >> 7;
107         s[21] = h6 >> 15;
108         s[22] = (h6 >> 23) | (h7 << 3);
109         s[23] = h7 >> 5;
110         s[24] = h7 >> 13;
111         s[25] = (h7 >> 21) | (h8 << 4);
112         s[26] = h8 >> 4;
113         s[27] = h8 >> 12;
114         s[28] = (h8 >> 20) | (h9 << 6);
115         s[29] = h9 >> 2;
116         s[30] = h9 >> 10;
117         s[31] = h9 >> 18;
118 }