mirror of
https://github.com/luxfi/precompile.git
synced 2026-09-24 00:26:21 +00:00
246 lines
7.5 KiB
Solidity
246 lines
7.5 KiB
Solidity
// SPDX-License-Identifier: MIT
|
|
pragma solidity ^0.8.24;
|
|
|
|
/**
|
|
* @title ICoronaThreshold
|
|
* @notice Interface for the Corona Threshold Signature precompile
|
|
* @dev Precompile address: 0x020000000000000000000000000000000000000B
|
|
*
|
|
* This precompile verifies LWE-based threshold signatures from the Corona protocol
|
|
* (https://eprint.iacr.org/2024/1113) used in Quasar quantum consensus.
|
|
*
|
|
* Key Features:
|
|
* - Post-quantum security (LWE-based lattice cryptography)
|
|
* - Two-round threshold signature protocol
|
|
* - Configurable t-of-n threshold
|
|
* - Compatible with Quasar consensus validators
|
|
*
|
|
* Security Level:
|
|
* - Classical: >128-bit
|
|
* - Quantum: Resistant to Shor's algorithm
|
|
* - Based on Learning With Errors (LWE) problem
|
|
*/
|
|
interface ICoronaThreshold {
|
|
/**
|
|
* @notice Verify a Corona threshold signature
|
|
* @param threshold The minimum number of parties required (t)
|
|
* @param totalParties The total number of parties in the protocol (n)
|
|
* @param messageHash The 32-byte hash of the message that was signed
|
|
* @param signature The threshold signature bytes
|
|
* @return valid True if the signature is valid and threshold is met
|
|
*
|
|
* @dev Input format:
|
|
* [0:4] = threshold t (uint32)
|
|
* [4:8] = total parties n (uint32)
|
|
* [8:40] = message hash (32 bytes)
|
|
* [40:...] = threshold signature (~4KB)
|
|
*
|
|
* @dev Gas cost: 150,000 + (n * 10,000)
|
|
* - 2 parties: 170,000 gas
|
|
* - 3 parties: 180,000 gas
|
|
* - 5 parties: 200,000 gas
|
|
* - 10 parties: 250,000 gas
|
|
*/
|
|
function verifyThreshold(
|
|
uint32 threshold,
|
|
uint32 totalParties,
|
|
bytes32 messageHash,
|
|
bytes calldata signature
|
|
) external view returns (bool valid);
|
|
|
|
/**
|
|
* @notice Estimate gas for threshold verification
|
|
* @param parties The number of parties in the threshold signature
|
|
* @return gasEstimate The estimated gas cost
|
|
*/
|
|
function estimateGas(uint32 parties) external pure returns (uint256 gasEstimate);
|
|
}
|
|
|
|
/**
|
|
* @title CoronaThresholdLib
|
|
* @notice Library for interacting with the Corona Threshold precompile
|
|
*/
|
|
library CoronaThresholdLib {
|
|
/// @notice Address of the Corona threshold precompile
|
|
address constant CORONA_THRESHOLD = 0x020000000000000000000000000000000000000B;
|
|
|
|
/// @notice Gas costs
|
|
uint256 constant BASE_GAS = 150_000;
|
|
uint256 constant PER_PARTY_GAS = 10_000;
|
|
|
|
/// @notice Errors
|
|
error InvalidThreshold();
|
|
error SignatureVerificationFailed();
|
|
error InsufficientGas();
|
|
|
|
/**
|
|
* @notice Verify a threshold signature, reverting on failure
|
|
* @param threshold Minimum number of parties required
|
|
* @param totalParties Total number of parties
|
|
* @param messageHash Hash of the signed message
|
|
* @param signature Threshold signature bytes
|
|
*/
|
|
function verifyOrRevert(
|
|
uint32 threshold,
|
|
uint32 totalParties,
|
|
bytes32 messageHash,
|
|
bytes calldata signature
|
|
) internal view {
|
|
if (threshold == 0 || threshold > totalParties) {
|
|
revert InvalidThreshold();
|
|
}
|
|
|
|
bool valid = ICoronaThreshold(CORONA_THRESHOLD).verifyThreshold(
|
|
threshold,
|
|
totalParties,
|
|
messageHash,
|
|
signature
|
|
);
|
|
|
|
if (!valid) {
|
|
revert SignatureVerificationFailed();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @notice Estimate gas required for verification
|
|
* @param parties Number of parties in threshold
|
|
* @return Gas estimate
|
|
*/
|
|
function estimateGas(uint32 parties) internal pure returns (uint256) {
|
|
return BASE_GAS + (uint256(parties) * PER_PARTY_GAS);
|
|
}
|
|
|
|
/**
|
|
* @notice Check if threshold parameters are valid
|
|
* @param threshold Minimum parties required
|
|
* @param totalParties Total parties
|
|
* @return True if valid
|
|
*/
|
|
function isValidThreshold(uint32 threshold, uint32 totalParties) internal pure returns (bool) {
|
|
return threshold > 0 && threshold <= totalParties;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @title CoronaThresholdVerifier
|
|
* @notice Abstract contract for using Corona threshold signatures
|
|
*/
|
|
abstract contract CoronaThresholdVerifier {
|
|
using CoronaThresholdLib for *;
|
|
|
|
/// @notice Emitted when a threshold signature is verified
|
|
event ThresholdSignatureVerified(
|
|
uint32 indexed threshold,
|
|
uint32 indexed totalParties,
|
|
bytes32 messageHash,
|
|
bool valid
|
|
);
|
|
|
|
/**
|
|
* @notice Verify a threshold signature
|
|
* @param threshold Minimum number of parties required
|
|
* @param totalParties Total number of parties
|
|
* @param messageHash Hash of the signed message
|
|
* @param signature Threshold signature bytes
|
|
* @return True if valid
|
|
*/
|
|
function verifyThresholdSignature(
|
|
uint32 threshold,
|
|
uint32 totalParties,
|
|
bytes32 messageHash,
|
|
bytes calldata signature
|
|
) internal view returns (bool) {
|
|
return ICoronaThreshold(CoronaThresholdLib.CORONA_THRESHOLD).verifyThreshold(
|
|
threshold,
|
|
totalParties,
|
|
messageHash,
|
|
signature
|
|
);
|
|
}
|
|
|
|
/**
|
|
* @notice Verify a threshold signature with event emission
|
|
* @param threshold Minimum number of parties required
|
|
* @param totalParties Total number of parties
|
|
* @param messageHash Hash of the signed message
|
|
* @param signature Threshold signature bytes
|
|
*/
|
|
function verifyThresholdSignatureWithEvent(
|
|
uint32 threshold,
|
|
uint32 totalParties,
|
|
bytes32 messageHash,
|
|
bytes calldata signature
|
|
) internal {
|
|
bool valid = verifyThresholdSignature(threshold, totalParties, messageHash, signature);
|
|
emit ThresholdSignatureVerified(threshold, totalParties, messageHash, valid);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @title QuasarValidator
|
|
* @notice Example contract using Corona threshold signatures for Quasar consensus
|
|
*/
|
|
contract QuasarValidator is CoronaThresholdVerifier {
|
|
struct Validator {
|
|
address addr;
|
|
bytes publicKey;
|
|
bool active;
|
|
}
|
|
|
|
uint32 public constant CONSENSUS_THRESHOLD = 2; // 2/3 threshold
|
|
uint32 public constant TOTAL_VALIDATORS = 3;
|
|
|
|
mapping(address => Validator) public validators;
|
|
|
|
/**
|
|
* @notice Verify consensus signature from validators
|
|
* @param messageHash Hash of the consensus message
|
|
* @param signature Aggregated threshold signature
|
|
*/
|
|
function verifyConsensus(
|
|
bytes32 messageHash,
|
|
bytes calldata signature
|
|
) external view returns (bool) {
|
|
return verifyThresholdSignature(
|
|
CONSENSUS_THRESHOLD,
|
|
TOTAL_VALIDATORS,
|
|
messageHash,
|
|
signature
|
|
);
|
|
}
|
|
|
|
/**
|
|
* @notice Submit a consensus decision with threshold signature
|
|
* @param messageHash Hash of the consensus message
|
|
* @param signature Aggregated threshold signature from validators
|
|
*/
|
|
function submitConsensus(
|
|
bytes32 messageHash,
|
|
bytes calldata signature
|
|
) external {
|
|
CoronaThresholdLib.verifyOrRevert(
|
|
CONSENSUS_THRESHOLD,
|
|
TOTAL_VALIDATORS,
|
|
messageHash,
|
|
signature
|
|
);
|
|
|
|
// Process consensus decision
|
|
emit ThresholdSignatureVerified(
|
|
CONSENSUS_THRESHOLD,
|
|
TOTAL_VALIDATORS,
|
|
messageHash,
|
|
true
|
|
);
|
|
}
|
|
|
|
/**
|
|
* @notice Estimate gas for consensus verification
|
|
* @return Gas estimate
|
|
*/
|
|
function estimateConsensusGas() external pure returns (uint256) {
|
|
return CoronaThresholdLib.estimateGas(TOTAL_VALIDATORS);
|
|
}
|
|
}
|