diff --git a/11.md b/11.md index 130f0f85..8e7ac654 100644 --- a/11.md +++ b/11.md @@ -2,13 +2,13 @@ `optional` -`depends on: NUT-10` +`depends on: NUT-10, NUT-08` --- This NUT describes Pay-to-Public-Key (P2PK) which is one kind of spending condition based on [NUT-10][10]'s well-known `Secret`. Using P2PK, we can lock ecash tokens to a receiver's ECC public key and require a Schnorr signature with the corresponding private key to unlock the ecash. The spending condition is enforced by the mint. -Caution: If the mint does not support this type of spending condition, proofs may be treated as a regular anyone-can-spend tokens. Applications need to make sure to check whether the mint supports a specific kind of spending condition by checking the mint's [info][06] endpoint. +Caution: If the mint does not support this type of spending condition, proofs may be treated as a regular anyone-can-spend tokens. Applications need to make sure to check whether the mint supports a specific kind of spending condition by checking the mint's [NUT-06][06] info endpoint. ## Pay-to-Pubkey @@ -45,38 +45,43 @@ The recipient who owns the private key of the public key `Secret.data` can spend } ``` -#### Signature scheme +### Signature scheme To spend a token locked with `P2PK`, the spender needs to include signatures in the spent proofs. We use `libsecp256k1`'s serialized 64 byte Schnorr signatures on the SHA256 hash of the message to sign. The message to sign is the field `Proof.secret` in the inputs. If indicated by `Secret.tags.sigflag` in the inputs, outputs might also require signatures on the message `BlindedMessage.B_`. -An ecash spending operation like [swap][03] and [melt][05] can have multiple inputs and outputs. If we have more than one input or output, we provide signatures in each `Proof` and `BlindedMessage` individually. The inputs are the `Proofs` provided in the `inputs` field and the outputs are the `BlindedMessages` in the `outputs` field in the request body (see `PostMeltRequest` in [NUT-05][05] and `PostSwapRequest` in [NUT-03][03]). +An ecash spending operation like [swap][03] and [melt][05] can have multiple inputs and outputs. If we have more than one locked input, we either provide signatures in each input individually (for `SIG_INPUTS`) or only in the first input for the entire transaction (for `SIG_ALL`). The inputs are the `Proofs` provided in the `inputs` field and the outputs are the `BlindedMessages` in the `outputs` field in the request body (see `PostMeltRequest` in [NUT-05][05] and `PostSwapRequest` in [NUT-03][03]). ### Tags -More complex spending conditions can be defined in the tags in `Proof.tags`. All tags are optional. Tags are arrays with two or more strings being `["key", "value1", "value2", ...]`. +More complex spending conditions can be defined in the tags in `Secret.tags`. All tags are optional. Tags are arrays with two or more strings being `["key", "value1", "value2", ...]`. We denote a specific tag in a proof Supported tags are: -- `sigflag: ` determines whether outputs have to be signed as well -- `n_sigs: ` specifies the minimum number of valid signatures expected -- `pubkeys: ` are additional public keys that can provide signatures (_allows multiple entries_) +- `sigflag: ` sets the signature flag +- `pubkeys: ` are additional public keys (together with the one in the `data` field of the secret) that can provide signatures (_allows multiple entries_) +- `n_sigs: ` specifies the minimum number of public keys providing valid signatures - `locktime: ` is the Unix timestamp of when the lock expires - `refund: ` are optional refund public keys that can exclusively spend after `locktime` (_allows multiple entries_) +- `n_sigs_refund: ` specifies the minimum number of refund public keys providing valid signatures -**Note:** The tag serialization type is `[, , ...]` but some tag values are `int`. Wallets and mints must cast types appropriately for de/serialization. +> [!NOTE] +> +> The tag serialization type is `[, , ...]` but some tag values are `int`. Wallets and mints must cast types appropriately for de/serialization. #### Signature flags Signature flags are defined in the tag `Secret.tags['sigflag']`. Currently, there are two signature flags. -- `SIG_INPUTS` requires valid signatures on all inputs. It is the default signature flag and will be applied even if the `sigflag` tag is absent. -- `SIG_ALL` requires valid signatures on all inputs and on all outputs. +- `SIG_INPUTS` requires valid signatures on all inputs independently. It is the default signature flag and will be applied if the `sigflag` tag is absent. +- `SIG_ALL` requires valid signatures on all inputs and on all outputs of a transaction. -The signature flag `SIG_ALL` is enforced if at least one of the `Proofs` have the flag `SIG_ALL`. Otherwise, `SIG_INPUTS` is enforced. +If any one input has the signature flag `SIG_ALL`, then all inputs are required to have the same kind, the flag `SIG_ALL` and the same `Secret.data` and `Secret.tags`, otherwise an error is returned. -#### Signature +`SIG_INPUTS` is only enforced if no input is `SIG_ALL`. -Signatures must be provided in the field `Proof.witness.signatures` for each `Proof` which is an input. If the signature flag `SIG_ALL` is enforced, signatures must also be provided for every output in its field `BlindedMessage.witness.signatures`. +#### Signature flag `SIG_INPUTS` + +`SIG_INPUTS` means that each `Proof` (input) requires it's own signature. The signature is provided in the `Proof.witness` field of each input separately. The format of the [witness](#witness-format) is defined later on. ##### Signed inputs @@ -92,51 +97,98 @@ A `Proof` (an input) with a signature `P2PKWitness.signatures` on `secret` is th } ``` -The `secret` of each input is **signed as a string**. +The `secret` field is **signed as a string**. -##### Signed outputs +##### Witness format -A `BlindedMessage` (an output) with a signature `P2PKWitness.signatures` on `B_` is the JSON (see [NUT-00][00]): +Signatures are stored in `P2PKWitness` objects and are provided in either each `Proof.witness` of all inputs separately (for `SIG_INPUTS`) or only in the first input of the transaction (for `SIG_ALL`). `P2PKWitness` is a serialized JSON string of the form ```json { - "amount": , - "B_": , - "witness": // Signatures on "B_" + "signatures": ]> } ``` -The `B_` of each output is **signed as bytes** which comes from the original hex string. +The `signatures` are an array of signatures in hex and correspond to the signatures by one or more signing public keys. -##### Witness format +#### Signature flag `SIG_ALL` -`P2PKWitness` is a serialized JSON string of the form +`SIG_ALL` is enforced only if the following conditions are met: -```json -{ - "signatures": ]> -} +- If one input has the signature flag `SIG_ALL`, all other inputs MUST have the same `Secret.data` and `Secret.tags`, and by extension, also be `SIG_ALL`. +- If one or more inputs differ from this, an error is returned. + +If this condition is met, the `SIG_ALL` flag is enforced and only **the first input of a transaction requires a witness** that covers all other inputs and outputs of the transaction. All signatures by the signing public keys MUST be provided in the `Proof.witness` of the first input of the transaction. + +#### Message aggregation for `SIG_ALL` + +The message to be signed depends on the type of transaction containing an input with signature flag `SIG_ALL`. + +##### Aggregation for `swap` + +A swap contains `inputs` and `outputs` (see [NUT-03][03]). To provide a valid signature, the owner (or owners) of the signing public keys must concatenate the `secret` fields of all `Proofs` (inputs), and the `B_` fields of all `BlindedMessages` (outputs, see [NUT-00][00]) to a single message string in the order they appear in the transaction. This string concatenated is then hashed and signed (see [Signature scheme](#signature-scheme)). + +If a swap transaction has `n` inputs and `m` outputs, the message to sign becomes: + +``` +msg = secret_0 || ... || secret_n || B_0 || ... || B_m ``` -The `signatures` are an array of signatures in hex. The witness for a spent proof can be obtained with a `Proof` state check (see [NUT-07][07]). +Here, `||` denotes string concatenation. The `B_` of each output is **a hex string**. + +##### Aggregation for `melt` + +For a melt transaction, the message to sign is composed of all the inputs, the quote ID being paid, and the [NUT-08][08] blank `outputs`. + +If a melt transaction has `n` inputs, `m` blank outputs, and a quote ID `quote_id`, the message to sign becomes: + +``` +msg = secret_0 || ... || secret_n || B_0 || ... || B_m || quote_id +``` + +Here, `||` denotes string concatenation. The `B_` of each output is **a hex string**. ### Multisig -If the tag `n_sigs` is a positive integer, the mint will also consider signatures from public keys specified in the `pubkeys` tag additional to the public key in `Secret.data`. If the number of valid signatures is greater or equal to the number specified in `n_sigs`, the transaction is valid. +Cashu offers two levels of multi-signature protection: `Locktime MultiSig` and `Refund MultiSig`, which are activated depending on the status of the proof's `locktime` tag. + +#### Locktime MultiSig + +> [!NOTE] +> Locktime Multisig conditions only apply if the `locktime` tag is not present, or is a timestamp in the future. + +If the `pubkeys` tag is present, the `Proof` is spendable only if a valid signature is given by at least ONE of the public keys contained in the `Secret.data` field or the `pubkeys` tag. + +If the `n_sigs` tag is a positive integer, the mint will require at least `n_sigs` of those public keys to provide a valid signature. + +If the number of public keys with valid signatures is greater or equal to the number specified in `n_sigs`, the transaction is valid. The signatures are provided in an array of strings in the `P2PKWitness` object. + +Expressed as an "n-of-m" scheme, `n = n_sigs` is the number of required signatures and `m = 1 (data field) + len(pubkeys tag)` is the number of public keys that could sign. + +> [!CAUTION] +> +> Because Schnorr signatures are non-deterministic, we expect a minimum number of unique public keys with valid signatures instead of expecting a minimum number of signatures. + +#### Locktime + +If the tag `locktime` is the unix time and the mint's local clock is greater than `locktime`, the `Proof` becomes spendable by anyone, except if the following condition is also true. -Expressed as an "n-of-m" scheme, `n = n_sigs` is the number of required signatures and `m = 1 ("data" field) + len(pubkeys tag)` is the number of public keys that could sign. +> [!NOTE] +> A `Proof` is considered spendable by anyone if it only requires a `secret` and a valid signature `C` to be spent (which is the default case). -### Locktime +#### Refund MultiSig -If the tag `locktime` is the unix time and the mint's local clock is greater than `locktime`, the `Proof` becomes spendable by anyone, except if the following condition is also true. Note: A `Proof` is considered spendable by anyone if it only requires a `secret` and a valid signature `C` to be spent (which is the default case). +If the `locktime` tag is in the past and the `refund` tag is present, the `Proof` is spendable only if a valid signature is given by at least ONE of the `refund` pubkeys. -#### Refund public keys +If the `n_sigs_refund` tag is present, the mint will require at least`n_sigs_refund` of the `refund` pubkeys to provide a valid signature. -If the `locktime` is in the past and a tag `refund` is present, the `Proof` is spendable only if a valid signature by one of the the `refund` pubkeys is provided in `Proof.witness.signatures` and, depending on the signature flag, in `BlindedMessage.witness.signatures`. +> [!CAUTION] +> +> Because Schnorr signatures are non-deterministic, we expect a minimum number of unique public keys with valid signatures instead of expecting a minimum number of signatures. #### Complex Example -This is an example `secret` that locks a `Proof` with a Pay-to-Pubkey (P2PK) condition that requires 2-of-3 signatures from the public keys in the `data` field and the `pubkeys` tag. If the `timelock` has passed, the `Proof` becomes spendable with a single signature from the public key in the `refund` tag. The signature flag `sigflag` indicates that signatures are necessary on the `inputs` and the `outputs` of a transaction. +This is an example `Secret` that locks a `Proof` with a Pay-to-Pubkey (P2PK) condition that requires 2-of-3 signatures from the public keys in the `data` field and the `pubkeys` tag. If the `timelock` has passed, the `Proof` becomes spendable with a single signature from ONE of the two public keys in the `refund` tag. The signature flag `sigflag` indicates that signatures are necessary on the `inputs` and the `outputs` of the transaction this `Proof` is spent by. ```json [ @@ -150,7 +202,8 @@ This is an example `secret` that locks a `Proof` with a Pay-to-Pubkey (P2PK) con ["locktime", "1689418329"], [ "refund", - "033281c37677ea273eb7183b783067f5244933ef78d8c3f15b1a77cb246099c26e" + "033281c37677ea273eb7183b783067f5244933ef78d8c3f15b1a77cb246099c26e", + "02e2aeb97f47690e3c418592a5bcda77282d1339a3017f5558928c2441b7731d50" ], [ "pubkeys", diff --git a/tests/11-test.md b/tests/11-test.md index af2922dc..eb9e2ad3 100644 --- a/tests/11-test.md +++ b/tests/11-test.md @@ -1,5 +1,7 @@ # NUT-11 Test Vectors +### SIG_INPUTS Test Vectors + The following is a `Proof` with a valid signature. ```json @@ -71,3 +73,194 @@ The following is a `Proof` with a signature from the refund key that is **not** "witness": "{\"signatures\":[\"f661d3dc046d636d47cb3d06586da42c498f0300373d1c2a4f417a44252cdf3809bce207c8888f934dba0d2b1671f1b8622d526840f2d5883e571b462630c1ff\"]}" } ``` + +### SIG_ALL Test Vectors + +Example `SwapRequest`: + +```json +{ + "inputs": [ + { + "amount": 0, + "id": "009a1f293253e41e", + "secret": "[\"P2PK\",{\"nonce\":\"c537ea76c1ac9cfa44d15dac91a63315903a3b4afa8e4e20f868f87f65ff2d16\",\"data\":\"026f6a2b1d709dbca78124a9f30a742985f7eddd894e72f637f7085bf69b997b9a\",\"tags\":[[\"pubkeys\",\"03142715675faf8da1ecc4d51e0b9e539fa0d52fdd96ed60dbe99adb15d6b05ad9\"],[\"n_sigs\",\"2\"],[\"sigflag\",\"SIG_ALL\"]]}]", + "C": "026f6a2b1d709dbca78124a9f30a742985f7eddd894e72f637f7085bf69b997b9a", + "witness": "{\"signatures\":[\"c38cf7943f59206dc22734d39c17e342674a4025e6d3b424eb79d445a57257d57b45dd94fcd1b8dd8013e9240a4133bdef6523f64cd7288d890f3bbb8e3c6453\",\"f766dbb80e5c27de9a4770486e11e1bac0b1c4f782bf807a5189ea9c3e294559a3de4e217d3dfceafd4d9e8dcbfe4e9a188052d6dab9df07df7844224292de36\"]}" + } + ], + "outputs": [ + { + "amount": 0, + "id": "009a1f293253e41e", + "B_": "026f6a2b1d709dbca78124a9f30a742985f7eddd894e72f637f7085bf69b997b9a" + } + ] +} +``` + +The following is the `msg_to_sign` on the above `SwapRequest`. + +``` +["P2PK",{"nonce":"c537ea76c1ac9cfa44d15dac91a63315903a3b4afa8e4e20f868f87f65ff2d16","data":"026f6a2b1d709dbca78124a9f30a742985f7eddd894e72f637f7085bf69b997b9a","tags":[["pubkeys","03142715675faf8da1ecc4d51e0b9e539fa0d52fdd96ed60dbe99adb15d6b05ad9"],["n_sigs","2"],["sigflag","SIG_ALL"]]}]026f6a2b1d709dbca78124a9f30a742985f7eddd894e72f637f7085bf69b997b9a +``` + +The following is a `SwapRequest` with a valid sig_all signature. + +```json +{ + "inputs": [ + { + "amount": 0, + "id": "009a1f293253e41e", + "secret": "[\"P2PK\",{\"nonce\":\"fc14ca312b7442d05231239d0e3cdcb6b2335250defcb8bec7d2efe9e26c90a6\",\"data\":\"026f6a2b1d709dbca78124a9f30a742985f7eddd894e72f637f7085bf69b997b9a\",\"tags\":[[\"sigflag\",\"SIG_ALL\"]]}]", + "C": "026f6a2b1d709dbca78124a9f30a742985f7eddd894e72f637f7085bf69b997b9a", + "witness": "{\"signatures\":[\"aa6f3b3f112ec3e834aded446ea67a90cdb26b43e08cfed259e0bbd953395c4af11117c58ec0ec3de404f31076692426cde40d2c1602d9dd067a872cb11ac3c0\"]}" + }, + { + "amount": 0, + "id": "009a1f293253e41f", + "secret": "[\"P2PK\",{\"nonce\":\"fc14ca312b7442d05231239d0e3cdcb6b2335250defcb8bec7d2efe9e26c90a6\",\"data\":\"026f6a2b1d709dbca78124a9f30a742985f7eddd894e72f637f7085bf69b997b9a\",\"tags\":[[\"sigflag\",\"SIG_ALL\"]]}]", + "C": "026f6a2b1d709dbca78124a9f30a742985f7eddd894e72f637f7085bf69b997b9a" + } + ], + "outputs": [ + { + "amount": 0, + "id": "009a1f293253e41e", + "B_": "026f6a2b1d709dbca78124a9f30a742985f7eddd894e72f637f7085bf69b997b9a" + } + ] +} +``` + +The following is a `SwapRequest` that is invalid as there are multiple secrets. + +```json +{ + "inputs": [ + { + "amount": 1, + "secret": "[\"P2PK\",{\"nonce\":\"859d4935c4907062a6297cf4e663e2835d90d97ecdd510745d32f6816323a41f\",\"data\":\"0249098aa8b9d2fbec49ff8598feb17b592b986e62319a4fa488a3dc36387157a7\",\"tags\":[[\"sigflag\",\"SIG_ALL\"]]}]", + "C": "02698c4e2b5f9534cd0687d87513c759790cf829aa5739184a3e3735471fbda904", + "id": "009a1f293253e41e", + "witness": "{\"signatures\":[\"60f3c9b766770b46caac1d27e1ae6b77c8866ebaeba0b9489fe6a15a837eaa6fcd6eaa825499c72ac342983983fd3ba3a8a41f56677cc99ffd73da68b59e1383\"]}" + }, + { + "amount": 1, + "secret": "[\"P2PK\",{\"nonce\":\"859d4935c4907062a6297cf4e663e2835d90d97ecdd510745d32f6816323a41f\",\"data\":\"02a60c27104cf6023581e790970fc33994a320abe36e7ceed16771b0f8d76f0666\",\"tags\":[[\"sigflag\",\"SIG_ALL\"]]}]", + "C": "02698c4e2b5f9534cd0687d87513c759790cf829aa5739184a3e3735471fbda904", + "id": "009a1f293253e41f", + "witness": "{\"signatures\":[\"60f3c9b766770b46caac1d27e1ae6b77c8866ebaeba0b9489fe6a15a837eaa6fcd6eaa825499c72ac342983983fd3ba3a8a41f56677cc99ffd73da68b59e1383\"]}" + } + ], + "outputs": [ + { + "amount": 2, + "B_": "02698c4e2b5f9534cd0687d87513c759790cf829aa5739184a3e3735471fbda904", + "id": "009a1f293253e41e" + } + ] +} +``` + +The following is a `SwapRequest` multiple valid signatures are provided and required. + +```json +{ + "inputs": [ + { + "amount": 0, + "id": "009a1f293253e41e", + "secret": "[\"P2PK\",{\"nonce\":\"c537ea76c1ac9cfa44d15dac91a63315903a3b4afa8e4e20f868f87f65ff2d16\",\"data\":\"026f6a2b1d709dbca78124a9f30a742985f7eddd894e72f637f7085bf69b997b9a\",\"tags\":[[\"pubkeys\",\"03142715675faf8da1ecc4d51e0b9e539fa0d52fdd96ed60dbe99adb15d6b05ad9\"],[\"n_sigs\",\"2\"],[\"sigflag\",\"SIG_ALL\"]]}]", + "C": "026f6a2b1d709dbca78124a9f30a742985f7eddd894e72f637f7085bf69b997b9a", + "witness": "{\"signatures\":[\"c38cf7943f59206dc22734d39c17e342674a4025e6d3b424eb79d445a57257d57b45dd94fcd1b8dd8013e9240a4133bdef6523f64cd7288d890f3bbb8e3c6453\",\"f766dbb80e5c27de9a4770486e11e1bac0b1c4f782bf807a5189ea9c3e294559a3de4e217d3dfceafd4d9e8dcbfe4e9a188052d6dab9df07df7844224292de36\"]}" + } + ], + "outputs": [ + { + "amount": 0, + "id": "009a1f293253e41e", + "B_": "026f6a2b1d709dbca78124a9f30a742985f7eddd894e72f637f7085bf69b997b9a" + } + ] +} +``` + +Example `MeltRequest`: + +```json +{ + "quote": "2fc40ad3-2f6a-4a7e-91fb-b8c2b5dc2bf7", + "inputs": [ + { + "amount": 0, + "id": "009a1f293253e41e", + "secret": "[\"P2PK\",{\"nonce\":\"1d0db9cbd2aa7370a3d6e0e3ce5714758ed7a085e2f8da9814924100e1fc622e\",\"data\":\"026f6a2b1d709dbca78124a9f30a742985f7eddd894e72f637f7085bf69b997b9a\",\"tags\":[[\"pubkeys\",\"026f6a2b1d709dbca78124a9f30a742985f7eddd894e72f637f7085bf69b997b9a\",\"03142715675faf8da1ecc4d51e0b9e539fa0d52fdd96ed60dbe99adb15d6b05ad9\"],[\"n_sigs\",\"2\"],[\"sigflag\",\"SIG_ALL\"]]}]", + "C": "026f6a2b1d709dbca78124a9f30a742985f7eddd894e72f637f7085bf69b997b9a", + "witness": "{\"signatures\":[\"b2077717cfe43086582679ce3fbe1802f9b8652f93828c2e1a75b9e553c0ab66cd14b9c5f6c45a098375fe6583e106c7ccdb1421636daf893576e15815f3483f\",\"179f687c2236c3d0767f3b2af88478cad312e7f76183fb5781754494709334c578c7232dc57017d06b9130a406f8e3ece18245064cda4ef66808ed3ff68c933e\"]}" + } + ], + "outputs": [ + { + "amount": 0, + "id": "009a1f293253e41e", + "B_": "028b708cfd03b38bdc0a561008119594106f0c563061ae3fbfc8981b5595fd4e2b" + } + ] +} +``` + +The following is the valid `msg_to_sign` on the above `MeltRequest`. + +``` +["P2PK",{"nonce":"1d0db9cbd2aa7370a3d6e0e3ce5714758ed7a085e2f8da9814924100e1fc622e","data":"026f6a2b1d709dbca78124a9f30a742985f7eddd894e72f637f7085bf69b997b9a","tags":[["pubkeys","026f6a2b1d709dbca78124a9f30a742985f7eddd894e72f637f7085bf69b997b9a","03142715675faf8da1ecc4d51e0b9e539fa0d52fdd96ed60dbe99adb15d6b05ad9"],["n_sigs","2"],["sigflag","SIG_ALL"]]}]028b708cfd03b38bdc0a561008119594106f0c563061ae3fbfc8981b5595fd4e2b2fc40ad3-2f6a-4a7e-91fb-b8c2b5dc2bf7 +``` + +The following is a valid `SIG_ALL` `MeltRequest`. + +```json +{ + "quote": "0f983814-de91-46b8-8875-1b358a35298a", + "inputs": [ + { + "amount": 0, + "id": "009a1f293253e41e", + "secret": "[\"P2PK\",{\"nonce\":\"600050bd36cccdc71dec82e97679fa3e7712c22ea33cf4fe69d4d78223757e57\",\"data\":\"026f6a2b1d709dbca78124a9f30a742985f7eddd894e72f637f7085bf69b997b9a\",\"tags\":[[\"pubkeys\",\"026f6a2b1d709dbca78124a9f30a742985f7eddd894e72f637f7085bf69b997b9a\"],[\"sigflag\",\"SIG_ALL\"]]}]", + "C": "026f6a2b1d709dbca78124a9f30a742985f7eddd894e72f637f7085bf69b997b9a", + "witness": "{\"signatures\":[\"b66c342654ccc95a62100f8f4a76afe1aea612c9c63383be3c7feb5110bb8eabe7ccaa9f117abd524be8c9a2e331e7d70248aeae337b9ce405625b3c49fc627d\"]}" + } + ], + "outputs": [ + { + "amount": 0, + "id": "009a1f293253e41e", + "B_": "026f6a2b1d709dbca78124a9f30a742985f7eddd894e72f637f7085bf69b997b9a" + } + ] +} +``` + +The following is a valid multi-sig `SIG_ALL` `MeltRequest`. + +```json +{ + "quote": "2fc40ad3-2f6a-4a7e-91fb-b8c2b5dc2bf7", + "inputs": [ + { + "amount": 0, + "id": "009a1f293253e41e", + "secret": "[\"P2PK\",{\"nonce\":\"1d0db9cbd2aa7370a3d6e0e3ce5714758ed7a085e2f8da9814924100e1fc622e\",\"data\":\"026f6a2b1d709dbca78124a9f30a742985f7eddd894e72f637f7085bf69b997b9a\",\"tags\":[[\"pubkeys\",\"026f6a2b1d709dbca78124a9f30a742985f7eddd894e72f637f7085bf69b997b9a\",\"03142715675faf8da1ecc4d51e0b9e539fa0d52fdd96ed60dbe99adb15d6b05ad9\"],[\"n_sigs\",\"2\"],[\"sigflag\",\"SIG_ALL\"]]}]", + "C": "026f6a2b1d709dbca78124a9f30a742985f7eddd894e72f637f7085bf69b997b9a", + "witness": "{\"signatures\":[\"b2077717cfe43086582679ce3fbe1802f9b8652f93828c2e1a75b9e553c0ab66cd14b9c5f6c45a098375fe6583e106c7ccdb1421636daf893576e15815f3483f\",\"179f687c2236c3d0767f3b2af88478cad312e7f76183fb5781754494709334c578c7232dc57017d06b9130a406f8e3ece18245064cda4ef66808ed3ff68c933e\"]}" + } + ], + "outputs": [ + { + "amount": 0, + "id": "009a1f293253e41e", + "B_": "028b708cfd03b38bdc0a561008119594106f0c563061ae3fbfc8981b5595fd4e2b" + } + ] +} +```