diff --git a/11.md b/11.md index 8d8900f51..5a4a633e4 100644 --- a/11.md +++ b/11.md @@ -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) ``` @@ -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. diff --git a/tests/11-test.md b/tests/11-test.md index 22f748763..4baddba21 100644 --- a/tests/11-test.md +++ b/tests/11-test.md @@ -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, @@ -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 ```