From 676ee65d825ea8ecf30d96023d14d863ef3e776c Mon Sep 17 00:00:00 2001 From: Leopold Joy Date: Fri, 11 Sep 2026 21:26:03 +0100 Subject: [PATCH 1/5] docs: specify hinted TEE registration Co-authored-by: OpenCode --- docs/llms-full.txt | 2 +- docs/llms.txt | 2 +- .../base-protocol/proofs/registrar.mdx | 578 ++++++++---------- docs/upgrades/upcoming-features.mdx | 2 +- 4 files changed, 242 insertions(+), 342 deletions(-) diff --git a/docs/llms-full.txt b/docs/llms-full.txt index 11ae273fd..534fdd080 100644 --- a/docs/llms-full.txt +++ b/docs/llms-full.txt @@ -264,7 +264,7 @@ const client = createPublicClient({ chain: base, transport: http() }) - [Proposer](https://docs.base.org/specifications/base-protocol/proofs/proposer): Specification of the proposer, an offchain service that turns canonical L2 checkpoint ranges into AggregateVerifier games on L1. -- [Registrar](https://docs.base.org/specifications/base-protocol/proofs/registrar): Specification of the registrar, an offchain service that maintains the onchain registry of accepted TEE signer identities via attestation ZK proofs. +- [Registrar](https://docs.base.org/specifications/base-protocol/proofs/registrar): Specification of the registrar and the hinted P-384 flow used to register AWS Nitro Enclave signer identities on L1. - [TEE Prover](https://docs.base.org/specifications/base-protocol/proofs/tee-prover): Specification of the TEE prover, an offchain service that re-executes L2 block ranges inside AWS Nitro Enclaves to produce signed proof material for AggregateVerifier games. diff --git a/docs/llms.txt b/docs/llms.txt index c93ad4e34..612ebb426 100644 --- a/docs/llms.txt +++ b/docs/llms.txt @@ -198,7 +198,7 @@ - [Proposer](https://docs.base.org/specifications/base-protocol/proofs/proposer): Specification of the proposer, an offchain service that turns canonical L2 checkpoint ranges into AggregateVerifier games on L1. -- [Registrar](https://docs.base.org/specifications/base-protocol/proofs/registrar): Specification of the registrar, an offchain service that maintains the onchain registry of accepted TEE signer identities via attestation ZK proofs. +- [Registrar](https://docs.base.org/specifications/base-protocol/proofs/registrar): Specification of the registrar and the hinted P-384 flow used to register AWS Nitro Enclave signer identities on L1. - [TEE Prover](https://docs.base.org/specifications/base-protocol/proofs/tee-prover): Specification of the TEE prover, an offchain service that re-executes L2 block ranges inside AWS Nitro Enclaves to produce signed proof material for AggregateVerifier games. diff --git a/docs/specifications/base-protocol/proofs/registrar.mdx b/docs/specifications/base-protocol/proofs/registrar.mdx index 48668a06a..632c17471 100644 --- a/docs/specifications/base-protocol/proofs/registrar.mdx +++ b/docs/specifications/base-protocol/proofs/registrar.mdx @@ -1,412 +1,312 @@ --- title: "Registrar" -description: "Specification of the registrar, an offchain service that maintains the onchain registry of accepted TEE signer identities via attestation ZK proofs." +description: "Specification of the registrar and the hinted P-384 flow used to register AWS Nitro Enclave signer identities on L1." --- -The registrar is an offchain service that maintains the onchain registry of accepted TEE signer -identities. It discovers running TEE prover instances, fetches AWS Nitro Enclave attestation -documents from each enclave, generates a ZK proof that the attestation is well-formed, and submits -the resulting signer registration to [`TEEProverRegistry`](https://github.com/base/contracts/blob/main/src/L1/proofs/tee/TEEProverRegistry.sol) -on L1. It also deregisters signers whose backing instances are no longer reachable, and revokes -intermediate certificates that AWS has withdrawn. +The registrar is an offchain service that maintains the signer set in +[`TEEProverRegistry`](https://github.com/base/contracts/blob/main/src/L1/proofs/tee/TEEProverRegistry.sol). +It discovers Base TEE prover instances, obtains an AWS Nitro attestation for each enclave signer, +generates P-384 verification hints locally, caches the attestation certificate chain on L1, and +submits the final signer registration. -A registrar is operated by Base. The proof system trusts only signers that this registrar has -registered, so registrar correctness is a prerequisite for accepting TEE proofs onchain. Its output -is still self-validating: the attestation ZK proof, the enclave PCR0 measurement, and the signer -public key are all checked by `TEEProverRegistry` and [`NitroEnclaveVerifier`](https://github.com/base/contracts/blob/main/src/L1/proofs/tee/NitroEnclaveVerifier.sol) -before the signer becomes valid. +This flow replaces the previous RISC Zero attestation proof and external Boundless proving path. +There is no runtime backend selector or fallback to ZK verification. The TEE proof format, +`TEEVerifier`, `AggregateVerifier`, `TEE_IMAGE_HASH`, and SP1 state-proof behavior are unchanged. +Registration requires the hinted-compatible registrar and prover-host signer API; legacy registrar +artifacts are retained only for rollback. ## Responsibilities A conforming registrar performs the following work: -1. Discover the current set of TEE prover instances behind the production load balancer. -2. Fetch the per-enclave signer public keys and Nitro attestation documents from each instance. -3. Optionally check the attestation certificate chain against AWS-published CRLs and against the - onchain durable revocation set. -4. Generate a ZK proof of attestation correctness for every enclave that is not yet registered. -5. Submit `TEEProverRegistry.registerSigner()` for newly attested signers. -6. Submit `TEEProverRegistry.deregisterSigner()` for onchain signers whose instances are gone. -7. Submit `NitroEnclaveVerifier.revokeCert()` for intermediate certificates discovered to be - revoked. -8. Recover in-flight proof requests across process restarts without re-spending proving work. - -The registrar does not gate which PCR0 measurements are accepted. Registration is PCR0-agnostic so -that the next image's signers can be pre-registered ahead of a hardfork. Acceptance of proofs -produced by a given signer is enforced onchain by [`TEEVerifier`](https://github.com/base/contracts/blob/main/src/L1/proofs/tee/TEEVerifier.sol) -against the current `TEE_IMAGE_HASH` of the active game implementation. - -The registrar also does not create proposals, generate proof material for proposals or disputes, -or dispute invalid state transitions. Those responsibilities belong to the proposer, the TEE -provers, and the challenger. - -## Startup Configuration - -At startup, the registrar connects to: - -- an L1 execution RPC for contract reads and transaction submission -- AWS APIs for ELBv2 target health and EC2 instance metadata -- a JSON-RPC endpoint on each discovered TEE prover instance -- a proving backend (Boundless marketplace or a self-hosted RISC Zero prover) -- `TEEProverRegistry` -- an optional `NitroEnclaveVerifier`, required only when CRL checking is enabled - -The registrar reads no contract configuration at startup beyond the registry and verifier -addresses provided by the operator. It treats every onchain signer it has not seen in its own -instance set as an orphan candidate, so a single registrar must be the sole writer for a given -registry. +1. Discover TEE prover instances behind the configured AWS load balancer. +2. Fetch each enclave's secp256k1 public key and a fresh Nitro attestation bound to that signer. +3. Parse the COSE and X.509 data without changing the signed encodings. +4. Validate the expected signer, nonce, PCR0, trust anchor, certificate order, and freshness locally. +5. Generate the checked P-384 inverse hints required by the onchain verifier. +6. Reuse valid cached certificates and cache missing certificates in parent-first order. +7. Submit the final attestation to `TEEProverRegistry.registerSigner()`. +8. Optionally monitor AWS certificate revocation lists and persist confirmed revocations on L1. +9. Deregister signers whose backing prover instances are no longer active. + +The registrar does not select the accepted enclave image. Registration records the attested PCR0, +but [`TEEVerifier`](https://github.com/base/contracts/blob/main/src/L1/proofs/tee/TEEVerifier.sol) +accepts a signer only when its recorded image hash matches the active `TEE_IMAGE_HASH`. This allows +the next image's signers to be registered before an image rotation without allowing them to produce +accepted proofs early. + +## Architecture + +```mermaid TEE Signer Registration lines wrap expandable +flowchart LR + registrar[Registrar] + prover[TEE prover instance] + registry[TEEProverRegistry] + validator[NitroValidator] + certs[CertManager] + p384[P384Verifier] + + prover -- "signer key + attestation" --> registrar + registrar -- "cache certificate + hints" --> certs + registrar -- "attestation TBS + signature + hints" --> registry + registry --> validator + validator --> certs + certs --> p384 + validator --> p384 +``` -## Driver Loop +The onchain validation stack contains three contracts: -The registrar runs a single driver loop: - -1. Discover the current instance set. -2. Process every instance concurrently, bounded by `max_concurrency`. -3. Read the onchain signer set. -4. Deregister orphan signers. -5. Sleep `poll_interval` seconds, or exit on cancellation. - -The loop runs `step()` once on startup before sleeping. Cancellation is observed promptly between -ticks and inside long-running tx retries so the service can shut down without leaving partial -state. - -## Instance Discovery - -The registrar uses AWS ALB target group polling. DNS, SRV, and Kubernetes discovery are not -supported. - -Each discovery cycle: - -1. Calls `elasticloadbalancingv2.DescribeTargetHealth(target_group_arn)`. -2. Filters out non-instance targets (target IDs that do not start with `i-`). -3. Deduplicates instance IDs that appear on more than one port. -4. Calls `ec2.DescribeInstances(instance_ids)` to read each instance's private IP and launch time. -5. Builds JSON-RPC endpoint URLs of the form `http://{private_ip}:{prover_port}` and pairs each - with its ALB-reported health state. - -Health states map as follows: - -| AWS state | Internal state | `should_register()` | -| ------------ | -------------- | ------------------- | -| `initial` | `Initial` | true | -| `healthy` | `Healthy` | true | -| `draining` | `Draining` | false | -| anything else| `Unhealthy` | false | - -`Unhealthy` instances within `unhealthy_registration_window` seconds of `launch_time` are still -allowed to register. This is a warm-up grace period: it lets a new instance whose JSON-RPC -endpoint is briefly slow finish enclave attestation and registration before the next ALB health -check would deregister it. The window must be smaller than the Boundless proving timeout so that -a started proof can complete before the instance becomes ineligible. - -Discovery failures abort that tick and skip orphan cleanup. They do not deregister live signers. - -## Per-Instance Processing - -For each discovered instance, the registrar: - -1. Calls `enclave_signerPublicKey` to fetch the per-enclave SEC1 public keys. Each instance can - host multiple enclaves and each enclave has its own signer key. -2. Derives the Ethereum signer address from each public key as the last 20 bytes of - `keccak256(uncompressed_pubkey_xy)`. -3. Returns immediately if no signers were reported. The address set still contributes nothing for - this instance and the call is a no-op. -4. Decides whether the instance is currently registerable: - - `Initial` and `Healthy` instances proceed. - - `Unhealthy` instances within the warm-up window proceed. - - All other instances contribute their addresses to the active set but do not generate new - proofs or transactions. -5. Generates a single 32-byte random nonce and calls `enclave_signerAttestation` once with that - nonce. The nonce binds every per-enclave attestation in the returned batch to the same - freshness commitment. -6. Performs CRL checks once per batch when CRL checking is enabled. Each enclave has its own - signing key, but AWS Nitro attestations are signed by the parent EC2 instance's Nitro - Hypervisor, whose signing key is endorsed by a per-instance AWS-issued certificate chain. - Every enclave on the same instance therefore produces an attestation under the same parent - chain, so a single CRL check per instance is sufficient. -7. For each signer address, runs the registration pipeline. - -All reachable instances contribute to the active signer set, including `Draining` and `Unhealthy` -ones. This prevents an instance that is rotating in or out from being deregistered prematurely. - -## Attestation Proof Generation - -The registrar produces proof material for every signer not yet onchain by calling an -`AttestationProofProvider`. The provider returns: - -```text Attestation Proof Provider Output -output // ABI-encoded VerifierJournal (PCRs, public key, timestamp, cert hashes) -proofBytes // Groth16 seal -``` +| Contract | Role | +| --- | --- | +| `P384Verifier` | Verifies P-384 signatures while checking caller-supplied modular inverse hints. | +| `CertManager` | Pins the AWS Nitro root, verifies and caches non-root certificates, and enforces certificate expiry and revocation. | +| `NitroValidator` | Parses the signed Nitro attestation, re-walks the cached certificate chain, and verifies the final COSE signature. | + +`TEEProverRegistry` holds an immutable `NitroValidator` reference. The registrar discovers +`CertManager` through `TEEProverRegistry.NITRO_VALIDATOR()` and `NitroValidator.certManager()`; +operators do not configure those addresses separately. -`output` is the `VerifierJournal` consumed by `NitroEnclaveVerifier.verify()` during -`registerSigner()`. `proofBytes` is the Groth16 SNARK that proves the journal corresponds to a -valid Nitro attestation document. +## Driver Loop + +The registrar runs one polling loop: -The registrar supports two backends: +1. Query AWS ALB and EC2 for the current prover instances. +2. Probe `/readyz` on every non-draining target. The load balancer's `/healthz` is registration-gated, + so it cannot be used to bootstrap registration. +3. Resolve signer public keys and attestations concurrently, bounded by `max_concurrency`. +4. Start one registration task per eligible signer and cancel tasks whose signer is no longer eligible. +5. Read the onchain signer set and deregister unprotected signers when discovery was conclusive. +6. Sleep for `poll_interval`, or stop on cancellation. -| Backend | Description | -| ----------- | ------------------------------------------------------------------------------------------------------------ | -| `boundless` | Submits the proving job to the Boundless marketplace using a dedicated wallet. | -| `direct` | Loads the guest ELF locally and proves via `risc0_zkvm::default_prover()`, routing to Bonsai or a local prover according to RISC Zero environment variables. | +Only instances that pass `/readyz` are eligible for new registrations. Draining instances still +contribute their known signer addresses to the active set so a rotation does not immediately +deregister them. -Both backends are valid production paths. `boundless` is the primary production backend. -`direct` is also used for local development and tests, but it is suitable for production fallback -when an operator needs to bypass the marketplace, for example during a Boundless incident or for -private-deployment scenarios. +When an instance disappears or becomes unhealthy, the registrar preserves its last-known signers +for `instance_cache_ttl_cycles`. It skips the entire orphan pass while any instance remains +unresolved. Pending registration tasks are also protected from orphan cleanup. -For Boundless, the registrar submits a `RequestParams` containing the program URL, the attestation -input, the expected `image_id`, and a `prefix_match(image_id)` requirement so a fulfilled request -cannot be replayed against a different program. Onchain Boundless submissions are serialized -behind a mutex to avoid wallet nonce races. +Discovery supports AWS ELBv2 target groups whose targets are EC2 instances. Targets whose IDs do +not start with `i-` are ignored. AWS API errors and missing EC2 data abort the tick and skip orphan +cleanup, but an empty target group is a conclusive result. The last-known-signer cache is in memory +and starts empty after a process restart. Operators must therefore configure and monitor the target +group carefully: a cold registrar pointed at an empty target group has no cached signers to protect. -### Restart Recovery +## Attestation Challenge -The registrar process is itself ephemeral. Across restarts, it must not re-spend proving work and -must not submit stale proofs. Boundless `RequestId` slots are derived deterministically: +Each signer receives a deterministic 32-byte nonce: -```text Request Index Derivation -request_index(signer, attempt) = u32::from_be_bytes(keccak256(signer || attempt)[..4]) +```text Attestation Nonce +keccak256( + "base-proof-tee-registrar:attestation-nonce:v1" || + teeProverRegistryAddress || + signerAddress +) ``` -For each signer, the registrar probes `max_recovery_attempts` consecutive deterministic slots -before submitting a fresh request. The action depends on the slot status: +The registrar requests one attestation per signer with that nonce. It rejects the response unless: -| Slot status | Registrar action | -| ------------- | --------------------------------------------------------------------------------- | -| `Unknown` | Record the first such slot as the candidate fresh-submission slot; keep scanning. | -| `Locked` | Resume `wait_for_request_fulfillment` and use the resulting receipt. | -| `Fulfilled` | Fetch the receipt and check journal freshness before accepting it. | -| `Expired` | Skip the slot permanently; continue scanning. | +- the attested `public_key` derives to the expected signer address; +- the attested nonce exactly matches the deterministic challenge; +- PCR0 is present, is 48 bytes, and is not the all-zero debug-mode measurement; +- the certificate chain starts at the pinned AWS Nitro root; +- the certificate chain is ordered parent-first and ends in one leaf certificate; and +- the attestation remains within the configured local freshness window. -A `RequestIsNotLocked` revert encountered mid-scan is treated as in-flight and short-circuits to -waiting on that slot. +The deterministic challenge binds the attestation to one registry and signer without requiring +registrar state across restarts. `TEEProverRegistry` independently enforces timestamp freshness, +but nonce matching is a registrar policy check because `NitroValidator` only exposes the signed +nonce to its caller. -If a recovered receipt's attestation timestamp is older than `max_attestation_age`, the registrar -discards it and submits a fresh request in the candidate slot. The default freshness window is -3300 seconds, kept strictly under the onchain `MAX_AGE` of 3600 seconds so a recovered proof can -still be submitted before it ages out onchain. +## Registration Plan -After an `ExecutionReverted` from `registerSigner()`, the signer is added to a per-process -`recovery_blocked` set. The next cycle skips the recovery scan for that signer and submits a fresh -request, so a known-bad recovered proof is never tried twice. The set is cleared on restart, which -gives one fresh attempt per process even for previously blocked signers. +The registrar preserves the exact protected-header and payload encodings from the input +`COSE_Sign1` document when constructing the signed `Sig_structure`. Re-encoding signed CBOR would +change the message and invalidate the AWS signature. -## Registration Transactions +For parity with the pinned `NitroValidator`, the registrar accepts an optional compact `0xD2` tag +followed by the compact `0x84` `COSE_Sign1` array, the ES384 protected header `0x44a1013822`, a +96-byte P-384 signature, and no trailing COSE or TBS data. The payload, `pcrs`, and `cabundle` +containers may use definite or indefinite lengths. Unknown payload keys are skipped, but recognized +keys must be unique. -For each unregistered signer, the registrar: +The parsed plan contains: -1. Calls `TEEProverRegistry.isRegisteredSigner(signer)`. If true, the signer is skipped. -2. Generates or recovers proof material as described above. -3. ABI-encodes `registerSigner(output, proofBytes)`. -4. Submits the transaction through the L1 transaction manager. -5. Retries failed submissions according to the rules below. -6. On a successful receipt, increments the registration counter. +- the signer derived from the 65-byte `0x04 || x || y` secp256k1 public key; +- PCR0, timestamp, and nonce; +- the pinned root certificate; +- non-root CA certificates followed by the leaf certificate; +- the exact attestation to-be-signed bytes and 96-byte P-384 signature; and +- cache and revocation identifiers matching `CertManager`. -The transaction retry rules are: +The pinned root cache key is `keccak256(root DER)`. Every non-root cache key is +`keccak256(TBSCertificate DER)`, excluding the malleable outer ECDSA signature. Non-root revocation +uses `keccak256(issuerHash || serialHash)`. `issuerHash` hashes the issuer Name content octets, +excluding its DER tag and length. `serialHash` hashes the serial INTEGER content octets, including a +leading `0x00` used for DER sign extension. These identities remain stable across equivalent outer +certificate encodings. -| Failure | Required behavior | -| ----------------------------- | ------------------------------------------------------------------------------------------------------- | -| Retryable error | Sleep `tx_retry_delay`, then retry, up to `max_tx_retries` total attempts. | -| `ExecutionReverted` revert | Block recovery for this signer so the next cycle generates a fresh proof, then return the error. | -| Insufficient funds, fee cap | Treat as non-retryable. Surface the error and stop attempting this signer for the current cycle. | -| Reverted receipt | Treat as a transaction failure even when submission succeeded. | -| Reported error after mining | Re-read `isRegisteredSigner(signer)`. If true, treat the attempt as success. | +## P-384 Hints -The post-error reconciliation is required because fee-bumping and nonce races can return errors -even when the underlying transaction has already been mined. Without the recheck, the registrar -would burn proving work generating a fresh proof for an already-registered signer. +AWS signs Nitro certificates and attestations with ECDSA over P-384. P-384 verification requires +many modular inversions, which are expensive to compute in the EVM. The registrar computes each +inverse offchain and supplies it as a hint. -Transaction submission is cancellation-aware: both the active send and the inter-attempt sleep -abort cleanly on shutdown, so the next process starts from a clean nonce state without committing -a partial transaction. +For every division by `b` modulo a prime `m`, the contract checks: -## Orphan Deregistration +```text Inverse Check +b * hint == 1 (mod m) +``` -After processing every instance, the registrar reconciles the onchain signer set against the -active set: +The hint is used only after this equality holds. Since an invertible value has one inverse modulo a +prime, a passing hint is the same value the contract would have computed. Incorrect, truncated, or +surplus hints revert. Hints affect liveness, not correctness: a faulty generator can prevent a +registration but cannot make an invalid signature pass. -1. If discovery failed for this tick, skip cleanup. -2. If cancellation was requested, skip cleanup. -3. Compare the number of reachable instances against the total discovered instances. If - `reachable_instances * 2 <= total_instances`, skip cleanup. -4. Read the onchain set with `TEEProverRegistry.getRegisteredSigners()`. -5. Compute `orphans = onchain_signers \ active_signers`. -6. For each orphan, in order: - 1. Recheck `isRegisteredSigner(signer)`. Skip if it returns false. - 2. ABI-encode `deregisterSigner(signer)` and submit it through the transaction manager. +Each hint stream is a concatenation of 48-byte big-endian inverses in the verifier's deterministic +consumption order. The registrar generates one stream for every non-root certificate signature and +one for the final attestation signature. Production hint generation is native Rust and does not +invoke Node, Go, or an external proving service. -The majority-reachable guard prevents a transient AWS or VPC outage from deregistering most of -the prover fleet at once. The per-orphan `isRegisteredSigner` recheck is a race guard: the set -returned by `getRegisteredSigners()` is read once per cycle, and another writer could have -deregistered a signer between that read and this transaction. Skipping already-deregistered -addresses avoids wasted gas on a no-op transaction. +## Certificate Cache -This procedure assumes a single registrar per `TEEProverRegistry`. Two registrars sharing a -registry would each treat the other's signers as orphans. +`CertManager` stores the pinned AWS Nitro root at deployment. The registrar processes every +remaining certificate in parent-first order: -## Certificate Revocation +1. Read the candidate's cached metadata and revocation state. +2. If cached, require the expected CA or leaf role, an unexpired validity period, the original + parent binding, and a complete unrevoked path to the pinned root. +3. If not cached, call `verifyCACertWithHints()` or `verifyClientCertWithHints()` with the DER + certificate, parent cache key, and signature hints. +4. Re-read state after the transaction. A transaction error is treated as success if the expected + usable cache entry is now present. -When the operator enables CRL checking, the registrar enforces revocation using two layers in -order. Both are required to make CRL handling safe. +Cache writes are permissionless because all certificate data and hints are verified onchain. +Per-certificate locks prevent concurrent signer tasks from submitting duplicate cache transactions +for a shared chain. On restart or after a partial failure, the registrar reads the cache again and +continues from the first missing certificate. -### Layer 1: Onchain Durable Revocation Pre-Check +For a typical Nitro chain with three non-root CAs, transaction counts are: -For each intermediate certificate in the attestation chain, the registrar reads -`NitroEnclaveVerifier.revokedCerts(certPathDigest)`. Any hit blocks registration for that batch -and skips Layer 2 entirely. +| Cache state | Transactions | +| --- | ---: | +| Empty | 5: three CA cache writes, one leaf cache write, one registration | +| CA chain cached, new leaf | 2: one leaf cache write, one registration | +| CA chain and leaf cached | 1: registration only | -This layer protects against a known attack against the cached-cert path: an intermediate that was -once revoked onchain could be reintroduced through a later `_cacheNewCert` write if its CRL entry -is later pruned by AWS. Reading the durable mapping first ensures a revoked cert cannot be -silently rehabilitated. +Each signature verification is split into its own transaction so it remains below the EIP-7825 +per-transaction gas limit. Final registration intentionally supplies no certificate hints; +`NitroValidator` succeeds only if the complete chain is already cached and usable. -RPC errors against `revokedCerts` fail open and fall through to Layer 2, but are counted as -revocation check errors. `RegistrationDriver::new` requires a `NitroEnclaveVerifier` client when -CRL checking is enabled and rejects misconfiguration at startup. +## Final Registration -### Layer 2: AWS CRL Distribution Points +After the cache is ready, the registrar calls: -For intermediates that pass Layer 1, the registrar: +```solidity Registration Call +TEEProverRegistry.registerSigner(attestationTbs, signature, hints) +``` -1. Parses each CRL distribution point from the chain. -2. Validates the URL host against an allowlist requiring the `.amazonaws.com` suffix and the - `nitro-enclave` keyword. HTTP redirects are disabled and responses are bounded to 10 MiB. -3. Fetches the CRL with a configurable timeout. -4. Searches for the certificate's serial number. -5. For each revoked intermediate, submits `NitroEnclaveVerifier.revokeCert(certPathDigest)`. -6. Returns true if any intermediate is revoked, blocking registration for the batch. +The registry permits only its owner or manager to call this method. It delegates cryptographic and +certificate validation to `NitroValidator`, then applies Base-specific policy: -`revokeCert` failures are counted but do not abort registration of other instances on the same -tick. The submitted revocations transition Layer 1 to a hit on the next cycle so subsequent -registrations can short-circuit without re-fetching the CRL. +1. Reject attestations at least 60 minutes old. +2. Reject attestations whose second-level timestamp is greater than or equal to `block.timestamp`. +3. Require PCR0 at index zero, exactly 48 bytes, and not the debug-mode measurement. +4. Require a 65-byte uncompressed secp256k1 public key. +5. Derive the signer as the last 20 bytes of `keccak256(x || y)`. +6. Store the signer as registered and record `keccak256(PCR0)` as its image hash. -## Pending Registration Lifecycle +The registrar uses a 3,300-second default local freshness limit, leaving submission headroom under +the registry's 3,600-second limit. It checks freshness before every certificate, revocation, and +registration transaction so a multi-transaction cold flow stops before submitting stale material. -Each per-signer pipeline is keyed by Ethereum signer address. The Boundless proof slot for a -signer transitions through: +Before each registration attempt, and after ambiguous transaction errors, the registrar reads +`isRegisteredSigner(signer)`. An observed registration is treated as success. Retryable transaction +errors use bounded exponential backoff; reverted receipts and non-retryable errors fail the current +task. -```mermaid Pending Registration Lifecycle lines wrap expandable -flowchart TB - Start([process_instance]) --> Recover[Recovery scan] - Recover -->|Locked slot| Wait[wait_for_request_fulfillment] - Recover -->|Fulfilled slot| Fresh{Journal fresh?} - Recover -->|All slots Unknown/Expired| Submit[Submit fresh request] - Recover -->|Blocked recovery| Submit +## Certificate Revocation - Fresh -->|yes| Receipt[Use recovered receipt] - Fresh -->|no| Submit - Wait --> Receipt - Submit --> Wait +`CertManager` maintains a durable revocation set and an immutable pinned AWS Nitro root. The owner +can revoke or unrevoke the root as an emergency halt, set the non-root revoker, and unrevoke +certificate identities. The revoker role can revoke non-root issuer/serial identities. Revocation +is checked during cold verification, cache reuse, and the final cached-chain walk. - Receipt --> Send[tx_manager.send registerSigner] - Send -->|Ok| Done([Registered]) - Send -->|Retryable| Send - Send -->|ExecutionReverted| Block[Block recovery for signer] - Block --> Done -``` +For every registration attempt, the registrar checks the pinned root and every planned certificate +against `CertManager.isRevoked()`. A confirmed onchain revocation rejects the registration. -A pending recovery state, a fulfilled-but-stale receipt, and an `ExecutionReverted` revert all -funnel back to a fresh submission on the next tick rather than wedging the signer. +When CRL fetching is additionally enabled, the registrar: -## Onchain Interactions +1. Fetches CRLs only from allowlisted AWS Nitro hosts, without redirects and with a 10 MiB response + limit. +2. Matches intermediate certificate serial numbers against the CRLs. +3. Calls `CertManager.revokeCert()` for confirmed revocations before rejecting the registration. -The registrar uses the following contract calls. `TEEProverRegistry.isValidSigner()` is -intentionally not called by the registrar; that predicate is enforced by `TEEVerifier` at proof -submission time and includes an image-hash match that the registrar cannot satisfy by itself. +CRL fetch and parse failures are fail-open and retried on later cycles. Confirmed onchain +revocations always fail closed. -| Contract | Method | Caller path | -| -------------------------------------------------------------------------------------------------------------------------- | ------------------------------- | --------------------------------------------------- | -| [`TEEProverRegistry`](https://github.com/base/contracts/blob/main/src/L1/proofs/tee/TEEProverRegistry.sol) | `registerSigner(output, proof)` | Per-signer registration transaction. | -| [`TEEProverRegistry`](https://github.com/base/contracts/blob/main/src/L1/proofs/tee/TEEProverRegistry.sol) | `deregisterSigner(signer)` | Per-orphan deregistration transaction. | -| [`TEEProverRegistry`](https://github.com/base/contracts/blob/main/src/L1/proofs/tee/TEEProverRegistry.sol) | `isRegisteredSigner(signer)` | Pre-check, post-error reconciliation, orphan race guard. | -| [`TEEProverRegistry`](https://github.com/base/contracts/blob/main/src/L1/proofs/tee/TEEProverRegistry.sol) | `getRegisteredSigners()` | Once per cycle for orphan computation. | -| [`NitroEnclaveVerifier`](https://github.com/base/contracts/blob/main/src/L1/proofs/tee/NitroEnclaveVerifier.sol) | `revokeCert(certHash)` | When AWS CRL revokes an intermediate. | -| [`NitroEnclaveVerifier`](https://github.com/base/contracts/blob/main/src/L1/proofs/tee/NitroEnclaveVerifier.sol) | `revokedCerts(certHash)` | Layer-1 onchain durable revocation pre-check. | +## Orphan Deregistration -PCR0 enforcement happens onchain at proof submission, not at registration. The registrar registers -any enclave whose Nitro attestation verifies, regardless of its PCR0. This allows the next image's -fleet to be brought up and pre-registered in advance of a hardfork; those signers cannot produce -accepted proposals until the active game implementation's `TEE_IMAGE_HASH` matches their -registered image hash. +After registration task reconciliation, the registrar computes: -## Service Lifecycle +```text Orphan Formula +orphans = registered signers - active signers - pending signers +``` -At startup, the registrar: +It calls `deregisterSigner()` for each orphan only when discovery completed without unresolved +instances and the configured last-known-signer grace period has expired. Deregistration removes the +registered flag and stored image hash. This flow assumes one registrar controls a given registry; +independent registrars would otherwise classify each other's signers as orphans. -1. Parses CLI configuration and validates it. -2. Initializes tracing and installs the `rustls` ring crypto provider. -3. Installs a signal handler that triggers a cancellation token. -4. Initializes Prometheus metrics, including L1 wallet and Boundless wallet balance monitoring. -5. Builds the L1 provider, transaction manager, AWS SDK clients, and discovery client. -6. Builds the registry client and the optional Nitro verifier client. -7. Builds the proof provider for the configured backend. -8. Starts the health server and marks readiness. -9. Starts the driver loop. +## Upgrade Compatibility -The health endpoint reports ready as soon as wiring completes. Connectivity gating is intentionally -omitted because the registrar is outbound-only. +The hinted migration upgrades the existing `TEEProverRegistry` proxy implementation. It preserves +the proxy storage layout, owner, manager, game type, proposers, registered signers, and stored signer +image hashes. The active registrar and registry support only the new three-argument hinted API. -Each driver tick: +The migration does not change: -1. Discovers instances. -2. Processes instances concurrently. -3. Computes orphans subject to the majority-reachable guard. -4. Submits deregistration transactions for confirmed orphans. +- Nitro enclave signer generation or attestation production; +- PCR0-based image selection in `TEEVerifier`; +- `AggregateVerifier` behavior; +- TEE proposal and dispute proof formats; or +- SP1 state-proof behavior. -Shutdown is driven by a cancellation token. The driver loop exits, in-flight per-instance futures -are dropped, the readiness flag clears, the `up` metric is set to zero, and the health server is -joined. +Rollback requires the previously deployed registry implementation, legacy verifier, registrar +artifact, and proving credentials. The new source does not contain a mixed-generation compatibility +path. Certificate cache entries created by the hinted flow are independent state and do not affect a +legacy rollback. ## Operator Inputs -A registrar needs: - -- L1 RPC endpoint and chain ID. -- `TEEProverRegistry` address. -- AWS region and ALB target group ARN. -- Prover JSON-RPC port shared by the fleet. -- L1 transaction signer (local key, or remote signing endpoint plus expected address). -- Proving backend selection: `boundless` or `direct`. -- For `boundless`: marketplace RPC URL, dedicated wallet key, guest program URL, polling interval, - prove timeout, recovery attempt limit, and attestation freshness window. -- For `direct`: path to the guest ELF. -- Poll interval, prover JSON-RPC timeout, max concurrency, max transaction retries, transaction - retry delay, and the unhealthy registration warm-up window. +A registrar requires: -Optional inputs: +- an L1 RPC endpoint and `TEEProverRegistry` address; +- AWS region and ALB target group ARN; +- the prover JSON-RPC port; +- an L1 transaction signer and transaction-manager limits; +- attestation freshness, polling, timeout, concurrency, cache-grace, and retry settings; and +- health, logging, and Prometheus metrics settings. -- CRL checking enable flag. -- `NitroEnclaveVerifier` address, required when CRL checking is enabled. -- CRL fetch timeout. -- Health server bind address and port. -- Logging filter and Prometheus metrics settings. +No Boundless wallet, marketplace endpoint, RISC Zero program identifier, guest ELF, or proof-backend +selection is used. CRL monitoring is optional and requires the registrar transaction signer to hold +the configured `CertManager` revoker role. In the current CLI, +`--crl-nitro-verifier-address` or `BASE_REGISTRAR_CRL_NITRO_VERIFIER_ADDRESS` enables CRL fetching. +This legacy-named value is only an enable flag; contract discovery still follows the registry to +`NitroValidator` and then `CertManager`. ## Safety Requirements -A registrar implementation must preserve these safety properties: - -- Do not deregister live signers because of a transient AWS or VPC outage. Apply a - majority-reachable guard before any deregistration. -- Treat `Draining` and `Unhealthy` instances as part of the active set as long as their JSON-RPC - endpoint responds, so rotations do not race deregistration. -- Use a fresh random nonce per instance batch and pass it to the enclave attestation request so - the verifier journal carries an unguessable freshness commitment. -- Derive Boundless request slots deterministically from the signer address so a restarted process - can recover in-flight proving work without spending fresh proof costs. -- Reject recovered proofs whose attestation timestamp is older than `max_attestation_age` to keep - recovered proofs strictly inside the onchain `MAX_AGE` window. -- Block recovery for a signer after an `ExecutionReverted` so the next cycle proves freshly - rather than re-submitting the same bad proof. -- Recheck `isRegisteredSigner` after a transaction error to absorb fee-bump and nonce-race false - negatives. -- Recheck `isRegisteredSigner` for every orphan candidate immediately before submitting a - deregistration, so a concurrent writer or earlier in-flight tx cannot cause a redundant - deregistration transaction. -- When CRL checking is enabled, run the onchain durable revocation pre-check before fetching - network CRLs so a previously revoked intermediate cannot be silently rehabilitated. -- Restrict CRL fetches to allowlisted hosts and bound the response size to defeat SSRF and - resource-exhaustion attacks. -- Treat unavailable AWS APIs, unreachable prover endpoints, transient RPC errors, and Boundless - polling failures as retryable conditions for the next tick rather than as deregistration or - failure signals. +A conforming implementation must preserve these properties: + +- Preserve the exact signed COSE encodings when constructing the attestation TBS. +- Match the attested signer and deterministic nonce before any transaction is submitted. +- Pin the AWS Nitro root and reject malformed, expired, revoked, or parent-mismatched chains. +- Generate hints in the exact verifier order and rely on onchain checks for every supplied inverse. +- Cache certificates parent-first and recover by reading onchain state after every ambiguous result. +- Recheck freshness before each costly transaction in a cold registration. +- Recheck registration state before submission and after ambiguous transaction errors. +- Do not deregister signers while discovery is unresolved or during the configured grace period. +- Keep PCR0 acceptance at proof-submission time so image rotations can be staged safely. +- Do not add an unhinted, ZK, or externally proved runtime fallback to the hinted registration path. diff --git a/docs/upgrades/upcoming-features.mdx b/docs/upgrades/upcoming-features.mdx index 62febb75a..b54ccd542 100644 --- a/docs/upgrades/upcoming-features.mdx +++ b/docs/upgrades/upcoming-features.mdx @@ -17,7 +17,7 @@ Targets are ballpark quarters and may change. A feature moves onto a named upgra | B20 Improvements | Pay fees in B20s, scheduled multiplier updates, and composite policies for the B20 token standard. | [B20 changelog](/specifications/b20/changelog) | Q3 2026 | | Validity Transactions | A transaction type with onchain predicate checks for safer, conditional execution. | [Validity Transactions](/specifications/build-transaction/validity-transactions) | Q3 2026 | | Dynamic Upgrades | An onchain upgrade schedule that lets nodes activate forks live, without a client restart. | [Dynamic Upgrades](/upgrades/cobalt/dynamic-upgrades) | Q3 2026 | -| TEE Migration | Migrate Base infrastructure to run inside a Trusted Execution Environment. | Specification pending | Q3 2026 | +| TEE Registration Migration | Replace ZK-based Nitro attestation proofs with checked P-384 hints for TEE signer registration. | [Registrar specification](/specifications/base-protocol/proofs/registrar) | Q3 2026 | | Native Account Abstraction (EIP-8130) | Onchain smart accounts, scoped session keys, and native gas sponsorship, with no bundlers or relays. | [Native Account Abstraction](/specifications/native-account-abstraction) | TBD | ## How Features Ship From 2c3b4a577b175def21a634e7bce7786269cfebf1 Mon Sep 17 00:00:00 2001 From: Leopold Joy Date: Fri, 11 Sep 2026 21:55:31 +0100 Subject: [PATCH 2/5] docs: clarify permissioned TEE registration Co-authored-by: OpenCode --- docs/upgrades/upcoming-features.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/upgrades/upcoming-features.mdx b/docs/upgrades/upcoming-features.mdx index b54ccd542..89d3ce859 100644 --- a/docs/upgrades/upcoming-features.mdx +++ b/docs/upgrades/upcoming-features.mdx @@ -17,7 +17,7 @@ Targets are ballpark quarters and may change. A feature moves onto a named upgra | B20 Improvements | Pay fees in B20s, scheduled multiplier updates, and composite policies for the B20 token standard. | [B20 changelog](/specifications/b20/changelog) | Q3 2026 | | Validity Transactions | A transaction type with onchain predicate checks for safer, conditional execution. | [Validity Transactions](/specifications/build-transaction/validity-transactions) | Q3 2026 | | Dynamic Upgrades | An onchain upgrade schedule that lets nodes activate forks live, without a client restart. | [Dynamic Upgrades](/upgrades/cobalt/dynamic-upgrades) | Q3 2026 | -| TEE Registration Migration | Replace ZK-based Nitro attestation proofs with checked P-384 hints for TEE signer registration. | [Registrar specification](/specifications/base-protocol/proofs/registrar) | Q3 2026 | +| TEE Registration Migration | Speed up the permissioned registration of new TEE signers by replacing external ZK proving with P-384 hints verified onchain. | [Registrar specification](/specifications/base-protocol/proofs/registrar) | Q3 2026 | | Native Account Abstraction (EIP-8130) | Onchain smart accounts, scoped session keys, and native gas sponsorship, with no bundlers or relays. | [Native Account Abstraction](/specifications/native-account-abstraction) | TBD | ## How Features Ship From fdcf400429f4f3dcb5926114acf01567be471671 Mon Sep 17 00:00:00 2001 From: Leopold Joy Date: Fri, 11 Sep 2026 21:56:50 +0100 Subject: [PATCH 3/5] docs: simplify TEE registration summary Co-authored-by: OpenCode --- docs/upgrades/upcoming-features.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/upgrades/upcoming-features.mdx b/docs/upgrades/upcoming-features.mdx index 89d3ce859..4cf54939d 100644 --- a/docs/upgrades/upcoming-features.mdx +++ b/docs/upgrades/upcoming-features.mdx @@ -17,7 +17,7 @@ Targets are ballpark quarters and may change. A feature moves onto a named upgra | B20 Improvements | Pay fees in B20s, scheduled multiplier updates, and composite policies for the B20 token standard. | [B20 changelog](/specifications/b20/changelog) | Q3 2026 | | Validity Transactions | A transaction type with onchain predicate checks for safer, conditional execution. | [Validity Transactions](/specifications/build-transaction/validity-transactions) | Q3 2026 | | Dynamic Upgrades | An onchain upgrade schedule that lets nodes activate forks live, without a client restart. | [Dynamic Upgrades](/upgrades/cobalt/dynamic-upgrades) | Q3 2026 | -| TEE Registration Migration | Speed up the permissioned registration of new TEE signers by replacing external ZK proving with P-384 hints verified onchain. | [Registrar specification](/specifications/base-protocol/proofs/registrar) | Q3 2026 | +| TEE Registration Migration | Speed up the registration of new TEE signers by replacing external ZK proving with P-384 hints verified onchain. | [Registrar specification](/specifications/base-protocol/proofs/registrar) | Q3 2026 | | Native Account Abstraction (EIP-8130) | Onchain smart accounts, scoped session keys, and native gas sponsorship, with no bundlers or relays. | [Native Account Abstraction](/specifications/native-account-abstraction) | TBD | ## How Features Ship From 3318e09e7ecf1af6838cb89958f89b6f16b298cd Mon Sep 17 00:00:00 2001 From: Leopold Joy Date: Sat, 12 Sep 2026 01:21:49 +0100 Subject: [PATCH 4/5] docs: remove obsolete rollback references Co-authored-by: OpenCode --- docs/specifications/base-protocol/proofs/registrar.mdx | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/docs/specifications/base-protocol/proofs/registrar.mdx b/docs/specifications/base-protocol/proofs/registrar.mdx index 632c17471..560e92347 100644 --- a/docs/specifications/base-protocol/proofs/registrar.mdx +++ b/docs/specifications/base-protocol/proofs/registrar.mdx @@ -12,8 +12,7 @@ submits the final signer registration. This flow replaces the previous RISC Zero attestation proof and external Boundless proving path. There is no runtime backend selector or fallback to ZK verification. The TEE proof format, `TEEVerifier`, `AggregateVerifier`, `TEE_IMAGE_HASH`, and SP1 state-proof behavior are unchanged. -Registration requires the hinted-compatible registrar and prover-host signer API; legacy registrar -artifacts are retained only for rollback. +Registration requires the hinted-compatible registrar and prover-host signer API. ## Responsibilities @@ -273,11 +272,6 @@ The migration does not change: - TEE proposal and dispute proof formats; or - SP1 state-proof behavior. -Rollback requires the previously deployed registry implementation, legacy verifier, registrar -artifact, and proving credentials. The new source does not contain a mixed-generation compatibility -path. Certificate cache entries created by the hinted flow are independent state and do not affect a -legacy rollback. - ## Operator Inputs A registrar requires: From a538e086e051ebade09986f511b92734c6bac28d Mon Sep 17 00:00:00 2001 From: Leopold Joy Date: Sat, 12 Sep 2026 02:00:35 +0100 Subject: [PATCH 5/5] docs: add hinted TEE registration feature spec Co-authored-by: OpenCode --- docs/AGENTS.md | 2 +- docs/docs.json | 1 + docs/llms-full.txt | 2 + docs/llms.txt | 2 + .../proofs/hinted-tee-registration.mdx | 77 +++++++++++++++++++ docs/upgrades/upcoming-features.mdx | 2 +- 6 files changed, 84 insertions(+), 2 deletions(-) create mode 100644 docs/specifications/base-protocol/proofs/hinted-tee-registration.mdx diff --git a/docs/AGENTS.md b/docs/AGENTS.md index fc43973d0..27c7c235a 100644 --- a/docs/AGENTS.md +++ b/docs/AGENTS.md @@ -55,7 +55,7 @@ npx skills add base/base-skills |Specifications/Specifications/Base Protocol/Consensus:specifications/base-protocol/consensus/specification,specifications/base-protocol/consensus/derivation,specifications/base-protocol/consensus/p2p,specifications/base-protocol/consensus/rpc |Specifications/Specifications/Base Protocol/Execution:specifications/base-protocol/execution/l2-execution-engine,specifications/base-protocol/execution/precompiles,specifications/base-protocol/execution/predeploys,specifications/base-protocol/execution/preinstalls |Specifications/Specifications/Base Protocol/Bridging:specifications/base-protocol/bridging/standard-bridges,specifications/base-protocol/bridging/deposits,specifications/base-protocol/bridging/withdrawals,specifications/base-protocol/bridging/cross-domain-messengers,specifications/base-protocol/bridging/base-solana-bridge -|Specifications/Specifications/Base Protocol/Proofs:specifications/base-protocol/proofs/overview,specifications/base-protocol/proofs/challenger,specifications/base-protocol/proofs/proposer,specifications/base-protocol/proofs/registrar,specifications/base-protocol/proofs/tee-prover,specifications/base-protocol/proofs/zk-prover,specifications/base-protocol/proofs/proof-contracts +|Specifications/Specifications/Base Protocol/Proofs:specifications/base-protocol/proofs/overview,specifications/base-protocol/proofs/challenger,specifications/base-protocol/proofs/proposer,specifications/base-protocol/proofs/hinted-tee-registration,specifications/base-protocol/proofs/registrar,specifications/base-protocol/proofs/tee-prover,specifications/base-protocol/proofs/zk-prover,specifications/base-protocol/proofs/proof-contracts |Specifications/Specifications/B20:specifications/b20/specification-overview,specifications/b20/reference/constants-addresses,specifications/b20/reference/errors-events,specifications/b20/reference/invariants-tests,specifications/b20/changelog |Specifications/Specifications/B20/Interfaces:specifications/b20/reference/interfaces/i-activation-registry/index,specifications/b20/reference/interfaces/ib20/index,specifications/b20/reference/interfaces/ib20-asset/index,specifications/b20/reference/interfaces/ib20-factory/index,specifications/b20/reference/interfaces/ib20-stablecoin/index,specifications/b20/reference/interfaces/i-policy-registry/index |Specifications/Specifications/Transactions:specifications/transactions/transaction-ordering,specifications/transactions/transaction-finality,specifications/transactions/network-fees,specifications/transactions/throughput-and-limits,specifications/transactions/troubleshooting-transactions diff --git a/docs/docs.json b/docs/docs.json index ed72e6c4d..3c08131a5 100644 --- a/docs/docs.json +++ b/docs/docs.json @@ -216,6 +216,7 @@ "specifications/base-protocol/proofs/overview", "specifications/base-protocol/proofs/challenger", "specifications/base-protocol/proofs/proposer", + "specifications/base-protocol/proofs/hinted-tee-registration", "specifications/base-protocol/proofs/registrar", "specifications/base-protocol/proofs/tee-prover", "specifications/base-protocol/proofs/zk-prover", diff --git a/docs/llms-full.txt b/docs/llms-full.txt index 534fdd080..d8cb13c7a 100644 --- a/docs/llms-full.txt +++ b/docs/llms-full.txt @@ -264,6 +264,8 @@ const client = createPublicClient({ chain: base, transport: http() }) - [Proposer](https://docs.base.org/specifications/base-protocol/proofs/proposer): Specification of the proposer, an offchain service that turns canonical L2 checkpoint ranges into AggregateVerifier games on L1. +- [Hinted TEE Registration](https://docs.base.org/specifications/base-protocol/proofs/hinted-tee-registration): Migration from external ZK proving to checked P-384 hints for registering new AWS Nitro Enclave signers. + - [Registrar](https://docs.base.org/specifications/base-protocol/proofs/registrar): Specification of the registrar and the hinted P-384 flow used to register AWS Nitro Enclave signer identities on L1. - [TEE Prover](https://docs.base.org/specifications/base-protocol/proofs/tee-prover): Specification of the TEE prover, an offchain service that re-executes L2 block ranges inside AWS Nitro Enclaves to produce signed proof material for AggregateVerifier games. diff --git a/docs/llms.txt b/docs/llms.txt index 612ebb426..ffa1f6cc3 100644 --- a/docs/llms.txt +++ b/docs/llms.txt @@ -198,6 +198,8 @@ - [Proposer](https://docs.base.org/specifications/base-protocol/proofs/proposer): Specification of the proposer, an offchain service that turns canonical L2 checkpoint ranges into AggregateVerifier games on L1. +- [Hinted TEE Registration](https://docs.base.org/specifications/base-protocol/proofs/hinted-tee-registration): Migration from external ZK proving to checked P-384 hints for registering new AWS Nitro Enclave signers. + - [Registrar](https://docs.base.org/specifications/base-protocol/proofs/registrar): Specification of the registrar and the hinted P-384 flow used to register AWS Nitro Enclave signer identities on L1. - [TEE Prover](https://docs.base.org/specifications/base-protocol/proofs/tee-prover): Specification of the TEE prover, an offchain service that re-executes L2 block ranges inside AWS Nitro Enclaves to produce signed proof material for AggregateVerifier games. diff --git a/docs/specifications/base-protocol/proofs/hinted-tee-registration.mdx b/docs/specifications/base-protocol/proofs/hinted-tee-registration.mdx new file mode 100644 index 000000000..2960ac9b1 --- /dev/null +++ b/docs/specifications/base-protocol/proofs/hinted-tee-registration.mdx @@ -0,0 +1,77 @@ +--- +title: "Hinted TEE Registration" +description: "Migration from external ZK proving to checked P-384 hints for registering new AWS Nitro Enclave signers." +--- + +Base is replacing the RISC Zero and Boundless flow used to register new TEE signers with direct +AWS Nitro attestation verification using checked P-384 hints. + +The change makes registration faster and removes the dependency on an external ZK proving service. +It does not change how enclaves produce TEE state proofs or how those proofs are verified. + +## Previous Flow + +The registrar previously sent each Nitro attestation to an external proving service. That service +produced a RISC Zero proof showing that the attestation and its AWS certificate chain were valid. +The registrar then submitted the proof to `TEEProverRegistry` on L1. + +This added an external availability dependency and could delay new signer registration while the ZK +proof was generated. + +## New Flow + +The registrar now: + +1. Fetches a fresh AWS Nitro attestation for the new enclave signer. +2. Generates P-384 modular inverse hints locally. +3. Verifies and caches any missing AWS certificates through `CertManager`. +4. Submits the attestation, its signature, and the final hint stream to `TEEProverRegistry`. +5. Records the signer and its attested PCR0 after all onchain checks pass. + +`TEEProverRegistry` permits only its owner or manager to perform the final registration. Certificate +cache writes are permissionless because `CertManager` verifies the certificate, its parent chain, +and every supplied hint before storing it. + +## Checked Hints + +P-384 verification requires many modular inversions. Computing those inversions in the EVM is +expensive, but checking a proposed inverse is comparatively cheap. The registrar computes the +values offchain and supplies them as hints. + +Every hint is checked onchain before use. Incorrect, missing, or surplus hints revert, so the hint +generator is required for liveness but is not trusted for correctness. A faulty or malicious hint +cannot make an invalid certificate or attestation pass. + +## Certificate Caching + +The AWS Nitro root is pinned in `CertManager`. Non-root CA certificates and the leaf certificate are +verified and cached in parent-first order. Later registrations can reuse cached certificates while +they remain valid and unrevoked. + +For a typical Nitro certificate chain: + +| Cache state | Registration transactions | +| --- | ---: | +| Empty | 5 | +| CA chain cached, new leaf | 2 | +| CA chain and leaf cached | 1 | + +The registrar reads onchain cache state before each write, allowing it to resume after a partial +registration or process restart without repeating completed certificate transactions. + +## Unchanged Behavior + +This migration does not change: + +- signer key generation inside the Nitro Enclave; +- the attestation fields produced by AWS Nitro; +- PCR0-based enclave image selection; +- TEE proposal or dispute proof formats; +- `TEEVerifier` or `AggregateVerifier` behavior; or +- SP1 state-proof verification. + +The existing `TEEProverRegistry` proxy is upgraded without changing its storage layout. Existing +owners, managers, proposers, registered signers, and signer image hashes are preserved. + +For the full registration lifecycle, validation rules, revocation handling, and operator +requirements, see the [Registrar specification](/specifications/base-protocol/proofs/registrar). diff --git a/docs/upgrades/upcoming-features.mdx b/docs/upgrades/upcoming-features.mdx index 4cf54939d..4334df2e6 100644 --- a/docs/upgrades/upcoming-features.mdx +++ b/docs/upgrades/upcoming-features.mdx @@ -17,7 +17,7 @@ Targets are ballpark quarters and may change. A feature moves onto a named upgra | B20 Improvements | Pay fees in B20s, scheduled multiplier updates, and composite policies for the B20 token standard. | [B20 changelog](/specifications/b20/changelog) | Q3 2026 | | Validity Transactions | A transaction type with onchain predicate checks for safer, conditional execution. | [Validity Transactions](/specifications/build-transaction/validity-transactions) | Q3 2026 | | Dynamic Upgrades | An onchain upgrade schedule that lets nodes activate forks live, without a client restart. | [Dynamic Upgrades](/upgrades/cobalt/dynamic-upgrades) | Q3 2026 | -| TEE Registration Migration | Speed up the registration of new TEE signers by replacing external ZK proving with P-384 hints verified onchain. | [Registrar specification](/specifications/base-protocol/proofs/registrar) | Q3 2026 | +| TEE Registration Migration | Speed up the registration of new TEE signers by replacing external ZK proving with P-384 hints verified onchain. | [Hinted TEE Registration](/specifications/base-protocol/proofs/hinted-tee-registration) | Q3 2026 | | Native Account Abstraction (EIP-8130) | Onchain smart accounts, scoped session keys, and native gas sponsorship, with no bundlers or relays. | [Native Account Abstraction](/specifications/native-account-abstraction) | TBD | ## How Features Ship