Files
coreth/contracts/PostQuantumVerifier.sol
zeekay 0d4c19f41c Update to use luxfi/crypto v1.3.2
- Fixed post-quantum crypto imports to use luxfi/crypto
- Kept go-verkle for Verkle tree support
- All crypto operations use unified luxfi/crypto package
2025-08-16 09:52:51 -05:00

227 lines
8.5 KiB
Solidity

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;
/**
* @title PostQuantumVerifier
* @notice Contract for verifying post-quantum signatures using precompiled contracts
* @dev Uses Lux network's post-quantum precompiles for FALCON and Dilithium verification
*/
contract PostQuantumVerifier {
// Precompile addresses for post-quantum signatures
address constant FALCON_VERIFY = 0x0000000000000000000000000000000000000100;
address constant FALCON_RECOVER = 0x0000000000000000000000000000000000000101;
address constant DILITHIUM_VERIFY = 0x0000000000000000000000000000000000000102;
address constant ETH_FALCON_VERIFY = 0x0000000000000000000000000000000000000103;
address constant ETH_DILITHIUM_VERIFY = 0x0000000000000000000000000000000000000104;
// Events
event FalconVerified(address indexed verifier, bytes32 messageHash, bool valid);
event DilithiumVerified(address indexed verifier, bytes32 messageHash, bool valid);
event AddressRecovered(address indexed recovered, bytes32 messageHash);
/**
* @notice Verify a FALCON-512 signature (NIST-compliant)
* @param signature The FALCON signature
* @param message The message that was signed
* @param publicKey The FALCON public key (897 bytes)
* @return valid True if signature is valid
*/
function verifyFalcon(
bytes memory signature,
bytes memory message,
bytes memory publicKey
) public returns (bool valid) {
// ABI encode the parameters for the precompile
bytes memory input = abi.encode(signature, message, publicKey);
// Call the FALCON verify precompile
(bool success, bytes memory result) = FALCON_VERIFY.staticcall(input);
if (success && result.length == 32) {
valid = uint256(bytes32(result)) == 1;
emit FalconVerified(msg.sender, keccak256(message), valid);
}
return valid;
}
/**
* @notice Verify an ETH-optimized FALCON signature (uses Keccak instead of SHAKE)
* @param messageHash The hash of the message (32 bytes)
* @param salt The signature salt (40 bytes)
* @param s2 The s2 component of signature (compacted format)
* @param ntth The public key in NTT domain (compacted format)
* @return valid True if signature is valid
*/
function verifyETHFalcon(
bytes32 messageHash,
bytes memory salt,
uint256[] memory s2,
uint256[] memory ntth
) public returns (bool valid) {
require(salt.length == 40, "Invalid salt length");
require(s2.length == 32, "Invalid s2 length");
require(ntth.length == 32, "Invalid public key length");
// Pack the data for ETH-optimized format
bytes memory input = abi.encodePacked(messageHash, salt);
// Add compacted s2
for (uint i = 0; i < s2.length; i++) {
input = abi.encodePacked(input, s2[i]);
}
// Add compacted ntth (public key in NTT domain)
for (uint i = 0; i < ntth.length; i++) {
input = abi.encodePacked(input, ntth[i]);
}
// Call the ETH-optimized FALCON verify precompile
(bool success, bytes memory result) = ETH_FALCON_VERIFY.staticcall(input);
if (success && result.length == 32) {
valid = uint256(bytes32(result)) == 1;
emit FalconVerified(msg.sender, messageHash, valid);
}
return valid;
}
/**
* @notice Recover an address from a FALCON signature (EPERVIER variant)
* @param messageHash The hash of the message
* @param salt The signature salt (40 bytes)
* @param signature The FALCON signature with recovery
* @return recovered The recovered Ethereum address
*/
function recoverFalconAddress(
bytes32 messageHash,
bytes memory salt,
bytes memory signature
) public returns (address recovered) {
require(salt.length == 40, "Invalid salt length");
// Pack the input
bytes memory input = abi.encodePacked(messageHash, salt, signature);
// Call the FALCON recover precompile
(bool success, bytes memory result) = FALCON_RECOVER.staticcall(input);
if (success && result.length == 32) {
recovered = address(uint160(uint256(bytes32(result))));
emit AddressRecovered(recovered, messageHash);
}
return recovered;
}
/**
* @notice Verify a Dilithium3 signature (NIST-compliant)
* @param signature The Dilithium signature (3293 bytes)
* @param message The message that was signed
* @param publicKey The Dilithium public key (1952 bytes)
* @return valid True if signature is valid
*/
function verifyDilithium(
bytes memory signature,
bytes memory message,
bytes memory publicKey
) public returns (bool valid) {
require(signature.length == 3293, "Invalid signature length");
require(publicKey.length == 1952, "Invalid public key length");
// ABI encode the parameters for the precompile
bytes memory input = abi.encode(signature, message, publicKey);
// Call the Dilithium verify precompile
(bool success, bytes memory result) = DILITHIUM_VERIFY.staticcall(input);
if (success && result.length == 32) {
valid = uint256(bytes32(result)) == 1;
emit DilithiumVerified(msg.sender, keccak256(message), valid);
}
return valid;
}
/**
* @notice Verify an ETH-optimized Dilithium signature
* @param messageHash The hash of the message
* @param signatureData The packed signature and public key data
* @return valid True if signature is valid
*/
function verifyETHDilithium(
bytes32 messageHash,
bytes memory signatureData
) public returns (bool valid) {
// Pack the input
bytes memory input = abi.encodePacked(messageHash, signatureData);
// Call the ETH-optimized Dilithium verify precompile
(bool success, bytes memory result) = ETH_DILITHIUM_VERIFY.staticcall(input);
if (success && result.length == 32) {
valid = uint256(bytes32(result)) == 1;
emit DilithiumVerified(msg.sender, messageHash, valid);
}
return valid;
}
/**
* @notice Check if an address has been quantum-secured
* @dev This would integrate with a registry of quantum-secured addresses
*/
mapping(address => bool) public quantumSecured;
mapping(address => bytes) public falconPublicKeys;
mapping(address => bytes) public dilithiumPublicKeys;
/**
* @notice Register a FALCON public key for an address
* @param publicKey The FALCON public key to register
*/
function registerFalconKey(bytes memory publicKey) public {
require(publicKey.length == 897, "Invalid FALCON public key length");
falconPublicKeys[msg.sender] = publicKey;
quantumSecured[msg.sender] = true;
}
/**
* @notice Register a Dilithium public key for an address
* @param publicKey The Dilithium public key to register
*/
function registerDilithiumKey(bytes memory publicKey) public {
require(publicKey.length == 1952, "Invalid Dilithium public key length");
dilithiumPublicKeys[msg.sender] = publicKey;
quantumSecured[msg.sender] = true;
}
/**
* @notice Execute a transaction with FALCON signature verification
* @param target The target contract
* @param data The transaction data
* @param signature The FALCON signature
* @param signer The address that should have signed
*/
function executeWithFalcon(
address target,
bytes memory data,
bytes memory signature,
address signer
) public returns (bool success, bytes memory returnData) {
// Get the registered FALCON public key
bytes memory publicKey = falconPublicKeys[signer];
require(publicKey.length > 0, "No FALCON key registered");
// Verify the signature
bytes32 messageHash = keccak256(abi.encodePacked(target, data, block.number));
bytes memory message = abi.encodePacked(messageHash);
bool valid = verifyFalcon(signature, message, publicKey);
require(valid, "Invalid FALCON signature");
// Execute the transaction
(success, returnData) = target.call(data);
}
}