Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
151 changes: 151 additions & 0 deletions CIP-????/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@
---
CIP: ????
Title: Sign transaction IDs together with guards
Status: Proposed
Category: Ledger
Authors:
- Polina Vinogradova <polina.vinogradova@iohk.io>
- Nicolas Henin <nicolas.henin@iohk.io>
Implementors: []
Discussions:
- https://github.com/cardano-foundation/CIPs/pull/1110
Created: 2025-10-29
License: CC-BY-4.0
---

## Abstract
We propose the following change to the ledger signature checking mechanism : instead of signing just the transaction ID, users
will now be required to sign the hash of the pair of (i) transaction ID and (ii) the hash of the guards listed in the transaction body.
This way, key holders will have no need to inspect the transaction they are signing in
order to be sure that the transaction satisfied its guards (if posted on-chain).

## Motivation: why is this CIP necessary?

This CIP (which depends on CIP-0118) serves both a practical and a conceptual purpose.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
This CIP (which depends on CIP-0118) serves both a practical and a conceptual purpose.
This CIP (which depends on [CIP-0118 | Nested Transactions](https://github.com/cardano-foundation/CIPs/pull/862)) serves both a practical and a conceptual purpose.


**Conceptually :** In recent years, intent-centric ledger models have been gaining a lot of momentum (e.g. Anoma, Khalani, CoW Swap, UniswapX, etc.).
There are many benefits to intent-centric design, not the least of which is that users do not need to care about the details of
how their intent is fulfilled. In the case of Cardano, this would be the details of the transaction that fulfills it. Cardano
is already moving towards intent-based design in its plan to introduce Nested Transactions in CIP-0118. CIP-0118 suggests that
intents are expressed as sub-transactions, and a complete batch (i.e. a fully valid top-level transaction) fulfills a given
sub-transaction's intent. This CIP takes this a step further : intents can be expressed as smart contracts, further distancing
users from the need to be concerned with how exactly their intents are fulfilled, as long as they satisfy the constraints they
specify using a smart contract script.

The functionality of expressing an intent as a guard script (i.e. a Plutus script that
is required to be executed by a transaction) is already part of CIP-0118. This CIP merely introduces a conceptual separation of
intent and the transaction that satisfies it. That is, by signing an intent-transaction pair ,
a user gets assurance that the transaction cannot be posted on-chain unless it both includes this guard
and also satisfies it, without ever
having to inspect the transaction.

**Practically :** The practical need for this stems from an intent-based ultra-light client design that is currently in the progress.
Such a light client has the capacity to submit an intent in the form of a script, but includes a requirement that it
does not inspect the transaction that is constructed to solve it.
The reason for this requirement is to enable implementing a two-party computation protocol for construction of
intent-fulfilling transactions.
We require a way to guarantee to such a client that their intent is solved by the transaction
they sign (in the case that the transaction is validated by the ledger and posted on-chain).


## Specification

### Ledger Changes

During transaction deserialization, the `MemoBytes` mechanism (an abstraction for a data type that encodes its own serialization) will be
used to store the bytes of the CDDL field containing the guards of the transaction.
The following values will be computed in the process of transaction processing :

- `guardsHash`, which will be computed by hashing the bytes of the guards, and
- `txidAndGuards`, which will be computed by hashing the concatenation `(txid ++ guardsHash)`

Signature checking will now check that each key signed `txidAndGuards`.

** Note ** There are other options for how exactly to compute the final hash of the data that will be signed. E.g.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
** Note ** There are other options for how exactly to compute the final hash of the data that will be signed. E.g.
**Note** There are other options for how exactly to compute the final hash of the data that will be signed. E.g.

we can exclude the `guards` field from the `txid` computation (e.g. move this field outside the body), then compute `guardsHash`
and `txidAndGuards` as above, signing the latter. This would mean `guards` are hashed twice (to compute
`guardsHash` and also `txidAndGuards`) instead of three times,
(i.e. as part of `txid` and then also `guardsHash` and also `txidAndGuards`).
Moreover, this would represent the most complete separation of `guards` as intents from
the rest of the transaction as "the thing that fulfills the intent".

### CDDL

No change necessary.

### Nested Transactions

It appears that there are no special cases required for sub- or top-level- transactions. In both cases,
all signatures will be checked on data constructed using the mechanism described above.

### Plutus

Plutus scripts are not able to see the signatures on a transaction, only the signing keys.
It appears that this change can be implemented without requiring a new version of Plutus.

### CLI

To support this change, the CLI will have to be modified to implement the new signing strategy.

### Backwards Compatibility

This change will be best suited for a hard fork (e.g. alongside Nested Transactions) that already does not have backwards compatibility
since it will not itself be backwards compatible.

### Future Intent DSL Development

The work described in this section is not part of the proposal being made here, but rather is a future outlook on
how intents could function using this feature.

A Plutus script is both hard to compose and hard to parse into instructions about what is required of a
transaction. To address this, we envision relying on very narrow-domain DSLs, each tailored to only a specific
usecase. The idea is to have as few as one or two expression constructors, such as for the case of sending funds
from wallet to wallet:

`SendMoney : List KeyHash x Value x Address x Address -> Exp`

A client constructs some intent `exp = SendMoney lskeys v addr1 addr1`
Then, an expression `exp` in this DSL is compiled to a (CBOR-encoded) guard `scr` and the client sends the pair `(exp , scr)`
to an intent solver. The solver uses `exp` to build a transaction with ID `txid` (which includes
`scr` as one of its guards). The solver
then checks that the resulting transaction indeed satisfies the script `scr` by validating it against the current ledger state (except
for checking the clients's signature, which is not yet attached).
The solver sends the client the `txid`, and the client can then sign `hash (txid ++ hash scr)`.

We speculate that such narrow-domain DSLs may find use in the broader context of taking full advantage of the
Nested Transaction functionality. We would go so far as to say that this is what Cardano intents *are*, and sub-txs (as they
are also intents)
will benefit from also being paired with concise DSL descriptions of this nature. This would facilitate the process of filtering sub-txs
top-level builders are interested in, as well as the process of intent fulfillment (i.e. top-level transaction construction).
This possibility has already come up in discussions about top-level observers in CIP-0118.

## Rationale: how does this CIP achieve its goals?

The goal of this CIP is to describe a mechanism for intent validation without transaction inspection. That is, a user knows that a transaction
they signed (according to the new signing mechanism) either satisfies their intent (expressed as a guard script)
or is discarded - without the need to inspect the transaction body.
We have specified the required signing mechanism and rule
changes required to ensure this, and explained why this is guaranteed above.

### Alternatives

We are (in parallel to making this CIP) working on a ZK-based solution that will allow proving to users that a given
transaction ID corresponds to a transaction that includes
in its list of guard scripts a specific script. Using blind signatures, our benchmarks show that generating the
necessary proof in an average case may take ~5s
(link to paper will be provided when it becomes public). This is significantly slower than performing two additional
hashing operations.

## Path to Active

### Acceptance Criteria
- [ ] Ledger rule changes are implemented in the ledger spec and repo and included in an upcoming major hard fork.

### Implementation Plan
- [ ] Passes all requirements of both Plutus and Ledger teams as agreed to improve Plutus script efficiency and usability.

## Copyright
This CIP is licensed under [CC-BY-4.0](https://creativecommons.org/licenses/by/4.0/legalcode).

[CC-BY-4.0]: https://creativecommons.org/licenses/by/4.0/legalcode
[Apache-2.0]: http://www.apache.org/licenses/LICENSE-2.0