smult.c 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204
  1. /* 2008, Google Inc.
  2. * Code released into the public domain
  3. *
  4. * curve25519: Curve25519 elliptic curve, public key function
  5. *
  6. * Adam Langley <agl@imperialviolet.org>
  7. *
  8. * Derived from public domain C code by Daniel J. Bernstein <djb@cr.yp.to>
  9. *
  10. * More information about curve25519 can be found here
  11. * http://cr.yp.to/ecdh.html
  12. *
  13. * djb's sample implementation of curve25519 is written in a special assembly
  14. * language called qhasm and uses the floating point registers.
  15. *
  16. * This is, almost, a clean room reimplementation from the curve25519 paper. It
  17. * uses many of the tricks described therein. Only the crecip function is taken
  18. * from the sample implementation.
  19. *
  20. * You have to have read the curve25519 paper to understand this code:
  21. * http://cr.yp.to/ecdh/curve25519-20060209.pdf
  22. *
  23. * DJB used limb sizes of ceil(25.5) bits in a 64-bit limb. Thus he has 10
  24. * limbs in a reduced coefficient form. Here, we use 51-bits in a 64-bit limb.
  25. * This means that we use the full 64x64->128 bit mult in x86-64 and are often
  26. * dealing with 128-bit values.
  27. *
  28. * Thus values are stored in arrays of 5 uint64_t's. Index 0 is the least
  29. * significant value. We maintain that the limbs are always positive. The only
  30. * place where this can change is in fdifference_backwards, so we fix up any
  31. * negative values by carrying between them.
  32. */
  33. #include <string.h>
  34. #include <stdint.h>
  35. #include "crypto_scalarmult.h"
  36. typedef uint8_t u8;
  37. typedef uint64_t felem;
  38. /* Sum two numbers: output += in */
  39. static void
  40. fsum(felem *output, const felem *in) {
  41. output[0] = output[0] + in[0];
  42. output[1] = output[1] + in[1];
  43. output[2] = output[2] + in[2];
  44. output[3] = output[3] + in[3];
  45. output[4] = output[4] + in[4];
  46. }
  47. // Externs from the .s file.
  48. extern void crypto_scalarmult_curve25519_donna_fmul(felem *output, const felem *in1, const felem *in2);
  49. extern void crypto_scalarmult_curve25519_donna_fsquare(felem *output, const felem *in1);
  50. extern void crypto_scalarmult_curve25519_donna_fexpand(felem *ouptut, const u8 *input);
  51. extern void crypto_scalarmult_curve25519_donna_fcontract(u8 *output, const felem *input);
  52. extern void crypto_scalarmult_curve25519_donna_freduce_coefficients(felem *inout);
  53. extern void crypto_scalarmult_curve25519_donna_fscalar(felem *output, const felem *input);
  54. extern void crypto_scalarmult_curve25519_donna_fdifference_backwards(felem *output, const felem *input);
  55. extern void crypto_scalarmult_curve25519_donna_cmult(felem *x, felem *z, const u8 *n, const felem *q);
  56. #define fmul crypto_scalarmult_curve25519_donna_fmul
  57. #define fmonty crypto_scalarmult_curve25519_donna_fmonty
  58. #define fsquare crypto_scalarmult_curve25519_donna_fsquare
  59. #define fexpand crypto_scalarmult_curve25519_donna_fexpand
  60. #define fcontract crypto_scalarmult_curve25519_donna_fcontract
  61. #define freduce_coefficients crypto_scalarmult_curve25519_donna_freduce_coefficients
  62. #define fscalar crypto_scalarmult_curve25519_donna_fscalar
  63. #define fdifference_backwards crypto_scalarmult_curve25519_donna_fdifference_backwards
  64. #define cmult crypto_scalarmult_curve25519_donna_cmult
  65. /* Input: Q, Q', Q-Q'
  66. * Output: 2Q, Q+Q'
  67. *
  68. * x2 z3: long form
  69. * x3 z3: long form
  70. * x z: short form, destroyed
  71. * xprime zprime: short form, destroyed
  72. * qmqp: short form, preserved
  73. */
  74. void __attribute__((visibility ("hidden")))
  75. fmonty(felem *x2, /* output 2Q */
  76. felem *x3, /* output Q + Q' */
  77. felem *x, /* input Q */
  78. felem *xprime, /* input Q' */
  79. const felem *qmqp /* input Q - Q' */) {
  80. felem *const z2 = &x2[5];
  81. felem *const z3 = &x3[5];
  82. felem *const z = &x[5];
  83. felem *const zprime = &xprime[5];
  84. felem origx[5], origxprime[5], zzz[5], xx[5], zz[5], xxprime[5],
  85. zzprime[5], zzzprime[5];
  86. memcpy(origx, x, 5 * sizeof(felem));
  87. fsum(x, z);
  88. fdifference_backwards(z, origx); // does x - z
  89. memcpy(origxprime, xprime, sizeof(felem) * 5);
  90. fsum(xprime, zprime);
  91. fdifference_backwards(zprime, origxprime);
  92. fmul(xxprime, xprime, z);
  93. fmul(zzprime, x, zprime);
  94. memcpy(origxprime, xxprime, sizeof(felem) * 5);
  95. fsum(xxprime, zzprime);
  96. fdifference_backwards(zzprime, origxprime);
  97. fsquare(x3, xxprime);
  98. fsquare(zzzprime, zzprime);
  99. fmul(z3, zzzprime, qmqp);
  100. fsquare(xx, x);
  101. fsquare(zz, z);
  102. fmul(x2, xx, zz);
  103. fdifference_backwards(zz, xx); // does zz = xx - zz
  104. fscalar(zzz, zz); // * 121665
  105. freduce_coefficients(zzz);
  106. fsum(zzz, xx);
  107. fmul(z2, zz, zzz);
  108. }
  109. // -----------------------------------------------------------------------------
  110. // Shamelessly copied from djb's code
  111. // -----------------------------------------------------------------------------
  112. static void
  113. crecip(felem *out, const felem *z) {
  114. felem z2[5];
  115. felem z9[5];
  116. felem z11[5];
  117. felem z2_5_0[5];
  118. felem z2_10_0[5];
  119. felem z2_20_0[5];
  120. felem z2_50_0[5];
  121. felem z2_100_0[5];
  122. felem t0[5];
  123. felem t1[5];
  124. int i;
  125. /* 2 */ fsquare(z2,z);
  126. /* 4 */ fsquare(t1,z2);
  127. /* 8 */ fsquare(t0,t1);
  128. /* 9 */ fmul(z9,t0,z);
  129. /* 11 */ fmul(z11,z9,z2);
  130. /* 22 */ fsquare(t0,z11);
  131. /* 2^5 - 2^0 = 31 */ fmul(z2_5_0,t0,z9);
  132. /* 2^6 - 2^1 */ fsquare(t0,z2_5_0);
  133. /* 2^7 - 2^2 */ fsquare(t1,t0);
  134. /* 2^8 - 2^3 */ fsquare(t0,t1);
  135. /* 2^9 - 2^4 */ fsquare(t1,t0);
  136. /* 2^10 - 2^5 */ fsquare(t0,t1);
  137. /* 2^10 - 2^0 */ fmul(z2_10_0,t0,z2_5_0);
  138. /* 2^11 - 2^1 */ fsquare(t0,z2_10_0);
  139. /* 2^12 - 2^2 */ fsquare(t1,t0);
  140. /* 2^20 - 2^10 */ for (i = 2;i < 10;i += 2) { fsquare(t0,t1); fsquare(t1,t0); }
  141. /* 2^20 - 2^0 */ fmul(z2_20_0,t1,z2_10_0);
  142. /* 2^21 - 2^1 */ fsquare(t0,z2_20_0);
  143. /* 2^22 - 2^2 */ fsquare(t1,t0);
  144. /* 2^40 - 2^20 */ for (i = 2;i < 20;i += 2) { fsquare(t0,t1); fsquare(t1,t0); }
  145. /* 2^40 - 2^0 */ fmul(t0,t1,z2_20_0);
  146. /* 2^41 - 2^1 */ fsquare(t1,t0);
  147. /* 2^42 - 2^2 */ fsquare(t0,t1);
  148. /* 2^50 - 2^10 */ for (i = 2;i < 10;i += 2) { fsquare(t1,t0); fsquare(t0,t1); }
  149. /* 2^50 - 2^0 */ fmul(z2_50_0,t0,z2_10_0);
  150. /* 2^51 - 2^1 */ fsquare(t0,z2_50_0);
  151. /* 2^52 - 2^2 */ fsquare(t1,t0);
  152. /* 2^100 - 2^50 */ for (i = 2;i < 50;i += 2) { fsquare(t0,t1); fsquare(t1,t0); }
  153. /* 2^100 - 2^0 */ fmul(z2_100_0,t1,z2_50_0);
  154. /* 2^101 - 2^1 */ fsquare(t1,z2_100_0);
  155. /* 2^102 - 2^2 */ fsquare(t0,t1);
  156. /* 2^200 - 2^100 */ for (i = 2;i < 100;i += 2) { fsquare(t1,t0); fsquare(t0,t1); }
  157. /* 2^200 - 2^0 */ fmul(t1,t0,z2_100_0);
  158. /* 2^201 - 2^1 */ fsquare(t0,t1);
  159. /* 2^202 - 2^2 */ fsquare(t1,t0);
  160. /* 2^250 - 2^50 */ for (i = 2;i < 50;i += 2) { fsquare(t0,t1); fsquare(t1,t0); }
  161. /* 2^250 - 2^0 */ fmul(t0,t1,z2_50_0);
  162. /* 2^251 - 2^1 */ fsquare(t1,t0);
  163. /* 2^252 - 2^2 */ fsquare(t0,t1);
  164. /* 2^253 - 2^3 */ fsquare(t1,t0);
  165. /* 2^254 - 2^4 */ fsquare(t0,t1);
  166. /* 2^255 - 2^5 */ fsquare(t1,t0);
  167. /* 2^255 - 21 */ fmul(out,t1,z11);
  168. }
  169. int
  170. crypto_scalarmult(u8 *mypublic, const u8 *secret, const u8 *basepoint) {
  171. felem bp[5], x[5], z[5], zmone[5];
  172. unsigned char e[32];
  173. int i;
  174. for (i = 0;i < 32;++i) e[i] = secret[i];
  175. e[0] &= 248;
  176. e[31] &= 127;
  177. e[31] |= 64;
  178. fexpand(bp, basepoint);
  179. cmult(x, z, e, bp);
  180. crecip(zmone, z);
  181. fmul(z, x, zmone);
  182. fcontract(mypublic, z);
  183. return 0;
  184. }