No puede seleccionar más de 25 temas Los temas deben comenzar con una letra o número, pueden incluir guiones ('-') y pueden tener hasta 35 caracteres de largo.
 
 
 

422 líneas
13 KiB

  1. // Package p751sidh implements (ephemeral) supersingular isogeny
  2. // Diffie-Hellman, as described in Costello-Longa-Naehrig 2016. Portions of
  3. // the field arithmetic implementation were based on their implementation.
  4. // Internal functions useful for the implementation are published in the
  5. // p751toolbox package.
  6. //
  7. // This package follows their naming convention, writing "Alice" for the party
  8. // using 2^e-isogenies and "Bob" for the party using 3^e-isogenies.
  9. //
  10. // This package does NOT implement SIDH key validation, so it should only be
  11. // used for ephemeral DH. Each keypair should be used at most once.
  12. //
  13. // If you feel that SIDH may be appropriate for you, consult your
  14. // cryptographer.
  15. package p751sidh
  16. import (
  17. "errors"
  18. "io"
  19. )
  20. import . "github.com/cloudflare/p751sidh/p751toolbox"
  21. const (
  22. // The secret key size, in bytes.
  23. SecretKeySize = 48
  24. // The public key size, in bytes.
  25. PublicKeySize = 564
  26. // The shared secret size, in bytes.
  27. SharedSecretSize = 188
  28. )
  29. const maxAlice = 185
  30. var aliceIsogenyStrategy = [maxAlice]int{0, 1, 1, 2, 2, 2, 3, 4, 4, 4, 4, 5, 5,
  31. 6, 7, 8, 8, 9, 9, 9, 9, 9, 9, 9, 12, 11, 12, 12, 13, 14, 15, 16, 16, 16, 16,
  32. 16, 16, 17, 17, 18, 18, 17, 21, 17, 18, 21, 20, 21, 21, 21, 21, 21, 22, 25, 25,
  33. 25, 26, 27, 28, 28, 29, 30, 31, 32, 32, 32, 32, 32, 32, 32, 33, 33, 33, 35, 36,
  34. 36, 33, 36, 35, 36, 36, 35, 36, 36, 37, 38, 38, 39, 40, 41, 42, 38, 39, 40, 41,
  35. 42, 40, 46, 42, 43, 46, 46, 46, 46, 48, 48, 48, 48, 49, 49, 48, 53, 54, 51, 52,
  36. 53, 54, 55, 56, 57, 58, 59, 59, 60, 62, 62, 63, 64, 64, 64, 64, 64, 64, 64, 64,
  37. 65, 65, 65, 65, 65, 66, 67, 65, 66, 67, 66, 69, 70, 66, 67, 66, 69, 70, 69, 70,
  38. 70, 71, 72, 71, 72, 72, 74, 74, 75, 72, 72, 74, 74, 75, 72, 72, 74, 75, 75, 72,
  39. 72, 74, 75, 75, 77, 77, 79, 80, 80, 82}
  40. const maxBob = 239
  41. var bobIsogenyStrategy = [maxBob]int{0, 1, 1, 2, 2, 2, 3, 3, 4, 4, 4, 5, 5, 5, 6,
  42. 7, 8, 8, 8, 8, 9, 9, 9, 9, 9, 10, 12, 12, 12, 12, 12, 12, 13, 14, 14, 15, 16,
  43. 16, 16, 16, 16, 17, 16, 16, 17, 19, 19, 20, 21, 22, 22, 22, 22, 22, 22, 22, 22,
  44. 22, 22, 24, 24, 25, 27, 27, 28, 28, 29, 28, 29, 28, 28, 28, 30, 28, 28, 28, 29,
  45. 30, 33, 33, 33, 33, 34, 35, 37, 37, 37, 37, 38, 38, 37, 38, 38, 38, 38, 38, 39,
  46. 43, 38, 38, 38, 38, 43, 40, 41, 42, 43, 48, 45, 46, 47, 47, 48, 49, 49, 49, 50,
  47. 51, 50, 49, 49, 49, 49, 51, 49, 53, 50, 51, 50, 51, 51, 51, 52, 55, 55, 55, 56,
  48. 56, 56, 56, 56, 58, 58, 61, 61, 61, 63, 63, 63, 64, 65, 65, 65, 65, 66, 66, 65,
  49. 65, 66, 66, 66, 66, 66, 66, 66, 71, 66, 73, 66, 66, 71, 66, 73, 66, 66, 71, 66,
  50. 73, 68, 68, 71, 71, 73, 73, 73, 75, 75, 78, 78, 78, 80, 80, 80, 81, 81, 82, 83,
  51. 84, 85, 86, 86, 86, 86, 86, 87, 86, 88, 86, 86, 86, 86, 88, 86, 88, 86, 86, 86,
  52. 88, 88, 86, 86, 86, 93, 90, 90, 92, 92, 92, 93, 93, 93, 93, 93, 97, 97, 97, 97,
  53. 97, 97}
  54. // Bob's public key.
  55. type SIDHPublicKeyBob struct {
  56. affine_xP ExtensionFieldElement
  57. affine_xQ ExtensionFieldElement
  58. affine_xQmP ExtensionFieldElement
  59. }
  60. // Read a public key from a byte slice. The input must be at least 564 bytes long.
  61. func (pubKey *SIDHPublicKeyBob) FromBytes(input []byte) {
  62. if len(input) < 564 {
  63. panic("Too short input to SIDH pubkey FromBytes, expected 564 bytes")
  64. }
  65. pubKey.affine_xP.FromBytes(input[0:188])
  66. pubKey.affine_xQ.FromBytes(input[188:376])
  67. pubKey.affine_xQmP.FromBytes(input[376:564])
  68. }
  69. // Write a public key to a byte slice. The output must be at least 564 bytes long.
  70. func (pubKey *SIDHPublicKeyBob) ToBytes(output []byte) {
  71. if len(output) < 564 {
  72. panic("Too short output for SIDH pubkey FromBytes, expected 564 bytes")
  73. }
  74. pubKey.affine_xP.ToBytes(output[0:188])
  75. pubKey.affine_xQ.ToBytes(output[188:376])
  76. pubKey.affine_xQmP.ToBytes(output[376:564])
  77. }
  78. // Alice's public key.
  79. type SIDHPublicKeyAlice struct {
  80. affine_xP ExtensionFieldElement
  81. affine_xQ ExtensionFieldElement
  82. affine_xQmP ExtensionFieldElement
  83. }
  84. // Read a public key from a byte slice. The input must be at least 564 bytes long.
  85. func (pubKey *SIDHPublicKeyAlice) FromBytes(input []byte) {
  86. if len(input) < 564 {
  87. panic("Too short input to SIDH pubkey FromBytes, expected 564 bytes")
  88. }
  89. pubKey.affine_xP.FromBytes(input[0:188])
  90. pubKey.affine_xQ.FromBytes(input[188:376])
  91. pubKey.affine_xQmP.FromBytes(input[376:564])
  92. }
  93. // Write a public key to a byte slice. The output must be at least 564 bytes long.
  94. func (pubKey *SIDHPublicKeyAlice) ToBytes(output []byte) {
  95. if len(output) < 564 {
  96. panic("Too short output for SIDH pubkey FromBytes, expected 564 bytes")
  97. }
  98. pubKey.affine_xP.ToBytes(output[0:188])
  99. pubKey.affine_xQ.ToBytes(output[188:376])
  100. pubKey.affine_xQmP.ToBytes(output[376:564])
  101. }
  102. // Bob's secret key.
  103. type SIDHSecretKeyBob struct {
  104. Scalar [SecretKeySize]byte
  105. }
  106. // Alice's secret key.
  107. type SIDHSecretKeyAlice struct {
  108. Scalar [SecretKeySize]byte
  109. }
  110. // Generate a keypair for "Alice". Note that because this library does not
  111. // implement SIDH validation, each keypair should be used for at most one
  112. // shared secret computation.
  113. func GenerateAliceKeypair(rand io.Reader) (publicKey *SIDHPublicKeyAlice, secretKey *SIDHSecretKeyAlice, err error) {
  114. publicKey = new(SIDHPublicKeyAlice)
  115. secretKey = new(SIDHSecretKeyAlice)
  116. _, err = io.ReadFull(rand, secretKey.Scalar[:])
  117. if err != nil {
  118. return nil, nil, err
  119. }
  120. // Bit-twiddle to ensure scalar is in 2*[0,2^371):
  121. secretKey.Scalar[47] = 0
  122. secretKey.Scalar[46] &= 15 // clear high bits, so scalar < 2^372
  123. secretKey.Scalar[0] &= 254 // clear low bit, so scalar is even
  124. // We actually want scalar in 2*(0,2^371), but the above procedure
  125. // generates 0 with probability 2^(-371), which isn't worth checking
  126. // for.
  127. *publicKey = secretKey.PublicKey()
  128. return
  129. }
  130. // Set result to zero if the input scalar is <= 3^238.
  131. //go:noescape
  132. func checkLessThanThree238(scalar *[48]byte, result *uint32)
  133. // Set scalar = 3*scalar
  134. //go:noescape
  135. func multiplyByThree(scalar *[48]byte)
  136. // Generate a keypair for "Bob". Note that because this library does not
  137. // implement SIDH validation, each keypair should be used for at most one
  138. // shared secret computation.
  139. func GenerateBobKeypair(rand io.Reader) (publicKey *SIDHPublicKeyBob, secretKey *SIDHSecretKeyBob, err error) {
  140. publicKey = new(SIDHPublicKeyBob)
  141. secretKey = new(SIDHSecretKeyBob)
  142. // Perform rejection sampling to obtain a random value in [0,3^238]:
  143. var ok uint32
  144. for i := 0; i < 102; i++ {
  145. _, err = io.ReadFull(rand, secretKey.Scalar[:])
  146. if err != nil {
  147. return nil, nil, err
  148. }
  149. // Mask the high bits to obtain a uniform value in [0,2^378):
  150. secretKey.Scalar[47] &= 3
  151. // Accept if scalar < 3^238 (this happens w/ prob ~0.5828)
  152. checkLessThanThree238(&secretKey.Scalar, &ok)
  153. if ok == 0 {
  154. break
  155. }
  156. }
  157. // ok is nonzero if all 102 trials failed.
  158. // This happens with probability 0.41719...^102 < 2^(-128), i.e., never
  159. if ok != 0 {
  160. return nil, nil, errors.New("WOW! An event with probability < 2^(-128) occurred!!")
  161. }
  162. // Multiply by 3 to get a scalar in 3*[0,3^238):
  163. multiplyByThree(&secretKey.Scalar)
  164. // We actually want scalar in 2*(0,2^371), but the above procedure
  165. // generates 0 with probability 3^(-238), which isn't worth checking
  166. // for.
  167. *publicKey = secretKey.PublicKey()
  168. return
  169. }
  170. // Compute the corresponding public key for the given secret key.
  171. func (secretKey *SIDHSecretKeyAlice) PublicKey() SIDHPublicKeyAlice {
  172. var xP, xQ, xQmP, xR ProjectivePoint
  173. xP.FromAffinePrimeField(&Affine_xPB) // = ( x_P : 1) = x(P_B)
  174. xQ.FromAffinePrimeField(&Affine_xPB) //
  175. xQ.X.Neg(&xQ.X) // = (-x_P : 1) = x(Q_B)
  176. xQmP = DistortAndDifference(&Affine_xPB) // = x(Q_B - P_B)
  177. xR = SecretPoint(&Affine_xPA, &Affine_yPA, secretKey.Scalar[:])
  178. var currentCurve ProjectiveCurveParameters
  179. // Starting curve has a = 0, so (A:C) = (0,1)
  180. currentCurve.A.Zero()
  181. currentCurve.C.One()
  182. var firstPhi FirstFourIsogeny
  183. currentCurve, firstPhi = ComputeFirstFourIsogeny(&currentCurve)
  184. xP = firstPhi.Eval(&xP)
  185. xQ = firstPhi.Eval(&xQ)
  186. xQmP = firstPhi.Eval(&xQmP)
  187. xR = firstPhi.Eval(&xR)
  188. var points = make([]ProjectivePoint, 0, 8)
  189. var indices = make([]int, 0, 8)
  190. var phi FourIsogeny
  191. var i = 0
  192. for j := 1; j < 185; j++ {
  193. for i < 185-j {
  194. points = append(points, xR)
  195. indices = append(indices, i)
  196. k := int(aliceIsogenyStrategy[185-i-j])
  197. xR.Pow2k(&currentCurve, &xR, uint32(2*k))
  198. i = i + k
  199. }
  200. currentCurve, phi = ComputeFourIsogeny(&xR)
  201. for k := 0; k < len(points); k++ {
  202. points[k] = phi.Eval(&points[k])
  203. }
  204. xP = phi.Eval(&xP)
  205. xQ = phi.Eval(&xQ)
  206. xQmP = phi.Eval(&xQmP)
  207. // pop xR from points
  208. xR, points = points[len(points)-1], points[:len(points)-1]
  209. i, indices = int(indices[len(indices)-1]), indices[:len(indices)-1]
  210. }
  211. currentCurve, phi = ComputeFourIsogeny(&xR)
  212. xP = phi.Eval(&xP)
  213. xQ = phi.Eval(&xQ)
  214. xQmP = phi.Eval(&xQmP)
  215. var invZP, invZQ, invZQmP ExtensionFieldElement
  216. ExtensionFieldBatch3Inv(&xP.Z, &xQ.Z, &xQmP.Z, &invZP, &invZQ, &invZQmP)
  217. var publicKey SIDHPublicKeyAlice
  218. publicKey.affine_xP.Mul(&xP.X, &invZP)
  219. publicKey.affine_xQ.Mul(&xQ.X, &invZQ)
  220. publicKey.affine_xQmP.Mul(&xQmP.X, &invZQmP)
  221. return publicKey
  222. }
  223. // Compute the public key corresponding to the secret key.
  224. func (secretKey *SIDHSecretKeyBob) PublicKey() SIDHPublicKeyBob {
  225. var xP, xQ, xQmP, xR ProjectivePoint
  226. xP.FromAffinePrimeField(&Affine_xPA) // = ( x_P : 1) = x(P_A)
  227. xQ.FromAffinePrimeField(&Affine_xPA) //
  228. xQ.X.Neg(&xQ.X) // = (-x_P : 1) = x(Q_A)
  229. xQmP = DistortAndDifference(&Affine_xPA) // = x(Q_B - P_B)
  230. xR = SecretPoint(&Affine_xPB, &Affine_yPB, secretKey.Scalar[:])
  231. var currentCurve ProjectiveCurveParameters
  232. // Starting curve has a = 0, so (A:C) = (0,1)
  233. currentCurve.A.Zero()
  234. currentCurve.C.One()
  235. var points = make([]ProjectivePoint, 0, 8)
  236. var indices = make([]int, 0, 8)
  237. var phi ThreeIsogeny
  238. var i = 0
  239. for j := 1; j < 239; j++ {
  240. for i < 239-j {
  241. points = append(points, xR)
  242. indices = append(indices, i)
  243. k := int(bobIsogenyStrategy[239-i-j])
  244. xR.Pow3k(&currentCurve, &xR, uint32(k))
  245. i = i + k
  246. }
  247. currentCurve, phi = ComputeThreeIsogeny(&xR)
  248. for k := 0; k < len(points); k++ {
  249. points[k] = phi.Eval(&points[k])
  250. }
  251. xP = phi.Eval(&xP)
  252. xQ = phi.Eval(&xQ)
  253. xQmP = phi.Eval(&xQmP)
  254. // pop xR from points
  255. xR, points = points[len(points)-1], points[:len(points)-1]
  256. i, indices = int(indices[len(indices)-1]), indices[:len(indices)-1]
  257. }
  258. currentCurve, phi = ComputeThreeIsogeny(&xR)
  259. xP = phi.Eval(&xP)
  260. xQ = phi.Eval(&xQ)
  261. xQmP = phi.Eval(&xQmP)
  262. var invZP, invZQ, invZQmP ExtensionFieldElement
  263. ExtensionFieldBatch3Inv(&xP.Z, &xQ.Z, &xQmP.Z, &invZP, &invZQ, &invZQmP)
  264. var publicKey SIDHPublicKeyBob
  265. publicKey.affine_xP.Mul(&xP.X, &invZP)
  266. publicKey.affine_xQ.Mul(&xQ.X, &invZQ)
  267. publicKey.affine_xQmP.Mul(&xQmP.X, &invZQmP)
  268. return publicKey
  269. }
  270. // Compute (Alice's view of) a shared secret using Alice's secret key and Bob's public key.
  271. func (aliceSecret *SIDHSecretKeyAlice) SharedSecret(bobPublic *SIDHPublicKeyBob) [SharedSecretSize]byte {
  272. var currentCurve = RecoverCurveParameters(&bobPublic.affine_xP, &bobPublic.affine_xQ, &bobPublic.affine_xQmP)
  273. var xR, xP, xQ, xQmP ProjectivePoint
  274. xP.FromAffine(&bobPublic.affine_xP)
  275. xQ.FromAffine(&bobPublic.affine_xQ)
  276. xQmP.FromAffine(&bobPublic.affine_xQmP)
  277. xR.RightToLeftLadder(&currentCurve, &xP, &xQ, &xQmP, aliceSecret.Scalar[:])
  278. var firstPhi FirstFourIsogeny
  279. currentCurve, firstPhi = ComputeFirstFourIsogeny(&currentCurve)
  280. xR = firstPhi.Eval(&xR)
  281. var points = make([]ProjectivePoint, 0, 8)
  282. var indices = make([]int, 0, 8)
  283. var phi FourIsogeny
  284. var i = 0
  285. for j := 1; j < 185; j++ {
  286. for i < 185-j {
  287. points = append(points, xR)
  288. indices = append(indices, i)
  289. k := int(aliceIsogenyStrategy[185-i-j])
  290. xR.Pow2k(&currentCurve, &xR, uint32(2*k))
  291. i = i + k
  292. }
  293. currentCurve, phi = ComputeFourIsogeny(&xR)
  294. for k := 0; k < len(points); k++ {
  295. points[k] = phi.Eval(&points[k])
  296. }
  297. // pop xR from points
  298. xR, points = points[len(points)-1], points[:len(points)-1]
  299. i, indices = int(indices[len(indices)-1]), indices[:len(indices)-1]
  300. }
  301. currentCurve, _ = ComputeFourIsogeny(&xR)
  302. var sharedSecret [SharedSecretSize]byte
  303. var jInv = currentCurve.JInvariant()
  304. jInv.ToBytes(sharedSecret[:])
  305. return sharedSecret
  306. }
  307. // Compute (Bob's view of) a shared secret using Bob's secret key and Alice's public key.
  308. func (bobSecret *SIDHSecretKeyBob) SharedSecret(alicePublic *SIDHPublicKeyAlice) [SharedSecretSize]byte {
  309. var currentCurve = RecoverCurveParameters(&alicePublic.affine_xP, &alicePublic.affine_xQ, &alicePublic.affine_xQmP)
  310. var xR, xP, xQ, xQmP ProjectivePoint
  311. xP.FromAffine(&alicePublic.affine_xP)
  312. xQ.FromAffine(&alicePublic.affine_xQ)
  313. xQmP.FromAffine(&alicePublic.affine_xQmP)
  314. xR.RightToLeftLadder(&currentCurve, &xP, &xQ, &xQmP, bobSecret.Scalar[:])
  315. var points = make([]ProjectivePoint, 0, 8)
  316. var indices = make([]int, 0, 8)
  317. var phi ThreeIsogeny
  318. var i = 0
  319. for j := 1; j < 239; j++ {
  320. for i < 239-j {
  321. points = append(points, xR)
  322. indices = append(indices, i)
  323. k := int(bobIsogenyStrategy[239-i-j])
  324. xR.Pow3k(&currentCurve, &xR, uint32(k))
  325. i = i + k
  326. }
  327. currentCurve, phi = ComputeThreeIsogeny(&xR)
  328. for k := 0; k < len(points); k++ {
  329. points[k] = phi.Eval(&points[k])
  330. }
  331. // pop xR from points
  332. xR, points = points[len(points)-1], points[:len(points)-1]
  333. i, indices = int(indices[len(indices)-1]), indices[:len(indices)-1]
  334. }
  335. currentCurve, _ = ComputeThreeIsogeny(&xR)
  336. var sharedSecret [SharedSecretSize]byte
  337. var jInv = currentCurve.JInvariant()
  338. jInv.ToBytes(sharedSecret[:])
  339. return sharedSecret
  340. }