Du kan inte välja fler än 25 ämnen Ämnen måste starta med en bokstav eller siffra, kan innehålla bindestreck ('-') och vara max 35 tecken långa.
 
 
 

255 rader
5.4 KiB

  1. // +build noasm arm64 arm
  2. package p503toolbox
  3. // helper used for uint128 representation
  4. type uint128 struct {
  5. H, L uint64
  6. }
  7. // Adds 2 64bit digits in constant time.
  8. // Returns result and carry (1 or 0)
  9. func addc64(cin, a, b uint64) (ret, cout uint64) {
  10. t := a + cin
  11. ret = b + t
  12. cout = ((a & b) | ((a | b) & (^ret))) >> 63
  13. return
  14. }
  15. // Substracts 2 64bit digits in constant time.
  16. // Returns result and borrow (1 or 0)
  17. func subc64(bIn, a, b uint64) (ret, bOut uint64) {
  18. var tmp1 = a - b
  19. // Set bOut if bIn!=0 and tmp1==0 in constant time
  20. bOut = bIn & (1 ^ ((tmp1 | uint64(0-tmp1)) >> 63))
  21. // Constant time check if x<y
  22. bOut |= (a ^ ((a ^ b) | (uint64(a-b) ^ b))) >> 63
  23. ret = tmp1 - bIn
  24. return
  25. }
  26. // Multiplies 2 64bit digits in constant time
  27. func mul64(a, b uint64) (res uint128) {
  28. var al, bl, ah, bh, albl, albh, ahbl, ahbh uint64
  29. var res1, res2, res3 uint64
  30. var carry, maskL, maskH, temp uint64
  31. maskL = (^maskL) >> 32
  32. maskH = ^maskL
  33. al = a & maskL
  34. ah = a >> 32
  35. bl = b & maskL
  36. bh = b >> 32
  37. albl = al * bl
  38. albh = al * bh
  39. ahbl = ah * bl
  40. ahbh = ah * bh
  41. res.L = albl & maskL
  42. res1 = albl >> 32
  43. res2 = ahbl & maskL
  44. res3 = albh & maskL
  45. temp = res1 + res2 + res3
  46. carry = temp >> 32
  47. res.L ^= temp << 32
  48. res1 = ahbl >> 32
  49. res2 = albh >> 32
  50. res3 = ahbh & maskL
  51. temp = res1 + res2 + res3 + carry
  52. res.H = temp & maskL
  53. carry = temp & maskH
  54. res.H ^= (ahbh & maskH) + carry
  55. return
  56. }
  57. // Compute z = x + y (mod p).
  58. func fp751AddReduced(z, x, y *Fp751Element) {
  59. var carry uint64
  60. // z=x+y % p751
  61. for i := 0; i < fp751NumWords; i++ {
  62. z[i], carry = addc64(carry, x[i], y[i])
  63. }
  64. // z = z - p751x2
  65. carry = 0
  66. for i := 0; i < fp751NumWords; i++ {
  67. z[i], carry = subc64(carry, z[i], p751x2[i])
  68. }
  69. // z = z + p751x2
  70. mask := uint64(0 - carry)
  71. carry = 0
  72. for i := 0; i < fp751NumWords; i++ {
  73. z[i], carry = addc64(carry, z[i], p751x2[i]&mask)
  74. }
  75. }
  76. // Compute z = x - y (mod p).
  77. func fp751SubReduced(z, x, y *Fp751Element) {
  78. var borrow uint64
  79. for i := 0; i < fp751NumWords; i++ {
  80. z[i], borrow = subc64(borrow, x[i], y[i])
  81. }
  82. mask := uint64(0 - borrow)
  83. borrow = 0
  84. for i := 0; i < fp751NumWords; i++ {
  85. z[i], borrow = addc64(borrow, z[i], p751x2[i]&mask)
  86. }
  87. }
  88. // Conditionally swaps bits in x and y in constant time.
  89. // mask indicates bits to be swaped (set bits are swapped)
  90. // For details see "Hackers Delight, 2.20"
  91. //
  92. // Implementation doesn't actually depend on a prime field.
  93. func fp751ConditionalSwap(x, y *Fp751Element, mask uint8) {
  94. var tmp, mask64 uint64
  95. mask64 = 0 - uint64(mask)
  96. for i := 0; i < len(x); i++ {
  97. tmp = mask64 & (x[i] ^ y[i])
  98. x[i] = tmp ^ x[i]
  99. y[i] = tmp ^ y[i]
  100. }
  101. }
  102. // Perform Montgomery reduction: set z = x R^{-1} (mod 2*p)
  103. // with R=2^768. Destroys the input value.
  104. func fp751MontgomeryReduce(z *Fp751Element, x *fp751X2) {
  105. var carry, t, u, v uint64
  106. var uv uint128
  107. var count int
  108. count = 5 // number of 0 digits in the least significat part of p751 + 1
  109. for i := 0; i < fp751NumWords; i++ {
  110. for j := 0; j < i; j++ {
  111. if j < (i - count + 1) {
  112. uv = mul64(z[j], p751p1[i-j])
  113. v, carry = addc64(0, uv.L, v)
  114. u, carry = addc64(carry, uv.H, u)
  115. t += carry
  116. }
  117. }
  118. v, carry = addc64(0, v, x[i])
  119. u, carry = addc64(carry, u, 0)
  120. t += carry
  121. z[i] = v
  122. v = u
  123. u = t
  124. t = 0
  125. }
  126. for i := fp751NumWords; i < 2*fp751NumWords-1; i++ {
  127. if count > 0 {
  128. count--
  129. }
  130. for j := i - fp751NumWords + 1; j < fp751NumWords; j++ {
  131. if j < (fp751NumWords - count) {
  132. uv = mul64(z[j], p751p1[i-j])
  133. v, carry = addc64(0, uv.L, v)
  134. u, carry = addc64(carry, uv.H, u)
  135. t += carry
  136. }
  137. }
  138. v, carry = addc64(0, v, x[i])
  139. u, carry = addc64(carry, u, 0)
  140. t += carry
  141. z[i-fp751NumWords] = v
  142. v = u
  143. u = t
  144. t = 0
  145. }
  146. v, carry = addc64(0, v, x[2*fp751NumWords-1])
  147. z[fp751NumWords-1] = v
  148. }
  149. // Compute z = x * y.
  150. func fp751Mul(z *fp751X2, x, y *Fp751Element) {
  151. var u, v, t uint64
  152. var carry uint64
  153. var uv uint128
  154. for i := uint64(0); i < fp751NumWords; i++ {
  155. for j := uint64(0); j <= i; j++ {
  156. uv = mul64(x[j], y[i-j])
  157. v, carry = addc64(0, uv.L, v)
  158. u, carry = addc64(carry, uv.H, u)
  159. t += carry
  160. }
  161. z[i] = v
  162. v = u
  163. u = t
  164. t = 0
  165. }
  166. for i := fp751NumWords; i < (2*fp751NumWords)-1; i++ {
  167. for j := i - fp751NumWords + 1; j < fp751NumWords; j++ {
  168. uv = mul64(x[j], y[i-j])
  169. v, carry = addc64(0, uv.L, v)
  170. u, carry = addc64(carry, uv.H, u)
  171. t += carry
  172. }
  173. z[i] = v
  174. v = u
  175. u = t
  176. t = 0
  177. }
  178. z[2*fp751NumWords-1] = v
  179. }
  180. // Compute z = x + y, without reducing mod p.
  181. func fp751AddLazy(z, x, y *Fp751Element) {
  182. var carry uint64
  183. for i := 0; i < fp751NumWords; i++ {
  184. z[i], carry = addc64(carry, x[i], y[i])
  185. }
  186. }
  187. // Compute z = x + y, without reducing mod p.
  188. func fp751X2AddLazy(z, x, y *fp751X2) {
  189. var carry uint64
  190. for i := 0; i < 2*fp751NumWords; i++ {
  191. z[i], carry = addc64(carry, x[i], y[i])
  192. }
  193. }
  194. // Reduce a field element in [0, 2*p) to one in [0,p).
  195. func fp751StrongReduce(x *Fp751Element) {
  196. var borrow, mask uint64
  197. for i := 0; i < fp751NumWords; i++ {
  198. x[i], borrow = subc64(borrow, x[i], p751[i])
  199. }
  200. // Sets all bits if borrow = 1
  201. mask = 0 - borrow
  202. borrow = 0
  203. for i := 0; i < fp751NumWords; i++ {
  204. x[i], borrow = addc64(borrow, x[i], p751[i]&mask)
  205. }
  206. }
  207. // Compute z = x - y, without reducing mod p.
  208. func fp751X2SubLazy(z, x, y *fp751X2) {
  209. var borrow, mask uint64
  210. for i := 0; i < len(z); i++ {
  211. z[i], borrow = subc64(borrow, x[i], y[i])
  212. }
  213. // Sets all bits if borrow = 1
  214. mask = 0 - borrow
  215. borrow = 0
  216. for i := fp751NumWords; i < len(z); i++ {
  217. z[i], borrow = addc64(borrow, z[i], p751[i-fp751NumWords]&mask)
  218. }
  219. }