Você não pode selecionar mais de 25 tópicos Os tópicos devem começar com uma letra ou um número, podem incluir traços ('-') e podem ter até 35 caracteres.

utils_test.go 16 KiB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335
  1. package p503
  2. // Tools used for testing and debugging
  3. import (
  4. . "github.com/cloudflare/sidh/internal/isogeny"
  5. "math/big"
  6. "math/rand"
  7. "reflect"
  8. "testing/quick"
  9. )
  10. /* -------------------------------------------------------------------------
  11. Underlying field configuration
  12. -------------------------------------------------------------------------*/
  13. var (
  14. kFieldOps = FieldOperations()
  15. kParams = &SidhParams{
  16. Op: kFieldOps,
  17. OneFp2: P503_OneFp2,
  18. HalfFp2: P503_HalfFp2,
  19. Bytelen: P503_Bytelen,
  20. }
  21. kCurveOps = &CurveOperations{Params: kParams}
  22. )
  23. /* -------------------------------------------------------------------------
  24. Configure testing/quick
  25. -------------------------------------------------------------------------*/
  26. var (
  27. quickCheckScaleFactor = uint8(3)
  28. quickCheckConfig = &quick.Config{MaxCount: (1 << (12 + quickCheckScaleFactor))}
  29. )
  30. /* -------------------------------------------------------------------------
  31. Structure used by tests
  32. -------------------------------------------------------------------------*/
  33. type GeneratedTestParams struct {
  34. Point ProjectivePoint
  35. Cparam ProjectiveCurveParameters
  36. ExtElem Fp2Element
  37. }
  38. // A = 8752234765512331234913716743014562460822083005386252003333602919474238975785850965349950219277942402920758585086620525443539725921333735154674119646075*i + 6339624979889725406021454983012408976766782818694212228554611573314701271183857175866122275755278397694585249002282183018114967373119429936587424396917
  39. var curve_A = Fp2Element{
  40. A: FpElement{0xd9816986a543095f, 0xa78cb1d7217bec21, 0x9595dc97b74ea70, 0x9120a1da6b42797d, 0x59ef9d903f74e47c, 0x4c58a4cdc45b6d0b, 0x816d5213aaf7ee6d, 0x3892fee6bb7343},
  41. B: FpElement{0x28c5288acbedf11b, 0x2143a438c86f6c68, 0x7cb5c4ae9c4c8e34, 0xb478aea445eed48b, 0x24d5c175776db478, 0x234582f8676c0ebe, 0x56234267b625fb08, 0x2c6e58d84b1192}}
  42. // C = 10458464853790890798085664692909194316288127038910691163573355876336993883402795907795767791362493831987298578966325154262747805705783782806176495638177*i + 7770984753616185271325854825309278833018655051139367603077592443785629339985729818288672809062782315510526648882226172896710704020683893684611137718845
  43. var curve_C = Fp2Element{
  44. A: FpElement{0xe05948236f2f913b, 0xc45da9ad1219a255, 0x7a568972a32fc1d0, 0x30f00bdd7071c3b1, 0x3b761b8dac2c98bc, 0x760f21b2179737b6, 0x13217e6656a13476, 0x2606b798e685aa},
  45. B: FpElement{0x1c0171f78820052e, 0x440b7f7087e57140, 0xe0510c07b31b0e96, 0xd0cf489b2ac4aea9, 0x4fb328f1c1fdf783, 0xb3b4912342951cb7, 0x70a4b64e81961c42, 0x33eed63cf07181}}
  46. // x(P) = 9720237205826983370867050298878715935679372786589878620121159082290288918688002583435964840822877971257659901481591644347943354235932355923042390796255*i + 634577413124118560098123299804750904956499531431297942628887930019161512075536652691244843248133437326050395005054997679717801535474938466995392156605
  47. var affine_xP = Fp2Element{
  48. A: FpElement{0xb606d954d407faf2, 0x58a1ef6cd213a203, 0x9823b55033e62f7b, 0x59cafc060d5e25a1, 0x529685f1753526fc, 0xc2eac3d219989c7d, 0xc5e30c75dfd343a0, 0x378285adc968a0},
  49. B: FpElement{0x6670f36db977b9da, 0xa07e2fdda5e1a7f0, 0xf367a7a722aed87d, 0x6c269e06d595cd10, 0x8379aa6092d87700, 0x57276ce3557ee7ae, 0xac8107bfbcd28993, 0x3d6f98869617a7}}
  50. // x(Q) = 613162677562606602867371958793876971530136728660199185642812914351735322828980793298955764087721218995329689800176835576008483782305021671417330230966*i + 12939479853552958669415184882894789433224467828463058020095712989798268661016843892597050485554155971441665589419365957826417334087966365414056706471602
  51. var affine_xQ = Fp2Element{
  52. A: FpElement{0xd3d14533cb0db45c, 0xdaf10b9f5fb037cf, 0x9562c31985823562, 0xb79b75e2bf5635a5, 0x83d38fb1669c2d9, 0x5e67117a35a57cbd, 0x4b94ed6c3cbf54a4, 0x3f47706b62778d},
  53. B: FpElement{0x1c766c0e7ed612d6, 0x2f3b42979e8efd86, 0xd82bac0006415ee7, 0x20cfe3bec0970042, 0x8f6628807e862bf9, 0xac4f82d13fddd9c5, 0x70b756e4bac1fa85, 0x350c02508e50dc}}
  54. var affine_xPmQ = Fp2Element{
  55. A: FpElement{0x7295ac0e8a5531c8, 0xc02afbef6cdf51a8, 0x84d0c1bb8d80624f, 0x26abbf06c61e814b, 0xada277883fbdae07, 0x63b6739db68df3a7, 0x3554670381bcfcc6, 0x33419be255bbc6},
  56. B: FpElement{0xff9df35102da997a, 0xf9b920b2d8bd6210, 0x43d1514920e73bfb, 0x624c6fd6ef16da74, 0xeb535968ed0d1286, 0x9243e6ce29a636e6, 0x1849ed96cb7940e0, 0x1e4b495933b675}}
  57. var affine_xP2 = Fp2Element{
  58. A: FpElement{0x4e1133c2b3855902, 0x875a775c67597fbb, 0xd17eb74254141abb, 0x1d5a464a4f3391f5, 0x24405c332811d007, 0x7e47e3eb489a7372, 0x65b130dfd9efe605, 0xfa69fac179803},
  59. B: FpElement{0x329f5322e1be51ee, 0x9004dca8132ebd6f, 0x7cd87e447ca8a7b6, 0x10a6ec02c38ce69e, 0x8cef2ed7d112ac46, 0x5f385a9fc4b57cd7, 0x68a366354fe7a32e, 0x2223c1455486ac}}
  60. var affine_xP3 = Fp2Element{
  61. A: FpElement{0x74a2894cccbe287d, 0xa50e3ec842e13fce, 0xd42ea4d3f1b7ad0b, 0xa4943d50d306f99e, 0xf83e9c0955b08c33, 0xffd8e313402b9380, 0x967b315db0b2e6e, 0x3a0945883df3b4},
  62. B: FpElement{0xa9f610420a81c5ba, 0xbeb84b3ded2b4e75, 0x9fd6cea494470a70, 0x2fb0075e71900b0e, 0x63a0beb6abf3ca3d, 0xeb3e171798959f2e, 0x2209801eb702d40e, 0x36f8c4603e0fdb}}
  63. var affine_xP4 = Fp2Element{
  64. A: FpElement{0x4eb695d34b46be8f, 0xfb5e76c58585f2d2, 0xa41f8aafa6dbb531, 0x4db82f5db5cfd144, 0x14dab0e3200cbba0, 0x430381706a279f81, 0xdf6707a57161f81, 0x44740f17197c3},
  65. B: FpElement{0xa2473705cdb6d4e9, 0xfa3cd67b9c15502c, 0xf0928166d0c5cee1, 0x6150aba0c874faaa, 0x6c0b18d6d92f9034, 0xcff71d340fc1e72e, 0x19a47027af917587, 0x25ed4bad443b8f}}
  66. var affine_xP9 = Fp2Element{
  67. A: FpElement{0x112da30e288217e0, 0x5b336d527320a5f7, 0xbbf4d9403b68e3c6, 0x55eccb31c40b359c, 0x8907129ab69b3203, 0x69cc8c750125a915, 0xa41a38e6f530c0e1, 0xbe68e23af1b8d},
  68. B: FpElement{0x472c603765964213, 0xe4e64995b0769754, 0x4515583c74a6dd24, 0xff7c57f5818363a2, 0xbeaeb24662a92177, 0x8a54fa61fbf24c68, 0xa85542049eb45e12, 0x2b54caf655e285}}
  69. // m = 3904534670189250445536401319770569077681088033069864532895
  70. var mScalarBytes = [...]uint8{0x9f, 0x3b, 0xe7, 0xf9, 0xf4, 0x7c, 0xe6, 0xce, 0x79, 0x3e, 0x3d, 0x9f, 0x9f, 0x3b, 0xe7, 0xf9, 0xf4, 0x7c, 0xe6, 0xce, 0x79, 0x3e, 0x3d, 0x9f}
  71. var affine_xaP = Fp2Element{
  72. A: FpElement{0x100a82c2be58e28b, 0x70ee7b57f40d9103, 0xb9f21d6327411cbb, 0x976b2a65166591cb, 0x35435bd4614ca404, 0x15f862a9c6f51469, 0x14d9ccfe634f374a, 0x31234988b0766c},
  73. B: FpElement{0x323a3a13113b35f8, 0xc949dad174586c8f, 0x1c5ed3b1263143c, 0x13ba9870c9b5bab8, 0x79fb89a31cfe7f19, 0xa8af6d4b5d947ed2, 0xcff00f80d7b67a56, 0xfdfcb136bff75}}
  74. // Inputs for testing 3-point-ladder
  75. var threePointLadderInputs = []ProjectivePoint{
  76. // x(P)
  77. ProjectivePoint{
  78. X: Fp2Element{
  79. A: FpElement{0x43941FA9244C059E, 0xD1F337D076941189, 0x6B6A8B3A8763C96A, 0x6DF569708D6C9482, 0x487EE5707A52F4AA, 0xDE396F6E2559689E, 0xE5EE3895A8991469, 0x2B0946695790A8},
  80. B: FpElement{0xAB552C0FDAED092E, 0x7DF895E43E7DCB1C, 0x35C700E761920C4B, 0xCC5807DD70DC117A, 0x0884039A5A8DB18A, 0xD04620B3D0738052, 0xA200835605138F10, 0x3FF2E59B2FDC6A}},
  81. Z: P503_OneFp2,
  82. },
  83. // x(Q)
  84. ProjectivePoint{
  85. X: Fp2Element{
  86. A: FpElement{0x77015826982BA1FD, 0x44024489673471E4, 0x1CAA2A5F4D5DA63B, 0xA183C07E50738C01, 0x8B97782D4E1A0DE6, 0x9B819522FBC38280, 0x0BDA46A937FB7B8A, 0x3B3614305914DF},
  87. B: FpElement{0xBF0366E97B3168D9, 0xAA522AC3879CEF0F, 0x0AF5EC975BD035C8, 0x1F26FEE7BBAC165C, 0xA0EE6A637724A6AB, 0xFB52101E36BA3A38, 0xD29CF5E376E17376, 0x1374A50DF57071}},
  88. Z: P503_OneFp2,
  89. },
  90. // x(P-Q)
  91. ProjectivePoint{
  92. X: Fp2Element{
  93. A: FpElement{0xD99279BBD41EA559, 0x35CF18E72F578214, 0x90473B1DC77F73E8, 0xBFFEA930B25D7F66, 0xFD558EA177B900B2, 0x7CFAD273A782A23E, 0x6B1F610822E0F611, 0x26D2D2EF9619B5},
  94. B: FpElement{0x534F83651CBCC75D, 0x591FB4757AED5D08, 0x0B04353D40BED542, 0x829A94703AAC9139, 0x0F9C2E6D7663EB5B, 0x5D2D0F90C283F746, 0x34C872AA12A7676E, 0x0ECDB605FBFA16}},
  95. Z: P503_OneFp2,
  96. },
  97. }
  98. var curve = ProjectiveCurveParameters{A: curve_A, C: curve_C}
  99. // prime p503
  100. var p503BigIntPrime, _ = new(big.Int).SetString("13175843156907117380839252916199345042492186767578363998445663477035843932020761233518914911546024351608607150390087656982982306331019593961154237431807", 10)
  101. /* -------------------------------------------------------------------------
  102. Values used by benchmarking tools
  103. -------------------------------------------------------------------------*/
  104. // Package-level storage for this field element is intended to deter
  105. // compiler optimizations.
  106. var (
  107. benchmarkFpElement FpElement
  108. benchmarkFpElementX2 FpElementX2
  109. bench_x = FpElement{17026702066521327207, 5108203422050077993, 10225396685796065916, 11153620995215874678, 6531160855165088358, 15302925148404145445, 1248821577836769963, 9789766903037985294, 7493111552032041328, 10838999828319306046, 18103257655515297935, 27403304611634}
  110. bench_y = FpElement{4227467157325093378, 10699492810770426363, 13500940151395637365, 12966403950118934952, 16517692605450415877, 13647111148905630666, 14223628886152717087, 7167843152346903316, 15855377759596736571, 4300673881383687338, 6635288001920617779, 30486099554235}
  111. bench_z = FpElementX2{1595347748594595712, 10854920567160033970, 16877102267020034574, 12435724995376660096, 3757940912203224231, 8251999420280413600, 3648859773438820227, 17622716832674727914, 11029567000887241528, 11216190007549447055, 17606662790980286987, 4720707159513626555, 12887743598335030915, 14954645239176589309, 14178817688915225254, 1191346797768989683, 12629157932334713723, 6348851952904485603, 16444232588597434895, 7809979927681678066, 14642637672942531613, 3092657597757640067, 10160361564485285723, 240071237}
  112. )
  113. /* -------------------------------------------------------------------------
  114. Helpers
  115. -------------------------------------------------------------------------*/
  116. // Given xP = x(P), xQ = x(Q), and xPmQ = x(P-Q), compute xR = x(P+Q).
  117. //
  118. // Returns xR to allow chaining. Safe to overlap xP, xQ, xR.
  119. func AddProjFp2(xP, xQ, xPmQ *ProjectivePoint) ProjectivePoint {
  120. // Algorithm 1 of Costello-Smith.
  121. var v0, v1, v2, v3, v4 Fp2Element
  122. var xR ProjectivePoint
  123. kFieldOps.Add(&v0, &xP.X, &xP.Z) // X_P + Z_P
  124. kFieldOps.Sub(&v1, &xQ.X, &xQ.Z)
  125. kFieldOps.Mul(&v1, &v1, &v0) // (X_Q - Z_Q)(X_P + Z_P)
  126. kFieldOps.Sub(&v0, &xP.X, &xP.Z) // X_P - Z_P
  127. kFieldOps.Add(&v2, &xQ.X, &xQ.Z)
  128. kFieldOps.Mul(&v2, &v2, &v0) // (X_Q + Z_Q)(X_P - Z_P)
  129. kFieldOps.Add(&v3, &v1, &v2)
  130. kFieldOps.Square(&v3, &v3) // 4(X_Q X_P - Z_Q Z_P)^2
  131. kFieldOps.Sub(&v4, &v1, &v2)
  132. kFieldOps.Square(&v4, &v4) // 4(X_Q Z_P - Z_Q X_P)^2
  133. kFieldOps.Mul(&v0, &xPmQ.Z, &v3) // 4X_{P-Q}(X_Q X_P - Z_Q Z_P)^2
  134. kFieldOps.Mul(&xR.Z, &xPmQ.X, &v4) // 4Z_{P-Q}(X_Q Z_P - Z_Q X_P)^2
  135. xR.X = v0
  136. return xR
  137. }
  138. // Given xP = x(P) and cached curve parameters Aplus2C = A + 2*C, C4 = 4*C,
  139. // compute xQ = x([2]P).
  140. //
  141. // Returns xQ to allow chaining. Safe to overlap xP, xQ.
  142. func DoubleProjFp2(xP *ProjectivePoint, Aplus2C, C4 *Fp2Element) ProjectivePoint {
  143. // Algorithm 2 of Costello-Smith, amended to work with projective curve coefficients.
  144. var v1, v2, v3, xz4 Fp2Element
  145. var xQ ProjectivePoint
  146. kFieldOps.Add(&v1, &xP.X, &xP.Z) // (X+Z)^2
  147. kFieldOps.Square(&v1, &v1)
  148. kFieldOps.Sub(&v2, &xP.X, &xP.Z) // (X-Z)^2
  149. kFieldOps.Square(&v2, &v2)
  150. kFieldOps.Sub(&xz4, &v1, &v2) // 4XZ = (X+Z)^2 - (X-Z)^2
  151. kFieldOps.Mul(&v2, &v2, C4) // 4C(X-Z)^2
  152. kFieldOps.Mul(&xQ.X, &v1, &v2) // 4C(X+Z)^2(X-Z)^2
  153. kFieldOps.Mul(&v3, &xz4, Aplus2C) // 4XZ(A + 2C)
  154. kFieldOps.Add(&v3, &v3, &v2) // 4XZ(A + 2C) + 4C(X-Z)^2
  155. kFieldOps.Mul(&xQ.Z, &v3, &xz4) // (4XZ(A + 2C) + 4C(X-Z)^2)4XZ
  156. // Now (xQ.x : xQ.z)
  157. // = (4C(X+Z)^2(X-Z)^2 : (4XZ(A + 2C) + 4C(X-Z)^2)4XZ )
  158. // = ((X+Z)^2(X-Z)^2 : (4XZ((A + 2C)/4C) + (X-Z)^2)4XZ )
  159. // = ((X+Z)^2(X-Z)^2 : (4XZ((a + 2)/4) + (X-Z)^2)4XZ )
  160. return xQ
  161. }
  162. // Given x(P) and a scalar m in little-endian bytes, compute x([m]P) using the
  163. // Montgomery ladder. This is described in Algorithm 8 of Costello-Smith.
  164. //
  165. // This function's execution time is dependent only on the byte-length of the
  166. // input scalar. All scalars of the same input length execute in uniform time.
  167. // The scalar can be padded with zero bytes to ensure a uniform length.
  168. //
  169. // Safe to overlap the source with the destination.
  170. func ScalarMult(curve *ProjectiveCurveParameters, xP *ProjectivePoint, scalar []uint8) ProjectivePoint {
  171. var x0, x1, tmp ProjectivePoint
  172. var Aplus2C, C4 Fp2Element
  173. kFieldOps.Add(&Aplus2C, &curve.C, &curve.C) // = 2*C
  174. kFieldOps.Add(&C4, &Aplus2C, &Aplus2C) // = 4*C
  175. kFieldOps.Add(&Aplus2C, &Aplus2C, &curve.A) // = 2*C + A
  176. x0.X = P503_OneFp2
  177. x1 = *xP
  178. // Iterate over the bits of the scalar, top to bottom
  179. prevBit := uint8(0)
  180. for i := len(scalar) - 1; i >= 0; i-- {
  181. scalarByte := scalar[i]
  182. for j := 7; j >= 0; j-- {
  183. bit := (scalarByte >> uint(j)) & 0x1
  184. kCurveOps.Params.Op.CondSwap(&x0.X, &x0.Z, &x1.X, &x1.Z, (bit ^ prevBit))
  185. //sProjectivePointConditionalSwap(&x0, &x1, (bit ^ prevBit))
  186. tmp = DoubleProjFp2(&x0, &Aplus2C, &C4)
  187. x1 = AddProjFp2(&x0, &x1, xP)
  188. x0 = tmp
  189. prevBit = bit
  190. }
  191. }
  192. // now prevBit is the lowest bit of the scalar
  193. kCurveOps.Params.Op.CondSwap(&x0.X, &x0.Z, &x1.X, &x1.Z, prevBit)
  194. return x0
  195. }
  196. // Returns true if lhs = rhs. Takes variable time.
  197. func VartimeEqFp2(lhs, rhs *Fp2Element) bool {
  198. a := *lhs
  199. b := *rhs
  200. fp503StrongReduce(&a.A)
  201. fp503StrongReduce(&a.B)
  202. fp503StrongReduce(&b.A)
  203. fp503StrongReduce(&b.B)
  204. eq := true
  205. for i := 0; i < len(a.A) && eq; i++ {
  206. eq = eq && (a.A[i] == b.A[i])
  207. eq = eq && (a.B[i] == b.B[i])
  208. }
  209. return eq
  210. }
  211. // Returns true if lhs = rhs. Takes variable time.
  212. func VartimeEqProjFp2(lhs, rhs *ProjectivePoint) bool {
  213. var t0, t1 Fp2Element
  214. kFieldOps.Mul(&t0, &lhs.X, &rhs.Z)
  215. kFieldOps.Mul(&t1, &lhs.Z, &rhs.X)
  216. return VartimeEqFp2(&t0, &t1)
  217. }
  218. func (GeneratedTestParams) generateFp2p503(rand *rand.Rand) Fp2Element {
  219. // Generation strategy: low limbs taken from [0,2^64); high limb
  220. // taken from smaller range
  221. //
  222. // Size hint is ignored since all elements are fixed size.
  223. //
  224. // Field elements taken in range [0,2p). Emulate this by capping
  225. // the high limb by the top digit of 2*p-1:
  226. //
  227. // sage: (2*p-1).digits(2^64)[-1]
  228. // 36255204122967100
  229. //
  230. // This still allows generating values >= 2p, but hopefully that
  231. // excess is OK (and if it's not, we'll find out, because it's for
  232. // testing...)
  233. //
  234. highLimb := rand.Uint64() % 36255204122967100
  235. fpElementGen := func() FpElement {
  236. return FpElement{
  237. rand.Uint64(),
  238. rand.Uint64(),
  239. rand.Uint64(),
  240. rand.Uint64(),
  241. rand.Uint64(),
  242. rand.Uint64(),
  243. rand.Uint64(),
  244. highLimb,
  245. }
  246. }
  247. return Fp2Element{A: fpElementGen(), B: fpElementGen()}
  248. }
  249. func (c GeneratedTestParams) Generate(rand *rand.Rand, size int) reflect.Value {
  250. return reflect.ValueOf(
  251. GeneratedTestParams{
  252. ProjectivePoint{
  253. X: c.generateFp2p503(rand),
  254. Z: c.generateFp2p503(rand),
  255. },
  256. ProjectiveCurveParameters{
  257. A: c.generateFp2p503(rand),
  258. C: c.generateFp2p503(rand),
  259. },
  260. c.generateFp2p503(rand),
  261. })
  262. }
  263. func (x primeFieldElement) Generate(rand *rand.Rand, size int) reflect.Value {
  264. return reflect.ValueOf(primeFieldElement{A: new(GeneratedTestParams).generateFp2p503(rand).A})
  265. }
  266. // Convert an FpElement to a big.Int for testing. Because this is only
  267. // for testing, no big.Int to FpElement conversion is provided.
  268. func radix64ToBigInt(x []uint64) *big.Int {
  269. radix := new(big.Int)
  270. // 2^64
  271. radix.UnmarshalText(([]byte)("18446744073709551616"))
  272. base := new(big.Int).SetUint64(1)
  273. val := new(big.Int).SetUint64(0)
  274. tmp := new(big.Int)
  275. for _, xi := range x {
  276. tmp.SetUint64(xi)
  277. tmp.Mul(tmp, base)
  278. val.Add(val, tmp)
  279. base.Mul(base, radix)
  280. }
  281. return val
  282. }
  283. func toBigInt(x *FpElement) *big.Int {
  284. // Convert from Montgomery form
  285. return toBigIntFromMontgomeryForm(x)
  286. }
  287. func toBigIntFromMontgomeryForm(x *FpElement) *big.Int {
  288. // Convert from Montgomery form
  289. a := FpElement{}
  290. aR := FpElementX2{}
  291. copy(aR[:], x[:]) // = a*R
  292. fp503MontgomeryReduce(&a, &aR) // = a mod p in [0,2p)
  293. fp503StrongReduce(&a) // = a mod p in [0,p)
  294. return radix64ToBigInt(a[:])
  295. }