diff --git a/main/process/get_commitments.c b/main/process/get_commitments.c index 166a87cc..745928ec 100644 --- a/main/process/get_commitments.c +++ b/main/process/get_commitments.c @@ -15,7 +15,7 @@ static void reply_commitments(const void* ctx, CborEncoder* container) JADE_ASSERT(ctx); const commitment_t* commitments = (const commitment_t*)ctx; - JADE_ASSERT(commitments->content == (COMMITMENTS_BLINDERS | COMMITMENTS_INCLUDES_COMMITMENTS)); + JADE_ASSERT(commitments->content == (COMMITMENTS_ABF | COMMITMENTS_VBF | COMMITMENTS_INCLUDES_COMMITMENTS)); CborEncoder map_encoder; // result data CborError cberr = cbor_encoder_create_map(container, &map_encoder, 6); @@ -126,7 +126,7 @@ void get_commitments_process(void* process_ptr) goto cleanup; } - commitments.content = COMMITMENTS_BLINDERS | COMMITMENTS_INCLUDES_COMMITMENTS; + commitments.content = COMMITMENTS_ABF | COMMITMENTS_VBF | COMMITMENTS_INCLUDES_COMMITMENTS; jade_process_reply_to_message_result(process->ctx, &commitments, reply_commitments); JADE_LOGI("Success"); diff --git a/main/process/process_utils.h b/main/process/process_utils.h index dc4c7669..19bfe771 100644 --- a/main/process/process_utils.h +++ b/main/process/process_utils.h @@ -6,13 +6,16 @@ #include "../utils/cbor_rpc.h" #include "../utils/network.h" -#define COMMITMENTS_NONE 0 -#define COMMITMENTS_BLINDERS 1 -#define COMMITMENTS_BLINDING_KEY 2 -#define COMMITMENTS_VALUE_BLIND_PROOF 4 -#define COMMITMENTS_INCLUDES_COMMITMENTS 8 +#define COMMITMENTS_NONE 0x0 +#define COMMITMENTS_ABF 0x1 +#define COMMITMENTS_VBF 0x2 +#define COMMITMENTS_BLINDING_KEY 0x4 +#define COMMITMENTS_ASSET_BLIND_PROOF 0x8 +#define COMMITMENTS_VALUE_BLIND_PROOF 0x10 +#define COMMITMENTS_INCLUDES_COMMITMENTS 0x20 typedef struct { + uint8_t asset_blind_proof[ASSET_EXPLICIT_SURJECTIONPROOF_LEN]; uint8_t value_blind_proof[ASSET_EXPLICIT_RANGEPROOF_MAX_LEN]; uint8_t asset_generator[ASSET_GENERATOR_LEN]; uint8_t value_commitment[ASSET_COMMITMENT_LEN]; diff --git a/main/process/sign_liquid_tx.c b/main/process/sign_liquid_tx.c index 420da7fc..6fd433f5 100644 --- a/main/process/sign_liquid_tx.c +++ b/main/process/sign_liquid_tx.c @@ -193,22 +193,37 @@ static bool get_commitment_data(CborValue* item, commitment_t* commitment) commitment->content = COMMITMENTS_NONE; - if (!rpc_get_n_bytes("abf", item, sizeof(commitment->abf), commitment->abf)) { + // Need abf or asset_blind_proof + if (rpc_get_n_bytes("abf", item, sizeof(commitment->abf), commitment->abf)) { + commitment->content |= COMMITMENTS_ABF; + } + + if (rpc_get_n_bytes( + "asset_blind_proof", item, sizeof(commitment->asset_blind_proof), commitment->asset_blind_proof)) { + commitment->content |= COMMITMENTS_ASSET_BLIND_PROOF; + } + + if (!(commitment->content & (COMMITMENTS_ABF | COMMITMENTS_ASSET_BLIND_PROOF))) { return false; } - // Need a vbf *or* a value_blind_proof - if (!rpc_get_n_bytes("vbf", item, sizeof(commitment->vbf), commitment->vbf)) { - size_t written = 0; - rpc_get_bytes( - "value_blind_proof", sizeof(commitment->value_blind_proof), item, commitment->value_blind_proof, &written); - if (!written) { - return false; - } + // Need vbf or value_blind_proof + if (rpc_get_n_bytes("vbf", item, sizeof(commitment->vbf), commitment->vbf)) { + commitment->content |= COMMITMENTS_VBF; + } + + size_t written = 0; + rpc_get_bytes( + "value_blind_proof", sizeof(commitment->value_blind_proof), item, commitment->value_blind_proof, &written); + if (written && written <= sizeof(commitment->value_blind_proof)) { commitment->value_blind_proof_len = written; commitment->content |= COMMITMENTS_VALUE_BLIND_PROOF; } + if (!(commitment->content & (COMMITMENTS_VBF | COMMITMENTS_VALUE_BLIND_PROOF))) { + return false; + } + if (!rpc_get_n_bytes("asset_id", item, sizeof(commitment->asset_id), commitment->asset_id)) { return false; } @@ -217,10 +232,6 @@ static bool get_commitment_data(CborValue* item, commitment_t* commitment) return false; } - // Set flag to show struct is partially populated/initialised - no commitment overrides (yet). - // Passed blinders/unblinded values refer to commitments already present in the transaction outputs. - commitment->content |= COMMITMENTS_BLINDERS; - // Blinding key is optional in some scenarios if (rpc_get_n_bytes("blinding_key", item, sizeof(commitment->blinding_key), commitment->blinding_key)) { commitment->content |= COMMITMENTS_BLINDING_KEY; @@ -228,8 +239,8 @@ static bool get_commitment_data(CborValue* item, commitment_t* commitment) // Actual commitments are optional - but must be both commitments or neither. // If both are passed these will be copied into the tx and signed. - // If not passed, the above blinding factors must match what is already present in the transaction output. - // If just one commitment is passed it will be ignored. + // If not passed, the above blinding factors/proofs must match what is already present in the transaction output. + // Must be both or neither - error if only one commitment passed. if (rpc_has_field_data("asset_generator", item) || rpc_has_field_data("value_commitment", item)) { if (!rpc_get_n_bytes( "asset_generator", item, sizeof(commitment->asset_generator), commitment->asset_generator)) { @@ -316,24 +327,45 @@ static void get_commitments_allocate(const char* field, const CborValue* value, *data = commitments; } -#if defined(CONFIG_ESP32_SPIRAM_SUPPORT) || !defined(CONFIG_BT_ENABLED) -// Workaround to run 'wally_explicit_rangeproof_verify()' on a temporary stack, as the -// underlying libsecp call 'secp256k1_rangeproof_verify()' requires ~40kb of stack space. -// NOTE: a device with BLE compiled in but without SPIRAM does not have sufficient free -// memory to be able to do this verification, so atm we exclude it for those devices. -static bool explicit_rangeproof_verify(void* ctx) +#ifdef CONFIG_ESP32_SPIRAM_SUPPORT +// Workaround to run 'wally_explicit_surjectionproof_verify()' and 'wally_explicit_rangeproof_verify()' +// on a temporary stack, as the underlying libsecp calls require over 50kb of stack space. +// NOTE: devices without SPIRAM do not have sufficient free memory to be able to do this verification, +// so atm we exclude it for those devices. +static bool verify_explicit_proofs(void* ctx) { JADE_ASSERT(ctx); const commitment_t* commitments = (const commitment_t*)ctx; - JADE_ASSERT(commitments->content & COMMITMENTS_BLINDERS); + JADE_ASSERT(commitments->content & (COMMITMENTS_ASSET_BLIND_PROOF | COMMITMENTS_VALUE_BLIND_PROOF)); JADE_ASSERT(commitments->content & COMMITMENTS_INCLUDES_COMMITMENTS); - JADE_ASSERT(commitments->content & COMMITMENTS_VALUE_BLIND_PROOF); - return wally_explicit_rangeproof_verify(commitments->value_blind_proof, commitments->value_blind_proof_len, - commitments->value, commitments->value_commitment, sizeof(commitments->value_commitment), - commitments->asset_generator, sizeof(commitments->asset_generator)) - == WALLY_OK; + if (commitments->content & COMMITMENTS_ASSET_BLIND_PROOF) { + uint8_t reversed_asset_id[sizeof(commitments->asset_id)]; + reverse(reversed_asset_id, commitments->asset_id, sizeof(commitments->asset_id)); + + // NOTE: Appears to require ~52kb of stack space + if (wally_explicit_surjectionproof_verify(commitments->asset_blind_proof, + sizeof(commitments->asset_blind_proof), reversed_asset_id, sizeof(reversed_asset_id), + commitments->asset_generator, sizeof(commitments->asset_generator)) + != WALLY_OK) { + // Failed to verify explicit asset proof + return false; + } + } + + if (commitments->content & COMMITMENTS_VALUE_BLIND_PROOF) { + // NOTE: Appears to require ~40kb of stack space + if (wally_explicit_rangeproof_verify(commitments->value_blind_proof, commitments->value_blind_proof_len, + commitments->value, commitments->value_commitment, sizeof(commitments->value_commitment), + commitments->asset_generator, sizeof(commitments->asset_generator)) + != WALLY_OK) { + // Failed to verify explicit value proof + return false; + } + } + + return true; } #endif // CONFIG_ESP32_SPIRAM_SUPPORT || !CONFIG_BT_ENABLED @@ -347,42 +379,37 @@ static bool verify_commitment_consistent(const commitment_t* commitments, const return false; } - // 1. Check the blinded asset commitment can be reconstructed - // (ie. from the given reversed asset_id and abf) - uint8_t reversed_asset_id[sizeof(commitments->asset_id)]; - reverse(reversed_asset_id, commitments->asset_id, sizeof(commitments->asset_id)); - - uint8_t generator_tmp[sizeof(commitments->asset_generator)]; - if (wally_asset_generator_from_bytes(reversed_asset_id, sizeof(reversed_asset_id), commitments->abf, - sizeof(commitments->abf), generator_tmp, sizeof(generator_tmp)) - != WALLY_OK - || sodium_memcmp(commitments->asset_generator, generator_tmp, sizeof(generator_tmp)) != 0) { - *errmsg = "Failed to verify blinded asset generator from commitments data"; + if (!(commitments->content & (COMMITMENTS_ABF | COMMITMENTS_ASSET_BLIND_PROOF)) + || !(commitments->content & (COMMITMENTS_VBF | COMMITMENTS_VALUE_BLIND_PROOF))) { + *errmsg = "Failed to extract blinding factors or proofs from commitments data"; return false; } - // 2. Check the blinded value commitment - // Either: - // a) satisfies the provided 'value_blind_proof', or - // b) can be reconstructed (ie. from value, vbf, and asset generator) - // NOTE: only a device with SPIRAM has sufficient memory to be able to do this verification. - if (commitments->content & COMMITMENTS_VALUE_BLIND_PROOF) { -#if defined(CONFIG_ESP32_SPIRAM_SUPPORT) || !defined(CONFIG_BT_ENABLED) - // Because the underlying libsecp call 'secp256k1_rangeproof_verify()' requires more stack - // space than is available to the main task, we run that function with a temporary stack. - const size_t stack_size = 40 * 1024; // 40kb seems sufficient - if (!run_on_temporary_stack(stack_size, explicit_rangeproof_verify, (void*)commitments)) { - *errmsg = "Failed to verify blinded value commitment using explicit rangeproof"; + // 1. Asset generator + // If passed the abf, check the blinded asset commitment can be reconstructed + // (ie. from the given reversed asset_id and abf) + if (commitments->content & COMMITMENTS_ABF) { + uint8_t reversed_asset_id[sizeof(commitments->asset_id)]; + reverse(reversed_asset_id, commitments->asset_id, sizeof(commitments->asset_id)); + + uint8_t generator_tmp[sizeof(commitments->asset_generator)]; + if (wally_asset_generator_from_bytes(reversed_asset_id, sizeof(reversed_asset_id), commitments->abf, + sizeof(commitments->abf), generator_tmp, sizeof(generator_tmp)) + != WALLY_OK + || sodium_memcmp(commitments->asset_generator, generator_tmp, sizeof(generator_tmp)) != 0) { + *errmsg = "Failed to verify blinded asset generator from commitments data"; return false; } -#else - *errmsg = "Devices with radio enabled but without external SPIRAM are unable to verify rangeproof data"; - return false; -#endif // CONFIG_ESP32_SPIRAM_SUPPORT || !CONFIG_BT_ENABLED - } else { + } + + // 2. Value commitment + // If passed the vbf, check the blinded value commitment can be reconstructed + // (ie. from the given value, asset_generator and vbf) + if (commitments->content & COMMITMENTS_VBF) { uint8_t commitment_tmp[sizeof(commitments->value_commitment)]; - if (wally_asset_value_commitment(commitments->value, commitments->vbf, sizeof(commitments->vbf), generator_tmp, - sizeof(generator_tmp), commitment_tmp, sizeof(commitment_tmp)) + if (wally_asset_value_commitment(commitments->value, commitments->vbf, sizeof(commitments->vbf), + commitments->asset_generator, sizeof(commitments->asset_generator), commitment_tmp, + sizeof(commitment_tmp)) != WALLY_OK || sodium_memcmp(commitments->value_commitment, commitment_tmp, sizeof(commitment_tmp)) != 0) { *errmsg = "Failed to verify blinded value commitment from commitments data"; @@ -390,6 +417,22 @@ static bool verify_commitment_consistent(const commitment_t* commitments, const } } + // Verify any blinded proofs + // NOTE: only a device with SPIRAM has sufficient memory to be able to do this verification. + if (commitments->content & (COMMITMENTS_ASSET_BLIND_PROOF | COMMITMENTS_VALUE_BLIND_PROOF)) { +#ifdef CONFIG_ESP32_SPIRAM_SUPPORT + // Because the libsecp calls 'secp256k1_surjectionproof_verify()' and 'secp256k1_rangeproof_verify()' + // requires more stack space than is available to the main task, we run that function with a temporary stack. + const size_t stack_size = 54 * 1024; // 54kb seems sufficient + if (!run_on_temporary_stack(stack_size, verify_explicit_proofs, (void*)commitments)) { + *errmsg = "Failed to verify explicit asset/value commitment proofs"; + return false; + } +#else + *errmsg = "Devices without external SPIRAM are unable to verify explicit proofs"; + return false; +#endif // CONFIG_ESP32_SPIRAM_SUPPORT || !CONFIG_BT_ENABLED + } return true; } @@ -402,7 +445,7 @@ static bool add_output_info( JADE_INIT_OUT_PPTR(errmsg); JADE_ASSERT(!(outinfo->flags & (OUTPUT_FLAG_CONFIDENTIAL | OUTPUT_FLAG_HAS_UNBLINDED))); - if (commitments->content & COMMITMENTS_BLINDERS) { + if (commitments->content != COMMITMENTS_NONE) { // Output to be confidential/blinded, use the commitments data outinfo->flags |= (OUTPUT_FLAG_CONFIDENTIAL | OUTPUT_FLAG_HAS_UNBLINDED); diff --git a/test_data/liquid_txn_random_blinders_asset_proof.json b/test_data/liquid_txn_random_blinders_asset_proof.json new file mode 100644 index 00000000..15b4c156 --- /dev/null +++ b/test_data/liquid_txn_random_blinders_asset_proof.json @@ -0,0 +1,93 @@ +{ + "input": { + "network": "testnet-liquid", + "use_ae_signatures": true, + "txn": "02000000010278dabb82a679a70389c3cd45d9103dd8c30af23c91b47210c9a5ba933792124700000000230000000000000000000000000000000000000000000000000000000000000000000000feffffff77a0974a2431147cde839541f06328d6370096d1fac593bea59524ecd209df1600000000230000000000000000000000000000000000000000000000000000000000000000000000feffffff030a8347323badb12db15b892ac63ad1332352c48566953661b6e24440304a3ab19d0852c9d14ba48f52ec0ab6e5bf0cc64453815916e3cbe1d59ffe10d25bfed9ac0e02f89b431569ccd8baf8b5230bb9f8f1369ec6126ab94a42532f910301b9f9a9a117a91448aa7f7aa9e8618ca257243d7f1fba305db0fd84870bf379fdfd7a8e58500190cb8c6b1c4bb970ffd5b3c15aaf1e55e8d720c0b7a05409b35d0478d099bf975ee2093691d94e180e00b2abd48f88bcf461ef33b498b27803eacc70d98c5f0ea84e363b0534b93654aaf7a022ce6d5a4163e33430bdf66a7f17a914f569b49a86b71180614610e8d5605149720a5a018701499a818545f6bae39fc03b637f2a4e1e64e590cac1bc3a6f6d71aa4443654c1401000000000000011100008cb0040000000400480000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000051748c632103bfe3e0ae83aa5ed97d11ffd4ecdfb44e09d086b232bcb0fb1d4c13da4594b527ad6703ffff00b2756821030d14dd8299bc9c5747cb0a518e445b45a57df35d661006f4df1c864e7eb89649ac0000000400480000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000051748c6321038cc423bab95d2f71b38460c64c0424d400372b901d80edb4e9d9ce35cde5ba65ad6703ffff00b2756821028e307e4afd28effcbdbbfe2ae1c5578832c4793af93c1557f12a8eec9f8de768ac0063020003696d2c59ed6237dd693c6b420a1a478410306c85e5f13bdd7b86ebe15b6064ce1dd0b3b664f710554c70951438eb7591bf57d9c6d2df6cf536bd19a6d95da681e8b92dbd38f153c87e24ce647efffb603a52f030193e000daacb535f9b60d6c2fd4e10603300000000000000018173ea01ffee18cef696f0782cc982a00c2272cb507d92ceb27d495135fabc6a44182cd306cc82cacf2bfa93a187c04fe33db8f1c0aa0609ce307013405ad087c246bda6becf003e0840f14b046dfd852349a238d9e47b0ac3d1b0786f4901c272545acca91a32270bbcbc73294c02ff16d5b6364b139be7c6023618755970d80acf25ddf668037bab63a0095df5f13b8d8532b241086036d854c88cca2e7d43a40fb4095adbf1d0e94a9da5934c4cf0ebcf5f286210f22b4659404c6943380ef71b4d62a4db0ecb5f1bf23816637d8530f8cd03695e3e5645a48b3c29474d539dd9be2ef9af0522cc374ea6f95c22d75bf0d03f5f48d9c75cd98e51a395115d7d8fd9d2d7b9fd09a8fb9dac9c83fed6469d4fa217aeaf155a343079068a59d1ca61ac30e2efd095b3b918cf8499d7360abbb1482016466522a9c4a2f813151f84ca2e8aa66ad414f4a593a9e55f6e1b0f5d98bb5f3320e216f31ef8801e0c7debb01f7921a17d4e8873f1694b29b1d6fa2254e7cebbfc891d316c1d5ce97bbe9116bda3b6fde75e7e426168dda073a6c3a668716461654e0efd585c0b278c0b6bbadf2004247a2daf7491d75e4d0c4033dcc803ffd57e57c00c413154010daad3498137e8a6b33b34ee48acb43cb6e937aa3415c9d136729a087b22fb99a3ba975e5abbeaf7ea4e1311d645fe57793bfc68ad0df31ea55f18386d42e9b151c7ad85566b8c444d9e2f0cb93881eebf6ae64d1198b79576f53e19bfbd678c009fc6d89d4aa8d675adca0d3b8f56cf531ea6fb3d57f3f05610cf36938d320f68cd62b5be50f94569c2b03d4d01fcbfd1dc0cadfde52718f649a5a43cb95741224c035fc07587a694410cfa2a5a361bd4a0b055c389ddd61cfcd6200e25d790875515be0b7b9c139e55e72f1bee40d585b925a36903a32fb37cd77e624c242059a79ef38a0c193744380b2c35ab69d6d0101c2b911ef435343cd729ebfad017929c3529e6f01cdd70ac41d5b7060dd15829f0ae806a6d162a67371a41cb2bc21be518a6c780cf020885200df25ace80295064f16fdcae52dfe7d053619e0647295e92f688d47494454a61586defc3c736a55a0973d62d000a5e4151fbdb52e32a370944912e5f220f73e3f980240f32721f4f2941759724234b82bd76b22bbdb7d5ccffc628ba86f35adf74ee8e3490c89d02d54388bc03b595425f5e3559daff612e90eed74ea73e63627e16f01a20e40acff1da7fd574c41541e2d51cc795c3a2732e2f99f5eb4fb88eebbb945c4ce0876d0757fd96d930af91a6933401d27b6046227123ecc4fe7865c36dbe4729cf6bc92c4bdc1779ac8a4c2eac4d1e4999e9b211cb21079693f17eeccb3f3aefab865fe531ee96f16a5a35c9abd01396863c9e78deea1319343d8f56dfaa49935899c7a35c76911538849d054597ffa04a2e527507488c6c737d12c2f15757c5c04523e86f767bffe61d1f61c35d623b8d1920113fbd5ff9d63c440fd02ce3b0092a9f705820cf67cbab0364aa9443776b76324735a1a1b1f159d2333185b3edddf2879a5bf0c67ea5ddd1717440d6bd2d4a492fe6635ae9d13d0bc7e7a73548742b542de2447e3ec5dd9c3a9da029564d5719342d7a8705c00532d3b36d9a708b99c1841cc8d16fd4cbe988b787d968b0f4a18ec7f77e344fd3b73fe8c9655a777b1b9a1339809caa50e4cda297054a36f7967bc841de0f5ac3969c0c849482bb4684c4d85fd5265d80a97a694e6637a41cf6263dca7cafaeb974afab921dcc906c1141f850227d189c43ac62d02000e4b8001b4fd6ef94d951ebf6678054c32747be9e041b615368156e499a1ea333a3e760a3c7f355b8cf68a943ec19fff616dba215cafc28aef8ce991fbd6bc648c2e84ac64cd8af8c41821bacec9c03fe299037afa1a3861cc31301d751a77ebacfafb8aff7707edf1103ab8b1074f6395fb7b04248c0604596a398ed807fea1d7a44361a5f5182eb0fcedc5917acd1a975a159b31a471e1e12d73fb238868235192380e934ef74cb78d40e7e9f784e3dfbe5ccc5d876856716a6a94591f30a70c49c79bbb3b4f48a9fb3812a577b34ab99f36174252c3d4a67595f56140d16d0964d7bca71922d4f4b691e75fe69d4d04d1cc2031a54a9ecee59fef1cc158f272320abd67b04f726ffa056aa5b7c64ba91600812cbef928116bc516a5d0e35a77de7757716c535cd74fbf5d0f9156b637d6f40e11678abacecf365a43e25b6c1c5d15bebfb4357c86f9fbe366763a3e6962327f5e088b764db0dcc02bd1d6132dd91704239fb367e91126114cc1e2084b96d96068f45a279a495e82e63fb9f834f4021a463d7abbd5130ed34fdd2c01b75d608693924554531301bfc7fdeb27ed5598b1bdc98a7b7d4de08ab29de224c7a193962c32a78f760ee7a1dc45b9e27432d897f3a8933ccc264b614f816102df00591a186f0a1ca762ea62c1933e31a12ea9c00ccbd6d185119af901a72b24b4f644b85d858a708f5e94e7e5bb76e93760cd71075a267649f6bde0e259968df3f520cf023dc60fdd72ab1af4f5f0b152d2e0c5ab382829bd3a1551c47e3fd98418b12f829035c1a95393eeafb485dd72f39b95fa308e639abfe03c3dc1aff226ffff424a5f599659d424ee62c4c25259967c2c9873b849feae063c31b3b2f4accde620f95f37870231289e9ccf6fc61436bab2c62c6b4efcfc8cc9f79a9776a8a93dd11d27e3444c572ef87f4873d55edec4b826b9e7ae1e582e565500aeefd772b03995cc9ae1a1dbc5bfb3c93670cfe50340ed0252dc338528b6ca98d412cae859c09f2888faa2dabb87bd9564946669b128c526ea90c34e5847c66092d49c996f026fd740bfe07de4b1d9ec8a38a7d8552e5a71bcabbe2900b87c562c043c98314331d3a80be0aa9a506da7df1fc3880e4802fc560a1fa53f2ae22fdeff0d5be97a268dbd11aea6640f65422bd789e74761cd02e3cbd9a25526a85a57802b34f0cb4fb96c8a11feadcc490376d558ede4fe5739ee355e933f85d684186358988e8cc1823297a3a22212e75751c2bba9c9975cfba9abfba20b36e64e257014bf524889ff8d9705860856a57ddbe5aeed8ca76209668f6e7af9171dfa9b91fd840a22e5410145c3ee24dbcd8be1398eda98ebc57aeb0072b65005295bcb5a88b80ff72df569fea95654d4e9e76f0a319df6df7ecdc5aaa1f1966b54c439a7cfdf37dc91cc8b35975540e111ba8bfc927a3ac7b9689a5a605b2358f9bfd36bbb85885318e0cddd325b405b1c4437c8b20261bb00ee7edc104860a034ce2705f43199a1844d331a8855d3c0c97577cbb453de191b11f6120331e7b7a8e0553ac0d37638c64d9c20ddbca1243c7ae83b3a25b082e2e8539d4b78ac1ab989e0aed683b3a09befffbda014f16c38ee9495b197f85cde4ccec9d9b7047a447d56232488fb48764395a273f98843411425dbec0f77b0ca96af2b0d5e4623704e21592d602763937be0c194d6801ab3219d6bfa71e3d1c0c06ca86d7a48b1cccbae4cbfb81f0b2c57a19bfcb7ad0d2f8761c099f69c2c2be9366663c7328d6294c60ad78983d5f0a39904a62c9ad2e05b3d2ecffb1121cd8a6fc3c43b8ec7a4634a45351f29cf8a062aeb665bf793c02948cc03c23d854d9b5622d19cce1cddaa650aff22eec6c23b1270629fec05293bd607027ff973964e4b31aa385955fa95c91c5e00849f83316f87e1108917f12151a001f0f06c55f4572459483a7c7854e92deea387eaf2faf70bfdeadce802a56ad2a4144a0980b24d10dce672d2af9e683dfc5c6101febb7da21a23e6f2263c6e170cf5c0666baeff3d8907a9566eba93282ef6b3d3db056e19fd077890845ba84807c97bae4852b606c41da32758885ebb2b8da389e16205293dca9435115828a42eb4d1c430b89fbfb99b120c36d331b6b70049c98b6124bfbe44da60850314afce6e4d39337a521c894934f1455084960a5ef19aba21c68b3977e499cdfa4c2421b0029b51d13dd0d7b9d9c656828545994a489862971e6e5715f01f23e976f111f9431f36113405a2fa9688ef939c165662886204b3160c78aadf603bd24d644a1efdc733897cbe80335c4b658756f0bf353429b50f33127f6eff7a07eb4fea6e71b67adf802bb8744d72e1ee39877c1848c9328c64d54c264f4e6ceecfdd31c2bf153d2d42dcdd66d29861665cdf2fd2056074b4d0663c7651d1cc80638f53d84ab2d88c7d772ac33666ae2e94039c9f2910865d4814f468346a6b4a731467ad459940448d145474cf6a8837c2c8418c3665bba7afbb49d4f730e1b3b97cf019a048d440c04cb1da0e78b52660049742e1ec5265dbda09f25be5dfa2b407d22216489af000acee1b81913bd665a0134077661cd27b82691854671e80f4bb2e26adf9ff966f59b9c8eec79b01071eaa81c61775f902057ec8d049189b7a99af66c7a25c3843cf99fdb4d5876066f0a80fde6d0e56c5e7a1d0f4c8e652d8ec4d63c435d4fc926235649b01f9204f75b0b36dc0b16225536dc55184436f14089c2480542cb8aaac6bb4b890e86660a2063da83386adde655e7ea15837112371060df7f5fe611084145874e82f49c11fc2eed7ee2a8a258bde0900e75cb7efe28d5bb840850d64010c3fb98d63fb350b4a63a7077afe5269493cd0118d3c62f5b6a9948068729a6f3d1a9d4cdceaa8bc231083248a9123639e216b00d45583a067d43d71ad3b70c5b80214a35830407b20815facc53b3d6977d3353bb2efd4b97e49dc2f198953f2da72ba6d53a56cc644142590227fda2ef55674b89ef6a9fc5bcb32bd9c8083c10a7282b411560004048ae23af13d7aec0bb8ed04999fb619f89205ee06d3a8bbc53ea3e17c620eb1702a5fb22553459e428fa7082ab6f5c4d692b737b031de37ce7d4086d2113a18ffd0d069a28622c4be184f174d25f5bf0637252590bbc72fd5ed30dbc3bb69400f4f4a58b02ae7e6142421f0f60893cf0e6d184e65d680d7e593891b89965cc5c9b620d69acbf45b271d2100ca49a7a890989f89593b9fcdd72dc532b0ef926e93ffd93537515cc83af78da1c59aebdce29f54212fcfc00073a03bd6bddeca43a8ad3da0c8573b72c6c6862848639618249bf2f7809f0ea8fe29a7cce3a46a2609574715a70472aac68bafc855dae16abad8f1dab5a9b0cb08da7f671790c230d181ea3523077f29a945461bcf0fa72ba4ac47662cffb1af9c93dff5a1fedbea857508687a7c71bbb6edb1aab02eed6e79a7edd92ea0a27184861b684db298d4d9ec6c2267bec52780ddf9c5dbeddf1d5204dd1e72aabdfca4654aa08a22bf6f2a3967418516b9020e3067675c34cc4165d294ed79bcc1ba815ce705eed4427361d99838a8f61a7536cef861b9dd8279ebbaa90c34ecf42d9443c88a7cbe57d5c5e9942456edaa104d3ba371f0c7508f8c54a759b53f0fd4c6414df76647cc21dee193cdcc304b6afe03b08c44badcea20f79efd9f5ce0004b6a4ca58ca1fb75a330e026a47ed993ae271859879126472c603ad142dd6808cb793711ddd7622a57fcbbd7729baa27ea06657d640bc4f1d9e50be22c1b80212f752fedeabca517a22a402c4aa97542ce4a5e2d814bef8cc2e397fe90e7ba343a4515e5ba06600666dfd5741d0b665c196f2a08150af64b265bf74c93bb311b6bcee7bc60c147017a1d6a12f54f1d2aed22cde9611ccf8b54af066f510db27e604cb3709ab1c9b0c35a02e03dd7e900c29284e8e958effd36070031ec39f3b2d77fa610ec2a292e4e3924bba4971c7266ce7cb38650c920285664b3ae92b580a80398170cfeb8dd1742c4cffc814bb3cb6ab4e4c30a574fc0a253f946d6098630200032d8d9106c3c366423c1a30895c884ea0613ccec860656cd5432908f870238c37d488d43656d30c72671c4db93ebb7f746be76b4fd8feef9b58972e5955eff642019644f4447259b4e3ddc8c9ed37e59dd5bdf9ea42e8b41b67c0fa9be31ebb7bfd4e10603300000000000000011c1b9d00fbd248207378607c1bbe3b68c825e0477a7714ac274fba50b4b77f1bd41f29b1d7b0af4556346a8c002fb77b4e7bda3dd3aebb676409b21887534ca7bd01e22405d98f529673cfcfb166bae323bede0dcfeb47a63fa15099a1206965052c3239f735db943233f6716eb57f3296dd0a70ed34c1bc68accdc24d5aea1f438cd304e520db9d029bc3a1b5f87bd24a480958a73b9bec68e4f1910dccc5dfb2a41199f6cf7abdd2a87a21b56d509099c617c4bed97b363fdc02a14d9bb77cc65b807798cdc3c93781d8f498e6255282d4169a17952ac997b812ad53332fbb17abc79123519dd9a5a41a3240c95d9ea2a2b373b2137f9c5113ecc9e0286468e24d17613bf3ccb958d5bf9ced20d822308baa789b2ee150072b9a74ad8bcf3a670332f9d920809030a69849a0d17a212525802a43ac7945be4d575dc4966386d1716bc3082fd387e093ac417a75dd72018e060beb23aca008870f590c7e6eba9cf88ffb089e32847de7050b58064456b4ed0d3c52f4b01d7691b41f2dd3e0f04c6c22b5ba6640f171e3dd99b3091c64d872e28a8225abf066318467d12b8486e4b7dfc75d90c173011aed0b1ee9b5a8e9a5db0813a1758d75e4a0b9ec7012d1e2ba88d577d951dee0c348f83e6fd550eae11528cba7b844e53d86cdb4dfae4050414da034eb5c81c2bf35326c1c1d12b95576ff0b130c297abb559f01d5e1dde51fe5a27c4583d9390c41585a2f17278fb0fca493fcca1b8798efe159977b459e340331ae48329062ad454d14a01c7ec04dc3bdd17b0d5ebde7d80e13ade498c7513ce2cb02fd2a724f7078cbae071b849b887437a043a9f571dd27b3f53b906824683b13c811b9cfa7bbd62796362125bae0928ffe448c6ea58ab57e58cb9f295ed1d59b13d201ebca13d0e9702bbfe26a7af40ca620b067bfcecd1d31c05791fd859b560e1c3b7fe931cbc877b105137a68373bd200d60a1b0002535749b13f043bbdb67f7a6f9d91fc897d86853b5c587a011f4ccd8b4e6929bb1abaf0f50d88c60e220c5c0733646eeed17445c2163248792723674f962ac2acaec38de683c8cff62240b4b1ca5b8641eb60113abc05ce5233ec9b6d451e031f9b45d82a2c61626255cc4dc98de04859ad02932653736282c279b9246a05919741d2c0a03a4cd6b02b3ffddd75c66e8fc720c12e561f968ce21d6f8cbbb6db2a611b86b4aa5a70f1d81d162debca5c4a83840648404ff4c6ddb701ba08bbbf75dc1025eb5e3b33cf6026ee5d0be97e6e449beca3bdb739bb2cc9d12a7bf7b5f64f2667df4568f0f143dd89f0a3870fa6f4b61926a772409085948700786a40ecf8c044ed533097bbd2a1c5f3906bb79559b137fa47844453fdd5ac2bd59c72bdd45bd08708976ba80917f7a97a2afae360f28292010fa274bf7acc09549ae48a83c50e0c8a483fba459735eaa317b0e72f664617440386dc337ae667be9571480fcd123a66b1fbe30525bb1605435337c91358d602b3403b525dec10f334097c65619ba5c20fc52a03c65bed574d0a873e2bf088c8d514f58a0b50e84dda7996deb7248f3eb1e254018f31cdbc46d62c96dc871aef4febdf689586d5ead40da1dc723b492e04a7c5ef2116f4e5940256a83a477681a67811b3a57f21692baffa2143291bde3e91fc3a7e1f754de21661a0e3e718560d9655eb1133ab245d561d0312ff1841165814e422d74290ef7432247752105c65ff71faa9242d5edc175d1535f7ebcdaeee20ddb0a68dbd0a854baa1db2c1302cfac4de26117409d6a0b2ddd7934bcea4980d31d488be89764a85b5acd69cef850b3d76858100210146ba66c0e6ca96229a8561de0578b7da170c194d103afa546edb70e4148b51e3638630d38904cae379d33f023a41e19bd70cfbdd4c214a04a91568ff28ecc2def5e17a679890367ed647e151b81259b53ed4f262e43bd292e39e4abf78789c66c9abb832c08266640f1d209ba872dbf92057f641cc0cdbae17deb92183309ab4fb3d2353b39acb6b2988ce6f908096eef9276b1d74d52591672fd61aeb222be065f83811c29f8a212a7243a088e04eb7387cdd7eeee4ddf8505c962e53e3b416ebb36e65031c90f81c15df96bb0fd537340a7b9f7e70addac0eccda6cacfa7d6468bdee7f39080c45a9dea454aaa0dfef82a35e5cc07b3f440e6c7137cb1d9957dec892bd6b5e6b8cd5dd59c1117ac97a0d2cc1983be16ab3442b84a4f03a1237f68e3d8165ddb9dd103a87f164c32af646810efd39953de5f8a05b67688c3ebbee9dc208e94f1145573b0bb9e5529a4be510317a4dc11534bd13d8ff92944b8092d83fd215d1583d9267ffd0826327edfc3c14a15ba694625951dbc853aeb463a6670c5f29f9d4fb5640f886c67cfd78320642a31195127cdb515560ad35913713f8cba2d8c32e407b43706a58eda1bdf9846685d6fd2ea2e01365256418ba8c30012d1b92b27a02f45873377b478f3afa74eab26ae539890b181f1a8636009dbdf3d51c3ea8fea23b9355af261d4da0ffe8517d7091931caf5547b684070f56484f2c04e2f7f8a1feb6e59e90e0bed4c31c4298e2cd773b41dbe7614fdff0cc8bafad4f7d24f1c6f36f43faa1f5bdc18fbe5b72b35be40f6fdb2c45cd4edcab359138ee21f8c345d7ff8fde0f7f03ceb04f31b9b9f0b1eeac8e067d6ef725a0d88d91fd8118e04aca24f054d497029ec4fe8eaca750b9b6b8415280e02597e2d91c9729ea16040cbc8d59901841f562b14eef65b86ee36d8b2b8420c5c4ec13332226514c968f2f34e7cb4f375cee795bed05933f63018a706812c3adfae55a7aaa3066feb7114aecf5f48b7d2fbf3b716495a6165f00d9302475bca49d5836625159a91e39e46b73038ec772e448b3b5c6e159cdd4146fbb282ee6fa0885e18b86968d9335cf50bda1c083c72e064c116ae5e569573078b352916084decc2f74c3492a1ce5b602d7afa71b20e1ba1ba8d1d17f7ff5c836f1d2cb65d066250792470c3e40d6e849ce8869c9065d2a149f51889a24559ee94025547b07ce2e176d015b715274a946da6da8069bb86a1d04d711ed1876e13ec0f034f7e7c3885c53ef4c5ce5503a1ed8505b122a6dc26c631bdce08743aa4d0157b358a49b181f8dfa8fe45ff31cf8bcae6df5e8943aee63c8b6532104a07cb53acebe17eeb926c2d9a6f8f2da9cbacecd8a1fbccd6650fba2436233898c5b3dcd9e37229e20742a4d7baa9d0b03a95baa81aa0834f394074f8d005c31baff7c84e31ad238ce9b696809cf59d162cbaef7402c89af42aaa6b66c3d66589ecf9349f8721455d8e5b7bbb1169d9dfda4aba871dce5b2651575c4d10ad150898f521f198fe812934fb13702eefe4ebad7aad185fa40436f77b6d00ce7f5eafc376c8a1ad12b1b5ee91f265f7fe5bbd85a146dd77967e4eabcd523ed74381b6c4649e068c9724a42ee9c5ac9193f4e5dfe0ffcb88900cf75e5142461af23d61360fed582e342e9ba8e7cb6abaf5b2d0dbe3413c22c1b174f37a5dcac78a17e6fabba04c4c3de756b0a9c23006036d80a882c4b78bf2fb99d357b2877c443d52ab771b8061298bda6ff829fdce986db93a8adcf044dfa3a226460312b8f6d5d6afca6610fa570f3d5e358c1b58b2dde2bb3e7128427aef8eb9465b2e787a04991200539125aea00e62b6f6464b3a22d3682a0ef11a92f652bc56ec83acb3976e0d89f7f8fd9e1b9c7f5114ea8a2dc216fdd30cb253f9fa1d9440c4e2e8ad919ca971d9d6fbec57f08d3c0182ce4cf9af26ef2230c0c015a8da3f9fec27563be9a8775273eaef0a2302ca383bd7dbe0a6e793f5cf4f9e1f2825c37282977379e9cc5b9cac9bc58d114990b3452b5a6bf9f09d9165e06f23d909e27e0122f43141c6739ff4fd864d2d4cb9dd745d98fbfb3716e2cd514c339ead9394abd032186587dc97aeef3568540735a2777c267c4a955c4db15bdb80cc58dcff10c400fb69919f8912e58b7060eeccc1bb49e8c77a646e88bb45061659dcf71a6c807daaa747fc61f9d2ed62377e22a5e9ba2d1854c51aea3bb9d32fb2c1dc1a8f787a329f4829286499bf4ee18fe9b1bf1c0b621ae0a9f43f48e3ced8b42481e88db72ececa2c576eb45a97d4067702b48c21a3204ea008e771882a2bd4794cbb39475015d5792bbb3680263f3eba58dd6809b557de177291bad203008a67bb85c61340e62440c680afb216133511356accaa5c78640f8103c07ca8509ef07ab4d914392e279b7911ff862deeac2fe5a8bd2ac476bff8ea105d313b615336637029c59e31b747c4303ee8c4e9c93b4f576f6307b1e9a5dc50a58c0c3bd32e33bd452e4af8f094a8983e643f33046d8e2a9503c80e0e57c5e2bff971228ac83633701e271dff8468199b629e95b3618b11d753b30d5f9a70388bdea3db8c6a5094fb6b58349433adc525b76266a31cdf7ccd955d3774828f6b9e69acf663c5b3c9c1884879a0a11afb1023838b1e3be392cd5ca03a754688a378ee5c698e621731dec5820b776187910af57ea266222f8e63a5c93a916345612fcff5731cb94dff802e9509f17737e12430afbead6f1163f777eb06d9950cf4e4e2b6367888661c4ea84f6cc7f0e9f145889f1adde72e0908a2845d1e87100a807398a2becb669b095d43ad3304f2e0c79e65fd262269483ec1d0b5d89c6ac7a2b7c61d6f199fd030012386cfd559de61baaaedeb4562a5342523bc5758a2c58d11aef612256404b0b66429d07eea4c88a6168ebac7e952cd4b8e841c629f3a7cd4273f0ca8392824c7c878a8794bf4eba4d3cb36cad6fc1ac9f78107e2d71e4eb2ae07eca300ae8b9a65cf324cc81a125f9e075fd378239931d5e6df84f69c8814a115a9ab63032503f267d509cadfbb066e93d4131ec4701016af22981450462154d6f78c2369ac0c5a88833e14a223109676f68ab66af9876c72ab1a3db011eaeb025d77d6183d8a727b882d05890cc4b2a53ac1907fb46b5b2c3e8ba7c0eb548e77a009b846d03a4014ac5b902722a7e3cb538a5b788466749ccf49c87d1c04c2ed9b7957e452025d0dd48bca3ed47198d5f55d7cd3eab7ca4415309e09629ff4787fdb2f6c37d804b2022a5ff7f44d9ce3b87bb534e3f54cd4ee55558097a3715c39219746ffa145a8c7b8454fbad92898ea23cdac2f1706323a22395c7a95e52ff9695daa21bc4d19a3b5585967c665dc87ff20b526ab85407d600165c2855af3572351ffda531a66126b85683d9912ecc501d510243fb5ae070045d85b8f9beba70e9628de932cbf9cf9beeeb75483d6b23532a568d6f88a43951d058cac5347af8add04564808a2fe9ee365f807036a055a1e24aac3bf3f0a6bda40503380fbaf4dbd4c9c5ca6e2ff44a178da6b62e695204ca5cdb64007f646daf2adc9bdfd36329594fbe8645bb2f802af382a629f2672b9e09b3065f5cd8da9b0280b4ee3eb5792d872e696e4b0013bcc9175f2e68c66166f57811bd84cd684ec8b2387529a0d583f21d8cbd8c9c1933c5574cc9ee5d83b4b94940829225b0012bf551e6a55a939a334cfe006b815b9d1bf4e7a07a5d989c51c156c0eafadb670797bb593653a7cd0ec75ba3ca6a1a288758188f72c52157bde2ee819a691eb09b9c0ed9a80d71ec19a35c6a7d5c65cd8c6b64af995a5a695a88d36cd91e8bde73785ed6df89ee509cc515274c9d2fbaa8402bbef24e698c5a187988cef50260023280f514dcad02bf6cfe67dfd89e0be6caa79fc6076a7b1e8ef2f7215e07b03ab69c4b3e106f82122cfb35ebcae6d55a30ef39139c41742b6e05506f5aef1a8a1ebeeb97d3851b3d29f225b0007ccb110597342af39ee829f9280aef0fe260000", + "asset_info": [ + { + "asset_id": "38fca2d939696061a8f76d4e6b5eecd54e3b4221c846f24a6b279e79952850a5", + "contract": { + "entity": { + "domain": "liquidtestnet.com" + }, + "issuer_pubkey": "035d0f7b0207d9cc68870abfef621692bce082084ed3ca0c1ae432dd12d889be01", + "name": "Testnet Asset", + "precision": 3, + "ticker": "TEST", + "version": 0 + }, + "issuance_prevout": { + "txid": "0e19e938c74378ae83b549213a12be88ede6e32e1407bfdf50c4ec3f927408ec", + "vout": 0 + } + } + ], + "trusted_commitments": [ + { + "vbf": "c72c6aec382fd643d66aeb6bc953f713dbd8b4b09ad661adedc886af759bd531", + "blinding_key": "02232424317a3b8f7c3880d0d05e30f7381414299ef59566046133fa796741d02b", + "asset_generator": "0a14397507823e3f56002e09df5c25dd46dc7ac7317cf337ff004f36419471d9f6", + "value_commitment": "09ab421af012daee0415c3b7412b92a83a73ab91e9b737edf27d20b3a512624169", + "asset_id": "38fca2d939696061a8f76d4e6b5eecd54e3b4221c846f24a6b279e79952850a5", + "asset_blind_proof": "0100017454d5579ec0def281d4712c832e98af69208af4146ba691841d6605088e16c55cb5bffdbad36202475d94dea902fbcfa8c428ab7b3901e92df8b201ac865da3", + "value": 100 + }, + { + "vbf": "139cb6dcd5c48b2448ac78abc23d07080f9f941ced7f4f04da73f1a15f8b3326", + "blinding_key": "034fa5e74bf5a2998e4b0fb94eb14631c3a3588c035d151e548be3ed6c5302f2d1", + "asset_generator": "0b171c287d26dab3d69a23b9c0d45fb38f67abbd5093591acffb871e03c89cdbb4", + "value_commitment": "09deebaac97419f45ff834ad61c4a9afcf09e7750628ab0fb7b163df4f96c629b4", + "asset_id": "144c654344aa716d6f3abcc1ca90e5641e4e2a7f633bc09fe3baf64585819a49", + "asset_blind_proof": "010001d1afdefcb5524c48fa37eab82026a4e2c28ac69f6d78fb293c619df5deb32221d1879395c1046269330701ea9dd1bd51dcd0451aca1cce2f67e11dc4ec897811", + "value": 294727 + }, + null + ], + "change": [ + null, + { + "path": [ + 1, + 71 + ], + "is_change": false, + "csv_blocks": 65535 + }, + null + ], + "inputs": [ + { + "is_witness": true, + "script": "748c632103bfe3e0ae83aa5ed97d11ffd4ecdfb44e09d086b232bcb0fb1d4c13da4594b527ad6703ffff00b2756821030d14dd8299bc9c5747cb0a518e445b45a57df35d661006f4df1c864e7eb89649ac", + "path": [ + 1, + 49 + ], + "value_commitment": "08f615d657a23c6e49253ccd5e9f56cecb76d72c2d0ee6ad6729ebf1aaa573d816", + "ae_host_commitment": "57007bfa6e9b953150f24e691ec7a9ec255fe0f442e614a366c3ed9a3e3fd05f", + "ae_host_entropy": "4b275b6506148e82207b70924047e0deaba28d8dfee33282c8461bda63423f69" + }, + { + "is_witness": true, + "script": "748c6321038cc423bab95d2f71b38460c64c0424d400372b901d80edb4e9d9ce35cde5ba65ad6703ffff00b2756821028e307e4afd28effcbdbbfe2ae1c5578832c4793af93c1557f12a8eec9f8de768ac", + "path": [ + 1, + 61 + ], + "value_commitment": "08a29dcfc292b5fcfb45db3c2f4f1dbeceb6ab42605b7c1f45bf376c99ee0134e0", + "ae_host_commitment": "7d102a25bc39c1b29d5f4978d03deb2a9c479a4a213cf3133149cb2c02f42b0c", + "ae_host_entropy": "c81af0a035aa81b9fc9958c9b5d0ad4bb37f5685293748ae025d09c1cf89d58b" + } + ] + }, + "expected_output": [ + [ + "02f85fdaf4284b0942360736d397fd5115a3a4f7bd87b6097f72d6f32e0cebd6c0", + "3045022100d7f0319b5ef6ed2cf84924bba4da716299718ac705bd6ac6c39db8a1456088d8022063b7ef9902aae1b8011c67074c26a885aa6c17328c88708c3003b67be80f958201" + ], + [ + "03ef0e3a467739dd535af59ae0782a4158bef3a7b3835a387421ca0d9485e11fc0", + "3045022100da2cabb04abe19490e872c90bf664824a9d329bf38949e948534a0f0fefd86b402204fc0bc6a0629306780dbe77453dccc14234aaf1c2de5f01564bc888c098fc8ed01" + ] + ] +} diff --git a/test_data/liquid_txn_random_blinders_asset_value_proofs.json b/test_data/liquid_txn_random_blinders_asset_value_proofs.json new file mode 100644 index 00000000..4a5017c8 --- /dev/null +++ b/test_data/liquid_txn_random_blinders_asset_value_proofs.json @@ -0,0 +1,96 @@ +{ + "input": { + "network": "testnet-liquid", + "use_ae_signatures": true, + "txn": "02000000010278dabb82a679a70389c3cd45d9103dd8c30af23c91b47210c9a5ba933792124700000000230000000000000000000000000000000000000000000000000000000000000000000000feffffff77a0974a2431147cde839541f06328d6370096d1fac593bea59524ecd209df1600000000230000000000000000000000000000000000000000000000000000000000000000000000feffffff030a8347323badb12db15b892ac63ad1332352c48566953661b6e24440304a3ab19d0852c9d14ba48f52ec0ab6e5bf0cc64453815916e3cbe1d59ffe10d25bfed9ac0e02f89b431569ccd8baf8b5230bb9f8f1369ec6126ab94a42532f910301b9f9a9a117a91448aa7f7aa9e8618ca257243d7f1fba305db0fd84870bf379fdfd7a8e58500190cb8c6b1c4bb970ffd5b3c15aaf1e55e8d720c0b7a05409b35d0478d099bf975ee2093691d94e180e00b2abd48f88bcf461ef33b498b27803eacc70d98c5f0ea84e363b0534b93654aaf7a022ce6d5a4163e33430bdf66a7f17a914f569b49a86b71180614610e8d5605149720a5a018701499a818545f6bae39fc03b637f2a4e1e64e590cac1bc3a6f6d71aa4443654c1401000000000000011100008cb0040000000400480000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000051748c632103bfe3e0ae83aa5ed97d11ffd4ecdfb44e09d086b232bcb0fb1d4c13da4594b527ad6703ffff00b2756821030d14dd8299bc9c5747cb0a518e445b45a57df35d661006f4df1c864e7eb89649ac0000000400480000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000051748c6321038cc423bab95d2f71b38460c64c0424d400372b901d80edb4e9d9ce35cde5ba65ad6703ffff00b2756821028e307e4afd28effcbdbbfe2ae1c5578832c4793af93c1557f12a8eec9f8de768ac0063020003696d2c59ed6237dd693c6b420a1a478410306c85e5f13bdd7b86ebe15b6064ce1dd0b3b664f710554c70951438eb7591bf57d9c6d2df6cf536bd19a6d95da681e8b92dbd38f153c87e24ce647efffb603a52f030193e000daacb535f9b60d6c2fd4e10603300000000000000018173ea01ffee18cef696f0782cc982a00c2272cb507d92ceb27d495135fabc6a44182cd306cc82cacf2bfa93a187c04fe33db8f1c0aa0609ce307013405ad087c246bda6becf003e0840f14b046dfd852349a238d9e47b0ac3d1b0786f4901c272545acca91a32270bbcbc73294c02ff16d5b6364b139be7c6023618755970d80acf25ddf668037bab63a0095df5f13b8d8532b241086036d854c88cca2e7d43a40fb4095adbf1d0e94a9da5934c4cf0ebcf5f286210f22b4659404c6943380ef71b4d62a4db0ecb5f1bf23816637d8530f8cd03695e3e5645a48b3c29474d539dd9be2ef9af0522cc374ea6f95c22d75bf0d03f5f48d9c75cd98e51a395115d7d8fd9d2d7b9fd09a8fb9dac9c83fed6469d4fa217aeaf155a343079068a59d1ca61ac30e2efd095b3b918cf8499d7360abbb1482016466522a9c4a2f813151f84ca2e8aa66ad414f4a593a9e55f6e1b0f5d98bb5f3320e216f31ef8801e0c7debb01f7921a17d4e8873f1694b29b1d6fa2254e7cebbfc891d316c1d5ce97bbe9116bda3b6fde75e7e426168dda073a6c3a668716461654e0efd585c0b278c0b6bbadf2004247a2daf7491d75e4d0c4033dcc803ffd57e57c00c413154010daad3498137e8a6b33b34ee48acb43cb6e937aa3415c9d136729a087b22fb99a3ba975e5abbeaf7ea4e1311d645fe57793bfc68ad0df31ea55f18386d42e9b151c7ad85566b8c444d9e2f0cb93881eebf6ae64d1198b79576f53e19bfbd678c009fc6d89d4aa8d675adca0d3b8f56cf531ea6fb3d57f3f05610cf36938d320f68cd62b5be50f94569c2b03d4d01fcbfd1dc0cadfde52718f649a5a43cb95741224c035fc07587a694410cfa2a5a361bd4a0b055c389ddd61cfcd6200e25d790875515be0b7b9c139e55e72f1bee40d585b925a36903a32fb37cd77e624c242059a79ef38a0c193744380b2c35ab69d6d0101c2b911ef435343cd729ebfad017929c3529e6f01cdd70ac41d5b7060dd15829f0ae806a6d162a67371a41cb2bc21be518a6c780cf020885200df25ace80295064f16fdcae52dfe7d053619e0647295e92f688d47494454a61586defc3c736a55a0973d62d000a5e4151fbdb52e32a370944912e5f220f73e3f980240f32721f4f2941759724234b82bd76b22bbdb7d5ccffc628ba86f35adf74ee8e3490c89d02d54388bc03b595425f5e3559daff612e90eed74ea73e63627e16f01a20e40acff1da7fd574c41541e2d51cc795c3a2732e2f99f5eb4fb88eebbb945c4ce0876d0757fd96d930af91a6933401d27b6046227123ecc4fe7865c36dbe4729cf6bc92c4bdc1779ac8a4c2eac4d1e4999e9b211cb21079693f17eeccb3f3aefab865fe531ee96f16a5a35c9abd01396863c9e78deea1319343d8f56dfaa49935899c7a35c76911538849d054597ffa04a2e527507488c6c737d12c2f15757c5c04523e86f767bffe61d1f61c35d623b8d1920113fbd5ff9d63c440fd02ce3b0092a9f705820cf67cbab0364aa9443776b76324735a1a1b1f159d2333185b3edddf2879a5bf0c67ea5ddd1717440d6bd2d4a492fe6635ae9d13d0bc7e7a73548742b542de2447e3ec5dd9c3a9da029564d5719342d7a8705c00532d3b36d9a708b99c1841cc8d16fd4cbe988b787d968b0f4a18ec7f77e344fd3b73fe8c9655a777b1b9a1339809caa50e4cda297054a36f7967bc841de0f5ac3969c0c849482bb4684c4d85fd5265d80a97a694e6637a41cf6263dca7cafaeb974afab921dcc906c1141f850227d189c43ac62d02000e4b8001b4fd6ef94d951ebf6678054c32747be9e041b615368156e499a1ea333a3e760a3c7f355b8cf68a943ec19fff616dba215cafc28aef8ce991fbd6bc648c2e84ac64cd8af8c41821bacec9c03fe299037afa1a3861cc31301d751a77ebacfafb8aff7707edf1103ab8b1074f6395fb7b04248c0604596a398ed807fea1d7a44361a5f5182eb0fcedc5917acd1a975a159b31a471e1e12d73fb238868235192380e934ef74cb78d40e7e9f784e3dfbe5ccc5d876856716a6a94591f30a70c49c79bbb3b4f48a9fb3812a577b34ab99f36174252c3d4a67595f56140d16d0964d7bca71922d4f4b691e75fe69d4d04d1cc2031a54a9ecee59fef1cc158f272320abd67b04f726ffa056aa5b7c64ba91600812cbef928116bc516a5d0e35a77de7757716c535cd74fbf5d0f9156b637d6f40e11678abacecf365a43e25b6c1c5d15bebfb4357c86f9fbe366763a3e6962327f5e088b764db0dcc02bd1d6132dd91704239fb367e91126114cc1e2084b96d96068f45a279a495e82e63fb9f834f4021a463d7abbd5130ed34fdd2c01b75d608693924554531301bfc7fdeb27ed5598b1bdc98a7b7d4de08ab29de224c7a193962c32a78f760ee7a1dc45b9e27432d897f3a8933ccc264b614f816102df00591a186f0a1ca762ea62c1933e31a12ea9c00ccbd6d185119af901a72b24b4f644b85d858a708f5e94e7e5bb76e93760cd71075a267649f6bde0e259968df3f520cf023dc60fdd72ab1af4f5f0b152d2e0c5ab382829bd3a1551c47e3fd98418b12f829035c1a95393eeafb485dd72f39b95fa308e639abfe03c3dc1aff226ffff424a5f599659d424ee62c4c25259967c2c9873b849feae063c31b3b2f4accde620f95f37870231289e9ccf6fc61436bab2c62c6b4efcfc8cc9f79a9776a8a93dd11d27e3444c572ef87f4873d55edec4b826b9e7ae1e582e565500aeefd772b03995cc9ae1a1dbc5bfb3c93670cfe50340ed0252dc338528b6ca98d412cae859c09f2888faa2dabb87bd9564946669b128c526ea90c34e5847c66092d49c996f026fd740bfe07de4b1d9ec8a38a7d8552e5a71bcabbe2900b87c562c043c98314331d3a80be0aa9a506da7df1fc3880e4802fc560a1fa53f2ae22fdeff0d5be97a268dbd11aea6640f65422bd789e74761cd02e3cbd9a25526a85a57802b34f0cb4fb96c8a11feadcc490376d558ede4fe5739ee355e933f85d684186358988e8cc1823297a3a22212e75751c2bba9c9975cfba9abfba20b36e64e257014bf524889ff8d9705860856a57ddbe5aeed8ca76209668f6e7af9171dfa9b91fd840a22e5410145c3ee24dbcd8be1398eda98ebc57aeb0072b65005295bcb5a88b80ff72df569fea95654d4e9e76f0a319df6df7ecdc5aaa1f1966b54c439a7cfdf37dc91cc8b35975540e111ba8bfc927a3ac7b9689a5a605b2358f9bfd36bbb85885318e0cddd325b405b1c4437c8b20261bb00ee7edc104860a034ce2705f43199a1844d331a8855d3c0c97577cbb453de191b11f6120331e7b7a8e0553ac0d37638c64d9c20ddbca1243c7ae83b3a25b082e2e8539d4b78ac1ab989e0aed683b3a09befffbda014f16c38ee9495b197f85cde4ccec9d9b7047a447d56232488fb48764395a273f98843411425dbec0f77b0ca96af2b0d5e4623704e21592d602763937be0c194d6801ab3219d6bfa71e3d1c0c06ca86d7a48b1cccbae4cbfb81f0b2c57a19bfcb7ad0d2f8761c099f69c2c2be9366663c7328d6294c60ad78983d5f0a39904a62c9ad2e05b3d2ecffb1121cd8a6fc3c43b8ec7a4634a45351f29cf8a062aeb665bf793c02948cc03c23d854d9b5622d19cce1cddaa650aff22eec6c23b1270629fec05293bd607027ff973964e4b31aa385955fa95c91c5e00849f83316f87e1108917f12151a001f0f06c55f4572459483a7c7854e92deea387eaf2faf70bfdeadce802a56ad2a4144a0980b24d10dce672d2af9e683dfc5c6101febb7da21a23e6f2263c6e170cf5c0666baeff3d8907a9566eba93282ef6b3d3db056e19fd077890845ba84807c97bae4852b606c41da32758885ebb2b8da389e16205293dca9435115828a42eb4d1c430b89fbfb99b120c36d331b6b70049c98b6124bfbe44da60850314afce6e4d39337a521c894934f1455084960a5ef19aba21c68b3977e499cdfa4c2421b0029b51d13dd0d7b9d9c656828545994a489862971e6e5715f01f23e976f111f9431f36113405a2fa9688ef939c165662886204b3160c78aadf603bd24d644a1efdc733897cbe80335c4b658756f0bf353429b50f33127f6eff7a07eb4fea6e71b67adf802bb8744d72e1ee39877c1848c9328c64d54c264f4e6ceecfdd31c2bf153d2d42dcdd66d29861665cdf2fd2056074b4d0663c7651d1cc80638f53d84ab2d88c7d772ac33666ae2e94039c9f2910865d4814f468346a6b4a731467ad459940448d145474cf6a8837c2c8418c3665bba7afbb49d4f730e1b3b97cf019a048d440c04cb1da0e78b52660049742e1ec5265dbda09f25be5dfa2b407d22216489af000acee1b81913bd665a0134077661cd27b82691854671e80f4bb2e26adf9ff966f59b9c8eec79b01071eaa81c61775f902057ec8d049189b7a99af66c7a25c3843cf99fdb4d5876066f0a80fde6d0e56c5e7a1d0f4c8e652d8ec4d63c435d4fc926235649b01f9204f75b0b36dc0b16225536dc55184436f14089c2480542cb8aaac6bb4b890e86660a2063da83386adde655e7ea15837112371060df7f5fe611084145874e82f49c11fc2eed7ee2a8a258bde0900e75cb7efe28d5bb840850d64010c3fb98d63fb350b4a63a7077afe5269493cd0118d3c62f5b6a9948068729a6f3d1a9d4cdceaa8bc231083248a9123639e216b00d45583a067d43d71ad3b70c5b80214a35830407b20815facc53b3d6977d3353bb2efd4b97e49dc2f198953f2da72ba6d53a56cc644142590227fda2ef55674b89ef6a9fc5bcb32bd9c8083c10a7282b411560004048ae23af13d7aec0bb8ed04999fb619f89205ee06d3a8bbc53ea3e17c620eb1702a5fb22553459e428fa7082ab6f5c4d692b737b031de37ce7d4086d2113a18ffd0d069a28622c4be184f174d25f5bf0637252590bbc72fd5ed30dbc3bb69400f4f4a58b02ae7e6142421f0f60893cf0e6d184e65d680d7e593891b89965cc5c9b620d69acbf45b271d2100ca49a7a890989f89593b9fcdd72dc532b0ef926e93ffd93537515cc83af78da1c59aebdce29f54212fcfc00073a03bd6bddeca43a8ad3da0c8573b72c6c6862848639618249bf2f7809f0ea8fe29a7cce3a46a2609574715a70472aac68bafc855dae16abad8f1dab5a9b0cb08da7f671790c230d181ea3523077f29a945461bcf0fa72ba4ac47662cffb1af9c93dff5a1fedbea857508687a7c71bbb6edb1aab02eed6e79a7edd92ea0a27184861b684db298d4d9ec6c2267bec52780ddf9c5dbeddf1d5204dd1e72aabdfca4654aa08a22bf6f2a3967418516b9020e3067675c34cc4165d294ed79bcc1ba815ce705eed4427361d99838a8f61a7536cef861b9dd8279ebbaa90c34ecf42d9443c88a7cbe57d5c5e9942456edaa104d3ba371f0c7508f8c54a759b53f0fd4c6414df76647cc21dee193cdcc304b6afe03b08c44badcea20f79efd9f5ce0004b6a4ca58ca1fb75a330e026a47ed993ae271859879126472c603ad142dd6808cb793711ddd7622a57fcbbd7729baa27ea06657d640bc4f1d9e50be22c1b80212f752fedeabca517a22a402c4aa97542ce4a5e2d814bef8cc2e397fe90e7ba343a4515e5ba06600666dfd5741d0b665c196f2a08150af64b265bf74c93bb311b6bcee7bc60c147017a1d6a12f54f1d2aed22cde9611ccf8b54af066f510db27e604cb3709ab1c9b0c35a02e03dd7e900c29284e8e958effd36070031ec39f3b2d77fa610ec2a292e4e3924bba4971c7266ce7cb38650c920285664b3ae92b580a80398170cfeb8dd1742c4cffc814bb3cb6ab4e4c30a574fc0a253f946d6098630200032d8d9106c3c366423c1a30895c884ea0613ccec860656cd5432908f870238c37d488d43656d30c72671c4db93ebb7f746be76b4fd8feef9b58972e5955eff642019644f4447259b4e3ddc8c9ed37e59dd5bdf9ea42e8b41b67c0fa9be31ebb7bfd4e10603300000000000000011c1b9d00fbd248207378607c1bbe3b68c825e0477a7714ac274fba50b4b77f1bd41f29b1d7b0af4556346a8c002fb77b4e7bda3dd3aebb676409b21887534ca7bd01e22405d98f529673cfcfb166bae323bede0dcfeb47a63fa15099a1206965052c3239f735db943233f6716eb57f3296dd0a70ed34c1bc68accdc24d5aea1f438cd304e520db9d029bc3a1b5f87bd24a480958a73b9bec68e4f1910dccc5dfb2a41199f6cf7abdd2a87a21b56d509099c617c4bed97b363fdc02a14d9bb77cc65b807798cdc3c93781d8f498e6255282d4169a17952ac997b812ad53332fbb17abc79123519dd9a5a41a3240c95d9ea2a2b373b2137f9c5113ecc9e0286468e24d17613bf3ccb958d5bf9ced20d822308baa789b2ee150072b9a74ad8bcf3a670332f9d920809030a69849a0d17a212525802a43ac7945be4d575dc4966386d1716bc3082fd387e093ac417a75dd72018e060beb23aca008870f590c7e6eba9cf88ffb089e32847de7050b58064456b4ed0d3c52f4b01d7691b41f2dd3e0f04c6c22b5ba6640f171e3dd99b3091c64d872e28a8225abf066318467d12b8486e4b7dfc75d90c173011aed0b1ee9b5a8e9a5db0813a1758d75e4a0b9ec7012d1e2ba88d577d951dee0c348f83e6fd550eae11528cba7b844e53d86cdb4dfae4050414da034eb5c81c2bf35326c1c1d12b95576ff0b130c297abb559f01d5e1dde51fe5a27c4583d9390c41585a2f17278fb0fca493fcca1b8798efe159977b459e340331ae48329062ad454d14a01c7ec04dc3bdd17b0d5ebde7d80e13ade498c7513ce2cb02fd2a724f7078cbae071b849b887437a043a9f571dd27b3f53b906824683b13c811b9cfa7bbd62796362125bae0928ffe448c6ea58ab57e58cb9f295ed1d59b13d201ebca13d0e9702bbfe26a7af40ca620b067bfcecd1d31c05791fd859b560e1c3b7fe931cbc877b105137a68373bd200d60a1b0002535749b13f043bbdb67f7a6f9d91fc897d86853b5c587a011f4ccd8b4e6929bb1abaf0f50d88c60e220c5c0733646eeed17445c2163248792723674f962ac2acaec38de683c8cff62240b4b1ca5b8641eb60113abc05ce5233ec9b6d451e031f9b45d82a2c61626255cc4dc98de04859ad02932653736282c279b9246a05919741d2c0a03a4cd6b02b3ffddd75c66e8fc720c12e561f968ce21d6f8cbbb6db2a611b86b4aa5a70f1d81d162debca5c4a83840648404ff4c6ddb701ba08bbbf75dc1025eb5e3b33cf6026ee5d0be97e6e449beca3bdb739bb2cc9d12a7bf7b5f64f2667df4568f0f143dd89f0a3870fa6f4b61926a772409085948700786a40ecf8c044ed533097bbd2a1c5f3906bb79559b137fa47844453fdd5ac2bd59c72bdd45bd08708976ba80917f7a97a2afae360f28292010fa274bf7acc09549ae48a83c50e0c8a483fba459735eaa317b0e72f664617440386dc337ae667be9571480fcd123a66b1fbe30525bb1605435337c91358d602b3403b525dec10f334097c65619ba5c20fc52a03c65bed574d0a873e2bf088c8d514f58a0b50e84dda7996deb7248f3eb1e254018f31cdbc46d62c96dc871aef4febdf689586d5ead40da1dc723b492e04a7c5ef2116f4e5940256a83a477681a67811b3a57f21692baffa2143291bde3e91fc3a7e1f754de21661a0e3e718560d9655eb1133ab245d561d0312ff1841165814e422d74290ef7432247752105c65ff71faa9242d5edc175d1535f7ebcdaeee20ddb0a68dbd0a854baa1db2c1302cfac4de26117409d6a0b2ddd7934bcea4980d31d488be89764a85b5acd69cef850b3d76858100210146ba66c0e6ca96229a8561de0578b7da170c194d103afa546edb70e4148b51e3638630d38904cae379d33f023a41e19bd70cfbdd4c214a04a91568ff28ecc2def5e17a679890367ed647e151b81259b53ed4f262e43bd292e39e4abf78789c66c9abb832c08266640f1d209ba872dbf92057f641cc0cdbae17deb92183309ab4fb3d2353b39acb6b2988ce6f908096eef9276b1d74d52591672fd61aeb222be065f83811c29f8a212a7243a088e04eb7387cdd7eeee4ddf8505c962e53e3b416ebb36e65031c90f81c15df96bb0fd537340a7b9f7e70addac0eccda6cacfa7d6468bdee7f39080c45a9dea454aaa0dfef82a35e5cc07b3f440e6c7137cb1d9957dec892bd6b5e6b8cd5dd59c1117ac97a0d2cc1983be16ab3442b84a4f03a1237f68e3d8165ddb9dd103a87f164c32af646810efd39953de5f8a05b67688c3ebbee9dc208e94f1145573b0bb9e5529a4be510317a4dc11534bd13d8ff92944b8092d83fd215d1583d9267ffd0826327edfc3c14a15ba694625951dbc853aeb463a6670c5f29f9d4fb5640f886c67cfd78320642a31195127cdb515560ad35913713f8cba2d8c32e407b43706a58eda1bdf9846685d6fd2ea2e01365256418ba8c30012d1b92b27a02f45873377b478f3afa74eab26ae539890b181f1a8636009dbdf3d51c3ea8fea23b9355af261d4da0ffe8517d7091931caf5547b684070f56484f2c04e2f7f8a1feb6e59e90e0bed4c31c4298e2cd773b41dbe7614fdff0cc8bafad4f7d24f1c6f36f43faa1f5bdc18fbe5b72b35be40f6fdb2c45cd4edcab359138ee21f8c345d7ff8fde0f7f03ceb04f31b9b9f0b1eeac8e067d6ef725a0d88d91fd8118e04aca24f054d497029ec4fe8eaca750b9b6b8415280e02597e2d91c9729ea16040cbc8d59901841f562b14eef65b86ee36d8b2b8420c5c4ec13332226514c968f2f34e7cb4f375cee795bed05933f63018a706812c3adfae55a7aaa3066feb7114aecf5f48b7d2fbf3b716495a6165f00d9302475bca49d5836625159a91e39e46b73038ec772e448b3b5c6e159cdd4146fbb282ee6fa0885e18b86968d9335cf50bda1c083c72e064c116ae5e569573078b352916084decc2f74c3492a1ce5b602d7afa71b20e1ba1ba8d1d17f7ff5c836f1d2cb65d066250792470c3e40d6e849ce8869c9065d2a149f51889a24559ee94025547b07ce2e176d015b715274a946da6da8069bb86a1d04d711ed1876e13ec0f034f7e7c3885c53ef4c5ce5503a1ed8505b122a6dc26c631bdce08743aa4d0157b358a49b181f8dfa8fe45ff31cf8bcae6df5e8943aee63c8b6532104a07cb53acebe17eeb926c2d9a6f8f2da9cbacecd8a1fbccd6650fba2436233898c5b3dcd9e37229e20742a4d7baa9d0b03a95baa81aa0834f394074f8d005c31baff7c84e31ad238ce9b696809cf59d162cbaef7402c89af42aaa6b66c3d66589ecf9349f8721455d8e5b7bbb1169d9dfda4aba871dce5b2651575c4d10ad150898f521f198fe812934fb13702eefe4ebad7aad185fa40436f77b6d00ce7f5eafc376c8a1ad12b1b5ee91f265f7fe5bbd85a146dd77967e4eabcd523ed74381b6c4649e068c9724a42ee9c5ac9193f4e5dfe0ffcb88900cf75e5142461af23d61360fed582e342e9ba8e7cb6abaf5b2d0dbe3413c22c1b174f37a5dcac78a17e6fabba04c4c3de756b0a9c23006036d80a882c4b78bf2fb99d357b2877c443d52ab771b8061298bda6ff829fdce986db93a8adcf044dfa3a226460312b8f6d5d6afca6610fa570f3d5e358c1b58b2dde2bb3e7128427aef8eb9465b2e787a04991200539125aea00e62b6f6464b3a22d3682a0ef11a92f652bc56ec83acb3976e0d89f7f8fd9e1b9c7f5114ea8a2dc216fdd30cb253f9fa1d9440c4e2e8ad919ca971d9d6fbec57f08d3c0182ce4cf9af26ef2230c0c015a8da3f9fec27563be9a8775273eaef0a2302ca383bd7dbe0a6e793f5cf4f9e1f2825c37282977379e9cc5b9cac9bc58d114990b3452b5a6bf9f09d9165e06f23d909e27e0122f43141c6739ff4fd864d2d4cb9dd745d98fbfb3716e2cd514c339ead9394abd032186587dc97aeef3568540735a2777c267c4a955c4db15bdb80cc58dcff10c400fb69919f8912e58b7060eeccc1bb49e8c77a646e88bb45061659dcf71a6c807daaa747fc61f9d2ed62377e22a5e9ba2d1854c51aea3bb9d32fb2c1dc1a8f787a329f4829286499bf4ee18fe9b1bf1c0b621ae0a9f43f48e3ced8b42481e88db72ececa2c576eb45a97d4067702b48c21a3204ea008e771882a2bd4794cbb39475015d5792bbb3680263f3eba58dd6809b557de177291bad203008a67bb85c61340e62440c680afb216133511356accaa5c78640f8103c07ca8509ef07ab4d914392e279b7911ff862deeac2fe5a8bd2ac476bff8ea105d313b615336637029c59e31b747c4303ee8c4e9c93b4f576f6307b1e9a5dc50a58c0c3bd32e33bd452e4af8f094a8983e643f33046d8e2a9503c80e0e57c5e2bff971228ac83633701e271dff8468199b629e95b3618b11d753b30d5f9a70388bdea3db8c6a5094fb6b58349433adc525b76266a31cdf7ccd955d3774828f6b9e69acf663c5b3c9c1884879a0a11afb1023838b1e3be392cd5ca03a754688a378ee5c698e621731dec5820b776187910af57ea266222f8e63a5c93a916345612fcff5731cb94dff802e9509f17737e12430afbead6f1163f777eb06d9950cf4e4e2b6367888661c4ea84f6cc7f0e9f145889f1adde72e0908a2845d1e87100a807398a2becb669b095d43ad3304f2e0c79e65fd262269483ec1d0b5d89c6ac7a2b7c61d6f199fd030012386cfd559de61baaaedeb4562a5342523bc5758a2c58d11aef612256404b0b66429d07eea4c88a6168ebac7e952cd4b8e841c629f3a7cd4273f0ca8392824c7c878a8794bf4eba4d3cb36cad6fc1ac9f78107e2d71e4eb2ae07eca300ae8b9a65cf324cc81a125f9e075fd378239931d5e6df84f69c8814a115a9ab63032503f267d509cadfbb066e93d4131ec4701016af22981450462154d6f78c2369ac0c5a88833e14a223109676f68ab66af9876c72ab1a3db011eaeb025d77d6183d8a727b882d05890cc4b2a53ac1907fb46b5b2c3e8ba7c0eb548e77a009b846d03a4014ac5b902722a7e3cb538a5b788466749ccf49c87d1c04c2ed9b7957e452025d0dd48bca3ed47198d5f55d7cd3eab7ca4415309e09629ff4787fdb2f6c37d804b2022a5ff7f44d9ce3b87bb534e3f54cd4ee55558097a3715c39219746ffa145a8c7b8454fbad92898ea23cdac2f1706323a22395c7a95e52ff9695daa21bc4d19a3b5585967c665dc87ff20b526ab85407d600165c2855af3572351ffda531a66126b85683d9912ecc501d510243fb5ae070045d85b8f9beba70e9628de932cbf9cf9beeeb75483d6b23532a568d6f88a43951d058cac5347af8add04564808a2fe9ee365f807036a055a1e24aac3bf3f0a6bda40503380fbaf4dbd4c9c5ca6e2ff44a178da6b62e695204ca5cdb64007f646daf2adc9bdfd36329594fbe8645bb2f802af382a629f2672b9e09b3065f5cd8da9b0280b4ee3eb5792d872e696e4b0013bcc9175f2e68c66166f57811bd84cd684ec8b2387529a0d583f21d8cbd8c9c1933c5574cc9ee5d83b4b94940829225b0012bf551e6a55a939a334cfe006b815b9d1bf4e7a07a5d989c51c156c0eafadb670797bb593653a7cd0ec75ba3ca6a1a288758188f72c52157bde2ee819a691eb09b9c0ed9a80d71ec19a35c6a7d5c65cd8c6b64af995a5a695a88d36cd91e8bde73785ed6df89ee509cc515274c9d2fbaa8402bbef24e698c5a187988cef50260023280f514dcad02bf6cfe67dfd89e0be6caa79fc6076a7b1e8ef2f7215e07b03ab69c4b3e106f82122cfb35ebcae6d55a30ef39139c41742b6e05506f5aef1a8a1ebeeb97d3851b3d29f225b0007ccb110597342af39ee829f9280aef0fe260000", + "asset_info": [ + { + "asset_id": "38fca2d939696061a8f76d4e6b5eecd54e3b4221c846f24a6b279e79952850a5", + "contract": { + "entity": { + "domain": "liquidtestnet.com" + }, + "issuer_pubkey": "035d0f7b0207d9cc68870abfef621692bce082084ed3ca0c1ae432dd12d889be01", + "name": "Testnet Asset", + "precision": 3, + "ticker": "TEST", + "version": 0 + }, + "issuance_prevout": { + "txid": "0e19e938c74378ae83b549213a12be88ede6e32e1407bfdf50c4ec3f927408ec", + "vout": 0 + } + } + ], + "trusted_commitments": [ + { + "abf": "5aab13a09edd4bcc8391093f2648fe2ba3098ac5694c31f7d37ab8e0f1b6b2ef", + "vbf": "c72c6aec382fd643d66aeb6bc953f713dbd8b4b09ad661adedc886af759bd531", + "blinding_key": "02232424317a3b8f7c3880d0d05e30f7381414299ef59566046133fa796741d02b", + "asset_generator": "0a14397507823e3f56002e09df5c25dd46dc7ac7317cf337ff004f36419471d9f6", + "value_commitment": "09ab421af012daee0415c3b7412b92a83a73ab91e9b737edf27d20b3a512624169", + "asset_id": "38fca2d939696061a8f76d4e6b5eecd54e3b4221c846f24a6b279e79952850a5", + "asset_blind_proof": "0100017454d5579ec0def281d4712c832e98af69208af4146ba691841d6605088e16c55cb5bffdbad36202475d94dea902fbcfa8c428ab7b3901e92df8b201ac865da3", + "value": 100, + "value_blind_proof": "200000000000000064b4fad658767eac9d1ad0fb81f559a2c13c16666d80299d253688a171af91070d43d26abb52b9e08917cbda72a7095379295ba1ece239c9f9ce0fc3f8a270b4f8" + }, + { + "abf": "1eb7e054c234d5d3f075be8296d9834160a6eba2a082a99c357fb1fc71503a8e", + "vbf": "139cb6dcd5c48b2448ac78abc23d07080f9f941ced7f4f04da73f1a15f8b3326", + "blinding_key": "034fa5e74bf5a2998e4b0fb94eb14631c3a3588c035d151e548be3ed6c5302f2d1", + "asset_generator": "0b171c287d26dab3d69a23b9c0d45fb38f67abbd5093591acffb871e03c89cdbb4", + "value_commitment": "09deebaac97419f45ff834ad61c4a9afcf09e7750628ab0fb7b163df4f96c629b4", + "asset_id": "144c654344aa716d6f3abcc1ca90e5641e4e2a7f633bc09fe3baf64585819a49", + "asset_blind_proof": "010001d1afdefcb5524c48fa37eab82026a4e2c28ac69f6d78fb293c619df5deb32221d1879395c1046269330701ea9dd1bd51dcd0451aca1cce2f67e11dc4ec897811", + "value": 294727, + "value_blind_proof": "200000000000047f47eb9b2f9267f23f7f64c6f93ab7cb7311b305abe97f4ac7877e981ffc7d4f662052de1efc379c28cf17f887e92208e70739e1e7abd095227587a895589e725de8" + }, + null + ], + "change": [ + null, + { + "path": [ + 1, + 71 + ], + "csv_blocks": 65535 + }, + null + ], + "inputs": [ + { + "is_witness": true, + "script": "748c632103bfe3e0ae83aa5ed97d11ffd4ecdfb44e09d086b232bcb0fb1d4c13da4594b527ad6703ffff00b2756821030d14dd8299bc9c5747cb0a518e445b45a57df35d661006f4df1c864e7eb89649ac", + "path": [ + 1, + 49 + ], + "value_commitment": "08f615d657a23c6e49253ccd5e9f56cecb76d72c2d0ee6ad6729ebf1aaa573d816", + "ae_host_commitment": "57007bfa6e9b953150f24e691ec7a9ec255fe0f442e614a366c3ed9a3e3fd05f", + "ae_host_entropy": "4b275b6506148e82207b70924047e0deaba28d8dfee33282c8461bda63423f69" + }, + { + "is_witness": true, + "script": "748c6321038cc423bab95d2f71b38460c64c0424d400372b901d80edb4e9d9ce35cde5ba65ad6703ffff00b2756821028e307e4afd28effcbdbbfe2ae1c5578832c4793af93c1557f12a8eec9f8de768ac", + "path": [ + 1, + 61 + ], + "value_commitment": "08a29dcfc292b5fcfb45db3c2f4f1dbeceb6ab42605b7c1f45bf376c99ee0134e0", + "ae_host_commitment": "7d102a25bc39c1b29d5f4978d03deb2a9c479a4a213cf3133149cb2c02f42b0c", + "ae_host_entropy": "c81af0a035aa81b9fc9958c9b5d0ad4bb37f5685293748ae025d09c1cf89d58b" + } + ] + }, + "expected_output": [ + [ + "02f85fdaf4284b0942360736d397fd5115a3a4f7bd87b6097f72d6f32e0cebd6c0", + "3045022100d7f0319b5ef6ed2cf84924bba4da716299718ac705bd6ac6c39db8a1456088d8022063b7ef9902aae1b8011c67074c26a885aa6c17328c88708c3003b67be80f958201" + ], + [ + "03ef0e3a467739dd535af59ae0782a4158bef3a7b3835a387421ca0d9485e11fc0", + "3045022100da2cabb04abe19490e872c90bf664824a9d329bf38949e948534a0f0fefd86b402204fc0bc6a0629306780dbe77453dccc14234aaf1c2de5f01564bc888c098fc8ed01" + ] + ] +} diff --git a/test_jade.py b/test_jade.py index 7c2f5e13..9ebdcd11 100644 --- a/test_jade.py +++ b/test_jade.py @@ -1344,6 +1344,12 @@ def test_bad_params_liquid(jade, has_psram, has_ble): BADVAL32 = EXPECTED_LIQ_COMMITMENT_1['abf'] BADVAL33 = EXPECTED_LIQ_COMMITMENT_1['value_commitment'] + # Correct lengths, prefixes, etc. + BAD_ASSET_PROOF = h2b("0100017454d5579ec0def281d4712c832e98af69208af4146ba\ +691841d6605088e16c55cb5bffdbad36202475d94dea902fbcfa8c428ab7b3901e92df8b201ac865da3") + BAD_VALUE_PROOF = h2b("200000000000047f47eb9b2f9267f23f7f64c6f93ab7cb7311b\ +305abe97f4ac7877e981ffc7d4f662052de1efc379c28cf17f887e92208e70739e1e7abd095227587a895589e725de8") + GOOD_ASSET = { "asset_id": "38fca2d939696061a8f76d4e6b5eecd54e3b4221c846f24a6b279e79952850a5", "contract": { @@ -1390,6 +1396,11 @@ def _commitsUpdate(key, val): commits[key] = val return commits + def _commitsAssetBlindProof(val): + commits = _commitsMinus('abf') + commits['asset_blind_proof'] = val + return commits + def _commitsValueBlindProof(val): commits = _commitsMinus('vbf') commits['value_blind_proof'] = val @@ -1676,13 +1687,20 @@ def _commitsValueBlindProof(val): (_commitsUpdate('vbf', BADVAL32), 'verify blinded value commitment'), (_commitsUpdate('asset_generator', BADVAL33), 'blinded asset generator'), (_commitsUpdate('value_commitment', BADVAL33), 'blinded value commitment'), + # Asset blind proof in place of abf + (_commitsAssetBlindProof(''), 'extract trusted commitments'), + (_commitsAssetBlindProof('notbin'), 'extract trusted commitments'), + (_commitsAssetBlindProof('123abc'), 'extract trusted commitments'), # Value blind proof in place of vbf (_commitsValueBlindProof(''), 'extract trusted commitments'), (_commitsValueBlindProof('notbin'), 'extract trusted commitments'), (_commitsValueBlindProof('123abc'), 'extract trusted commitments')] - if has_psram or not has_ble: - bad_commitments.append((_commitsValueBlindProof(BADVAL32), - 'blinded value commitment using explicit rangeproof')) + if has_psram: + # Invalid/incorrect explicit proofs + bad_commitments.append((_commitsAssetBlindProof(BAD_ASSET_PROOF), + 'Failed to verify explicit asset/value commitment proofs')) + bad_commitments.append((_commitsValueBlindProof(BAD_VALUE_PROOF), + 'Failed to verify explicit asset/value commitment proofs')) # Test all the simple cases for badmsg, errormsg in bad_params: @@ -1703,7 +1721,7 @@ def _commitsValueBlindProof(val): for badinput, errormsg in bad_liq_inputs: # Initiate a good sign-liquid-tx result = _test_good_params(jade, - ('signLiquid', 'sign_liquid_tx', + ('signLiquidInput', 'sign_liquid_tx', {'network': 'localtest-liquid', 'txn': GOODTX, 'num_inputs': 1, @@ -2370,10 +2388,10 @@ def test_sign_liquid_tx(jadeapi, has_psram, has_ble, pattern): logger.warning("Skipping test - tx too large for non-psram device") continue - # Skip any rangeproof tests which cannot be handled by ble-enabled no-psram devices - if has_ble and \ - any(tcs and 'value_blind_proof' in tcs for tcs in inputdata['trusted_commitments']): - logger.warning("Skipping test - value_blind_proof too large for non-psram device") + # Skip any explicit proof tests which cannot be handled by no-psram devices + if any(tcs and ('value_blind_proof' in tcs or 'asset_blind_proof' in tcs) + for tcs in inputdata['trusted_commitments']): + logger.warning("Skipping test - explicit proofs too large for non-psram device") continue rslt = jadeapi.sign_liquid_tx(inputdata['network'],