1d4afb5ceSopenharmony_ci/* $OpenBSD: smult_curve25519_ref.c,v 1.2 2013/11/02 22:02:14 markus Exp $ */
2d4afb5ceSopenharmony_ci/*
3d4afb5ceSopenharmony_civersion 20081011
4d4afb5ceSopenharmony_ciMatthew Dempsky
5d4afb5ceSopenharmony_ciPublic domain.
6d4afb5ceSopenharmony_ciDerived from public domain code by D. J. Bernstein.
7d4afb5ceSopenharmony_ci*/
8d4afb5ceSopenharmony_ci
9d4afb5ceSopenharmony_cistatic void add(unsigned int out[32],const unsigned int a[32],const unsigned int b[32])
10d4afb5ceSopenharmony_ci{
11d4afb5ceSopenharmony_ci  unsigned int j;
12d4afb5ceSopenharmony_ci  unsigned int u;
13d4afb5ceSopenharmony_ci  u = 0;
14d4afb5ceSopenharmony_ci  for (j = 0;j < 31;++j) { u += a[j] + b[j]; out[j] = u & 255; u >>= 8; }
15d4afb5ceSopenharmony_ci  u += a[31] + b[31]; out[31] = u;
16d4afb5ceSopenharmony_ci}
17d4afb5ceSopenharmony_ci
18d4afb5ceSopenharmony_cistatic void sub(unsigned int out[32],const unsigned int a[32],const unsigned int b[32])
19d4afb5ceSopenharmony_ci{
20d4afb5ceSopenharmony_ci  unsigned int j;
21d4afb5ceSopenharmony_ci  unsigned int u;
22d4afb5ceSopenharmony_ci  u = 218;
23d4afb5ceSopenharmony_ci  for (j = 0;j < 31;++j) {
24d4afb5ceSopenharmony_ci    u += a[j] + 65280 - b[j];
25d4afb5ceSopenharmony_ci    out[j] = u & 255;
26d4afb5ceSopenharmony_ci    u >>= 8;
27d4afb5ceSopenharmony_ci  }
28d4afb5ceSopenharmony_ci  u += a[31] - b[31];
29d4afb5ceSopenharmony_ci  out[31] = u;
30d4afb5ceSopenharmony_ci}
31d4afb5ceSopenharmony_ci
32d4afb5ceSopenharmony_cistatic void squeeze(unsigned int a[32])
33d4afb5ceSopenharmony_ci{
34d4afb5ceSopenharmony_ci  unsigned int j;
35d4afb5ceSopenharmony_ci  unsigned int u;
36d4afb5ceSopenharmony_ci  u = 0;
37d4afb5ceSopenharmony_ci  for (j = 0;j < 31;++j) { u += a[j]; a[j] = u & 255; u >>= 8; }
38d4afb5ceSopenharmony_ci  u += a[31]; a[31] = u & 127;
39d4afb5ceSopenharmony_ci  u = 19 * (u >> 7);
40d4afb5ceSopenharmony_ci  for (j = 0;j < 31;++j) { u += a[j]; a[j] = u & 255; u >>= 8; }
41d4afb5ceSopenharmony_ci  u += a[31]; a[31] = u;
42d4afb5ceSopenharmony_ci}
43d4afb5ceSopenharmony_ci
44d4afb5ceSopenharmony_cistatic const unsigned int minusp[32] = {
45d4afb5ceSopenharmony_ci 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 128
46d4afb5ceSopenharmony_ci} ;
47d4afb5ceSopenharmony_ci
48d4afb5ceSopenharmony_cistatic void freeze(unsigned int a[32])
49d4afb5ceSopenharmony_ci{
50d4afb5ceSopenharmony_ci  unsigned int aorig[32];
51d4afb5ceSopenharmony_ci  unsigned int j;
52d4afb5ceSopenharmony_ci  unsigned int negative;
53d4afb5ceSopenharmony_ci
54d4afb5ceSopenharmony_ci  for (j = 0;j < 32;++j) aorig[j] = a[j];
55d4afb5ceSopenharmony_ci  add(a,a,minusp);
56d4afb5ceSopenharmony_ci  negative = (unsigned int)-(int)((a[31] >> 7) & 1);
57d4afb5ceSopenharmony_ci  for (j = 0;j < 32;++j) a[j] ^= negative & (aorig[j] ^ a[j]);
58d4afb5ceSopenharmony_ci}
59d4afb5ceSopenharmony_ci
60d4afb5ceSopenharmony_cistatic void mult(unsigned int out[32],const unsigned int a[32],const unsigned int b[32])
61d4afb5ceSopenharmony_ci{
62d4afb5ceSopenharmony_ci  unsigned int i;
63d4afb5ceSopenharmony_ci
64d4afb5ceSopenharmony_ci  for (i = 0;i < 32;++i) {
65d4afb5ceSopenharmony_ci    unsigned int j;
66d4afb5ceSopenharmony_ci    unsigned int u;
67d4afb5ceSopenharmony_ci    u = 0;
68d4afb5ceSopenharmony_ci    for (j = 0;j <= i;++j) u += a[j] * b[i - j];
69d4afb5ceSopenharmony_ci    for (j = i + 1;j < 32;++j) u += 38 * a[j] * b[i + 32 - j];
70d4afb5ceSopenharmony_ci    out[i] = u;
71d4afb5ceSopenharmony_ci  }
72d4afb5ceSopenharmony_ci  squeeze(out);
73d4afb5ceSopenharmony_ci}
74d4afb5ceSopenharmony_ci
75d4afb5ceSopenharmony_cistatic void mult121665(unsigned int out[32],const unsigned int a[32])
76d4afb5ceSopenharmony_ci{
77d4afb5ceSopenharmony_ci  unsigned int j;
78d4afb5ceSopenharmony_ci  unsigned int u;
79d4afb5ceSopenharmony_ci
80d4afb5ceSopenharmony_ci  u = 0;
81d4afb5ceSopenharmony_ci  for (j = 0;j < 31;++j) { u += 121665 * a[j]; out[j] = u & 255; u >>= 8; }
82d4afb5ceSopenharmony_ci  u += 121665 * a[31]; out[31] = u & 127;
83d4afb5ceSopenharmony_ci  u = 19 * (u >> 7);
84d4afb5ceSopenharmony_ci  for (j = 0;j < 31;++j) { u += out[j]; out[j] = u & 255; u >>= 8; }
85d4afb5ceSopenharmony_ci  u += out[j]; out[j] = u;
86d4afb5ceSopenharmony_ci}
87d4afb5ceSopenharmony_ci
88d4afb5ceSopenharmony_cistatic void square(unsigned int out[32],const unsigned int a[32])
89d4afb5ceSopenharmony_ci{
90d4afb5ceSopenharmony_ci  unsigned int i;
91d4afb5ceSopenharmony_ci  unsigned int j;
92d4afb5ceSopenharmony_ci  unsigned int u;
93d4afb5ceSopenharmony_ci
94d4afb5ceSopenharmony_ci  for (i = 0;i < 32;++i) {
95d4afb5ceSopenharmony_ci    u = 0;
96d4afb5ceSopenharmony_ci    for (j = 0;j < i - j;++j) u += a[j] * a[i - j];
97d4afb5ceSopenharmony_ci    for (j = i + 1;j < i + 32 - j;++j)
98d4afb5ceSopenharmony_ci	    if (i + 32 - j < 32 && j < 32)
99d4afb5ceSopenharmony_ci		    u += 38 * a[j] * a[i + 32 - j];
100d4afb5ceSopenharmony_ci    u *= 2;
101d4afb5ceSopenharmony_ci    if ((i & 1) == 0) {
102d4afb5ceSopenharmony_ci      u += a[i / 2] * a[i / 2];
103d4afb5ceSopenharmony_ci      u += 38 * a[i / 2 + 16] * a[i / 2 + 16];
104d4afb5ceSopenharmony_ci    }
105d4afb5ceSopenharmony_ci    out[i] = u;
106d4afb5ceSopenharmony_ci  }
107d4afb5ceSopenharmony_ci  squeeze(out);
108d4afb5ceSopenharmony_ci}
109d4afb5ceSopenharmony_ci
110d4afb5ceSopenharmony_cistatic void smc_select(unsigned int p[64],unsigned int q[64],const unsigned int r[64],const unsigned int s[64],unsigned int b)
111d4afb5ceSopenharmony_ci{
112d4afb5ceSopenharmony_ci  unsigned int j;
113d4afb5ceSopenharmony_ci  unsigned int t;
114d4afb5ceSopenharmony_ci  unsigned int bminus1;
115d4afb5ceSopenharmony_ci
116d4afb5ceSopenharmony_ci  bminus1 = b - 1;
117d4afb5ceSopenharmony_ci  for (j = 0;j < 64;++j) {
118d4afb5ceSopenharmony_ci    t = bminus1 & (r[j] ^ s[j]);
119d4afb5ceSopenharmony_ci    p[j] = s[j] ^ t;
120d4afb5ceSopenharmony_ci    q[j] = r[j] ^ t;
121d4afb5ceSopenharmony_ci  }
122d4afb5ceSopenharmony_ci}
123d4afb5ceSopenharmony_ci
124d4afb5ceSopenharmony_cistatic void mainloop(unsigned int work[64],const unsigned char e[32])
125d4afb5ceSopenharmony_ci{
126d4afb5ceSopenharmony_ci  unsigned int xzm1[64];
127d4afb5ceSopenharmony_ci  unsigned int xzm[64];
128d4afb5ceSopenharmony_ci  unsigned int xzmb[64];
129d4afb5ceSopenharmony_ci  unsigned int xzm1b[64];
130d4afb5ceSopenharmony_ci  unsigned int xznb[64];
131d4afb5ceSopenharmony_ci  unsigned int xzn1b[64];
132d4afb5ceSopenharmony_ci  unsigned int a0[64];
133d4afb5ceSopenharmony_ci  unsigned int a1[64];
134d4afb5ceSopenharmony_ci  unsigned int b0[64];
135d4afb5ceSopenharmony_ci  unsigned int b1[64];
136d4afb5ceSopenharmony_ci  unsigned int c1[64];
137d4afb5ceSopenharmony_ci  unsigned int r[32];
138d4afb5ceSopenharmony_ci  unsigned int s[32];
139d4afb5ceSopenharmony_ci  unsigned int t[32];
140d4afb5ceSopenharmony_ci  unsigned int u[32];
141d4afb5ceSopenharmony_ci  unsigned int j;
142d4afb5ceSopenharmony_ci  unsigned int b;
143d4afb5ceSopenharmony_ci  int pos;
144d4afb5ceSopenharmony_ci
145d4afb5ceSopenharmony_ci  for (j = 0;j < 32;++j) xzm1[j] = work[j];
146d4afb5ceSopenharmony_ci  xzm1[32] = 1;
147d4afb5ceSopenharmony_ci  for (j = 33;j < 64;++j) xzm1[j] = 0;
148d4afb5ceSopenharmony_ci
149d4afb5ceSopenharmony_ci  xzm[0] = 1;
150d4afb5ceSopenharmony_ci  for (j = 1;j < 64;++j) xzm[j] = 0;
151d4afb5ceSopenharmony_ci
152d4afb5ceSopenharmony_ci  for (pos = 254;pos >= 0;--pos) {
153d4afb5ceSopenharmony_ci    b = (unsigned int)(e[pos / 8] >> (pos & 7));
154d4afb5ceSopenharmony_ci    b &= 1;
155d4afb5ceSopenharmony_ci    smc_select(xzmb,xzm1b,xzm,xzm1,b);
156d4afb5ceSopenharmony_ci    add(a0,xzmb,xzmb + 32);
157d4afb5ceSopenharmony_ci    sub(a0 + 32,xzmb,xzmb + 32);
158d4afb5ceSopenharmony_ci    add(a1,xzm1b,xzm1b + 32);
159d4afb5ceSopenharmony_ci    sub(a1 + 32,xzm1b,xzm1b + 32);
160d4afb5ceSopenharmony_ci    square(b0,a0);
161d4afb5ceSopenharmony_ci    square(b0 + 32,a0 + 32);
162d4afb5ceSopenharmony_ci    mult(b1,a1,a0 + 32);
163d4afb5ceSopenharmony_ci    mult(b1 + 32,a1 + 32,a0);
164d4afb5ceSopenharmony_ci    add(c1,b1,b1 + 32);
165d4afb5ceSopenharmony_ci    sub(c1 + 32,b1,b1 + 32);
166d4afb5ceSopenharmony_ci    square(r,c1 + 32);
167d4afb5ceSopenharmony_ci    sub(s,b0,b0 + 32);
168d4afb5ceSopenharmony_ci    mult121665(t,s);
169d4afb5ceSopenharmony_ci    add(u,t,b0);
170d4afb5ceSopenharmony_ci    mult(xznb,b0,b0 + 32);
171d4afb5ceSopenharmony_ci    mult(xznb + 32,s,u);
172d4afb5ceSopenharmony_ci    square(xzn1b,c1);
173d4afb5ceSopenharmony_ci    mult(xzn1b + 32,r,work);
174d4afb5ceSopenharmony_ci    smc_select(xzm,xzm1,xznb,xzn1b,b);
175d4afb5ceSopenharmony_ci  }
176d4afb5ceSopenharmony_ci
177d4afb5ceSopenharmony_ci  for (j = 0;j < 64;++j) work[j] = xzm[j];
178d4afb5ceSopenharmony_ci}
179d4afb5ceSopenharmony_ci
180d4afb5ceSopenharmony_cistatic void recip(unsigned int out[32],const unsigned int z[32])
181d4afb5ceSopenharmony_ci{
182d4afb5ceSopenharmony_ci  unsigned int z2[32];
183d4afb5ceSopenharmony_ci  unsigned int z9[32];
184d4afb5ceSopenharmony_ci  unsigned int z11[32];
185d4afb5ceSopenharmony_ci  unsigned int z2_5_0[32];
186d4afb5ceSopenharmony_ci  unsigned int z2_10_0[32];
187d4afb5ceSopenharmony_ci  unsigned int z2_20_0[32];
188d4afb5ceSopenharmony_ci  unsigned int z2_50_0[32];
189d4afb5ceSopenharmony_ci  unsigned int z2_100_0[32];
190d4afb5ceSopenharmony_ci  unsigned int t0[32];
191d4afb5ceSopenharmony_ci  unsigned int t1[32];
192d4afb5ceSopenharmony_ci  int i;
193d4afb5ceSopenharmony_ci
194d4afb5ceSopenharmony_ci  /* 2 */ square(z2,z);
195d4afb5ceSopenharmony_ci  /* 4 */ square(t1,z2);
196d4afb5ceSopenharmony_ci  /* 8 */ square(t0,t1);
197d4afb5ceSopenharmony_ci  /* 9 */ mult(z9,t0,z);
198d4afb5ceSopenharmony_ci  /* 11 */ mult(z11,z9,z2);
199d4afb5ceSopenharmony_ci  /* 22 */ square(t0,z11);
200d4afb5ceSopenharmony_ci  /* 2^5 - 2^0 = 31 */ mult(z2_5_0,t0,z9);
201d4afb5ceSopenharmony_ci
202d4afb5ceSopenharmony_ci  /* 2^6 - 2^1 */ square(t0,z2_5_0);
203d4afb5ceSopenharmony_ci  /* 2^7 - 2^2 */ square(t1,t0);
204d4afb5ceSopenharmony_ci  /* 2^8 - 2^3 */ square(t0,t1);
205d4afb5ceSopenharmony_ci  /* 2^9 - 2^4 */ square(t1,t0);
206d4afb5ceSopenharmony_ci  /* 2^10 - 2^5 */ square(t0,t1);
207d4afb5ceSopenharmony_ci  /* 2^10 - 2^0 */ mult(z2_10_0,t0,z2_5_0);
208d4afb5ceSopenharmony_ci
209d4afb5ceSopenharmony_ci  /* 2^11 - 2^1 */ square(t0,z2_10_0);
210d4afb5ceSopenharmony_ci  /* 2^12 - 2^2 */ square(t1,t0);
211d4afb5ceSopenharmony_ci  /* 2^20 - 2^10 */ for (i = 2;i < 10;i += 2) { square(t0,t1); square(t1,t0); }
212d4afb5ceSopenharmony_ci  /* 2^20 - 2^0 */ mult(z2_20_0,t1,z2_10_0);
213d4afb5ceSopenharmony_ci
214d4afb5ceSopenharmony_ci  /* 2^21 - 2^1 */ square(t0,z2_20_0);
215d4afb5ceSopenharmony_ci  /* 2^22 - 2^2 */ square(t1,t0);
216d4afb5ceSopenharmony_ci  /* 2^40 - 2^20 */ for (i = 2;i < 20;i += 2) { square(t0,t1); square(t1,t0); }
217d4afb5ceSopenharmony_ci  /* 2^40 - 2^0 */ mult(t0,t1,z2_20_0);
218d4afb5ceSopenharmony_ci
219d4afb5ceSopenharmony_ci  /* 2^41 - 2^1 */ square(t1,t0);
220d4afb5ceSopenharmony_ci  /* 2^42 - 2^2 */ square(t0,t1);
221d4afb5ceSopenharmony_ci  /* 2^50 - 2^10 */ for (i = 2;i < 10;i += 2) { square(t1,t0); square(t0,t1); }
222d4afb5ceSopenharmony_ci  /* 2^50 - 2^0 */ mult(z2_50_0,t0,z2_10_0);
223d4afb5ceSopenharmony_ci
224d4afb5ceSopenharmony_ci  /* 2^51 - 2^1 */ square(t0,z2_50_0);
225d4afb5ceSopenharmony_ci  /* 2^52 - 2^2 */ square(t1,t0);
226d4afb5ceSopenharmony_ci  /* 2^100 - 2^50 */ for (i = 2;i < 50;i += 2) { square(t0,t1); square(t1,t0); }
227d4afb5ceSopenharmony_ci  /* 2^100 - 2^0 */ mult(z2_100_0,t1,z2_50_0);
228d4afb5ceSopenharmony_ci
229d4afb5ceSopenharmony_ci  /* 2^101 - 2^1 */ square(t1,z2_100_0);
230d4afb5ceSopenharmony_ci  /* 2^102 - 2^2 */ square(t0,t1);
231d4afb5ceSopenharmony_ci  /* 2^200 - 2^100 */ for (i = 2;i < 100;i += 2) { square(t1,t0); square(t0,t1); }
232d4afb5ceSopenharmony_ci  /* 2^200 - 2^0 */ mult(t1,t0,z2_100_0);
233d4afb5ceSopenharmony_ci
234d4afb5ceSopenharmony_ci  /* 2^201 - 2^1 */ square(t0,t1);
235d4afb5ceSopenharmony_ci  /* 2^202 - 2^2 */ square(t1,t0);
236d4afb5ceSopenharmony_ci  /* 2^250 - 2^50 */ for (i = 2;i < 50;i += 2) { square(t0,t1); square(t1,t0); }
237d4afb5ceSopenharmony_ci  /* 2^250 - 2^0 */ mult(t0,t1,z2_50_0);
238d4afb5ceSopenharmony_ci
239d4afb5ceSopenharmony_ci  /* 2^251 - 2^1 */ square(t1,t0);
240d4afb5ceSopenharmony_ci  /* 2^252 - 2^2 */ square(t0,t1);
241d4afb5ceSopenharmony_ci  /* 2^253 - 2^3 */ square(t1,t0);
242d4afb5ceSopenharmony_ci  /* 2^254 - 2^4 */ square(t0,t1);
243d4afb5ceSopenharmony_ci  /* 2^255 - 2^5 */ square(t1,t0);
244d4afb5ceSopenharmony_ci  /* 2^255 - 21 */ mult(out,t1,z11);
245d4afb5ceSopenharmony_ci}
246d4afb5ceSopenharmony_ci
247d4afb5ceSopenharmony_ciint crypto_scalarmult_curve25519(unsigned char *q,
248d4afb5ceSopenharmony_ci  const unsigned char *n,
249d4afb5ceSopenharmony_ci  const unsigned char *p)
250d4afb5ceSopenharmony_ci{
251d4afb5ceSopenharmony_ci  unsigned int work[96];
252d4afb5ceSopenharmony_ci  unsigned char e[32];
253d4afb5ceSopenharmony_ci  unsigned int i;
254d4afb5ceSopenharmony_ci  for (i = 0;i < 32;++i) e[i] = n[i];
255d4afb5ceSopenharmony_ci  e[0] &= 248;
256d4afb5ceSopenharmony_ci  e[31] &= 127;
257d4afb5ceSopenharmony_ci  e[31] |= 64;
258d4afb5ceSopenharmony_ci  for (i = 0;i < 32;++i) work[i] = p[i];
259d4afb5ceSopenharmony_ci  mainloop(work,e);
260d4afb5ceSopenharmony_ci  recip(work + 32,work + 32);
261d4afb5ceSopenharmony_ci  mult(work + 64,work,work + 32);
262d4afb5ceSopenharmony_ci  freeze(work + 64);
263d4afb5ceSopenharmony_ci  for (i = 0;i < 32;++i) q[i] = (unsigned char)work[64 + i];
264d4afb5ceSopenharmony_ci  return 0;
265d4afb5ceSopenharmony_ci}
266