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.

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196
  1. // +build noasm !amd64
  2. package p751
  3. import (
  4. . "github.com/cloudflare/p751sidh/internal/isogeny"
  5. . "github.com/cloudflare/p751sidh/internal/arith"
  6. )
  7. // Compute z = x + y (mod p).
  8. func fp751AddReduced(z, x, y *FpElement) {
  9. var carry uint64
  10. // z=x+y % p751
  11. for i := 0; i < NumWords; i++ {
  12. z[i], carry = Addc64(carry, x[i], y[i])
  13. }
  14. // z = z - p751x2
  15. carry = 0
  16. for i := 0; i < NumWords; i++ {
  17. z[i], carry = Subc64(carry, z[i], p751x2[i])
  18. }
  19. // z = z + p751x2
  20. mask := uint64(0 - carry)
  21. carry = 0
  22. for i := 0; i < NumWords; i++ {
  23. z[i], carry = Addc64(carry, z[i], p751x2[i]&mask)
  24. }
  25. }
  26. // Compute z = x - y (mod p).
  27. func fp751SubReduced(z, x, y *FpElement) {
  28. var borrow uint64
  29. for i := 0; i < NumWords; i++ {
  30. z[i], borrow = Subc64(borrow, x[i], y[i])
  31. }
  32. mask := uint64(0 - borrow)
  33. borrow = 0
  34. for i := 0; i < NumWords; i++ {
  35. z[i], borrow = Addc64(borrow, z[i], p751x2[i]&mask)
  36. }
  37. }
  38. // Conditionally swaps bits in x and y in constant time.
  39. // mask indicates bits to be swaped (set bits are swapped)
  40. // For details see "Hackers Delight, 2.20"
  41. //
  42. // Implementation doesn't actually depend on a prime field.
  43. func fp751ConditionalSwap(x, y *FpElement, mask uint8) {
  44. var tmp, mask64 uint64
  45. mask64 = 0 - uint64(mask)
  46. for i := 0; i < len(x); i++ {
  47. tmp = mask64 & (x[i] ^ y[i])
  48. x[i] = tmp ^ x[i]
  49. y[i] = tmp ^ y[i]
  50. }
  51. }
  52. // Perform Montgomery reduction: set z = x R^{-1} (mod 2*p)
  53. // with R=2^768. Destroys the input value.
  54. func fp751MontgomeryReduce(z *FpElement, x *FpElementX2) {
  55. var carry, t, u, v uint64
  56. var uv Uint128
  57. var count int
  58. count = 5 // number of 0 digits in the least significat part of p751 + 1
  59. for i := 0; i < NumWords; i++ {
  60. for j := 0; j < i; j++ {
  61. if j < (i - count + 1) {
  62. uv = Mul64(z[j], p751p1[i-j])
  63. v, carry = Addc64(0, uv.L, v)
  64. u, carry = Addc64(carry, uv.H, u)
  65. t += carry
  66. }
  67. }
  68. v, carry = Addc64(0, v, x[i])
  69. u, carry = Addc64(carry, u, 0)
  70. t += carry
  71. z[i] = v
  72. v = u
  73. u = t
  74. t = 0
  75. }
  76. for i := NumWords; i < 2*NumWords-1; i++ {
  77. if count > 0 {
  78. count--
  79. }
  80. for j := i - NumWords + 1; j < NumWords; j++ {
  81. if j < (NumWords - count) {
  82. uv = Mul64(z[j], p751p1[i-j])
  83. v, carry = Addc64(0, uv.L, v)
  84. u, carry = Addc64(carry, uv.H, u)
  85. t += carry
  86. }
  87. }
  88. v, carry = Addc64(0, v, x[i])
  89. u, carry = Addc64(carry, u, 0)
  90. t += carry
  91. z[i-NumWords] = v
  92. v = u
  93. u = t
  94. t = 0
  95. }
  96. v, carry = Addc64(0, v, x[2*NumWords-1])
  97. z[NumWords-1] = v
  98. }
  99. // Compute z = x * y.
  100. func fp751Mul(z *FpElementX2, x, y *FpElement) {
  101. var u, v, t uint64
  102. var carry uint64
  103. var uv Uint128
  104. for i := uint64(0); i < NumWords; i++ {
  105. for j := uint64(0); j <= i; j++ {
  106. uv = Mul64(x[j], y[i-j])
  107. v, carry = Addc64(0, uv.L, v)
  108. u, carry = Addc64(carry, uv.H, u)
  109. t += carry
  110. }
  111. z[i] = v
  112. v = u
  113. u = t
  114. t = 0
  115. }
  116. for i := NumWords; i < (2*NumWords)-1; i++ {
  117. for j := i - NumWords + 1; j < NumWords; j++ {
  118. uv = Mul64(x[j], y[i-j])
  119. v, carry = Addc64(0, uv.L, v)
  120. u, carry = Addc64(carry, uv.H, u)
  121. t += carry
  122. }
  123. z[i] = v
  124. v = u
  125. u = t
  126. t = 0
  127. }
  128. z[2*NumWords-1] = v
  129. }
  130. // Compute z = x + y, without reducing mod p.
  131. func fp751AddLazy(z, x, y *FpElement) {
  132. var carry uint64
  133. for i := 0; i < NumWords; i++ {
  134. z[i], carry = Addc64(carry, x[i], y[i])
  135. }
  136. }
  137. // Compute z = x + y, without reducing mod p.
  138. func fp751X2AddLazy(z, x, y *FpElementX2) {
  139. var carry uint64
  140. for i := 0; i < 2*NumWords; i++ {
  141. z[i], carry = Addc64(carry, x[i], y[i])
  142. }
  143. }
  144. // Reduce a field element in [0, 2*p) to one in [0,p).
  145. func fp751StrongReduce(x *FpElement) {
  146. var borrow, mask uint64
  147. for i := 0; i < NumWords; i++ {
  148. x[i], borrow = Subc64(borrow, x[i], p751[i])
  149. }
  150. // Sets all bits if borrow = 1
  151. mask = 0 - borrow
  152. borrow = 0
  153. for i := 0; i < NumWords; i++ {
  154. x[i], borrow = Addc64(borrow, x[i], p751[i]&mask)
  155. }
  156. }
  157. // Compute z = x - y, without reducing mod p.
  158. func fp751X2SubLazy(z, x, y *FpElementX2) {
  159. var borrow, mask uint64
  160. for i := 0; i < len(z); i++ {
  161. z[i], borrow = Subc64(borrow, x[i], y[i])
  162. }
  163. // Sets all bits if borrow = 1
  164. mask = 0 - borrow
  165. borrow = 0
  166. for i := NumWords; i < len(z); i++ {
  167. z[i], borrow = Addc64(borrow, z[i], p751[i-NumWords]&mask)
  168. }
  169. }