25'ten fazla konu seçemezsiniz Konular bir harf veya rakamla başlamalı, kısa çizgiler ('-') içerebilir ve en fazla 35 karakter uzunluğunda olabilir.

740 satır
22 KiB

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