Nevar pievienot vairāk kā 25 tēmas Tēmai ir jāsākas ar burtu vai ciparu, tā var saturēt domu zīmes ('-') un var būt līdz 35 simboliem gara.

696 rindas
21 KiB

  1. package sike
  2. import (
  3. "crypto/hmac"
  4. "crypto/sha256"
  5. "crypto/subtle"
  6. "errors"
  7. "io"
  8. )
  9. // Constants used for cSHAKE customization
  10. // Those values are different than in [SIKE] - they are encoded on 16bits. This is
  11. // done in order for implementation to be compatible with [REF] and test vectors.
  12. var G = []byte{0x00, 0x00}
  13. var H = []byte{0x01, 0x00}
  14. var F = []byte{0x02, 0x00}
  15. // Generates HMAC-SHA256 sum
  16. func hashMac(out, in, S []byte) {
  17. h := hmac.New(sha256.New, in)
  18. h.Write(S)
  19. copy(out, h.Sum(nil))
  20. }
  21. // Zeroize Fp2
  22. func zeroize(fp *Fp2) {
  23. // Zeroizing in 2 seperated loops tells compiler to
  24. // use fast runtime.memclr()
  25. for i := range fp.A {
  26. fp.A[i] = 0
  27. }
  28. for i := range fp.B {
  29. fp.B[i] = 0
  30. }
  31. }
  32. // Convert the input to wire format.
  33. //
  34. // The output byte slice must be at least 2*bytelen(p) bytes long.
  35. func convFp2ToBytes(output []byte, fp2 *Fp2) {
  36. if len(output) < 2*Params.Bytelen {
  37. panic("output byte slice too short")
  38. }
  39. var a Fp2
  40. fromMontDomain(fp2, &a)
  41. // convert to bytes in little endian form
  42. for i := 0; i < Params.Bytelen; i++ {
  43. // set i = j*8 + k
  44. tmp := i / 8
  45. k := uint64(i % 8)
  46. output[i] = byte(a.A[tmp] >> (8 * k))
  47. output[i+Params.Bytelen] = byte(a.B[tmp] >> (8 * k))
  48. }
  49. }
  50. // Read 2*bytelen(p) bytes into the given ExtensionFieldElement.
  51. //
  52. // It is an error to call this function if the input byte slice is less than 2*bytelen(p) bytes long.
  53. func convBytesToFp2(fp2 *Fp2, input []byte) {
  54. if len(input) < 2*Params.Bytelen {
  55. panic("input byte slice too short")
  56. }
  57. for i := 0; i < Params.Bytelen; i++ {
  58. j := i / 8
  59. k := uint64(i % 8)
  60. fp2.A[j] |= uint64(input[i]) << (8 * k)
  61. fp2.B[j] |= uint64(input[i+Params.Bytelen]) << (8 * k)
  62. }
  63. toMontDomain(fp2)
  64. }
  65. // -----------------------------------------------------------------------------
  66. // Functions for traversing isogeny trees acoording to strategy. Key type 'A' is
  67. //
  68. // Traverses isogeny tree in order to compute xR, xP, xQ and xQmP needed
  69. // for public key generation.
  70. func traverseTreePublicKeyA(curve *ProjectiveCurveParameters, xR, phiP, phiQ, phiR *ProjectivePoint, pub *PublicKey) {
  71. var points = make([]ProjectivePoint, 0, 8)
  72. var indices = make([]int, 0, 8)
  73. var i, sidx int
  74. cparam := CalcCurveParamsEquiv4(curve)
  75. phi := NewIsogeny4()
  76. strat := pub.params.A.IsogenyStrategy
  77. stratSz := len(strat)
  78. for j := 1; j <= stratSz; j++ {
  79. for i <= stratSz-j {
  80. points = append(points, *xR)
  81. indices = append(indices, i)
  82. k := strat[sidx]
  83. sidx++
  84. Pow2k(xR, &cparam, 2*k)
  85. i += int(k)
  86. }
  87. cparam = phi.GenerateCurve(xR)
  88. for k := 0; k < len(points); k++ {
  89. points[k] = phi.EvaluatePoint(&points[k])
  90. }
  91. *phiP = phi.EvaluatePoint(phiP)
  92. *phiQ = phi.EvaluatePoint(phiQ)
  93. *phiR = phi.EvaluatePoint(phiR)
  94. // pop xR from points
  95. *xR, points = points[len(points)-1], points[:len(points)-1]
  96. i, indices = int(indices[len(indices)-1]), indices[:len(indices)-1]
  97. }
  98. }
  99. // Traverses isogeny tree in order to compute xR needed
  100. // for public key generation.
  101. func traverseTreeSharedKeyA(curve *ProjectiveCurveParameters, xR *ProjectivePoint, pub *PublicKey) {
  102. var points = make([]ProjectivePoint, 0, 8)
  103. var indices = make([]int, 0, 8)
  104. var i, sidx int
  105. cparam := CalcCurveParamsEquiv4(curve)
  106. phi := NewIsogeny4()
  107. strat := pub.params.A.IsogenyStrategy
  108. stratSz := len(strat)
  109. for j := 1; j <= stratSz; j++ {
  110. for i <= stratSz-j {
  111. points = append(points, *xR)
  112. indices = append(indices, i)
  113. k := strat[sidx]
  114. sidx++
  115. Pow2k(xR, &cparam, 2*k)
  116. i += int(k)
  117. }
  118. cparam = phi.GenerateCurve(xR)
  119. for k := 0; k < len(points); k++ {
  120. points[k] = phi.EvaluatePoint(&points[k])
  121. }
  122. // pop xR from points
  123. *xR, points = points[len(points)-1], points[:len(points)-1]
  124. i, indices = int(indices[len(indices)-1]), indices[:len(indices)-1]
  125. }
  126. }
  127. // Traverses isogeny tree in order to compute xR, xP, xQ and xQmP needed
  128. // for public key generation.
  129. func traverseTreePublicKeyB(curve *ProjectiveCurveParameters, xR, phiP, phiQ, phiR *ProjectivePoint, pub *PublicKey) {
  130. var points = make([]ProjectivePoint, 0, 8)
  131. var indices = make([]int, 0, 8)
  132. var i, sidx int
  133. cparam := CalcCurveParamsEquiv3(curve)
  134. phi := NewIsogeny3()
  135. strat := pub.params.B.IsogenyStrategy
  136. stratSz := len(strat)
  137. for j := 1; j <= stratSz; j++ {
  138. for i <= stratSz-j {
  139. points = append(points, *xR)
  140. indices = append(indices, i)
  141. k := strat[sidx]
  142. sidx++
  143. Pow3k(xR, &cparam, k)
  144. i += int(k)
  145. }
  146. cparam = phi.GenerateCurve(xR)
  147. for k := 0; k < len(points); k++ {
  148. points[k] = phi.EvaluatePoint(&points[k])
  149. }
  150. *phiP = phi.EvaluatePoint(phiP)
  151. *phiQ = phi.EvaluatePoint(phiQ)
  152. *phiR = phi.EvaluatePoint(phiR)
  153. // pop xR from points
  154. *xR, points = points[len(points)-1], points[:len(points)-1]
  155. i, indices = int(indices[len(indices)-1]), indices[:len(indices)-1]
  156. }
  157. }
  158. // Traverses isogeny tree in order to compute xR, xP, xQ and xQmP needed
  159. // for public key generation.
  160. func traverseTreeSharedKeyB(curve *ProjectiveCurveParameters, xR *ProjectivePoint, pub *PublicKey) {
  161. var points = make([]ProjectivePoint, 0, 8)
  162. var indices = make([]int, 0, 8)
  163. var i, sidx int
  164. cparam := CalcCurveParamsEquiv3(curve)
  165. phi := NewIsogeny3()
  166. strat := pub.params.B.IsogenyStrategy
  167. stratSz := len(strat)
  168. for j := 1; j <= stratSz; j++ {
  169. for i <= stratSz-j {
  170. points = append(points, *xR)
  171. indices = append(indices, i)
  172. k := strat[sidx]
  173. sidx++
  174. Pow3k(xR, &cparam, k)
  175. i += int(k)
  176. }
  177. cparam = phi.GenerateCurve(xR)
  178. for k := 0; k < len(points); k++ {
  179. points[k] = phi.EvaluatePoint(&points[k])
  180. }
  181. // pop xR from points
  182. *xR, points = points[len(points)-1], points[:len(points)-1]
  183. i, indices = int(indices[len(indices)-1]), indices[:len(indices)-1]
  184. }
  185. }
  186. // Generate a public key in the 2-torsion group
  187. func publicKeyGenA(prv *PrivateKey) (pub *PublicKey) {
  188. var xPA, xQA, xRA ProjectivePoint
  189. var xPB, xQB, xRB, xR ProjectivePoint
  190. var invZP, invZQ, invZR Fp2
  191. var tmp ProjectiveCurveParameters
  192. pub = NewPublicKey(KeyVariant_SIDH_A)
  193. var phi = NewIsogeny4()
  194. // Load points for A
  195. xPA = ProjectivePoint{X: prv.params.A.Affine_P, Z: prv.params.OneFp2}
  196. xQA = ProjectivePoint{X: prv.params.A.Affine_Q, Z: prv.params.OneFp2}
  197. xRA = ProjectivePoint{X: prv.params.A.Affine_R, Z: prv.params.OneFp2}
  198. // Load points for B
  199. xRB = ProjectivePoint{X: prv.params.B.Affine_R, Z: prv.params.OneFp2}
  200. xQB = ProjectivePoint{X: prv.params.B.Affine_Q, Z: prv.params.OneFp2}
  201. xPB = ProjectivePoint{X: prv.params.B.Affine_P, Z: prv.params.OneFp2}
  202. // Find isogeny kernel
  203. tmp.C = pub.params.OneFp2
  204. xR = ScalarMul3Pt(&tmp, &xPA, &xQA, &xRA, prv.params.A.SecretBitLen, prv.Scalar)
  205. // Reset params object and travers isogeny tree
  206. tmp.C = pub.params.OneFp2
  207. zeroize(&tmp.A)
  208. traverseTreePublicKeyA(&tmp, &xR, &xPB, &xQB, &xRB, pub)
  209. // Secret isogeny
  210. phi.GenerateCurve(&xR)
  211. xPA = phi.EvaluatePoint(&xPB)
  212. xQA = phi.EvaluatePoint(&xQB)
  213. xRA = phi.EvaluatePoint(&xRB)
  214. Fp2Batch3Inv(&xPA.Z, &xQA.Z, &xRA.Z, &invZP, &invZQ, &invZR)
  215. mul(&pub.affine_xP, &xPA.X, &invZP)
  216. mul(&pub.affine_xQ, &xQA.X, &invZQ)
  217. mul(&pub.affine_xQmP, &xRA.X, &invZR)
  218. return
  219. }
  220. // Generate a public key in the 3-torsion group
  221. func publicKeyGenB(prv *PrivateKey) (pub *PublicKey) {
  222. var xPB, xQB, xRB, xR ProjectivePoint
  223. var xPA, xQA, xRA ProjectivePoint
  224. var invZP, invZQ, invZR Fp2
  225. var tmp ProjectiveCurveParameters
  226. pub = NewPublicKey(prv.keyVariant)
  227. var phi = NewIsogeny3()
  228. // Load points for B
  229. xRB = ProjectivePoint{X: prv.params.B.Affine_R, Z: prv.params.OneFp2}
  230. xQB = ProjectivePoint{X: prv.params.B.Affine_Q, Z: prv.params.OneFp2}
  231. xPB = ProjectivePoint{X: prv.params.B.Affine_P, Z: prv.params.OneFp2}
  232. // Load points for A
  233. xPA = ProjectivePoint{X: prv.params.A.Affine_P, Z: prv.params.OneFp2}
  234. xQA = ProjectivePoint{X: prv.params.A.Affine_Q, Z: prv.params.OneFp2}
  235. xRA = ProjectivePoint{X: prv.params.A.Affine_R, Z: prv.params.OneFp2}
  236. tmp.C = pub.params.OneFp2
  237. xR = ScalarMul3Pt(&tmp, &xPB, &xQB, &xRB, prv.params.B.SecretBitLen, prv.Scalar)
  238. tmp.C = pub.params.OneFp2
  239. zeroize(&tmp.A)
  240. traverseTreePublicKeyB(&tmp, &xR, &xPA, &xQA, &xRA, pub)
  241. phi.GenerateCurve(&xR)
  242. xPB = phi.EvaluatePoint(&xPA)
  243. xQB = phi.EvaluatePoint(&xQA)
  244. xRB = phi.EvaluatePoint(&xRA)
  245. Fp2Batch3Inv(&xPB.Z, &xQB.Z, &xRB.Z, &invZP, &invZQ, &invZR)
  246. mul(&pub.affine_xP, &xPB.X, &invZP)
  247. mul(&pub.affine_xQ, &xQB.X, &invZQ)
  248. mul(&pub.affine_xQmP, &xRB.X, &invZR)
  249. return
  250. }
  251. // -----------------------------------------------------------------------------
  252. // Key agreement functions
  253. //
  254. // Establishing shared keys in in 2-torsion group
  255. func deriveSecretA(prv *PrivateKey, pub *PublicKey) []byte {
  256. var sharedSecret = make([]byte, pub.params.SharedSecretSize)
  257. var cparam ProjectiveCurveParameters
  258. var xP, xQ, xQmP ProjectivePoint
  259. var xR ProjectivePoint
  260. var phi = NewIsogeny4()
  261. var jInv Fp2
  262. // Recover curve coefficients
  263. cparam.C = pub.params.OneFp2
  264. RecoverCoordinateA(&cparam, &pub.affine_xP, &pub.affine_xQ, &pub.affine_xQmP)
  265. // Find kernel of the morphism
  266. xP = ProjectivePoint{X: pub.affine_xP, Z: pub.params.OneFp2}
  267. xQ = ProjectivePoint{X: pub.affine_xQ, Z: pub.params.OneFp2}
  268. xQmP = ProjectivePoint{X: pub.affine_xQmP, Z: pub.params.OneFp2}
  269. xR = ScalarMul3Pt(&cparam, &xP, &xQ, &xQmP, pub.params.A.SecretBitLen, prv.Scalar)
  270. // Traverse isogeny tree
  271. traverseTreeSharedKeyA(&cparam, &xR, pub)
  272. // Calculate j-invariant on isogeneus curve
  273. c := phi.GenerateCurve(&xR)
  274. RecoverCurveCoefficients4(&cparam, &c)
  275. Jinvariant(&cparam, &jInv)
  276. convFp2ToBytes(sharedSecret, &jInv)
  277. return sharedSecret
  278. }
  279. // Establishing shared keys in in 3-torsion group
  280. func deriveSecretB(prv *PrivateKey, pub *PublicKey) []byte {
  281. var sharedSecret = make([]byte, pub.params.SharedSecretSize)
  282. var xP, xQ, xQmP ProjectivePoint
  283. var xR ProjectivePoint
  284. var cparam ProjectiveCurveParameters
  285. var phi = NewIsogeny3()
  286. var jInv Fp2
  287. // Recover curve coefficients
  288. cparam.C = pub.params.OneFp2
  289. RecoverCoordinateA(&cparam, &pub.affine_xP, &pub.affine_xQ, &pub.affine_xQmP)
  290. // Find kernel of the morphism
  291. xP = ProjectivePoint{X: pub.affine_xP, Z: pub.params.OneFp2}
  292. xQ = ProjectivePoint{X: pub.affine_xQ, Z: pub.params.OneFp2}
  293. xQmP = ProjectivePoint{X: pub.affine_xQmP, Z: pub.params.OneFp2}
  294. xR = ScalarMul3Pt(&cparam, &xP, &xQ, &xQmP, pub.params.B.SecretBitLen, prv.Scalar)
  295. // Traverse isogeny tree
  296. traverseTreeSharedKeyB(&cparam, &xR, pub)
  297. // Calculate j-invariant on isogeneus curve
  298. c := phi.GenerateCurve(&xR)
  299. RecoverCurveCoefficients3(&cparam, &c)
  300. Jinvariant(&cparam, &jInv)
  301. convFp2ToBytes(sharedSecret, &jInv)
  302. return sharedSecret
  303. }
  304. func encrypt(skA *PrivateKey, pkA, pkB *PublicKey, ptext []byte) ([]byte, error) {
  305. var n [40]byte // n can is max 320-bit (see 1.4 of [SIKE])
  306. var ptextLen = len(ptext)
  307. if pkB.keyVariant != KeyVariant_SIKE {
  308. return nil, errors.New("wrong key type")
  309. }
  310. j, err := DeriveSecret(skA, pkB)
  311. if err != nil {
  312. return nil, err
  313. }
  314. hashMac(n[:ptextLen], j, F)
  315. for i, _ := range ptext {
  316. n[i] ^= ptext[i]
  317. }
  318. ret := make([]byte, pkA.Size()+ptextLen)
  319. copy(ret, pkA.Export())
  320. copy(ret[pkA.Size():], n[:ptextLen])
  321. return ret, nil
  322. }
  323. // NewPrivateKey initializes private key.
  324. // Usage of this function guarantees that the object is correctly initialized.
  325. func NewPrivateKey(v KeyVariant) *PrivateKey {
  326. prv := &PrivateKey{key: key{params: &Params, keyVariant: v}}
  327. if (v & KeyVariant_SIDH_A) == KeyVariant_SIDH_A {
  328. prv.Scalar = make([]byte, prv.params.A.SecretByteLen)
  329. } else {
  330. prv.Scalar = make([]byte, prv.params.B.SecretByteLen)
  331. }
  332. if v == KeyVariant_SIKE {
  333. prv.S = make([]byte, prv.params.MsgLen)
  334. }
  335. return prv
  336. }
  337. // NewPublicKey initializes public key.
  338. // Usage of this function guarantees that the object is correctly initialized.
  339. func NewPublicKey(v KeyVariant) *PublicKey {
  340. return &PublicKey{key: key{params: &Params, keyVariant: v}}
  341. }
  342. // Import clears content of the public key currently stored in the structure
  343. // and imports key stored in the byte string. Returns error in case byte string
  344. // size is wrong. Doesn't perform any validation.
  345. func (pub *PublicKey) Import(input []byte) error {
  346. if len(input) != pub.Size() {
  347. return errors.New("sidh: input to short")
  348. }
  349. ssSz := pub.params.SharedSecretSize
  350. convBytesToFp2(&pub.affine_xP, input[0:ssSz])
  351. convBytesToFp2(&pub.affine_xQ, input[ssSz:2*ssSz])
  352. convBytesToFp2(&pub.affine_xQmP, input[2*ssSz:3*ssSz])
  353. return nil
  354. }
  355. // Exports currently stored key. In case structure hasn't been filled with key data
  356. // returned byte string is filled with zeros.
  357. func (pub *PublicKey) Export() []byte {
  358. output := make([]byte, pub.params.PublicKeySize)
  359. ssSz := pub.params.SharedSecretSize
  360. convFp2ToBytes(output[0:ssSz], &pub.affine_xP)
  361. convFp2ToBytes(output[ssSz:2*ssSz], &pub.affine_xQ)
  362. convFp2ToBytes(output[2*ssSz:3*ssSz], &pub.affine_xQmP)
  363. return output
  364. }
  365. // Size returns size of the public key in bytes
  366. func (pub *PublicKey) Size() int {
  367. return pub.params.PublicKeySize
  368. }
  369. // Exports currently stored key. In case structure hasn't been filled with key data
  370. // returned byte string is filled with zeros.
  371. func (prv *PrivateKey) Export() []byte {
  372. ret := make([]byte, len(prv.Scalar)+len(prv.S))
  373. copy(ret, prv.S)
  374. copy(ret[len(prv.S):], prv.Scalar)
  375. return ret
  376. }
  377. // Size returns size of the private key in bytes
  378. func (prv *PrivateKey) Size() int {
  379. tmp := len(prv.Scalar)
  380. if prv.keyVariant == KeyVariant_SIKE {
  381. tmp += int(prv.params.MsgLen)
  382. }
  383. return tmp
  384. }
  385. // Import clears content of the private key currently stored in the structure
  386. // and imports key from octet string. In case of SIKE, the random value 'S'
  387. // must be prepended to the value of actual private key (see SIKE spec for details).
  388. // Function doesn't import public key value to PrivateKey object.
  389. func (prv *PrivateKey) Import(input []byte) error {
  390. if len(input) != prv.Size() {
  391. return errors.New("sidh: input to short")
  392. }
  393. copy(prv.S, input[:len(prv.S)])
  394. copy(prv.Scalar, input[len(prv.S):])
  395. return nil
  396. }
  397. // Generates random private key for SIDH or SIKE. Generated value is
  398. // formed as little-endian integer from key-space <2^(e2-1)..2^e2 - 1>
  399. // for KeyVariant_A or <2^(s-1)..2^s - 1>, where s = floor(log_2(3^e3)),
  400. // for KeyVariant_B.
  401. //
  402. // Returns error in case user provided RNG fails.
  403. func (prv *PrivateKey) Generate(rand io.Reader) error {
  404. var err error
  405. var dp *DomainParams
  406. if (prv.keyVariant & KeyVariant_SIDH_A) == KeyVariant_SIDH_A {
  407. dp = &prv.params.A
  408. } else {
  409. dp = &prv.params.B
  410. }
  411. if prv.keyVariant == KeyVariant_SIKE && err == nil {
  412. _, err = io.ReadFull(rand, prv.S)
  413. }
  414. // Private key generation takes advantage of the fact that keyspace for secret
  415. // key is (0, 2^x - 1), for some possitivite value of 'x' (see SIKE, 1.3.8).
  416. // It means that all bytes in the secret key, but the last one, can take any
  417. // value between <0x00,0xFF>. Similarily for the last byte, but generation
  418. // needs to chop off some bits, to make sure generated value is an element of
  419. // a key-space.
  420. _, err = io.ReadFull(rand, prv.Scalar)
  421. if err != nil {
  422. return err
  423. }
  424. prv.Scalar[len(prv.Scalar)-1] &= (1 << (dp.SecretBitLen % 8)) - 1
  425. // Make sure scalar is SecretBitLen long. SIKE spec says that key
  426. // space starts from 0, but I'm not confortable with having low
  427. // value scalars used for private keys. It is still secrure as per
  428. // table 5.1 in [SIKE].
  429. prv.Scalar[len(prv.Scalar)-1] |= 1 << ((dp.SecretBitLen % 8) - 1)
  430. return err
  431. }
  432. // Generates public key.
  433. //
  434. // Constant time.
  435. func (prv *PrivateKey) GeneratePublicKey() *PublicKey {
  436. if (prv.keyVariant & KeyVariant_SIDH_A) == KeyVariant_SIDH_A {
  437. return publicKeyGenA(prv)
  438. }
  439. return publicKeyGenB(prv)
  440. }
  441. // Computes a shared secret which is a j-invariant. Function requires that pub has
  442. // different KeyVariant than prv. Length of returned output is 2*ceil(log_2 P)/8),
  443. // where P is a prime defining finite field.
  444. //
  445. // It's important to notice that each keypair must not be used more than once
  446. // to calculate shared secret.
  447. //
  448. // Function may return error. This happens only in case provided input is invalid.
  449. // Constant time for properly initialized private and public key.
  450. func DeriveSecret(prv *PrivateKey, pub *PublicKey) ([]byte, error) {
  451. if (pub == nil) || (prv == nil) {
  452. return nil, errors.New("sidh: invalid arguments")
  453. }
  454. if (pub.keyVariant == prv.keyVariant) || (pub.params.Id != prv.params.Id) {
  455. return nil, errors.New("sidh: public and private are incompatbile")
  456. }
  457. if (prv.keyVariant & KeyVariant_SIDH_A) == KeyVariant_SIDH_A {
  458. return deriveSecretA(prv, pub), nil
  459. } else {
  460. return deriveSecretB(prv, pub), nil
  461. }
  462. }
  463. // Uses SIKE public key to encrypt plaintext. Requires cryptographically secure PRNG
  464. // Returns ciphertext in case encryption succeeds. Returns error in case PRNG fails
  465. // or wrongly formated input was provided.
  466. func Encrypt(rng io.Reader, pub *PublicKey, ptext []byte) ([]byte, error) {
  467. var ptextLen = len(ptext)
  468. // c1 must be security level + 64 bits (see [SIKE] 1.4 and 4.3.3)
  469. if ptextLen != (pub.params.KemSize + 8) {
  470. return nil, errors.New("Unsupported message length")
  471. }
  472. skA := NewPrivateKey(KeyVariant_SIDH_A)
  473. err := skA.Generate(rng)
  474. if err != nil {
  475. return nil, err
  476. }
  477. pkA := skA.GeneratePublicKey()
  478. return encrypt(skA, pkA, pub, ptext)
  479. }
  480. // Uses SIKE private key to decrypt ciphertext. Returns plaintext in case
  481. // decryption succeeds or error in case unexptected input was provided.
  482. // Constant time
  483. func Decrypt(prv *PrivateKey, ctext []byte) ([]byte, error) {
  484. var n [40]byte // n can is max 320-bit (see 1.4 of [SIKE])
  485. var c1_len int
  486. var pk_len = prv.params.PublicKeySize
  487. if prv.keyVariant != KeyVariant_SIKE {
  488. return nil, errors.New("wrong key type")
  489. }
  490. // ctext is a concatenation of (pubkey_A || c1=ciphertext)
  491. // it must be security level + 64 bits (see [SIKE] 1.4 and 4.3.3)
  492. c1_len = len(ctext) - pk_len
  493. if c1_len != (int(prv.params.KemSize) + 8) {
  494. return nil, errors.New("wrong size of cipher text")
  495. }
  496. c0 := NewPublicKey(KeyVariant_SIDH_A)
  497. err := c0.Import(ctext[:pk_len])
  498. if err != nil {
  499. return nil, err
  500. }
  501. j, err := DeriveSecret(prv, c0)
  502. if err != nil {
  503. return nil, err
  504. }
  505. hashMac(n[:c1_len], j, F)
  506. for i, _ := range n[:c1_len] {
  507. n[i] ^= ctext[pk_len+i]
  508. }
  509. return n[:c1_len], nil
  510. }
  511. // Encapsulation receives the public key and generates SIKE ciphertext and shared secret.
  512. // The generated ciphertext is used for authentication.
  513. // The rng must be cryptographically secure PRNG.
  514. // Error is returned in case PRNG fails or wrongly formated input was provided.
  515. func Encapsulate(rng io.Reader, pub *PublicKey) (ctext []byte, secret []byte, err error) {
  516. // Buffer for random, secret message
  517. var ptext = make([]byte, pub.params.MsgLen)
  518. // r = G(ptext||pub)
  519. var r = make([]byte, pub.params.A.SecretByteLen)
  520. // Resulting shared secret
  521. secret = make([]byte, pub.params.KemSize)
  522. // Generate ephemeral value
  523. _, err = io.ReadFull(rng, ptext)
  524. if err != nil {
  525. return nil, nil, err
  526. }
  527. // must be big enough to store ptext+c0+c1
  528. var hmac_key = make([]byte, pub.Size()+2*Params.MsgLen)
  529. copy(hmac_key, ptext)
  530. copy(hmac_key[len(ptext):], pub.Export())
  531. hashMac(r, hmac_key[:len(ptext)+pub.Size()], G)
  532. // Ensure bitlength is not bigger then to 2^e2-1
  533. r[len(r)-1] &= (1 << (pub.params.A.SecretBitLen % 8)) - 1
  534. // (c0 || c1) = Enc(pkA, ptext; r)
  535. skA := NewPrivateKey(KeyVariant_SIDH_A)
  536. err = skA.Import(r)
  537. if err != nil {
  538. return nil, nil, err
  539. }
  540. pkA := skA.GeneratePublicKey()
  541. ctext, err = encrypt(skA, pkA, pub, ptext)
  542. if err != nil {
  543. return nil, nil, err
  544. }
  545. // K = H(ptext||(c0||c1))
  546. copy(hmac_key, ptext)
  547. copy(hmac_key[len(ptext):], ctext)
  548. hashMac(secret, hmac_key[:len(ptext)+len(ctext)], H)
  549. return ctext, secret, nil
  550. }
  551. // Decapsulate given the keypair and ciphertext as inputs, Decapsulate outputs a shared
  552. // secret if plaintext verifies correctly, otherwise function outputs random value.
  553. // Decapsulation may fail in case input is wrongly formated.
  554. // Constant time for properly initialized input.
  555. func Decapsulate(prv *PrivateKey, pub *PublicKey, ctext []byte) ([]byte, error) {
  556. var r = make([]byte, pub.params.A.SecretByteLen)
  557. // Resulting shared secret
  558. var secret = make([]byte, pub.params.KemSize)
  559. var skA = NewPrivateKey(KeyVariant_SIDH_A)
  560. m, err := Decrypt(prv, ctext)
  561. if err != nil {
  562. return nil, err
  563. }
  564. // r' = G(m'||pub)
  565. var hmac_key = make([]byte, pub.Size()+2*Params.MsgLen)
  566. copy(hmac_key, m)
  567. copy(hmac_key[len(m):], pub.Export())
  568. hashMac(r, hmac_key[:len(m)+pub.Size()], G)
  569. // Ensure bitlength is not bigger than 2^e2-1
  570. r[len(r)-1] &= (1 << (pub.params.A.SecretBitLen % 8)) - 1
  571. // Never fails
  572. skA.Import(r)
  573. // Never fails
  574. pkA := skA.GeneratePublicKey()
  575. c0 := pkA.Export()
  576. if subtle.ConstantTimeCompare(c0, ctext[:len(c0)]) == 1 {
  577. copy(hmac_key, m)
  578. } else {
  579. // S is chosen at random when generating a key and unknown to other party. It
  580. // may seem weird, but it's correct. It is important that S is unpredictable
  581. // to other party. Without this check, it is possible to recover a secret, by
  582. // providing series of invalid ciphertexts. It is also important that in case
  583. //
  584. // See more details in "On the security of supersingular isogeny cryptosystems"
  585. // (S. Galbraith, et al., 2016, ePrint #859).
  586. copy(hmac_key, prv.S)
  587. }
  588. copy(hmac_key[len(m):], ctext)
  589. hashMac(secret, hmac_key[:len(m)+len(ctext)], H)
  590. return secret, nil
  591. }