aere-contracts/contracts/AereSecurity.sol
Aere Network a13a649b77
Some checks are pending
contracts-ci / Install (lockfile) → compile → full test suite (push) Waiting to run
contracts-ci / PQC known-answer tests (NIST vectors) (push) Waiting to run
contracts-ci / Coverage (scoped, with artifacts) (push) Waiting to run
Initial public release
Aere Network public source. Everything here can be checked against the live
chain (chain id 2800, https://rpc.aere.network).

Scope note, stated up front rather than buried: consensus on chain 2800 is
classical secp256k1 ECDSA QBFT. The post-quantum work in this repository is at
the signature, precompile, account and transport layers. Nothing here makes the
consensus post-quantum, and no document in it should be read as claiming so.
2026-07-20 01:02:37 +03:00

342 lines
12 KiB
Solidity

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;
import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/security/ReentrancyGuard.sol";
import "@openzeppelin/contracts/security/Pausable.sol";
/**
* @title AERE Security Contract
* @dev Manages security monitoring and threat detection with enhanced security
*/
contract AereSecurity is Ownable, ReentrancyGuard, Pausable {
enum ThreatLevel { Low, Medium, High, Critical }
enum AlertStatus { Active, Resolved, Investigating }
struct SecurityAlert {
uint256 id;
string alertType;
ThreatLevel severity;
string message;
address reporter;
uint256 timestamp;
AlertStatus status;
string resolution;
}
struct SecurityMetrics {
uint256 totalAlerts;
uint256 resolvedAlerts;
uint256 criticalAlerts;
uint256 lastScanTime;
bool systemHealthy;
}
// State variables
mapping(uint256 => SecurityAlert) public alerts;
mapping(address => bool) public authorizedReporters;
mapping(address => uint256) public reputationScores;
mapping(address => uint256) public reportCounts;
mapping(address => uint256) public lastReportTime;
uint256 public alertCount = 0;
SecurityMetrics public securityMetrics;
// Security parameters
uint256 public constant RATE_LIMIT_WINDOW = 1 hours;
uint256 public constant MAX_REPORTS_PER_WINDOW = 10;
uint256 public constant MIN_REPUTATION_TO_REPORT = 50;
// Events
event SecurityAlertCreated(uint256 indexed alertId, ThreatLevel severity, string alertType, address indexed reporter);
event AlertResolved(uint256 indexed alertId, string resolution, address indexed resolver);
event ThreatDetected(address indexed source, string threatType, ThreatLevel severity, address indexed detector);
event ReputationUpdated(address indexed entity, uint256 oldScore, uint256 newScore);
event ReporterAuthorized(address indexed reporter, address indexed authorizer);
event ReporterRevoked(address indexed reporter, address indexed revoker);
modifier onlyAuthorizedReporter() {
require(authorizedReporters[msg.sender], "AereSecurity: Not authorized to report");
require(reputationScores[msg.sender] >= MIN_REPUTATION_TO_REPORT, "AereSecurity: Insufficient reputation");
_;
}
modifier rateLimited() {
require(
reportCounts[msg.sender] < MAX_REPORTS_PER_WINDOW ||
block.timestamp > lastReportTime[msg.sender] + RATE_LIMIT_WINDOW,
"AereSecurity: Rate limit exceeded"
);
if (block.timestamp > lastReportTime[msg.sender] + RATE_LIMIT_WINDOW) {
reportCounts[msg.sender] = 0;
}
reportCounts[msg.sender]++;
lastReportTime[msg.sender] = block.timestamp;
_;
}
constructor() {
securityMetrics = SecurityMetrics({
totalAlerts: 0,
resolvedAlerts: 0,
criticalAlerts: 0,
lastScanTime: block.timestamp,
systemHealthy: true
});
// Owner is authorized reporter by default with high reputation
authorizedReporters[msg.sender] = true;
reputationScores[msg.sender] = 100;
emit ReporterAuthorized(msg.sender, msg.sender);
emit ReputationUpdated(msg.sender, 0, 100);
}
/**
* @dev Add authorized security reporter with reputation check
*/
function addAuthorizedReporter(address reporter) external onlyOwner {
require(reporter != address(0), "AereSecurity: Invalid reporter address");
require(!authorizedReporters[reporter], "AereSecurity: Reporter already authorized");
authorizedReporters[reporter] = true;
if (reputationScores[reporter] == 0) {
reputationScores[reporter] = MIN_REPUTATION_TO_REPORT;
}
emit ReporterAuthorized(reporter, msg.sender);
}
/**
* @dev Remove authorized security reporter
*/
function removeAuthorizedReporter(address reporter) external onlyOwner {
require(reporter != msg.sender, "AereSecurity: Cannot remove self");
authorizedReporters[reporter] = false;
emit ReporterRevoked(reporter, msg.sender);
}
/**
* @dev Report security alert with enhanced validation
*/
function reportSecurityAlert(
string memory alertType,
ThreatLevel severity,
string memory message
) external onlyAuthorizedReporter rateLimited whenNotPaused nonReentrant returns (uint256) {
require(bytes(alertType).length > 0 && bytes(alertType).length <= 100, "AereSecurity: Invalid alert type");
require(bytes(message).length > 0 && bytes(message).length <= 1000, "AereSecurity: Invalid message");
alertCount++;
uint256 alertId = alertCount;
alerts[alertId] = SecurityAlert({
id: alertId,
alertType: alertType,
severity: severity,
message: message,
reporter: msg.sender,
timestamp: block.timestamp,
status: AlertStatus.Active,
resolution: ""
});
securityMetrics.totalAlerts++;
if (severity == ThreatLevel.Critical) {
securityMetrics.criticalAlerts++;
securityMetrics.systemHealthy = false;
}
// Update reporter reputation (positive for reporting)
_updateReputationSafe(msg.sender, reputationScores[msg.sender] + 1);
emit SecurityAlertCreated(alertId, severity, alertType, msg.sender);
return alertId;
}
/**
* @dev Resolve security alert with enhanced validation
*/
function resolveAlert(uint256 alertId, string memory resolution) external onlyOwner nonReentrant {
require(alertId > 0 && alertId <= alertCount, "AereSecurity: Alert does not exist");
require(alerts[alertId].status != AlertStatus.Resolved, "AereSecurity: Alert already resolved");
require(bytes(resolution).length > 0 && bytes(resolution).length <= 1000, "AereSecurity: Invalid resolution");
alerts[alertId].status = AlertStatus.Resolved;
alerts[alertId].resolution = resolution;
securityMetrics.resolvedAlerts++;
// Update system health if all critical alerts resolved
if (alerts[alertId].severity == ThreatLevel.Critical) {
securityMetrics.criticalAlerts = securityMetrics.criticalAlerts > 0 ? securityMetrics.criticalAlerts - 1 : 0;
if (securityMetrics.criticalAlerts == 0) {
securityMetrics.systemHealthy = true;
}
}
emit AlertResolved(alertId, resolution, msg.sender);
}
/**
* @dev Detect and report threat with enhanced validation
*/
function detectThreat(
address source,
string memory threatType,
ThreatLevel severity
) external onlyAuthorizedReporter rateLimited whenNotPaused nonReentrant {
require(source != address(0), "AereSecurity: Invalid source address");
require(bytes(threatType).length > 0 && bytes(threatType).length <= 100, "AereSecurity: Invalid threat type");
// Update reputation score for the source (negative impact)
if (reputationScores[source] > uint256(severity) + 1) {
_updateReputationSafe(source, reputationScores[source] - (uint256(severity) + 1));
} else {
_updateReputationSafe(source, 0);
}
// Create alert
string memory message = string(abi.encodePacked("Threat detected from ", _addressToString(source)));
this.reportSecurityAlert(threatType, severity, message);
emit ThreatDetected(source, threatType, severity, msg.sender);
}
/**
* @dev Update reputation score with bounds checking
*/
function updateReputation(address entity, uint256 score) external onlyOwner {
require(entity != address(0), "AereSecurity: Invalid entity address");
require(score <= 100, "AereSecurity: Score too high");
uint256 oldScore = reputationScores[entity];
_updateReputationSafe(entity, score);
emit ReputationUpdated(entity, oldScore, score);
}
/**
* @dev Internal safe reputation update
*/
function _updateReputationSafe(address entity, uint256 score) internal {
uint256 oldScore = reputationScores[entity];
reputationScores[entity] = score > 100 ? 100 : score;
if (oldScore != reputationScores[entity]) {
emit ReputationUpdated(entity, oldScore, reputationScores[entity]);
}
}
/**
* @dev Perform security scan (only owner, rate limited)
*/
function performSecurityScan() external onlyOwner {
require(block.timestamp >= securityMetrics.lastScanTime + 1 hours, "AereSecurity: Scan rate limited");
securityMetrics.lastScanTime = block.timestamp;
securityMetrics.systemHealthy = (securityMetrics.criticalAlerts == 0);
}
/**
* @dev Emergency pause function
*/
function emergencyPause() external onlyOwner {
_pause();
}
/**
* @dev Unpause function
*/
function unpause() external onlyOwner {
_unpause();
}
/**
* @dev Get alert details with existence check
*/
function getAlert(uint256 alertId) external view returns (SecurityAlert memory) {
require(alertId > 0 && alertId <= alertCount, "AereSecurity: Alert does not exist");
return alerts[alertId];
}
/**
* @dev Get security metrics
*/
function getSecurityMetrics() external view returns (SecurityMetrics memory) {
return securityMetrics;
}
/**
* @dev Get reputation score
*/
function getReputationScore(address entity) external view returns (uint256) {
return reputationScores[entity];
}
/**
* @dev Check if system is healthy
*/
function isSystemHealthy() external view returns (bool) {
return securityMetrics.systemHealthy && securityMetrics.criticalAlerts == 0 && !paused();
}
/**
* @dev Get active alerts count by severity
*/
function getActiveAlertsBySeverity(ThreatLevel severity) external view returns (uint256) {
uint256 count = 0;
for (uint256 i = 1; i <= alertCount; i++) {
if (alerts[i].severity == severity && alerts[i].status == AlertStatus.Active) {
count++;
}
}
return count;
}
/**
* @dev Check if address is authorized reporter
*/
function isAuthorizedReporter(address reporter) external view returns (bool) {
return authorizedReporters[reporter] && reputationScores[reporter] >= MIN_REPUTATION_TO_REPORT;
}
/**
* @dev Get reporter statistics
*/
function getReporterStats(address reporter) external view returns (
bool authorized,
uint256 reputation,
uint256 reportsInWindow,
uint256 lastReport
) {
return (
authorizedReporters[reporter],
reputationScores[reporter],
reportCounts[reporter],
lastReportTime[reporter]
);
}
/**
* @dev Convert address to string
*/
function _addressToString(address account) internal pure returns (string memory) {
bytes32 value = bytes32(uint256(uint160(account)));
bytes memory alphabet = "0123456789abcdef";
bytes memory str = new bytes(42);
str[0] = '0';
str[1] = 'x';
for (uint256 i = 0; i < 20; i++) {
str[2+i*2] = alphabet[uint8(value[i + 12] >> 4)];
str[3+i*2] = alphabet[uint8(value[i + 12] & 0x0f)];
}
return string(str);
}
}