enforce double signature

This commit is contained in:
ITScutaru 2025-07-01 12:50:36 +03:00
parent b454b003db
commit 3263216974

View File

@ -77,47 +77,74 @@ Block.validateLoginBlock = function (Env, publicKey, signature, block, pqPublicK
if (sigType === 1 && u8_signature.length > 65) {
// Hybrid signature - check the classical part first
const classicalSig = u8_signature.subarray(1, 1 + 64); // Ed25519 signature is 64 bytes
verified = Nacl.sign.detached.verify(hash, classicalSig, u8_public_key);
const classicalVerified = Nacl.sign.detached.verify(hash, classicalSig, u8_public_key);
// Check for PQ signature as well, but don't require it to pass
if (verified && ml_kem && ml_dsa) {
try {
// Get PQ signature length from the 4 bytes after classical signature
const pqSigLenView = new DataView(u8_signature.buffer, u8_signature.byteOffset + 65);
const pqSigLen = pqSigLenView.getUint32(0, false); // big-endian
if (!classicalVerified) {
Env.Log.error('BLOCK_CLASSICAL_VERIFICATION_FAILED', {
blockId: publicKey
});
return void cb('E_COULD_NOT_VERIFY_CLASSICAL');
}
// Extract PQ signature
const pqSig = u8_signature.subarray(1 + 64 + 4, 1 + 64 + 4 + pqSigLen);
// Now check PQ signature - this is required for hybrid signatures
let pqVerified = false;
// If PQ public key is provided, verify the PQ signature
let publicKeyToUse = pqPublicKey;
if (!publicKeyToUse && Env.blockInfo && Env.blockInfo[publicKey] && Env.blockInfo[publicKey].pqPublicKey) {
publicKeyToUse = Env.blockInfo[publicKey].pqPublicKey;
}
if (!ml_kem || !ml_dsa) {
Env.Log.error('BLOCK_PQ_VERIFICATION_ERROR', {
error: 'PQ libraries not available',
blockId: publicKey
});
return void cb('E_PQ_LIBRARIES_MISSING');
}
if (publicKeyToUse) {
const pqPublicKeyDecoded = Util.decodeBase64(publicKeyToUse);
try {
// Get PQ signature length from the 4 bytes after classical signature
const pqSigLenView = new DataView(u8_signature.buffer, u8_signature.byteOffset + 65);
const pqSigLen = pqSigLenView.getUint32(0, false); // big-endian
const pqVerified = ml_dsa.ml_dsa44.internal.verify(
pqPublicKeyDecoded,
hash,
pqSig
);
// Extract PQ signature
const pqSig = u8_signature.subarray(1 + 64 + 4, 1 + 64 + 4 + pqSigLen);
console.log("PQ verification result:", pqVerified);
// If PQ public key is provided, verify the PQ signature
let publicKeyToUse = pqPublicKey;
if (!publicKeyToUse && Env.blockInfo && Env.blockInfo[publicKey] && Env.blockInfo[publicKey].pqPublicKey) {
publicKeyToUse = Env.blockInfo[publicKey].pqPublicKey;
}
Env.Log.info('BLOCK_PQ_VERIFICATION_RESULT', {
blockId: publicKey,
result: pqVerified
});
}
} catch (err) {
if (!publicKeyToUse) {
Env.Log.error('BLOCK_PQ_VERIFICATION_ERROR', {
error: err.message,
error: 'PQ public key not available',
blockId: publicKey
});
return void cb('E_MISSING_PQ_PUBLIC_KEY');
}
const pqPublicKeyDecoded = Util.decodeBase64(publicKeyToUse);
pqVerified = ml_dsa.ml_dsa44.internal.verify(
pqPublicKeyDecoded,
hash,
pqSig
);
Env.Log.info('BLOCK_PQ_VERIFICATION_RESULT', {
blockId: publicKey,
result: pqVerified
});
if (!pqVerified) {
return void cb('E_COULD_NOT_VERIFY_PQ');
}
} catch (err) {
Env.Log.error('BLOCK_PQ_VERIFICATION_ERROR', {
error: err.message,
blockId: publicKey
});
return void cb('E_PQ_VERIFICATION_ERROR');
}
// Both classical and PQ signatures verified
verified = classicalVerified && pqVerified;
} else {
// Classical signature or unrecognized format - use normal verification
// For type 0 we need to skip the first byte
@ -151,49 +178,81 @@ Block.validateAncestorProof = function (Env, proof, _cb) {
if (sigType === 1 && u8_sig.length > 65) {
// Hybrid signature - check the classical part first
const classicalSig = u8_sig.subarray(1, 1 + 64); // Ed25519 signature is 64 bytes
valid = Nacl.sign.detached.verify(u8_pub, classicalSig, u8_pub);
const classicalVerified = Nacl.sign.detached.verify(u8_pub, classicalSig, u8_pub);
// Check for PQ signature as well, but don't require it to pass
if (valid && ml_kem && ml_dsa) {
try {
// Get PQ signature length from the 4 bytes after classical signature
const pqSigLenView = new DataView(u8_sig.buffer, u8_sig.byteOffset + 65);
const pqSigLen = pqSigLenView.getUint32(0, false); // big-endian
if (!classicalVerified) {
Env.Log.error('ANCESTOR_CLASSICAL_VERIFICATION_FAILED', {
blockId: pub
});
w.abort();
return void cb('E_INVALID_ANCESTOR_PROOF_CLASSICAL');
}
// Extract PQ signature
const pqSig = u8_sig.subarray(1 + 64 + 4, 1 + 64 + 4 + pqSigLen);
// Now check PQ signature - this is required for hybrid signatures
let pqVerified = false;
// If PQ public key is provided, verify the PQ signature
let pqPublicKey;
if (Env.blockInfo && Env.blockInfo[pub] && Env.blockInfo[pub].pqPublicKey) {
pqPublicKey = Env.blockInfo[pub].pqPublicKey;
} else if (ancestorPqPublicKey) {
pqPublicKey = ancestorPqPublicKey;
}
if (!ml_kem || !ml_dsa) {
Env.Log.error('ANCESTOR_PQ_VERIFICATION_ERROR', {
error: 'PQ libraries not available',
blockId: pub
});
w.abort();
return void cb('E_PQ_LIBRARIES_MISSING');
}
if (pqPublicKey) {
const pqPublicKeyDecoded = Util.decodeBase64(pqPublicKey);
try {
// Get PQ signature length from the 4 bytes after classical signature
const pqSigLenView = new DataView(u8_sig.buffer, u8_sig.byteOffset + 65);
const pqSigLen = pqSigLenView.getUint32(0, false); // big-endian
const pqVerified = ml_dsa.ml_dsa44.internal.verify(
pqPublicKeyDecoded,
u8_pub,
pqSig
);
// Extract PQ signature
const pqSig = u8_sig.subarray(1 + 64 + 4, 1 + 64 + 4 + pqSigLen);
console.log("PQ verification result 2:", pqVerified);
// If PQ public key is provided, verify the PQ signature
let pqPublicKey;
if (Env.blockInfo && Env.blockInfo[pub] && Env.blockInfo[pub].pqPublicKey) {
pqPublicKey = Env.blockInfo[pub].pqPublicKey;
} else if (ancestorPqPublicKey) {
pqPublicKey = ancestorPqPublicKey;
}
Env.Log.info('ANCESTOR_PQ_VERIFICATION_RESULT', {
blockId: pub,
result: pqVerified
});
}
} catch (err) {
if (!pqPublicKey) {
Env.Log.error('ANCESTOR_PQ_VERIFICATION_ERROR', {
error: err.message,
error: 'PQ public key not available',
blockId: pub
});
w.abort();
return void cb('E_MISSING_PQ_PUBLIC_KEY');
}
const pqPublicKeyDecoded = Util.decodeBase64(pqPublicKey);
pqVerified = ml_dsa.ml_dsa44.internal.verify(
pqPublicKeyDecoded,
u8_pub,
pqSig
);
Env.Log.info('ANCESTOR_PQ_VERIFICATION_RESULT', {
blockId: pub,
result: pqVerified
});
if (!pqVerified) {
w.abort();
return void cb('E_INVALID_ANCESTOR_PROOF_PQ');
}
} catch (err) {
Env.Log.error('ANCESTOR_PQ_VERIFICATION_ERROR', {
error: err.message,
blockId: pub
});
w.abort();
return void cb('E_PQ_VERIFICATION_ERROR');
}
// Both classical and PQ signatures verified
valid = classicalVerified && pqVerified;
} else {
// Classical signature or unrecognized format - use normal verification
// For type 0 we need to skip the first byte