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