// SPDX-License-Identifier: MIT pragma solidity ^0.8.26; /// @title SealedPolicyRegistry — sealed policy-hash registry read through RIP-7212 (GH-W1-001 §2.2). /// @notice A policy (OPA bundle: fee split, buyback rule, pricing) is identified by the sha256 of its bundle. Only the /// sealed key (an ATECC608B chip, P-256) can register a hash: the chip signs sha256(hex(keccak256(policyId, hash, nonce))) /// and the precompile at 0x100 verifies it. Consumers (hooks, exchanges) call isRegistered(policyId, hash). contract SealedPolicyRegistry { address internal constant P256_VERIFIER = address(0x100); uint256 internal constant N_HALF = 0x7FFFFFFF800000007FFFFFFFFFFFFFFFDE737D56D38BCF4279DCE5617E3192A8; uint256 public immutable qx; uint256 public immutable qy; mapping(bytes32 => bytes32) public current; // policyId -> current policy hash mapping(bytes32 => mapping(bytes32 => bool)) public registered; uint256 public nonce; event PolicyRegistered(bytes32 indexed policyId, bytes32 indexed policyHash, uint256 nonce); event PolicyRefused(bytes32 indexed policyId, bytes32 indexed policyHash, string reason); constructor(uint256 _qx, uint256 _qy) { qx = _qx; qy = _qy; } /// @notice Register a policy hash. Anyone may relay; only a signature from the sealed chip is accepted. function register(bytes32 policyId, bytes32 policyHash, bytes calldata sig) external { if (sig.length != 64) { emit PolicyRefused(policyId, policyHash, "bad-sig-length"); revert("SEALED: bad signature length"); } uint256 r = uint256(bytes32(sig[0:32])); uint256 s = uint256(bytes32(sig[32:64])); if (s > N_HALF) { emit PolicyRefused(policyId, policyHash, "high-s"); revert("SEALED: high-s"); } bytes32 message = keccak256(abi.encodePacked(policyId, policyHash, nonce)); bytes32 inner = sha256(bytes(_hex(message, true))); // material "0x" bytes32 digest = sha256(bytes(_hex(inner, false))); // broker digest mode: chip signs SHA-256 over hex64(sha256(material)) (bool ok, bytes memory out) = P256_VERIFIER.staticcall(abi.encodePacked(digest, r, s, qx, qy)); if (!(ok && out.length == 32 && abi.decode(out, (uint256)) == 1)) { emit PolicyRefused(policyId, policyHash, "sealed-signature-invalid"); revert("SEALED: signature invalid"); } registered[policyId][policyHash] = true; current[policyId] = policyHash; nonce++; emit PolicyRegistered(policyId, policyHash, nonce - 1); } function isRegistered(bytes32 policyId, bytes32 policyHash) external view returns (bool) { return registered[policyId][policyHash]; } function messageFor(bytes32 policyId, bytes32 policyHash) external view returns (bytes32) { return keccak256(abi.encodePacked(policyId, policyHash, nonce)); } function _hex(bytes32 h, bool prefixed) internal pure returns (string memory) { bytes16 alphabet = 0x30313233343536373839616263646566; uint256 o = prefixed ? 2 : 0; bytes memory str = new bytes(64 + o); if (prefixed) { str[0] = "0"; str[1] = "x"; } for (uint256 i = 0; i < 32; i++) { str[o + i * 2] = alphabet[uint8(h[i] >> 4)]; str[o + 1 + i * 2] = alphabet[uint8(h[i] & 0x0f)]; } return string(str); } }