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.

140 regels
4.3 KiB

  1. package sike
  2. // Set dest = x^((p-3)/4). If x is square, this is 1/sqrt(x).
  3. // Uses variation of sliding-window algorithm from with window size
  4. // of 5 and least to most significant bit sliding (left-to-right)
  5. // See HAC 14.85 for general description.
  6. //
  7. // Allowed to overlap x with dest.
  8. // All values in Montgomery domains
  9. // Set dest = x^(2^k), for k >= 1, by repeated squarings.
  10. func p34(dest, x *Fp) {
  11. var lookup [16]Fp
  12. // Sliding-window strategy computed with etc/scripts/sliding_window_strat_calc.py
  13. //
  14. // This performs sum(powStrategy) + 1 squarings and len(lookup) + len(mulStrategy)
  15. // multiplications.
  16. 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}
  17. 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}
  18. // Precompute lookup table of odd multiples of x for window
  19. // size k=5.
  20. var xx Fp
  21. fpMulRdc(&xx, x, x)
  22. lookup[0] = *x
  23. for i := 1; i < 16; i++ {
  24. fpMulRdc(&lookup[i], &lookup[i-1], &xx)
  25. }
  26. // Now lookup = {x, x^3, x^5, ... }
  27. // so that lookup[i] = x^{2*i + 1}
  28. // so that lookup[k/2] = x^k, for odd k
  29. *dest = lookup[mulStrategy[0]]
  30. for i := uint8(1); i < uint8(len(powStrategy)); i++ {
  31. fpMulRdc(dest, dest, dest)
  32. for j := uint8(1); j < powStrategy[i]; j++ {
  33. fpMulRdc(dest, dest, dest)
  34. }
  35. fpMulRdc(dest, dest, &lookup[mulStrategy[i]])
  36. }
  37. }
  38. func add(dest, lhs, rhs *Fp2) {
  39. fpAddRdc(&dest.A, &lhs.A, &rhs.A)
  40. fpAddRdc(&dest.B, &lhs.B, &rhs.B)
  41. }
  42. func sub(dest, lhs, rhs *Fp2) {
  43. fpSubRdc(&dest.A, &lhs.A, &rhs.A)
  44. fpSubRdc(&dest.B, &lhs.B, &rhs.B)
  45. }
  46. func mul(dest, lhs, rhs *Fp2) {
  47. // Let (a,b,c,d) = (lhs.a,lhs.b,rhs.a,rhs.b).
  48. a := &lhs.A
  49. b := &lhs.B
  50. c := &rhs.A
  51. d := &rhs.B
  52. // We want to compute
  53. //
  54. // (a + bi)*(c + di) = (a*c - b*d) + (a*d + b*c)i
  55. //
  56. // Use Karatsuba's trick: note that
  57. //
  58. // (b - a)*(c - d) = (b*c + a*d) - a*c - b*d
  59. //
  60. // so (a*d + b*c) = (b-a)*(c-d) + a*c + b*d.
  61. var ac, bd FpX2
  62. fpMul(&ac, a, c) // = a*c*R*R
  63. fpMul(&bd, b, d) // = b*d*R*R
  64. var b_minus_a, c_minus_d Fp
  65. fpSubRdc(&b_minus_a, b, a) // = (b-a)*R
  66. fpSubRdc(&c_minus_d, c, d) // = (c-d)*R
  67. var ad_plus_bc FpX2
  68. fpMul(&ad_plus_bc, &b_minus_a, &c_minus_d) // = (b-a)*(c-d)*R*R
  69. fp2Add(&ad_plus_bc, &ad_plus_bc, &ac) // = ((b-a)*(c-d) + a*c)*R*R
  70. fp2Add(&ad_plus_bc, &ad_plus_bc, &bd) // = ((b-a)*(c-d) + a*c + b*d)*R*R
  71. fpMontRdc(&dest.B, &ad_plus_bc) // = (a*d + b*c)*R mod p
  72. var ac_minus_bd FpX2
  73. fp2Sub(&ac_minus_bd, &ac, &bd) // = (a*c - b*d)*R*R
  74. fpMontRdc(&dest.A, &ac_minus_bd) // = (a*c - b*d)*R mod p
  75. }
  76. func inv(dest, x *Fp2) {
  77. var e1, e2 FpX2
  78. var f1, f2 Fp
  79. fpMul(&e1, &x.A, &x.A) // = a*a*R*R
  80. fpMul(&e2, &x.B, &x.B) // = b*b*R*R
  81. fp2Add(&e1, &e1, &e2) // = (a^2 + b^2)*R*R
  82. fpMontRdc(&f1, &e1) // = (a^2 + b^2)*R mod p
  83. // Now&f1 = a^2 + b^2
  84. fpMulRdc(&f2, &f1, &f1)
  85. p34(&f2, &f2)
  86. fpMulRdc(&f2, &f2, &f2)
  87. fpMulRdc(&f2, &f2, &f1)
  88. fpMul(&e1, &x.A, &f2)
  89. fpMontRdc(&dest.A, &e1)
  90. fpSubRdc(&f1, &Fp{}, &x.B)
  91. fpMul(&e1, &f1, &f2)
  92. fpMontRdc(&dest.B, &e1)
  93. }
  94. func sqr(dest, x *Fp2) {
  95. var a2, aPlusB, aMinusB Fp
  96. var a2MinB2, ab2 FpX2
  97. a := &x.A
  98. b := &x.B
  99. // (a + bi)*(a + bi) = (a^2 - b^2) + 2abi.
  100. fpAddRdc(&a2, a, a) // = a*R + a*R = 2*a*R
  101. fpAddRdc(&aPlusB, a, b) // = a*R + b*R = (a+b)*R
  102. fpSubRdc(&aMinusB, a, b) // = a*R - b*R = (a-b)*R
  103. fpMul(&a2MinB2, &aPlusB, &aMinusB) // = (a+b)*(a-b)*R*R = (a^2 - b^2)*R*R
  104. fpMul(&ab2, &a2, b) // = 2*a*b*R*R
  105. fpMontRdc(&dest.A, &a2MinB2) // = (a^2 - b^2)*R mod p
  106. fpMontRdc(&dest.B, &ab2) // = 2*a*b*R mod p
  107. }
  108. // In case choice == 1, performs following swap in constant time:
  109. // xPx <-> xQx
  110. // xPz <-> xQz
  111. // Otherwise returns xPx, xPz, xQx, xQz unchanged
  112. func condSwap(xPx, xPz, xQx, xQz *Fp2, choice uint8) {
  113. fpSwapCond(&xPx.A, &xQx.A, choice)
  114. fpSwapCond(&xPx.B, &xQx.B, choice)
  115. fpSwapCond(&xPz.A, &xQz.A, choice)
  116. fpSwapCond(&xPz.B, &xQz.B, choice)
  117. }