Skip to content

Commit

Permalink
WIP: add ML-DSA + Ed25519 (Node only)
Browse files Browse the repository at this point in the history
Dilithium lib uses Buffer and doesn't work with browser
  • Loading branch information
larabr committed Nov 3, 2023
1 parent 0b8d674 commit ffb47e2
Show file tree
Hide file tree
Showing 11 changed files with 326 additions and 5 deletions.
142 changes: 142 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@
"postversion": "git push && git push --tags && npm publish"
},
"devDependencies": {
"@asanrom/dilithium": "^1.1.0",
"@openpgp/asmcrypto.js": "^3.0.0",
"@openpgp/jsdoc": "^3.6.11",
"@openpgp/noble-curves": "^1.2.1-0",
Expand Down
21 changes: 20 additions & 1 deletion src/crypto/crypto.js
Original file line number Diff line number Diff line change
Expand Up @@ -243,6 +243,11 @@ export function parsePublicKeyParams(algo, bytes) {
const mlkemPublicKey = util.readExactSubarray(bytes, read, read + 1184); read += mlkemPublicKey.length;
return { read, publicParams: { eccPublicKey, mlkemPublicKey } };
}
case enums.publicKey.pqc_mldsa_ed25519: {
const eccPublicKey = util.readExactSubarray(bytes, read, read + getCurvePayloadSize(enums.publicKey.ed25519)); read += eccPublicKey.length;
const mldsaPublicKey = util.readExactSubarray(bytes, read, read + 1952); read += mldsaPublicKey.length;
return { read, publicParams: { eccPublicKey, mldsaPublicKey } };
}
default:
throw new UnsupportedError('Unknown public key encryption algorithm.');
}
Expand Down Expand Up @@ -316,6 +321,11 @@ export function parsePrivateKeyParams(algo, bytes, publicParams) {
const mlkemSecretKey = util.readExactSubarray(bytes, read, read + 2400); read += mlkemSecretKey.length;
return { read, privateParams: { eccSecretKey, mlkemSecretKey } };
}
case enums.publicKey.pqc_mldsa_x25519: {
const eccSecretKey = util.readExactSubarray(bytes, read, read + getCurvePayloadSize(enums.publicKey.ed25519)); read += eccSecretKey.length;
const mldsaSecretKey = util.readExactSubarray(bytes, read, read + 4000); read += mldsaSecretKey.length;
return { read, privateParams: { eccSecretKey, mldsaSecretKey } };
}
default:
throw new UnsupportedError('Unknown public key encryption algorithm.');
}
Expand Down Expand Up @@ -405,7 +415,8 @@ export function serializeParams(algo, params) {
enums.publicKey.x448,
enums.publicKey.aead,
enums.publicKey.hmac,
enums.publicKey.pqc_mlkem_x25519
enums.publicKey.pqc_mlkem_x25519,
enums.publicKey.pqc_mldsa_ed25519
]);
const orderedParams = Object.keys(params).map(name => {
const param = params[name];
Expand Down Expand Up @@ -477,6 +488,11 @@ export async function generateParams(algo, bits, oid, symmetric) {
privateParams: { eccSecretKey, mlkemSecretKey },
publicParams: { eccPublicKey, mlkemPublicKey }
}));
case enums.publicKey.pqc_mldsa_ed25519:
return publicKey.postQuantum.signature.generate(algo).then(({ eccSecretKey, eccPublicKey, mldsaSecretKey, mldsaPublicKey }) => ({
privateParams: { eccSecretKey, mldsaSecretKey },
publicParams: { eccPublicKey, mldsaPublicKey }
}));
case enums.publicKey.dsa:
case enums.publicKey.elgamal:
throw new Error('Unsupported algorithm for key generation.');
Expand Down Expand Up @@ -568,6 +584,9 @@ export async function validateParams(algo, publicParams, privateParams) {
return keySize === keyMaterial.length &&
util.equalsUint8Array(digest, await hash.sha256(hashSeed));
}
case enums.publicKey.pqc_mlkem_x25519:
case enums.publicKey.pqc_mldsa_ed25519:
throw new Error('TODO');
default:
throw new Error('Unknown public key algorithm.');
}
Expand Down
4 changes: 3 additions & 1 deletion src/crypto/public_key/post_quantum/index.js
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
};
40 changes: 40 additions & 0 deletions src/crypto/public_key/post_quantum/signature/ecc_dsa.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
// TODOOOOO is this file needed? vs inlining calls in signature.js?


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');
}
}
1 change: 1 addition & 0 deletions src/crypto/public_key/post_quantum/signature/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { generate, sign, verify } from './signature';
47 changes: 47 additions & 0 deletions src/crypto/public_key/post_quantum/signature/ml_dsa.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import enums from '../../../../enums';

export async function generate(algo) {
switch (algo) {
case enums.publicKey.pqc_mldsa_ed25519: {
const { DilithiumKeyPair, DilithiumLevel } = await import('@asanrom/dilithium');

const level = DilithiumLevel.get(3);
const keyPair = DilithiumKeyPair.generate(level);

const mldsaSecretKey = keyPair.getPrivateKey().getBytes();
const mldsaPublicKey = keyPair.getPublicKey().getBytes();

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 { DilithiumPrivateKey, DilithiumLevel } = await import('@asanrom/dilithium');
const level = DilithiumLevel.get(3);
const secretKey = DilithiumPrivateKey.fromBytes(mldsaSecretKey, level);
const mldsaSignature = secretKey.sign(dataDigest).getBytes();
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 { DilithiumPublicKey, DilithiumSignature, DilithiumLevel } = await import('@asanrom/dilithium');
const level = DilithiumLevel.get(3);
const publicKey = DilithiumPublicKey.fromBytes(mldsaPublicKey, level);
const signature = DilithiumSignature.fromBytes(mldsaSignature, level);
return publicKey.verifySignature(dataDigest, signature);
}
default:
throw new Error('Unsupported signature algorithm');
}
}
Loading

0 comments on commit ffb47e2

Please sign in to comment.