From d9a5ff72ced21e8afb72d29b017f92c80303f5f8 Mon Sep 17 00:00:00 2001 From: roethke Date: Thu, 10 Sep 2026 16:48:58 -0700 Subject: [PATCH 1/2] docs: add Upcoming Features page for planned protocol work Lists planned protocol features with ballpark quarter targets and spec links, independent of any named upgrade, per Henri's proposal to defer named upgrade pages until an upgrade is scheduled and locked in. Co-Authored-By: Claude --- docs/AGENTS.md | 2 +- docs/docs.json | 1 + docs/llms-full.txt | 2 ++ docs/llms.txt | 2 ++ docs/upgrades/overview.mdx | 4 ++++ docs/upgrades/upcoming-features.mdx | 27 +++++++++++++++++++++++++++ 6 files changed, 37 insertions(+), 1 deletion(-) create mode 100644 docs/upgrades/upcoming-features.mdx diff --git a/docs/AGENTS.md b/docs/AGENTS.md index e3a25e3cd..fc43973d0 100644 --- a/docs/AGENTS.md +++ b/docs/AGENTS.md @@ -91,7 +91,7 @@ npx skills add base/base-skills |SDKs & APIs/Base MCP/Guides:agents/guides/check-balance,agents/guides/send-tokens,agents/guides/swap-tokens,agents/guides/view-history,agents/guides/sign-messages,agents/guides/batch-calls,agents/guides/x402-payments |SDKs & APIs/Base MCP/Skill & Plugins:agents/plugins/index,agents/plugins/custom-plugins |SDKs & APIs/Base MCP/Skill & Plugins/Native Plugins:agents/plugins/native/index,agents/plugins/native/aerodrome,agents/plugins/native/avantis,agents/plugins/native/balancer,agents/plugins/native/bankr,agents/plugins/native/bitrefill,agents/plugins/native/brickken,agents/plugins/native/clawnch,agents/plugins/native/flaunch,agents/plugins/native/gmgn,agents/plugins/native/hydrex,agents/plugins/native/kyberswap,agents/plugins/native/moonwell,agents/plugins/native/morpho,agents/plugins/native/o1-exchange,agents/plugins/native/opensea,agents/plugins/native/printr,agents/plugins/native/uniswap,agents/plugins/native/venice,agents/plugins/native/virtuals,agents/plugins/native/yo -|Upgrades/Overview:upgrades/overview,base-chain/network-information/configuration-changelog +|Upgrades/Overview:upgrades/overview,upgrades/upcoming-features,base-chain/network-information/configuration-changelog |Upgrades/Denim:upgrades/denim/overview,upgrades/denim/200ms-blocks,upgrades/denim/migrate-from-flashblocks |Upgrades/Cobalt:upgrades/cobalt/overview,upgrades/cobalt/dynamic-upgrades,base-chain/specs/reference/b20/changelog/02-cobalt-b20asset-multiplier,base-chain/specs/reference/b20/changelog/02-cobalt-b20-seize,base-chain/specs/reference/b20/changelog/02-cobalt-policyregistry-composite-policy |Upgrades/Beryl:upgrades/beryl/overview,upgrades/beryl/reth-v2,upgrades/beryl/reducing-canonical-withdrawal-delay,upgrades/beryl/b20 diff --git a/docs/docs.json b/docs/docs.json index 32765db79..ed72e6c4d 100644 --- a/docs/docs.json +++ b/docs/docs.json @@ -685,6 +685,7 @@ "group": "Overview", "pages": [ "upgrades/overview", + "upgrades/upcoming-features", "base-chain/network-information/configuration-changelog" ] }, diff --git a/docs/llms-full.txt b/docs/llms-full.txt index 59cda2446..11ae273fd 100644 --- a/docs/llms-full.txt +++ b/docs/llms-full.txt @@ -834,6 +834,8 @@ const client = createPublicClient({ chain: base, transport: http() }) - [Upgrades](https://docs.base.org/upgrades/overview): Track Base network upgrades, activation dates, and the protocol changes included in each release. +- [Upcoming Features](https://docs.base.org/upgrades/upcoming-features): Planned Base protocol features and their ballpark target quarters, tracked independently of a specific network upgrade. + - [Configuration Changelog](https://docs.base.org/base-chain/network-information/configuration-changelog): A log of configuration changes to the Base networks. ### Denim diff --git a/docs/llms.txt b/docs/llms.txt index 431d03720..c93ad4e34 100644 --- a/docs/llms.txt +++ b/docs/llms.txt @@ -768,6 +768,8 @@ - [Upgrades](https://docs.base.org/upgrades/overview): Track Base network upgrades, activation dates, and the protocol changes included in each release. +- [Upcoming Features](https://docs.base.org/upgrades/upcoming-features): Planned Base protocol features and their ballpark target quarters, tracked independently of a specific network upgrade. + - [Configuration Changelog](https://docs.base.org/base-chain/network-information/configuration-changelog): A log of configuration changes to the Base networks. ### Denim diff --git a/docs/upgrades/overview.mdx b/docs/upgrades/overview.mdx index 9dd629b1b..a508c18a2 100644 --- a/docs/upgrades/overview.mdx +++ b/docs/upgrades/overview.mdx @@ -7,6 +7,10 @@ Base evolves through named network upgrades. Each release introduces protocol ch A month without a confirmed activation timestamp is a planning target and may change. + +For planned protocol features that are not yet tied to a scheduled upgrade, see [Upcoming Features](/upgrades/upcoming-features). + + ## Denim diff --git a/docs/upgrades/upcoming-features.mdx b/docs/upgrades/upcoming-features.mdx new file mode 100644 index 000000000..62febb75a --- /dev/null +++ b/docs/upgrades/upcoming-features.mdx @@ -0,0 +1,27 @@ +--- +title: "Upcoming Features" +description: "Planned Base protocol features and their ballpark target quarters, tracked independently of a specific network upgrade." +--- + +This page lists Base protocol features that are planned or in development, independent of the named upgrade that eventually ships them. Each entry links to its specification where one exists. + + +Targets are ballpark quarters and may change. A feature moves onto a named upgrade page (for example, [Cobalt](/upgrades/cobalt/overview)) only once that upgrade is scheduled and locked in, at which point the official activation dates and final feature list are published. + + +## Planned Features + +| Feature | Summary | Details | Target | +|---------|---------|---------|--------| +| 200ms Native Blocks | Five canonical blocks per second, replacing Flashblocks with canonical block and RPC streams. | [200ms Native Blocks](/upgrades/denim/200ms-blocks) | Q4 2026 | +| 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 | +| 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 + +1. **Proposed** — a feature is designed and, where applicable, written up as a specification. It appears in the table above with a ballpark target. +2. **Scheduled** — once an upgrade that carries the feature is locked in, a named upgrade page is published with official Base Sepolia and Base Mainnet activation dates. +3. **Live** — the upgrade activates and moves to the [Upgrades](/upgrades/overview) timeline. From 0c221a4965e72773f1e53f3d4d1c1a6d2bf14184 Mon Sep 17 00:00:00 2001 From: Leopold Joy Date: Thu, 24 Sep 2026 18:12:43 +0200 Subject: [PATCH 2/2] docs: specify hinted TEE registration (#1956) * docs: specify hinted TEE registration Co-authored-by: OpenCode * docs: clarify permissioned TEE registration Co-authored-by: OpenCode * docs: simplify TEE registration summary Co-authored-by: OpenCode * docs: remove obsolete rollback references Co-authored-by: OpenCode * docs: add hinted TEE registration feature spec Co-authored-by: OpenCode --------- Co-authored-by: OpenCode --- docs/AGENTS.md | 2 +- docs/docs.json | 1 + docs/llms-full.txt | 4 +- docs/llms.txt | 4 +- .../proofs/hinted-tee-registration.mdx | 77 +++ .../base-protocol/proofs/registrar.mdx | 574 +++++++----------- docs/upgrades/upcoming-features.mdx | 2 +- 7 files changed, 320 insertions(+), 344 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 11ae273fd..d8cb13c7a 100644 --- a/docs/llms-full.txt +++ b/docs/llms-full.txt @@ -264,7 +264,9 @@ 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. +- [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 c93ad4e34..ffa1f6cc3 100644 --- a/docs/llms.txt +++ b/docs/llms.txt @@ -198,7 +198,9 @@ - [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. +- [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/specifications/base-protocol/proofs/registrar.mdx b/docs/specifications/base-protocol/proofs/registrar.mdx index 48668a06a..560e92347 100644 --- a/docs/specifications/base-protocol/proofs/registrar.mdx +++ b/docs/specifications/base-protocol/proofs/registrar.mdx @@ -1,412 +1,306 @@ --- 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. ## 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 supports two backends: +The registrar runs one polling loop: -| 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. | +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. -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. +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. -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. +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. -### Restart Recovery +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. -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: +## Attestation Challenge -```text Request Index Derivation -request_index(signer, attempt) = u32::from_be_bytes(keccak256(signer || attempt)[..4]) -``` +Each signer receives a deterministic 32-byte nonce: -For each signer, the registrar probes `max_recovery_attempts` consecutive deterministic slots -before submitting a fresh request. The action depends on the slot status: +```text Attestation Nonce +keccak256( + "base-proof-tee-registrar:attestation-nonce:v1" || + teeProverRegistryAddress || + signerAddress +) +``` -| 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 registrar requests one attestation per signer with that nonce. It rejects the response unless: -A `RequestIsNotLocked` revert encountered mid-scan is treated as in-flight and short-circuits to -waiting on that slot. +- 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. -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. +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. -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. +## Registration Plan -## Registration Transactions +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. -For each unregistered signer, the registrar: +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. -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 parsed plan contains: -The transaction retry rules are: +- 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`. -| 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. | +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. -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. +## P-384 Hints -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. +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. -## Orphan Deregistration +For every division by `b` modulo a prime `m`, the contract checks: -After processing every instance, the registrar reconciles the onchain signer set against the -active set: +```text Inverse Check +b * hint == 1 (mod m) +``` -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. +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. -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. +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. -This procedure assumes a single registrar per `TEEProverRegistry`. Two registrars sharing a -registry would each treat the other's signers as orphans. +## Certificate Cache -## Certificate Revocation +`CertManager` stores the pinned AWS Nitro root at deployment. The registrar processes every +remaining certificate in parent-first order: -When the operator enables CRL checking, the registrar enforces revocation using two layers in -order. Both are required to make CRL handling safe. +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. -### Layer 1: Onchain Durable Revocation Pre-Check +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. -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. +For a typical Nitro chain with three non-root CAs, transaction counts are: -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. +| 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 | -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. +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. -### Layer 2: AWS CRL Distribution Points +## Final Registration -For intermediates that pass Layer 1, the registrar: +After the cache is ready, the registrar calls: -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. +```solidity Registration Call +TEEProverRegistry.registerSigner(attestationTbs, signature, hints) +``` -`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. +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: -## Pending Registration Lifecycle +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. -Each per-signer pipeline is keyed by Ethereum signer address. The Boundless proof slot for a -signer transitions through: +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. -```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 +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. - Fresh -->|yes| Receipt[Use recovered receipt] - Fresh -->|no| Submit - Wait --> Receipt - Submit --> Wait +## Certificate Revocation - Receipt --> Send[tx_manager.send registerSigner] - Send -->|Ok| Done([Registered]) - Send -->|Retryable| Send - Send -->|ExecutionReverted| Block[Block recovery for signer] - Block --> Done -``` +`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. -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. +For every registration attempt, the registrar checks the pinned root and every planned certificate +against `CertManager.isRevoked()`. A confirmed onchain revocation rejects the registration. -## Onchain Interactions +When CRL fetching is additionally enabled, the registrar: -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. +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. -| 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. | +CRL fetch and parse failures are fail-open and retried on later cycles. Confirmed onchain +revocations always fail closed. -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. +## Orphan Deregistration -## Service Lifecycle +After registration task reconciliation, the registrar computes: -At startup, the registrar: +```text Orphan Formula +orphans = registered signers - active signers - pending signers +``` -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. +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. -The health endpoint reports ready as soon as wiring completes. Connectivity gating is intentionally -omitted because the registrar is outbound-only. +## Upgrade Compatibility -Each driver tick: +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. -1. Discovers instances. -2. Processes instances concurrently. -3. Computes orphans subject to the majority-reachable guard. -4. Submits deregistration transactions for confirmed orphans. +The migration does not change: -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. +- 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. ## 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..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 Migration | Migrate Base infrastructure to run inside a Trusted Execution Environment. | Specification pending | 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