Skip to content
Closed
Show file tree
Hide file tree
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
8 changes: 6 additions & 2 deletions 11.md
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,7 @@ message = len32(quote) || quote
|| len32(C_i) || C_i
|| for each output j (in request order):
len32(amount_j) || amount_j
|| len32(B_j) || B_j
|| len32(B_hash_j) || B_hash_j

message_hash = tagged_hash("Cashu_SigAllSig_v1", message)
```
Expand All @@ -159,11 +159,15 @@ Where:
- `secret_i` is the UTF-8 bytes of the input's **unescaped** `secret` string.
- `C_i` is the raw byte representation of the input's signature point (e.g. 33-byte compressed secp256k1 point), decoded from the proof's hex string.
- `amount_j` is the output amount as canonical minimal big-endian bytes (e.g. `0` → empty byte array, `1` → `0x01`, `256` → `0x0100`); thus `len32(amount_j)` is its length in bytes as a 32-bit integer (e.g. `0` for amount `0`, `1` for amount `1`, `2` for amount `256`).
- `B_j` is the raw byte representation of the blinded message (e.g. 33-byte compressed secp256k1 point), decoded from the request's hex string.
- `B_j` is the canonical raw point encoding of the blinded message, decoded from the request's hex string, and `B_hash_j = SHA256(B_j)` is its raw 32-byte digest; thus `len32(B_hash_j)` is always `32` (`0x00000020`). For secp256k1, `B_j` is the 33-byte compressed SEC1 encoding, including its `0x02` or `0x03` parity prefix. It is not the 32-byte x-only representation and not the UTF-8 bytes of the hexadecimal string.
- `tagged_hash` uses the [BIP-340] construction `SHA256(SHA256(tag) || SHA256(tag) || message)`, where `tag` is encoded as UTF-8 and each inner SHA-256 result is its raw 32-byte digest. For this tag, `SHA256("Cashu_SigAllSig_v1") = c83c413c874b6f3da4c6310558d0d174c56f1a0a034023ae225ab3648e9626b3`.

The inputs are the `Proofs` in the transaction's `inputs` field. The outputs are the `BlindedMessages` in its `outputs` field: for a swap all requested outputs, for a melt the [NUT-08][08] blank outputs (zero output entries if absent). The 32-byte `message_hash` is signed directly with the Schnorr scheme in [Signature scheme](#signature-scheme), without a further SHA-256.

Hashing each `B_` lets a signer commit to an output without learning its blinded point. The party constructing the output MAY provide `B_hash_j` to the signer and reveal `B_j` only when the transaction is submitted. The mint MUST compute `B_hash_j` from each submitted `B_j` when validating the signature.

The hash commits to the complete point encoding. In particular, the compressed secp256k1 points `B_` and `-B_`, which have the same x-coordinate but different parity prefixes, produce distinct commitments.

> [!NOTE]
>
> The output keyset `id` is deliberately not part of the message. Output keysets are already constrained at the mint: new outputs **MUST** be from an active keyset ([NUT-02][02]), and the inputs and outputs of a transaction must share one unit (error codes `11009`/`11010`). Leaving the `id` unbound lets pre-signed transactions remain valid across keyset rotations.
Expand Down
23 changes: 15 additions & 8 deletions tests/11-test.md
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,7 @@ The following `SwapRequest` is signed over the v1 message. The witness carries o
"id": "009a1f293253e41e",
"secret": "[\"P2PK\",{\"nonce\":\"859d4935c4907062a6297cf4e663e2835d90d97ecdd510745d32f6816323a41f\",\"data\":\"0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798\",\"tags\":[[\"sigflag\",\"SIG_ALL\"]]}]",
"C": "02698c4e2b5f9534cd0687d87513c759790cf829aa5739184a3e3735471fbda904",
"witness": "{\"signatures\":[\"55c4e0d72598a64af2a04d1d348af7beb97b35fe1af91711e205414a24c869ba047b5bd298b87c7b58b439833e244b5498136fd4cccdf9d41b0fe72db8279722\",\"947864cac6d9369f358257eece81c4aa9deb2e63899f2d868e7c243ff334ade5db1d8db010daa2b9f4407610458d9ffa3250eb778d1a0980f4de671627c8718e\"]}"
"witness": "{\"signatures\":[\"b5b11a31d66024cb2ec696d8d057437ec501b3e82c37e1fb4cba11f076f946fbcc0222e8298f9ac0392498f278824ceb78c98ce0939d4043a48b8e003944f44f\",\"947864cac6d9369f358257eece81c4aa9deb2e63899f2d868e7c243ff334ade5db1d8db010daa2b9f4407610458d9ffa3250eb778d1a0980f4de671627c8718e\"]}"
},
{
"amount": 2,
Expand All @@ -160,24 +160,31 @@ The following `SwapRequest` is signed over the v1 message. The witness carries o
}
```

The corresponding v1 `message` (554 bytes, hex) and its tagged hash `message_hash` are:
The output hashes are:

```
message = 00000000000000c05b225032504b222c7b226e6f6e6365223a2238353964343933356334393037303632613632393763663465363633653238333564393064393765636464353130373435643332663638313633323361343166222c2264617461223a22303237396265363637656639646362626163353561303632393563653837306230373032396266636462326463653238643935396632383135623136663831373938222c2274616773223a5b5b22736967666c6167222c225349475f414c4c225d5d7d5d0000002102698c4e2b5f9534cd0687d87513c759790cf829aa5739184a3e3735471fbda904000000c05b225032504b222c7b226e6f6e6365223a2231366439333761323961653465356434613665396639393539633464346239613864366632663762326630613162336334643565366637303831393261336234222c2264617461223a22303237396265363637656639646362626163353561303632393563653837306230373032396266636462326463653238643935396632383135623136663831373938222c2274616773223a5b5b22736967666c6167222c225349475f414c4c225d5d7d5d0000002102c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee5000000010800000021035015e6d7ade60ba8426cefaf1832bbd27257636e44a76b922d78e79b47cb689d0000000102000000210288d7649652d0a83fc9c966c969fb217f15904431e61a44b14999fabc1b5d9ac6
message_hash = b2a0a8ee2d8911585d97adce15c8d7e664c712baa31c0f3d8a6e32b909fdda2b
SHA256(B_0) = a0f1ae7f6d95b4b375c668f305259e1ee879adadb4cd1d8f0dc65e55e277442a
SHA256(B_1) = fc971046204651ae0ecd8c397b621fb15110762920d1451073c20fb200e916af
```

The corresponding v1 `message` (552 bytes, hex) and its tagged hash `message_hash` are:

```
message = 00000000000000c05b225032504b222c7b226e6f6e6365223a2238353964343933356334393037303632613632393763663465363633653238333564393064393765636464353130373435643332663638313633323361343166222c2264617461223a22303237396265363637656639646362626163353561303632393563653837306230373032396266636462326463653238643935396632383135623136663831373938222c2274616773223a5b5b22736967666c6167222c225349475f414c4c225d5d7d5d0000002102698c4e2b5f9534cd0687d87513c759790cf829aa5739184a3e3735471fbda904000000c05b225032504b222c7b226e6f6e6365223a2231366439333761323961653465356434613665396639393539633464346239613864366632663762326630613162336334643565366637303831393261336234222c2264617461223a22303237396265363637656639646362626163353561303632393563653837306230373032396266636462326463653238643935396632383135623136663831373938222c2274616773223a5b5b22736967666c6167222c225349475f414c4c225d5d7d5d0000002102c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee5000000010800000020a0f1ae7f6d95b4b375c668f305259e1ee879adadb4cd1d8f0dc65e55e277442a000000010200000020fc971046204651ae0ecd8c397b621fb15110762920d1451073c20fb200e916af
message_hash = 485917c8b231e13c361281c7d587ba8721634501b24e15c92c4d6d8826912405
```

Note the empty quote field for a swap: the first four bytes of `message` are `len32(quote) = 0`, and no quote bytes follow.

For a melt of quote `9d745270-1405-46de-b5c5-e2762b4f5e00` with the same inputs and outputs, the v1 `message` (590 bytes, hex) and its tagged hash `message_hash` are:
For a melt of quote `9d745270-1405-46de-b5c5-e2762b4f5e00` with the same inputs and outputs, the v1 `message` (588 bytes, hex) and its tagged hash `message_hash` are:

```
message = 0000002439643734353237302d313430352d343664652d623563352d653237363262346635653030000000c05b225032504b222c7b226e6f6e6365223a2238353964343933356334393037303632613632393763663465363633653238333564393064393765636464353130373435643332663638313633323361343166222c2264617461223a22303237396265363637656639646362626163353561303632393563653837306230373032396266636462326463653238643935396632383135623136663831373938222c2274616773223a5b5b22736967666c6167222c225349475f414c4c225d5d7d5d0000002102698c4e2b5f9534cd0687d87513c759790cf829aa5739184a3e3735471fbda904000000c05b225032504b222c7b226e6f6e6365223a2231366439333761323961653465356434613665396639393539633464346239613864366632663762326630613162336334643565366637303831393261336234222c2264617461223a22303237396265363637656639646362626163353561303632393563653837306230373032396266636462326463653238643935396632383135623136663831373938222c2274616773223a5b5b22736967666c6167222c225349475f414c4c225d5d7d5d0000002102c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee5000000010800000021035015e6d7ade60ba8426cefaf1832bbd27257636e44a76b922d78e79b47cb689d0000000102000000210288d7649652d0a83fc9c966c969fb217f15904431e61a44b14999fabc1b5d9ac6
message_hash = 2cdffe8a0eed5d22da07adc0f149d49e0ddca5cdafa6d872630d0c52e167e548
message = 0000002439643734353237302d313430352d343664652d623563352d653237363262346635653030000000c05b225032504b222c7b226e6f6e6365223a2238353964343933356334393037303632613632393763663465363633653238333564393064393765636464353130373435643332663638313633323361343166222c2264617461223a22303237396265363637656639646362626163353561303632393563653837306230373032396266636462326463653238643935396632383135623136663831373938222c2274616773223a5b5b22736967666c6167222c225349475f414c4c225d5d7d5d0000002102698c4e2b5f9534cd0687d87513c759790cf829aa5739184a3e3735471fbda904000000c05b225032504b222c7b226e6f6e6365223a2231366439333761323961653465356434613665396639393539633464346239613864366632663762326630613162336334643565366637303831393261336234222c2264617461223a22303237396265363637656639646362626163353561303632393563653837306230373032396266636462326463653238643935396632383135623136663831373938222c2274616773223a5b5b22736967666c6167222c225349475f414c4c225d5d7d5d0000002102c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee5000000010800000020a0f1ae7f6d95b4b375c668f305259e1ee879adadb4cd1d8f0dc65e55e277442a000000010200000020fc971046204651ae0ecd8c397b621fb15110762920d1451073c20fb200e916af
message_hash = 4aa23fb1a0f72c4a9f27ec5ffb73dbc29548639d5dcfb60d4e331b05ee53eaa3
```

A valid signature on the melt message by the test key is:

```
b22645e507c51a37070402ccc36b5b41cc33fe5bdc2ff3f3ee12d0b7340f9742dfaf64c49e9b1243e7a71b31329a63d9c174fd82f133491b16723f8dcd3f7693
f51b773ed444ed1ab86b2df259e1ce7409b5a7fff99b5a6367b51354aab5e15073964d9518fa8103df21bfb4cb520e651f87f9d05a2fd8a287201d1b8696d966
```
Loading