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