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.
 
 
 

489 line
15 KiB

  1. package cln16sidh
  2. //------------------------------------------------------------------------------
  3. // Extension Field
  4. //------------------------------------------------------------------------------
  5. // Represents an element of the extension field F_{p^2}.
  6. type ExtensionFieldElement struct {
  7. // This field element is in Montgomery form, so that the value `a` is
  8. // represented by `aR mod p`.
  9. a fp751Element
  10. // This field element is in Montgomery form, so that the value `b` is
  11. // represented by `bR mod p`.
  12. b fp751Element
  13. }
  14. var zeroExtensionField = ExtensionFieldElement{
  15. a: fp751Element{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0},
  16. b: fp751Element{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0},
  17. }
  18. var oneExtensionField = ExtensionFieldElement{
  19. a: fp751Element{0x249ad, 0x0, 0x0, 0x0, 0x0, 0x8310000000000000, 0x5527b1e4375c6c66, 0x697797bf3f4f24d0, 0xc89db7b2ac5c4e2e, 0x4ca4b439d2076956, 0x10f7926c7512c7e9, 0x2d5b24bce5e2},
  20. b: fp751Element{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0},
  21. }
  22. // Set dest = 0.
  23. //
  24. // Returns dest to allow chaining operations.
  25. func (dest *ExtensionFieldElement) Zero() *ExtensionFieldElement {
  26. *dest = zeroExtensionField
  27. return dest
  28. }
  29. // Set dest = 1.
  30. //
  31. // Returns dest to allow chaining operations.
  32. func (dest *ExtensionFieldElement) One() *ExtensionFieldElement {
  33. *dest = oneExtensionField
  34. return dest
  35. }
  36. // Set dest = lhs * rhs.
  37. //
  38. // Allowed to overlap lhs or rhs with dest.
  39. //
  40. // Returns dest to allow chaining operations.
  41. func (dest *ExtensionFieldElement) Mul(lhs, rhs *ExtensionFieldElement) *ExtensionFieldElement {
  42. // Let (a,b,c,d) = (lhs.a,lhs.b,rhs.a,rhs.b).
  43. a := &lhs.a
  44. b := &lhs.b
  45. c := &rhs.a
  46. d := &rhs.b
  47. // We want to compute
  48. //
  49. // (a + bi)*(c + di) = (a*c - b*d) + (a*d + b*c)i
  50. //
  51. // Use Karatsuba's trick: note that
  52. //
  53. // (b - a)*(c - d) = (b*c + a*d) - a*c - b*d
  54. //
  55. // so (a*d + b*c) = (b-a)*(c-d) + a*c + b*d.
  56. var ac, bd fp751X2
  57. fp751Mul(&ac, a, c) // = a*c*R*R
  58. fp751Mul(&bd, b, d) // = b*d*R*R
  59. var b_minus_a, c_minus_d fp751Element
  60. fp751SubReduced(&b_minus_a, b, a) // = (b-a)*R
  61. fp751SubReduced(&c_minus_d, c, d) // = (c-d)*R
  62. var ad_plus_bc fp751X2
  63. fp751Mul(&ad_plus_bc, &b_minus_a, &c_minus_d) // = (b-a)*(c-d)*R*R
  64. fp751X2AddLazy(&ad_plus_bc, &ad_plus_bc, &ac) // = ((b-a)*(c-d) + a*c)*R*R
  65. fp751X2AddLazy(&ad_plus_bc, &ad_plus_bc, &bd) // = ((b-a)*(c-d) + a*c + b*d)*R*R
  66. fp751MontgomeryReduce(&dest.b, &ad_plus_bc) // = (a*d + b*c)*R mod p
  67. var ac_minus_bd fp751X2
  68. fp751X2SubLazy(&ac_minus_bd, &ac, &bd) // = (a*c - b*d)*R*R
  69. fp751MontgomeryReduce(&dest.a, &ac_minus_bd) // = (a*c - b*d)*R mod p
  70. return dest
  71. }
  72. // Set dest = 1/x
  73. //
  74. // Allowed to overlap dest with x.
  75. //
  76. // Returns dest to allow chaining operations.
  77. func (dest *ExtensionFieldElement) Inv(x *ExtensionFieldElement) *ExtensionFieldElement {
  78. a := &x.a
  79. b := &x.b
  80. // We want to compute
  81. //
  82. // 1 1 (a - bi) (a - bi)
  83. // -------- = -------- -------- = -----------
  84. // (a + bi) (a + bi) (a - bi) (a^2 + b^2)
  85. //
  86. // Letting c = 1/(a^2 + b^2), this is
  87. //
  88. // 1/(a+bi) = a*c - b*ci.
  89. var asq_plus_bsq PrimeFieldElement
  90. var asq, bsq fp751X2
  91. fp751Mul(&asq, a, a) // = a*a*R*R
  92. fp751Mul(&bsq, b, b) // = b*b*R*R
  93. fp751X2AddLazy(&asq, &asq, &bsq) // = (a^2 + b^2)*R*R
  94. fp751MontgomeryReduce(&asq_plus_bsq.a, &asq) // = (a^2 + b^2)*R mod p
  95. // Now asq_plus_bsq = a^2 + b^2
  96. var asq_plus_bsq_inv PrimeFieldElement
  97. asq_plus_bsq_inv.Inv(&asq_plus_bsq)
  98. c := &asq_plus_bsq_inv.a
  99. var ac fp751X2
  100. fp751Mul(&ac, a, c)
  101. fp751MontgomeryReduce(&dest.a, &ac)
  102. var minus_b fp751Element
  103. fp751SubReduced(&minus_b, &minus_b, b)
  104. var minus_bc fp751X2
  105. fp751Mul(&minus_bc, &minus_b, c)
  106. fp751MontgomeryReduce(&dest.b, &minus_bc)
  107. return dest
  108. }
  109. // Set (y1, y2, y3, y4) = (1/x1, 1/x2, 1/x3, 1/x4).
  110. //
  111. // All xi, yi must be distinct.
  112. func ExtensionFieldBatch4Inv(x1, x2, x3, x4, y1, y2, y3, y4 *ExtensionFieldElement) {
  113. var x1x2, x3x4, t ExtensionFieldElement
  114. x1x2.Mul(x1, x2) // x1*x2
  115. x3x4.Mul(x3, x4) // x3*x4
  116. t.Mul(&x1x2, &x3x4).Inv(&t) // 1/(x1*x2*x3*x4)
  117. y1.Mul(&t, x2).Mul(y1, &x3x4) // 1/x1
  118. y2.Mul(&t, x1).Mul(y2, &x3x4) // 1/x2
  119. y3.Mul(&t, x4).Mul(y3, &x1x2) // 1/x3
  120. y4.Mul(&t, x3).Mul(y4, &x1x2) // 1/x4
  121. }
  122. // Set dest = x * x
  123. //
  124. // Allowed to overlap dest with x.
  125. //
  126. // Returns dest to allow chaining operations.
  127. func (dest *ExtensionFieldElement) Square(x *ExtensionFieldElement) *ExtensionFieldElement {
  128. a := &x.a
  129. b := &x.b
  130. // We want to compute
  131. //
  132. // (a + bi)*(a + bi) = (a^2 - b^2) + 2abi.
  133. var a2, a_plus_b, a_minus_b fp751Element
  134. fp751AddReduced(&a2, a, a) // = a*R + a*R = 2*a*R
  135. fp751AddReduced(&a_plus_b, a, b) // = a*R + b*R = (a+b)*R
  136. fp751SubReduced(&a_minus_b, a, b) // = a*R - b*R = (a-b)*R
  137. var asq_minus_bsq, ab2 fp751X2
  138. fp751Mul(&asq_minus_bsq, &a_plus_b, &a_minus_b) // = (a+b)*(a-b)*R*R = (a^2 - b^2)*R*R
  139. fp751Mul(&ab2, &a2, b) // = 2*a*b*R*R
  140. fp751MontgomeryReduce(&dest.a, &asq_minus_bsq) // = (a^2 - b^2)*R mod p
  141. fp751MontgomeryReduce(&dest.b, &ab2) // = 2*a*b*R mod p
  142. return dest
  143. }
  144. // Set dest = lhs + rhs.
  145. //
  146. // Allowed to overlap lhs or rhs with dest.
  147. //
  148. // Returns dest to allow chaining operations.
  149. func (dest *ExtensionFieldElement) Add(lhs, rhs *ExtensionFieldElement) *ExtensionFieldElement {
  150. fp751AddReduced(&dest.a, &lhs.a, &rhs.a)
  151. fp751AddReduced(&dest.b, &lhs.b, &rhs.b)
  152. return dest
  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 *ExtensionFieldElement) Sub(lhs, rhs *ExtensionFieldElement) *ExtensionFieldElement {
  160. fp751SubReduced(&dest.a, &lhs.a, &rhs.a)
  161. fp751SubReduced(&dest.b, &lhs.b, &rhs.b)
  162. return dest
  163. }
  164. // If choice = 1u8, set (x,y) = (y,x). If choice = 0u8, set (x,y) = (x,y).
  165. //
  166. // Returns dest to allow chaining operations.
  167. func ExtensionFieldElementConditionalSwap(x, y *ExtensionFieldElement, choice uint8) {
  168. fp751ConditionalSwap(&x.a, &y.a, choice)
  169. fp751ConditionalSwap(&x.b, &y.b, choice)
  170. }
  171. // Set dest = if choice == 0 { x } else { y }, in constant time.
  172. //
  173. // Can overlap z with x or y or both.
  174. //
  175. // Returns dest to allow chaining operations.
  176. func (dest *ExtensionFieldElement) ConditionalAssign(x, y *ExtensionFieldElement, choice uint8) *ExtensionFieldElement {
  177. fp751ConditionalAssign(&dest.a, &x.a, &y.a, choice)
  178. fp751ConditionalAssign(&dest.b, &x.b, &y.b, choice)
  179. return dest
  180. }
  181. // Returns true if lhs = rhs. Takes variable time.
  182. func (lhs *ExtensionFieldElement) VartimeEq(rhs *ExtensionFieldElement) bool {
  183. return lhs.a.vartimeEq(rhs.a) && lhs.b.vartimeEq(rhs.b)
  184. }
  185. //------------------------------------------------------------------------------
  186. // Prime Field
  187. //------------------------------------------------------------------------------
  188. // Represents an element of the prime field F_p.
  189. type PrimeFieldElement struct {
  190. // This field element is in Montgomery form, so that the value `a` is
  191. // represented by `aR mod p`.
  192. a fp751Element
  193. }
  194. // Set dest to x.
  195. //
  196. // Returns dest to allow chaining operations.
  197. func (dest *PrimeFieldElement) SetUint64(x uint64) *PrimeFieldElement {
  198. var xRR fp751X2
  199. dest.a = fp751Element{} // = 0
  200. dest.a[0] = x // = x
  201. fp751Mul(&xRR, &dest.a, &montgomeryRsq) // = x*R*R
  202. fp751MontgomeryReduce(&dest.a, &xRR) // = x*R mod p
  203. return dest
  204. }
  205. // Set dest = lhs * rhs.
  206. //
  207. // Allowed to overlap lhs or rhs with dest.
  208. //
  209. // Returns dest to allow chaining operations.
  210. func (dest *PrimeFieldElement) Mul(lhs, rhs *PrimeFieldElement) *PrimeFieldElement {
  211. a := &lhs.a // = a*R
  212. b := &rhs.a // = b*R
  213. var ab fp751X2
  214. fp751Mul(&ab, a, b) // = a*b*R*R
  215. fp751MontgomeryReduce(&dest.a, &ab) // = a*b*R mod p
  216. return dest
  217. }
  218. // Set dest = x^(2^k), for k >= 1, by repeated squarings.
  219. //
  220. // Allowed to overlap x with dest.
  221. //
  222. // Returns dest to allow chaining operations.
  223. func (dest *PrimeFieldElement) Pow2k(x *PrimeFieldElement, k uint8) *PrimeFieldElement {
  224. dest.Square(x)
  225. for i := uint8(1); i < k; i++ {
  226. dest.Square(dest)
  227. }
  228. return dest
  229. }
  230. // Set dest = x^2
  231. //
  232. // Allowed to overlap x with dest.
  233. //
  234. // Returns dest to allow chaining operations.
  235. func (dest *PrimeFieldElement) Square(x *PrimeFieldElement) *PrimeFieldElement {
  236. a := &x.a // = a*R
  237. b := &x.a // = b*R
  238. var ab fp751X2
  239. fp751Mul(&ab, a, b) // = a*b*R*R
  240. fp751MontgomeryReduce(&dest.a, &ab) // = a*b*R mod p
  241. return dest
  242. }
  243. // Set dest = lhs + rhs.
  244. //
  245. // Allowed to overlap lhs or rhs with dest.
  246. //
  247. // Returns dest to allow chaining operations.
  248. func (dest *PrimeFieldElement) Add(lhs, rhs *PrimeFieldElement) *PrimeFieldElement {
  249. fp751AddReduced(&dest.a, &lhs.a, &rhs.a)
  250. return dest
  251. }
  252. // Set dest = lhs - rhs.
  253. //
  254. // Allowed to overlap lhs or rhs with dest.
  255. //
  256. // Returns dest to allow chaining operations.
  257. func (dest *PrimeFieldElement) Sub(lhs, rhs *PrimeFieldElement) *PrimeFieldElement {
  258. fp751SubReduced(&dest.a, &lhs.a, &rhs.a)
  259. return dest
  260. }
  261. // Returns true if lhs = rhs. Takes variable time.
  262. func (lhs *PrimeFieldElement) VartimeEq(rhs *PrimeFieldElement) bool {
  263. return lhs.a.vartimeEq(rhs.a)
  264. }
  265. // If choice = 1u8, set (x,y) = (y,x). If choice = 0u8, set (x,y) = (x,y).
  266. //
  267. // Returns dest to allow chaining operations.
  268. func PrimeFieldConditionalSwap(x, y *PrimeFieldElement, choice uint8) {
  269. fp751ConditionalSwap(&x.a, &y.a, choice)
  270. }
  271. // Set dest = if choice == 0 { x } else { y }, in constant time.
  272. //
  273. // Can overlap z with x or y or both.
  274. //
  275. // Returns dest to allow chaining operations.
  276. func (dest *PrimeFieldElement) ConditionalAssign(x, y *PrimeFieldElement, choice uint8) *PrimeFieldElement {
  277. fp751ConditionalAssign(&dest.a, &x.a, &y.a, choice)
  278. return dest
  279. }
  280. // Set dest = sqrt(x), if x is a square. If x is nonsquare dest is undefined.
  281. //
  282. // Allowed to overlap x with dest.
  283. //
  284. // Returns dest to allow chaining operations.
  285. func (dest *PrimeFieldElement) Sqrt(x *PrimeFieldElement) *PrimeFieldElement {
  286. tmp_x := *x // Copy x in case dest == x
  287. // Since x is assumed to be square, x = y^2
  288. dest.P34(x) // dest = (y^2)^((p-3)/4) = y^((p-3)/2)
  289. dest.Mul(dest, &tmp_x) // dest = y^2 * y^((p-3)/2) = y^((p+1)/2)
  290. // Now dest^2 = y^(p+1) = y^2 = x, so dest = sqrt(x)
  291. return dest
  292. }
  293. // Set dest = 1/x.
  294. //
  295. // Allowed to overlap x with dest.
  296. //
  297. // Returns dest to allow chaining operations.
  298. func (dest *PrimeFieldElement) Inv(x *PrimeFieldElement) *PrimeFieldElement {
  299. tmp_x := *x // Copy x in case dest == x
  300. dest.Square(x) // dest = x^2
  301. dest.P34(dest) // dest = (x^2)^((p-3)/4) = x^((p-3)/2)
  302. dest.Square(dest) // dest = x^(p-3)
  303. dest.Mul(dest, &tmp_x) // dest = x^(p-2)
  304. return dest
  305. }
  306. // Set dest = x^((p-3)/4). If x is square, this is 1/sqrt(x).
  307. //
  308. // Allowed to overlap x with dest.
  309. //
  310. // Returns dest to allow chaining operations.
  311. func (dest *PrimeFieldElement) P34(x *PrimeFieldElement) *PrimeFieldElement {
  312. // Sliding-window strategy computed with Sage, awk, sed, and tr.
  313. //
  314. // This performs sum(powStrategy) = 744 squarings and len(mulStrategy)
  315. // = 137 multiplications, in addition to 1 squaring and 15
  316. // multiplications to build a lookup table.
  317. //
  318. // In total this is 745 squarings, 152 multiplications. Since squaring
  319. // is not implemented for the prime field, this is 897 multiplications
  320. // in total.
  321. 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}
  322. 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}
  323. initialMul := uint8(27)
  324. // Build a lookup table of odd multiples of x.
  325. lookup := [16]PrimeFieldElement{}
  326. xx := &PrimeFieldElement{}
  327. xx.Square(x) // Set xx = x^2
  328. lookup[0] = *x
  329. for i := 1; i < 16; i++ {
  330. lookup[i].Mul(&lookup[i-1], xx)
  331. }
  332. // Now lookup = {x, x^3, x^5, ... }
  333. // so that lookup[i] = x^{2*i + 1}
  334. // so that lookup[k/2] = x^k, for odd k
  335. *dest = lookup[initialMul/2]
  336. for i := uint8(0); i < 137; i++ {
  337. dest.Pow2k(dest, powStrategy[i])
  338. dest.Mul(dest, &lookup[mulStrategy[i]/2])
  339. }
  340. return dest
  341. }
  342. //------------------------------------------------------------------------------
  343. // Internals
  344. //------------------------------------------------------------------------------
  345. const fp751NumWords = 12
  346. // (2^768) mod p.
  347. // This can't be a constant because Go doesn't allow array constants, so try
  348. // not to modify it.
  349. var montgomeryR = fp751Element{149933, 0, 0, 0, 0, 9444048418595930112, 6136068611055053926, 7599709743867700432, 14455912356952952366, 5522737203492907350, 1222606818372667369, 49869481633250}
  350. // (2^768)^2 mod p
  351. // This can't be a constant because Go doesn't allow array constants, so try
  352. // not to modify it.
  353. var montgomeryRsq = fp751Element{2535603850726686808, 15780896088201250090, 6788776303855402382, 17585428585582356230, 5274503137951975249, 2266259624764636289, 11695651972693921304, 13072885652150159301, 4908312795585420432, 6229583484603254826, 488927695601805643, 72213483953973}
  354. // Internal representation of an element of the base field F_p.
  355. //
  356. // This type is distinct from PrimeFieldElement in that no particular meaning
  357. // is assigned to the representation -- it could represent an element in
  358. // Montgomery form, or not. Tracking the meaning of the field element is left
  359. // to higher types.
  360. type fp751Element [fp751NumWords]uint64
  361. // Represents an intermediate product of two elements of the base field F_p.
  362. type fp751X2 [2 * fp751NumWords]uint64
  363. // If choice = 0, leave x,y unchanged. If choice = 1, set x,y = y,x.
  364. // This function executes in constant time.
  365. //go:noescape
  366. func fp751ConditionalSwap(x, y *fp751Element, choice uint8)
  367. // If choice = 0, set z = x. If choice = 1, set z = y.
  368. // This function executes in constant time.
  369. //
  370. // Can overlap z with x or y or both.
  371. //go:noescape
  372. func fp751ConditionalAssign(z, x, y *fp751Element, choice uint8)
  373. // Compute z = x + y (mod p).
  374. //go:noescape
  375. func fp751AddReduced(z, x, y *fp751Element)
  376. // Compute z = x - y (mod p).
  377. //go:noescape
  378. func fp751SubReduced(z, x, y *fp751Element)
  379. // Compute z = x + y, without reducing mod p.
  380. //go:noescape
  381. func fp751AddLazy(z, x, y *fp751Element)
  382. // Compute z = x + y, without reducing mod p.
  383. //go:noescape
  384. func fp751X2AddLazy(z, x, y *fp751X2)
  385. // Compute z = x - y, without reducing mod p.
  386. //go:noescape
  387. func fp751X2SubLazy(z, x, y *fp751X2)
  388. // Compute z = x * y.
  389. //go:noescape
  390. func fp751Mul(z *fp751X2, x, y *fp751Element)
  391. // Perform Montgomery reduction: set z = x R^{-1} (mod p).
  392. // Destroys the input value.
  393. //go:noescape
  394. func fp751MontgomeryReduce(z *fp751Element, x *fp751X2)
  395. // Reduce a field element in [0, 2*p) to one in [0,p).
  396. //go:noescape
  397. func fp751StrongReduce(x *fp751Element)
  398. func (x fp751Element) vartimeEq(y fp751Element) bool {
  399. fp751StrongReduce(&x)
  400. fp751StrongReduce(&y)
  401. eq := true
  402. for i := 0; i < fp751NumWords; i++ {
  403. eq = (x[i] == y[i]) && eq
  404. }
  405. return eq
  406. }