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.
 
 
 

256 regels
8.0 KiB

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