diff --git a/src/crypto/crypto.js b/src/crypto/crypto.js index 293ab2866..378a69e88 100644 --- a/src/crypto/crypto.js +++ b/src/crypto/crypto.js @@ -39,6 +39,8 @@ import OID from '../type/oid'; import { UnsupportedError } from '../packet/packet'; import ECDHXSymmetricKey from '../type/ecdh_x_symkey'; +export { isPostQuantumAlgo } from './public_key/post_quantum'; + /** * Encrypts data using specified algorithm and public key parameters. * See {@link https://tools.ietf.org/html/rfc4880#section-9.1|RFC 4880 9.1} for public key algorithms. @@ -98,7 +100,7 @@ export async function publicKeyEncrypt(keyAlgo, symmetricAlgo, publicParams, pri } case enums.publicKey.pqc_mlkem_x25519: { const { eccPublicKey, mlkemPublicKey } = publicParams; - const { eccCipherText, mlkemCipherText, wrappedKey } = await publicKey.postQuantum.kem.encrypt(keyAlgo, eccPublicKey, mlkemPublicKey, data); + const { eccCipherText, mlkemCipherText, wrappedKey } = await publicKey.postQuantum.mlkem.encrypt(keyAlgo, eccPublicKey, mlkemPublicKey, data); const C = ECDHXSymmetricKey.fromObject({ algorithm: symmetricAlgo, wrappedKey }); return { eccCipherText, mlkemCipherText, C }; } @@ -169,7 +171,7 @@ export async function publicKeyDecrypt(keyAlgo, publicKeyParams, privateKeyParam const { eccSecretKey, mlkemSecretKey } = privateKeyParams; const { eccPublicKey, mlkemPublicKey } = publicKeyParams; const { eccCipherText, mlkemCipherText, C } = sessionKeyParams; - return publicKey.postQuantum.kem.decrypt(keyAlgo, eccCipherText, mlkemCipherText, eccSecretKey, eccPublicKey, mlkemSecretKey, mlkemPublicKey, C.wrappedKey); + return publicKey.postQuantum.mlkem.decrypt(keyAlgo, eccCipherText, mlkemCipherText, eccSecretKey, eccPublicKey, mlkemSecretKey, mlkemPublicKey, C.wrappedKey); } default: throw new Error('Unknown public key encryption algorithm.'); @@ -252,6 +254,10 @@ export function parsePublicKeyParams(algo, bytes) { const mldsaPublicKey = util.readExactSubarray(bytes, read, read + 1952); read += mldsaPublicKey.length; return { read, publicParams: { eccPublicKey, mldsaPublicKey } }; } + case enums.publicKey.pqc_slhdsa_shake128s: { + const slhdsaPublicKey = util.readExactSubarray(bytes, read, read + 32); read += slhdsaPublicKey.length; + return { read, publicParams: { slhdsaPublicKey } }; + } default: throw new UnsupportedError('Unknown public key encryption algorithm.'); } @@ -326,15 +332,20 @@ export async function parsePrivateKeyParams(algo, bytes, publicParams) { case enums.publicKey.pqc_mlkem_x25519: { const eccSecretKey = util.readExactSubarray(bytes, read, read + getCurvePayloadSize(enums.publicKey.x25519)); read += eccSecretKey.length; const mlkemSeed = util.readExactSubarray(bytes, read, read + 64); read += mlkemSeed.length; - const { mlkemSecretKey } = await publicKey.postQuantum.kem.mlkemExpandSecretSeed(algo, mlkemSeed); + const { mlkemSecretKey } = await publicKey.postQuantum.mlkem.mlkemExpandSecretSeed(algo, mlkemSeed); return { read, privateParams: { eccSecretKey, mlkemSecretKey, mlkemSeed } }; } case enums.publicKey.pqc_mldsa_ed25519: { const eccSecretKey = util.readExactSubarray(bytes, read, read + getCurvePayloadSize(enums.publicKey.ed25519)); read += eccSecretKey.length; const mldsaSeed = util.readExactSubarray(bytes, read, read + 32); read += mldsaSeed.length; - const { mldsaSecretKey } = await publicKey.postQuantum.signature.mldsaExpandSecretSeed(algo, mldsaSeed); + const { mldsaSecretKey } = await publicKey.postQuantum.mldsa.mldsaExpandSecretSeed(algo, mldsaSeed); return { read, privateParams: { eccSecretKey, mldsaSecretKey, mldsaSeed } }; } + case enums.publicKey.pqc_slhdsa_shake128s: { + const slhdsaSecretKey = util.readExactSubarray(bytes, read, read + 64); read += slhdsaSecretKey.length; + + return { read, privateParams: { slhdsaSecretKey } }; + } default: throw new UnsupportedError('Unknown public key encryption algorithm.'); } @@ -425,7 +436,8 @@ export function serializeParams(algo, params) { enums.publicKey.aead, enums.publicKey.hmac, enums.publicKey.pqc_mlkem_x25519, - enums.publicKey.pqc_mldsa_ed25519 + enums.publicKey.pqc_mldsa_ed25519, + enums.publicKey.pqc_slhdsa_shake128s ]); const excludedFields = { @@ -503,15 +515,20 @@ export async function generateParams(algo, bits, oid, symmetric) { return createSymmetricParams(keyMaterial, new SymAlgoEnum(symmetric)); } case enums.publicKey.pqc_mlkem_x25519: - return publicKey.postQuantum.kem.generate(algo).then(({ eccSecretKey, eccPublicKey, mlkemSeed, mlkemSecretKey, mlkemPublicKey }) => ({ + return publicKey.postQuantum.mlkem.generate(algo).then(({ eccSecretKey, eccPublicKey, mlkemSeed, mlkemSecretKey, mlkemPublicKey }) => ({ privateParams: { eccSecretKey, mlkemSeed, mlkemSecretKey }, publicParams: { eccPublicKey, mlkemPublicKey } })); case enums.publicKey.pqc_mldsa_ed25519: - return publicKey.postQuantum.signature.generate(algo).then(({ eccSecretKey, eccPublicKey, mldsaSeed, mldsaSecretKey, mldsaPublicKey }) => ({ + return publicKey.postQuantum.mldsa.generate(algo).then(({ eccSecretKey, eccPublicKey, mldsaSeed, mldsaSecretKey, mldsaPublicKey }) => ({ privateParams: { eccSecretKey, mldsaSeed, mldsaSecretKey }, publicParams: { eccPublicKey, mldsaPublicKey } })); + case enums.publicKey.pqc_slhdsa_shake128s: + return publicKey.postQuantum.slhdsa.generate(algo).then(({ slhdsaSecretKey, slhdsaPublicKey }) => ({ + privateParams: { slhdsaSecretKey }, + publicParams: { slhdsaPublicKey } + })); case enums.publicKey.dsa: case enums.publicKey.elgamal: throw new Error('Unsupported algorithm for key generation.'); @@ -606,12 +623,17 @@ export async function validateParams(algo, publicParams, privateParams) { case enums.publicKey.pqc_mlkem_x25519: { const { eccSecretKey, mlkemSeed } = privateParams; const { eccPublicKey, mlkemPublicKey } = publicParams; - return publicKey.postQuantum.kem.validateParams(algo, eccPublicKey, eccSecretKey, mlkemPublicKey, mlkemSeed); + return publicKey.postQuantum.mlkem.validateParams(algo, eccPublicKey, eccSecretKey, mlkemPublicKey, mlkemSeed); } case enums.publicKey.pqc_mldsa_ed25519: { const { eccSecretKey, mldsaSeed } = privateParams; const { eccPublicKey, mldsaPublicKey } = publicParams; - return publicKey.postQuantum.signature.validateParams(algo, eccPublicKey, eccSecretKey, mldsaPublicKey, mldsaSeed); + return publicKey.postQuantum.mldsa.validateParams(algo, eccPublicKey, eccSecretKey, mldsaPublicKey, mldsaSeed); + } + case enums.publicKey.pqc_slhdsa_shake128s: { + const { slhdsaSecretKey } = privateParams; + const { slhdsaPublicKey } = publicParams; + return publicKey.postQuantum.slhdsa.validateParams(algo, slhdsaPublicKey, slhdsaSecretKey); } default: throw new Error('Unknown public key algorithm.'); diff --git a/src/crypto/public_key/post_quantum/index.js b/src/crypto/public_key/post_quantum/index.js index cf803ef88..6aa2b574d 100644 --- a/src/crypto/public_key/post_quantum/index.js +++ b/src/crypto/public_key/post_quantum/index.js @@ -1,7 +1,31 @@ -import * as kem from './kem/index'; -import * as signature from './signature'; +import * as mlkem from './ml_kem'; +import * as mldsa from './ml_dsa'; +import * as slhdsa from './slh_dsa'; +import enums from '../../../enums'; export { - kem, - signature + mlkem, + mldsa, + slhdsa }; + +const pqcAlgos = new Set([ + enums.publicKey.pqc_mldsa_ed25519, + enums.publicKey.pqc_mlkem_x25519, + enums.publicKey.pqc_slhdsa_shake128s +]); + +export function isPostQuantumAlgo(algo) { + return pqcAlgos.has(algo); +} + +export function getRequiredHashAlgo(signatureAlgo) { + switch (signatureAlgo) { + case enums.publicKey.pqc_mldsa_ed25519: + return mldsa.getRequiredHashAlgo(signatureAlgo); + case enums.publicKey.pqc_slhdsa_shake128s: + return slhdsa.getRequiredHashAlgo(signatureAlgo); + default: + throw new Error('Unsupported signature algorithm'); + } +} diff --git a/src/crypto/public_key/post_quantum/signature/signature.js b/src/crypto/public_key/post_quantum/ml_dsa/combiner.js similarity index 98% rename from src/crypto/public_key/post_quantum/signature/signature.js rename to src/crypto/public_key/post_quantum/ml_dsa/combiner.js index fcdfc745c..c5a378f05 100644 --- a/src/crypto/public_key/post_quantum/signature/signature.js +++ b/src/crypto/public_key/post_quantum/ml_dsa/combiner.js @@ -1,5 +1,5 @@ import enums from '../../../../enums'; -import * as mldsa from './ml_dsa'; +import * as mldsa from './ml_dsa_pure'; import * as eccdsa from './ecc_dsa'; export async function generate(algo) { diff --git a/src/crypto/public_key/post_quantum/signature/ecc_dsa.js b/src/crypto/public_key/post_quantum/ml_dsa/ecc_dsa.js similarity index 100% rename from src/crypto/public_key/post_quantum/signature/ecc_dsa.js rename to src/crypto/public_key/post_quantum/ml_dsa/ecc_dsa.js diff --git a/src/crypto/public_key/post_quantum/signature/index.js b/src/crypto/public_key/post_quantum/ml_dsa/index.js similarity index 77% rename from src/crypto/public_key/post_quantum/signature/index.js rename to src/crypto/public_key/post_quantum/ml_dsa/index.js index a1b1dc436..6fafb6936 100644 --- a/src/crypto/public_key/post_quantum/signature/index.js +++ b/src/crypto/public_key/post_quantum/ml_dsa/index.js @@ -1,2 +1,2 @@ -export { generate, sign, verify, validateParams, getRequiredHashAlgo } from './signature'; -export { expandSecretSeed as mldsaExpandSecretSeed } from './ml_dsa'; +export { generate, sign, verify, validateParams, getRequiredHashAlgo } from './combiner'; +export { expandSecretSeed as mldsaExpandSecretSeed } from './ml_dsa_pure'; diff --git a/src/crypto/public_key/post_quantum/signature/ml_dsa.js b/src/crypto/public_key/post_quantum/ml_dsa/ml_dsa_pure.js similarity index 100% rename from src/crypto/public_key/post_quantum/signature/ml_dsa.js rename to src/crypto/public_key/post_quantum/ml_dsa/ml_dsa_pure.js diff --git a/src/crypto/public_key/post_quantum/kem/ecc_kem.js b/src/crypto/public_key/post_quantum/ml_kem/ecc_kem.js similarity index 100% rename from src/crypto/public_key/post_quantum/kem/ecc_kem.js rename to src/crypto/public_key/post_quantum/ml_kem/ecc_kem.js diff --git a/src/crypto/public_key/post_quantum/kem/index.js b/src/crypto/public_key/post_quantum/ml_kem/index.js similarity index 84% rename from src/crypto/public_key/post_quantum/kem/index.js rename to src/crypto/public_key/post_quantum/ml_kem/index.js index 399750ad7..29c8ba96d 100644 --- a/src/crypto/public_key/post_quantum/kem/index.js +++ b/src/crypto/public_key/post_quantum/ml_kem/index.js @@ -1,2 +1,2 @@ -export { generate, encrypt, decrypt, validateParams } from './kem'; -export { expandSecretSeed as mlkemExpandSecretSeed } from './ml_kem'; +export { generate, encrypt, decrypt, validateParams } from './kem_combiner'; +export { expandSecretSeed as mlkemExpandSecretSeed } from './ml_kem_pure'; diff --git a/src/crypto/public_key/post_quantum/kem/kem.js b/src/crypto/public_key/post_quantum/ml_kem/kem_combiner.js similarity index 98% rename from src/crypto/public_key/post_quantum/kem/kem.js rename to src/crypto/public_key/post_quantum/ml_kem/kem_combiner.js index e26d5b269..e5bb94ccb 100644 --- a/src/crypto/public_key/post_quantum/kem/kem.js +++ b/src/crypto/public_key/post_quantum/ml_kem/kem_combiner.js @@ -1,5 +1,5 @@ import * as eccKem from './ecc_kem'; -import * as mlKem from './ml_kem'; +import * as mlKem from './ml_kem_pure'; import * as aesKW from '../../../aes_kw'; import util from '../../../../util'; import enums from '../../../../enums'; diff --git a/src/crypto/public_key/post_quantum/kem/ml_kem.js b/src/crypto/public_key/post_quantum/ml_kem/ml_kem_pure.js similarity index 100% rename from src/crypto/public_key/post_quantum/kem/ml_kem.js rename to src/crypto/public_key/post_quantum/ml_kem/ml_kem_pure.js diff --git a/src/crypto/public_key/post_quantum/noble_post_quantum.ts b/src/crypto/public_key/post_quantum/noble_post_quantum.ts index de77098ef..041030442 100644 --- a/src/crypto/public_key/post_quantum/noble_post_quantum.ts +++ b/src/crypto/public_key/post_quantum/noble_post_quantum.ts @@ -7,4 +7,3 @@ export { ml_kem768 } from '@noble/post-quantum/ml-kem'; export { ml_dsa65 } from '@noble/post-quantum/ml-dsa'; - diff --git a/src/crypto/public_key/post_quantum/slh_dsa/index.js b/src/crypto/public_key/post_quantum/slh_dsa/index.js new file mode 100644 index 000000000..517c26e7d --- /dev/null +++ b/src/crypto/public_key/post_quantum/slh_dsa/index.js @@ -0,0 +1,75 @@ +import enums from '../../../../enums'; +import { getRandomBytes } from '../../../random'; + + +export async function generate(algo) { + switch (algo) { + case enums.publicKey.pqc_slhdsa_shake128s: { + const { slh_dsa_shake_128s } = await import('@noble/post-quantum/slh-dsa'); + const { secretKey: slhdsaSecretKey, publicKey: slhdsaPublicKey } = slh_dsa_shake_128s.keygen(); + + return { slhdsaSecretKey, slhdsaPublicKey }; + } + default: + throw new Error('Unsupported signature algorithm'); + } +} + +export async function sign(signatureAlgo, hashAlgo, slhdsaSecretKey, dataDigest) { + if (hashAlgo !== getRequiredHashAlgo(signatureAlgo)) { + // The signature hash algo MUST be set to the specified algorithm, see + // https://www.ietf.org/archive/id/draft-ietf-openpgp-pqc-06.html#section-6.1.1 + throw new Error('Unexpected hash algorithm for PQC signature'); + } + + switch (signatureAlgo) { + case enums.publicKey.pqc_slhdsa_shake128s: { + const { slh_dsa_shake_128s } = await import('@noble/post-quantum/slh-dsa'); + const slhdsaSignature = slh_dsa_shake_128s.sign(slhdsaSecretKey, dataDigest); + return { slhdsaSignature }; + } + default: + throw new Error('Unsupported signature algorithm'); + } +} + +export async function verify(signatureAlgo, hashAlgo, slhdsaPublicKey, dataDigest, { slhdsaSignature }) { + if (hashAlgo !== getRequiredHashAlgo(signatureAlgo)) { + // The signature hash algo MUST be set to the specified algorithm, see + // https://www.ietf.org/archive/id/draft-ietf-openpgp-pqc-06.html#section-6.1.1 + throw new Error('Unexpected hash algorithm for PQC signature'); + } + + switch (signatureAlgo) { + case enums.publicKey.pqc_slhdsa_shake128s: { + const { slh_dsa_shake_128s } = await import('@noble/post-quantum/slh-dsa'); + return slh_dsa_shake_128s.verify(slhdsaPublicKey, dataDigest, slhdsaSignature); + } + default: + throw new Error('Unsupported signature algorithm'); + } +} + +export async function validateParams(algo, slhdsaPublicKey, slhdsaSecretKey) { + switch (algo) { + case enums.publicKey.pqc_slhdsa_shake128s: { + // TODO check if more performant validation is possible via public key re-derivation + const randomBytes = getRandomBytes(16); + const { slhdsaSignature } = await sign(algo, slhdsaSecretKey, randomBytes); + const trialSignatureVerified = await verify(algo, slhdsaPublicKey, randomBytes, slhdsaSignature); + return trialSignatureVerified; + } + default: + throw new Error('Unsupported signature algorithm'); + } +} + +export function getRequiredHashAlgo(signatureAlgo) { + // See https://www.ietf.org/archive/id/draft-ietf-openpgp-pqc-06.html#section-6.1.1 + switch (signatureAlgo) { + case enums.publicKey.pqc_slhdsa_shake128s: + return enums.hash.sha3_256; + default: + throw new Error('Unsupported signature algorithm'); + } +} diff --git a/src/crypto/signature.js b/src/crypto/signature.js index 9b7d6a89f..203c6657a 100644 --- a/src/crypto/signature.js +++ b/src/crypto/signature.js @@ -76,6 +76,10 @@ export function parseSignatureParams(algo, signature) { const mldsaSignature = util.readExactSubarray(signature, read, read + 3309); read += mldsaSignature.length; return { read, signatureParams: { eccSignature, mldsaSignature } }; } + case enums.publicKey.pqc_slhdsa_shake128s: { + const slhdsaSignature = util.readExactSubarray(signature, read, read + 7856); read += slhdsaSignature.length; + return { read, signatureParams: { slhdsaSignature } }; + } default: throw new UnsupportedError('Unknown signature algorithm.'); } @@ -142,7 +146,11 @@ export async function verify(algo, hashAlgo, signature, publicParams, privatePar } case enums.publicKey.pqc_mldsa_ed25519: { const { eccPublicKey, mldsaPublicKey } = publicParams; - return publicKey.postQuantum.signature.verify(algo, hashAlgo, eccPublicKey, mldsaPublicKey, hashed, signature); + return publicKey.postQuantum.mldsa.verify(algo, hashAlgo, eccPublicKey, mldsaPublicKey, hashed, signature); + } + case enums.publicKey.pqc_slhdsa_shake128s: { + const { slhdsaPublicKey } = publicParams; + return publicKey.postQuantum.slhdsa.verify(algo, hashAlgo, slhdsaPublicKey, hashed, signature); } default: throw new Error('Unknown signature algorithm.'); @@ -208,7 +216,11 @@ export async function sign(algo, hashAlgo, publicKeyParams, privateKeyParams, da case enums.publicKey.pqc_mldsa_ed25519: { const { eccPublicKey } = publicKeyParams; const { eccSecretKey, mldsaSecretKey } = privateKeyParams; - return publicKey.postQuantum.signature.sign(algo, hashAlgo, eccSecretKey, eccPublicKey, mldsaSecretKey, hashed); + return publicKey.postQuantum.mldsa.sign(algo, hashAlgo, eccSecretKey, eccPublicKey, mldsaSecretKey, hashed); + } + case enums.publicKey.pqc_slhdsa_shake128s: { + const { slhdsaSecretKey } = privateKeyParams; + return publicKey.postQuantum.slhdsa.sign(algo, hashAlgo, slhdsaSecretKey, hashed); } default: throw new Error('Unknown signature algorithm.'); diff --git a/src/enums.js b/src/enums.js index 2d842b77d..1f6d82e00 100644 --- a/src/enums.js +++ b/src/enums.js @@ -112,7 +112,8 @@ export default { pqc_mlkem_x25519: 105, /** Post-quantum ML-DSA-64 + Ed25519 (Sign only) */ pqc_mldsa_ed25519: 107, - + /** Post-quantum SLH-DSA-128S (Sign only) */ + pqc_slhdsa_shake128s: 109, /** Persistent symmetric keys: encryption algorithm */ aead: 100, /** Persistent symmetric keys: authentication algorithm */ diff --git a/src/key/helper.js b/src/key/helper.js index 6db537582..d12364c19 100644 --- a/src/key/helper.js +++ b/src/key/helper.js @@ -117,10 +117,10 @@ export async function createBindingSignature(subkey, primaryKey, options, config * @async */ export async function getPreferredHashAlgo(targetKeys, signingKeyPacket, date = new Date(), targetUserIDs = [], config) { - if (signingKeyPacket.algorithm === enums.publicKey.pqc_mldsa_ed25519) { - // For PQC, the returned hash algo MUST be set to the specified algorithm, see - // https://datatracker.ietf.org/doc/html/draft-ietf-openpgp-pqc#section-5.2.1. - return crypto.publicKey.postQuantum.signature.getRequiredHashAlgo(signingKeyPacket.algorithm); + // For PQC, the returned hash algo MUST be set to the specified algorithm, see + // https://datatracker.ietf.org/doc/html/draft-ietf-openpgp-pqc#section-5.2.1. + if (crypto.isPostQuantumAlgo(signingKeyPacket.algorithm)) { + return crypto.publicKey.postQuantum.getRequiredHashAlgo(signingKeyPacket.algorithm); } /** @@ -475,6 +475,7 @@ export function validateSigningKeyPacket(keyPacket, signature, config) { case enums.publicKey.ed448: case enums.publicKey.hmac: case enums.publicKey.pqc_mldsa_ed25519: + case enums.publicKey.pqc_slhdsa_shake128s: if (!signature.keyFlags && !config.allowMissingKeyFlags) { throw new Error('None of the key flags is set: consider passing `config.allowMissingKeyFlags`'); } diff --git a/src/packet/public_key.js b/src/packet/public_key.js index 09e2fe45a..5855d09ac 100644 --- a/src/packet/public_key.js +++ b/src/packet/public_key.js @@ -140,11 +140,8 @@ class PublicKeyPacket { } // The composite ML-DSA + EdDSA schemes MUST be used only with v6 keys. // The composite ML-KEM + ECDH schemes MUST be used only with v6 keys. - if (this.version !== 6 && ( - this.algorithm === enums.publicKey.pqc_mldsa_ed25519 || - this.algorithm === enums.publicKey.pqc_mlkem_x25519 - )) { - throw new Error('Unexpected key version: ML-DSA and ML-KEM algorithms can only be used with v6 keys'); + if (this.version !== 6 && crypto.isPostQuantumAlgo(this.algorithm)) { + throw new Error('Unexpected key version: post-quantum algorithms can only be used with v6 keys'); } this.publicParams = publicParams; pos += read; diff --git a/src/packet/secret_key.js b/src/packet/secret_key.js index e94e00a62..d50c07e6f 100644 --- a/src/packet/secret_key.js +++ b/src/packet/secret_key.js @@ -532,10 +532,7 @@ class SecretKeyPacket extends PublicKeyPacket { )) { throw new Error(`Cannot generate v6 keys of type 'ecc' with curve ${curve}. Generate a key of type 'curve25519' instead`); } - if (this.version !== 6 && ( - this.algorithm === enums.publicKey.pqc_mldsa_ed25519 || - this.algorithm === enums.publicKey.pqc_mlkem_x25519 - )) { + if (this.version !== 6 && crypto.isPostQuantumAlgo(this.algorithm)) { throw new Error(`Cannot generate v${this.version} keys of type 'pqc'. Generate a v6 key instead`); } const { privateParams, publicParams } = await crypto.generateParams(this.algorithm, bits, curve, symmetric); diff --git a/test/crypto/postQuantum.js b/test/crypto/postQuantum.js index 9614cd450..42e1d086e 100644 --- a/test/crypto/postQuantum.js +++ b/test/crypto/postQuantum.js @@ -589,6 +589,727 @@ WmFbdK/B+gwukZuv6/ADssjK6jFXXnCtvOghLjtOVKDo/QsSLzhDpNsAAAAAAAAA AAAAAAAAAAAABQwRGCAn -----END PGP PUBLIC KEY BLOCK-----`; +const slhdsaPrivateKey = `-----BEGIN PGP PRIVATE KEY BLOCK----- + +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 +GXjAz110OD7IrJykydmxG+WiVkeP7RdkMCXM5OGNJ/4aXGuTyLCMRjk4gSp6 +V+jYMc28I5EDWfTQagLFeF8d3VTpR38eZxrvj9/jbVc46wXW2ZfCVbj9l2C8 +bybOKpmtNJEFxA+Ya2AcCKtqRyFHfeDD3fNMgtn/PbP7MeOcEVEaBrl7YQQN +V/fx7tskWXF1/xmZVhYmNOrNf854GW3OunSUV8FgMyRGq4dS5W79cGhQBQ23 +sPsZj6Tof88zDbesv8+E4dqPnFlynn4BF9CIB+GJk6v9tSsNsipgGlxSNw4k +wN7Ar0kpRhnbNMk7BGj/IIAbavzMa7rEcHxKeJnCaS6YDjzr8n5WJYC5/7j9 +gvaVNbL61eZ4rEVrE1l4am1uxARHaN+UjrndnzAztyAOHzukTnAnhpRoq2x4 +eHffMeoTIc7xWIGgxg0MENyAas0FR7npxwtU7PaEkLV4NYEK1sTQ5LfccVUV +PXPgkqVVqFMlYPTpJ3zXSe4VewWmqrx7AWjPMNCyW6Va3O3Lq/oUz/5jDfGv +y7EHITH9Oe0avRDyoqfv8Waj4ps1Yb2eGgDDDCnbqlbpXKlBp6WIoIy+2Fs9 +EcYbhCt9vuYknFyD8WN4+xpbc0lPODocRoQqmmhfYedPJ6K5+nmzYRHf2Mn7 +wAp4DFB9O+zc6QFmztc5wab/PB7oIE5BL3fe5nxmne6iIPQhJVD4m/Bo6Qhb ++Guh3LhM9N2dwZnEEpwaT1P27LUuersi53ktc1mac2djj+E13JQCoex/83wa +qowIYHfkFO87dY3wR7ZmYRCUb+72Kq6AGVx3WGDk2IgGmEC4b9DeUxU2ipQl +Skn9+oI18lxjG0gMSgwYeqo80+JDF9dyheztuUUyeP1ArQKDzFnDj/K0WcDg +ELrYi0gp1lTCc5WeBH0/9O35SvJybfqRp/hQHl79vzlbHissGRidyS5doxKu +OyTwypC26m0Sr/O020/v/h3QsITFP5dShRLduE8tV3C/SrtUuvGjqWgQAHbR +kYKlU+YLBa3Dj+LqgeUwW/u2Hj5aiEBUq8zg7TAverEHQ+csbDLyHlLbSDPd +whWaNjAONWzmSUEehjnn6ujQORdtpqLDBqpfTQBbShXZBMMpE4h8G5rbPFLM +sxrNpSx42F6qkVaVULsiEaTbIBYVnrbdK258HKpg2Qydzti1lx4N16unTxIh +T45cEAJK5Jg0OkEihHQEMhzok5WWsKbQs7hyhw6CJv7xpSO7Sh6pvB3Y1Djg +qwBbad3i7yRO9RI2cYnUzjzsstcqj5JPcbL78blZJ4Jv6e9ewMT74JG3bV02 +7Y+XXJm/QpW2mXxdvnC5iu2tQaKPju5JYPa/qyF00/r45994Foi+hcAEyK5O +Tl7ic9aPNHlD57EKuHdMRxvihqJvt+IoHlNJ6EvD71wUpDTyh9nRgSMS7MrM +1gC0MhO4cO2biYLMePGUpmLyK4p9ajKtTqqIZFfL7eJVTHiJEmumW5vJIoYw +GoPOj8mz8as11N2ny50Ys4pv7qhNfkEsGqHI9iiBjojXiiG4Cyi8hVGgnmfT +cWd3pEpUuiQMWBKokikyM/gYk90i01QY7caO95/zWcfKT7uBQime0krKeUaD +LY5p1KmSY/wj7acbs8PYJuW7kFQOKmP33kMEcmJ4VO1rc8F5jarBICCut56L ++H95aBsnt7ObJ5rdZMfgvfnD6sRVV7mLsXqQ4OSYhQsDPqjXgE/rlnGGjiHM +anDBIZPOFBUIlK+mmIvXahyKE6nflbRe4gcNFq5AtFz5E3yMvVKJ42eKck21 +EJwlIDlxOkc9/t8hUngoY3V41sU/Y535FkcBxc3oN9LRnAU8DN7WNIBlAlPB +edOw+lU8HZRlsOuHRQLQ2eboJSR+T890GoaIH/NgPWR9f22E3nm2qcFTd6RV +FMhyLj/uhUlFCdKxlF0aLeyMa40rO/U4yUXcMpnNMTRw7soungOjvy7Frhfb +m9ry4yST5pCNNzsgvCpJmc8hhCfFyNzp6KqBbBamz0hLMcgBQ5kZlOLcbPIM +jbOZ0iVrRojMjhwSD+WNxJNo70cCz96GOnhoXEcMJyxIDKm5s4oR/hqgoDmi +53MgZKWc8qWo8pVy7iqwRRamaXB9DLvovo+PWlSxm91i66JgcoaAyAlnY/U+ +W7aE +-----END PGP PRIVATE KEY BLOCK-----`; + +const slhdsaPublicKey = `-----BEGIN PGP PUBLIC KEY BLOCK----- + +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 +fQy76L6Pj1pUsZvdYuuiYHKGgMgJZ2P1Plu2hA== +-----END PGP PUBLIC KEY BLOCK-----`; + + export default () => describe('PQC', function () { it('ML-KEM + X25519 - Generate/encrypt/decrypt', async function () { const sessionKey = { data: new Uint8Array(16).fill(1), algorithm: 'aes128' }; @@ -1206,4 +1927,32 @@ jXoyrGhDDakI/1XygauU5DpNuhgApoA= expect(data).to.equal(plaintext); await expect(verified).to.eventually.be.true; }); + + // TODO key generation & signing test skipped for now as it's too slow + it.skip('SLH-DSA - generate/sign/verify', async function () { + const digest = new Uint8Array(32).fill(1); + const hashAlgo = openpgp.enums.hash.sha3_256; + + // TODO: key generation test skipped for now as it's too slow + const { privateParams, publicParams } = await generateParams(openpgp.enums.publicKey.pqc_slhdsa_shake256s); + const signature = await sign(openpgp.enums.publicKey.pqc_slhdsa_shake128s, hashAlgo, publicParams, privateParams, null, digest); + const verified = await verify(openpgp.enums.publicKey.pqc_slhdsa_shake128s, hashAlgo, signature, publicParams, null, null, digest); + expect(verified).to.be.true; + + // test that unexpected hash algo is rejected both on signing and verification + const unexpectedHashAlgo = openpgp.enums.hash.sha256; + await expect(sign(openpgp.enums.publicKey.pqc_slhdsa_shake128s, unexpectedHashAlgo, publicParams, privateParams, null, digest)).to.be.rejectedWith(/Unexpected hash algorithm for PQC signature/); + await expect(verify(openpgp.enums.publicKey.pqc_slhdsa_shake128s, hashAlgo, signature, publicParams, null, null, digest)).to.be.rejectedWith(/Unexpected hash algorithm for PQC signature/); + }); + + it('SLH-DSA - Test vector', async function () { + const privateKey = await openpgp.readKey({ armoredKey: slhdsaPrivateKey }); + const publicKey = await openpgp.readKey({ armoredKey: slhdsaPublicKey }); + + // `getSigningKey()` internally verifies the ML-DSA binding sigs + const signingKey1 = await privateKey.getSigningKey(); + const signingKey2 = await publicKey.getSigningKey(); + + expect(signingKey1.getKeyID().equals(signingKey2.getKeyID())).to.be.true; + }); });