diff --git a/tips/tip-1011.md b/tips/tip-1011.md new file mode 100644 index 0000000000..28c6c72614 --- /dev/null +++ b/tips/tip-1011.md @@ -0,0 +1,100 @@ +--- +id: TIP-1011 +title: P256 and WebAuthn Address Derivation +description: Documents how P256 and WebAuthn signatures derive account addresses from public keys, and clarifies that both signature types share the same address space. +authors: Tempo Team +status: Draft +related: Transactions, Account Keychain +protocolVersion: T1 +--- + +# TIP-1011: P256 and WebAuthn Address Derivation + +## Abstract + +TIP-1011 documents the address derivation scheme for P256 (secp256r1) and WebAuthn signatures on Tempo. Both signature types derive addresses using `keccak256(pub_key_x || pub_key_y)`, taking the last 20 bytes as the address. This means a single P256 key pair produces the same address regardless of whether it is used with raw P256 signatures or WebAuthn signatures. + +## Motivation + +Tempo supports three signature types for transaction authorization: + +1. **secp256k1**: Standard Ethereum-compatible ECDSA signatures +2. **P256**: Raw secp256r1 (NIST P-256) signatures +3. **WebAuthn**: WebAuthn-wrapped P256 signatures (passkeys, hardware keys) + +Users should understand that P256 and WebAuthn signatures share the same address derivation mechanism. A private key used for P256 signatures can also be used for WebAuthn signatures over the same account address, and vice versa. This is intentional and expected behavior. + +--- + +# Specification + +## Address Derivation + +### secp256k1 + +For secp256k1 signatures, address derivation follows the standard Ethereum approach: + +``` +address = keccak256(uncompressed_public_key)[12:32] +``` + +Where `uncompressed_public_key` is the 64-byte concatenation of the x and y coordinates (excluding the 0x04 prefix). + +### P256 and WebAuthn + +For both P256 and WebAuthn signatures, address derivation uses: + +``` +address = keccak256(pub_key_x || pub_key_y)[12:32] +``` + +Where: +- `pub_key_x`: 32-byte x-coordinate of the P256 public key +- `pub_key_y`: 32-byte y-coordinate of the P256 public key +- `||`: byte concatenation + +This is implemented as: + +```rust +pub fn derive_p256_address(pub_key_x: &B256, pub_key_y: &B256) -> Address { + let hash = keccak256([pub_key_x.as_slice(), pub_key_y.as_slice()].concat()); + Address::from_slice(&hash[12..]) +} +``` + +## Shared Address Space + +Because P256 and WebAuthn signatures use the same address derivation, a single P256 key pair maps to exactly one address. This has the following implications: + +1. **Key reuse across signature types**: A user can sign transactions for the same address using either raw P256 signatures or WebAuthn signatures, provided they use the same underlying key pair. + +2. **Passkey portability**: A passkey (WebAuthn) used to create an account can also authorize transactions via raw P256 signatures if the private key is exported or available through another interface. + +3. **No signature type binding**: The protocol does not restrict which signature type can be used for a given address. Any valid signature (P256 or WebAuthn) from the corresponding private key will be accepted. + +## Security Considerations + +This shared address space is acceptable because: + +1. **Same key material**: Both signature types require possession of the same private key. There is no privilege escalation—if an attacker has the private key, they can sign with either method. + +2. **No replay across types**: Transaction signatures include the signature type in the encoding, preventing a P256 signature from being replayed as WebAuthn or vice versa. + +3. **User flexibility**: Users benefit from being able to use whichever signing method is most convenient for their current context (e.g., passkey on mobile, raw P256 from a hardware security module). + +--- + +# Invariants + +- Given the same `(pub_key_x, pub_key_y)` pair, the derived address MUST always be identical regardless of signature type +- A transaction signed with P256 MUST recover to the same address as the same transaction signed with WebAuthn using the same key pair +- P256/WebAuthn addresses occupy a different address space than secp256k1 addresses (different curves, different key pairs) + +## Test Cases + +The test suite must cover: + +1. **P256 address derivation**: Verify `derive_p256_address(x, y)` produces the expected address +2. **WebAuthn same address**: Verify WebAuthn signature recovery produces the same address as P256 for identical keys +3. **Cross-signature authorization**: Verify an account created via P256 can authorize transactions via WebAuthn (and vice versa) +4. **Determinism**: Verify repeated derivations with the same key produce identical addresses