forked from openpgpjs/openpgpjs
-
Notifications
You must be signed in to change notification settings - Fork 8
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
PQC: Implement draft RFC for ML-DSA with Ed25519 (#13)
Implements Draft 6 (https://datatracker.ietf.org/doc/draft-ietf-openpgp-pqc/06/)
- Loading branch information
Showing
16 changed files
with
1,314 additions
and
25 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,7 @@ | ||
import * as kem from './kem/index'; | ||
import * as signature from './signature'; | ||
|
||
export { | ||
kem | ||
kem, | ||
signature | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
import * as eddsa from '../../elliptic/eddsa'; | ||
import enums from '../../../../enums'; | ||
|
||
export async function generate(algo) { | ||
switch (algo) { | ||
case enums.publicKey.pqc_mldsa_ed25519: { | ||
const { A, seed } = await eddsa.generate(enums.publicKey.ed25519); | ||
return { | ||
eccPublicKey: A, | ||
eccSecretKey: seed | ||
}; | ||
} | ||
default: | ||
throw new Error('Unsupported signature algorithm'); | ||
} | ||
} | ||
|
||
export async function sign(signatureAlgo, hashAlgo, eccSecretKey, eccPublicKey, dataDigest) { | ||
switch (signatureAlgo) { | ||
case enums.publicKey.pqc_mldsa_ed25519: { | ||
const { RS: eccSignature } = await eddsa.sign(enums.publicKey.ed25519, hashAlgo, null, eccPublicKey, eccSecretKey, dataDigest); | ||
|
||
return { eccSignature }; | ||
} | ||
default: | ||
throw new Error('Unsupported signature algorithm'); | ||
} | ||
} | ||
|
||
export async function verify(signatureAlgo, hashAlgo, eccPublicKey, dataDigest, eccSignature) { | ||
switch (signatureAlgo) { | ||
case enums.publicKey.pqc_mldsa_ed25519: | ||
return eddsa.verify(enums.publicKey.ed25519, hashAlgo, { RS: eccSignature }, null, eccPublicKey, dataDigest); | ||
default: | ||
throw new Error('Unsupported signature algorithm'); | ||
} | ||
} | ||
|
||
export async function validateParams(algo, eccPublicKey, eccSecretKey) { | ||
switch (algo) { | ||
case enums.publicKey.pqc_mldsa_ed25519: | ||
return eddsa.validateParams(enums.publicKey.ed25519, eccPublicKey, eccSecretKey); | ||
default: | ||
throw new Error('Unsupported signature algorithm'); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
export { generate, sign, verify, validateParams, getRequiredHashAlgo } from './signature'; | ||
export { expandSecretSeed as mldsaExpandSecretSeed } from './ml_dsa'; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,69 @@ | ||
import enums from '../../../../enums'; | ||
import util from '../../../../util'; | ||
import { getRandomBytes } from '../../../random'; | ||
|
||
export async function generate(algo) { | ||
switch (algo) { | ||
case enums.publicKey.pqc_mldsa_ed25519: { | ||
const mldsaSeed = getRandomBytes(32); | ||
const { mldsaSecretKey, mldsaPublicKey } = await expandSecretSeed(algo, mldsaSeed); | ||
|
||
return { mldsaSeed, mldsaSecretKey, mldsaPublicKey }; | ||
} | ||
default: | ||
throw new Error('Unsupported signature algorithm'); | ||
} | ||
} | ||
|
||
/** | ||
* Expand ML-DSA secret seed and retrieve the secret and public key material | ||
* @param {module:enums.publicKey} algo - Public key algorithm | ||
* @param {Uint8Array} seed - secret seed to expand | ||
* @returns {Promise<{ mldsaPublicKey: Uint8Array, mldsaSecretKey: Uint8Array }>} | ||
*/ | ||
export async function expandSecretSeed(algo, seed) { | ||
switch (algo) { | ||
case enums.publicKey.pqc_mldsa_ed25519: { | ||
const { ml_dsa65 } = await import('@noble/post-quantum/ml-dsa'); | ||
const { secretKey: mldsaSecretKey, publicKey: mldsaPublicKey } = ml_dsa65.keygen(seed); | ||
|
||
return { mldsaSecretKey, mldsaPublicKey }; | ||
} | ||
default: | ||
throw new Error('Unsupported signature algorithm'); | ||
} | ||
} | ||
|
||
export async function sign(algo, mldsaSecretKey, dataDigest) { | ||
switch (algo) { | ||
case enums.publicKey.pqc_mldsa_ed25519: { | ||
const { ml_dsa65 } = await import('@noble/post-quantum/ml-dsa'); | ||
const mldsaSignature = ml_dsa65.sign(mldsaSecretKey, dataDigest); | ||
return { mldsaSignature }; | ||
} | ||
default: | ||
throw new Error('Unsupported signature algorithm'); | ||
} | ||
} | ||
|
||
export async function verify(algo, mldsaPublicKey, dataDigest, mldsaSignature) { | ||
switch (algo) { | ||
case enums.publicKey.pqc_mldsa_ed25519: { | ||
const { ml_dsa65 } = await import('@noble/post-quantum/ml-dsa'); | ||
return ml_dsa65.verify(mldsaPublicKey, dataDigest, mldsaSignature); | ||
} | ||
default: | ||
throw new Error('Unsupported signature algorithm'); | ||
} | ||
} | ||
|
||
export async function validateParams(algo, mldsaPublicKey, mldsaSeed) { | ||
switch (algo) { | ||
case enums.publicKey.pqc_mldsa_ed25519: { | ||
const { mldsaPublicKey: expectedPublicKey } = await expandSecretSeed(algo, mldsaSeed); | ||
return util.equalsUint8Array(mldsaPublicKey, expectedPublicKey); | ||
} | ||
default: | ||
throw new Error('Unsupported signature algorithm'); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,70 @@ | ||
import enums from '../../../../enums'; | ||
import * as mldsa from './ml_dsa'; | ||
import * as eccdsa from './ecc_dsa'; | ||
|
||
export async function generate(algo) { | ||
switch (algo) { | ||
case enums.publicKey.pqc_mldsa_ed25519: { | ||
const { eccSecretKey, eccPublicKey } = await eccdsa.generate(algo); | ||
const { mldsaSeed, mldsaSecretKey, mldsaPublicKey } = await mldsa.generate(algo); | ||
return { eccSecretKey, eccPublicKey, mldsaSeed, mldsaSecretKey, mldsaPublicKey }; | ||
} | ||
default: | ||
throw new Error('Unsupported signature algorithm'); | ||
} | ||
} | ||
|
||
export async function sign(signatureAlgo, hashAlgo, eccSecretKey, eccPublicKey, mldsaSecretKey, dataDigest) { | ||
if (hashAlgo !== getRequiredHashAlgo(signatureAlgo)) { | ||
// The signature hash algo MUST be set to the specified algorithm, see | ||
// https://datatracker.ietf.org/doc/html/draft-ietf-openpgp-pqc#section-5.2.1. | ||
throw new Error('Unexpected hash algorithm for PQC signature'); | ||
} | ||
|
||
switch (signatureAlgo) { | ||
case enums.publicKey.pqc_mldsa_ed25519: { | ||
const { eccSignature } = await eccdsa.sign(signatureAlgo, hashAlgo, eccSecretKey, eccPublicKey, dataDigest); | ||
const { mldsaSignature } = await mldsa.sign(signatureAlgo, mldsaSecretKey, dataDigest); | ||
|
||
return { eccSignature, mldsaSignature }; | ||
} | ||
default: | ||
throw new Error('Unsupported signature algorithm'); | ||
} | ||
} | ||
|
||
export async function verify(signatureAlgo, hashAlgo, eccPublicKey, mldsaPublicKey, dataDigest, { eccSignature, mldsaSignature }) { | ||
if (hashAlgo !== getRequiredHashAlgo(signatureAlgo)) { | ||
// The signature hash algo MUST be set to the specified algorithm, see | ||
// https://datatracker.ietf.org/doc/html/draft-ietf-openpgp-pqc#section-5.2.1. | ||
throw new Error('Unexpected hash algorithm for PQC signature'); | ||
} | ||
|
||
switch (signatureAlgo) { | ||
case enums.publicKey.pqc_mldsa_ed25519: { | ||
const eccVerifiedPromise = eccdsa.verify(signatureAlgo, hashAlgo, eccPublicKey, dataDigest, eccSignature); | ||
const mldsaVerifiedPromise = mldsa.verify(signatureAlgo, mldsaPublicKey, dataDigest, mldsaSignature); | ||
const verified = await eccVerifiedPromise && await mldsaVerifiedPromise; | ||
return verified; | ||
} | ||
default: | ||
throw new Error('Unsupported signature algorithm'); | ||
} | ||
} | ||
|
||
export function getRequiredHashAlgo(signatureAlgo) { | ||
// See https://datatracker.ietf.org/doc/html/draft-ietf-openpgp-pqc#section-5.2.1. | ||
switch (signatureAlgo) { | ||
case enums.publicKey.pqc_mldsa_ed25519: | ||
return enums.hash.sha3_256; | ||
default: | ||
throw new Error('Unsupported signature algorithm'); | ||
} | ||
} | ||
|
||
export async function validateParams(algo, eccPublicKey, eccSecretKey, mldsaPublicKey, mldsaSeed) { | ||
const eccValidationPromise = eccdsa.validateParams(algo, eccPublicKey, eccSecretKey); | ||
const mldsaValidationPromise = mldsa.validateParams(algo, mldsaPublicKey, mldsaSeed); | ||
const valid = await eccValidationPromise && await mldsaValidationPromise; | ||
return valid; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.