```
  BIP: 349
  Layer: Consensus (soft fork)
  Title: OP_INTERNALKEY
  Authors: Brandon Black <freedom@reardencode.com>
           Jeremy Rubin <j@rubin.io>
  Status: Draft
  Type: Specification
  Assigned: 2024-11-14
  License: BSD-3-Clause
```

## Abstract

This BIP describes a new tapscript opcode (`OP_INTERNALKEY`) which
pushes the _taproot internal key_ to the stack.

## Specification

When verifying taproot script path spends having leaf version `0xc0` (as
defined in [BIP 342]), `OP_INTERNALKEY` replaces `OP_SUCCESS203` (0xcb).
`OP_INTERNALKEY` pushes the 32-byte x-only representation of the _taproot
internal key_ (referred to as _p_), as defined in [BIP 341], to the stack.

## Motivation

### Key spend with additional conditions

When building taproot outputs, especially those secured by an aggregate key
representing more than one signer, the parties may wish to collaborate on
signing with the _taproot internal key_, but only with additional script
restrictions. In this case, `OP_INTERNALKEY` saves 8 vBytes.

### Mitigated control block overhead for scripts using hash locks

In cases where key path spending is not desired, the internal key may be set to
a NUMS point whose bytes would otherwise be required in a tapscript. This could
be used with any hash locked transaction, for example, to save 8 vBytes.

Note: The internal key must be the X coordinate of a point on the SECP256K1
curve, so any such hash must be checked and modified until it is such an X
coordinate. This will typically take approximately 2 attempts.

### Re-Keying with Merkle Root Preservation

Consider a program such `CTV <X> CSFS <S+1> CLTV`. Such fragments are useful for LN-Symmetry applications.

Such a program would be embedded within a Taproot script path, such as `TR(X, {CTV <X> CSFS <S+1> CLTV})`.

Were the internal key to be updated from `X` to `Y`, the resulting program would be: `TR(Y, {CTV <X> CSFS <S+1> CLTV})`.

The key in the leaf and the key-path would be mismatched. Were `OP_INTERNALKEY` to be used,
the leaf would automatically re-key.
E.g., `TR(X, {CTV OP_INTERNALKEY CSFS <S+1> CLTV})` is equivalent to `TR(X, {CTV <X> CSFS <S+1> CLTV})`
and `TR(Y, {CTV OP_INTERNALKEY CSFS <S+1> CLTV})` is equivalent to `TR(Y, {CTV <Y> CSFS <S+1> CLTV})`.

While this particular example is contrived, the general technique of using `OP_INTERNALKEY`
as updatable across an entire script tree is a helpful covenant primitive when it is desirable to
invalidate signatures from prior states. For example, the theoretical `OP_TAPLEAFUPDATEVERIFY` opcode
modifies the internal key directly to remove or add a participant, and `OP_INTERNALKEY` would ensure
that the tweaked key is used from all script paths where desired.

## Reference Implementation

A reference implementation is provided here:

https://github.com/bitcoin/bitcoin/pull/29269

## Backward Compatibility

By constraining the behavior of an OP_SUCCESS opcode, deployment of the BIP
can be done in a backwards compatible, soft-fork manner. If anyone were to
rely on the OP_SUCCESS behavior of `OP_SUCCESS203`, `OP_INTERNALKEY` would
invalidate their spend.

## Deployment

TBD

## Credits

The concept for INTERNALKEY first arose in a [discussion](https://gnusha.org/bitcoin-wizards/2022-01-05.log) between Russell O'Connor
and Jeremy Rubin in Bitcoin Wizards IRC, inspired by BIP-0118's key punning technique
for the internal key. It was later
drafted into this BIP by Brandon Black.


## Copyright

This document is licensed under the 3-clause BSD license.

[BIP 341]: https://github.com/bitcoin/bips/blob/master/bip-0341.mediawiki

[BIP 342]: https://github.com/bitcoin/bips/blob/master/bip-0342.mediawiki
