crystals-kyber-ts
Version:
KYBER is an IND-CCA2-secure key encapsulation mechanism (KEM).
297 lines • 13.9 kB
JavaScript
import { Buffer } from "buffer";
import { SHA3, SHAKE } from "sha3";
import { Utilities } from "../lib/utilities";
import { Indcpa } from "../lib/indcpa";
/**
* Abstract class for Kyber implementation
*/
export class KyberService {
/**
* Default constructor that is called by the implementing Kyber service
* @param paramsK
*/
constructor(paramsK) {
this.paramsK = paramsK;
this.indcpa = new Indcpa(this.paramsK);
}
/**
* Generate local Kyber Keys
*/
generateKyberKeys() {
// IND-CPA keypair
const indcpakeys = this.indcpa.indcpaKeyGen();
const pk = indcpakeys[0];
const sk = indcpakeys[1];
// FO transform to make IND-CCA2
// get hash of pk
const buffer1 = Buffer.from(pk);
const hash1 = new SHA3(256);
hash1.update(buffer1);
let pkh = hash1.digest();
// read 32 random values (0-255) into a 32 byte array
const rnd = Buffer.alloc(KyberService.paramsSymBytes);
for (let i = 0; i < KyberService.paramsSymBytes; i++) {
rnd[i] = Utilities.nextInt(256);
}
// concatenate to form IND-CCA2 private key: sk + pk + h(pk) + rnd
for (let i = 0; i < pk.length; i++) {
sk.push(pk[i]);
}
for (let i = 0; i < pkh.length; i++) {
sk.push(pkh[i]);
}
for (let i = 0; i < rnd.length; i++) {
sk.push(rnd[i]);
}
const keys = []; // 2
keys[0] = pk;
keys[1] = sk;
return keys;
}
/**
* Generate a shared secret and cipher text from the given
* public key
* @param publicKey
*/
encrypt(publicKey) {
// random 32 bytes
const m = Buffer.alloc(KyberService.paramsSymBytes);
for (let i = 0; i < KyberService.paramsSymBytes; i++) {
m[i] = Utilities.nextInt(256);
}
// hash m with SHA3-256
const buffer1 = Buffer.from(m);
const hash1 = new SHA3(256);
hash1.update(buffer1);
const mhBuf = hash1.digest();
const mh = [];
for (const val of mhBuf) {
mh.push(val);
}
// hash pk with SHA3-256
const buffer2 = Buffer.from(publicKey);
const hash2 = new SHA3(256);
hash2.update(buffer2);
let pkh = hash2.digest();
// hash mh and pkh with SHA3-512
const buffer3 = Buffer.from(mh);
const buffer4 = Buffer.from(pkh);
const hash3 = new SHA3(512);
hash3.update(buffer3).update(buffer4);
const kr = hash3.digest();
const kr1 = kr.slice(0, KyberService.paramsSymBytes);
const kr2Buf = kr.slice(KyberService.paramsSymBytes, kr.length);
const kr2 = [];
for (const num of kr2Buf) {
kr2.push(num);
}
// generate ciphertext c
const cipherText = this.indcpa.indcpaEncrypt(publicKey, mh, kr2);
// hash ciphertext with SHA3-256
const buffer5 = Buffer.from(cipherText);
const hash4 = new SHA3(256);
hash4.update(buffer5);
let ch = hash4.digest();
// hash kr1 and ch with SHAKE-256
const buffer6 = Buffer.from(kr1);
const buffer7 = Buffer.from(ch);
const hash5 = new SHAKE(256);
hash5.update(buffer6).update(buffer7);
const ssBuf = hash5.digest();
// output (c, ss)
const result = []; // 2
result[0] = cipherText;
const sharedSecret = [];
for (let i = 0; i < KyberService.paramsSymBytes; ++i) {
sharedSecret[i] = ssBuf[i];
}
result[1] = sharedSecret;
return result;
}
/**
* Decrypt the given cipher text to create the same shared secret with
* the local private key
* @param cipherText
* @param privateKey
*/
decrypt(cipherText, privateKey) {
// extract sk, pk, pkh and z
let startIndex = 0;
let endIndex = 0;
switch (this.paramsK) {
case 2:
endIndex = KyberService.paramsIndcpaSecretKeyBytesK512;
break;
case 3:
endIndex = KyberService.paramsIndcpaSecretKeyBytesK768;
break;
default:
endIndex = KyberService.paramsIndcpaSecretKeyBytesK1024;
}
const indcpaPrivateKey = privateKey.slice(startIndex, endIndex); // indcpa secret key
startIndex = endIndex;
switch (this.paramsK) {
case 2:
endIndex += KyberService.paramsIndcpaPublicKeyBytesK512;
break;
case 3:
endIndex += KyberService.paramsIndcpaPublicKeyBytesK768;
break;
default:
endIndex += KyberService.paramsIndcpaPublicKeyBytesK1024;
}
const indcpaPublicKey = privateKey.slice(startIndex, endIndex); // indcpa public key
startIndex = endIndex;
endIndex += KyberService.paramsSymBytes;
const pkh = privateKey.slice(startIndex, endIndex); // sha3-256 hash
startIndex = endIndex;
endIndex += KyberService.paramsSymBytes;
const z = privateKey.slice(startIndex, endIndex);
// IND-CPA decrypt
const m = this.indcpa.indcpaDecrypt(cipherText, indcpaPrivateKey);
// hash m and pkh with SHA3-512
const buffer1 = Buffer.from(m);
const buffer2 = Buffer.from(pkh);
const hash1 = new SHA3(512);
hash1.update(buffer1).update(buffer2);
const krBuf = hash1.digest();
const kr = [];
for (const num of krBuf) {
kr.push(num);
}
const kr1 = krBuf.slice(0, KyberService.paramsSymBytes);
const kr2Buf = krBuf.slice(KyberService.paramsSymBytes, kr.length);
const kr2 = [];
for (const num of kr2Buf) {
kr2.push(num);
}
// IND-CPA encrypt
const cmp = this.indcpa.indcpaEncrypt(indcpaPublicKey, m, kr2);
// compare c and cmp to verify the generated shared secret
const fail = Utilities.constantTimeCompare(cipherText, cmp);
// hash c with SHA3-256
const md = new SHA3(256);
md.update(Buffer.from(cipherText));
const krh = md.digest();
let kyberSKBytes = 0;
switch (this.paramsK) {
case 2:
kyberSKBytes = KyberService.Kyber512SKBytes;
break;
case 3:
kyberSKBytes = KyberService.Kyber768SKBytes;
break;
default:
kyberSKBytes = KyberService.Kyber1024SKBytes;
}
let index = privateKey.length - KyberService.paramsSymBytes;
for (let i = 0; i < KyberService.paramsSymBytes; i++) {
kr[i] = Utilities.intToByte((kr[i]) ^ ((fail & 0xFF) & ((kr[i]) ^ (privateKey[index]))));
index += 1;
}
const tempBuf = [];
let ctr = 0;
for (ctr = 0; ctr < kr.length; ++ctr) {
tempBuf[ctr] = kr[ctr];
}
let ctr2 = 0;
for (; ctr < krh.length; ++ctr) {
tempBuf[ctr] = krh[ctr2++];
}
const buffer3 = Buffer.from(cipherText);
const hash2 = new SHA3(256);
hash2.update(buffer3);
let ch = hash2.digest();
const buffer4 = Buffer.from(kr1);
const buffer5 = Buffer.from(ch);
const hash3 = new SHAKE(256);
hash3.update(buffer4).update(buffer5);
const ssBuf = hash3.digest();
const sharedSecret = [];
for (let i = 0; i < KyberService.paramsSymBytes; ++i) {
sharedSecret[i] = ssBuf[i];
}
return sharedSecret;
}
}
KyberService.nttZetas = [
2285, 2571, 2970, 1812, 1493, 1422, 287, 202, 3158, 622, 1577, 182, 962,
2127, 1855, 1468, 573, 2004, 264, 383, 2500, 1458, 1727, 3199, 2648, 1017,
732, 608, 1787, 411, 3124, 1758, 1223, 652, 2777, 1015, 2036, 1491, 3047,
1785, 516, 3321, 3009, 2663, 1711, 2167, 126, 1469, 2476, 3239, 3058, 830,
107, 1908, 3082, 2378, 2931, 961, 1821, 2604, 448, 2264, 677, 2054, 2226,
430, 555, 843, 2078, 871, 1550, 105, 422, 587, 177, 3094, 3038, 2869, 1574,
1653, 3083, 778, 1159, 3182, 2552, 1483, 2727, 1119, 1739, 644, 2457, 349,
418, 329, 3173, 3254, 817, 1097, 603, 610, 1322, 2044, 1864, 384, 2114, 3193,
1218, 1994, 2455, 220, 2142, 1670, 2144, 1799, 2051, 794, 1819, 2475, 2459,
478, 3221, 3021, 996, 991, 958, 1869, 1522, 1628
];
KyberService.nttZetasInv = [
1701, 1807, 1460, 2371, 2338, 2333, 308, 108, 2851, 870, 854, 1510, 2535,
1278, 1530, 1185, 1659, 1187, 3109, 874, 1335, 2111, 136, 1215, 2945, 1465,
1285, 2007, 2719, 2726, 2232, 2512, 75, 156, 3000, 2911, 2980, 872, 2685,
1590, 2210, 602, 1846, 777, 147, 2170, 2551, 246, 1676, 1755, 460, 291, 235,
3152, 2742, 2907, 3224, 1779, 2458, 1251, 2486, 2774, 2899, 1103, 1275, 2652,
1065, 2881, 725, 1508, 2368, 398, 951, 247, 1421, 3222, 2499, 271, 90, 853,
1860, 3203, 1162, 1618, 666, 320, 8, 2813, 1544, 282, 1838, 1293, 2314, 552,
2677, 2106, 1571, 205, 2918, 1542, 2721, 2597, 2312, 681, 130, 1602, 1871,
829, 2946, 3065, 1325, 2756, 1861, 1474, 1202, 2367, 3147, 1752, 2707, 171,
3127, 3042, 1907, 1836, 1517, 359, 758, 1441
];
KyberService.paramsN = 256;
KyberService.paramsQ = 3329;
KyberService.paramsQinv = 62209;
KyberService.paramsSymBytes = 32;
KyberService.paramsPolyBytes = 384;
KyberService.paramsETAK512 = 3;
KyberService.paramsETAK768K1024 = 2;
KyberService.paramsPolyvecBytesK512 = 2 * KyberService.paramsPolyBytes;
KyberService.paramsPolyvecBytesK768 = 3 * KyberService.paramsPolyBytes;
KyberService.paramsPolyvecBytesK1024 = 4 * KyberService.paramsPolyBytes;
KyberService.paramsPolyCompressedBytesK512 = 128;
KyberService.paramsPolyCompressedBytesK768 = 128;
KyberService.paramsPolyCompressedBytesK1024 = 160;
KyberService.paramsPolyvecCompressedBytesK512 = 2 * 320;
KyberService.paramsPolyvecCompressedBytesK768 = 3 * 320;
KyberService.paramsPolyvecCompressedBytesK1024 = 4 * 352;
KyberService.paramsIndcpaPublicKeyBytesK512 = KyberService.paramsPolyvecBytesK512 + KyberService.paramsSymBytes;
KyberService.paramsIndcpaPublicKeyBytesK768 = KyberService.paramsPolyvecBytesK768 + KyberService.paramsSymBytes;
KyberService.paramsIndcpaPublicKeyBytesK1024 = KyberService.paramsPolyvecBytesK1024 + KyberService.paramsSymBytes;
KyberService.paramsIndcpaSecretKeyBytesK512 = 2 * KyberService.paramsPolyBytes;
KyberService.paramsIndcpaSecretKeyBytesK768 = 3 * KyberService.paramsPolyBytes;
KyberService.paramsIndcpaSecretKeyBytesK1024 = 4 * KyberService.paramsPolyBytes;
// Kyber512SKBytes is a constant representing the byte length of private keys in Kyber-512
KyberService.Kyber512SKBytes = KyberService.paramsPolyvecBytesK512 + ((KyberService.paramsPolyvecBytesK512 + KyberService.paramsSymBytes) + 2 * KyberService.paramsSymBytes);
// Kyber768SKBytes is a constant representing the byte length of private keys in Kyber-768
KyberService.Kyber768SKBytes = KyberService.paramsPolyvecBytesK768 + ((KyberService.paramsPolyvecBytesK768 + KyberService.paramsSymBytes) + 2 * KyberService.paramsSymBytes);
// Kyber1024SKBytes is a constant representing the byte length of private keys in Kyber-1024
KyberService.Kyber1024SKBytes = KyberService.paramsPolyvecBytesK1024 + ((KyberService.paramsPolyvecBytesK1024 + KyberService.paramsSymBytes) + 2 * KyberService.paramsSymBytes);
// Kyber512PKBytes is a constant representing the byte length of public keys in Kyber-512
KyberService.Kyber512PKBytes = KyberService.paramsPolyvecBytesK512 + KyberService.paramsSymBytes;
// Kyber768PKBytes is a constant representing the byte length of public keys in Kyber-768
KyberService.Kyber768PKBytes = KyberService.paramsPolyvecBytesK768 + KyberService.paramsSymBytes;
// Kyber1024PKBytes is a constant representing the byte length of public keys in Kyber-1024
KyberService.Kyber1024PKBytes = KyberService.paramsPolyvecBytesK1024 + KyberService.paramsSymBytes;
// KyberEncoded512PKBytes is a constant representing the byte length of encoded public keys in Kyber-512
KyberService.KyberEncoded512PKBytes = 967;
// KyberEncoded768PKBytes is a constant representing the byte length of encoded public keys in Kyber-768
KyberService.KyberEncoded768PKBytes = 1351;
// KyberEncoded1024PKBytes is a constant representing the byte length of encoded public keys in Kyber-1024
KyberService.KyberEncoded1024PKBytes = 1735;
// Kyber512CTBytes is a constant representing the byte length of ciphertexts in Kyber-512
KyberService.Kyber512CTBytes = KyberService.paramsPolyvecCompressedBytesK512 + KyberService.paramsPolyCompressedBytesK512;
// Kyber768CTBytes is a constant representing the byte length of ciphertexts in Kyber-768
KyberService.Kyber768CTBytes = KyberService.paramsPolyvecCompressedBytesK768 + KyberService.paramsPolyCompressedBytesK768;
// Kyber1024CTBytes is a constant representing the byte length of ciphertexts in Kyber-1024
KyberService.Kyber1024CTBytes = KyberService.paramsPolyvecCompressedBytesK1024 + KyberService.paramsPolyCompressedBytesK1024;
// KyberEncoded512CTBytes is a constant representing the byte length of Encoded ciphertexts in Kyber-512
KyberService.KyberEncoded512CTBytes = 935;
// KyberEncoded768CTBytes is a constant representing the byte length of Encoded ciphertexts in Kyber-768
KyberService.KyberEncoded768CTBytes = 1255;
// KyberEncoded1024CTBytes is a constant representing the byte length of Encoded ciphertexts in Kyber-1024
KyberService.KyberEncoded1024CTBytes = 1735;
// KyberSSBytes is a constant representing the byte length of shared secrets in Kyber
KyberService.KyberSSBytes = 32;
// KyberEncodedSSBytes is a constant representing the byte length of encoded shared secrets in Kyber
KyberService.KyberEncodedSSBytes = 193;
//# sourceMappingURL=kyber.service.js.map