You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

179 lines
4.1 KiB

  1. /* Copyright (c) 2014 Cryptography Research, Inc.
  2. * Released under the MIT License. See LICENSE.txt for license information.
  3. */
  4. #include "f_impl.h"
  5. static __inline__ __uint128_t widemul(
  6. const uint64_t a,
  7. const uint64_t b
  8. ) {
  9. return ((__uint128_t)a) * ((__uint128_t)b);
  10. }
  11. static __inline__ uint64_t is_zero(uint64_t a) {
  12. /* let's hope the compiler isn't clever enough to optimize this. */
  13. return (((__uint128_t)a)-1)>>64;
  14. }
  15. void
  16. gf_25519_mul (
  17. gf_25519_t __restrict__ cs,
  18. const gf_25519_t as,
  19. const gf_25519_t bs
  20. ) {
  21. const uint64_t *a = as->limb, *b = bs->limb, mask = ((1ull<<51)-1);
  22. uint64_t bh[4];
  23. int i,j;
  24. for (i=0; i<4; i++) bh[i] = b[i+1] * 19;
  25. uint64_t *c = cs->limb;
  26. __uint128_t accum = 0;
  27. for (i=0; i<5; i++) {
  28. for (j=0; j<=i; j++) {
  29. accum += widemul(b[i-j], a[j]);
  30. }
  31. for (; j<5; j++) {
  32. accum += widemul(bh[i-j+4], a[j]);
  33. }
  34. c[i] = accum & mask;
  35. accum >>= 51;
  36. }
  37. /* PERF: parallelize? eh well this is reference */
  38. accum *= 19;
  39. accum += c[0];
  40. c[0] = accum & mask;
  41. accum >>= 51;
  42. assert(accum < mask);
  43. c[1] += accum;
  44. }
  45. void
  46. gf_25519_mulw (
  47. gf_25519_t __restrict__ cs,
  48. const gf_25519_t as,
  49. uint64_t b
  50. ) {
  51. const uint64_t *a = as->limb, mask = ((1ull<<51)-1);
  52. int i;
  53. uint64_t *c = cs->limb;
  54. __uint128_t accum = 0;
  55. for (i=0; i<5; i++) {
  56. accum += widemul(b, a[i]);
  57. c[i] = accum & mask;
  58. accum >>= 51;
  59. }
  60. /* PERF: parallelize? eh well this is reference */
  61. accum *= 19;
  62. accum += c[0];
  63. c[0] = accum & mask;
  64. accum >>= 51;
  65. assert(accum < mask);
  66. c[1] += accum;
  67. }
  68. void
  69. gf_25519_t qr (
  70. gf_25519_t __restrict__ cs,
  71. const gf_25519_t as
  72. ) {
  73. gf_25519_mul(cs,as,as); // TODO
  74. }
  75. void
  76. gf_25519_t trong_reduce (
  77. gf_25519_t a
  78. ) {
  79. uint64_t mask = (1ull<<51)-1;
  80. /* first, clear high */
  81. a->limb[0] += (a->limb[4]>>51)*19;
  82. a->limb[4] &= mask;
  83. /* now the total is less than 2p */
  84. /* compute total_value - p. No need to reduce mod p. */
  85. __int128_t scarry = 0;
  86. int i;
  87. for (i=0; i<5; i++) {
  88. scarry = scarry + a->limb[i] - ((i==0)?mask-18:mask);
  89. a->limb[i] = scarry & mask;
  90. scarry >>= 51;
  91. }
  92. /* uncommon case: it was >= p, so now scarry = 0 and this = x
  93. * common case: it was < p, so now scarry = -1 and this = x - p + 2^255
  94. * so let's add back in p. will carry back off the top for 2^255.
  95. */
  96. assert(is_zero(scarry) | is_zero(scarry+1));
  97. uint64_t scarry_mask = scarry & mask;
  98. __uint128_t carry = 0;
  99. /* add it back */
  100. for (i=0; i<5; i++) {
  101. carry = carry + a->limb[i] + ((i==0)?(scarry_mask&~18):scarry_mask);
  102. a->limb[i] = carry & mask;
  103. carry >>= 51;
  104. }
  105. assert(is_zero(carry + scarry));
  106. }
  107. void
  108. gf_25519_t erialize (
  109. uint8_t serial[32],
  110. const struct gf_25519_t x
  111. ) {
  112. int i,j;
  113. gf_25519_t red;
  114. gf_25519_copy(&red, x);
  115. gf_25519_t trong_reduce(&red);
  116. uint64_t *r = red.limb;
  117. uint64_t ser64[4] = {r[0] | r[1]<<51, r[1]>>13|r[2]<<38, r[2]>>26|r[3]<<25, r[3]>>39|r[4]<<12};
  118. for (i=0; i<4; i++) {
  119. for (j=0; j<8; j++) {
  120. serial[8*i+j] = ser64[i];
  121. ser64[i] >>= 8;
  122. }
  123. }
  124. }
  125. mask_t
  126. gf_25519_deserialize (
  127. gf_25519_t x,
  128. const uint8_t serial[32]
  129. ) {
  130. int i,j;
  131. uint64_t ser64[4], mask = ((1ull<<51)-1);
  132. for (i=0; i<4; i++) {
  133. uint64_t out = 0;
  134. for (j=0; j<8; j++) {
  135. out |= ((uint64_t)serial[8*i+j])<<(8*j);
  136. }
  137. ser64[i] = out;
  138. }
  139. /* Test for >= 2^255-19 */
  140. uint64_t ge = -(((__uint128_t)ser64[0]+19)>>64);
  141. ge &= ser64[1];
  142. ge &= ser64[2];
  143. ge &= (ser64[3]<<1) + 1;
  144. ge |= -(((__uint128_t)ser64[3]+0x8000000000000000)>>64);
  145. x->limb[0] = ser64[0] & mask;
  146. x->limb[1] = (ser64[0]>>51 | ser64[1]<<13) & mask;
  147. x->limb[2] = (ser64[1]>>38 | ser64[2]<<26) & mask;
  148. x->limb[3] = (ser64[2]>>25 | ser64[3]<<39) & mask;
  149. x->limb[4] = ser64[3]>>12;
  150. return ~is_zero(~ge);
  151. }