Du kannst nicht mehr als 25 Themen auswählen Themen müssen entweder mit einem Buchstaben oder einer Ziffer beginnen. Sie können Bindestriche („-“) enthalten und bis zu 35 Zeichen lang sein.

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249
  1. package p503
  2. import (
  3. . "github.com/cloudflare/sidh/internal/isogeny"
  4. )
  5. type fp503Ops struct{}
  6. func FieldOperations() FieldOps {
  7. return &fp503Ops{}
  8. }
  9. func (fp503Ops) Add(dest, lhs, rhs *Fp2Element) {
  10. fp503AddReduced(&dest.A, &lhs.A, &rhs.A)
  11. fp503AddReduced(&dest.B, &lhs.B, &rhs.B)
  12. }
  13. func (fp503Ops) Sub(dest, lhs, rhs *Fp2Element) {
  14. fp503SubReduced(&dest.A, &lhs.A, &rhs.A)
  15. fp503SubReduced(&dest.B, &lhs.B, &rhs.B)
  16. }
  17. func (fp503Ops) Mul(dest, lhs, rhs *Fp2Element) {
  18. // Let (a,b,c,d) = (lhs.a,lhs.b,rhs.a,rhs.b).
  19. a := &lhs.A
  20. b := &lhs.B
  21. c := &rhs.A
  22. d := &rhs.B
  23. // We want to compute
  24. //
  25. // (a + bi)*(c + di) = (a*c - b*d) + (a*d + b*c)i
  26. //
  27. // Use Karatsuba's trick: note that
  28. //
  29. // (b - a)*(c - d) = (b*c + a*d) - a*c - b*d
  30. //
  31. // so (a*d + b*c) = (b-a)*(c-d) + a*c + b*d.
  32. var ac, bd FpElementX2
  33. fp503Mul(&ac, a, c) // = a*c*R*R
  34. fp503Mul(&bd, b, d) // = b*d*R*R
  35. var b_minus_a, c_minus_d FpElement
  36. fp503SubReduced(&b_minus_a, b, a) // = (b-a)*R
  37. fp503SubReduced(&c_minus_d, c, d) // = (c-d)*R
  38. var ad_plus_bc FpElementX2
  39. fp503Mul(&ad_plus_bc, &b_minus_a, &c_minus_d) // = (b-a)*(c-d)*R*R
  40. fp503X2AddLazy(&ad_plus_bc, &ad_plus_bc, &ac) // = ((b-a)*(c-d) + a*c)*R*R
  41. fp503X2AddLazy(&ad_plus_bc, &ad_plus_bc, &bd) // = ((b-a)*(c-d) + a*c + b*d)*R*R
  42. fp503MontgomeryReduce(&dest.B, &ad_plus_bc) // = (a*d + b*c)*R mod p
  43. var ac_minus_bd FpElementX2
  44. fp503X2SubLazy(&ac_minus_bd, &ac, &bd) // = (a*c - b*d)*R*R
  45. fp503MontgomeryReduce(&dest.A, &ac_minus_bd) // = (a*c - b*d)*R mod p
  46. }
  47. // Set dest = 1/x
  48. //
  49. // Allowed to overlap dest with x.
  50. //
  51. // Returns dest to allow chaining operations.
  52. func (fp503Ops) Inv(dest, x *Fp2Element) {
  53. a := &x.A
  54. b := &x.B
  55. // We want to compute
  56. //
  57. // 1 1 (a - bi) (a - bi)
  58. // -------- = -------- -------- = -----------
  59. // (a + bi) (a + bi) (a - bi) (a^2 + b^2)
  60. //
  61. // Letting c = 1/(a^2 + b^2), this is
  62. //
  63. // 1/(a+bi) = a*c - b*ci.
  64. var asq_plus_bsq primeFieldElement
  65. var asq, bsq FpElementX2
  66. fp503Mul(&asq, a, a) // = a*a*R*R
  67. fp503Mul(&bsq, b, b) // = b*b*R*R
  68. fp503X2AddLazy(&asq, &asq, &bsq) // = (a^2 + b^2)*R*R
  69. fp503MontgomeryReduce(&asq_plus_bsq.A, &asq) // = (a^2 + b^2)*R mod p
  70. // Now asq_plus_bsq = a^2 + b^2
  71. inv := asq_plus_bsq
  72. inv.Mul(&asq_plus_bsq, &asq_plus_bsq)
  73. inv.P34(&inv)
  74. inv.Mul(&inv, &inv)
  75. inv.Mul(&inv, &asq_plus_bsq)
  76. var ac FpElementX2
  77. fp503Mul(&ac, a, &inv.A)
  78. fp503MontgomeryReduce(&dest.A, &ac)
  79. var minus_b FpElement
  80. fp503SubReduced(&minus_b, &minus_b, b)
  81. var minus_bc FpElementX2
  82. fp503Mul(&minus_bc, &minus_b, &inv.A)
  83. fp503MontgomeryReduce(&dest.B, &minus_bc)
  84. }
  85. func (fp503Ops) Square(dest, x *Fp2Element) {
  86. a := &x.A
  87. b := &x.B
  88. // We want to compute
  89. //
  90. // (a + bi)*(a + bi) = (a^2 - b^2) + 2abi.
  91. var a2, a_plus_b, a_minus_b FpElement
  92. fp503AddReduced(&a2, a, a) // = a*R + a*R = 2*a*R
  93. fp503AddReduced(&a_plus_b, a, b) // = a*R + b*R = (a+b)*R
  94. fp503SubReduced(&a_minus_b, a, b) // = a*R - b*R = (a-b)*R
  95. var asq_minus_bsq, ab2 FpElementX2
  96. fp503Mul(&asq_minus_bsq, &a_plus_b, &a_minus_b) // = (a+b)*(a-b)*R*R = (a^2 - b^2)*R*R
  97. fp503Mul(&ab2, &a2, b) // = 2*a*b*R*R
  98. fp503MontgomeryReduce(&dest.A, &asq_minus_bsq) // = (a^2 - b^2)*R mod p
  99. fp503MontgomeryReduce(&dest.B, &ab2) // = 2*a*b*R mod p
  100. }
  101. // In case choice == 1, performs following swap in constant time:
  102. // xPx <-> xQx
  103. // xPz <-> xQz
  104. // Otherwise returns xPx, xPz, xQx, xQz unchanged
  105. func (fp503Ops) CondSwap(xPx, xPz, xQx, xQz *Fp2Element, choice uint8) {
  106. fp503ConditionalSwap(&xPx.A, &xQx.A, choice)
  107. fp503ConditionalSwap(&xPx.B, &xQx.B, choice)
  108. fp503ConditionalSwap(&xPz.A, &xQz.A, choice)
  109. fp503ConditionalSwap(&xPz.B, &xQz.B, choice)
  110. }
  111. // Converts values in x.A and x.B to Montgomery domain
  112. // x.A = x.A * R mod p
  113. // x.B = x.B * R mod p
  114. // Performs v = v*R^2*R^(-1) mod p, for both x.A and x.B
  115. func (fp503Ops) ToMontgomery(x *Fp2Element) {
  116. var aRR FpElementX2
  117. // convert to montgomery domain
  118. fp503Mul(&aRR, &x.A, &p503R2) // = a*R*R
  119. fp503MontgomeryReduce(&x.A, &aRR) // = a*R mod p
  120. fp503Mul(&aRR, &x.B, &p503R2)
  121. fp503MontgomeryReduce(&x.B, &aRR)
  122. }
  123. // Converts values in x.A and x.B from Montgomery domain
  124. // a = x.A mod p
  125. // b = x.B mod p
  126. //
  127. // After returning from the call x is not modified.
  128. func (fp503Ops) FromMontgomery(x *Fp2Element, out *Fp2Element) {
  129. var aR FpElementX2
  130. // convert from montgomery domain
  131. // TODO: make fpXXXMontgomeryReduce use stack instead of reusing aR
  132. // so that we don't have do this copy here
  133. copy(aR[:], x.A[:])
  134. fp503MontgomeryReduce(&out.A, &aR) // = a mod p in [0, 2p)
  135. fp503StrongReduce(&out.A) // = a mod p in [0, p)
  136. for i := range aR {
  137. aR[i] = 0
  138. }
  139. copy(aR[:], x.B[:])
  140. fp503MontgomeryReduce(&out.B, &aR)
  141. fp503StrongReduce(&out.B)
  142. }
  143. //------------------------------------------------------------------------------
  144. // Prime Field
  145. //------------------------------------------------------------------------------
  146. // Represents an element of the prime field F_p.
  147. type primeFieldElement struct {
  148. // This field element is in Montgomery form, so that the value `A` is
  149. // represented by `aR mod p`.
  150. A FpElement
  151. }
  152. // Set dest = lhs * rhs.
  153. //
  154. // Allowed to overlap lhs or rhs with dest.
  155. //
  156. // Returns dest to allow chaining operations.
  157. func (dest *primeFieldElement) Mul(lhs, rhs *primeFieldElement) *primeFieldElement {
  158. a := &lhs.A // = a*R
  159. b := &rhs.A // = b*R
  160. var ab FpElementX2
  161. fp503Mul(&ab, a, b) // = a*b*R*R
  162. fp503MontgomeryReduce(&dest.A, &ab) // = a*b*R mod p
  163. return dest
  164. }
  165. // Set dest = x^(2^k), for k >= 1, by repeated squarings.
  166. //
  167. // Allowed to overlap x with dest.
  168. //
  169. // Returns dest to allow chaining operations.
  170. func (dest *primeFieldElement) Pow2k(x *primeFieldElement, k uint8) *primeFieldElement {
  171. dest.Mul(x, x)
  172. for i := uint8(1); i < k; i++ {
  173. dest.Mul(dest, dest)
  174. }
  175. return dest
  176. }
  177. // Set dest = x^((p-3)/4). If x is square, this is 1/sqrt(x).
  178. // Uses variation of sliding-window algorithm from with window size
  179. // of 5 and least to most significant bit sliding (left-to-right)
  180. // See HAC 14.85 for general description.
  181. //
  182. // Allowed to overlap x with dest.
  183. //
  184. // Returns dest to allow chaining operations.
  185. func (dest *primeFieldElement) P34(x *primeFieldElement) *primeFieldElement {
  186. // Sliding-window strategy computed with etc/scripts/sliding_window_strat_calc.py
  187. //
  188. // This performs sum(powStrategy) + 1 squarings and len(lookup) + len(mulStrategy)
  189. // multiplications.
  190. powStrategy := []uint8{1, 12, 5, 5, 2, 7, 11, 3, 8, 4, 11, 4, 7, 5, 6, 3, 7, 5, 7, 2, 12, 5, 6, 4, 6, 8, 6, 4, 7, 5, 5, 8, 5, 8, 5, 5, 8, 9, 3, 6, 2, 10, 6, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 3}
  191. mulStrategy := []uint8{0, 12, 11, 10, 0, 1, 8, 3, 7, 1, 8, 3, 6, 7, 14, 2, 14, 14, 9, 0, 13, 9, 15, 5, 12, 7, 13, 7, 15, 6, 7, 9, 0, 5, 7, 6, 8, 8, 3, 7, 0, 10, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 3}
  192. // Precompute lookup table of odd multiples of x for window
  193. // size k=5.
  194. lookup := [16]primeFieldElement{}
  195. xx := &primeFieldElement{}
  196. xx.Mul(x, x)
  197. lookup[0] = *x
  198. for i := 1; i < 16; i++ {
  199. lookup[i].Mul(&lookup[i-1], xx)
  200. }
  201. // Now lookup = {x, x^3, x^5, ... }
  202. // so that lookup[i] = x^{2*i + 1}
  203. // so that lookup[k/2] = x^k, for odd k
  204. *dest = lookup[mulStrategy[0]]
  205. for i := uint8(1); i < uint8(len(powStrategy)); i++ {
  206. dest.Pow2k(dest, powStrategy[i])
  207. dest.Mul(dest, &lookup[mulStrategy[i]])
  208. }
  209. return dest
  210. }