您最多选择25个主题 主题必须以字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符
 
 
 

259 行
5.4 KiB

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