Non puoi selezionare più di 25 argomenti Gli argomenti devono iniziare con una lettera o un numero, possono includere trattini ('-') e possono essere lunghi fino a 35 caratteri.

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