diff --git a/.gitignore b/.gitignore index e5f983e03..60c756e78 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,6 @@ bld *.pyc +*.swp src/test/__pycache__/ *~ *.class @@ -43,6 +44,7 @@ src/test_bech32* src/test_blech32* src/test_clear* src/test_tx* +src/test_psbt* src/test_elements_tx* src/test-suite.log src/swig_java/swig_java_wrap.c @@ -82,10 +84,14 @@ docs/source/core.rst docs/source/crypto.rst docs/source/psbt.rst docs/source/script.rst +docs/source/symmetric.rst docs/source/transaction.rst docs/source/elements.rst .idea/ +# ctags +tags + # MacOS **/.DS_Store diff --git a/CHANGES.md b/CHANGES.md index ee784e154..d8db54e31 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,50 +1,48 @@ # Changes +## Version 0.7.9 + +- wally_is_elements_build now takes a size_t output instead of uin64_t. + +- elements_pegout_script_from_bytes, asset_pak_whitelistproof and + psbt_to_bytes now follow the library convention for too-short buffers + instead of returning WALLY_EINVAL. See the generated API documentation + section "Variable Length Output Buffers" for details. + +- FINGERPRINT_LEN was renamed to BIP32_KEY_FINGERPRINT_LEN for + consistency - You should change any references in your source when upgrading. + +- Almost all functions comprising the PSBT interface have changed name, + arguments, semantics or all three. Users can consider the new interface final. + ## Version 0.7.8 -- Deprecate Python 2 wheels -- Honor CFLAGS, default to O2 -- Bug fixing +- Python 2 wheels are now deprecated. Users should move to Python 3 as soon as possible. ## Version 0.7.7 -- Expose wally_psbt_get_length -- Add wally_scriptpubkey_to_address -- Return written bytes in asset_pak_whitelistproof -- Elements bug fixes +- API change of wally_asset_pak_whitelistproof to return the number of bytes written. ## Version 0.7.6 -- Add flag to sort multisig keys (BIP67) -- Add bip32_key_get_fingerprint -- Add Liquid developer guide -- Add liquid support to address_to_scriptpubkey +- No API changes ## Version 0.7.5 -- Add support for P2PKH, P2SH-P2WPKH, P2WPKH address derivation from BIP32 key -- Add support for P2KH and P2SH address parsing -- Add support for PSBT -- Add support for blech32 -- Add support for pegin and pegout -- Bug fixing, build updates and improvements +- No API changes ## Version 0.7.4 -- Add support for recoverable signatures -- Generalize Elements function to use external nonces -- Expose blinding key functions to js wrapper -- doc improvement and bugs fixing +- No API changes ## Version 0.7.3 -- Exposed ECDH, added py3.7 x86_64 linux wheels to released artifacts, updated - JS bindings to support latest nodejs, doc typos and bug fixing. +- No API changes ## Version 0.7.2 - API change of wally_tx_to_bytes and wally_tx_to_hex to not accept - WALLY_TX_FLAG_USE_ELEMENTS bit set in flags. You should remove such flag when + WALLY_TX_FLAG_USE_ELEMENTS set in flags. You should remove this flag when upgrading. This change affects elements transactions only. ## Version 0.6.5 diff --git a/README.md b/README.md index 75f230bbb..042d306d1 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,7 @@ Read the API documentation at https://wally.readthedocs.io. Note that library interfaces may change slightly while the library design matures. Please see the [CHANGES](./CHANGES.md) file to determine if the API has changed when upgrading. -Please report bugs and submit patches to https://github.com/ElementsProject/libwally-core. +Please report bugs and submit patches to [Our github repository](https://github.com/ElementsProject/libwally-core). If you wish to report a security issue, please read [Our security reporting guidelines](./SECURITY.md). [![Build Status](https://travis-ci.org/ElementsProject/libwally-core.svg?branch=master)](https://travis-ci.org/ElementsProject/libwally-core) @@ -149,8 +149,22 @@ should format your changes using [uncrustify](https://github.com/uncrustify/uncr version 0.60 or later. The script `./tools/uncrustify` will reformat all C sources in the library as needed, with the currently chosen uncrustify options. +To reformat a single source file, use e.g.: +``` +$ ./tools/uncrustify src/transaction.c +``` + +Or to reformat all source files, pass no arguments: +``` +$ ./tools/uncrustify +``` + You should also make sure the existing tests pass and if possible write tests -covering any new functionality, following the existing style. +covering any new functionality, following the existing style. You can run the +tests via: +``` +$ make check +``` ## Generating a coverage report @@ -159,15 +173,15 @@ To generate an HTML coverage report, install `lcov` and use: ``` $ ./tools/cleanup.sh $ ./tools/autogen.sh -$ ./configure --enable-debug --enable-export-all --enable-swig-python --enable-swig-java --enable-coverage +$ ./configure --enable-debug --enable-export-all --enable-swig-python --enable-swig-java --enable-js_wrappers --enable-coverage $ make $ ./tools/coverage.sh clean $ make check $ ./tools/coverage.sh ``` -The coverage report can then be viewed at `src/lcov/index.html`. Patches to -increase the test coverage are welcome. +The coverage report can then be viewed at `./src/lcov/src/index.html`. Patches +to increase the test coverage are welcome. ## Users of libwally-core diff --git a/SECURITY.md b/SECURITY.md new file mode 100644 index 000000000..071e4adf5 --- /dev/null +++ b/SECURITY.md @@ -0,0 +1,326 @@ +# Security + +The maintainers of libwally take security very seriously and are committed to addressing any disclosed security vulnerabilities quickly and carefully. If you find a security vulnerability, please report it to us following the steps described here. + +## Reporting a Vulnerability + +Privately and confidentially send us a description of the vulnerability that you have discovered using an encrypted and authenticated channel. PGP encrypted email is preferred. Our contact information is given below. + +In your report, please include as much information as you can, including: + +* a description of the vulnerability and how it could be exploited +* its potential impact (e.g. privacy leak, denial of service, theft of funds) +* steps or code for reproducing it +* a proposed patch for remedying it + +Also, provide us with a secure means to contact you with any follow up questions we might have. + +## Considerations + +Please take care not to violate the privacy of users in your report. For example, stack traces or exploit scripts sent to us should never contain private keys or personally identifiable information. + +Give us at least one week to investigate the vulnerability you found and up to 90 days to fix it. Also, please give us reasonable advanced notice if at any point you intend to disclose the vulnerability to anyone else. + +In general, please investigate and report bugs in a way that makes a reasonable, good faith effort not to be disruptive or harmful to us, this software's users, or the users of dependent projects. + +We will take care to inform the maintainers of dependent projects. + +## How to Contact Us + +### Primary Contact + +Jon Griffiths +jgriffiths@blockstream.com + +Please use the following PGP key for communication: + + +``` +Email: Jon Griffiths +Fingerprint: 129EE55E90E6E7BB5ED3530DFD9FCBA3C53CED20 + +-----BEGIN PGP PUBLIC KEY BLOCK----- + +mQINBFcpb6cBEACshfpRfpq1su/TdjBphD1kBeyJbU5FhsX3LbOmyWERcvqH8ES8 +tKd0oVrt8pGj1R+GLrmT/bKA0qizsKzB46ErkCFqTrZIJc7c/dXB/N3ZqwRLi6zH +kfA9llqEd1fHCjFpNAGE9KFHqdVq2MGw0tCqRmOX+2ny0PqEe8mluCZV5drsDq4M +DDUVQPGP8JG0Z0J03jyOCHWz5D7E7vGazl5RhMZu2109xEM26vevUd1y8QLsjWLS +vyFjNKEgNGkxQnJ3JL5JLnlduiZQS8lM2KIpZw8G8sxtE4iuc/FQLWy6F9Mb23mg +eL9OYxVhY9/QS0EUS48/lqc2oxGHnDCn1U5jUK9ihMwLupgY8glCqXtHf0jqVDjV +QThqHVdxRqYuvlgaRSDf7YKgV8QOG0/j2o0u0Ums7zfA+yvtO0rgqKpb7SgQU3cx +y+JX1Ko8Aoa/KQEv44LuRLwBZ7B3WmBcitv/YHtdYFyYADCMwKaojG5Rh7sxgwgp +3788Rm81EpqjNlj1IoFBQ4UU7aRgcXnngUTSY3JTZ8XEmvH6Q1i51L7nfXcg1Nkz +E1Fuz4NGedh2iwHmGLUxkSqUgyavvmZ+OxiVr/lxIEKKEbR+nuE5yP6dk3Uv8RjA +/l+Ak1Tu6EWvCYFMPb4asOtKu2Z09gpXabeyMC17hsHsAfmqEkSKdgZzcQARAQAB +tClKb24gR3JpZmZpdGhzIDxqb25fcF9ncmlmZml0aHNAeWFob28uY29tPokCPQQT +AQIAJwIbAwUJAeEzgAIeAQIXgAUCVylwhwULCQgHAwUVCgkICwUWAgMBAAAKCRD9 +n8ujxTztII8qD/4zlQ6q5lwBHkyO2ZiDkh33kKllUg2DdbYG7or6W8GAxWs7Naap +SRjKzsh6j2emP1SWTKi/wRSiqk7xO7FLD29OTuIMYTox6QPm/hTLw5GqQ8z84lJ0 +cIn+l3ntxW10l062nsp/bfVIt6vg06RbQtppdp16Ki6EhYLojsZ5F8K9+55wc055 +OBll4QNGy/jcdyfYtjrddTadnqjjBEub8sx5cCqfSQiqAY/rIAa5DqMcvf6DS56L +0uLpcIDNn9knc3STQUTKlide1tYOSEUYsE705FGlrY0tJzvt2lHKq8xfaj4mOHx0 +k9Ji5HiSrTM+PBcYZ/mdQgw3JTLaOyPCpw8zIUJKudkqiBYAVUJjQfHHq7YsmMUg +dqQmjG5Mu99+YYNRhMoCGcrFdsbtrpS4F/vf/WSYstzw8NXIcroFB/68IYWqaeSM +sGVXpV7wKmeNSnaz1xBrdVhD+2m9Kyg9fttfPHLyN3iQipoFDGyBGeL5Iej+Nn4K +MR6fT1lxQilLBrtTv6rdWMIPDbiey0nUSRC6IkFlPB8R+fFdUx9gNSARzkZrl7lr +s0yuEV+6BWfxPwcYlNSfJJEovOVvbogvlx2NTVzXCXd6o4sdH6CKPTeAoIHPUJ+8 +zLQAq8C6bWa/AyfDZzymFraiiwA6SDb3yWUpQPQFyqGPTC5cm/pD/IOJvIkCPgQT +AQIAKAUCVylvpwIbAwUJAeEzgAYLCQgHAwIGFQgCCQoLBBYCAwECHgECF4AACgkQ +/Z/Lo8U87SCaSg//am7TvXy1SX13kCHrzeU933z1d81MMFHI47mvBYb1OzYROM5z +SVD/82XI6kYbzPAf74Tc2BlaeEKP5pfoSjGT5x97o14tx3HuYG5LVjVpgCxI1yuP +XzyLRU9JWJBMkeWC8obZd/4P0iFELylLC570LuKsMx1G00Luxsy2xXXSCOhdJY9f +598qehqACTKCXYLMUspGqgC/nJDCUAzi+mXqybdhTh9Dd5sFL0OIL+/NIDlT4/HE +KOBK1lVBUQiH5TJLhaaRijXlUTYntBba5uu0j/PUNYJ+FKVp/YNcA7QPJQOpVxjX +RaNgN+65UswA5SQmbr+k5pXmBhIFW9Q0pW6C5c4bLrH9p7jneJJQJlOevf3WGnjm +9Qkubmz9COwzmBMMqixNoHtElsjAwWs/o1W6va+qcTwkrGfyQMMS8pZEc0WWAaO5 +0MrOyhc3Bz+MV5/lWeV10zR8SHGjXQSoE/zlKi7rKtZr9jLg3A3JabH54LmTbbHT +ARK4GWYXMqrCAzN+Fn2AQvOoU3xA3HEatKDxoPd9tGRmr8if/jEkjlJ336E/oPq7 +hxEX42qKyqbW6WED937eSuKIZoMGusdp0S778NOa9E+KyizARAUui50PAeL15K9G +h+0VRx4VxWyFk8Ra/bVs9CmDUciMmV2wx87LAU+30ak2K2M29Vkhlm8/zB+JAj4E +EwECACgCGwMGCwkIBwMCBhUIAgkKCwQWAgMBAh4BAheABQJZCv4qBQkDwsHuAAoJ +EP2fy6PFPO0gBGIP/3zw8WZRURPQfQ0hC8UQc96uaPU7IBQrMXDBj+y8XBNLCFJX +UhT3rS1wlN5foCt0DxkgLIAU73GUJ0Q7qG0Vcap7YWSpcw6y6Ih7vxVRzAqe8nfC +IznSK28uhJgVErelNLOYLqiV3nO5oHOSVLL95JwvexPw/zIkbSQwr7mX/Rica8iG +qEGXqRgjasgLz0BhR7OozzgdXHmVcwtQ2x9t5ySso/doj+RrSTdCbSw+5l8fZOC/ +HEIdOWrjkL5r84EmZHfb1sbk0CAPZeX1lnaXSitYenb5Yl90ejSOjGwqV4F+/ZoA +LspvU1SeDiASQaFaK/gxuVeGVduYcbXriD06iGsMzX6BkathV/hPd2naneT4T85K +SgjUs9Mby9/gy84uNDDsH3PSBlYJCH+GuVkafiwD9GZc8sr5KJtCIFA/ZCJk0omJ +Mdod8QaWKwCpiJO4ynnliiBnXKMHABYQBR4B68fz2RduQ94tnGEdbyJbakPQ1viL +7Gr0hkau6Rn/p8qzH7ZG5zI1N6e1TUTwiRsDJK82N/R6hHj2ovf6oDp2oa5/0E1g +AlzstP4b2BmVnyEivc72smRbPwqN4kyoc6xUQsH7nWmXdw05uHW583et9Aa8R9My +65ubRnk6TWkwcUycJZMzPI9UJCIPj8vDHw8+6esVR+iaf60YYdzRPIZ7nQjjiQI+ +BBMBAgAoAhsDBgsJCAcDAgYVCAIJCgsEFgIDAQIeAQIXgAUCWu+aGwUJBadd8QAK +CRD9n8ujxTztIMOkD/49LKpwugFKAMtAN8tg5JmOmvFvzUgHKNaI1QLDw/7CB1E8 +3+zSTEge9MQme7pBeHbf8wHqRIOEQJuygmYcsXNdDhe2cDbuKKhBRnTiYyzZojSH +7Q/+21N4e0zIsizFCEwDFmIJa3YFGmVH28Cql2AtopW4yv9ZR4D/Fe9DF3um9llg +rZEOyIysJuj56rGUuRs1779xs+taVV74n3Vt6CY+zE0nbZayzac1G9SmowKeJjnY +aLoaxthpac4ysBDBfJaIj3ddU1exXiOJJYrOQ43h2iRmcpVRZ6QOtGRIsixLc/Sx +8x2ML4iHtY1V37oFCLa8PZs35Q/Jtbj/CRmM/WpmnCNR3e8rHGwHdJiV6oLChbE2 +BQuhQdxPSDPGJ2Z6CBpycWtCl2cH4INdbvjQyqyhRyWugqUSYkhzVe0q3VA5sJMj +otHeSSsBV8PeakjV3hQ7idH4DFwExKrJOm2Miif/MKJSOx14lWPeshHOIivwB3M/ +mt1hVHp512GuNdNNPWx3F3kPZbk2n03WL6rNb5EgA+6py7pEDOZgy9BmzAkTz3cN +0cySdqESS7oPpWfWDjYYJo4KndKdfmgWCf3y4HbCW01tjgSC4hk8sqmLOEhQ+s1h +vTB9U9jFtszCyNOrzsDqEDpgu8PFWGdOr+Fg5bQtLvf40dlu8JaFmllDpCALHYkC +MwQQAQgAHRYhBBM+rBeUNvFKXPG3lIYP64BOZpMgBQJboUJGAAoJEIYP64BOZpMg +0CMP/iNHXbGqGH0N7+BjwV4HrQxQ5+G4LEVu0EIq0Ut6n5I0ie5sAhOj/AKATLTx +CpQiAkuNb3VVXmmVgKAV76ClKzIr5/n0j+Iy+Pgjy817swVt56edeBZxv76pduaP +wUnfDxV0+SQpzBR7WavZ9v5cQFj0YI/vAlCeOSEDbqbZuu01f6WzhBNAk4VBV09q +T7/HgUCeRF4GpPF+jUMjM5bsH+9Xizf9CKLixw++KvcMiyzMFfruWSLm7m1lyAws +rItz1HKWvbrs59IRVs59QkmwD6e/LaZ+mycco95RarRvG/sgPEBIhUfdoevgWTIy +WRgUgY1YWEtOSpDHEnnwG/qPgqakrYUsPD3N42szqisLOxD9qWSGJnQJpcbbeAEO +byaMN7fVFAZ0AszDvUKiDb3ZEUI/DWl3P2+Rs4a0lXXAeL2itdikunZshvDyuzk+ +LV0BMNMfz232spxqZTYjUFGM19KA2nRqlmL2RX+vz8066EZpf7V84g2Ai+3jVlUJ +K/sBcFblwwpXcvpBqumeiWD01GI/DT9yU98Qm41uPk/5J+/NKAXzaOofEAlxPCN0 +R6U4nrTwslELdahh1QGVLUZA2wasLmwpXrs6/7lI3HQ3Y9A2zonsfwVCTHpIYJn0 +wT287lsehVjkqiK/Q/ectsgfy1qK51kYcdqLpcf0we4qIOaQiQIcBBABCgAGBQJb +p5nLAAoJEKJtbZ/giO1YFSkQAKh84zOXp63A3WhAqpMODwIOc3bHhfgD2emJAwBA +cvJ0jF6gQeQceWtoW3Fy0ivA/LQCX6cemriyJNOUHXAiilzcXQH/1VuUatD6K6X7 +eCbbilah0EMrUG/PLcvf8KlicazKwUpv9lLAdE5horUaq56QcGzWxL9OQkHJKpTp +aHo3Y4eEiXiAJr18t6OGuP3sqvPqOe7RuS9gHGyfVRb9cg8k1T9f4WdCNyoyAsbd +I2I7LtTln2xY/DDU9ynzOkwpxXCrxYmE3zMcPCTe5xITQ3JkprWIGDKFrxomYx4M +8DF9gtDLzOzA+7gHNbzsJzA2mUpvoA3ajz/GHNZUdh0yIeGmZKQbaA1uONUZTlxx +dRdoNTXl2AQ8NbD7VThxIj3ib8v4q6NpohPrzYZ+PmtUdd+stFWxkafB44LgjfbR +WO/JE4zVwrfykDRoMGwL4nCgcssyuCSDdtYaKgIiiUqZNyDakzcMMI6TMT/VfjXk +vjZYTOtXGsFJQRg9L9AEtVIsOB/IkChPL1AyzdQjK15jlQTo0qw7sr0zysFMyNML +rr49Sjcv0+cO3MHyT7Fi7gvHLVy6Lh6cvDtjaNUgYfrslimQdqUS7W7piEOKlADY +eUD8YFxmtHSkqmkdYW/ULYOlkp2nzjlfOG0GGfvibz1opIF9aSZH6on7eox/DS+i +DjVJiQIzBBABCAAdFiEEDXrynMkm7zNZa1t+hkxNCRC0MNcFAluskTIACgkQhkxN +CRC0MNfdxw/+KxfOpVzONnv62CBFG+XuzJ0yWNFuVvEJGwcFVKBozlpw5I6SDxtv +fL+BbRkuXMKI9vrXbvC8QKkOfz2zVTiDPYwXqnq6YeN+Tp5WKfsNWxDXLfTLS8nS +mPektqH5oWSCCqrGIYjGRBQ2vC4c0vjMHLRmXHMjuB7brC8XMYTIA3DhbN9wG3+F +dkTTjKIDrMfdn4gGOEmAiYYQuwjnnOAG9WIOfmsIuda5+taIId7mamV3N45rjn+k +uYJ9p0TsRoOM1gKyrrwFPSY1z354Vq9hcwOoCgNklATlEx+MkNG5jNmeXH0aH4HW +QqoryrJH+5+KNKKjkBe2vg6JXDDICAF6L/TtYhLxLrfz9G+ZIrU2x7O0xB8XXORY +X0fskhMqf0HdbJDfmHDWUmsG07FGCG9ppt/DC5QQYjnH+znSfug1/1IN9fo5FIDe +LgMjaa7CdvmVpdwTqZHuE9EcFqp2WjusmcPWW9npd5vHYpL7WxFzOyqQ1Gtjphmo +CkoWHKP1NpBZ106QHoUvmyfGQgz1GTfvzpH+YU/9rPbidJOIe3LkHXCFg5Txox5m +kf+85FFi5myCuxoRFIUu8oP2XMwPtLc1Bnt3bdKJmP+J+WcSmYLDdoBfzROL0M2i +6YAC4Grd6Jt2d5vMaCzqYFK00gvYQON6543YLGS6tTHPiOo5LIrXi1SJAhwEEAEC +AAYFAluk8hEACgkQAAI0BZy1BxUScBAAq4EiTtzbO91FN2vOHq1TIxObnw/GA5xt +Z7y7uKV9ZlrboyJ/L9WUT3JNRWPejhTeXIAz404Zqu0wsf1SJ6G6Dk1fN/xzpkOi +SoG4TsY3aw2JiuNzqd3GF6DipD5LMyoldlEsJAj2Xq43XnD0ZClT431jkj2EP03X +37xw/8LyFPdqovoGtr/a4ZVQBcJbuHxJdYZ4orDKSfnwEj4Mb9b29pEza22HKs3d +thc3aTMTOH9K2a/3X4aN1li7KfFwHgW+L7BFkbd9APpfgAb1VwcZLZnDYrEiIxzj +iagJqPH1PfGDNGju+K42Mtb/T3f7BnwyTuOhRNfOxIzGofpjYDkl5GhSGk5HSPxg +hXZvpCEn5pTDpqI/yzbw2j+njiLnTZvjsTMaOccw6i1b0V6K4fMOXDdc0LbE5rBS +37/izR4DHSRwCP4eVpz1OWkyx3FhjXNVCAW2xRUheOP+REjwFbZGWyiNTl9AtDki +85BVNdvqVKk2GhxK5MC/0A3k0qowy6FIEJcpwdf1wCbH3VQ0iOGCLI5baHOP7/WZ +AlyyfZhrGVlN2lqI9t9Rs8VPlig7we/HK0flxAiV/Rx0wvTgWEOXgaoio4DFhMdh ++Wf3eQU2R20C2BZEvdtzh77HaG+GRTbRYwZpiUsrMsIni8/Zb51HunAVNf0t60Se +i6Ry+XufyQGJATMEEAEKAB0WIQR0gJCTeNVE6mttzrdTWxKYC7ik0wUCW6HPZAAK +CRBTWxKYC7ik00sEB/0d7YWDsv1xSr9emZBwVkLaTHhwSrD4hbvYkO3CzQ4td/HS +0jlraIzI7uZJrA0KXELSMGfa8I7h8khMCl6Es6xeJs46uv/Bk/9ccLqvfwMSGD7r +uURMYPXaQqba/oYCHXhIlwjDqm/J8lgdJOfxUmml26qG23UO/g6hxSpsMcoNZ+qx +Vnl1Xp9poGKo2CwPfIGgJcc6wDU26OlWQluuux0ErtYa1o6DdmJikRnYxLxamo0J +mbL+YWeOC1CZd0M3bIjK2y1nrtnFglAuC5XuZYCGMNDnQO0lJNrQS3OezD7nNXJ7 +xZZso9G8KbK4i4Ube7KHMND3mHLCzaYyyKLItmoNiQIzBBABCAAdFiEEjMl02c/Q +NNzu0hOwKlfgphDX8ZwFAlug8mcACgkQKlfgphDX8ZwjQg//bfCvWSSq/XSNTdYc +tSysVaVHICm4BdOkMh6Gtb/1TJ4fE9mHnfza2h3zgQF3ayOk4JC0O/Ybfsm8HFXN +c7RBh+IQJ1DclXkhH+e1dXyPFuMR5SWR1dL4PMvyHfT2iUe7Ibud+EUDFWFA1CC9 +L/fEWfW3+mCizFI8IgoHObL6U0+4xATICacuTyNFtK90IWNcA/DuPm7x467qY1f7 +PmEfrPhXVrGkqy1kAswZz+pKly3S/FOpeqN+o5B/tA+X25v0R4XUPYsp3LToDJX3 +x6iPq0vrDQFkHG3SXdGBgR/ipy3bObSOguE6iDg12ZxNQbmXB0ggHjurVv6/9Twy +wN6UDD9iNs0JDXQ4fXbHs5qYChhxzGeU6dNGzqk0PC6j/ubFyb1zWqLTToa0FZuh +HS1Z2A6amiw7VAXXobjZ34N0lr9qnu/BrOqE7dMnvK/CX6T9mM5bGPf8zKvI8j29 +OTtS9BGq0LDjGkTuquLUzDodvZHeVinJ2IKLAmrrM5dhhDjDRamIpXIcUrG0akhS +exMP/2XLLNpz4Oa51AWf7nswc39s+Y3mFeO2qYdEDHXRvBESbZid/W7olVFbABnV +N/NGkDJmCZL3vRojnVBX7vv+7WHICsR50nApov6Yh3VO1XKooVdgpIOremGMlxR6 +xJ6PNW3YuUa8kPCM+EwafBSdF/eJAj4EEwECACgCGwMGCwkIBwMCBhUIAgkKCwQW +AgMBAh4BAheABQJfAiUnBQkJuej1AAoJEP2fy6PFPO0gN1cP/2jTMkl04rRf0JgD +IuyUAC5ZDYxjd0qnTtMLE1bJxOdAh5a450PdQWQFjqyRWlfpQlznxrO1O0H/x1/D +5ZNgLU7FlXYmuGj86NfIIiUxH+MbkjiQ7VUgNt04PRqt4GpWWn9O14Xxz09JSVA4 +19lC8FVt9M2JzUEi/hAte9GsXr0FHo1hDBZeXpGvZi8RbnbkEv+PXHiAWlpPEKeu +w6h9qej1r3DrYYPOmnYGc5R1MygDQe4Wag3owx3QOTx9pHV4TCaUtLNL04lzDgjB +cSjQNskzovi8AAnpMjU9Igvly+eD+vZ5019K42UJAkD3QM5u9xt8tkztPn3/GZgM +NpGrubWph5aEYx0XI/+ywBj52VfVrHf07htS+o+aj1EJDdB1TsXcPK/ecu/pF0z1 +xfEmKYhYdBPHIfymocFW316kOl5kGryuZC2sEDUFveihadC4C80XYPLycIelQ5vt +3lJp5CbdbZNGSEpW7tiB1sjKDAO1+j6O9mqG9opo35iTGlLkJYNRZQmzIytAvLKg +YNt9h9+/tzEZxpyLtPddXiVzieCTpf5lf9JWrAHfE9pf+/nHy9TU3KlQ+5JFq9Jp +ZYtXmnjz4sXsU/SzZc8ZgVfa81ZB9ZPpWeTytgmIvZ8IB0dg9J78VQLsomgNDGXR +rQNLeK0S9XuwzBEdHW4D1NXGapQRuQINBFcpb6cBEADHIXZN1ns7lR1sG/+WxnMJ +u5EB38/t16Rd/f+KmNKk+iyHdHxHALERoIP7P0BUhm259szYbMM6VJp7Rm2fUN/7 +BbtTdoCdignuna4bENX3RI9lCTXU3QbXo4JT9EcnoIhwosV1XxBASqAdc5Yosn7R +uQP/yXKjQz6Auce95NGRPKzgSGkgWRA7mzzRkxCQ5QIL2CmTi4KsXyJWCKLPst3u +xJpW2vucouRdBQoQ1a1gX76RFKIYaKLrbJ6tVzUYrve2LHCs8Q4mNVy/LrxKNHtv +9muilTYEyOdXf1R7zHgTH7QW2xoS5Bjt0iaOx6wdSc4xwx4uQMuIHyveT8uagahY +W7g7xd0tIi3yja1qDdkvU4zp975/Q/Ls+qW2/4CahlukOj8LX/teiLuaFaHlDYqI +Hv22URBaIQuK+L/f3Ogi+hLbSCWSu4zLYvAWZ2Bl2amfDrC3t46gT9u8uNDhlt9Y +4H10s5kON4nXVwgRRPllRc2IYqK6i0JHvF9xE5OvnYDPRblV54WQjJmAkmrEl4Up +kd5SVqVoNf99MzvWrjiId3oZKUb3bfv+tfMCupjr6ELOg9dOQrXHB1qfrrs2q4s4 +ltF3+D5jpqhz09UZW/HEpbdEwvqS0Bb1W7oq5jd/LwL/hhmPVey65k4VfDuZF7gX +Mf7o5/pgbQgIaeRRWJnjBwARAQABiQIlBBgBAgAPAhsMBQJa75o7BQkFp14PAAoJ +EP2fy6PFPO0gjQQQAIgM+dTJlwnZBmgSDgnYOKAV8IKc4JWf0jlmQ/7Nkqpyujb4 +oMYDkvLNkKhs0QsiaCowz2IY96RksEUEZRim2L8sXYi17RYxsu6l0Cb54YBpQXZw +gOUPxIJmT4vdoP0cEf6ryo3G7BQ+XqpKOyORRd22/Oplu5DQLzEJZIu+YEptobBY +pUFqM8C9hFviCJW0juDDSdrJjiUnP9sqPXfbXpRZ3GbgUatlFeOOFFqS++rRP5fH +JngxFHqWKd1f4SOP/5ECtb1POGBPT9WT0YLuis6Oqo4yTvk/Oyn3mVNPiSlBkXML +GDUj3L/1rrADtj7HKPkHssR9cWq0MoUwaucSAvJEvdd0WPqG+7tIcO3SvZpkpIhu +L55vW1i9Iog+Vy60VsdgbM0QB1TC2OwRomWCYy9OrPbNk9Uk0oOuvrmc3ni7HpcT +TDm/+ocvtJ35OPwqdA47oxq1lY3dvRrB/6n4XT028PI+Axpga0/4w+oxN9ZESgTk +S0Jf9fuSKCXNWgcWkegKYr4ExEvJMKbx5O8DYJgQbvtmx7XUL/oUrYbpYWlhYx3x +/EvlWIE38p3us/0o8cYjh+gsxAtaBPmsW2KDsu205AMSsjUoF8jnY0eaMTvORQcW +LDc1js0jGKX1KoNRxySa4IwUrN+BSbtIonPw27Uch6NIu9+1CwUkagFOAimUuQIN +BFcpcKEBEADO3laIO69lLMz5yv+71c8cfr1Xjw99ax6JRw5+S+63/EooZzMQAnVu +79e9EDqL4w5qudCTnb5DWARnPY9pSbMvuP6vvNJYmLeiGT4R7pzlxw7oNDfoTknI +XmEOjVSHFg0YFSU0pxv0F35adC5m2YcxEEGOXNNxFZ9m/H8XDA0DsA2hqlxhcKCn +qQ8/aH6gkAUdXfpW+dXac7h6MazsErsMaPssPAvmlMNglOEvRoCtvI6+PB4rCsJL +eBaCj3pu+DaJRSyJyTt2TKKoYVxW6SlRIWn4ysii/P7XMjM4fNUJJOvLBwdEDkJj +eKNiGsz5ahAWrfVQ7aTuvp0h2g3LyY2tYhDeLGY4Tm13eVi58s3oNLcXdgsfMTgE +udA0OwvEdR5Kfgth0thBZUjsUH5xML8t/FpLmKniUE4VdnkatSSZAe+5xqmkn7V3 +ZJm1XkhUHFdETVc/xgTF7spccPjzMDkrFqGKmoC9n9ZJDX7K4BhIxMHG6SnLbXVd +4D+9ErRePchem9Q+yo6bBzw8X9nxBeju4pBkpmr3eCF33Atn+bN0ncp2G8BW2h73 +aWuXXqMhkCSko4UB3sviuCL9aXkAaqvk5WRBAhsZhEgO7ZEsTz0NTf6BxZJ+l1B/ +fNFAL+0awLpDOWsI4Fj4DO/6EXdmwRAmRBsSzv/WvfbJBzRBKZdoZQARAQABiQRE +BBgBAgAPAhsCBQJa75pVBQkFp10xAinBXSAEGQECAAYFAlcpcKEACgkQ9xwiw9sf +cidUWxAAqBuhLpGsfE761pLeO3DLEtUKt/YXFNiS62MSOO3hQYduZihq45Lvc6oI +eFvPGZq3ewHJ/YKI3BeCYJqB3yYWDzd2XQySozMMT1CsJF5AbnQ+VYmICGOQDgVU +LP1YOt5zuYK1MKCwG2sh/1pOJAbZA7Oj8BOU8hz90r7+F/65HMDku6QZnglpb1WT +v3+U/TQcuarYdPd/gqUJogwLfvSRhFcSXav/qpcCHvJqO7iuz+8cGIoply87YKz0 +WsipQl8wO5fFpk+T2LIc7vWfs56CIRh4+xI/TJAySwpX7Vm2D1AZtN/myYXrVt2J +N+GyAzUZXU42kOpkIR5ojagSohxdQcX+C821vk0izHxivqkm+Rue/TqdrnYSyoRQ +earNG3ErPRnF3GP3m82IsZEGwM3I2ev8hpQ5wtehXv3VGnfpeqonrVecvMsNrFvl +Zw8OsLKbct3DQug1rIacgb3tXz9oO+VSY8c0vNuaY8gPqyXuoWWht+djgnvueTom +TbaBCIySnzj2qlCkfrMkWOZG7ONhl+HWSRekIWiYirsWhTxEPgNSebXvBdDYhn5Y +a2Cu4glJDhO4ptFX59pKDyDltwFXgc9IfZfkVrVMVx6IwhjrXILZvul01LDeyVOw +8Dcy+epUpJ1012qUb9Capzrq8kXEsb4FdBqOpZ9e3MOWlQONlGgJEP2fy6PFPO0g +TV4P/RY9pjtEMYCQ4i2qPdDXFpaIFv8f0UlAegN9bF32uSWXHLksuo6J+/40vYDt +qPzBO1JQUovKb4Xgn9muN+YDT0u7RyItEQSYczEOjf1ygd354bjvefhfarMboupl +5h1zKR/S9hCQMA6CyyN83ucSPGzuJXaTro5a1IIL8aFJGyRU0wlFmW8csa6w3rtO +u13jSh+XRSXrcGL4/IpTrSVbvqRVF6ptyiLnOPJ1tf2DMUCz7Z3UFm2sXd29seL2 +Fq3KwEWbLeMlGlRRVbdUJkVtQqhcG3H1pWTcPbO2nWdNEIsV+DovvaaHp7yg12ok +/8+GY8fwEnfb90+w1Pox5iUlBX47NdYsuX8QEON3fbt2+rTKE2hElIpGOBOjQwF9 +Q3r7/tJ8wHJS4TBFzuNOmgLNG1jVuasYEB5NdXQgrYd0ADnAsGHq+L/5tsoA8B/y +OWdlXLdRZGdThgIrJLBy0HCes0vf7BU67wXWOpUzTYVMphStomafGnqMkTjhUUAQ +6KOPGVWBXGhTqNQEWhlHr9Ro+9We0ULbeWt3Ldcnfr9erap8q474jvTW3cbbqAT/ +7qS44dDnO07gu76L/UntHgRUM5p+AwIcbwduMDGOZxMK0rNlc3GQm7KDdlJGewAr +HXv4f5B0kS3W42HJYVfByu0jHyyM3Q36LW6hchdGRpKHHlDFiQREBBgBAgAPAhsC +BQJfAiWrBQkJueiFAinBXSAEGQECAAYFAlcpcKEACgkQ9xwiw9sfcidUWxAAqBuh +LpGsfE761pLeO3DLEtUKt/YXFNiS62MSOO3hQYduZihq45Lvc6oIeFvPGZq3ewHJ +/YKI3BeCYJqB3yYWDzd2XQySozMMT1CsJF5AbnQ+VYmICGOQDgVULP1YOt5zuYK1 +MKCwG2sh/1pOJAbZA7Oj8BOU8hz90r7+F/65HMDku6QZnglpb1WTv3+U/TQcuarY +dPd/gqUJogwLfvSRhFcSXav/qpcCHvJqO7iuz+8cGIoply87YKz0WsipQl8wO5fF +pk+T2LIc7vWfs56CIRh4+xI/TJAySwpX7Vm2D1AZtN/myYXrVt2JN+GyAzUZXU42 +kOpkIR5ojagSohxdQcX+C821vk0izHxivqkm+Rue/TqdrnYSyoRQearNG3ErPRnF +3GP3m82IsZEGwM3I2ev8hpQ5wtehXv3VGnfpeqonrVecvMsNrFvlZw8OsLKbct3D +Qug1rIacgb3tXz9oO+VSY8c0vNuaY8gPqyXuoWWht+djgnvueTomTbaBCIySnzj2 +qlCkfrMkWOZG7ONhl+HWSRekIWiYirsWhTxEPgNSebXvBdDYhn5Ya2Cu4glJDhO4 +ptFX59pKDyDltwFXgc9IfZfkVrVMVx6IwhjrXILZvul01LDeyVOw8Dcy+epUpJ10 +12qUb9Capzrq8kXEsb4FdBqOpZ9e3MOWlQONlGgJEP2fy6PFPO0g6OUP/i7NGgKx +8BcqGwxLnD/0yWAxFIR4hhqyEFMhu3at1x3RAS+Wbp2VVtVBKXEjHF8FU4uumAtV +jnDX7znLNRxU3V5V3D0ISxMtvbqhW1mCMyrbc0o2fwd53klT2E8vE9B+VV6XUYzk +Viqj0YOcQ7mTDbNufPrapdRtT5g/05lC98MBSjzGVv11h9t8dTMcmPBgMMwzdYEJ +tdHHJzfjmvqApYe6mP3NvCO9j8qukVX3nQjxx/5y2E17CyASwU8iLpB1mjPcTKFZ +xQVdg61m7ftwptIdasQaY7msqaW9C44ULMdxMq8E25ebMT1W8pGzLjO5xXI6v1o5 +h9hRNJEjPVpODgcBz8V+VZaiyfbF5/Rq/SUhHXLdxLS4ZvdWxoWj3NtbItg42OtG +qOU8CFh6pZQp3j2bvkQMdTQ587QByTE3cev+1RAjrjGNqIpSyAhDrFICP6Wz4EkX +OO43P0SZry7u5/lQRSo9w3r0j29MmGSZrVxgG3WRuzXh7e7Ii8uSETjqtmIXu9xO +9HokXbIcVmqD+eF2hdtx1FpSTvV3iefOn7XVVcyWGQHDfOXtbfyE5McZkX1YZ9gf +vS/3t/c23hqM2rFNVBs+yKfZIGEa7w+WedspQ4RR9PuTJP1El1aPCVheMIKxJHgz +24DIbd7BgGqHkwKf6fItseIGXWNWMFtLhObb +=GEF6 +-----END PGP PUBLIC KEY BLOCK----- +``` + +## Escalation + +If there is no response from the authors within 3 days, please escalate your vulnerability report by emailing security@blockstream.com using this PGP key: + + +``` +-----BEGIN PGP PUBLIC KEY BLOCK----- + +mQINBFv/XdQBEAC2iS1uQij2AJSnvQZxScnqf6v0db63QDbS6GjH5PndQ8cF0szv +YJYCFBigkzj4BkKxbJJlnfPW6Jl3SfzCGDvBW3IYuB3S10InDqJFYcM1ZemWCGAs +HA48NDfB4AIBIFH09H4dUE/J6yAdhX/+Qa/bjOhiwrCFVE2pVtMN8aTFnaLzxCP+ +fWZUaPrPv84B7uxEdLM77wIhsN+16FAr1qS42NfKDDolBAs//Bmv5fkNC7lzAVCf +MA/QEcNlAvButPrNyZU3t25maUv5hhKUDdJ2G/iACf8tVgp+ygmD8NHQMLPSaFqa +O5wy77Fd5OyX3Gii/E8MtPEsePViwecwJqc/3UXBx7zTRou2gxLikVFTnJb+Jit9 +F2kcljhCjHGxsuhf4Zr6zu+RTHHDgdBmpt4t1HA2jft/40r+uWQjL/rNP+01HgZj +4OLHkSI5VfJsXRn1EqOGpBIzR56f0GaxA0jluQMfkE9PTMxg5+YbrGgdot3l7pQ3 ++mqMu3aim2EYZZHTsMCRt4j4pRn5g4BZan+w7STfA7rIMJu/MjP3G4s+IFMPVRki +QLwktZSD+x2M9iIsOD4YVheMKtU6WRroFeCkXzIzLYwCuZ4ym/JFJMH+Keuyo254 +5hcymw+ivmPP+xuuoP1npQioRH4RKpfDgskABv8+t5rteV4BtUIWL33A/wARAQAB +tDlCbG9ja3N0cmVhbSBTZWN1cml0eSBSZXBvcnRpbmcgPHNlY3VyaXR5QGJsb2Nr +c3RyZWFtLmNvbT6JAk4EEwEKADgWIQQRdlQtqY5x4TNyLvdKyMyIaESi1gUCW/9d +1AIbAwULCQgHAgYVCgkICwIEFgIDAQIeAQIXgAAKCRBKyMyIaESi1lcQD/9HZmtP +XhKtwC92zTsT5Xqt/K4ckaiJRaUlHeFtfkHpTdXIUFIJjZ1w1JJAWLtRf58MY45U +5DAOOYQptoXiy4USZkIMH1uBtFSAvyCUXH5cDWK1347G5rUg6Ry8Cxe+wzXOlxfr +f/9Vs28z+awfIrvk50sj4QW+mMlS69VwuHUl5CJ+BtcqQWQO85ummQxQq8rMw7rD +AwkftqiMKz+YLw5/xECyiXDDdQr66kdkglbQGgiciS7HNo0SQ2XqTNcGZkRA3lmv +HYCchZpgr9qxfnLjgVddJB+iNTwFZ7AQ7ZBlYWvu5UIMweuEz+yB7WGbQZLOsRZ8 +OaIPmZ150VX0sQYeXYhoFrraNW6obFqsSklnQbsfw6KsCaFvYhNZgHf177YlrAzq +puR53H1sOjOQq8pnbjyf4XLhAGMC65LydWtkQK77m46kOBZad9UGg2WKg/SY+3pF +WWdP7vlsR7oJyElEQfUwBsT16K/6kenyagQ6CzqnF/X+W7P1STndpBJp4lD0RfaD +v6UyqxPYhUuQ24jP5jm8+RtS+OGB00czY2cVSDgjYVuU80WsW+Qt0XtLKeoVYdCb +TaKgreicqbz0Afr9hbPIieW2wbQnYlRPjprTVhhGsxlaUb7Kcz7fapliJrKBFgy5 +odUljZ+iSompuiYtFhVYA8e6sx0pRUGOopnkGLkCDQRb/13UARAA3WAlRv6DofgG +xu+L2ePZb1OCQTkn4Eq+24veGibPvlqFJivF1ebctUtxiKVsz0dXtWcAYk7Rh2I/ +xsEGxIzhjr5VLVOdldM5AgJna6WPvOA4sPXjdy47R71NfEQfg9Svv93mmkpbJsL3 +NuHxvpoeO4A9JrFfwn7WJevXOiUWdKJ+nn0ZPwjYle6i27OfIojyVmZVQEiHC/Il +LxQEYaNDalAorjnn0b7X7S3Z8pMAb8HqD0RTXXed9LPgbasARyND2I2xy1txUDPI +Qcq6tIbryGYlegEHuvsE31zRPoNjnXkwABb6qBkUUiZMbRJCYOQXSo7Z2tasKHIJ +I/FnIj8dmT/IXDb9KiWr8wziGLdgnZx3QZGt5P0LIMFKrfXMNJO7EmO1QMbgZFgk +JPhJ0o61PvMaVLMQVoxD6K7bKOzI2t4LTA0l5RxuMcadu8G13YzgVXX44Cac1qUn +xriMzk62HXdSeZozcO/IRN7Kdw2bB++5EVYTQN1EEhIymXVUrBg2pXvLSXalg+kp +0BhLVHcbTI51mKz8GY9NUShFI7ZEzxzzltcEA+F5TLrPMgT+tx+QvjDdGWIhWycI +KW53hjKiGolhpG9Kqo9ogtCO2a3r6JspO0z+54/EF5rS2LI13pqk0qNgoYMYqChe +XU8BJdZ9siCooQ+3o+Y/9TkQWSAwnWkAEQEAAYkCNgQYAQoAIBYhBBF2VC2pjnHh +M3Iu90rIzIhoRKLWBQJb/13UAhsMAAoJEErIzIhoRKLWGhoP/jFfwRrda1RNR6OY +NHOIa4x4PtjDuYwDYgI5X2NQXlglyOTWouKjY1eu7LRoQSS5blD7BA9GHhYRDBL/ +0NQo/EQn3JFoitGWs07Bry0A4DTOz0H7wRqVXtN+Ck13QdEemq+suLE+PcbRJ4Ei +ANoNVgSRGqYO683oXEzGgzF+FXXPbcRTNHwvV8LgmUioe2cgHX3Q2PC3gUTmnNkq +IhWirlT5cQVSLS2IzsP903uq8VtHl7lXLkS6Ba3CmwLoHYfhurGQNR6Av2WPgL2D +oY8NOxPdz9QxBUzUVObiMm3UfD/eTF73NAmNJRDqYzpY/l54ZyxLFjlfXRpwKrx/ +islwezx+2fzns5u4xwdywVHzvgsmbXMIDdNTaTS8BDaKbAopLmbmuTnnTbJXWFbb +mQ2/GHcB0mKuXDkzt+7JMQ0NHtrGC3qvEtnTXZGXr3uIhFDkJSOoaH68dqq5++pz +GtT+aiv3L120r0pSSyTgbPsrqSlWgXEuJ4uzt3j69J0Qek0YrL0EDxHdnGPW4+fv +AZiq1RFG8MHOy0Obahed5uqlzXCNtroHdgSQeR+6IkODSsEd+hVdXJs/hjcWLNG5 +VNztar/H4BSwlhKbgvFivOzhj8x5TNoqMM95G8Ew/5idiT/YQgsA6lcwsEZ78t9O +lTHPj4G8vH5F/zIFb+uQNSlKzuH+ +=8mAH +-----END PGP PUBLIC KEY BLOCK----- +``` + +## Acknowledgement + +Your help in maintaining and improving the security of this software is deeply appreciated. When the vulnerability you have reported is patched here and in downstream dependencies, we will publicly disclose it. Let us know if you would like to remain anonymous or would like to be acknowledged. We would be happy to acknowledge your contributions to closing the vulnerability you found in the release notes, source code and/or documentation in this repository. diff --git a/configure.ac b/configure.ac index 8fb802f5c..40cca2092 100644 --- a/configure.ac +++ b/configure.ac @@ -174,6 +174,9 @@ AX_CHECK_COMPILE_FLAG([-Wpedantic], [AM_CFLAGS="-Wpedantic $AM_CFLAGS"]) AX_CHECK_COMPILE_FLAG([-Wextra], [AM_CFLAGS="-Wextra $AM_CFLAGS"]) AX_CHECK_COMPILE_FLAG([-Wall], [AM_CFLAGS="-Wall $AM_CFLAGS"]) +# Needed for Ubuntu 20.04LTS when compiling as a library +AX_CHECK_COMPILE_FLAG([-D_DEFAULT_SOURCE=1], [AM_CFLAGS="-D_DEFAULT_SOURCE=1 $AM_CFLAGS"]) + # Disable some unhelpful errors from those enabled above AX_CHECK_COMPILE_FLAG([-Wno-unused-function], [AM_CFLAGS="$AM_CFLAGS -Wno-unused-function"]) AX_CHECK_COMPILE_FLAG([-Wno-long-long], [AM_CFLAGS="$AM_CFLAGS -Wno-long-long"]) diff --git a/docs/source/Liquid.rst b/docs/source/Liquid.rst index 1ac62b42a..3a3f91d86 100644 --- a/docs/source/Liquid.rst +++ b/docs/source/Liquid.rst @@ -30,7 +30,7 @@ blinding key from a mnemonic. :start-after: start-derive_blinding_key :end-before: end-derive_blinding_key -Finally call the wally function `confidential_addr_from_addr` to combine +Finally call the wally function :c:func:`wally_confidential_addr_from_addr` to combine the non-confidential address with the public blinding key to create a confidential address. We also supply a blinding prefix indicating the network version. @@ -39,7 +39,7 @@ network version. :start-after: start-create_conf_address :end-before: end-create_conf_address -The confidential address can now be passed to liquid-cli to received +The confidential address can now be passed to liquid-cli to receive funds. We'll send 1.1 BTC to our confidential address and save the raw hex transaction for further processing. @@ -87,7 +87,7 @@ less some fixed ``fee``. Generate blinding factors for the outputs. These are asset blinding factors (abf) and value blinding factors (vbf). The blinding factors are random except for the final vbf which must be calculated by calling -:c:func:`asset_final_vbf`. +:c:func:`wally_asset_final_vbf`. .. literalinclude:: ../../src/pyexample/liquid/receive-send.py :start-after: start-blinding_factors @@ -95,7 +95,7 @@ random except for the final vbf which must be calculated by calling A confidential output address can be decomposed into a standard address plus the public blinding key, and the libwally function -`address_to_scriptpubkey` will provide the corresponding script pubkey. +:c:func:`wally_address_to_scriptpubkey` will provide the corresponding script pubkey. .. literalinclude:: ../../src/pyexample/liquid/receive-send.py :start-after: start-decompose_address @@ -130,7 +130,7 @@ Sign the transaction inputs. :end-before: end-sign The transaction is now ready to be broadcast, the hex value is easily -retrieved by calling `tx_to_hex`. +retrieved by calling :c:func:`wally_tx_to_hex`. .. literalinclude:: ../../src/pyexample/liquid/receive-send.py :start-after: start-to_hex diff --git a/docs/source/conf.py b/docs/source/conf.py index c728bbc8e..42ed6f6c5 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -3,6 +3,9 @@ # libwally-core documentation build configuration file SCANNING, DOCS, FUNC = 1, 2, 3 +from os import getenv +DUMP_FUNCS = getenv("WALLY_DOC_DUMP_FUNCS") is not None + def get_doc_lines(l): if l.startswith('.. '): return [' ' + l, ''] @@ -12,13 +15,18 @@ def output_func(docs, func): is_normal_ret = 'WALLY_CORE_API int' in func func = func[:-1].replace('WALLY_CORE_API','').strip() func = func.replace(',',', ').replace(' ', ' ') + if DUMP_FUNCS: + # Dump function definitions if requested + print ('%s' % func) ret = ['.. c:function:: ' + func, ''] - seen_param = False + is_variable_buffer_ret = 'unsigned char *bytes_out, size_t len, size_t *written' in func for l in docs: ret.extend(get_doc_lines(l)) if is_normal_ret: - ret.append(' :return: WALLY_OK or an error code.') # FIXME: Link - ret.append(' :rtype: int') + if is_variable_buffer_ret: + ret.append(' :return: See :ref:`variable-length-output-buffers`') + else: + ret.append(' :return: See :ref:`error-codes`') ret.append('') ret.append('') return ret @@ -53,8 +61,8 @@ def extract_docs(infile, outfile): # Generate the documentation source files for m in [ - 'core', 'crypto', 'address', 'bip32', 'bip38', 'bip39', 'script', 'psbt', 'transaction', - 'elements' + 'core', 'crypto', 'address', 'bip32', 'bip38', 'bip39', 'script', 'psbt', + 'symmetric', 'transaction', 'elements' ]: extract_docs('../../include/wally_%s.h' % m, '%s.rst' % m) diff --git a/docs/source/conventions.rst b/docs/source/conventions.rst new file mode 100644 index 000000000..8572d7ee2 --- /dev/null +++ b/docs/source/conventions.rst @@ -0,0 +1,45 @@ +Library Conventions +=================== + +.. _error-codes: + +Error Codes +----------- + +The following values can be returned by library functions: + +================ ============================================= +Code Meaning +================ ============================================= +``WALLY_OK`` The function completed without error. + See :ref:`variable-length-output-buffers` if + applicable for the function. +``WALLY_ERROR`` An internal or unexpected error happened in + the library. In some cases this code may + indicate a specific error condition which + will be documented with the function. +``WALLY_EINVAL`` One or more parameters passed to the function + is not valid. For example, a required buffer + value is NULL or of the wrong length. +``WALLY_ENOMEM`` The function required memory allocation but + no memory could be allocated from the O/S. +================ ============================================= + + +.. _variable-length-output-buffers: + +Variable Length Output Buffers +------------------------------ + +Some functions write output that can vary in length to user supplied buffers. +In these cases, the number of written bytes is placed in the ``written`` +output parameter when the function completes. + +If the user supplied buffer is of insufficient size, these functions will +still return ``WALLY_OK``, but will place the required size in the ``written`` +output parameter. + +Callers must check not only that the function succeeds, but also that the +number of bytes written is less than or equal to the supplied buffer size. +If the buffer is too small, it should be resized to the returned size and the +call retried. diff --git a/docs/source/index.rst b/docs/source/index.rst index 06e8ae9d9..37590e050 100644 --- a/docs/source/index.rst +++ b/docs/source/index.rst @@ -13,6 +13,7 @@ libwally-core documentation bip39 psbt script + symmetric transaction elements @@ -20,6 +21,7 @@ libwally-core documentation :maxdepth: 2 :caption: Developer Guides + Library Conventions Liquid Indices and tables diff --git a/include/wally.hpp b/include/wally.hpp index e35152b33..006373c3e 100644 --- a/include/wally.hpp +++ b/include/wally.hpp @@ -10,7 +10,9 @@ #include #include #include +#include #include +#include #include /* These wrappers allow passing containers such as std::vector, std::array, @@ -45,7 +47,7 @@ template <> inline auto get_p(const std::nullptr_t& p) { #define WALLY_FN_3(F, N) inline int F(uint32_t i321) { return ::N(i321); } -#define WALLY_FN_333_BBBBBA(F, N) template inline int F(uint32_t i321, uint32_t i322, uint32_t i323, const I1 &i1, const I2 &i2, const I3 &i3, const I4 &i4, const I5 &i5, O * *out) { \ +#define WALLY_FN_333BBBBB_A(F, N) template inline int F(uint32_t i321, uint32_t i322, uint32_t i323, const I1 &i1, const I2 &i2, const I3 &i3, const I4 &i4, const I5 &i5, O * *out) { \ return ::N(i321, i322, i323, WALLYB(i1), WALLYB(i2), WALLYB(i3), WALLYB(i4), WALLYB(i5), out); \ } @@ -53,8 +55,16 @@ template <> inline auto get_p(const std::nullptr_t& p) { return ::N(i321, i322, s1, s2, out); \ } -#define WALLY_FN_3_A(F, N) template inline int F(uint32_t i321, O * *out) { \ - return ::N(i321, out); \ +#define WALLY_FN_S_A(F, N) template inline int F(size_t s1, O * *out) { \ + return ::N(s1, out); \ +} + +#define WALLY_FN_3SSS_A(F, N) template inline int F(uint32_t i321, size_t s1, size_t s2, size_t s3, O * *out) { \ + return ::N(i321, s1, s2, s3, out); \ +} + +#define WALLY_FN_SSSS_S(F, N) inline int F(size_t s1, size_t s2, size_t s3, size_t s4, size_t * written = 0) { \ + return ::N(s1, s2, s3, s4, written); \ } #define WALLY_FN_6_B(F, N) template inline int F(uint64_t i641, O & out) { \ @@ -65,9 +75,19 @@ template <> inline auto get_p(const std::nullptr_t& p) { return ::N(i641, WALLYB(i1), out); \ } -#define WALLY_FN_6BBBBBB_A(F, N) template \ - inline int F(uint64_t i641, const I1 &i1, const I2 &i2, const I3 &i3, const I4& i4, const I5 &i5, const I6 &i6, O * *out) { \ - return ::N(i641, WALLYB(i1), WALLYB(i2), WALLYB(i3), WALLYB(i4), WALLYB(i5), WALLYB(i6), out); \ +#define WALLY_FN_BBBBBB_A(F, N) template \ + inline int F(const I1 &i1, const I2 &i2, const I3 &i3, const I4& i4, const I5 &i5, const I6 &i6, O * *out) { \ + return ::N(WALLYB(i1), WALLYB(i2), WALLYB(i3), WALLYB(i4), WALLYB(i5), WALLYB(i6), out); \ +} + +#define WALLY_FN_BB_A(F, N) template \ + inline int F(const I1 &i1, const I2 &i2, O * *out) { \ + return ::N(WALLYB(i1), WALLYB(i2), out); \ +} + +#define WALLY_FN_BBB3_A(F, N) template \ + inline int F(const I1 &i1, const I2 &i2, const I3 &i3, uint32_t i321, O * *out) { \ + return ::N(WALLYB(i1), WALLYB(i2), WALLYB(i3), i321, out); \ } #define WALLY_FN_B(F, N) template inline int F(const I &i1) { return ::N(WALLYB(i1)); } @@ -116,6 +136,10 @@ template <> inline auto get_p(const std::nullptr_t& p) { return ::N(WALLYB(i1), WALLYB(i2), i321, out); \ } +#define WALLY_FN_BB3B(F, N) template inline int F(const I1 &i1, const I2 &i2, uint32_t i321, const I3 &i3) { \ + return ::N(WALLYB(i1), WALLYB(i2), i321, WALLYB(i3)); \ +} + #define WALLY_FN_BB3_B(F, N) template inline int F(const I1 &i1, const I2 &i2, uint32_t i321, O & out) { \ return ::N(WALLYB(i1), WALLYB(i2), i321, WALLYO(out)); \ } @@ -132,6 +156,10 @@ template <> inline auto get_p(const std::nullptr_t& p) { return written || ret != WALLY_OK ? ret : n == static_cast(out.size()) ? WALLY_OK : WALLY_EINVAL; \ } +#define WALLY_FN_6BB_B(F, N) template inline int F(uint64_t i641, const I1 &i1, const I2 &i2, O & out) { \ + return ::N(i641, WALLYB(i1), WALLYB(i2), WALLYO(out)); \ +} + #define WALLY_FN_BB_B(F, N) template inline int F(const I1 &i1, const I2 &i2, O & out) { \ return ::N(WALLYB(i1), WALLYB(i2), WALLYO(out)); \ } @@ -154,6 +182,14 @@ template <> inline auto get_p(const std::nullptr_t& p) { return ::N(WALLYB(i1), WALLYO(out)); \ } +#define WALLY_FN_B_6(F, N) template inline int F(const I &i1, uint64_t *out) { \ + return ::N(WALLYB(i1), out); \ +} + +#define WALLY_FN_BSBB_B(F, N) template inline int F(const I1 &i1, size_t s1, const I2& i2, const I3& i3, O & out) { \ + return ::N(WALLYB(i1), s1, WALLYB(i2), WALLYB(i3), WALLYO(out)); \ +} + #define WALLY_FN_B_BS(F, N) template inline int F(const I &i1, O & out, size_t * written = 0) { \ size_t n; \ int ret = ::N(WALLYB(i1), WALLYO(out), written ? written : &n); \ @@ -180,6 +216,14 @@ template <> inline auto get_p(const std::nullptr_t& p) { return ::N(WALLYP(p1), i321); \ } +#define WALLY_FN_PS3(F, N) template inline int F(const P1 &p1, size_t s1, uint32_t i321) { \ + return ::N(WALLYP(p1), s1, i321); \ +} + +#define WALLY_FN_P6(F, N) template inline int F(const P1 &p1, uint64_t i641) { \ + return ::N(WALLYP(p1), i641); \ +} + #define WALLY_FN_P33(F, N) template inline int F(const P1 &p1, uint32_t i321, uint32_t i322) { \ return ::N(WALLYP(p1), i321, i322); \ } @@ -188,18 +232,18 @@ template <> inline auto get_p(const std::nullptr_t& p) { return ::N(WALLYP(p1), i321, i322, out); \ } -#define WALLY_FN_P3B(F, N) template inline int F(const P1 &p1, uint32_t i321, const I1 &i1, O & out) { \ - return ::N(WALLYP(p1), i321, WALLYB(i1), WALLYO(out)); \ +#define WALLY_FN_P3B_A(F, N) template inline int F(const P1 &p1, uint32_t i321, const I1 &i1, O * * out) { \ + return ::N(WALLYP(p1), i321, WALLYB(i1), out); \ } -#define WALLY_FN_P3B633_B(F, N) template inline int F(const P1 &p1, uint32_t i321, const I1 &i1, uint64_t i641, uint32_t i322, uint32_t i323, O & out) { \ - return ::N(WALLYP(p1), i321, WALLYB(i1), i641, i322, i323, WALLYO(out)); \ +#define WALLY_FN_PSB633_B(F, N) template inline int F(const P1 &p1, size_t s1, const I1 &i1, uint64_t i641, uint32_t i321, uint32_t i322, O & out) { \ + return ::N(WALLYP(p1), s1, WALLYB(i1), i641, i321, i322, WALLYO(out)); \ } -#define WALLY_FN_P3BB36333_B(F, N) \ +#define WALLY_FN_PSBB36333_B(F, N) \ template \ - inline int F(const P1 &p1, uint32_t i321, const I1 &i1, const I2 &i2, uint32_t i322, uint64_t i641, uint32_t i323, uint32_t i324, uint32_t i325, O & out) { \ - return ::N(WALLYP(p1), i321, WALLYB(i1), WALLYB(i2), i322, i641, i323, i324, i325, WALLYO(out)); \ + inline int F(const P1 &p1, size_t s1, const I1 &i1, const I2 &i2, uint32_t i321, uint64_t i641, uint32_t i322, uint32_t i323, uint32_t i324, O & out) { \ + return ::N(WALLYP(p1), s1, WALLYB(i1), WALLYB(i2), i321, i641, i322, i323, i324, WALLYO(out)); \ } #define WALLY_FN_P3_A(F, N) template inline int F(const P1 &p1, uint32_t i321, O * *out) { \ @@ -210,6 +254,10 @@ template <> inline auto get_p(const std::nullptr_t& p) { return ::N(WALLYP(p1), i321, WALLYO(out)); \ } +#define WALLY_FN_P33_B(F, N) template inline int F(const P1 &p1, uint32_t i321, uint32_t i322, O & out) { \ + return ::N(WALLYP(p1), i321, i322, WALLYO(out)); \ +} + #define WALLY_FN_P3_BS(F, N) template inline int F(const P1 &p1, uint32_t i321, O & out, size_t * written = 0) { \ size_t n; \ int ret = ::N(WALLYP(p1), i321, WALLYO(out), written ? written : &n); \ @@ -228,20 +276,32 @@ template <> inline auto get_p(const std::nullptr_t& p) { return ::N(WALLYP(p1), i641, WALLYB(i1), i321); \ } -#define WALLY_FN_P6BB33_B(F, N) template \ - inline int F(const P1 &p1, uint64_t i641, const I1 &i1, const I2 &i2, uint32_t i321, uint32_t i322, O & out) { \ - return ::N(WALLYP(p1), i641, WALLYB(i1), WALLYB(i2), i321, i322, WALLYO(out)); \ +#define WALLY_FN_PSBB33_B(F, N) template \ + inline int F(const P1 &p1, size_t s1, const I1 &i1, const I2 &i2, uint32_t i321, uint32_t i322, O & out) { \ + return ::N(WALLYP(p1), s1, WALLYB(i1), WALLYB(i2), i321, i322, WALLYO(out)); \ } -#define WALLY_FN_P6BBBBBB3(F, N) template \ - inline int F(const P1 &p1, uint64_t i641, const I1 &i1, const I2 &i2, const I3 &i3, const I4& i4, const I5 &i5, const I6 &i6, uint32_t i321) { \ - return ::N(WALLYP(p1), i641, WALLYB(i1), WALLYB(i2), WALLYB(i3), WALLYB(i4), WALLYB(i5), WALLYB(i6), i321); \ +#define WALLY_FN_PBBBBBB3(F, N) template \ + inline int F(const P1 &p1, const I1 &i1, const I2 &i2, const I3 &i3, const I4& i4, const I5 &i5, const I6 &i6, uint32_t i321) { \ + return ::N(WALLYP(p1), WALLYB(i1), WALLYB(i2), WALLYB(i3), WALLYB(i4), WALLYB(i5), WALLYB(i6), i321); \ } #define WALLY_FN_PB(F, N) template inline int F(const P1 &p1, const I1 &i1) { \ return ::N(WALLYP(p1), WALLYB(i1)); \ } +#define WALLY_FN_PB3(F, N) template inline int F(const P1 &p1, const I1 &i1, uint32_t i321) { \ + return ::N(WALLYP(p1), WALLYB(i1), i321); \ +} + +#define WALLY_FN_PBB(F, N) template \ + inline int F(const P1 &p1, const I1 &i1, const I2 &i2) { return ::N(WALLYP(p1), WALLYB(i1), WALLYB(i2)); } + +#define WALLY_FN_PBBB(F, N) template \ + inline int F(const P1 &p1, const I1 &i1, const I2 &i2, const I3 &i3) { \ + return ::N(WALLYP(p1), WALLYB(i1), WALLYB(i2), WALLYB(i3)); \ +} + #define WALLY_FN_PBBBBB(F, N) template \ inline int F(const P1 &p1, const I1 &i1, const I2 &i2, const I3 &i3, const I4& i4, const I5 &i5) { \ return ::N(WALLYP(p1), WALLYB(i1), WALLYB(i2), WALLYB(i3), WALLYB(i4), WALLYB(i5)); \ @@ -262,10 +322,10 @@ template <> inline auto get_p(const std::nullptr_t& p) { return ::N(WALLYB(i1), i321, i322, WALLYB(i2), WALLYP(p1), WALLYB(i3), WALLYB(i4), WALLYB(i5), WALLYB(i6), WALLYB(i7), WALLYB(i8), out); \ } -#define WALLY_FN_PB33BPBBBBBB3(F, N) template \ +#define WALLY_FN_PB33BPBBBBBBP3(F, N) template \ inline int F(const P1 &p1, const I1 &i1, uint32_t i321, uint32_t i322, const I2 &i2, const P2 &p2, \ - const I3 &i3, const I4& i4, const I5 &i5, const I6 &i6, const I7& i7, const I8& i8, uint32_t i323) { \ - return ::N(WALLYP(p1), WALLYB(i1), i321, i322, WALLYB(i2), WALLYP(p2), WALLYB(i3), WALLYB(i4), WALLYB(i5), WALLYB(i6), WALLYB(i7), WALLYB(i8), i323); \ + const I3 &i3, const I4& i4, const I5 &i5, const I6 &i6, const I7& i7, const I8& i8, const P3& p3, uint32_t i323) { \ + return ::N(WALLYP(p1), WALLYB(i1), i321, i322, WALLYB(i2), WALLYP(p2), WALLYB(i3), WALLYB(i4), WALLYB(i5), WALLYB(i6), WALLYB(i7), WALLYB(i8), WALLYP(p3), i323); \ } #define WALLY_FN_PB3_A(F, N) template inline int F(const P1 &p1, const I1 &i1, uint32_t i321, O * *out) { \ @@ -284,16 +344,75 @@ template <> inline auto get_p(const std::nullptr_t& p) { return ::N(WALLYP(p1), WALLYB(i1), out); \ } +#define WALLY_FN_PB_S(F, N) template inline int F(const P1 &p1, const I1 &i1, size_t * written) { \ + return ::N(WALLYP(p1), WALLYB(i1), written); \ +} + #define WALLY_FN_PP(F, N) template inline int F(const P1 &p1, const P2 &p2) { \ return ::N(WALLYP(p1), WALLYP(p2)); \ } +#define WALLY_FN_PPP_A(F, N) template inline int F(const P1 &p1, const P2 &p2, const P3& p3, O * *out) { \ + return ::N(WALLYP(p1), WALLYP(p2), WALLYP(p3), out); \ +} + +#define WALLY_FN_PP3_A(F, N) template inline int F(const P1 &p1, const P2 &p2, uint32_t i321, O * *out) { \ + return ::N(WALLYP(p1), WALLYP(p2), i321, out); \ +} + +#define WALLY_FN_PPPB_A(F, N) template \ + inline int F(const P1 &p1, const P2 &p2, const P3& p3, const I1& i1, O * *out) { \ + return ::N(WALLYP(p1), WALLYP(p2), WALLYP(p3), WALLYB(i1), out); \ +} + #define WALLY_FN_PP3_BS(F, N) template inline int F(const P1 &p1, const P2 &p2, uint32_t i321, O & out, size_t * written = 0) { \ size_t n; \ int ret = ::N(WALLYP(p1), WALLYP(p2), i321, WALLYO(out), written ? written : &n); \ return written || ret != WALLY_OK ? ret : n == static_cast(out.size()) ? WALLY_OK : WALLY_EINVAL; \ } +#define WALLY_FN_BBSBBB_BS(F, N) template \ + inline int F(const I1 &i1, const I2 &i2, size_t s1, const I3& i3, const I4& i4, const I5& i5, O & out, size_t * written = 0) { \ + size_t n; \ + int ret = ::N(WALLYB(i1), WALLYB(i2), s1, WALLYB(i3), WALLYB(i4), WALLYB(i5), WALLYO(out), written ? written : &n); \ + return written || ret != WALLY_OK ? ret : n == static_cast(out.size()) ? WALLY_OK : WALLY_EINVAL; \ +} + +#define WALLY_FN_BBBB3_BS(F, N) template \ + inline int F(const I1 &i1, const I2 &i2, const I3& i3, const I4& i4, uint32_t i321, O & out, size_t * written = 0) { \ + size_t n; \ + int ret = ::N(WALLYB(i1), WALLYB(i2), WALLYB(i3), WALLYB(i4), i321, WALLYO(out), written ? written : &n); \ + return written || ret != WALLY_OK ? ret : n == static_cast(out.size()) ? WALLY_OK : WALLY_EINVAL; \ +} + +#define WALLY_FN_BBBBBBB_BS(F, N) template \ + inline int F(const I1 &i1, const I2 &i2, const I3& i3, const I4& i4, const I5& i5, const I6& i6, const I7& i7, O & out, size_t * written = 0) { \ + size_t n; \ + int ret = ::N(WALLYB(i1), WALLYB(i2), WALLYB(i3), WALLYB(i4), WALLYB(i5), WALLYB(i6), WALLYB(i7), WALLYO(out), written ? written : &n); \ + return written || ret != WALLY_OK ? ret : n == static_cast(out.size()) ? WALLY_OK : WALLY_EINVAL; \ +} + +#define WALLY_FN_6BBBBBBBB6II_BS(F, N) template \ + inline int F(uint64_t i641, const I1 &i1, const I2 &i2, const I3& i3, const I4& i4, const I5& i5, const I6& i6, const I7& i7, const I8& i8, uint64_t i642, int i321, int i322, O & out, size_t * written = 0) { \ + size_t n; \ + int ret = ::N(i641, WALLYB(i1), WALLYB(i2), WALLYB(i3), WALLYB(i4), WALLYB(i5), WALLYB(i6), WALLYB(i7), WALLYB(i8), i642, i321, i322, WALLYO(out), written ? written : &n); \ + return written || ret != WALLY_OK ? ret : n == static_cast(out.size()) ? WALLY_OK : WALLY_EINVAL; \ +} + +#define WALLY_FN_BBBBB_BBB6(F, N) template \ + inline int F(const I1 &i1, const I2 &i2, size_t s1, const I3& i3, const I4& i4, const I5& i5, O1& out1, O2& out2, O3& out3, uint64_t *out) { \ + return ::N(WALLYB(i1), WALLYB(i2), WALLYB(i3), WALLYB(i4), WALLYB(i5), WALLYO(out1), WALLYO(out2), WALLYO(out3), out); \ +} + +#define WALLY_FN_BBBBBB_BBB6(F, N) template \ + inline int F(const I1 &i1, const I2 &i2, size_t s1, const I3& i3, const I4& i4, const I5& i5, const I6& i6, O1& out1, O2& out2, O3& out3, uint64_t *out) { \ + return ::N(WALLYB(i1), WALLYB(i2), WALLYB(i3), WALLYB(i4), WALLYB(i5), WALLYB(i6), WALLYO(out1), WALLYO(out2), WALLYO(out3), out); \ +} + +#define WALLY_FN_PP_B(F, N) template inline int F(const P1 &p1, const P2 &p2, O & out) { \ + return ::N(WALLYP(p1), WALLYP(p2), WALLYO(out)); \ +} + #define WALLY_FN_PP_BS(F, N) template inline int F(const P1 &p1, const P2 &p2, O & out, size_t * written = 0) { \ size_t n; \ int ret = ::N(WALLYP(p1), WALLYP(p2), WALLYO(out), written ? written : &n); \ @@ -316,10 +435,18 @@ template <> inline auto get_p(const std::nullptr_t& p) { return ::N(WALLYP(p1), s1, out); \ } +#define WALLY_FN__A(F, N) template inline int F(O **out) { return ::N(out); } + +#define WALLY_FN__S(F, N) inline int F(size_t *written) { return ::N(written); } + #define WALLY_FN_P_A(F, N) template inline int F(const P1 &p1, O * *out) { \ return ::N(WALLYP(p1), out); \ } +#define WALLY_FN_P_B(F, N) template inline int F(const P1 &p1, O & out) { \ + return ::N(WALLYP(p1), WALLYO(out)); \ +} + #define WALLY_FN_P_BS(F, N) template inline int F(const P1 &p1, O & out, size_t * written = 0) { \ size_t n; \ int ret = ::N(WALLYP(p1), WALLYO(out), written ? written : &n); \ @@ -330,121 +457,182 @@ template <> inline auto get_p(const std::nullptr_t& p) { return ::N(WALLYP(p1), written); \ } -#define WALLY_FN_P_P(F, N) template inline int F(const P1 &p1, O * written) { \ - return ::N(WALLYP(p1), written); \ +#define WALLY_FN_P_P(F, N) template inline int F(const P1 &p1, O * out) { \ + return ::N(WALLYP(p1), out); \ } #define WALLY_FN_S_S(F, N) inline int F(size_t s1, size_t * written) { \ return ::N(s1, written); \ } -WALLY_FN_3(init, wally_init) WALLY_FN_3(cleanup, wally_cleanup) -WALLY_FN_333_BBBBBA(bip32_key_init_alloc, bip32_key_init_alloc) +WALLY_FN_3(init, wally_init) +WALLY_FN_333BBBBB_A(bip32_key_init_alloc, bip32_key_init_alloc) WALLY_FN_33SS_A(tx_init_alloc, wally_tx_init_alloc) -WALLY_FN_3_A(tx_witness_stack_init_alloc, wally_tx_witness_stack_init_alloc) +WALLY_FN_3SSS_A(psbt_init_alloc, wally_psbt_init_alloc) WALLY_FN_6B_A(tx_output_init_alloc, wally_tx_output_init_alloc) WALLY_FN_B(ec_private_key_verify, wally_ec_private_key_verify) WALLY_FN_B(ec_public_key_verify, wally_ec_public_key_verify) WALLY_FN_B(secp_randomize, wally_secp_randomize) WALLY_FN_B33BP_A(tx_input_init_alloc, wally_tx_input_init_alloc) -WALLY_FN_B33_A(bip32_key_from_parent_alloc, bip32_key_from_parent_alloc) WALLY_FN_B33_A(bip32_key_from_seed_alloc, bip32_key_from_seed_alloc) WALLY_FN_B33_A(wif_from_bytes, wally_wif_from_bytes) WALLY_FN_B33_BS(scriptpubkey_csv_2of2_then_1_from_bytes, wally_scriptpubkey_csv_2of2_then_1_from_bytes) WALLY_FN_B33_BS(scriptpubkey_csv_2of3_then_2_from_bytes, wally_scriptpubkey_csv_2of3_then_2_from_bytes) WALLY_FN_B33_BS(scriptpubkey_multisig_from_bytes, wally_scriptpubkey_multisig_from_bytes) WALLY_FN_B33_P(bip32_key_from_seed, bip32_key_from_seed) +WALLY_FN_B3B_B(symmetric_key_from_parent, wally_symmetric_key_from_parent) WALLY_FN_B3_A(base58_from_bytes, wally_base58_from_bytes) +WALLY_FN_B3_A(scriptpubkey_to_address, wally_scriptpubkey_to_address) WALLY_FN_B3_A(tx_from_bytes, wally_tx_from_bytes) WALLY_FN_B3_BS(format_bitcoin_message, wally_format_bitcoin_message) WALLY_FN_B3_BS(script_push_from_bytes, wally_script_push_from_bytes) +WALLY_FN_B3_BS(scriptpubkey_op_return_from_bytes, wally_scriptpubkey_op_return_from_bytes) WALLY_FN_B3_BS(scriptpubkey_p2pkh_from_bytes, wally_scriptpubkey_p2pkh_from_bytes) WALLY_FN_B3_BS(scriptpubkey_p2sh_from_bytes, wally_scriptpubkey_p2sh_from_bytes) WALLY_FN_B3_BS(witness_program_from_bytes, wally_witness_program_from_bytes) WALLY_FN_BB333_B(scrypt, wally_scrypt) +WALLY_FN_BB33_B(pbkdf2_hmac_sha256, wally_pbkdf2_hmac_sha256) +WALLY_FN_BB33_B(pbkdf2_hmac_sha512, wally_pbkdf2_hmac_sha512) +WALLY_FN_BB3B(ec_sig_verify, wally_ec_sig_verify) WALLY_FN_BB3_A(bip38_from_private_key, bip38_from_private_key) +WALLY_FN_BB3_A(witness_p2wpkh_from_sig, wally_witness_p2wpkh_from_sig) WALLY_FN_BB3_B(aes, wally_aes) WALLY_FN_BB3_B(bip38_raw_from_private_key, bip38_raw_from_private_key) WALLY_FN_BB3_B(bip38_raw_to_private_key, bip38_raw_to_private_key) WALLY_FN_BB3_B(ec_sig_from_bytes, wally_ec_sig_from_bytes) -WALLY_FN_BB3_B(ec_sig_verify, wally_ec_sig_verify) WALLY_FN_BB3_BS(scriptsig_p2pkh_from_sig, wally_scriptsig_p2pkh_from_sig) +WALLY_FN_BBB3_A(witness_multisig_from_bytes, wally_witness_multisig_from_bytes) WALLY_FN_BBB3_BS(aes_cbc, wally_aes_cbc) WALLY_FN_BBB3_BS(scriptsig_multisig_from_bytes, wally_scriptsig_multisig_from_bytes) +WALLY_FN_BB_A(witness_p2wpkh_from_der, wally_witness_p2wpkh_from_der) +WALLY_FN_BB_B(ec_sig_to_public_key, wally_ec_sig_to_public_key) +WALLY_FN_BB_B(ecdh, wally_ecdh) WALLY_FN_BB_B(hmac_sha256, wally_hmac_sha256) WALLY_FN_BB_B(hmac_sha512, wally_hmac_sha512) -WALLY_FN_BB_B(ecdh, wally_ecdh) -WALLY_FN_BP3_A(addr_segwit_from_bytes, wally_addr_segwit_from_bytes) WALLY_FN_BB_BS(scriptsig_p2pkh_from_der, wally_scriptsig_p2pkh_from_der) +WALLY_FN_BP3_A(addr_segwit_from_bytes, wally_addr_segwit_from_bytes) WALLY_FN_B_A(bip32_key_unserialize_alloc, bip32_key_unserialize_alloc) WALLY_FN_B_A(hex_from_bytes, wally_hex_from_bytes) +WALLY_FN_B_A(psbt_from_bytes, wally_psbt_from_bytes) WALLY_FN_B_B(ec_public_key_decompress, wally_ec_public_key_decompress) WALLY_FN_B_B(ec_public_key_from_private_key, wally_ec_public_key_from_private_key) +WALLY_FN_B_B(ec_public_key_negate, wally_ec_public_key_negate) WALLY_FN_B_B(ec_sig_from_der, wally_ec_sig_from_der) WALLY_FN_B_B(ec_sig_normalize, wally_ec_sig_normalize) WALLY_FN_B_B(hash160, wally_hash160) WALLY_FN_B_B(sha256, wally_sha256) +WALLY_FN_B_B(sha256_midstate, wally_sha256_midstate) WALLY_FN_B_B(sha256d, wally_sha256d) WALLY_FN_B_B(sha512, wally_sha512) +WALLY_FN_B_B(symmetric_key_from_seed, wally_symmetric_key_from_seed) WALLY_FN_B_BS(ec_sig_to_der, wally_ec_sig_to_der) WALLY_FN_B_P(bip32_key_unserialize, bip32_key_unserialize) +WALLY_FN_B_S(bip38_raw_get_flags, bip38_raw_get_flags) WALLY_FN_B_S(scriptpubkey_get_type, wally_scriptpubkey_get_type) -WALLY_FN_BB33_B(pbkdf2_hmac_sha256, wally_pbkdf2_hmac_sha256) -WALLY_FN_BB33_B(pbkdf2_hmac_sha512, wally_pbkdf2_hmac_sha512) WALLY_FN_P(bip32_key_free, bip32_key_free) +WALLY_FN_P(bip32_key_strip_private_key, bip32_key_strip_private_key) WALLY_FN_P(get_operations, wally_get_operations) +WALLY_FN_P(keypath_map_free, wally_keypath_map_free) +WALLY_FN_P(partial_sigs_map_free, wally_partial_sigs_map_free) +WALLY_FN_P(psbt_free, wally_psbt_free) WALLY_FN_P(set_operations, wally_set_operations) WALLY_FN_P(tx_free, wally_tx_free) WALLY_FN_P(tx_input_free, wally_tx_input_free) WALLY_FN_P(tx_output_free, wally_tx_output_free) WALLY_FN_P(tx_witness_stack_free, wally_tx_witness_stack_free) +WALLY_FN_P(unknowns_map_free, wally_unknowns_map_free) +WALLY_FN_P3(psbt_input_set_sighash_type, wally_psbt_input_set_sighash_type) WALLY_FN_P3(tx_witness_stack_add_dummy, wally_tx_witness_stack_add_dummy) -WALLY_FN_P3(tx_witness_stack_set_dummy, wally_tx_witness_stack_set_dummy) +WALLY_FN_P33_A(bip32_key_from_parent_alloc, bip32_key_from_parent_alloc) +WALLY_FN_P33_A(bip32_key_to_address, wally_bip32_key_to_address) +WALLY_FN_P33_A(wif_to_address, wally_wif_to_address) +WALLY_FN_P33_B(wif_to_bytes, wally_wif_to_bytes) WALLY_FN_P33_P(bip32_key_from_parent, bip32_key_from_parent) -WALLY_FN_P3B(tx_witness_stack_set, wally_tx_witness_stack_set) -WALLY_FN_P3B633_B(tx_get_btc_signature_hash, wally_tx_get_btc_signature_hash) -WALLY_FN_P3BB36333_B(tx_get_signature_hash, wally_tx_get_signature_hash) WALLY_FN_P3_A(bip32_key_to_base58, bip32_key_to_base58) +WALLY_FN_P3_A(psbt_to_base64, wally_psbt_to_base64) +WALLY_FN_P3_A(tx_clone, wally_tx_clone) WALLY_FN_P3_A(tx_from_hex, wally_tx_from_hex) WALLY_FN_P3_A(tx_to_hex, wally_tx_to_hex) WALLY_FN_P3_B(bip32_key_serialize, bip32_key_serialize) -WALLY_FN_P3_B(wif_to_bytes, wally_wif_to_bytes) +WALLY_FN_P3_BS(address_to_scriptpubkey, wally_address_to_scriptpubkey) WALLY_FN_P3_BS(base58_to_bytes, wally_base58_to_bytes) +WALLY_FN_P3_BS(psbt_to_bytes, wally_psbt_to_bytes) WALLY_FN_P3_BS(tx_to_bytes, wally_tx_to_bytes) WALLY_FN_P3_BS(wif_to_public_key, wally_wif_to_public_key) +WALLY_FN_P3_S(psbt_get_length, wally_psbt_get_length) WALLY_FN_P3_S(tx_get_length, wally_tx_get_length) -WALLY_FN_P33_A(wif_to_address, wally_wif_to_address) WALLY_FN_P6B3(tx_add_raw_output, wally_tx_add_raw_output) +WALLY_FN_PB(psbt_input_set_final_script_sig, wally_psbt_input_set_final_script_sig) +WALLY_FN_PB(psbt_input_set_redeem_script, wally_psbt_input_set_redeem_script) +WALLY_FN_PB(psbt_input_set_witness_script, wally_psbt_input_set_witness_script) +WALLY_FN_PB(psbt_output_set_redeem_script, wally_psbt_output_set_redeem_script) +WALLY_FN_PB(psbt_output_set_witness_script, wally_psbt_output_set_witness_script) WALLY_FN_PB(tx_witness_stack_add, wally_tx_witness_stack_add) +WALLY_FN_PB3(psbt_sign, wally_psbt_sign) WALLY_FN_PB33BP3(tx_add_raw_input, wally_tx_add_raw_input) WALLY_FN_PB3_A(bip32_key_from_parent_path_alloc, bip32_key_from_parent_path_alloc) WALLY_FN_PB3_B(bip38_to_private_key, bip38_to_private_key) WALLY_FN_PB3_P(bip32_key_from_parent_path, bip32_key_from_parent_path) +WALLY_FN_PBB(partial_sigs_map_add, wally_partial_sigs_map_add) +WALLY_FN_PBB(unknowns_map_add, wally_unknowns_map_add) +WALLY_FN_PBBB(keypath_map_add, wally_keypath_map_add) WALLY_FN_PB_A(bip39_mnemonic_from_bytes, bip39_mnemonic_from_bytes) +WALLY_FN_PB_S(keypath_map_find, wally_keypath_map_find) +WALLY_FN_PB_S(partial_sigs_map_find, wally_partial_sigs_map_find) +WALLY_FN_PB_S(unknowns_map_find, wally_unknowns_map_find) WALLY_FN_PP(bip39_mnemonic_validate, bip39_mnemonic_validate) +WALLY_FN_PP(psbt_combine, wally_psbt_combine) +WALLY_FN_PP(psbt_input_set_final_witness, wally_psbt_input_set_final_witness) +WALLY_FN_PP(psbt_input_set_keypaths, wally_psbt_input_set_keypaths) +WALLY_FN_PP(psbt_input_set_non_witness_utxo, wally_psbt_input_set_non_witness_utxo) +WALLY_FN_PP(psbt_input_set_partial_sigs, wally_psbt_input_set_partial_sigs) +WALLY_FN_PP(psbt_input_set_unknowns, wally_psbt_input_set_unknowns) +WALLY_FN_PP(psbt_input_set_witness_utxo, wally_psbt_input_set_witness_utxo) +WALLY_FN_PP(psbt_output_set_keypaths, wally_psbt_output_set_keypaths) +WALLY_FN_PP(psbt_output_set_unknowns, wally_psbt_output_set_unknowns) +WALLY_FN_PP(psbt_set_global_tx, wally_psbt_set_global_tx) WALLY_FN_PP(tx_add_input, wally_tx_add_input) WALLY_FN_PP(tx_add_output, wally_tx_add_output) +WALLY_FN_PP3_A(bip32_key_to_addr_segwit, wally_bip32_key_to_addr_segwit) WALLY_FN_PP3_BS(addr_segwit_to_bytes, wally_addr_segwit_to_bytes) WALLY_FN_PP_BS(bip39_mnemonic_to_bytes, bip39_mnemonic_to_bytes) WALLY_FN_PP_BS(bip39_mnemonic_to_seed, bip39_mnemonic_to_seed) WALLY_FN_PS(tx_remove_input, wally_tx_remove_input) WALLY_FN_PS(tx_remove_output, wally_tx_remove_output) +WALLY_FN_PS3(tx_witness_stack_set_dummy, wally_tx_witness_stack_set_dummy) WALLY_FN_PSB(tx_set_input_script, wally_tx_set_input_script) +WALLY_FN_PSB(tx_witness_stack_set, wally_tx_witness_stack_set) +WALLY_FN_PSB633_B(tx_get_btc_signature_hash, wally_tx_get_btc_signature_hash) +WALLY_FN_PSBB36333_B(tx_get_signature_hash, wally_tx_get_signature_hash) WALLY_FN_PSP(tx_set_input_witness, wally_tx_set_input_witness) WALLY_FN_PS_A(bip39_get_word, bip39_get_word) WALLY_FN_P_A(bip32_key_from_base58_alloc, bip32_key_from_base58_alloc) -WALLY_FN_P_A(bip39_get_languages, bip39_get_languages) WALLY_FN_P_A(bip39_get_wordlist, bip39_get_wordlist) +WALLY_FN_P_A(psbt_extract, wally_psbt_extract) +WALLY_FN_P_A(psbt_from_base64, wally_psbt_from_base64) +WALLY_FN_P_A(tx_output_clone_alloc, wally_tx_output_clone_alloc) +WALLY_FN_P_A(tx_witness_stack_clone_alloc, wally_tx_witness_stack_clone_alloc) +WALLY_FN_P_B(bip32_key_get_fingerprint, bip32_key_get_fingerprint) +WALLY_FN_P_B(tx_get_txid, wally_tx_get_txid) WALLY_FN_P_BS(hex_to_bytes, wally_hex_to_bytes) +WALLY_FN_P_P(bip32_key_from_base58, bip32_key_from_base58) +WALLY_FN_P_P(tx_get_total_output_satoshi, wally_tx_get_total_output_satoshi) +WALLY_FN_P_P(tx_output_clone, wally_tx_output_clone) WALLY_FN_P_S(base58_get_length, wally_base58_get_length) -WALLY_FN_P_S(wif_is_uncompressed, wally_wif_is_uncompressed) +WALLY_FN_P_S(bip38_get_flags, bip38_get_flags) +WALLY_FN_P_S(psbt_is_elements, wally_psbt_is_elements) WALLY_FN_P_S(tx_get_vsize, wally_tx_get_vsize) WALLY_FN_P_S(tx_get_weight, wally_tx_get_weight) WALLY_FN_P_S(tx_get_witness_count, wally_tx_get_witness_count) -WALLY_FN_P_P(bip32_key_from_base58, bip32_key_from_base58) -WALLY_FN_P_P(tx_get_total_output_satoshi, wally_tx_get_total_output_satoshi) +WALLY_FN_P_S(tx_is_coinbase, wally_tx_is_coinbase) +WALLY_FN_P_S(wif_is_uncompressed, wally_wif_is_uncompressed) +WALLY_FN_S_A(keypath_map_init_alloc, wally_keypath_map_init_alloc) +WALLY_FN_S_A(partial_sigs_map_init_alloc, wally_partial_sigs_map_init_alloc) +WALLY_FN_S_A(tx_witness_stack_init_alloc, wally_tx_witness_stack_init_alloc) +WALLY_FN_S_A(unknowns_map_init_alloc, wally_unknowns_map_init_alloc) WALLY_FN_S_S(tx_vsize_from_weight, wally_tx_vsize_from_weight) +WALLY_FN__A(bip39_get_languages, bip39_get_languages) inline struct secp256k1_context_struct *get_secp_context() { return ::wally_get_secp_context(); @@ -464,28 +652,74 @@ template inline int clear(O& out) { inline bool is_elements_build() { - uint64_t ret = 0; + size_t ret; ::wally_is_elements_build(&ret); return ret != 0; } #ifdef BUILD_ELEMENTS -WALLY_FN_PBBBBBB(tx_elements_input_issuance_set, wally_tx_elements_input_issuance_set) +WALLY_FN_3SSS_A(psbt_elements_init_alloc, wally_psbt_elements_init_alloc) +WALLY_FN_6BBBBBBBB6II_BS(asset_rangeproof, wally_asset_rangeproof) +WALLY_FN_6BB_B(asset_value_commitment, wally_asset_value_commitment) +WALLY_FN_6_B(tx_confidential_value_from_satoshi, wally_tx_confidential_value_from_satoshi) +WALLY_FN_B33BPBBBBBBP_A(tx_elements_input_init_alloc, wally_tx_elements_input_init_alloc) +WALLY_FN_B3B_B(tx_elements_issuance_generate_entropy, wally_tx_elements_issuance_generate_entropy) +WALLY_FN_B3_B(tx_elements_issuance_calculate_reissuance_token, wally_tx_elements_issuance_calculate_reissuance_token) +WALLY_FN_BB3_BS(elements_pegin_contract_script_from_bytes, wally_elements_pegin_contract_script_from_bytes) +WALLY_FN_BBBB3_BS(elements_pegout_script_from_bytes, wally_elements_pegout_script_from_bytes) +WALLY_FN_BBBBBBB_BS(asset_surjectionproof, wally_asset_surjectionproof) +WALLY_FN_BBBBBB_A(tx_elements_output_init_alloc, wally_tx_elements_output_init_alloc) +WALLY_FN_BBBBBB_BBB6(asset_unblind, wally_asset_unblind) +WALLY_FN_BBBBB_BBB6(asset_unblind_with_nonce, wally_asset_unblind_with_nonce) +WALLY_FN_BBSBBB_BS(asset_pak_whitelistproof, wally_asset_pak_whitelistproof) +WALLY_FN_BB_B(asset_blinding_key_to_ec_private_key, wally_asset_blinding_key_to_ec_private_key) +WALLY_FN_BB_B(asset_generator_from_bytes, wally_asset_generator_from_bytes) +WALLY_FN_BSBB_B(asset_final_vbf, wally_asset_final_vbf) +WALLY_FN_B_6(tx_confidential_value_to_satoshi, wally_tx_confidential_value_to_satoshi) +WALLY_FN_B_B(asset_blinding_key_from_seed, wally_asset_blinding_key_from_seed) +WALLY_FN_B_B(tx_elements_issuance_calculate_asset, wally_tx_elements_issuance_calculate_asset) +WALLY_FN_P(psbt_input_clear_value, wally_psbt_input_clear_value) +WALLY_FN_P(psbt_finalize, wally_psbt_finalize) WALLY_FN_P(tx_elements_input_issuance_free, wally_tx_elements_input_issuance_free) -WALLY_FN_B33BPBBBBBB_A(tx_elements_input_init_alloc, wally_tx_elements_input_init_alloc) -WALLY_FN_PBBBBB(tx_elements_output_commitment_set, wally_tx_elements_output_commitment_set) WALLY_FN_P(tx_elements_output_commitment_free, wally_tx_elements_output_commitment_free) -WALLY_FN_6BBBBBB_A(tx_elements_output_init_alloc, wally_tx_elements_output_init_alloc) +WALLY_FN_P3B_A(confidential_addr_from_addr, wally_confidential_addr_from_addr) +WALLY_FN_P3_A(confidential_addr_to_addr, wally_confidential_addr_to_addr) +WALLY_FN_P3_B(confidential_addr_to_ec_public_key, wally_confidential_addr_to_ec_public_key) +WALLY_FN_P6(psbt_input_set_value, wally_psbt_input_set_value) +WALLY_FN_PB(psbt_input_set_asset, wally_psbt_input_set_asset) +WALLY_FN_PB(psbt_input_set_abf, wally_psbt_input_set_abf) +WALLY_FN_PB(psbt_input_set_claim_script, wally_psbt_input_set_claim_script) +WALLY_FN_PB(psbt_input_set_genesis_blockhash, wally_psbt_input_set_genesis_blockhash) +WALLY_FN_PB(psbt_input_set_txoutproof, wally_psbt_input_set_txoutproof) +WALLY_FN_PB(psbt_input_set_vbf, wally_psbt_input_set_vbf) +WALLY_FN_PB(psbt_output_set_abf, wally_psbt_output_set_abf) +WALLY_FN_PB(psbt_output_set_asset_commitment, wally_psbt_output_set_asset_commitment) +WALLY_FN_PB(psbt_output_set_blinding_pubkey, wally_psbt_output_set_blinding_pubkey) +WALLY_FN_PB(psbt_output_set_nonce, wally_psbt_output_set_nonce) +WALLY_FN_PB(psbt_output_set_rangeproof, wally_psbt_output_set_rangeproof) +WALLY_FN_PB(psbt_output_set_surjectionproof, wally_psbt_output_set_surjectionproof) +WALLY_FN_PB(psbt_output_set_vbf, wally_psbt_output_set_vbf) +WALLY_FN_PB(psbt_output_set_value_commitment, wally_psbt_output_set_value_commitment) WALLY_FN_PB33BPBBBBBB3(tx_add_elements_raw_input, wally_tx_add_elements_raw_input) -WALLY_FN_P6BBBBBB3(tx_add_elements_raw_output, wally_tx_add_elements_raw_output) +WALLY_FN_PB33BPBBBBBBP3(tx_add_elements_raw_input, wally_tx_add_elements_raw_input) +WALLY_FN_PB3P(bip32_key_with_tweak_from_parent_path, bip32_key_with_tweak_from_parent_path) +WALLY_FN_PB3_A(bip32_key_with_tweak_from_parent_path_alloc, bip32_key_with_tweak_from_parent_path_alloc) +WALLY_FN_PBBBBB(tx_elements_output_commitment_set, wally_tx_elements_output_commitment_set) +WALLY_FN_PBBBBBB(tx_elements_input_issuance_set, wally_tx_elements_input_issuance_set) +WALLY_FN_PBBBBBB3(tx_add_elements_raw_output, wally_tx_add_elements_raw_output) +WALLY_FN_PP(psbt_input_set_peg_in_tx, wally_psbt_input_set_peg_in_tx) +WALLY_FN_PPPB_A(confidential_addr_from_addr_segwit, wally_confidential_addr_from_addr_segwit) +WALLY_FN_PPP_A(confidential_addr_to_addr_segwit, wally_confidential_addr_to_addr_segwit) +WALLY_FN_PP_B(confidential_addr_segwit_to_ec_public_key, wally_confidential_addr_segwit_to_ec_public_key) +WALLY_FN_PSBB33_B(tx_get_elements_signature_hash, wally_tx_get_elements_signature_hash) +WALLY_FN_P_S(tx_elements_input_is_pegin, wally_tx_elements_input_is_pegin) WALLY_FN_P_S(tx_is_elements, wally_tx_is_elements) -WALLY_FN_6_B(tx_confidential_value_from_satoshi, wally_tx_confidential_value_from_satoshi) -WALLY_FN_P6BB33_B(tx_get_elements_signature_hash, wally_tx_get_elements_signature_hash) -WALLY_FN_B3B_B(tx_elements_issuance_generate_entropy, wally_tx_elements_issuance_generate_entropy) -WALLY_FN_B_B(tx_elements_issuance_calculate_asset, wally_tx_elements_issuance_calculate_asset) -WALLY_FN_B3_B(tx_elements_issuance_calculate_reissuance_token, wally_tx_elements_issuance_calculate_reissuance_token) +WALLY_FN_SSSS_S(elements_pegout_script_size, wally_elements_pegout_script_size) +WALLY_FN_S_S(asset_pak_whitelistproof_size, wally_asset_pak_whitelistproof_size) +WALLY_FN_S_S(asset_surjectionproof_size, wally_asset_surjectionproof_size) #endif /* BUILD_ELEMENTS */ +#undef WALLYP #undef WALLYB #undef WALLYO diff --git a/include/wally_bip32.h b/include/wally_bip32.h index 7c9e0fe24..875cf4764 100644 --- a/include/wally_bip32.h +++ b/include/wally_bip32.h @@ -12,6 +12,9 @@ extern "C" { #define BIP32_ENTROPY_LEN_256 32 #define BIP32_ENTROPY_LEN_512 64 +/** Length of a BIP32 key fingerprint */ +#define BIP32_KEY_FINGERPRINT_LEN 4 + /** Length of an ext_key serialized using BIP32 format */ #define BIP32_SERIALIZED_LEN 78 @@ -332,7 +335,7 @@ WALLY_CORE_API int bip32_key_strip_private_key( * * :param hdkey: The extended key. * :param bytes_out: Destination for the fingerprint. - * :param len: Size of ``bytes_out`` in bytes. Must be ``FINGERPRINT_LEN``. + * :param len: Size of ``bytes_out`` in bytes. Must be ``BIP32_KEY_FINGERPRINT_LEN``. */ WALLY_CORE_API int bip32_key_get_fingerprint( struct ext_key *hdkey, diff --git a/include/wally_core.h b/include/wally_core.h index e75af8edb..e31d01dc3 100644 --- a/include/wally_core.h +++ b/include/wally_core.h @@ -28,9 +28,6 @@ extern "C" { #define WALLY_EINVAL -2 /** Invalid argument */ #define WALLY_ENOMEM -3 /** malloc() failed */ -/** BIP32 fingerprint length */ -#define FINGERPRINT_LEN 4 - /** * Initialize wally. * @@ -244,9 +241,9 @@ WALLY_CORE_API int wally_set_operations( /** * Determine if the library was built with elements support. * - * :param value_out: 1 if the library supports elements, otherwise 0. + * :param written: 1 if the library supports elements, otherwise 0. */ -WALLY_CORE_API int wally_is_elements_build(uint64_t *value_out); +WALLY_CORE_API int wally_is_elements_build(size_t *written); #ifdef __cplusplus } diff --git a/include/wally_crypto.h b/include/wally_crypto.h index 1a557d95e..cca9c1b72 100644 --- a/include/wally_crypto.h +++ b/include/wally_crypto.h @@ -293,6 +293,8 @@ WALLY_CORE_API int wally_pbkdf2_hmac_sha512( /** Indicates that the signature is recoverable */ #define EC_FLAG_RECOVERABLE 0x8 +/* All defined flags */ +#define EC_FLAGS_ALL (0x1 | 0x2 | 0x4 | 0x8) /** * Verify that a private key is valid. @@ -347,7 +349,7 @@ WALLY_CORE_API int wally_ec_public_key_decompress( * Negates a public key. * * :param pub_key: The public key to negate. - * :param pub_key_len:: The length of ``pub_key`` in bytes. Must be ``EC_PUBLIC_KEY_LEN``. + * :param pub_key_len: The length of ``pub_key`` in bytes. Must be ``EC_PUBLIC_KEY_LEN``. * :param bytes_out: Destination for the resulting public key. * :param len: The length of ``bytes_out`` in bytes. Must be ``EC_PUBLIC_KEY_LEN``. */ @@ -483,30 +485,32 @@ WALLY_CORE_API int wally_ec_sig_to_public_key( * :param len: The length of ``bytes_out`` in bytes. * :param written: Destination for the number of bytes written to ``bytes_out``. */ -WALLY_CORE_API int wally_format_bitcoin_message(const unsigned char *bytes, - size_t bytes_len, - uint32_t flags, - unsigned char *bytes_out, - size_t len, - size_t *written); +WALLY_CORE_API int wally_format_bitcoin_message( + const unsigned char *bytes, + size_t bytes_len, + uint32_t flags, + unsigned char *bytes_out, + size_t len, + size_t *written); /** * * Compute an EC Diffie-Hellman secret in constant time * * :param pub_key: The public key. - * :param pub_key_len: The length of ``pubkey`` in bytes. Must be ``EC_PUBLIC_KEY_LEN``. - * :param bytes: The private key. - * :param bytes_len: The length of ``privkey`` in bytes. Must be ``EC_PRIVATE_KEY_LEN``. - * :param output: Destination for the shared secret. - * :param output_len: The length of ``output`` in bytes. Must be ``SHA256_LEN``. + * :param pub_key_len: The length of ``pub_key`` in bytes. Must be ``EC_PUBLIC_KEY_LEN``. + * :param priv_key: The private key. + * :param priv_key_len: The length of ``priv_key`` in bytes. Must be ``EC_PRIVATE_KEY_LEN``. + * :param bytes_out: Destination for the shared secret. + * :param len: The length of ``bytes_out`` in bytes. Must be ``SHA256_LEN``. */ -WALLY_CORE_API int wally_ecdh(const unsigned char *pub_key, - size_t pub_key_len, - const unsigned char *bytes, - size_t bytes_len, - unsigned char *bytes_out, - size_t len); +WALLY_CORE_API int wally_ecdh( + const unsigned char *pub_key, + size_t pub_key_len, + const unsigned char *priv_key, + size_t priv_key_len, + unsigned char *bytes_out, + size_t len); #ifdef __cplusplus } diff --git a/include/wally_elements.h b/include/wally_elements.h index 229bc1432..bf1674e3f 100644 --- a/include/wally_elements.h +++ b/include/wally_elements.h @@ -25,7 +25,7 @@ extern "C" { * :param asset: Asset Tag to create a blinding generator for. * :param asset_len: Length of ``asset`` in bytes. Must be ``ASSET_TAG_LEN``. * :param abf: Asset Blinding Factor (Random entropy to blind with). - * :param abf_len: Length of ``abf`` in bytes. Must be ``ASSET_TAG_LEN``. + * :param abf_len: Length of ``abf`` in bytes. Must be ``BLINDING_FACTOR_LEN``. * :param bytes_out: Destination for the resulting Asset Generator. * :param len: The length of ``bytes_out`` in bytes. Must be ``ASSET_GENERATOR_LEN``. */ @@ -49,7 +49,7 @@ WALLY_CORE_API int wally_asset_generator_from_bytes( * :param abf_len: Length of ``abf`` in bytes. Must be ``values_len`` * ``BLINDING_FACTOR_LEN``. * :param vbf: Array of bytes representing (``values_len`` - 1) value blinding factors. * :param vbf_len: Length of ``vbf`` in bytes. Must be (``values_len`` - 1) * ``BLINDING_FACTOR_LEN``. - * :param bytes_out: Buffer to received the final value blinding factor. + * :param bytes_out: Buffer to receive the final value blinding factor. * :param len: Length of ``bytes_out``. Must be ``BLINDING_FACTOR_LEN``. */ WALLY_CORE_API int wally_asset_final_vbf( @@ -72,7 +72,7 @@ WALLY_CORE_API int wally_asset_final_vbf( * :param generator: Asset generator from `wally_asset_generator_from_bytes`. * :param generator_len: Length of ``generator``. Must be ``ASSET_GENERATOR_LEN``. * :param bytes_out: Buffer to receive value commitment. - * :param len: Length of ``bytes_out``. Must be ``ASSET_GENERATOR_LEN``. + * :param len: Length of ``bytes_out``. Must be ``ASSET_COMMITMENT_LEN``. */ WALLY_CORE_API int wally_asset_value_commitment( uint64_t value, @@ -209,6 +209,27 @@ WALLY_CORE_API int wally_asset_surjectionproof( size_t len, size_t *written); +/** + * Unblind a confidential transaction output. + * + * :param nonce_hash: SHA-256 hash of the generated nonce. + * :param nonce_hash_len: Length of ``nonce_hash``. Must be ``SHA256_LEN``. + * :param proof: Rangeproof from :c:func:`wally_tx_get_output_rangeproof`. + * :param proof_len: Length of ``proof``. + * :param commitment: Value commitment from :c:func:`wally_tx_get_output_value`. + * :param commitment_len: Length of ``commitment``. + * :param extra: Script pubkey from :c:func:`wally_tx_get_output_script`. + * :param extra_len: Length of ``extra``. + * :param generator: Asset generator from :c:func:`wally_tx_get_output_asset`. + * :param generator_len: Length of ``generator``. Must be ``ASSET_GENERATOR_LEN``. + * :param asset_out: Buffer to receive unblinded asset id. + * :param asset_out_len: Length of ``asset_out``. Must be ``ASSET_TAG_LEN``. + * :param abf_out: Buffer to receive asset blinding factor. + * :param abf_out_len: Length of ``abf_out``. Must be ``BLINDING_FACTOR_LEN``. + * :param vbf_out: Buffer to receive asset blinding factor. + * :param vbf_out_len: Length of ``vbf_out``. Must be ``BLINDING_FACTOR_LEN``. + * :param value_out: Destination for unblinded transaction output value. + */ WALLY_CORE_API int wally_asset_unblind_with_nonce( const unsigned char *nonce_hash, size_t nonce_hash_len, diff --git a/include/wally_psbt.h b/include/wally_psbt.h index 1743c72f3..176725a2b 100644 --- a/include/wally_psbt.h +++ b/include/wally_psbt.h @@ -2,7 +2,7 @@ #define LIBWALLY_CORE_PSBT_H #include "wally_transaction.h" -#include "wally_core.h" +#include "wally_bip32.h" #ifdef __cplusplus extern "C" { @@ -10,7 +10,11 @@ extern "C" { #define WALLY_PSBT_SEPARATOR 0x00 +/* The proprietary type is the same for all scopes */ +#define WALLY_PSBT_PROPRIETARY_TYPE 0xFC + #define WALLY_PSBT_GLOBAL_UNSIGNED_TX 0x00 +#define WALLY_PSBT_GLOBAL_VERSION 0xFB #define WALLY_PSBT_IN_NON_WITNESS_UTXO 0x00 #define WALLY_PSBT_IN_WITNESS_UTXO 0x01 @@ -22,12 +26,36 @@ extern "C" { #define WALLY_PSBT_IN_FINAL_SCRIPTSIG 0x07 #define WALLY_PSBT_IN_FINAL_SCRIPTWITNESS 0x08 +#ifdef BUILD_ELEMENTS +#define WALLY_PSBT_IN_ELEMENTS_VALUE 0x00 +#define WALLY_PSBT_IN_ELEMENTS_VALUE_BLINDER 0x01 +#define WALLY_PSBT_IN_ELEMENTS_ASSET 0x02 +#define WALLY_PSBT_IN_ELEMENTS_ASSET_BLINDER 0x03 +#define WALLY_PSBT_IN_ELEMENTS_PEG_IN_TX 0x04 +#define WALLY_PSBT_IN_ELEMENTS_TXOUT_PROOF 0x05 +#define WALLY_PSBT_IN_ELEMENTS_GENESIS_HASH 0x06 +#define WALLY_PSBT_IN_ELEMENTS_CLAIM_SCRIPT 0x07 +#endif /* BUILD ELEMENTS */ + #define WALLY_PSBT_OUT_REDEEM_SCRIPT 0x00 #define WALLY_PSBT_OUT_WITNESS_SCRIPT 0x01 #define WALLY_PSBT_OUT_BIP32_DERIVATION 0x02 +#ifdef BUILD_ELEMENTS +#define WALLY_PSBT_OUT_ELEMENTS_VALUE_COMMITMENT 0x00 +#define WALLY_PSBT_OUT_ELEMENTS_VALUE_BLINDER 0x01 +#define WALLY_PSBT_OUT_ELEMENTS_ASSET_COMMITMENT 0x02 +#define WALLY_PSBT_OUT_ELEMENTS_ASSET_BLINDER 0x03 +#define WALLY_PSBT_OUT_ELEMENTS_RANGE_PROOF 0x04 +#define WALLY_PSBT_OUT_ELEMENTS_SURJECTION_PROOF 0x05 +#define WALLY_PSBT_OUT_ELEMENTS_BLINDING_PUBKEY 0x06 +#define WALLY_PSBT_OUT_ELEMENTS_NONCE_COMMITMENT 0x07 +#endif /* BUILD ELEMENTS */ + +/* PSBT Version number */ +#define WALLY_PSBT_HIGHEST_VERSION 0 + #ifdef SWIG -struct wally_key_origin_info; struct wally_keypath_map; struct wally_partial_sigs_map; struct wally_unknowns_map; @@ -36,17 +64,12 @@ struct wally_psbt_output; struct wally_psbt; #else -/** Key origin data. Contains a BIP 32 fingerprint and the derivation path */ -struct wally_key_origin_info { - unsigned char fingerprint[FINGERPRINT_LEN]; +/** A BIP 32 path and fingerprint with associated public key */ +struct wally_keypath_item { uint32_t *path; size_t path_len; -}; - -/** Item in keypath map */ -struct wally_keypath_item { + unsigned char fingerprint[BIP32_KEY_FINGERPRINT_LEN]; unsigned char pubkey[EC_PUBLIC_KEY_UNCOMPRESSED_LEN]; - struct wally_key_origin_info origin; }; /** A map of public keys to BIP 32 fingerprint and derivation paths */ @@ -56,14 +79,14 @@ struct wally_keypath_map { size_t items_allocation_len; }; -/** Item in partial signatures map */ +/** A signature with associated public key */ struct wally_partial_sigs_item { unsigned char pubkey[EC_PUBLIC_KEY_UNCOMPRESSED_LEN]; unsigned char *sig; size_t sig_len; }; -/** A map of public key's to signatures */ +/** A map of public keys to signatures */ struct wally_partial_sigs_map { struct wally_partial_sigs_item *items; size_t num_items; @@ -78,14 +101,14 @@ struct wally_unknowns_item { size_t value_len; }; -/** Unknown items map */ +/** A map of unknown key,value pairs */ struct wally_unknowns_map { struct wally_unknowns_item *items; size_t num_items; size_t items_allocation_len; }; -/** A psbt input map */ +/** A PSBT input */ struct wally_psbt_input { struct wally_tx *non_witness_utxo; struct wally_tx_output *witness_utxo; @@ -100,9 +123,26 @@ struct wally_psbt_input { struct wally_partial_sigs_map *partial_sigs; struct wally_unknowns_map *unknowns; uint32_t sighash_type; +#ifdef BUILD_ELEMENTS + uint64_t value; + uint32_t has_value; + unsigned char *vbf; + size_t vbf_len; + unsigned char *asset; + size_t asset_len; + unsigned char *abf; + size_t abf_len; + struct wally_tx *peg_in_tx; + unsigned char *txoutproof; + size_t txoutproof_len; + unsigned char *genesis_blockhash; + size_t genesis_blockhash_len; + unsigned char *claim_script; + size_t claim_script_len; +#endif /* BUILD_ELEMENTS */ }; -/** A psbt output map */ +/** A PSBT output */ struct wally_psbt_output { unsigned char *redeem_script; size_t redeem_script_len; @@ -110,10 +150,29 @@ struct wally_psbt_output { size_t witness_script_len; struct wally_keypath_map *keypaths; struct wally_unknowns_map *unknowns; +#ifdef BUILD_ELEMENTS + unsigned char *blinding_pubkey; + size_t blinding_pubkey_len; + unsigned char *value_commitment; + size_t value_commitment_len; + unsigned char *vbf; + size_t vbf_len; + unsigned char *asset_commitment; + size_t asset_commitment_len; + unsigned char *abf; + size_t abf_len; + unsigned char *nonce; + size_t nonce_len; + unsigned char *rangeproof; + size_t rangeproof_len; + unsigned char *surjectionproof; + size_t surjectionproof_len; +#endif /* BUILD_ELEMENTS */ }; /** A partially signed bitcoin transaction */ struct wally_psbt { + unsigned char magic[5]; struct wally_tx *tx; struct wally_psbt_input *inputs; size_t num_inputs; @@ -122,16 +181,19 @@ struct wally_psbt { size_t num_outputs; size_t outputs_allocation_len; struct wally_unknowns_map *unknowns; + uint32_t version; }; #endif /* SWIG */ /** * Allocate and initialize a new keypath map. * - * :param alloc_len: The number of items to allocate. - * :param output: Destination for the new keypath map + * :param allocation_len: The number of items to allocate. + * :param output: Destination for the new keypath map. */ -WALLY_CORE_API int wally_keypath_map_init_alloc(size_t alloc_len, struct wally_keypath_map **output); +WALLY_CORE_API int wally_keypath_map_init_alloc( + size_t allocation_len, + struct wally_keypath_map **output); #ifndef SWIG_PYTHON /** @@ -139,35 +201,55 @@ WALLY_CORE_API int wally_keypath_map_init_alloc(size_t alloc_len, struct wally_k * * :param keypaths: The keypath map to free. */ -WALLY_CORE_API int wally_keypath_map_free(struct wally_keypath_map *keypaths); +WALLY_CORE_API int wally_keypath_map_free( + struct wally_keypath_map *keypaths); #endif /* SWIG_PYTHON */ + /** - * Add an item to a keypath map + * Find an item in a keypath map. * - * :param keypaths: The keypath map to add to - * :param pubkey: The pubkey to add - * :param pubkey_len: The length of the pubkey. Must be ``EC_PUBLIC_KEY_UNCOMPRESSED_LEN`` or ``EC_PUBLIC_KEY_LEN`` - * :param fingerprint: The master key fingerprint for the pubkey - * :param fingerprint_len: The length of the fingerprint. Must be ``FINGERPRINT_LEN`` - * :param path: The BIP32 derivation path for the pubkey - * :param path_len: The number of items in path + * :param keypaths: The keypath map to find ``pub_key`` in. + * :param pub_key: The pubkey to find. + * :param pub_key_len: Length of ``pub_key`` in bytes. Must be ``EC_PUBLIC_KEY_UNCOMPRESSED_LEN`` or ``EC_PUBLIC_KEY_LEN``. + * :param written: On success, set to zero if the item is not found, otherwise + *| the index of the item plus one. */ -WALLY_CORE_API int wally_add_new_keypath(struct wally_keypath_map *keypaths, - unsigned char *pubkey, - size_t pubkey_len, - unsigned char *fingerprint, - size_t fingerprint_len, - uint32_t *path, - size_t path_len); +WALLY_CORE_API int wally_keypath_map_find( + const struct wally_keypath_map *keypaths, + const unsigned char *pub_key, + size_t pub_key_len, + size_t *written); + +/** + * Add an item to a keypath map. + * + * :param keypaths: The keypath map to add to. + * :param pub_key: The pubkey to add. + * :param pub_key_len: Length of ``pub_key`` in bytes. Must be ``EC_PUBLIC_KEY_UNCOMPRESSED_LEN`` or ``EC_PUBLIC_KEY_LEN``. + * :param fingerprint: The master key fingerprint for the pubkey. + * :param fingerprint_len: Length of ``fingerprint`` in bytes. Must be ``BIP32_KEY_FINGERPRINT_LEN``. + * :param child_path: The BIP32 derivation path for the pubkey. + * :param child_path_len: The number of items in ``child_path``. + */ +WALLY_CORE_API int wally_keypath_map_add( + struct wally_keypath_map *keypaths, + const unsigned char *pub_key, + size_t pub_key_len, + const unsigned char *fingerprint, + size_t fingerprint_len, + const uint32_t *child_path, + size_t child_path_len); /** * Allocate and initialize a new partial sigs map. * - * :param alloc_len: The number of items to allocate. - * :param output: Destination for the new partial sigs map + * :param allocation_len: The number of items to allocate. + * :param output: Destination for the new partial sigs map. */ -WALLY_CORE_API int wally_partial_sigs_map_init_alloc(size_t alloc_len, struct wally_partial_sigs_map **output); +WALLY_CORE_API int wally_partial_sigs_map_init_alloc( + size_t allocation_len, + struct wally_partial_sigs_map **output); #ifndef SWIG_PYTHON /** @@ -175,287 +257,255 @@ WALLY_CORE_API int wally_partial_sigs_map_init_alloc(size_t alloc_len, struct wa * * :param sigs: The partial sigs map to free. */ -WALLY_CORE_API int wally_partial_sigs_map_free(struct wally_partial_sigs_map *sigs); +WALLY_CORE_API int wally_partial_sigs_map_free( + struct wally_partial_sigs_map *sigs); #endif /* SWIG_PYTHON */ /** - * Add an item to a partial sigs map + * Find an item in a partial sigs map. * - * :param sigs: The partial sigs map to add to - * :param pubkey: The pubkey to add - * :param pubkey_len: Length of the public key. Must be ``EC_PUBLIC_KEY_LEN`` or ``EC_PUBLIC_KEY_UNCOMPRESSED_LEN`` - * :param sig: The signature to add - * :param sig_len: The length of sig + * :param sigs: The partial sigs map to find ``pub_key`` in. + * :param pub_key: The pubkey to find. + * :param pub_key_len: Length of ``pub_key`` in bytes. Must be ``EC_PUBLIC_KEY_UNCOMPRESSED_LEN`` or ``EC_PUBLIC_KEY_LEN``. + * :param written: On success, set to zero if the item is not found, otherwise + *| the index of the item plus one. */ -WALLY_CORE_API int wally_add_new_partial_sig(struct wally_partial_sigs_map *sigs, - unsigned char *pubkey, - size_t pubkey_len, - unsigned char *sig, - size_t sig_len); +WALLY_CORE_API int wally_partial_sigs_map_find( + const struct wally_partial_sigs_map *sigs, + const unsigned char *pub_key, + size_t pub_key_len, + size_t *written); /** - * Allocate and initialize a new unknowns map + * Add an item to a partial sigs map. * - * :param alloc_len: The number of items to allocate. - * :param output: Destination for the new unknowns map + * :param sigs: The partial sigs map to add to. + * :param pub_key: The pubkey to add. + * :param pub_key_len: Length of ``pub_key`` in bytes. Must be ``EC_PUBLIC_KEY_LEN`` or ``EC_PUBLIC_KEY_UNCOMPRESSED_LEN`` + * :param sig: The DER-encoded signature to add. + * :param sig_len: Length of ``sig`` in bytes. */ -WALLY_CORE_API int wally_unknowns_map_init_alloc(size_t alloc_len, struct wally_unknowns_map **output); +WALLY_CORE_API int wally_partial_sigs_map_add( + struct wally_partial_sigs_map *sigs, + const unsigned char *pub_key, + size_t pub_key_len, + const unsigned char *sig, + size_t sig_len); + +/** + * Allocate and initialize a new unknowns map. + * + * :param allocation_len: The number of items to allocate. + * :param output: Destination for the new unknowns map. + */ +WALLY_CORE_API int wally_unknowns_map_init_alloc( + size_t allocation_len, + struct wally_unknowns_map **output); #ifndef SWIG_PYTHON /** * Free an unknowns map allocated by `wally_unknowns_map_init_alloc`. * - * :param unknowns: The unknowns map map to free. + * :param unknowns: The unknowns map to free. */ -WALLY_CORE_API int wally_unknowns_map_free(struct wally_unknowns_map *unknowns); +WALLY_CORE_API int wally_unknowns_map_free( + struct wally_unknowns_map *unknowns); #endif /* SWIG_PYTHON */ /** - * Add an item to an unknowns map + * Find an item in an unknowns map. * - * :param unknowns: The unknowns map to add to - * :param key: The key to add - * :param key_len: The length of the key - * :param value: The value to add - * :param value_len: The length of value + * :param unknowns: The unknowns map to find ``key`` in. + * :param key: The key to find. + * :param key_len: Length of ``key`` in bytes. + * :param written: On success, set to zero if the item is not found, otherwise + *| the index of the item plus one. */ -WALLY_CORE_API int wally_add_new_unknown(struct wally_unknowns_map *unknowns, - unsigned char *key, - size_t key_len, - unsigned char *value, - size_t value_len); +WALLY_CORE_API int wally_unknowns_map_find( + const struct wally_unknowns_map *unknowns, + const unsigned char *key, + size_t key_len, + size_t *written); /** - * Allocate and initialize a new psbt input. + * Add an item to an unknowns map. * - * :param non_witness_utxo: The non witness utxo for this input if it exists. - * :param witness_utxo: The witness utxo for this input if it exists. - * :param redeem_script: The redeem script for this input - * :param redeem_script_len: The length of the redeem script. - * :param witness_script: The witness script for this input - * :param witness_script_len: The length of the witness script. - * :param final_script_sig: The scriptSig for this input - * :param final_script_sig_len: Size of ``final_script_sig`` in bytes. - * :param final_witness: The witness stack for the input, or NULL if no witness is present. - * :param keypaths: The HD keypaths for this input. - * :param partial_sigs: The partial signatures for this input. - * :param unknowns: The unknown key value pairs for this input. - * :param sighash_type: The sighash type for this input - * :param output: Destination for the resulting psbt input. - */ -WALLY_CORE_API int wally_psbt_input_init_alloc( - struct wally_tx *non_witness_utxo, - struct wally_tx_output *witness_utxo, - unsigned char *redeem_script, - size_t redeem_script_len, - unsigned char *witness_script, - size_t witness_script_len, - unsigned char *final_script_sig, - size_t final_script_sig_len, - struct wally_tx_witness_stack *final_witness, - struct wally_keypath_map *keypaths, - struct wally_partial_sigs_map *partial_sigs, + * :param unknowns: The unknowns map to add to. + * :param key: The key to add. + * :param key_len: Length of ``key`` in bytes. + * :param value: The value to add. + * :param value_len: Length of ``value`` in bytes. + */ +WALLY_CORE_API int wally_unknowns_map_add( struct wally_unknowns_map *unknowns, - uint32_t sighash_type, - struct wally_psbt_input **output); + const unsigned char *key, + size_t key_len, + const unsigned char *value, + size_t value_len); +#ifndef SWIG /** - * Set the non_witness_utxo in an input + * Set the non_witness_utxo in an input. * * :param input: The input to update. * :param non_witness_utxo: The non witness utxo for this input if it exists. */ WALLY_CORE_API int wally_psbt_input_set_non_witness_utxo( struct wally_psbt_input *input, - struct wally_tx *non_witness_utxo); + const struct wally_tx *non_witness_utxo); /** - * Set the witness_utxo in an input + * Set the witness_utxo in an input. * * :param input: The input to update. * :param witness_utxo: The witness utxo for this input if it exists. */ WALLY_CORE_API int wally_psbt_input_set_witness_utxo( struct wally_psbt_input *input, - struct wally_tx_output *witness_utxo); + const struct wally_tx_output *witness_utxo); /** - * Set the redeem_script in an input + * Set the redeem_script in an input. * * :param input: The input to update. - * :param redeem_script: The redeem script for this input - * :param redeem_script_len: The length of the redeem script. + * :param script: The redeem script for this input. + * :param script_len: Length of ``script`` in bytes. */ WALLY_CORE_API int wally_psbt_input_set_redeem_script( struct wally_psbt_input *input, - unsigned char *redeem_script, - size_t redeem_script_len); + const unsigned char *script, + size_t script_len); /** - * Set the witness_script in an input + * Set the witness_script in an input. * * :param input: The input to update. - * :param witness_script: The witness script for this input - * :param witness_script_len: The length of the witness script. + * :param script: The witness script for this input. + * :param script_len: Length of ``script`` in bytes. */ WALLY_CORE_API int wally_psbt_input_set_witness_script( struct wally_psbt_input *input, - unsigned char *witness_script, - size_t witness_script_len); + const unsigned char *script, + size_t script_len); /** - * Set the final_script_sig in an input + * Set the final_script_sig in an input. * * :param input: The input to update. - * :param final_script_sig: The scriptSig for this input - * :param final_script_sig_len: Size of ``final_script_sig`` in bytes. + * :param final_script_sig: The scriptSig for this input. + * :param final_script_sig_len: Length of ``final_script_sig`` in bytes. */ WALLY_CORE_API int wally_psbt_input_set_final_script_sig( struct wally_psbt_input *input, - unsigned char *final_script_sig, + const unsigned char *final_script_sig, size_t final_script_sig_len); /** - * Set the final_witness in an input + * Set the final_witness in an input. * * :param input: The input to update. * :param final_witness: The witness stack for the input, or NULL if no witness is present. */ WALLY_CORE_API int wally_psbt_input_set_final_witness( struct wally_psbt_input *input, - struct wally_tx_witness_stack *final_witness); + const struct wally_tx_witness_stack *final_witness); /** - * Set the keypaths in an input + * Set the keypaths in an input. * * :param input: The input to update. * :param keypaths: The HD keypaths for this input. */ WALLY_CORE_API int wally_psbt_input_set_keypaths( struct wally_psbt_input *input, - struct wally_keypath_map *keypaths); + const struct wally_keypath_map *keypaths); /** - * Set the partial_sigs in an input + * Set the partial_sigs in an input. * * :param input: The input to update. * :param partial_sigs: The partial signatures for this input. */ WALLY_CORE_API int wally_psbt_input_set_partial_sigs( struct wally_psbt_input *input, - struct wally_partial_sigs_map *partial_sigs); + const struct wally_partial_sigs_map *partial_sigs); /** - * Set the partial_sigs in an input + * Set the partial_sigs in an input. * * :param input: The input to update. * :param unknowns: The unknown key value pairs for this input. */ WALLY_CORE_API int wally_psbt_input_set_unknowns( struct wally_psbt_input *input, - struct wally_unknowns_map *unknowns); + const struct wally_unknowns_map *unknowns); /** - * Set the partial_sigs in an input + * Set the partial_sigs in an input. * * :param input: The input to update. - * :param sighash_type: The sighash type for this input + * :param sighash_type: The sighash type for this input. */ WALLY_CORE_API int wally_psbt_input_set_sighash_type( struct wally_psbt_input *input, uint32_t sighash_type); -#ifndef SWIG_PYTHON /** - * Free a psbt input allocated by `wally_psbt_input_init_alloc`. - * - * :param input: The psbt input to free. - */ -WALLY_CORE_API int wally_psbt_input_free(struct wally_psbt_input *input); -#endif /* SWIG_PYTHON */ - -/** - * Allocate and initialize a new psbt output. - * - * :param redeem_script: The redeem script needed for spending this output - * :param redeem_script_len: The length of the redeem script. - * :param witness_script: The witness script needed for spending for this output - * :param witness_script_len: The length of the witness script. - * :param keypaths: The HD keypaths for the keys needed for spending this output - * :param unknowns: The unknown key value pairs for this output. - * :param output: Destination for the resulting psbt output. - */ -WALLY_CORE_API int wally_psbt_output_init_alloc( - unsigned char *redeem_script, - size_t redeem_script_len, - unsigned char *witness_script, - size_t witness_script_len, - struct wally_keypath_map *keypaths, - struct wally_unknowns_map *unknowns, - struct wally_psbt_output **output); - -/** - * Set the redeem_script in an output + * Set the redeem_script in an output. * * :param output: The input to update. - * :param redeem_script: The redeem script for this output - * :param redeem_script_len: The length of the redeem script. + * :param script: The redeem script for this output. + * :param script_len: Length of ``script`` in bytes. */ WALLY_CORE_API int wally_psbt_output_set_redeem_script( struct wally_psbt_output *output, - unsigned char *redeem_script, - size_t redeem_script_len); + const unsigned char *script, + size_t script_len); /** - * Set the witness_script in an output + * Set the witness_script in an output. * * :param output: The output to update. - * :param witness_script: The witness script for this output - * :param witness_script_len: The length of the witness script. + * :param script: The witness script for this output. + * :param script_len: Length of ``script`` in bytes. */ WALLY_CORE_API int wally_psbt_output_set_witness_script( struct wally_psbt_output *output, - unsigned char *witness_script, - size_t witness_script_len); + const unsigned char *script, + size_t script_len); /** - * Set the keypaths in an output + * Set the keypaths in an output. * * :param output: The output to update. * :param keypaths: The HD keypaths for this output. */ WALLY_CORE_API int wally_psbt_output_set_keypaths( struct wally_psbt_output *output, - struct wally_keypath_map *keypaths); + const struct wally_keypath_map *keypaths); /** - * Set the partial_sigs in an output + * Set the partial_sigs in an output. * * :param output: The output to update. * :param unknowns: The unknown key value pairs for this output. */ WALLY_CORE_API int wally_psbt_output_set_unknowns( struct wally_psbt_output *output, - struct wally_unknowns_map *unknowns); - -#ifndef SWIG_PYTHON -/** - * Free a psbt output allocated by `wally_psbt_output_init_alloc`. - * - * :param output: The psbt output to free. - */ -WALLY_CORE_API int wally_psbt_output_free(struct wally_psbt_output *output); -#endif /* SWIG_PYTHON */ + const struct wally_unknowns_map *unknowns); +#endif /* SWIG */ /** - * Allocate and initialize a new psbt. + * Allocate and initialize a new PSBT. * + * :param version: The version of the PSBT. Must be 0. * :param inputs_allocation_len: The number of inputs to pre-allocate space for. * :param outputs_allocation_len: The number of outputs to pre-allocate space for. * :param global_unknowns_allocation_len: The number of global unknowns to allocate space for. - * :param output: Destination for the resulting psbt output. + * :param output: Destination for the resulting PSBT output. */ WALLY_CORE_API int wally_psbt_init_alloc( + uint32_t version, size_t inputs_allocation_len, size_t outputs_allocation_len, size_t global_unknowns_allocation_len, @@ -463,121 +513,362 @@ WALLY_CORE_API int wally_psbt_init_alloc( #ifndef SWIG_PYTHON /** - * Free a psbt allocated by `wally_psbt_init_alloc`. + * Free a PSBT allocated by `wally_psbt_init_alloc`. * - * :param psbt: The psbt to free. + * :param psbt: The PSBT to free. */ -WALLY_CORE_API int wally_psbt_free(struct wally_psbt *psbt); +WALLY_CORE_API int wally_psbt_free( + struct wally_psbt *psbt); #endif /* SWIG_PYTHON */ /** - * Set the global transaction for a psbt. - * Also initializes all of the wally_psbt_input and wally_psbt_outputs necessary + * Set the global transaction for a PSBT. * + * :param psbt: The PSBT to set the transaction for. * :param tx: The transaction to set. - * :param psbt: The psbt to set the transaction for + * + * The global transaction can only be set on a newly created PSBT. After this + * call completes the PSBT will have empty inputs and outputs for each input + * and output in the transaction ``tx`` given. */ WALLY_CORE_API int wally_psbt_set_global_tx( struct wally_psbt *psbt, - struct wally_tx *tx); + const struct wally_tx *tx); /** - * Create a psbt from its serialized bytes. + * Create a PSBT from its serialized bytes. * - * :param bytes: Bytes to create the psbt from. - * :param bytes_len: Length of ``bytes`` in bytes. - * :param output: Destination for the resulting psbt. + * :param bytes: Bytes to create the PSBT from. + * :param len: Length of ``bytes`` in bytes. + * :param output: Destination for the resulting PSBT. */ WALLY_CORE_API int wally_psbt_from_bytes( const unsigned char *bytes, - size_t bytes_len, + size_t len, struct wally_psbt **output); /** - * Get length of psbt when serialized to bytes. + * Get the length of a PSBT when serialized to bytes. * * :param psbt: the PSBT. - * :param len: Length in bytes when serialized. + * :param flags: Flags controlling length determination. Must be 0. + * :param written: Destination for the length in bytes when serialized. */ WALLY_CORE_API int wally_psbt_get_length( const struct wally_psbt *psbt, - size_t *len); + uint32_t flags, + size_t *written); /** - * Serialize a psbt to bytes. + * Serialize a PSBT to bytes. * * :param psbt: the PSBT to serialize. + * :param flags: Flags controlling serialization. Must be 0. * :param bytes_out: Bytes to create the transaction from. - * :param bytes_len: Length of ``bytes`` in bytes (use `wally_psbt_get_length`). - * :param bytes_written: number of bytes written to bytes_out + * :param len: Length of ``bytes`` in bytes (use `wally_psbt_get_length`). + * :param written: number of bytes written to bytes_out. */ WALLY_CORE_API int wally_psbt_to_bytes( const struct wally_psbt *psbt, - unsigned char *bytes_out, size_t bytes_len, - size_t *bytes_written); + uint32_t flags, + unsigned char *bytes_out, + size_t len, + size_t *written); /** - * Create a psbt from the base64 string. + * Create a PSBT from its serialized base64 string. * - * :param string: Base64 string to create the psbt from. - * :param output: Destination for the resulting psbt. + * :param base64: Base64 string to create the PSBT from. + * :param output: Destination for the resulting PSBT. */ WALLY_CORE_API int wally_psbt_from_base64( - const char *string, + const char *base64, struct wally_psbt **output); /** - * Create a base64 string for a psbt + * Serialize a PSBT to a base64 string. * * :param psbt: the PSBT to serialize. - * :param output: Destination for the resulting psbt. + * :param flags: Flags controlling serialization. Must be 0. + * :param output: Destination for the resulting serialized PSBT. */ WALLY_CORE_API int wally_psbt_to_base64( - struct wally_psbt *psbt, + const struct wally_psbt *psbt, + uint32_t flags, char **output); /** - * Combine the metadata from multiple PSBTs into one + * Combine the metadata from a source PSBT into another PSBT. * - * :param psbts: Array of PSBTs to combine - * :param psbts_len: Number of PSBTs in psbts - * :param output: Destination for resulting psbt + * :param psbt: the PSBT to combine into. + * :param source: the PSBT to copy data from. */ -WALLY_CORE_API int wally_combine_psbts( - const struct wally_psbt *psbts, - size_t psbts_len, - struct wally_psbt **output); +WALLY_CORE_API int wally_psbt_combine( + struct wally_psbt *psbt, + const struct wally_psbt *src); /** - * Sign a PSBT using the simple signer algorithm: https://github.com/bitcoin/bips/blob/master/bip-0174.mediawiki#simple-signer-algorithm + * Sign a PSBT using the simple signer algorithm. + * + * :param psbt: PSBT to sign. Directly modifies this PSBT. + * :param key: Private key to sign PSBT with. + * :param key_len: Length of key in bytes. Must be ``EC_PRIVATE_KEY_LEN``. + * :param flags: Flags controlling sigining. Must be 0 or EC_FLAG_GRIND_R. * - * :param psbt: PSBT to sign. Directly modifies this PSBT - * :param key: Private key to sign PSBT with - * :param key_len: Length of key in bytes. Must be ``EC_PRIVATE_KEY_LEN`` + * .. note:: See https://github.com/bitcoin/bips/blob/master/bip-0174.mediawiki#simple-signer-algorithm + *| for a description of the simple signer algorithm. */ -WALLY_CORE_API int wally_sign_psbt( +WALLY_CORE_API int wally_psbt_sign( struct wally_psbt *psbt, const unsigned char *key, - size_t key_len); + size_t key_len, + uint32_t flags); /** - * Finalize a PSBT + * Finalize a PSBT. * - * :param psbt: PSBT to finalize. Directly modifies this PSBT + * :param psbt: PSBT to finalize. Directly modifies this PSBT. */ -WALLY_CORE_API int wally_finalize_psbt( +WALLY_CORE_API int wally_psbt_finalize( struct wally_psbt *psbt); /** - * Convert a finalized PSBT to a network transaction, i.e. extract + * Extract a network transaction from a finalized PSBT. * - * :param psbt: PSBT to extract. Directly modifies this PSBT - * :param output: Resulting transaction + * :param psbt: PSBT to extract from. + * :param output: Destination for the resulting transaction. */ -WALLY_CORE_API int wally_extract_psbt( - struct wally_psbt *psbt, +WALLY_CORE_API int wally_psbt_extract( + const struct wally_psbt *psbt, struct wally_tx **output); +/** + * Determine if a PSBT is an elements PSBT. + * + * :param psbt: The PSBT to check. + * :param written: 1 if the PSBT is an elements PSBT, otherwise 0. + */ +WALLY_CORE_API int wally_psbt_is_elements( + const struct wally_psbt *psbt, + size_t *written); + +#ifdef BUILD_ELEMENTS +/** + * Allocate and initialize a new elements PSBT. + * + * :param version: The version of the PSBT. Must be 0. + * :param inputs_allocation_len: The number of inputs to pre-allocate space for. + * :param outputs_allocation_len: The number of outputs to pre-allocate space for. + * :param global_unknowns_allocation_len: The number of global unknowns to allocate space for. + * :param output: Destination for the resulting PSBT output. + */ +WALLY_CORE_API int wally_psbt_elements_init_alloc( + uint32_t version, + size_t inputs_allocation_len, + size_t outputs_allocation_len, + size_t global_unknowns_allocation_len, + struct wally_psbt **output); + +#ifndef SWIG +/** + * Set the value in an elements input. + * + * :param input: The input to update. + * :param value: The value for this input. + */ +WALLY_CORE_API int wally_psbt_input_set_value( + struct wally_psbt_input *input, + uint64_t value); + +/** + * Clear the value in an elements input. + * + * :param input: The input to update. + */ +WALLY_CORE_API int wally_psbt_input_clear_value( + struct wally_psbt_input *input); + +/** + * Set the value blinding factor in an elements input. + * + * :param input: The input to update. + * :param vbf: The value blinding factor. + * :param vbf_len: Length of ``vbf``. Must be ``BLINDING_FACTOR_LEN``. + */ +WALLY_CORE_API int wally_psbt_input_set_vbf( + struct wally_psbt_input *input, + const unsigned char *vbf, + size_t vbf_len); + +/** + * Set the asset in an elements input. + * + * :param input: The input to update. + * :param asset: The asset for this input. + * :param asset_len: Length of ``asset`` in bytes. + */ +WALLY_CORE_API int wally_psbt_input_set_asset( + struct wally_psbt_input *input, + const unsigned char *asset, + size_t asset_len); + +/** + * Set the asset blinding factor in an elements input + * + * :param input: The input to update. + * :param abf: The asset blinding factor. + * :param abf_len: Length of ``abf`` in bytes. Must be ``BLINDING_FACTOR_LEN``. + */ +WALLY_CORE_API int wally_psbt_input_set_abf( + struct wally_psbt_input *input, + const unsigned char *abf, + size_t abf_len); + +/** + * Set the peg in tx in an input. + * + * :param input: The input to update. + * :param peg_in_tx: The peg in tx for this input if it exists. + */ +WALLY_CORE_API int wally_psbt_input_set_peg_in_tx( + struct wally_psbt_input *input, + const struct wally_tx *peg_in_tx); + +/** + * Set the txout proof in an elements input. + * + * :param input: The input to update. + * :param proof: The txout proof for this input. + * :param proof_len: Length of ``proof`` in bytes. + */ +WALLY_CORE_API int wally_psbt_input_set_txoutproof( + struct wally_psbt_input *input, + const unsigned char *proof, + size_t proof_len); + +/** + * Set the genesis hash in an elements input. + * + * :param input: The input to update. + * :param genesis_blockhash: The genesis hash for this input. + * :param genesis_blockhash_len: Length of ``genesis_blockhash`` in bytes. Must be ``SHA256_LEN``. + */ +WALLY_CORE_API int wally_psbt_input_set_genesis_blockhash( + struct wally_psbt_input *input, + const unsigned char *genesis_blockhash, + size_t genesis_blockhash_len); + +/** + * Set the claim script in an elements input. + * + * :param input: The input to update. + * :param script: The claim script for this input. + * :param script_len: Length of ``script`` in bytes. + */ +WALLY_CORE_API int wally_psbt_input_set_claim_script( + struct wally_psbt_input *input, + const unsigned char *script, + size_t script_len); + +/** + * Set the blinding pubkey in an elements output. + * + * :param output: The output to update. + * :param pub_key: The blinding pubkey for this output. + * :param pub_key_len: Length of ``pub_key`` in bytes. + */ +WALLY_CORE_API int wally_psbt_output_set_blinding_pubkey( + struct wally_psbt_output *output, + const unsigned char *pub_key, + size_t pub_key_len); + +/** + * Set the value commitment in an elements output. + * + * :param output: The output to update. + * :param commitment: The value commitment for this output. + * :param commitment_len: Length of ``commitment`` in bytes. + */ +WALLY_CORE_API int wally_psbt_output_set_value_commitment( + struct wally_psbt_output *output, + const unsigned char *commitment, + size_t commitment_len); + +/** + * Set the value blinding factor in an elements output. + * + * :param output: The output to update. + * :param vbf: The value blinding factor. + * :param vbf_len: Length of ``vbf``. Must be ``BLINDING_FACTOR_LEN``. + */ +WALLY_CORE_API int wally_psbt_output_set_vbf( + struct wally_psbt_output *output, + const unsigned char *vbf, + size_t vbf_len); + +/** + * Set the asset commitment in an elements output. + * + * :param output: The output to update. + * :param commitment: The asset commitment for this output. + * :param commitment_len: Length of ``commitment`` in bytes. + */ +WALLY_CORE_API int wally_psbt_output_set_asset_commitment( + struct wally_psbt_output *output, + const unsigned char *commitment, + size_t commitment_len); + +/** + * Set the asset blinding factor in an elements output. + * + * :param output: The output to update. + * :param abf: The asset blinding factor. + * :param abf_len: Length of ``abf`` in bytes. Must be ``BLINDING_FACTOR_LEN``. + */ +WALLY_CORE_API int wally_psbt_output_set_abf( + struct wally_psbt_output *output, + const unsigned char *abf, + size_t abf_len); + +/** + * Set the nonce commitment in an elements output. + * + * :param output: The output to update. + * :param nonce: The commitment used to create the nonce (with the blinding key) for the range proof. + * :param nonce_len: Size of ``nonce`` in bytes. Must be ``WALLY_TX_ASSET_CT_NONCE_LEN``. + */ +WALLY_CORE_API int wally_psbt_output_set_nonce( + struct wally_psbt_output *output, + const unsigned char *nonce, + size_t nonce_len); + +/** + * Set the range proof in an elements output. + * + * :param output: The output to update. + * :param proof: The range proof for this output. + * :param proof_len: Length of ``proof`` in bytes. + */ +WALLY_CORE_API int wally_psbt_output_set_rangeproof( + struct wally_psbt_output *output, + const unsigned char *proof, + size_t proof_len); + +/** + * Set the surjection proof in an elements output. + * + * :param output: The output to update. + * :param proof: The surjection proof for this output. + * :param proof_len: Length of ``proof`` in bytes. + */ +WALLY_CORE_API int wally_psbt_output_set_surjectionproof( + struct wally_psbt_output *output, + const unsigned char *proof, + size_t proof_len); +#endif /* SWIG */ + +#endif /* BUILD_ELEMENTS */ + #ifdef __cplusplus } #endif diff --git a/include/wally_script.h b/include/wally_script.h index a2a7d4ca5..cfd803514 100644 --- a/include/wally_script.h +++ b/include/wally_script.h @@ -37,6 +37,7 @@ extern "C" { #define WALLY_SCRIPT_MULTISIG_SORTED 0x8 /** Sort public keys (BIP67) */ /* Script opcodes */ +#ifndef WALLY_DISABLE_OP_CODE #define OP_0 0x00 #define OP_FALSE 0x00 #define OP_PUSHDATA1 0x4c @@ -164,6 +165,7 @@ extern "C" { #define OP_NOP10 0xb9 #define OP_INVALIDOPCODE 0xff +#endif /* WALLY_DISABLE_OP_CODE */ /** * Determine the type of a scriptPubkey script. @@ -297,8 +299,12 @@ WALLY_CORE_API int wally_witness_p2wpkh_from_der( * :param written: Destination for the number of bytes written to ``bytes_out``. */ WALLY_CORE_API int wally_scriptpubkey_op_return_from_bytes( - const unsigned char *bytes, size_t bytes_len, - uint32_t flags, unsigned char *bytes_out, size_t len, size_t *written); + const unsigned char *bytes, + size_t bytes_len, + uint32_t flags, + unsigned char *bytes_out, + size_t len, + size_t *written); /** * Create a P2SH scriptPubkey. @@ -331,6 +337,8 @@ WALLY_CORE_API int wally_scriptpubkey_p2sh_from_bytes( * :param bytes_out: Destination for the resulting scriptPubkey. * :param len: The length of ``bytes_out`` in bytes. * :param written: Destination for the number of bytes written to ``bytes_out``. + * + * .. note:: A maximum of 15 keys are allowed to be passed. */ WALLY_CORE_API int wally_scriptpubkey_multisig_from_bytes( const unsigned char *bytes, @@ -487,44 +495,44 @@ WALLY_CORE_API int wally_witness_program_from_bytes( /** * Get the pegout script size. * - * :param parent_genesis_blockhash_len: Length of ``parent_genesis_blockhash`` in bytes. Must be 32. + * :param genesis_blockhash_len: Length of ``genesis_blockhash`` in bytes. Must be ``SHA256_LEN``. * :param mainchain_script_len: Length of ``mainchain_script`` in bytes. * :param sub_pubkey_len: Length of ``sub_pubkey`` in bytes. Must be ``EC_PUBLIC_KEY_LEN``. - * :param whitelist_proof_len: The length of ``whitelist_proof`` in bytes. + * :param whitelistproof_len: The length of ``whitelistproof`` in bytes. * :param written: Destination for the number of bytes required to hold the pegout script. */ WALLY_CORE_API int wally_elements_pegout_script_size( - size_t parent_genesis_blockhash_len, + size_t genesis_blockhash_len, size_t mainchain_script_len, size_t sub_pubkey_len, - size_t whitelist_proof_len, + size_t whitelistproof_len, size_t *written); /** * Create a pegout script. * - * :param parent_genesis_blockhash: The genesis blockhash of the parent chain. - * :param parent_genesis_blockhash_len: Length of ``parent_genesis_blockhash`` in bytes. Must be 32. + * :param genesis_blockhash: The genesis blockhash of the parent chain. + * :param genesis_blockhash_len: Length of ``genesis_blockhash`` in bytes. Must be ``SHA256_LEN``. * :param mainchain_script: The parent chain script. * :param mainchain_script_len: Length of ``mainchain_script`` in bytes. * :param sub_pubkey: The whitelisted public key. * :param sub_pubkey_len: Length of ``sub_pubkey`` in bytes. Must be ``EC_PUBLIC_KEY_LEN``. - * :param whitelist_proof: The whitelist proof. - * :param whitelist_proof_len: The length of ``whitelist_proof`` in bytes. + * :param whitelistproof: The whitelist proof. + * :param whitelistproof_len: The length of ``whitelistproof`` in bytes. * :param flags: Must be zero. * :param bytes_out: Destination for the resulting pegout script. * :param len: The length of ``bytes_out`` in bytes. * :param written: Destination for the number of bytes written to ``bytes_out``. */ WALLY_CORE_API int wally_elements_pegout_script_from_bytes( - const unsigned char *parent_genesis_blockhash, - size_t parent_genesis_blockhash_len, + const unsigned char *genesis_blockhash, + size_t genesis_blockhash_len, const unsigned char *mainchain_script, size_t mainchain_script_len, const unsigned char *sub_pubkey, size_t sub_pubkey_len, - const unsigned char *whitelist_proof, - size_t whitelist_proof_len, + const unsigned char *whitelistproof, + size_t whitelistproof_len, uint32_t flags, unsigned char *bytes_out, size_t len, diff --git a/include/wally_symmetric.h b/include/wally_symmetric.h index 1102bb230..2d9e8b040 100644 --- a/include/wally_symmetric.h +++ b/include/wally_symmetric.h @@ -7,17 +7,13 @@ extern "C" { #endif -#define SYMMETRIC_KEY_LEN 32 - /** - * Create a new symmetric key from entropy. - * - * This creates a new symmetric master key. + * Create a new symmetric parent key from entropy. * * :param bytes: Entropy to use. * :param bytes_len: Size of ``bytes`` in bytes. Must be one of ``BIP32_ENTROPY_LEN_128``, *| ``BIP32_ENTROPY_LEN_256`` or ``BIP32_ENTROPY_LEN_512``. - * :param bytes_out: Destination for the resulting key. + * :param bytes_out: Destination for the resulting parent key. * :param len: Size of ``bytes_out`` in bytes. Must be ``HMAC_SHA512_LEN``. */ WALLY_CORE_API int wally_symmetric_key_from_seed( @@ -31,7 +27,7 @@ WALLY_CORE_API int wally_symmetric_key_from_seed( * Create a new child symmetric key from a parent key. * * :param bytes: Parent key to use. - * :param bytes_len: Size of ``bytes`` in bytes. Must be one of ``HMAC_SHA512_LEN``. + * :param bytes_len: Size of ``bytes`` in bytes. Must be ``HMAC_SHA512_LEN``. * :param version: Version byte to prepend to ``label``. Must be zero. * :param label: Label to use for the child. * :param label_len: Size of ``label`` in bytes. @@ -41,7 +37,7 @@ WALLY_CORE_API int wally_symmetric_key_from_seed( WALLY_CORE_API int wally_symmetric_key_from_parent( const unsigned char *bytes, size_t bytes_len, - unsigned char version, + uint32_t version, const unsigned char *label, size_t label_len, unsigned char *bytes_out, @@ -51,4 +47,4 @@ WALLY_CORE_API int wally_symmetric_key_from_parent( } #endif -#endif /* LIBWALLY_CORE_ELEMENTS_H */ +#endif /* LIBWALLY_CORE_SYMMETRIC_H */ diff --git a/include/wally_transaction.h b/include/wally_transaction.h index 602725867..4bfa0f3cd 100644 --- a/include/wally_transaction.h +++ b/include/wally_transaction.h @@ -21,8 +21,9 @@ extern "C" { #define WALLY_TXHASH_LEN 32 /** Size of a transaction hash in bytes */ -#define WALLY_TX_FLAG_USE_WITNESS 0x1 /* Encode witness data if present */ -#define WALLY_TX_FLAG_USE_ELEMENTS 0x2 /* Encode/Decode as an elements transaction */ +#define WALLY_TX_FLAG_USE_WITNESS 0x1 /* Encode witness data if present */ +#define WALLY_TX_FLAG_USE_ELEMENTS 0x2 /* Encode/Decode as an elements transaction */ +#define WALLY_TX_FLAG_ALLOW_PARTIAL 0x4 /* Allow partially complete transactions */ #define WALLY_TX_FLAG_BLINDED_INITIAL_ISSUANCE 0x1 @@ -140,6 +141,16 @@ WALLY_CORE_API int wally_tx_witness_stack_init_alloc( size_t allocation_len, struct wally_tx_witness_stack **output); +/** + * Create a copy of a witness stack. + * + * :param stack: The witness stack to copy. + * :param output: Destination for the resulting copy. + */ +WALLY_CORE_API int wally_tx_witness_stack_clone_alloc( + const struct wally_tx_witness_stack *stack, + struct wally_tx_witness_stack **output); + /** * Add a witness to a witness stack. * @@ -244,6 +255,30 @@ WALLY_CORE_API int wally_tx_output_init_alloc( size_t script_len, struct wally_tx_output **output); +/** + * Create a new copy of a transaction output. + * + * :param tx_output_in: The transaction output to clone. + * :param output: Destination for the resulting transaction output copy. + */ +WALLY_CORE_API int wally_tx_output_clone_alloc( + const struct wally_tx_output *tx_output_in, + struct wally_tx_output **output); + +#ifndef SWIG +/** + * Create a new copy of a transaction output in-place. + * + * :param tx_output_in: The transaction output to clone. + * :param output: Destination for the resulting transaction output copy. + * + * .. note:: ``output`` is overwritten in place, and not cleared first. + */ +WALLY_CORE_API int wally_tx_output_clone( + const struct wally_tx_output *tx_output_in, + struct wally_tx_output *output); +#endif /* SWIG */ + #ifndef SWIG_PYTHON /** * Free a transaction output allocated by `wally_tx_output_init_alloc`. @@ -269,6 +304,18 @@ WALLY_CORE_API int wally_tx_init_alloc( size_t outputs_allocation_len, struct wally_tx **output); +/** + * Create a new copy of a transaction. + * + * :param tx: The transaction to clone. + * :param flags: Flags controlling script creation. Must be 0. + * :param output: Destination for the resulting transaction copy. + */ +WALLY_CORE_API int wally_tx_clone( + const struct wally_tx *tx, + uint32_t flags, + struct wally_tx **output); + /** * Add a transaction input to a transaction. * @@ -396,6 +443,20 @@ WALLY_CORE_API int wally_tx_get_witness_count( WALLY_CORE_API int wally_tx_free(struct wally_tx *tx); #endif /* SWIG_PYTHON */ +/** + * Return the txid of a transaction. + * + * :param tx: The transaction to compute the txid of. + * :param bytes_out: Destination for the txid. + * :param len: Size of ``bytes_out`` in bytes. Must be ``WALLY_TXHASH_LEN``. + * + * .. note:: The txid is expensive to compute. + */ +WALLY_CORE_API int wally_tx_get_txid( + const struct wally_tx *tx, + unsigned char *bytes_out, + size_t len); + /** * Return the length of transaction once serialized into bytes. * @@ -686,7 +747,7 @@ WALLY_CORE_API int wally_tx_elements_input_is_pegin( * :param asset: The commitment to a possibly blinded asset. * :param asset_len: Size of ``asset`` in bytes. Must be ``WALLY_TX_ASSET_CT_ASSET_LEN``. * :param value: The commitment to a possibly blinded value. - * :param value_len: Size of ``value`` in bytes. Must be ``WALLY_TX_ASSET_CT_VALUE_LEN``. + * :param value_len: Size of ``value`` in bytes. Must be ``WALLY_TX_ASSET_CT_VALUE_LEN`` or ``WALLY_TX_ASSET_CT_VALUE_UNBLIND_LEN``. * :param nonce: The commitment used to create the nonce (with the blinding key) for the range proof. * :param nonce_len: Size of ``nonce`` in bytes. Must be ``WALLY_TX_ASSET_CT_NONCE_LEN``. * :param surjectionproof: surjection proof. @@ -725,7 +786,7 @@ WALLY_CORE_API int wally_tx_elements_output_commitment_free( * :param asset: The asset tag of the output. * :param asset_len: Size of ``asset`` in bytes. Must be ``WALLY_TX_ASSET_CT_ASSET_LEN``. * :param value: The commitment to a possibly blinded value. - * :param value_len: Size of ``value`` in bytes. Must be ``WALLY_TX_ASSET_CT_VALUE_LEN``. + * :param value_len: Size of ``value`` in bytes. Must be ``WALLY_TX_ASSET_CT_VALUE_LEN`` or ``WALLY_TX_ASSET_CT_VALUE_UNBLIND_LEN``. * :param nonce: The commitment used to create the nonce (with the blinding key) for the range proof. * :param nonce_len: Size of ``nonce`` in bytes. Must be ``WALLY_TX_ASSET_CT_NONCE_LEN``. * :param surjectionproof: The surjection proof. @@ -808,7 +869,7 @@ WALLY_CORE_API int wally_tx_add_elements_raw_input( * :param asset: The asset tag of the output. * :param asset_len: Size of ``asset`` in bytes. Must be ``WALLY_TX_ASSET_CT_ASSET_LEN``. * :param value: The commitment to a possibly blinded value. - * :param value_len: Size of ``value`` in bytes. Must be ``WALLY_TX_ASSET_CT_VALUE_LEN``. + * :param value_len: Size of ``value`` in bytes. Must be ``WALLY_TX_ASSET_CT_VALUE_LEN`` or ``WALLY_TX_ASSET_CT_VALUE_UNBLIND_LEN``. * :param nonce: The commitment used to create the nonce (with the blinding key) for the range proof. * :param nonce_len: Size of ``nonce`` in bytes. Must be ``WALLY_TX_ASSET_CT_NONCE_LEN``. * :param surjectionproof: The surjection proof. @@ -899,7 +960,7 @@ WALLY_CORE_API int wally_tx_get_elements_signature_hash( * Calculate the asset entropy from a prevout and the Ricardian contract hash. * * :param txhash: The prevout transaction hash. - * :param txhash_len: Size of ``txhash`` in bytes. Must be ``SHA256_LEN``. + * :param txhash_len: Size of ``txhash`` in bytes. Must be ``WALLY_TXHASH_LEN``. * :param index: The prevout index. * :param contract_hash: The issuer specified Ricardian contract hash. * :param contract_hash_len: Size of ``contract hash`` in bytes. Must be ``SHA256_LEN``. @@ -935,7 +996,7 @@ WALLY_CORE_API int wally_tx_elements_issuance_calculate_asset( * :param entropy: The asset entropy. * :param entropy_len: Size of ``entropy`` in bytes. Must be ``SHA256_LEN``. * :param flags: ``WALLY_TX_FLAG_BLINDED_INITIAL_ISSUANCE`` if initial issuance was blinded, - * | pass 0 otherwise. + *| pass 0 otherwise. * :param bytes_out: Destination for the re-issuance token. * :param len: Size of ``bytes_out`` in bytes. Must be ``SHA256_LEN``. */ diff --git a/src/Makefile.am b/src/Makefile.am index f69b4cefe..9e0e6da46 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -16,6 +16,7 @@ include_HEADERS += $(top_srcdir)/include/wally_crypto.h include_HEADERS += $(top_srcdir)/include/wally_elements.h include_HEADERS += $(top_srcdir)/include/wally_psbt.h include_HEADERS += $(top_srcdir)/include/wally_script.h +include_HEADERS += $(top_srcdir)/include/wally_symmetric.h include_HEADERS += $(top_srcdir)/include/wally_transaction.h pkgconfigdir = $(libdir)/pkgconfig @@ -185,6 +186,7 @@ libwallycore_la_SOURCES = \ mnemonic.c \ pbkdf2.c \ psbt.c \ + pullpush.c \ script.c \ scrypt.c \ sign.c \ @@ -225,6 +227,16 @@ noinst_PROGRAMS += test_bech32 test_bech32_SOURCES = ctest/test_bech32.c test_bech32_CFLAGS = -I$(top_srcdir)/include $(AM_CFLAGS) test_bech32_LDADD = $(lib_LTLIBRARIES) @CTEST_EXTRA_STATIC@ +TESTS += test_psbt +noinst_PROGRAMS += test_psbt +test_psbt_SOURCES = ctest/test_psbt.c ccan/ccan/str/hex/hex.c +test_psbt_CFLAGS = -I$(top_srcdir)/include $(AM_CFLAGS) -I$(srcdir)/ccan +test_psbt_LDADD = $(lib_LTLIBRARIES) @CTEST_EXTRA_STATIC@ +TESTS += test_psbt_limits +noinst_PROGRAMS += test_psbt_limits +test_psbt_limits_SOURCES = ctest/test_psbt_limits.c ccan/ccan/str/hex/hex.c +test_psbt_limits_CFLAGS = -I$(top_srcdir)/include $(AM_CFLAGS) -I$(srcdir)/ccan +test_psbt_limits_LDADD = $(lib_LTLIBRARIES) @CTEST_EXTRA_STATIC@ if USE_PTHREAD TESTS += test_clear noinst_PROGRAMS += test_clear @@ -262,7 +274,6 @@ if RUN_PYTHON_TESTS $(AM_V_at)$(PYTHON_TEST) test/test_bip38.py $(AM_V_at)$(PYTHON_TEST) test/test_bip39.py $(AM_V_at)$(PYTHON_TEST) test/test_ecdh.py - $(AM_V_at)$(PYTHON_TEST) test/test_elements.py $(AM_V_at)$(PYTHON_TEST) test/test_hash.py $(AM_V_at)$(PYTHON_TEST) test/test_hex.py $(AM_V_at)$(PYTHON_TEST) test/test_hmac.py @@ -272,23 +283,29 @@ if RUN_PYTHON_TESTS $(AM_V_at)$(PYTHON_TEST) test/test_script.py $(AM_V_at)$(PYTHON_TEST) test/test_scrypt.py $(AM_V_at)$(PYTHON_TEST) test/test_sign.py + $(AM_V_at)$(PYTHON_TEST) test/test_symmetric.py $(AM_V_at)$(PYTHON_TEST) test/test_transaction.py $(AM_V_at)$(PYTHON_TEST) test/test_wif.py $(AM_V_at)$(PYTHON_TEST) test/test_wordlist.py +if BUILD_ELEMENTS + $(AM_V_at)$(PYTHON_TEST) test/test_pset.py + $(AM_V_at)$(PYTHON_TEST) test/test_confidential_addr.py + $(AM_V_at)$(PYTHON_TEST) test/test_pegin.py + $(AM_V_at)$(PYTHON_TEST) test/test_pegout.py + $(AM_V_at)$(PYTHON_TEST) test/test_elements.py +endif if USE_SWIG_PYTHON - $(AM_V_at)$(PYTHON_SWIGTEST) swig_python/contrib/address.py $(AM_V_at)$(PYTHON_SWIGTEST) swig_python/contrib/bip32.py $(AM_V_at)$(PYTHON_SWIGTEST) swig_python/contrib/mnemonic.py + $(AM_V_at)$(PYTHON_SWIGTEST) swig_python/contrib/psbt.py $(AM_V_at)$(PYTHON_SWIGTEST) swig_python/contrib/sha.py + $(AM_V_at)$(PYTHON_SWIGTEST) swig_python/contrib/signmessage.py $(AM_V_at)$(PYTHON_SWIGTEST) swig_python/contrib/tx.py if BUILD_ELEMENTS - $(AM_V_at)$(PYTHON_TEST) test/test_confidential_addr.py - $(AM_V_at)$(PYTHON_TEST) test/test_pegin.py - $(AM_V_at)$(PYTHON_TEST) test/test_pegout.py $(AM_V_at)$(PYTHON_SWIGTEST) swig_python/contrib/elements_tx.py $(AM_V_at)$(PYTHON_SWIGTEST) pyexample/liquid/receive-send.py endif -endif +endif # USE_SWIG_PYTHON endif # RUN_PYTHON_TESTS if RUN_JAVA_TESTS if BUILD_ELEMENTS diff --git a/src/address.c b/src/address.c index 492610aed..11f8da76b 100644 --- a/src/address.c +++ b/src/address.c @@ -1,7 +1,5 @@ #include "internal.h" -#include "base58.h" #include -#include "ccan/ccan/build_assert/build_assert.h" #include #include #include @@ -70,6 +68,8 @@ int wally_bip32_key_to_addr_segwit(const struct ext_key *hdkey, const char *addr return WALLY_EINVAL; ret = wally_addr_segwit_from_bytes(witness_program_bytes, HASH160_LEN + 2, addr_family, flags, output); + + wally_clear(witness_program_bytes, sizeof(witness_program_bytes)); return ret; } @@ -118,29 +118,28 @@ int wally_address_to_scriptpubkey(const char *addr, uint32_t network, unsigned c size_t len, size_t *written) { uint32_t version, addr_network; - unsigned char bytes_base58_decode[1 + HASH160_LEN + BASE58_CHECKSUM_LEN]; - size_t written_base58_decode; + unsigned char decoded[1 + HASH160_LEN + BASE58_CHECKSUM_LEN]; + size_t decoded_len; if (written) *written = 0; - /* This returns WALLY_OK even if addr is too long for bytes_base58_decode */ - if (wally_base58_to_bytes(addr, BASE58_FLAG_CHECKSUM, bytes_base58_decode, sizeof(bytes_base58_decode), &written_base58_decode) != WALLY_OK) + if (wally_base58_to_bytes(addr, BASE58_FLAG_CHECKSUM, decoded, sizeof(decoded), &decoded_len) != WALLY_OK) return WALLY_EINVAL; - if (written_base58_decode != HASH160_LEN + 1) + if (decoded_len != HASH160_LEN + 1) return WALLY_EINVAL; - version = bytes_base58_decode[0]; + version = decoded[0]; if (network_from_addr_version(version, &addr_network) != WALLY_OK) return WALLY_EINVAL; if (network != addr_network) return WALLY_EINVAL; if (is_p2pkh(version)) { - return wally_scriptpubkey_p2pkh_from_bytes(bytes_base58_decode + 1, HASH160_LEN, 0, bytes_out, len, written); + return wally_scriptpubkey_p2pkh_from_bytes(decoded + 1, HASH160_LEN, 0, bytes_out, len, written); } else if (is_p2sh(version)) { - return wally_scriptpubkey_p2sh_from_bytes(bytes_base58_decode + 1, HASH160_LEN, 0, bytes_out, len, written); + return wally_scriptpubkey_p2sh_from_bytes(decoded + 1, HASH160_LEN, 0, bytes_out, len, written); } else { return WALLY_EINVAL; } @@ -200,6 +199,6 @@ int wally_scriptpubkey_to_address(const unsigned char *scriptpubkey, size_t scri } ret = wally_base58_from_bytes(bytes, sizeof(bytes), BASE58_FLAG_CHECKSUM, output); wally_clear(bytes, sizeof(bytes)); - return WALLY_OK; + return ret; } diff --git a/src/bech32.c b/src/bech32.c index 5e32d831b..11df0c1d6 100644 --- a/src/bech32.c +++ b/src/bech32.c @@ -168,7 +168,7 @@ static int convert_bits(uint8_t *out, size_t *outlen, int outbits, const uint8_t static int segwit_addr_encode(char *output, const char *hrp, int witver, const uint8_t *witprog, size_t witprog_len) { uint8_t data[65]; size_t datalen = 0; - if (witver > 16) goto fail; + if (witver < 0 || witver > 16) goto fail; if (witver == 0 && witprog_len != 20 && witprog_len != 32) goto fail; if (witprog_len < 2 || witprog_len > 40) goto fail; data[0] = witver; diff --git a/src/bip32.c b/src/bip32.c index 7150b41c6..0169e60f5 100644 --- a/src/bip32.c +++ b/src/bip32.c @@ -85,12 +85,6 @@ static bool key_is_private(const struct ext_key *hdkey) return hdkey->priv_key[0] == BIP32_FLAG_KEY_PRIVATE; } -static void key_strip_private_key(struct ext_key *key_out) -{ - key_out->priv_key[0] = BIP32_FLAG_KEY_PUBLIC; - wally_clear(key_out->priv_key + 1, sizeof(key_out->priv_key) - 1); -} - /* Compute a public key from a private key */ static int key_compute_pub_key(struct ext_key *key_out) { @@ -110,8 +104,7 @@ int bip32_key_free(const struct ext_key *hdkey) { if (!hdkey) return WALLY_EINVAL; - wally_clear((void *)hdkey, sizeof(*hdkey)); - wally_free((void *)hdkey); + clear_and_free((void *)hdkey, sizeof(*hdkey)); return WALLY_OK; } @@ -169,10 +162,9 @@ int bip32_key_from_seed(const unsigned char *bytes, size_t bytes_len, #define ALLOC_KEY() \ if (!output) \ return WALLY_EINVAL; \ - *output = wally_malloc(sizeof(struct ext_key)); \ + *output = wally_calloc(sizeof(struct ext_key)); \ if (!*output) \ - return WALLY_ENOMEM; \ - wally_clear((void *)*output, sizeof(struct ext_key)) + return WALLY_ENOMEM int bip32_key_from_seed_alloc(const unsigned char *bytes, size_t bytes_len, uint32_t version, uint32_t flags, @@ -257,7 +249,7 @@ int bip32_key_serialize(const struct ext_key *hdkey, uint32_t flags, *out++ = hdkey->depth; /* Save the first 32 bits of the parent key (aka fingerprint) only */ - out = copy_out(out, hdkey->parent160, FINGERPRINT_LEN); + out = copy_out(out, hdkey->parent160, BIP32_KEY_FINGERPRINT_LEN); tmp32_be = cpu_to_be32(hdkey->child_num); out = copy_out(out, &tmp32_be, sizeof(tmp32_be)); @@ -305,7 +297,7 @@ int bip32_key_unserialize(const unsigned char *bytes, size_t bytes_len, * user will need to call bip32_key_set_parent() (FIXME: Implement) * later if they want it to be fully populated. */ - bytes = copy_in(key_out->parent160, bytes, FINGERPRINT_LEN); + bytes = copy_in(key_out->parent160, bytes, BIP32_KEY_FINGERPRINT_LEN); bytes = copy_in(&key_out->child_num, bytes, sizeof(key_out->child_num)); key_out->child_num = be32_to_cpu(key_out->child_num); bytes = copy_in(key_out->chain_code, bytes, sizeof(key_out->chain_code)); @@ -324,7 +316,7 @@ int bip32_key_unserialize(const unsigned char *bytes, size_t bytes_len, return wipe_key_fail(key_out); /* Public key data in private key */ copy_in(key_out->pub_key, bytes, sizeof(key_out->pub_key)); - key_strip_private_key(key_out); + bip32_key_strip_private_key(key_out); } key_compute_hash160(key_out); @@ -338,7 +330,7 @@ int bip32_key_unserialize_alloc(const unsigned char *bytes, size_t bytes_len, ALLOC_KEY(); ret = bip32_key_unserialize(bytes, bytes_len, *output); - if (ret) { + if (ret != WALLY_OK) { wally_free(*output); *output = 0; } @@ -481,7 +473,7 @@ int bip32_key_from_parent(const struct ext_key *hdkey, uint32_t child_num, else key_out->version = BIP32_VER_TEST_PUBLIC; - key_strip_private_key(key_out); + bip32_key_strip_private_key(key_out); } key_out->depth = hdkey->depth + 1; @@ -505,7 +497,7 @@ int bip32_key_from_parent_alloc(const struct ext_key *hdkey, ALLOC_KEY(); ret = bip32_key_from_parent(hdkey, child_num, flags, *output); - if (ret) { + if (ret != WALLY_OK) { wally_free(*output); *output = 0; } @@ -561,7 +553,7 @@ int bip32_key_from_parent_path_alloc(const struct ext_key *hdkey, ALLOC_KEY(); ret = bip32_key_from_parent_path(hdkey, child_path, child_path_len, flags, *output); - if (ret) { + if (ret != WALLY_OK) { wally_free(*output); *output = 0; } @@ -608,7 +600,7 @@ int bip32_key_with_tweak_from_parent_path_alloc(const struct ext_key *hdkey, ALLOC_KEY(); ret = bip32_key_with_tweak_from_parent_path(hdkey, child_path, child_path_len, flags, *output); - if (ret) { + if (ret != WALLY_OK) { wally_free(*output); *output = NULL; } @@ -742,18 +734,19 @@ int bip32_key_from_base58_alloc(const char *base58, ALLOC_KEY(); ret = bip32_key_from_base58(base58, *output); - if (ret) { + if (ret != WALLY_OK) { wally_free(*output); *output = 0; } return ret; } -int bip32_key_strip_private_key(struct ext_key *hdkey) +int bip32_key_strip_private_key(struct ext_key *key_out) { - if (!hdkey) + if (!key_out) return WALLY_EINVAL; - key_strip_private_key(hdkey); + key_out->priv_key[0] = BIP32_FLAG_KEY_PUBLIC; + wally_clear(key_out->priv_key + 1, sizeof(key_out->priv_key) - 1); return WALLY_OK; } @@ -763,7 +756,7 @@ int bip32_key_get_fingerprint(struct ext_key *hdkey, /* Validate our arguments and then the input key */ if (!hdkey || !key_is_valid(hdkey) || - !bytes_out || len != FINGERPRINT_LEN) + !bytes_out || len != BIP32_KEY_FINGERPRINT_LEN) return WALLY_EINVAL; /* Derive hash160 if needed. */ @@ -772,7 +765,7 @@ int bip32_key_get_fingerprint(struct ext_key *hdkey, } /* Fingerprint is first 32 bits of the key hash. */ - memcpy(bytes_out, hdkey->hash160, FINGERPRINT_LEN); + memcpy(bytes_out, hdkey->hash160, BIP32_KEY_FINGERPRINT_LEN); return WALLY_OK; } diff --git a/src/bip39.c b/src/bip39.c index 0eb1038b5..427774303 100644 --- a/src/bip39.c +++ b/src/bip39.c @@ -203,7 +203,7 @@ int bip39_mnemonic_to_seed(const char *mnemonic, const char *passphrase, unsigned char *bytes_out, size_t len, size_t *written) { - const size_t bip9_cost = 2048u; + const uint32_t bip9_cost = 2048u; const char *prefix = "mnemonic"; const size_t prefix_len = strlen(prefix); const size_t passphrase_len = passphrase ? strlen(passphrase) : 0; @@ -232,8 +232,7 @@ int bip39_mnemonic_to_seed(const char *mnemonic, const char *passphrase, if (!ret && written) *written = BIP39_SEED_LEN_512; /* Succeeded */ - wally_clear(salt, salt_len); - wally_free(salt); + clear_and_free(salt, salt_len); return ret; } diff --git a/src/blech32.c b/src/blech32.c index 9da31c958..857dac5b5 100644 --- a/src/blech32.c +++ b/src/blech32.c @@ -171,7 +171,7 @@ static int blech32_convert_bits(uint8_t *out, size_t *outlen, int outbits, const static int blech32_addr_encode(char *output, const char *hrp, int witver, const uint8_t *witprog, size_t witprog_len) { uint8_t data[WALLY_BLECH32_MAXLEN]; size_t datalen = 0; - if (witver > 16) goto fail; + if (witver < 0 || witver > 16) goto fail; if (witver == 0 && witprog_len != 53 && witprog_len != 65) goto fail; if (witprog_len < 2 || witprog_len > 65) goto fail; data[0] = witver; @@ -279,9 +279,9 @@ int wally_confidential_addr_from_addr_segwit( if (output) *output = NULL; - if (!address || !addr_family || !confidential_addr_family || !pub_key - || pub_key_len != EC_PUBLIC_KEY_LEN || !output - || strlen(confidential_addr_family) >= WALLY_BLECH32_MAXLEN) + if (!address || !addr_family || !confidential_addr_family || !pub_key || + pub_key_len != EC_PUBLIC_KEY_LEN || !output || + strlen(confidential_addr_family) >= WALLY_BLECH32_MAXLEN) return WALLY_EINVAL; /* get v0 witness programs script */ diff --git a/src/ctest/psbts.h b/src/ctest/psbts.h new file mode 100644 index 000000000..375223386 --- /dev/null +++ b/src/ctest/psbts.h @@ -0,0 +1,320 @@ +struct psbt_test { + const char *hex; + const char *base64; +}; + +/* From BIP 174: + * + * The following are invalid PSBTs: + */ +static const struct psbt_test invalid_psbts[] = { +/* + Case: Network transaction, not PSBT format + Bytes in Hex: +*/ + { "0200000001268171371edff285e937adeea4b37b78000c0566cbb3ad64641713ca42171bf6000000006a473044022070b2245123e6bf474d60c5b50c043d4c691a5d2435f09a34a7662a9dc251790a022001329ca9dacf280bdf30740ec0390422422c81cb45839457aeb76fc12edd95b3012102657d118d3357b8e0f4c2cd46db7b39f6d9c38d9a70abcb9b2de5dc8dbfe4ce31feffffff02d3dff505000000001976a914d0c59903c5bac2868760e90fd521a4665aa7652088ac00e1f5050000000017a9143545e6e33b832c47050f24d3eeb93c9c03948bc787b32e1300", + +/* + Base64 String: +*/ + "AgAAAAEmgXE3Ht/yhek3re6ks3t4AAwFZsuzrWRkFxPKQhcb9gAAAABqRzBEAiBwsiRRI+a/R01gxbUMBD1MaRpdJDXwmjSnZiqdwlF5CgIgATKcqdrPKAvfMHQOwDkEIkIsgctFg5RXrrdvwS7dlbMBIQJlfRGNM1e44PTCzUbbezn22cONmnCry5st5dyNv+TOMf7///8C09/1BQAAAAAZdqkU0MWZA8W6woaHYOkP1SGkZlqnZSCIrADh9QUAAAAAF6kUNUXm4zuDLEcFDyTT7rk8nAOUi8eHsy4TAA=="}, + +/* + Case: PSBT missing outputs + Bytes in Hex: +*/ + { "70736274ff0100750200000001268171371edff285e937adeea4b37b78000c0566cbb3ad64641713ca42171bf60000000000feffffff02d3dff505000000001976a914d0c59903c5bac2868760e90fd521a4665aa7652088ac00e1f5050000000017a9143545e6e33b832c47050f24d3eeb93c9c03948bc787b32e1300000100fda5010100000000010289a3c71eab4d20e0371bbba4cc698fa295c9463afa2e397f8533ccb62f9567e50100000017160014be18d152a9b012039daf3da7de4f53349eecb985ffffffff86f8aa43a71dff1448893a530a7237ef6b4608bbb2dd2d0171e63aec6a4890b40100000017160014fe3e9ef1a745e974d902c4355943abcb34bd5353ffffffff0200c2eb0b000000001976a91485cff1097fd9e008bb34af709c62197b38978a4888ac72fef84e2c00000017a914339725ba21efd62ac753a9bcd067d6c7a6a39d05870247304402202712be22e0270f394f568311dc7ca9a68970b8025fdd3b240229f07f8a5f3a240220018b38d7dcd314e734c9276bd6fb40f673325bc4baa144c800d2f2f02db2765c012103d2e15674941bad4a996372cb87e1856d3652606d98562fe39c5e9e7e413f210502483045022100d12b852d85dcd961d2f5f4ab660654df6eedcc794c0c33ce5cc309ffb5fce58d022067338a8e0e1725c197fb1a88af59f51e44e4255b20167c8684031c05d1f2592a01210223b72beef0965d10be0778efecd61fcac6f79a4ea169393380734464f84f2ab30000000000", +/* + Base64 String: +*/ + "cHNidP8BAHUCAAAAASaBcTce3/KF6Tet7qSze3gADAVmy7OtZGQXE8pCFxv2AAAAAAD+////AtPf9QUAAAAAGXapFNDFmQPFusKGh2DpD9UhpGZap2UgiKwA4fUFAAAAABepFDVF5uM7gyxHBQ8k0+65PJwDlIvHh7MuEwAAAQD9pQEBAAAAAAECiaPHHqtNIOA3G7ukzGmPopXJRjr6Ljl/hTPMti+VZ+UBAAAAFxYAFL4Y0VKpsBIDna89p95PUzSe7LmF/////4b4qkOnHf8USIk6UwpyN+9rRgi7st0tAXHmOuxqSJC0AQAAABcWABT+Pp7xp0XpdNkCxDVZQ6vLNL1TU/////8CAMLrCwAAAAAZdqkUhc/xCX/Z4Ai7NK9wnGIZeziXikiIrHL++E4sAAAAF6kUM5cluiHv1irHU6m80GfWx6ajnQWHAkcwRAIgJxK+IuAnDzlPVoMR3HyppolwuAJf3TskAinwf4pfOiQCIAGLONfc0xTnNMkna9b7QPZzMlvEuqFEyADS8vAtsnZcASED0uFWdJQbrUqZY3LLh+GFbTZSYG2YVi/jnF6efkE/IQUCSDBFAiEA0SuFLYXc2WHS9fSrZgZU327tzHlMDDPOXMMJ/7X85Y0CIGczio4OFyXBl/saiK9Z9R5E5CVbIBZ8hoQDHAXR8lkqASECI7cr7vCWXRC+B3jv7NYfysb3mk6haTkzgHNEZPhPKrMAAAAAAA=="}, + +/* + Case: PSBT where one input has a filled scriptSig in the unsigned tx + Bytes in Hex: + +*/ + { "70736274ff0100fd0a010200000002ab0949a08c5af7c49b8212f417e2f15ab3f5c33dcf153821a8139f877a5b7be4000000006a47304402204759661797c01b036b25928948686218347d89864b719e1f7fcf57d1e511658702205309eabf56aa4d8891ffd111fdf1336f3a29da866d7f8486d75546ceedaf93190121035cdc61fc7ba971c0b501a646a2a83b102cb43881217ca682dc86e2d73fa88292feffffffab0949a08c5af7c49b8212f417e2f15ab3f5c33dcf153821a8139f877a5b7be40100000000feffffff02603bea0b000000001976a914768a40bbd740cbe81d988e71de2a4d5c71396b1d88ac8e240000000000001976a9146f4620b553fa095e721b9ee0efe9fa039cca459788ac00000000000001012000e1f5050000000017a9143545e6e33b832c47050f24d3eeb93c9c03948bc787010416001485d13537f2e265405a34dbafa9e3dda01fb82308000000", +/* + Base64 String: +*/ + "cHNidP8BAP0KAQIAAAACqwlJoIxa98SbghL0F+LxWrP1wz3PFTghqBOfh3pbe+QAAAAAakcwRAIgR1lmF5fAGwNrJZKJSGhiGDR9iYZLcZ4ff89X0eURZYcCIFMJ6r9Wqk2Ikf/REf3xM286KdqGbX+EhtdVRs7tr5MZASEDXNxh/HupccC1AaZGoqg7ECy0OIEhfKaC3Ibi1z+ogpL+////qwlJoIxa98SbghL0F+LxWrP1wz3PFTghqBOfh3pbe+QBAAAAAP7///8CYDvqCwAAAAAZdqkUdopAu9dAy+gdmI5x3ipNXHE5ax2IrI4kAAAAAAAAGXapFG9GILVT+glechue4O/p+gOcykWXiKwAAAAAAAABASAA4fUFAAAAABepFDVF5uM7gyxHBQ8k0+65PJwDlIvHhwEEFgAUhdE1N/LiZUBaNNuvqePdoB+4IwgAAAA="}, + +/* + Case: PSBT where inputs and outputs are provided but without an unsigned tx + Bytes in Hex: + +*/ + { "70736274ff000100fda5010100000000010289a3c71eab4d20e0371bbba4cc698fa295c9463afa2e397f8533ccb62f9567e50100000017160014be18d152a9b012039daf3da7de4f53349eecb985ffffffff86f8aa43a71dff1448893a530a7237ef6b4608bbb2dd2d0171e63aec6a4890b40100000017160014fe3e9ef1a745e974d902c4355943abcb34bd5353ffffffff0200c2eb0b000000001976a91485cff1097fd9e008bb34af709c62197b38978a4888ac72fef84e2c00000017a914339725ba21efd62ac753a9bcd067d6c7a6a39d05870247304402202712be22e0270f394f568311dc7ca9a68970b8025fdd3b240229f07f8a5f3a240220018b38d7dcd314e734c9276bd6fb40f673325bc4baa144c800d2f2f02db2765c012103d2e15674941bad4a996372cb87e1856d3652606d98562fe39c5e9e7e413f210502483045022100d12b852d85dcd961d2f5f4ab660654df6eedcc794c0c33ce5cc309ffb5fce58d022067338a8e0e1725c197fb1a88af59f51e44e4255b20167c8684031c05d1f2592a01210223b72beef0965d10be0778efecd61fcac6f79a4ea169393380734464f84f2ab30000000000", +/* + Base64 String: +*/ + "cHNidP8AAQD9pQEBAAAAAAECiaPHHqtNIOA3G7ukzGmPopXJRjr6Ljl/hTPMti+VZ+UBAAAAFxYAFL4Y0VKpsBIDna89p95PUzSe7LmF/////4b4qkOnHf8USIk6UwpyN+9rRgi7st0tAXHmOuxqSJC0AQAAABcWABT+Pp7xp0XpdNkCxDVZQ6vLNL1TU/////8CAMLrCwAAAAAZdqkUhc/xCX/Z4Ai7NK9wnGIZeziXikiIrHL++E4sAAAAF6kUM5cluiHv1irHU6m80GfWx6ajnQWHAkcwRAIgJxK+IuAnDzlPVoMR3HyppolwuAJf3TskAinwf4pfOiQCIAGLONfc0xTnNMkna9b7QPZzMlvEuqFEyADS8vAtsnZcASED0uFWdJQbrUqZY3LLh+GFbTZSYG2YVi/jnF6efkE/IQUCSDBFAiEA0SuFLYXc2WHS9fSrZgZU327tzHlMDDPOXMMJ/7X85Y0CIGczio4OFyXBl/saiK9Z9R5E5CVbIBZ8hoQDHAXR8lkqASECI7cr7vCWXRC+B3jv7NYfysb3mk6haTkzgHNEZPhPKrMAAAAAAA=="}, + +/* + Case: PSBT with duplicate keys in an input + Bytes in Hex: + +*/ + { "70736274ff0100750200000001268171371edff285e937adeea4b37b78000c0566cbb3ad64641713ca42171bf60000000000feffffff02d3dff505000000001976a914d0c59903c5bac2868760e90fd521a4665aa7652088ac00e1f5050000000017a9143545e6e33b832c47050f24d3eeb93c9c03948bc787b32e1300000100fda5010100000000010289a3c71eab4d20e0371bbba4cc698fa295c9463afa2e397f8533ccb62f9567e50100000017160014be18d152a9b012039daf3da7de4f53349eecb985ffffffff86f8aa43a71dff1448893a530a7237ef6b4608bbb2dd2d0171e63aec6a4890b40100000017160014fe3e9ef1a745e974d902c4355943abcb34bd5353ffffffff0200c2eb0b000000001976a91485cff1097fd9e008bb34af709c62197b38978a4888ac72fef84e2c00000017a914339725ba21efd62ac753a9bcd067d6c7a6a39d05870247304402202712be22e0270f394f568311dc7ca9a68970b8025fdd3b240229f07f8a5f3a240220018b38d7dcd314e734c9276bd6fb40f673325bc4baa144c800d2f2f02db2765c012103d2e15674941bad4a996372cb87e1856d3652606d98562fe39c5e9e7e413f210502483045022100d12b852d85dcd961d2f5f4ab660654df6eedcc794c0c33ce5cc309ffb5fce58d022067338a8e0e1725c197fb1a88af59f51e44e4255b20167c8684031c05d1f2592a01210223b72beef0965d10be0778efecd61fcac6f79a4ea169393380734464f84f2ab30000000001003f0200000001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000ffffffff010000000000000000036a010000000000000000", +/* + Base64 String: +*/ + "cHNidP8BAHUCAAAAASaBcTce3/KF6Tet7qSze3gADAVmy7OtZGQXE8pCFxv2AAAAAAD+////AtPf9QUAAAAAGXapFNDFmQPFusKGh2DpD9UhpGZap2UgiKwA4fUFAAAAABepFDVF5uM7gyxHBQ8k0+65PJwDlIvHh7MuEwAAAQD9pQEBAAAAAAECiaPHHqtNIOA3G7ukzGmPopXJRjr6Ljl/hTPMti+VZ+UBAAAAFxYAFL4Y0VKpsBIDna89p95PUzSe7LmF/////4b4qkOnHf8USIk6UwpyN+9rRgi7st0tAXHmOuxqSJC0AQAAABcWABT+Pp7xp0XpdNkCxDVZQ6vLNL1TU/////8CAMLrCwAAAAAZdqkUhc/xCX/Z4Ai7NK9wnGIZeziXikiIrHL++E4sAAAAF6kUM5cluiHv1irHU6m80GfWx6ajnQWHAkcwRAIgJxK+IuAnDzlPVoMR3HyppolwuAJf3TskAinwf4pfOiQCIAGLONfc0xTnNMkna9b7QPZzMlvEuqFEyADS8vAtsnZcASED0uFWdJQbrUqZY3LLh+GFbTZSYG2YVi/jnF6efkE/IQUCSDBFAiEA0SuFLYXc2WHS9fSrZgZU327tzHlMDDPOXMMJ/7X85Y0CIGczio4OFyXBl/saiK9Z9R5E5CVbIBZ8hoQDHAXR8lkqASECI7cr7vCWXRC+B3jv7NYfysb3mk6haTkzgHNEZPhPKrMAAAAAAQA/AgAAAAH//////////////////////////////////////////wAAAAAA/////wEAAAAAAAAAAANqAQAAAAAAAAAA"}, + +/* + Case: PSBT With invalid global transaction typed key + Bytes in Hex: + +*/ + { "70736274ff020001550200000001279a2323a5dfb51fc45f220fa58b0fc13e1e3342792a85d7e36cd6333b5cbc390000000000ffffffff01a05aea0b000000001976a914ffe9c0061097cc3b636f2cb0460fa4fc427d2b4588ac0000000000010120955eea0b0000000017a9146345200f68d189e1adc0df1c4d16ea8f14c0dbeb87220203b1341ccba7683b6af4f1238cd6e97e7167d569fac47f1e48d47541844355bd4646304302200424b58effaaa694e1559ea5c93bbfd4a89064224055cdf070b6771469442d07021f5c8eb0fea6516d60b8acb33ad64ede60e8785bfb3aa94b99bdf86151db9a9a010104220020771fd18ad459666dd49f3d564e3dbc42f4c84774e360ada16816a8ed488d5681010547522103b1341ccba7683b6af4f1238cd6e97e7167d569fac47f1e48d47541844355bd462103de55d1e1dac805e3f8a58c1fbf9b94c02f3dbaafe127fefca4995f26f82083bd52ae220603b1341ccba7683b6af4f1238cd6e97e7167d569fac47f1e48d47541844355bd4610b4a6ba67000000800000008004000080220603de55d1e1dac805e3f8a58c1fbf9b94c02f3dbaafe127fefca4995f26f82083bd10b4a6ba670000008000000080050000800000", +/* + Base64 String: +*/ + "cHNidP8CAAFVAgAAAAEnmiMjpd+1H8RfIg+liw/BPh4zQnkqhdfjbNYzO1y8OQAAAAAA/////wGgWuoLAAAAABl2qRT/6cAGEJfMO2NvLLBGD6T8Qn0rRYisAAAAAAABASCVXuoLAAAAABepFGNFIA9o0YnhrcDfHE0W6o8UwNvrhyICA7E0HMunaDtq9PEjjNbpfnFn1Wn6xH8eSNR1QYRDVb1GRjBDAiAEJLWO/6qmlOFVnqXJO7/UqJBkIkBVzfBwtncUaUQtBwIfXI6w/qZRbWC4rLM61k7eYOh4W/s6qUuZvfhhUduamgEBBCIAIHcf0YrUWWZt1J89Vk49vEL0yEd042CtoWgWqO1IjVaBAQVHUiEDsTQcy6doO2r08SOM1ul+cWfVafrEfx5I1HVBhENVvUYhA95V0eHayAXj+KWMH7+blMAvPbqv4Sf+/KSZXyb4IIO9Uq4iBgOxNBzLp2g7avTxI4zW6X5xZ9Vp+sR/HkjUdUGEQ1W9RhC0prpnAAAAgAAAAIAEAACAIgYD3lXR4drIBeP4pYwfv5uUwC89uq/hJ/78pJlfJvggg70QtKa6ZwAAAIAAAACABQAAgAAA"}, + +/* + Case: PSBT With invalid input witness utxo typed key + Bytes in Hex: + +*/ + { "70736274ff0100550200000001279a2323a5dfb51fc45f220fa58b0fc13e1e3342792a85d7e36cd6333b5cbc390000000000ffffffff01a05aea0b000000001976a914ffe9c0061097cc3b636f2cb0460fa4fc427d2b4588ac000000000002010020955eea0b0000000017a9146345200f68d189e1adc0df1c4d16ea8f14c0dbeb87220203b1341ccba7683b6af4f1238cd6e97e7167d569fac47f1e48d47541844355bd4646304302200424b58effaaa694e1559ea5c93bbfd4a89064224055cdf070b6771469442d07021f5c8eb0fea6516d60b8acb33ad64ede60e8785bfb3aa94b99bdf86151db9a9a010104220020771fd18ad459666dd49f3d564e3dbc42f4c84774e360ada16816a8ed488d5681010547522103b1341ccba7683b6af4f1238cd6e97e7167d569fac47f1e48d47541844355bd462103de55d1e1dac805e3f8a58c1fbf9b94c02f3dbaafe127fefca4995f26f82083bd52ae220603b1341ccba7683b6af4f1238cd6e97e7167d569fac47f1e48d47541844355bd4610b4a6ba67000000800000008004000080220603de55d1e1dac805e3f8a58c1fbf9b94c02f3dbaafe127fefca4995f26f82083bd10b4a6ba670000008000000080050000800000", +/* + Base64 String: +*/ + "cHNidP8BAFUCAAAAASeaIyOl37UfxF8iD6WLD8E+HjNCeSqF1+Ns1jM7XLw5AAAAAAD/////AaBa6gsAAAAAGXapFP/pwAYQl8w7Y28ssEYPpPxCfStFiKwAAAAAAAIBACCVXuoLAAAAABepFGNFIA9o0YnhrcDfHE0W6o8UwNvrhyICA7E0HMunaDtq9PEjjNbpfnFn1Wn6xH8eSNR1QYRDVb1GRjBDAiAEJLWO/6qmlOFVnqXJO7/UqJBkIkBVzfBwtncUaUQtBwIfXI6w/qZRbWC4rLM61k7eYOh4W/s6qUuZvfhhUduamgEBBCIAIHcf0YrUWWZt1J89Vk49vEL0yEd042CtoWgWqO1IjVaBAQVHUiEDsTQcy6doO2r08SOM1ul+cWfVafrEfx5I1HVBhENVvUYhA95V0eHayAXj+KWMH7+blMAvPbqv4Sf+/KSZXyb4IIO9Uq4iBgOxNBzLp2g7avTxI4zW6X5xZ9Vp+sR/HkjUdUGEQ1W9RhC0prpnAAAAgAAAAIAEAACAIgYD3lXR4drIBeP4pYwfv5uUwC89uq/hJ/78pJlfJvggg70QtKa6ZwAAAIAAAACABQAAgAAA"}, + +/* + Case: PSBT With invalid pubkey length for input partial signature typed key + Bytes in Hex: + +*/ + { "70736274ff0100550200000001279a2323a5dfb51fc45f220fa58b0fc13e1e3342792a85d7e36cd6333b5cbc390000000000ffffffff01a05aea0b000000001976a914ffe9c0061097cc3b636f2cb0460fa4fc427d2b4588ac0000000000010120955eea0b0000000017a9146345200f68d189e1adc0df1c4d16ea8f14c0dbeb87210203b1341ccba7683b6af4f1238cd6e97e7167d569fac47f1e48d47541844355bd46304302200424b58effaaa694e1559ea5c93bbfd4a89064224055cdf070b6771469442d07021f5c8eb0fea6516d60b8acb33ad64ede60e8785bfb3aa94b99bdf86151db9a9a010104220020771fd18ad459666dd49f3d564e3dbc42f4c84774e360ada16816a8ed488d5681010547522103b1341ccba7683b6af4f1238cd6e97e7167d569fac47f1e48d47541844355bd462103de55d1e1dac805e3f8a58c1fbf9b94c02f3dbaafe127fefca4995f26f82083bd52ae220603b1341ccba7683b6af4f1238cd6e97e7167d569fac47f1e48d47541844355bd4610b4a6ba67000000800000008004000080220603de55d1e1dac805e3f8a58c1fbf9b94c02f3dbaafe127fefca4995f26f82083bd10b4a6ba670000008000000080050000800000", +/* + Base64 String: +*/ + "cHNidP8BAFUCAAAAASeaIyOl37UfxF8iD6WLD8E+HjNCeSqF1+Ns1jM7XLw5AAAAAAD/////AaBa6gsAAAAAGXapFP/pwAYQl8w7Y28ssEYPpPxCfStFiKwAAAAAAAEBIJVe6gsAAAAAF6kUY0UgD2jRieGtwN8cTRbqjxTA2+uHIQIDsTQcy6doO2r08SOM1ul+cWfVafrEfx5I1HVBhENVvUYwQwIgBCS1jv+qppThVZ6lyTu/1KiQZCJAVc3wcLZ3FGlELQcCH1yOsP6mUW1guKyzOtZO3mDoeFv7OqlLmb34YVHbmpoBAQQiACB3H9GK1FlmbdSfPVZOPbxC9MhHdONgraFoFqjtSI1WgQEFR1IhA7E0HMunaDtq9PEjjNbpfnFn1Wn6xH8eSNR1QYRDVb1GIQPeVdHh2sgF4/iljB+/m5TALz26r+En/vykmV8m+CCDvVKuIgYDsTQcy6doO2r08SOM1ul+cWfVafrEfx5I1HVBhENVvUYQtKa6ZwAAAIAAAACABAAAgCIGA95V0eHayAXj+KWMH7+blMAvPbqv4Sf+/KSZXyb4IIO9ELSmumcAAACAAAAAgAUAAIAAAA=="}, + +/* + Case: PSBT With invalid redeemscript typed key + Bytes in Hex: + +*/ + { "70736274ff0100550200000001279a2323a5dfb51fc45f220fa58b0fc13e1e3342792a85d7e36cd6333b5cbc390000000000ffffffff01a05aea0b000000001976a914ffe9c0061097cc3b636f2cb0460fa4fc427d2b4588ac0000000000010120955eea0b0000000017a9146345200f68d189e1adc0df1c4d16ea8f14c0dbeb87220203b1341ccba7683b6af4f1238cd6e97e7167d569fac47f1e48d47541844355bd4646304302200424b58effaaa694e1559ea5c93bbfd4a89064224055cdf070b6771469442d07021f5c8eb0fea6516d60b8acb33ad64ede60e8785bfb3aa94b99bdf86151db9a9a01020400220020771fd18ad459666dd49f3d564e3dbc42f4c84774e360ada16816a8ed488d5681010547522103b1341ccba7683b6af4f1238cd6e97e7167d569fac47f1e48d47541844355bd462103de55d1e1dac805e3f8a58c1fbf9b94c02f3dbaafe127fefca4995f26f82083bd52ae220603b1341ccba7683b6af4f1238cd6e97e7167d569fac47f1e48d47541844355bd4610b4a6ba67000000800000008004000080220603de55d1e1dac805e3f8a58c1fbf9b94c02f3dbaafe127fefca4995f26f82083bd10b4a6ba670000008000000080050000800000", +/* + Base64 String: +*/ + "cHNidP8BAFUCAAAAASeaIyOl37UfxF8iD6WLD8E+HjNCeSqF1+Ns1jM7XLw5AAAAAAD/////AaBa6gsAAAAAGXapFP/pwAYQl8w7Y28ssEYPpPxCfStFiKwAAAAAAAEBIJVe6gsAAAAAF6kUY0UgD2jRieGtwN8cTRbqjxTA2+uHIgIDsTQcy6doO2r08SOM1ul+cWfVafrEfx5I1HVBhENVvUZGMEMCIAQktY7/qqaU4VWepck7v9SokGQiQFXN8HC2dxRpRC0HAh9cjrD+plFtYLisszrWTt5g6Hhb+zqpS5m9+GFR25qaAQIEACIAIHcf0YrUWWZt1J89Vk49vEL0yEd042CtoWgWqO1IjVaBAQVHUiEDsTQcy6doO2r08SOM1ul+cWfVafrEfx5I1HVBhENVvUYhA95V0eHayAXj+KWMH7+blMAvPbqv4Sf+/KSZXyb4IIO9Uq4iBgOxNBzLp2g7avTxI4zW6X5xZ9Vp+sR/HkjUdUGEQ1W9RhC0prpnAAAAgAAAAIAEAACAIgYD3lXR4drIBeP4pYwfv5uUwC89uq/hJ/78pJlfJvggg70QtKa6ZwAAAIAAAACABQAAgAAA"}, + +/* + Case: PSBT With invalid witnessscript typed key + Bytes in Hex: + +*/ + { "70736274ff0100550200000001279a2323a5dfb51fc45f220fa58b0fc13e1e3342792a85d7e36cd6333b5cbc390000000000ffffffff01a05aea0b000000001976a914ffe9c0061097cc3b636f2cb0460fa4fc427d2b4588ac0000000000010120955eea0b0000000017a9146345200f68d189e1adc0df1c4d16ea8f14c0dbeb87220203b1341ccba7683b6af4f1238cd6e97e7167d569fac47f1e48d47541844355bd4646304302200424b58effaaa694e1559ea5c93bbfd4a89064224055cdf070b6771469442d07021f5c8eb0fea6516d60b8acb33ad64ede60e8785bfb3aa94b99bdf86151db9a9a010104220020771fd18ad459666dd49f3d564e3dbc42f4c84774e360ada16816a8ed488d568102050047522103b1341ccba7683b6af4f1238cd6e97e7167d569fac47f1e48d47541844355bd462103de55d1e1dac805e3f8a58c1fbf9b94c02f3dbaafe127fefca4995f26f82083bd52ae220603b1341ccba7683b6af4f1238cd6e97e7167d569fac47f1e48d47541844355bd4610b4a6ba67000000800000008004000080220603de55d1e1dac805e3f8a58c1fbf9b94c02f3dbaafe127fefca4995f26f82083bd10b4a6ba670000008000000080050000800000", +/* + Base64 String: +*/ + "cHNidP8BAFUCAAAAASeaIyOl37UfxF8iD6WLD8E+HjNCeSqF1+Ns1jM7XLw5AAAAAAD/////AaBa6gsAAAAAGXapFP/pwAYQl8w7Y28ssEYPpPxCfStFiKwAAAAAAAEBIJVe6gsAAAAAF6kUY0UgD2jRieGtwN8cTRbqjxTA2+uHIgIDsTQcy6doO2r08SOM1ul+cWfVafrEfx5I1HVBhENVvUZGMEMCIAQktY7/qqaU4VWepck7v9SokGQiQFXN8HC2dxRpRC0HAh9cjrD+plFtYLisszrWTt5g6Hhb+zqpS5m9+GFR25qaAQEEIgAgdx/RitRZZm3Unz1WTj28QvTIR3TjYK2haBao7UiNVoECBQBHUiEDsTQcy6doO2r08SOM1ul+cWfVafrEfx5I1HVBhENVvUYhA95V0eHayAXj+KWMH7+blMAvPbqv4Sf+/KSZXyb4IIO9Uq4iBgOxNBzLp2g7avTxI4zW6X5xZ9Vp+sR/HkjUdUGEQ1W9RhC0prpnAAAAgAAAAIAEAACAIgYD3lXR4drIBeP4pYwfv5uUwC89uq/hJ/78pJlfJvggg70QtKa6ZwAAAIAAAACABQAAgAAA"}, + +/* + Case: PSBT With invalid bip32 typed key + Bytes in Hex: + +*/ + { "70736274ff0100550200000001279a2323a5dfb51fc45f220fa58b0fc13e1e3342792a85d7e36cd6333b5cbc390000000000ffffffff01a05aea0b000000001976a914ffe9c0061097cc3b636f2cb0460fa4fc427d2b4588ac0000000000010120955eea0b0000000017a9146345200f68d189e1adc0df1c4d16ea8f14c0dbeb87220203b1341ccba7683b6af4f1238cd6e97e7167d569fac47f1e48d47541844355bd4646304302200424b58effaaa694e1559ea5c93bbfd4a89064224055cdf070b6771469442d07021f5c8eb0fea6516d60b8acb33ad64ede60e8785bfb3aa94b99bdf86151db9a9a010104220020771fd18ad459666dd49f3d564e3dbc42f4c84774e360ada16816a8ed488d5681010547522103b1341ccba7683b6af4f1238cd6e97e7167d569fac47f1e48d47541844355bd462103de55d1e1dac805e3f8a58c1fbf9b94c02f3dbaafe127fefca4995f26f82083bd52ae210603b1341ccba7683b6af4f1238cd6e97e7167d569fac47f1e48d47541844355bd10b4a6ba67000000800000008004000080220603de55d1e1dac805e3f8a58c1fbf9b94c02f3dbaafe127fefca4995f26f82083bd10b4a6ba670000008000000080050000800000", +/* + Base64 String: +*/ + "cHNidP8BAFUCAAAAASeaIyOl37UfxF8iD6WLD8E+HjNCeSqF1+Ns1jM7XLw5AAAAAAD/////AaBa6gsAAAAAGXapFP/pwAYQl8w7Y28ssEYPpPxCfStFiKwAAAAAAAEBIJVe6gsAAAAAF6kUY0UgD2jRieGtwN8cTRbqjxTA2+uHIgIDsTQcy6doO2r08SOM1ul+cWfVafrEfx5I1HVBhENVvUZGMEMCIAQktY7/qqaU4VWepck7v9SokGQiQFXN8HC2dxRpRC0HAh9cjrD+plFtYLisszrWTt5g6Hhb+zqpS5m9+GFR25qaAQEEIgAgdx/RitRZZm3Unz1WTj28QvTIR3TjYK2haBao7UiNVoEBBUdSIQOxNBzLp2g7avTxI4zW6X5xZ9Vp+sR/HkjUdUGEQ1W9RiED3lXR4drIBeP4pYwfv5uUwC89uq/hJ/78pJlfJvggg71SriEGA7E0HMunaDtq9PEjjNbpfnFn1Wn6xH8eSNR1QYRDVb0QtKa6ZwAAAIAAAACABAAAgCIGA95V0eHayAXj+KWMH7+blMAvPbqv4Sf+/KSZXyb4IIO9ELSmumcAAACAAAAAgAUAAIAAAA=="}, + +/* + Case: PSBT With invalid non-witness utxo typed key + Bytes in Hex: + +*/ + { "70736274ff01009a020000000258e87a21b56daf0c23be8e7070456c336f7cbaa5c8757924f545887bb2abdd750000000000ffffffff838d0427d0ec650a68aa46bb0b098aea4422c071b2ca78352a077959d07cea1d0100000000ffffffff0270aaf00800000000160014d85c2b71d0060b09c9886aeb815e50991dda124d00e1f5050000000016001400aea9a2e5f0f876a588df5546e8742d1d87008f0000000000020000bb0200000001aad73931018bd25f84ae400b68848be09db706eac2ac18298babee71ab656f8b0000000048473044022058f6fc7c6a33e1b31548d481c826c015bd30135aad42cd67790dab66d2ad243b02204a1ced2604c6735b6393e5b41691dd78b00f0c5942fb9f751856faa938157dba01feffffff0280f0fa020000000017a9140fb9463421696b82c833af241c78c17ddbde493487d0f20a270100000017a91429ca74f8a08f81999428185c97b5d852e4063f6187650000000107da00473044022074018ad4180097b873323c0015720b3684cc8123891048e7dbcd9b55ad679c99022073d369b740e3eb53dcefa33823c8070514ca55a7dd9544f157c167913261118c01483045022100f61038b308dc1da865a34852746f015772934208c6d24454393cd99bdf2217770220056e675a675a6d0a02b85b14e5e29074d8a25a9b5760bea2816f661910a006ea01475221029583bf39ae0a609747ad199addd634fa6108559d6c5cd39b4c2183f1ab96e07f2102dab61ff49a14db6a7d02b0cd1fbb78fc4b18312b5b4e54dae4dba2fbfef536d752ae0001012000c2eb0b0000000017a914b7f5faf40e3d40a5a459b1db3535f2b72fa921e8870107232200208c2353173743b595dfb4a07b72ba8e42e3797da74e87fe7d9d7497e3b20289030108da0400473044022062eb7a556107a7c73f45ac4ab5a1dddf6f7075fb1275969a7f383efff784bcb202200c05dbb7470dbf2f08557dd356c7325c1ed30913e996cd3840945db12228da5f01473044022065f45ba5998b59a27ffe1a7bed016af1f1f90d54b3aa8f7450aa5f56a25103bd02207f724703ad1edb96680b284b56d4ffcb88f7fb759eabbe08aa30f29b851383d20147522103089dc10c7ac6db54f91329af617333db388cead0c231f723379d1b99030b02dc21023add904f3d6dcf59ddb906b0dee23529b7ffb9ed50e5e86151926860221f0e7352ae00220203a9a4c37f5996d3aa25dbac6b570af0650394492942460b354753ed9eeca5877110d90c6a4f000000800000008004000080002202027f6399757d2eff55a136ad02c684b1838b6556e5f1b6b34282a94b6b5005109610d90c6a4f00000080000000800500008000", +/* + Base64 String: +*/ + "cHNidP8BAJoCAAAAAljoeiG1ba8MI76OcHBFbDNvfLqlyHV5JPVFiHuyq911AAAAAAD/////g40EJ9DsZQpoqka7CwmK6kQiwHGyyng1Kgd5WdB86h0BAAAAAP////8CcKrwCAAAAAAWABTYXCtx0AYLCcmIauuBXlCZHdoSTQDh9QUAAAAAFgAUAK6pouXw+HaliN9VRuh0LR2HAI8AAAAAAAIAALsCAAAAAarXOTEBi9JfhK5AC2iEi+CdtwbqwqwYKYur7nGrZW+LAAAAAEhHMEQCIFj2/HxqM+GzFUjUgcgmwBW9MBNarULNZ3kNq2bSrSQ7AiBKHO0mBMZzW2OT5bQWkd14sA8MWUL7n3UYVvqpOBV9ugH+////AoDw+gIAAAAAF6kUD7lGNCFpa4LIM68kHHjBfdveSTSH0PIKJwEAAAAXqRQpynT4oI+BmZQoGFyXtdhS5AY/YYdlAAAAAQfaAEcwRAIgdAGK1BgAl7hzMjwAFXILNoTMgSOJEEjn282bVa1nnJkCIHPTabdA4+tT3O+jOCPIBwUUylWn3ZVE8VfBZ5EyYRGMAUgwRQIhAPYQOLMI3B2oZaNIUnRvAVdyk0IIxtJEVDk82ZvfIhd3AiAFbmdaZ1ptCgK4WxTl4pB02KJam1dgvqKBb2YZEKAG6gFHUiEClYO/Oa4KYJdHrRma3dY0+mEIVZ1sXNObTCGD8auW4H8hAtq2H/SaFNtqfQKwzR+7ePxLGDErW05U2uTbovv+9TbXUq4AAQEgAMLrCwAAAAAXqRS39fr0Dj1ApaRZsds1NfK3L6kh6IcBByMiACCMI1MXN0O1ld+0oHtyuo5C43l9p06H/n2ddJfjsgKJAwEI2gQARzBEAiBi63pVYQenxz9FrEq1od3fb3B1+xJ1lpp/OD7/94S8sgIgDAXbt0cNvy8IVX3TVscyXB7TCRPpls04QJRdsSIo2l8BRzBEAiBl9FulmYtZon/+GnvtAWrx8fkNVLOqj3RQql9WolEDvQIgf3JHA60e25ZoCyhLVtT/y4j3+3Weq74IqjDym4UTg9IBR1IhAwidwQx6xttU+RMpr2FzM9s4jOrQwjH3IzedG5kDCwLcIQI63ZBPPW3PWd25BrDe4jUpt/+57VDl6GFRkmhgIh8Oc1KuACICA6mkw39ZltOqJdusa1cK8GUDlEkpQkYLNUdT7Z7spYdxENkMak8AAACAAAAAgAQAAIAAIgICf2OZdX0u/1WhNq0CxoSxg4tlVuXxtrNCgqlLa1AFEJYQ2QxqTwAAAIAAAACABQAAgAA="}, + +/* + Case: PSBT With invalid final scriptsig typed key + Bytes in Hex: + +*/ + { "70736274ff01009a020000000258e87a21b56daf0c23be8e7070456c336f7cbaa5c8757924f545887bb2abdd750000000000ffffffff838d0427d0ec650a68aa46bb0b098aea4422c071b2ca78352a077959d07cea1d0100000000ffffffff0270aaf00800000000160014d85c2b71d0060b09c9886aeb815e50991dda124d00e1f5050000000016001400aea9a2e5f0f876a588df5546e8742d1d87008f00000000000100bb0200000001aad73931018bd25f84ae400b68848be09db706eac2ac18298babee71ab656f8b0000000048473044022058f6fc7c6a33e1b31548d481c826c015bd30135aad42cd67790dab66d2ad243b02204a1ced2604c6735b6393e5b41691dd78b00f0c5942fb9f751856faa938157dba01feffffff0280f0fa020000000017a9140fb9463421696b82c833af241c78c17ddbde493487d0f20a270100000017a91429ca74f8a08f81999428185c97b5d852e4063f618765000000020700da00473044022074018ad4180097b873323c0015720b3684cc8123891048e7dbcd9b55ad679c99022073d369b740e3eb53dcefa33823c8070514ca55a7dd9544f157c167913261118c01483045022100f61038b308dc1da865a34852746f015772934208c6d24454393cd99bdf2217770220056e675a675a6d0a02b85b14e5e29074d8a25a9b5760bea2816f661910a006ea01475221029583bf39ae0a609747ad199addd634fa6108559d6c5cd39b4c2183f1ab96e07f2102dab61ff49a14db6a7d02b0cd1fbb78fc4b18312b5b4e54dae4dba2fbfef536d752ae0001012000c2eb0b0000000017a914b7f5faf40e3d40a5a459b1db3535f2b72fa921e8870107232200208c2353173743b595dfb4a07b72ba8e42e3797da74e87fe7d9d7497e3b20289030108da0400473044022062eb7a556107a7c73f45ac4ab5a1dddf6f7075fb1275969a7f383efff784bcb202200c05dbb7470dbf2f08557dd356c7325c1ed30913e996cd3840945db12228da5f01473044022065f45ba5998b59a27ffe1a7bed016af1f1f90d54b3aa8f7450aa5f56a25103bd02207f724703ad1edb96680b284b56d4ffcb88f7fb759eabbe08aa30f29b851383d20147522103089dc10c7ac6db54f91329af617333db388cead0c231f723379d1b99030b02dc21023add904f3d6dcf59ddb906b0dee23529b7ffb9ed50e5e86151926860221f0e7352ae00220203a9a4c37f5996d3aa25dbac6b570af0650394492942460b354753ed9eeca5877110d90c6a4f000000800000008004000080002202027f6399757d2eff55a136ad02c684b1838b6556e5f1b6b34282a94b6b5005109610d90c6a4f00000080000000800500008000", +/* + Base64 String: +*/ + "cHNidP8BAJoCAAAAAljoeiG1ba8MI76OcHBFbDNvfLqlyHV5JPVFiHuyq911AAAAAAD/////g40EJ9DsZQpoqka7CwmK6kQiwHGyyng1Kgd5WdB86h0BAAAAAP////8CcKrwCAAAAAAWABTYXCtx0AYLCcmIauuBXlCZHdoSTQDh9QUAAAAAFgAUAK6pouXw+HaliN9VRuh0LR2HAI8AAAAAAAEAuwIAAAABqtc5MQGL0l+ErkALaISL4J23BurCrBgpi6vucatlb4sAAAAASEcwRAIgWPb8fGoz4bMVSNSByCbAFb0wE1qtQs1neQ2rZtKtJDsCIEoc7SYExnNbY5PltBaR3XiwDwxZQvufdRhW+qk4FX26Af7///8CgPD6AgAAAAAXqRQPuUY0IWlrgsgzryQceMF9295JNIfQ8gonAQAAABepFCnKdPigj4GZlCgYXJe12FLkBj9hh2UAAAACBwDaAEcwRAIgdAGK1BgAl7hzMjwAFXILNoTMgSOJEEjn282bVa1nnJkCIHPTabdA4+tT3O+jOCPIBwUUylWn3ZVE8VfBZ5EyYRGMAUgwRQIhAPYQOLMI3B2oZaNIUnRvAVdyk0IIxtJEVDk82ZvfIhd3AiAFbmdaZ1ptCgK4WxTl4pB02KJam1dgvqKBb2YZEKAG6gFHUiEClYO/Oa4KYJdHrRma3dY0+mEIVZ1sXNObTCGD8auW4H8hAtq2H/SaFNtqfQKwzR+7ePxLGDErW05U2uTbovv+9TbXUq4AAQEgAMLrCwAAAAAXqRS39fr0Dj1ApaRZsds1NfK3L6kh6IcBByMiACCMI1MXN0O1ld+0oHtyuo5C43l9p06H/n2ddJfjsgKJAwEI2gQARzBEAiBi63pVYQenxz9FrEq1od3fb3B1+xJ1lpp/OD7/94S8sgIgDAXbt0cNvy8IVX3TVscyXB7TCRPpls04QJRdsSIo2l8BRzBEAiBl9FulmYtZon/+GnvtAWrx8fkNVLOqj3RQql9WolEDvQIgf3JHA60e25ZoCyhLVtT/y4j3+3Weq74IqjDym4UTg9IBR1IhAwidwQx6xttU+RMpr2FzM9s4jOrQwjH3IzedG5kDCwLcIQI63ZBPPW3PWd25BrDe4jUpt/+57VDl6GFRkmhgIh8Oc1KuACICA6mkw39ZltOqJdusa1cK8GUDlEkpQkYLNUdT7Z7spYdxENkMak8AAACAAAAAgAQAAIAAIgICf2OZdX0u/1WhNq0CxoSxg4tlVuXxtrNCgqlLa1AFEJYQ2QxqTwAAAIAAAACABQAAgAA="}, + +/* + Case: PSBT With invalid final script witness typed key + Bytes in Hex: + +*/ + { "70736274ff01009a020000000258e87a21b56daf0c23be8e7070456c336f7cbaa5c8757924f545887bb2abdd750000000000ffffffff838d0427d0ec650a68aa46bb0b098aea4422c071b2ca78352a077959d07cea1d0100000000ffffffff0270aaf00800000000160014d85c2b71d0060b09c9886aeb815e50991dda124d00e1f5050000000016001400aea9a2e5f0f876a588df5546e8742d1d87008f00000000000100bb0200000001aad73931018bd25f84ae400b68848be09db706eac2ac18298babee71ab656f8b0000000048473044022058f6fc7c6a33e1b31548d481c826c015bd30135aad42cd67790dab66d2ad243b02204a1ced2604c6735b6393e5b41691dd78b00f0c5942fb9f751856faa938157dba01feffffff0280f0fa020000000017a9140fb9463421696b82c833af241c78c17ddbde493487d0f20a270100000017a91429ca74f8a08f81999428185c97b5d852e4063f6187650000000107da00473044022074018ad4180097b873323c0015720b3684cc8123891048e7dbcd9b55ad679c99022073d369b740e3eb53dcefa33823c8070514ca55a7dd9544f157c167913261118c01483045022100f61038b308dc1da865a34852746f015772934208c6d24454393cd99bdf2217770220056e675a675a6d0a02b85b14e5e29074d8a25a9b5760bea2816f661910a006ea01475221029583bf39ae0a609747ad199addd634fa6108559d6c5cd39b4c2183f1ab96e07f2102dab61ff49a14db6a7d02b0cd1fbb78fc4b18312b5b4e54dae4dba2fbfef536d752ae0001012000c2eb0b0000000017a914b7f5faf40e3d40a5a459b1db3535f2b72fa921e8870107232200208c2353173743b595dfb4a07b72ba8e42e3797da74e87fe7d9d7497e3b2028903020800da0400473044022062eb7a556107a7c73f45ac4ab5a1dddf6f7075fb1275969a7f383efff784bcb202200c05dbb7470dbf2f08557dd356c7325c1ed30913e996cd3840945db12228da5f01473044022065f45ba5998b59a27ffe1a7bed016af1f1f90d54b3aa8f7450aa5f56a25103bd02207f724703ad1edb96680b284b56d4ffcb88f7fb759eabbe08aa30f29b851383d20147522103089dc10c7ac6db54f91329af617333db388cead0c231f723379d1b99030b02dc21023add904f3d6dcf59ddb906b0dee23529b7ffb9ed50e5e86151926860221f0e7352ae00220203a9a4c37f5996d3aa25dbac6b570af0650394492942460b354753ed9eeca5877110d90c6a4f000000800000008004000080002202027f6399757d2eff55a136ad02c684b1838b6556e5f1b6b34282a94b6b5005109610d90c6a4f00000080000000800500008000", +/* + Base64 String: +*/ + "cHNidP8BAJoCAAAAAljoeiG1ba8MI76OcHBFbDNvfLqlyHV5JPVFiHuyq911AAAAAAD/////g40EJ9DsZQpoqka7CwmK6kQiwHGyyng1Kgd5WdB86h0BAAAAAP////8CcKrwCAAAAAAWABTYXCtx0AYLCcmIauuBXlCZHdoSTQDh9QUAAAAAFgAUAK6pouXw+HaliN9VRuh0LR2HAI8AAAAAAAEAuwIAAAABqtc5MQGL0l+ErkALaISL4J23BurCrBgpi6vucatlb4sAAAAASEcwRAIgWPb8fGoz4bMVSNSByCbAFb0wE1qtQs1neQ2rZtKtJDsCIEoc7SYExnNbY5PltBaR3XiwDwxZQvufdRhW+qk4FX26Af7///8CgPD6AgAAAAAXqRQPuUY0IWlrgsgzryQceMF9295JNIfQ8gonAQAAABepFCnKdPigj4GZlCgYXJe12FLkBj9hh2UAAAABB9oARzBEAiB0AYrUGACXuHMyPAAVcgs2hMyBI4kQSOfbzZtVrWecmQIgc9Npt0Dj61Pc76M4I8gHBRTKVafdlUTxV8FnkTJhEYwBSDBFAiEA9hA4swjcHahlo0hSdG8BV3KTQgjG0kRUOTzZm98iF3cCIAVuZ1pnWm0KArhbFOXikHTYolqbV2C+ooFvZhkQoAbqAUdSIQKVg785rgpgl0etGZrd1jT6YQhVnWxc05tMIYPxq5bgfyEC2rYf9JoU22p9ArDNH7t4/EsYMStbTlTa5Nui+/71NtdSrgABASAAwusLAAAAABepFLf1+vQOPUClpFmx2zU18rcvqSHohwEHIyIAIIwjUxc3Q7WV37Sge3K6jkLjeX2nTof+fZ10l+OyAokDAggA2gQARzBEAiBi63pVYQenxz9FrEq1od3fb3B1+xJ1lpp/OD7/94S8sgIgDAXbt0cNvy8IVX3TVscyXB7TCRPpls04QJRdsSIo2l8BRzBEAiBl9FulmYtZon/+GnvtAWrx8fkNVLOqj3RQql9WolEDvQIgf3JHA60e25ZoCyhLVtT/y4j3+3Weq74IqjDym4UTg9IBR1IhAwidwQx6xttU+RMpr2FzM9s4jOrQwjH3IzedG5kDCwLcIQI63ZBPPW3PWd25BrDe4jUpt/+57VDl6GFRkmhgIh8Oc1KuACICA6mkw39ZltOqJdusa1cK8GUDlEkpQkYLNUdT7Z7spYdxENkMak8AAACAAAAAgAQAAIAAIgICf2OZdX0u/1WhNq0CxoSxg4tlVuXxtrNCgqlLa1AFEJYQ2QxqTwAAAIAAAACABQAAgAA="}, + +/* + Case: PSBT With invalid pubkey in output BIP 32 derivation paths typed key + Bytes in Hex: + +*/ + { "70736274ff01009a020000000258e87a21b56daf0c23be8e7070456c336f7cbaa5c8757924f545887bb2abdd750000000000ffffffff838d0427d0ec650a68aa46bb0b098aea4422c071b2ca78352a077959d07cea1d0100000000ffffffff0270aaf00800000000160014d85c2b71d0060b09c9886aeb815e50991dda124d00e1f5050000000016001400aea9a2e5f0f876a588df5546e8742d1d87008f00000000000100bb0200000001aad73931018bd25f84ae400b68848be09db706eac2ac18298babee71ab656f8b0000000048473044022058f6fc7c6a33e1b31548d481c826c015bd30135aad42cd67790dab66d2ad243b02204a1ced2604c6735b6393e5b41691dd78b00f0c5942fb9f751856faa938157dba01feffffff0280f0fa020000000017a9140fb9463421696b82c833af241c78c17ddbde493487d0f20a270100000017a91429ca74f8a08f81999428185c97b5d852e4063f6187650000000107da00473044022074018ad4180097b873323c0015720b3684cc8123891048e7dbcd9b55ad679c99022073d369b740e3eb53dcefa33823c8070514ca55a7dd9544f157c167913261118c01483045022100f61038b308dc1da865a34852746f015772934208c6d24454393cd99bdf2217770220056e675a675a6d0a02b85b14e5e29074d8a25a9b5760bea2816f661910a006ea01475221029583bf39ae0a609747ad199addd634fa6108559d6c5cd39b4c2183f1ab96e07f2102dab61ff49a14db6a7d02b0cd1fbb78fc4b18312b5b4e54dae4dba2fbfef536d752ae0001012000c2eb0b0000000017a914b7f5faf40e3d40a5a459b1db3535f2b72fa921e8870107232200208c2353173743b595dfb4a07b72ba8e42e3797da74e87fe7d9d7497e3b20289030108da0400473044022062eb7a556107a7c73f45ac4ab5a1dddf6f7075fb1275969a7f383efff784bcb202200c05dbb7470dbf2f08557dd356c7325c1ed30913e996cd3840945db12228da5f01473044022065f45ba5998b59a27ffe1a7bed016af1f1f90d54b3aa8f7450aa5f56a25103bd02207f724703ad1edb96680b284b56d4ffcb88f7fb759eabbe08aa30f29b851383d20147522103089dc10c7ac6db54f91329af617333db388cead0c231f723379d1b99030b02dc21023add904f3d6dcf59ddb906b0dee23529b7ffb9ed50e5e86151926860221f0e7352ae00210203a9a4c37f5996d3aa25dbac6b570af0650394492942460b354753ed9eeca58710d90c6a4f000000800000008004000080002202027f6399757d2eff55a136ad02c684b1838b6556e5f1b6b34282a94b6b5005109610d90c6a4f00000080000000800500008000", +/* + Base64 String: +*/ + "cHNidP8BAJoCAAAAAljoeiG1ba8MI76OcHBFbDNvfLqlyHV5JPVFiHuyq911AAAAAAD/////g40EJ9DsZQpoqka7CwmK6kQiwHGyyng1Kgd5WdB86h0BAAAAAP////8CcKrwCAAAAAAWABTYXCtx0AYLCcmIauuBXlCZHdoSTQDh9QUAAAAAFgAUAK6pouXw+HaliN9VRuh0LR2HAI8AAAAAAAEAuwIAAAABqtc5MQGL0l+ErkALaISL4J23BurCrBgpi6vucatlb4sAAAAASEcwRAIgWPb8fGoz4bMVSNSByCbAFb0wE1qtQs1neQ2rZtKtJDsCIEoc7SYExnNbY5PltBaR3XiwDwxZQvufdRhW+qk4FX26Af7///8CgPD6AgAAAAAXqRQPuUY0IWlrgsgzryQceMF9295JNIfQ8gonAQAAABepFCnKdPigj4GZlCgYXJe12FLkBj9hh2UAAAABB9oARzBEAiB0AYrUGACXuHMyPAAVcgs2hMyBI4kQSOfbzZtVrWecmQIgc9Npt0Dj61Pc76M4I8gHBRTKVafdlUTxV8FnkTJhEYwBSDBFAiEA9hA4swjcHahlo0hSdG8BV3KTQgjG0kRUOTzZm98iF3cCIAVuZ1pnWm0KArhbFOXikHTYolqbV2C+ooFvZhkQoAbqAUdSIQKVg785rgpgl0etGZrd1jT6YQhVnWxc05tMIYPxq5bgfyEC2rYf9JoU22p9ArDNH7t4/EsYMStbTlTa5Nui+/71NtdSrgABASAAwusLAAAAABepFLf1+vQOPUClpFmx2zU18rcvqSHohwEHIyIAIIwjUxc3Q7WV37Sge3K6jkLjeX2nTof+fZ10l+OyAokDAQjaBABHMEQCIGLrelVhB6fHP0WsSrWh3d9vcHX7EnWWmn84Pv/3hLyyAiAMBdu3Rw2/LwhVfdNWxzJcHtMJE+mWzThAlF2xIijaXwFHMEQCIGX0W6WZi1mif/4ae+0BavHx+Q1Us6qPdFCqX1aiUQO9AiB/ckcDrR7blmgLKEtW1P/LiPf7dZ6rvgiqMPKbhROD0gFHUiEDCJ3BDHrG21T5EymvYXMz2ziM6tDCMfcjN50bmQMLAtwhAjrdkE89bc9Z3bkGsN7iNSm3/7ntUOXoYVGSaGAiHw5zUq4AIQIDqaTDf1mW06ol26xrVwrwZQOUSSlCRgs1R1PtnuylhxDZDGpPAAAAgAAAAIAEAACAACICAn9jmXV9Lv9VoTatAsaEsYOLZVbl8bazQoKpS2tQBRCWENkMak8AAACAAAAAgAUAAIAA"}, + +/* + Case: PSBT With invalid input sighash type typed key + Bytes in Hex: + +*/ + { "70736274ff0100730200000001301ae986e516a1ec8ac5b4bc6573d32f83b465e23ad76167d68b38e730b4dbdb0000000000ffffffff02747b01000000000017a91403aa17ae882b5d0d54b25d63104e4ffece7b9ea2876043993b0000000017a914b921b1ba6f722e4bfa83b6557a3139986a42ec8387000000000001011f00ca9a3b00000000160014d2d94b64ae08587eefc8eeb187c601e939f9037c0203000100000000010016001462e9e982fff34dd8239610316b090cd2a3b747cb000100220020876bad832f1d168015ed41232a9ea65a1815d9ef13c0ef8759f64b5b2b278a65010125512103b7ce23a01c5b4bf00a642537cdfabb315b668332867478ef51309d2bd57f8a8751ae00", +/* + Base64 String: +*/ + "cHNidP8BAHMCAAAAATAa6YblFqHsisW0vGVz0y+DtGXiOtdhZ9aLOOcwtNvbAAAAAAD/////AnR7AQAAAAAAF6kUA6oXrogrXQ1Usl1jEE5P/s57nqKHYEOZOwAAAAAXqRS5IbG6b3IuS/qDtlV6MTmYakLsg4cAAAAAAAEBHwDKmjsAAAAAFgAU0tlLZK4IWH7vyO6xh8YB6Tn5A3wCAwABAAAAAAEAFgAUYunpgv/zTdgjlhAxawkM0qO3R8sAAQAiACCHa62DLx0WgBXtQSMqnqZaGBXZ7xPA74dZ9ktbKyeKZQEBJVEhA7fOI6AcW0vwCmQlN836uzFbZoMyhnR471EwnSvVf4qHUa4A"}, + +/* + Case: PSBT With invalid output redeemScript typed key + Bytes in Hex: + +*/ + { "70736274ff0100730200000001301ae986e516a1ec8ac5b4bc6573d32f83b465e23ad76167d68b38e730b4dbdb0000000000ffffffff02747b01000000000017a91403aa17ae882b5d0d54b25d63104e4ffece7b9ea2876043993b0000000017a914b921b1ba6f722e4bfa83b6557a3139986a42ec8387000000000001011f00ca9a3b00000000160014d2d94b64ae08587eefc8eeb187c601e939f9037c0002000016001462e9e982fff34dd8239610316b090cd2a3b747cb000100220020876bad832f1d168015ed41232a9ea65a1815d9ef13c0ef8759f64b5b2b278a65010125512103b7ce23a01c5b4bf00a642537cdfabb315b668332867478ef51309d2bd57f8a8751ae00", +/* + Base64 String: +*/ + "cHNidP8BAHMCAAAAATAa6YblFqHsisW0vGVz0y+DtGXiOtdhZ9aLOOcwtNvbAAAAAAD/////AnR7AQAAAAAAF6kUA6oXrogrXQ1Usl1jEE5P/s57nqKHYEOZOwAAAAAXqRS5IbG6b3IuS/qDtlV6MTmYakLsg4cAAAAAAAEBHwDKmjsAAAAAFgAU0tlLZK4IWH7vyO6xh8YB6Tn5A3wAAgAAFgAUYunpgv/zTdgjlhAxawkM0qO3R8sAAQAiACCHa62DLx0WgBXtQSMqnqZaGBXZ7xPA74dZ9ktbKyeKZQEBJVEhA7fOI6AcW0vwCmQlN836uzFbZoMyhnR471EwnSvVf4qHUa4A"}, + +/* + Case: PSBT With invalid output witnessScript typed key + Bytes in Hex: + +*/ + { "70736274ff0100730200000001301ae986e516a1ec8ac5b4bc6573d32f83b465e23ad76167d68b38e730b4dbdb0000000000ffffffff02747b01000000000017a91403aa17ae882b5d0d54b25d63104e4ffece7b9ea2876043993b0000000017a914b921b1ba6f722e4bfa83b6557a3139986a42ec8387000000000001011f00ca9a3b00000000160014d2d94b64ae08587eefc8eeb187c601e939f9037c00010016001462e9e982fff34dd8239610316b090cd2a3b747cb000100220020876bad832f1d168015ed41232a9ea65a1815d9ef13c0ef8759f64b5b2b278a6521010025512103b7ce23a01c5b4bf00a642537cdfabb315b668332867478ef51309d06d57f8a8751ae00", +/* + Base64 String: +*/ + "cHNidP8BAHMCAAAAATAa6YblFqHsisW0vGVz0y+DtGXiOtdhZ9aLOOcwtNvbAAAAAAD/////AnR7AQAAAAAAF6kUA6oXrogrXQ1Usl1jEE5P/s57nqKHYEOZOwAAAAAXqRS5IbG6b3IuS/qDtlV6MTmYakLsg4cAAAAAAAEBHwDKmjsAAAAAFgAU0tlLZK4IWH7vyO6xh8YB6Tn5A3wAAQAWABRi6emC//NN2COWEDFrCQzSo7dHywABACIAIIdrrYMvHRaAFe1BIyqeploYFdnvE8Dvh1n2S1srJ4plIQEAJVEhA7fOI6AcW0vwCmQlN836uzFbZoMyhnR471EwnQbVf4qHUa4A"}, + +/* The following are a bunch of PSBTs with duplicate 0 length scripts */ + { "70736274ff01002a02000000000140420f000000000017a9146e91b72d5593e7d4391e2ff44e91e985c31641f08700000000000100000100016a00", + "cHNidP8BACoCAAAAAAFAQg8AAAAAABepFG6Rty1Vk+fUOR4v9E6R6YXDFkHwhwAAAAAAAQAAAQABagA="}, + { "70736274ff0100330100000001111111111111111111111111111111111111facade11111111111111111111117f00000000ffffffff000000000000010109ffffffffffffffff000101090000cafe000000000000", + "cHNidP8BADMBAAAAAREREREREREREREREREREREREfrK3hERERERERERERERfwAAAAD/////AAAAAAAAAQEJ//////////8AAQEJAADK/gAAAAAAAA=="}, + { "70736274ff0100330100000001111111111111111111111111111111111111facade11111111111111111111117f00000000ffffffff000000000000010304addedfee0103040100000000", + "cHNidP8BADMBAAAAAREREREREREREREREREREREREfrK3hERERERERERERERfwAAAAD/////AAAAAAAAAQMErd7f7gEDBAEAAAAA"}, + { "70736274ff0100330100000001111111111111111111111111111111111111facade11111111111111111111117f00000000ffffffff0000000000000104000104016a00", + "cHNidP8BADMBAAAAAREREREREREREREREREREREREfrK3hERERERERERERERfwAAAAD/////AAAAAAAAAQQAAQQBagA="}, + { "70736274ff0100330100000001111111111111111111111111111111111111facade11111111111111111111117f00000000ffffffff00000000000001010900e1f50500000000000105000105015100", + "cHNidP8BADMBAAAAAREREREREREREREREREREREREfrK3hERERERERERERERfwAAAAD/////AAAAAAAAAQEJAOH1BQAAAAAAAQUAAQUBUQA="}, + { "70736274ff0100330100000001111111111111111111111111111111111111facade11111111111111111111117f00000000ffffffff0000000000000107000107015100", + "cHNidP8BADMBAAAAAREREREREREREREREREREREREfrK3hERERERERERERERfwAAAAD/////AAAAAAAAAQcAAQcBUQA="}, + { "70736274ff0100330100000001111111111111111111111111111111111111facade11111111111111111111117f00000000ffffffff00000000000001010900e1f50500000000000108010001080301015100", + "cHNidP8BADMBAAAAAREREREREREREREREREREREREfrK3hERERERERERERERfwAAAAD/////AAAAAAAAAQEJAOH1BQAAAAAAAQgBAAEIAwEBUQA="}, + +/* Unsupported version number */ + { "70736274ff01fb04010000000100750200000001268171371edff285e937adeea4b37b78000c0566cbb3ad64641713ca42171bf60000000000feffffff02d3dff505000000001976a914d0c59903c5bac2868760e90fd521a4665aa7652088ac00e1f5050000000017a9143545e6e33b832c47050f24d3eeb93c9c03948bc787b32e1300000100fda5010100000000010289a3c71eab4d20e0371bbba4cc698fa295c9463afa2e397f8533ccb62f9567e50100000017160014be18d152a9b012039daf3da7de4f53349eecb985ffffffff86f8aa43a71dff1448893a530a7237ef6b4608bbb2dd2d0171e63aec6a4890b40100000017160014fe3e9ef1a745e974d902c4355943abcb34bd5353ffffffff0200c2eb0b000000001976a91485cff1097fd9e008bb34af709c62197b38978a4888ac72fef84e2c00000017a914339725ba21efd62ac753a9bcd067d6c7a6a39d05870247304402202712be22e0270f394f568311dc7ca9a68970b8025fdd3b240229f07f8a5f3a240220018b38d7dcd314e734c9276bd6fb40f673325bc4baa144c800d2f2f02db2765c012103d2e15674941bad4a996372cb87e1856d3652606d98562fe39c5e9e7e413f210502483045022100d12b852d85dcd961d2f5f4ab660654df6eedcc794c0c33ce5cc309ffb5fce58d022067338a8e0e1725c197fb1a88af59f51e44e4255b20167c8684031c05d1f2592a01210223b72beef0965d10be0778efecd61fcac6f79a4ea169393380734464f84f2ab300000000000000", + "cHNidP8B+wQBAAAAAQB1AgAAAAEmgXE3Ht/yhek3re6ks3t4AAwFZsuzrWRkFxPKQhcb9gAAAAAA/v///wLT3/UFAAAAABl2qRTQxZkDxbrChodg6Q/VIaRmWqdlIIisAOH1BQAAAAAXqRQ1RebjO4MsRwUPJNPuuTycA5SLx4ezLhMAAAEA/aUBAQAAAAABAomjxx6rTSDgNxu7pMxpj6KVyUY6+i45f4UzzLYvlWflAQAAABcWABS+GNFSqbASA52vPafeT1M0nuy5hf////+G+KpDpx3/FEiJOlMKcjfva0YIu7LdLQFx5jrsakiQtAEAAAAXFgAU/j6e8adF6XTZAsQ1WUOryzS9U1P/////AgDC6wsAAAAAGXapFIXP8Ql/2eAIuzSvcJxiGXs4l4pIiKxy/vhOLAAAABepFDOXJboh79Yqx1OpvNBn1semo50FhwJHMEQCICcSviLgJw85T1aDEdx8qaaJcLgCX907JAIp8H+KXzokAiABizjX3NMU5zTJJ2vW+0D2czJbxLqhRMgA0vLwLbJ2XAEhA9LhVnSUG61KmWNyy4fhhW02UmBtmFYv45xenn5BPyEFAkgwRQIhANErhS2F3Nlh0vX0q2YGVN9u7cx5TAwzzlzDCf+1/OWNAiBnM4qODhclwZf7GoivWfUeROQlWyAWfIaEAxwF0fJZKgEhAiO3K+7wll0Qvgd47+zWH8rG95pOoWk5M4BzRGT4TyqzAAAAAAAAAA=="}, + +}; + +/* The following are valid PSBTs: + */ +static const struct psbt_test valid_psbts[] = { +/* + Case: PSBT with one P2PKH input. Outputs are empty + Bytes in Hex: + +*/ + { "70736274ff0100750200000001268171371edff285e937adeea4b37b78000c0566cbb3ad64641713ca42171bf60000000000feffffff02d3dff505000000001976a914d0c59903c5bac2868760e90fd521a4665aa7652088ac00e1f5050000000017a9143545e6e33b832c47050f24d3eeb93c9c03948bc787b32e1300000100fda5010100000000010289a3c71eab4d20e0371bbba4cc698fa295c9463afa2e397f8533ccb62f9567e50100000017160014be18d152a9b012039daf3da7de4f53349eecb985ffffffff86f8aa43a71dff1448893a530a7237ef6b4608bbb2dd2d0171e63aec6a4890b40100000017160014fe3e9ef1a745e974d902c4355943abcb34bd5353ffffffff0200c2eb0b000000001976a91485cff1097fd9e008bb34af709c62197b38978a4888ac72fef84e2c00000017a914339725ba21efd62ac753a9bcd067d6c7a6a39d05870247304402202712be22e0270f394f568311dc7ca9a68970b8025fdd3b240229f07f8a5f3a240220018b38d7dcd314e734c9276bd6fb40f673325bc4baa144c800d2f2f02db2765c012103d2e15674941bad4a996372cb87e1856d3652606d98562fe39c5e9e7e413f210502483045022100d12b852d85dcd961d2f5f4ab660654df6eedcc794c0c33ce5cc309ffb5fce58d022067338a8e0e1725c197fb1a88af59f51e44e4255b20167c8684031c05d1f2592a01210223b72beef0965d10be0778efecd61fcac6f79a4ea169393380734464f84f2ab300000000000000", +/* + Base64 String: +*/ + "cHNidP8BAHUCAAAAASaBcTce3/KF6Tet7qSze3gADAVmy7OtZGQXE8pCFxv2AAAAAAD+////AtPf9QUAAAAAGXapFNDFmQPFusKGh2DpD9UhpGZap2UgiKwA4fUFAAAAABepFDVF5uM7gyxHBQ8k0+65PJwDlIvHh7MuEwAAAQD9pQEBAAAAAAECiaPHHqtNIOA3G7ukzGmPopXJRjr6Ljl/hTPMti+VZ+UBAAAAFxYAFL4Y0VKpsBIDna89p95PUzSe7LmF/////4b4qkOnHf8USIk6UwpyN+9rRgi7st0tAXHmOuxqSJC0AQAAABcWABT+Pp7xp0XpdNkCxDVZQ6vLNL1TU/////8CAMLrCwAAAAAZdqkUhc/xCX/Z4Ai7NK9wnGIZeziXikiIrHL++E4sAAAAF6kUM5cluiHv1irHU6m80GfWx6ajnQWHAkcwRAIgJxK+IuAnDzlPVoMR3HyppolwuAJf3TskAinwf4pfOiQCIAGLONfc0xTnNMkna9b7QPZzMlvEuqFEyADS8vAtsnZcASED0uFWdJQbrUqZY3LLh+GFbTZSYG2YVi/jnF6efkE/IQUCSDBFAiEA0SuFLYXc2WHS9fSrZgZU327tzHlMDDPOXMMJ/7X85Y0CIGczio4OFyXBl/saiK9Z9R5E5CVbIBZ8hoQDHAXR8lkqASECI7cr7vCWXRC+B3jv7NYfysb3mk6haTkzgHNEZPhPKrMAAAAAAAAA"}, + +/* + Case: PSBT with one P2PKH input and one P2SH-P2WPKH input. First input is signed and finalized. Outputs are empty + Bytes in Hex: + +*/ + { "70736274ff0100a00200000002ab0949a08c5af7c49b8212f417e2f15ab3f5c33dcf153821a8139f877a5b7be40000000000feffffffab0949a08c5af7c49b8212f417e2f15ab3f5c33dcf153821a8139f877a5b7be40100000000feffffff02603bea0b000000001976a914768a40bbd740cbe81d988e71de2a4d5c71396b1d88ac8e240000000000001976a9146f4620b553fa095e721b9ee0efe9fa039cca459788ac000000000001076a47304402204759661797c01b036b25928948686218347d89864b719e1f7fcf57d1e511658702205309eabf56aa4d8891ffd111fdf1336f3a29da866d7f8486d75546ceedaf93190121035cdc61fc7ba971c0b501a646a2a83b102cb43881217ca682dc86e2d73fa882920001012000e1f5050000000017a9143545e6e33b832c47050f24d3eeb93c9c03948bc787010416001485d13537f2e265405a34dbafa9e3dda01fb82308000000", +/* + Base64 String: +*/ + "cHNidP8BAKACAAAAAqsJSaCMWvfEm4IS9Bfi8Vqz9cM9zxU4IagTn4d6W3vkAAAAAAD+////qwlJoIxa98SbghL0F+LxWrP1wz3PFTghqBOfh3pbe+QBAAAAAP7///8CYDvqCwAAAAAZdqkUdopAu9dAy+gdmI5x3ipNXHE5ax2IrI4kAAAAAAAAGXapFG9GILVT+glechue4O/p+gOcykWXiKwAAAAAAAEHakcwRAIgR1lmF5fAGwNrJZKJSGhiGDR9iYZLcZ4ff89X0eURZYcCIFMJ6r9Wqk2Ikf/REf3xM286KdqGbX+EhtdVRs7tr5MZASEDXNxh/HupccC1AaZGoqg7ECy0OIEhfKaC3Ibi1z+ogpIAAQEgAOH1BQAAAAAXqRQ1RebjO4MsRwUPJNPuuTycA5SLx4cBBBYAFIXRNTfy4mVAWjTbr6nj3aAfuCMIAAAA"}, + +/* + Case: PSBT with one P2PKH input which has a non-final scriptSig and has a sighash type specified. Outputs are empty + Bytes in Hex: + +*/ + { "70736274ff0100750200000001268171371edff285e937adeea4b37b78000c0566cbb3ad64641713ca42171bf60000000000feffffff02d3dff505000000001976a914d0c59903c5bac2868760e90fd521a4665aa7652088ac00e1f5050000000017a9143545e6e33b832c47050f24d3eeb93c9c03948bc787b32e1300000100fda5010100000000010289a3c71eab4d20e0371bbba4cc698fa295c9463afa2e397f8533ccb62f9567e50100000017160014be18d152a9b012039daf3da7de4f53349eecb985ffffffff86f8aa43a71dff1448893a530a7237ef6b4608bbb2dd2d0171e63aec6a4890b40100000017160014fe3e9ef1a745e974d902c4355943abcb34bd5353ffffffff0200c2eb0b000000001976a91485cff1097fd9e008bb34af709c62197b38978a4888ac72fef84e2c00000017a914339725ba21efd62ac753a9bcd067d6c7a6a39d05870247304402202712be22e0270f394f568311dc7ca9a68970b8025fdd3b240229f07f8a5f3a240220018b38d7dcd314e734c9276bd6fb40f673325bc4baa144c800d2f2f02db2765c012103d2e15674941bad4a996372cb87e1856d3652606d98562fe39c5e9e7e413f210502483045022100d12b852d85dcd961d2f5f4ab660654df6eedcc794c0c33ce5cc309ffb5fce58d022067338a8e0e1725c197fb1a88af59f51e44e4255b20167c8684031c05d1f2592a01210223b72beef0965d10be0778efecd61fcac6f79a4ea169393380734464f84f2ab30000000001030401000000000000", +/* + Base64 String: +*/ + "cHNidP8BAHUCAAAAASaBcTce3/KF6Tet7qSze3gADAVmy7OtZGQXE8pCFxv2AAAAAAD+////AtPf9QUAAAAAGXapFNDFmQPFusKGh2DpD9UhpGZap2UgiKwA4fUFAAAAABepFDVF5uM7gyxHBQ8k0+65PJwDlIvHh7MuEwAAAQD9pQEBAAAAAAECiaPHHqtNIOA3G7ukzGmPopXJRjr6Ljl/hTPMti+VZ+UBAAAAFxYAFL4Y0VKpsBIDna89p95PUzSe7LmF/////4b4qkOnHf8USIk6UwpyN+9rRgi7st0tAXHmOuxqSJC0AQAAABcWABT+Pp7xp0XpdNkCxDVZQ6vLNL1TU/////8CAMLrCwAAAAAZdqkUhc/xCX/Z4Ai7NK9wnGIZeziXikiIrHL++E4sAAAAF6kUM5cluiHv1irHU6m80GfWx6ajnQWHAkcwRAIgJxK+IuAnDzlPVoMR3HyppolwuAJf3TskAinwf4pfOiQCIAGLONfc0xTnNMkna9b7QPZzMlvEuqFEyADS8vAtsnZcASED0uFWdJQbrUqZY3LLh+GFbTZSYG2YVi/jnF6efkE/IQUCSDBFAiEA0SuFLYXc2WHS9fSrZgZU327tzHlMDDPOXMMJ/7X85Y0CIGczio4OFyXBl/saiK9Z9R5E5CVbIBZ8hoQDHAXR8lkqASECI7cr7vCWXRC+B3jv7NYfysb3mk6haTkzgHNEZPhPKrMAAAAAAQMEAQAAAAAAAA=="}, + +/* + Case: PSBT with one P2PKH input and one P2SH-P2WPKH input both with non-final scriptSigs. P2SH-P2WPKH input's redeemScript is available. Outputs filled. + Bytes in Hex: + +*/ + { "70736274ff0100a00200000002ab0949a08c5af7c49b8212f417e2f15ab3f5c33dcf153821a8139f877a5b7be40000000000feffffffab0949a08c5af7c49b8212f417e2f15ab3f5c33dcf153821a8139f877a5b7be40100000000feffffff02603bea0b000000001976a914768a40bbd740cbe81d988e71de2a4d5c71396b1d88ac8e240000000000001976a9146f4620b553fa095e721b9ee0efe9fa039cca459788ac00000000000100df0200000001268171371edff285e937adeea4b37b78000c0566cbb3ad64641713ca42171bf6000000006a473044022070b2245123e6bf474d60c5b50c043d4c691a5d2435f09a34a7662a9dc251790a022001329ca9dacf280bdf30740ec0390422422c81cb45839457aeb76fc12edd95b3012102657d118d3357b8e0f4c2cd46db7b39f6d9c38d9a70abcb9b2de5dc8dbfe4ce31feffffff02d3dff505000000001976a914d0c59903c5bac2868760e90fd521a4665aa7652088ac00e1f5050000000017a9143545e6e33b832c47050f24d3eeb93c9c03948bc787b32e13000001012000e1f5050000000017a9143545e6e33b832c47050f24d3eeb93c9c03948bc787010416001485d13537f2e265405a34dbafa9e3dda01fb8230800220202ead596687ca806043edc3de116cdf29d5e9257c196cd055cf698c8d02bf24e9910b4a6ba670000008000000080020000800022020394f62be9df19952c5587768aeb7698061ad2c4a25c894f47d8c162b4d7213d0510b4a6ba6700000080010000800200008000", +/* + Base64 String: +*/ + "cHNidP8BAKACAAAAAqsJSaCMWvfEm4IS9Bfi8Vqz9cM9zxU4IagTn4d6W3vkAAAAAAD+////qwlJoIxa98SbghL0F+LxWrP1wz3PFTghqBOfh3pbe+QBAAAAAP7///8CYDvqCwAAAAAZdqkUdopAu9dAy+gdmI5x3ipNXHE5ax2IrI4kAAAAAAAAGXapFG9GILVT+glechue4O/p+gOcykWXiKwAAAAAAAEA3wIAAAABJoFxNx7f8oXpN63upLN7eAAMBWbLs61kZBcTykIXG/YAAAAAakcwRAIgcLIkUSPmv0dNYMW1DAQ9TGkaXSQ18Jo0p2YqncJReQoCIAEynKnazygL3zB0DsA5BCJCLIHLRYOUV663b8Eu3ZWzASECZX0RjTNXuOD0ws1G23s59tnDjZpwq8ubLeXcjb/kzjH+////AtPf9QUAAAAAGXapFNDFmQPFusKGh2DpD9UhpGZap2UgiKwA4fUFAAAAABepFDVF5uM7gyxHBQ8k0+65PJwDlIvHh7MuEwAAAQEgAOH1BQAAAAAXqRQ1RebjO4MsRwUPJNPuuTycA5SLx4cBBBYAFIXRNTfy4mVAWjTbr6nj3aAfuCMIACICAurVlmh8qAYEPtw94RbN8p1eklfBls0FXPaYyNAr8k6ZELSmumcAAACAAAAAgAIAAIAAIgIDlPYr6d8ZlSxVh3aK63aYBhrSxKJciU9H2MFitNchPQUQtKa6ZwAAAIABAACAAgAAgAA="}, + +/* + Case: PSBT with one P2SH-P2WSH input of a 2-of-2 multisig, redeemScript, witnessScript, and keypaths are available. Contains one signature. + Bytes in Hex: + +*/ + { "70736274ff0100550200000001279a2323a5dfb51fc45f220fa58b0fc13e1e3342792a85d7e36cd6333b5cbc390000000000ffffffff01a05aea0b000000001976a914ffe9c0061097cc3b636f2cb0460fa4fc427d2b4588ac0000000000010120955eea0b0000000017a9146345200f68d189e1adc0df1c4d16ea8f14c0dbeb87220203b1341ccba7683b6af4f1238cd6e97e7167d569fac47f1e48d47541844355bd4646304302200424b58effaaa694e1559ea5c93bbfd4a89064224055cdf070b6771469442d07021f5c8eb0fea6516d60b8acb33ad64ede60e8785bfb3aa94b99bdf86151db9a9a010104220020771fd18ad459666dd49f3d564e3dbc42f4c84774e360ada16816a8ed488d5681010547522103b1341ccba7683b6af4f1238cd6e97e7167d569fac47f1e48d47541844355bd462103de55d1e1dac805e3f8a58c1fbf9b94c02f3dbaafe127fefca4995f26f82083bd52ae220603b1341ccba7683b6af4f1238cd6e97e7167d569fac47f1e48d47541844355bd4610b4a6ba67000000800000008004000080220603de55d1e1dac805e3f8a58c1fbf9b94c02f3dbaafe127fefca4995f26f82083bd10b4a6ba670000008000000080050000800000", +/* + Base64 String: +*/ + "cHNidP8BAFUCAAAAASeaIyOl37UfxF8iD6WLD8E+HjNCeSqF1+Ns1jM7XLw5AAAAAAD/////AaBa6gsAAAAAGXapFP/pwAYQl8w7Y28ssEYPpPxCfStFiKwAAAAAAAEBIJVe6gsAAAAAF6kUY0UgD2jRieGtwN8cTRbqjxTA2+uHIgIDsTQcy6doO2r08SOM1ul+cWfVafrEfx5I1HVBhENVvUZGMEMCIAQktY7/qqaU4VWepck7v9SokGQiQFXN8HC2dxRpRC0HAh9cjrD+plFtYLisszrWTt5g6Hhb+zqpS5m9+GFR25qaAQEEIgAgdx/RitRZZm3Unz1WTj28QvTIR3TjYK2haBao7UiNVoEBBUdSIQOxNBzLp2g7avTxI4zW6X5xZ9Vp+sR/HkjUdUGEQ1W9RiED3lXR4drIBeP4pYwfv5uUwC89uq/hJ/78pJlfJvggg71SriIGA7E0HMunaDtq9PEjjNbpfnFn1Wn6xH8eSNR1QYRDVb1GELSmumcAAACAAAAAgAQAAIAiBgPeVdHh2sgF4/iljB+/m5TALz26r+En/vykmV8m+CCDvRC0prpnAAAAgAAAAIAFAACAAAA="}, + +/* + Case: PSBT with one P2WSH input of a 2-of-2 multisig. witnessScript, keypaths, and global xpubs are available. Contains no signatures. Outputs filled. + Bytes in Hex: + +*/ + { "70736274ff01005202000000019dfc6628c26c5899fe1bd3dc338665bfd55d7ada10f6220973df2d386dec12760100000000ffffffff01f03dcd1d000000001600147b3a00bfdc14d27795c2b74901d09da6ef133579000000004f01043587cf02da3fd0088000000097048b1ad0445b1ec8275517727c87b4e4ebc18a203ffa0f94c01566bd38e9000351b743887ee1d40dc32a6043724f2d6459b3b5a4d73daec8fbae0472f3bc43e20cd90c6a4fae000080000000804f01043587cf02da3fd00880000001b90452427139cd78c2cff2444be353cd58605e3e513285e528b407fae3f6173503d30a5e97c8adbc557dac2ad9a7e39c1722ebac69e668b6f2667cc1d671c83cab0cd90c6a4fae000080010000800001012b0065cd1d000000002200202c5486126c4978079a814e13715d65f36459e4d6ccaded266d0508645bafa6320105475221029da12cdb5b235692b91536afefe5c91c3ab9473d8e43b533836ab456299c88712103372b34234ed7cf9c1fea5d05d441557927be9542b162eb02e1ab2ce80224c00b52ae2206029da12cdb5b235692b91536afefe5c91c3ab9473d8e43b533836ab456299c887110d90c6a4fae0000800000008000000000220603372b34234ed7cf9c1fea5d05d441557927be9542b162eb02e1ab2ce80224c00b10d90c6a4fae0000800100008000000000002202039eff1f547a1d5f92dfa2ba7af6ac971a4bd03ba4a734b03156a256b8ad3a1ef910ede45cc500000080000000800100008000", +/* + Base64 String: +*/ + "cHNidP8BAFICAAAAAZ38ZijCbFiZ/hvT3DOGZb/VXXraEPYiCXPfLTht7BJ2AQAAAAD/////AfA9zR0AAAAAFgAUezoAv9wU0neVwrdJAdCdpu8TNXkAAAAATwEENYfPAto/0AiAAAAAlwSLGtBEWx7IJ1UXcnyHtOTrwYogP/oPlMAVZr046QADUbdDiH7h1A3DKmBDck8tZFmztaTXPa7I+64EcvO8Q+IM2QxqT64AAIAAAACATwEENYfPAto/0AiAAAABuQRSQnE5zXjCz/JES+NTzVhgXj5RMoXlKLQH+uP2FzUD0wpel8itvFV9rCrZp+OcFyLrrGnmaLbyZnzB1nHIPKsM2QxqT64AAIABAACAAAEBKwBlzR0AAAAAIgAgLFSGEmxJeAeagU4TcV1l82RZ5NbMre0mbQUIZFuvpjIBBUdSIQKdoSzbWyNWkrkVNq/v5ckcOrlHPY5DtTODarRWKZyIcSEDNys0I07Xz5wf6l0F1EFVeSe+lUKxYusC4ass6AIkwAtSriIGAp2hLNtbI1aSuRU2r+/lyRw6uUc9jkO1M4NqtFYpnIhxENkMak+uAACAAAAAgAAAAAAiBgM3KzQjTtfPnB/qXQXUQVV5J76VQrFi6wLhqyzoAiTACxDZDGpPrgAAgAEAAIAAAAAAACICA57/H1R6HV+S36K6evaslxpL0DukpzSwMVaiVritOh75EO3kXMUAAACAAAAAgAEAAIAA"}, + +/* + Case: PSBT with unknown types in the inputs. + Bytes in Hex: + +*/ + { "70736274ff01003f0200000001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000ffffffff010000000000000000036a010000000000000a0f0102030405060708090f0102030405060708090a0b0c0d0e0f0000", +/* + Base64 String: +*/ + "cHNidP8BAD8CAAAAAf//////////////////////////////////////////AAAAAAD/////AQAAAAAAAAAAA2oBAAAAAAAACg8BAgMEBQYHCAkPAQIDBAUGBwgJCgsMDQ4PAAA="}, + +/* + Case: PSBT with `PSBT_GLOBAL_XPUB`. + Bytes in Hex: + +*/ + { "70736274ff01009d0100000002710ea76ab45c5cb6438e607e59cc037626981805ae9e0dfd9089012abb0be5350100000000ffffffff190994d6a8b3c8c82ccbcfb2fba4106aa06639b872a8d447465c0d42588d6d670000000000ffffffff0200e1f505000000001976a914b6bc2c0ee5655a843d79afedd0ccc3f7dd64340988ac605af405000000001600141188ef8e4ce0449eaac8fb141cbf5a1176e6a088000000004f010488b21e039e530cac800000003dbc8a5c9769f031b17e77fea1518603221a18fd18f2b9a54c6c8c1ac75cbc3502f230584b155d1c7f1cd45120a653c48d650b431b67c5b2c13f27d7142037c1691027569c503100008000000080000000800001011f00e1f5050000000016001433b982f91b28f160c920b4ab95e58ce50dda3a4a220203309680f33c7de38ea6a47cd4ecd66f1f5a49747c6ffb8808ed09039243e3ad5c47304402202d704ced830c56a909344bd742b6852dccd103e963bae92d38e75254d2bb424502202d86c437195df46c0ceda084f2a291c3da2d64070f76bf9b90b195e7ef28f77201220603309680f33c7de38ea6a47cd4ecd66f1f5a49747c6ffb8808ed09039243e3ad5c1827569c5031000080000000800000008000000000010000000001011f00e1f50500000000160014388fb944307eb77ef45197d0b0b245e079f011de220202c777161f73d0b7c72b9ee7bde650293d13f095bc7656ad1f525da5fd2e10b11047304402204cb1fb5f869c942e0e26100576125439179ae88dca8a9dc3ba08f7953988faa60220521f49ca791c27d70e273c9b14616985909361e25be274ea200d7e08827e514d01220602c777161f73d0b7c72b9ee7bde650293d13f095bc7656ad1f525da5fd2e10b1101827569c5031000080000000800000008000000000000000000000220202d20ca502ee289686d21815bd43a80637b0698e1fbcdbe4caed445f6c1a0a90ef1827569c50310000800000008000000080000000000400000000", +/* + Base64 String: +*/ + "cHNidP8BAJ0BAAAAAnEOp2q0XFy2Q45gflnMA3YmmBgFrp4N/ZCJASq7C+U1AQAAAAD/////GQmU1qizyMgsy8+y+6QQaqBmObhyqNRHRlwNQliNbWcAAAAAAP////8CAOH1BQAAAAAZdqkUtrwsDuVlWoQ9ea/t0MzD991kNAmIrGBa9AUAAAAAFgAUEYjvjkzgRJ6qyPsUHL9aEXbmoIgAAAAATwEEiLIeA55TDKyAAAAAPbyKXJdp8DGxfnf+oVGGAyIaGP0Y8rmlTGyMGsdcvDUC8jBYSxVdHH8c1FEgplPEjWULQxtnxbLBPyfXFCA3wWkQJ1acUDEAAIAAAACAAAAAgAABAR8A4fUFAAAAABYAFDO5gvkbKPFgySC0q5XljOUN2jpKIgIDMJaA8zx9446mpHzU7NZvH1pJdHxv+4gI7QkDkkPjrVxHMEQCIC1wTO2DDFapCTRL10K2hS3M0QPpY7rpLTjnUlTSu0JFAiAthsQ3GV30bAztoITyopHD2i1kBw92v5uQsZXn7yj3cgEiBgMwloDzPH3jjqakfNTs1m8fWkl0fG/7iAjtCQOSQ+OtXBgnVpxQMQAAgAAAAIAAAACAAAAAAAEAAAAAAQEfAOH1BQAAAAAWABQ4j7lEMH63fvRRl9CwskXgefAR3iICAsd3Fh9z0LfHK57nveZQKT0T8JW8dlatH1Jdpf0uELEQRzBEAiBMsftfhpyULg4mEAV2ElQ5F5rojcqKncO6CPeVOYj6pgIgUh9JynkcJ9cOJzybFGFphZCTYeJb4nTqIA1+CIJ+UU0BIgYCx3cWH3PQt8crnue95lApPRPwlbx2Vq0fUl2l/S4QsRAYJ1acUDEAAIAAAACAAAAAgAAAAAAAAAAAAAAiAgLSDKUC7iiWhtIYFb1DqAY3sGmOH7zb5MrtRF9sGgqQ7xgnVpxQMQAAgAAAAIAAAACAAAAAAAQAAAAA"}, +}; diff --git a/src/ctest/test_clear.c b/src/ctest/test_clear.c index e2598ed5a..fc11c0bc8 100644 --- a/src/ctest/test_clear.c +++ b/src/ctest/test_clear.c @@ -86,7 +86,7 @@ static bool in_stack(const char *caller, const void *search, size_t len) for (i = 0; i < PTHREAD_STACK_MIN - len - 1; ++i) if (!memcmp(gstack + i, search, len)) { if (caller) { - printf("Found %s secret at stack position %ld and base %p\n", caller, (long)i, gstack); + printf("Found %s secret at stack position %ld and base %p\n", caller, (long)i, (void *)gstack); dump_mem(search, len); } return true; /* Found */ diff --git a/src/ctest/test_elements_tx.c b/src/ctest/test_elements_tx.c index f7fbbbb35..122d0c9ce 100644 --- a/src/ctest/test_elements_tx.c +++ b/src/ctest/test_elements_tx.c @@ -2,7 +2,6 @@ #include #include -#include #include #include #include diff --git a/src/ctest/test_psbt.c b/src/ctest/test_psbt.c new file mode 100644 index 000000000..0cfdd9f9f --- /dev/null +++ b/src/ctest/test_psbt.c @@ -0,0 +1,73 @@ +#include "config.h" + +#include +#include +#include +#include +#include + +#include "psbts.h" + +int main(void) +{ + size_t i; + + for (i = 0; i < sizeof(invalid_psbts) / sizeof(invalid_psbts[0]); i++) { + struct wally_psbt *psbt; + + if (wally_psbt_from_base64(invalid_psbts[i].base64, &psbt) != WALLY_OK) + continue; + errx(1, "Should have failed to parse psbt %s", invalid_psbts[i].base64); + } + + for (i = 0; i < sizeof(valid_psbts) / sizeof(valid_psbts[0]); i++) { + const char *base64_in = valid_psbts[i].base64; + struct wally_psbt *psbt, *psbt_clone; + char *output; + unsigned char *bytes; + size_t len, written; + + if (wally_psbt_from_base64(base64_in, &psbt) != WALLY_OK) + errx(1, "Failed to parse psbt %s", base64_in); + + if (wally_psbt_to_base64(psbt, 0, &output) != WALLY_OK) + errx(1, "Failed to base64 psbt %s", base64_in); + + if (strcmp(output, base64_in) != 0) + errx(1, "psbt %s turned into %s?", base64_in, output); + + wally_free_string(output); + + if (wally_psbt_get_length(psbt, 0, &len) != WALLY_OK) + errx(1, "Failed to get psbt %s len", base64_in); + + bytes = malloc(len); + if (wally_psbt_to_bytes(psbt, 0, bytes, len, &written) != WALLY_OK) + errx(1, "psbt %s could not to_bytes?", base64_in); + + if (len != written) { + errx(1, "psbt %s to_bytes to %zu not %zu?", base64_in, + written, len); + } + + if (wally_hex_from_bytes(bytes, len, &output) != WALLY_OK) + errx(1, "Failed to convert psbt bytes to hex"); + + if (strcmp(output, valid_psbts[i].hex) != 0) + errx(1, "psbt[%zi] bytes %s not %s", i, output, valid_psbts[i].hex); + + wally_free_string(output); + free(bytes); + + if (wally_psbt_from_base64(base64_in, &psbt_clone) != WALLY_OK) + errx(1, "Failed to parse psbt clone %s", base64_in); + + if (wally_psbt_combine(psbt_clone, psbt) != WALLY_OK) + errx(1, "Failed to combine psbts %s", base64_in); + + wally_psbt_free(psbt_clone); + wally_psbt_free(psbt); + } + + return 0; +} diff --git a/src/ctest/test_psbt_limits.c b/src/ctest/test_psbt_limits.c new file mode 100644 index 000000000..a73cfe560 --- /dev/null +++ b/src/ctest/test_psbt_limits.c @@ -0,0 +1,112 @@ +/* This is a superset of test_psbt, but requires mmap */ +#include "config.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "psbts.h" + +/* Create a cliff: any access past the end will SEGV */ +static unsigned char *cliff(size_t *size) +{ + unsigned char *p; + + /* One page is enough for our tests so far */ + *size = getpagesize(); + + /* MAP_ANON isn't POSIX, but MacOS doesn't let us mmap /dev/zero */ + p = mmap(NULL, *size + getpagesize(), + PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE, -1, 0); + if (p == MAP_FAILED) + err(1, "Failed to mmap anon"); + + /* Remove second page. */ + if (munmap(p + *size, getpagesize()) != 0) + err(1, "Failed to munmap /dev/zero"); + return p; +} + +/* Test that we don't read past end of buffer when unmarshalling */ +static void test_psbt_read(const struct psbt_test *test, + unsigned char *p, size_t plen) +{ + size_t i; + + /* It can fit, otherwise adjust cliff() */ + assert(hex_data_size(strlen(test->hex)) <= plen); + + /* Unpack right next to the cliff */ + for (i = 0; i <= hex_data_size(strlen(test->hex)); i++) { + struct wally_psbt *psbt; + size_t bit; + + if (!hex_decode(test->hex, i * 2, p + plen - i, i)) + abort(); + + /* Try it raw: probably will fail. */ + if (wally_psbt_from_bytes(p + plen - i, i, &psbt) == WALLY_OK) + wally_psbt_free(psbt); + + /* Now try flipping each bit in last byte. */ + for (bit = 0; bit < 8; bit++) { + p[plen - 1] ^= (1 << bit); + if (wally_psbt_from_bytes(p + plen - i, i, &psbt) == WALLY_OK) + wally_psbt_free(psbt); + p[plen - 1] ^= (1 << bit); + } + } +} + +/* Test that we don't write past end of buffer when marshaling */ +static void test_psbt_write(const struct psbt_test *test, + unsigned char *p, size_t plen) +{ + size_t i, psbt_len, written; + struct wally_psbt *psbt; + + if (wally_psbt_from_base64(test->base64, &psbt) != WALLY_OK) + abort(); + + if (wally_psbt_get_length(psbt, 0, &psbt_len) != WALLY_OK) + abort(); + + for (i = 0; i <= psbt_len; i++) { + /* A too short buffer should return OK and the required length */ + if (wally_psbt_to_bytes(psbt, 0, p + plen - i, i, &written) != WALLY_OK) { + errx(1, "wally_psbt_to_bytes should have suceeded"); + } + if (written != psbt_len) + errx(1, "wally_psbt_to_bytes %s wrote %zu in %zu bytes?", + test->base64, written, i); + } + wally_psbt_free(psbt); +} + +int main(void) +{ + size_t i; + size_t plen; + unsigned char *p = cliff(&plen); + + for (i = 0; i < sizeof(invalid_psbts) / sizeof(invalid_psbts[0]); i++) { + test_psbt_read(invalid_psbts + i, p, plen); + } + + for (i = 0; i < sizeof(valid_psbts) / sizeof(valid_psbts[0]); i++) { + test_psbt_read(valid_psbts + i, p, plen); + test_psbt_write(valid_psbts + i, p, plen); + } + + return 0; +} diff --git a/src/test/data/psbt.json b/src/data/psbt.json similarity index 96% rename from src/test/data/psbt.json rename to src/data/psbt.json index d17719b96..791f4e44a 100644 --- a/src/test/data/psbt.json +++ b/src/data/psbt.json @@ -17,7 +17,15 @@ "cHNidP8BAJoCAAAAAljoeiG1ba8MI76OcHBFbDNvfLqlyHV5JPVFiHuyq911AAAAAAD/////g40EJ9DsZQpoqka7CwmK6kQiwHGyyng1Kgd5WdB86h0BAAAAAP////8CcKrwCAAAAAAWABTYXCtx0AYLCcmIauuBXlCZHdoSTQDh9QUAAAAAFgAUAK6pouXw+HaliN9VRuh0LR2HAI8AAAAAAAEAuwIAAAABqtc5MQGL0l+ErkALaISL4J23BurCrBgpi6vucatlb4sAAAAASEcwRAIgWPb8fGoz4bMVSNSByCbAFb0wE1qtQs1neQ2rZtKtJDsCIEoc7SYExnNbY5PltBaR3XiwDwxZQvufdRhW+qk4FX26Af7///8CgPD6AgAAAAAXqRQPuUY0IWlrgsgzryQceMF9295JNIfQ8gonAQAAABepFCnKdPigj4GZlCgYXJe12FLkBj9hh2UAAAABB9oARzBEAiB0AYrUGACXuHMyPAAVcgs2hMyBI4kQSOfbzZtVrWecmQIgc9Npt0Dj61Pc76M4I8gHBRTKVafdlUTxV8FnkTJhEYwBSDBFAiEA9hA4swjcHahlo0hSdG8BV3KTQgjG0kRUOTzZm98iF3cCIAVuZ1pnWm0KArhbFOXikHTYolqbV2C+ooFvZhkQoAbqAUdSIQKVg785rgpgl0etGZrd1jT6YQhVnWxc05tMIYPxq5bgfyEC2rYf9JoU22p9ArDNH7t4/EsYMStbTlTa5Nui+/71NtdSrgABASAAwusLAAAAABepFLf1+vQOPUClpFmx2zU18rcvqSHohwEHIyIAIIwjUxc3Q7WV37Sge3K6jkLjeX2nTof+fZ10l+OyAokDAQjaBABHMEQCIGLrelVhB6fHP0WsSrWh3d9vcHX7EnWWmn84Pv/3hLyyAiAMBdu3Rw2/LwhVfdNWxzJcHtMJE+mWzThAlF2xIijaXwFHMEQCIGX0W6WZi1mif/4ae+0BavHx+Q1Us6qPdFCqX1aiUQO9AiB/ckcDrR7blmgLKEtW1P/LiPf7dZ6rvgiqMPKbhROD0gFHUiEDCJ3BDHrG21T5EymvYXMz2ziM6tDCMfcjN50bmQMLAtwhAjrdkE89bc9Z3bkGsN7iNSm3/7ntUOXoYVGSaGAiHw5zUq4AIQIDqaTDf1mW06ol26xrVwrwZQOUSSlCRgs1R1PtnuylhxDZDGpPAAAAgAAAAIAEAACAACICAn9jmXV9Lv9VoTatAsaEsYOLZVbl8bazQoKpS2tQBRCWENkMak8AAACAAAAAgAUAAIAA", "cHNidP8BAHMCAAAAATAa6YblFqHsisW0vGVz0y+DtGXiOtdhZ9aLOOcwtNvbAAAAAAD/////AnR7AQAAAAAAF6kUA6oXrogrXQ1Usl1jEE5P/s57nqKHYEOZOwAAAAAXqRS5IbG6b3IuS/qDtlV6MTmYakLsg4cAAAAAAAEBHwDKmjsAAAAAFgAU0tlLZK4IWH7vyO6xh8YB6Tn5A3wCAwABAAAAAAEAFgAUYunpgv/zTdgjlhAxawkM0qO3R8sAAQAiACCHa62DLx0WgBXtQSMqnqZaGBXZ7xPA74dZ9ktbKyeKZQEBJVEhA7fOI6AcW0vwCmQlN836uzFbZoMyhnR471EwnSvVf4qHUa4A", "cHNidP8BAHMCAAAAATAa6YblFqHsisW0vGVz0y+DtGXiOtdhZ9aLOOcwtNvbAAAAAAD/////AnR7AQAAAAAAF6kUA6oXrogrXQ1Usl1jEE5P/s57nqKHYEOZOwAAAAAXqRS5IbG6b3IuS/qDtlV6MTmYakLsg4cAAAAAAAEBHwDKmjsAAAAAFgAU0tlLZK4IWH7vyO6xh8YB6Tn5A3wAAgAAFgAUYunpgv/zTdgjlhAxawkM0qO3R8sAAQAiACCHa62DLx0WgBXtQSMqnqZaGBXZ7xPA74dZ9ktbKyeKZQEBJVEhA7fOI6AcW0vwCmQlN836uzFbZoMyhnR471EwnSvVf4qHUa4A", - "cHNidP8BAHMCAAAAATAa6YblFqHsisW0vGVz0y+DtGXiOtdhZ9aLOOcwtNvbAAAAAAD/////AnR7AQAAAAAAF6kUA6oXrogrXQ1Usl1jEE5P/s57nqKHYEOZOwAAAAAXqRS5IbG6b3IuS/qDtlV6MTmYakLsg4cAAAAAAAEBHwDKmjsAAAAAFgAU0tlLZK4IWH7vyO6xh8YB6Tn5A3wAAQAWABRi6emC//NN2COWEDFrCQzSo7dHywABACIAIIdrrYMvHRaAFe1BIyqeploYFdnvE8Dvh1n2S1srJ4plIQEAJVEhA7fOI6AcW0vwCmQlN836uzFbZoMyhnR471EwnSvVf4qHUa4A" + "cHNidP8BAHMCAAAAATAa6YblFqHsisW0vGVz0y+DtGXiOtdhZ9aLOOcwtNvbAAAAAAD/////AnR7AQAAAAAAF6kUA6oXrogrXQ1Usl1jEE5P/s57nqKHYEOZOwAAAAAXqRS5IbG6b3IuS/qDtlV6MTmYakLsg4cAAAAAAAEBHwDKmjsAAAAAFgAU0tlLZK4IWH7vyO6xh8YB6Tn5A3wAAQAWABRi6emC//NN2COWEDFrCQzSo7dHywABACIAIIdrrYMvHRaAFe1BIyqeploYFdnvE8Dvh1n2S1srJ4plIQEAJVEhA7fOI6AcW0vwCmQlN836uzFbZoMyhnR471EwnSvVf4qHUa4A", + "cHNidP8B+wQBAAAAAQB1AgAAAAEmgXE3Ht/yhek3re6ks3t4AAwFZsuzrWRkFxPKQhcb9gAAAAAA/v///wLT3/UFAAAAABl2qRTQxZkDxbrChodg6Q/VIaRmWqdlIIisAOH1BQAAAAAXqRQ1RebjO4MsRwUPJNPuuTycA5SLx4ezLhMAAAEA/aUBAQAAAAABAomjxx6rTSDgNxu7pMxpj6KVyUY6+i45f4UzzLYvlWflAQAAABcWABS+GNFSqbASA52vPafeT1M0nuy5hf////+G+KpDpx3/FEiJOlMKcjfva0YIu7LdLQFx5jrsakiQtAEAAAAXFgAU/j6e8adF6XTZAsQ1WUOryzS9U1P/////AgDC6wsAAAAAGXapFIXP8Ql/2eAIuzSvcJxiGXs4l4pIiKxy/vhOLAAAABepFDOXJboh79Yqx1OpvNBn1semo50FhwJHMEQCICcSviLgJw85T1aDEdx8qaaJcLgCX907JAIp8H+KXzokAiABizjX3NMU5zTJJ2vW+0D2czJbxLqhRMgA0vLwLbJ2XAEhA9LhVnSUG61KmWNyy4fhhW02UmBtmFYv45xenn5BPyEFAkgwRQIhANErhS2F3Nlh0vX0q2YGVN9u7cx5TAwzzlzDCf+1/OWNAiBnM4qODhclwZf7GoivWfUeROQlWyAWfIaEAxwF0fJZKgEhAiO3K+7wll0Qvgd47+zWH8rG95pOoWk5M4BzRGT4TyqzAAAAAAAAAA==", + "cHNidP8BACoCAAAAAAFAQg8AAAAAABepFG6Rty1Vk+fUOR4v9E6R6YXDFkHwhwAAAAAAAQAAAQABagA=", + "cHNidP8BADMBAAAAAREREREREREREREREREREREREfrK3hERERERERERERERfwAAAAD/////AAAAAAAAAQEJ//////////8AAQEJAADK/gAAAAAAAA==", + "cHNidP8BADMBAAAAAREREREREREREREREREREREREfrK3hERERERERERERERfwAAAAD/////AAAAAAAAAQMErd7f7gEDBAEAAAAA", + "cHNidP8BADMBAAAAAREREREREREREREREREREREREfrK3hERERERERERERERfwAAAAD/////AAAAAAAAAQQAAQQBagA=", + "cHNidP8BADMBAAAAAREREREREREREREREREREREREfrK3hERERERERERERERfwAAAAD/////AAAAAAAAAQEJAOH1BQAAAAAAAQUAAQUBUQA=", + "cHNidP8BADMBAAAAAREREREREREREREREREREREREfrK3hERERERERERERERfwAAAAD/////AAAAAAAAAQcAAQcBUQA=", + "cHNidP8BADMBAAAAAREREREREREREREREREREREREfrK3hERERERERERERERfwAAAAD/////AAAAAAAAAQEJAOH1BQAAAAAAAQgBAAEIAwEBUQA=" ], "valid" : [ { @@ -43,6 +51,11 @@ { "psbt": "cHNidP8BAD8CAAAAAf//////////////////////////////////////////AAAAAAD/////AQAAAAAAAAAAA2oBAAAAAAAACg8BAgMEBQYHCAkPAQIDBAUGBwgJCgsMDQ4PAAA=", "len": 101 + }, + { + "comment": "Partial transaction (with no outputs)", + "psbt": "cHNidP8BADMCAAAAAZCmTNqA77Z44FTcG0k2D2xkazaLwfTcYgkhBHT1hFy0AAAAAAD9////AGYAAAAAAQEgQEIPAAAAAAAXqRRlVyjzbP420BqlDTI2cERp+EpVQIcBBBYAFNa5adNt/9rZhpGT9mPuSA39xzSIAA==", + "len": 121 } ], "creator" : [ diff --git a/src/data/pset.json b/src/data/pset.json new file mode 100644 index 000000000..4b49da887 --- /dev/null +++ b/src/data/pset.json @@ -0,0 +1,6 @@ +{ + "valid": [{ + "pset": "cHNldP8BAOYCAAAAAAEJoA5k8iAABF66mJyk85LBsCUTVVfErOwxmexTjCBEyQAAAAAA/f///wMBXOe5Y9N/jy1Ryvu6koqqniILi7xmBXFJnANiijhRuM4BAAAAAO5rFFgAF6kUpruHAKCJvLhrCf5VkrhUvQ4+bDKHAVznuWPTf48tUcr7upKKqp4iC4u8ZgVxSZwDYoo4UbjOAQAAAAA7msoAABepFII2rTwCO4NdVWyoBFVzHVM/c1IBhwFc57lj03+PLVHK+7qSiqqeIguLvGYFcUmcA2KKOFG4zgEAAAAAAAATqAAAAAAAAAABAUMBXOe5Y9N/jy1Ryvu6koqqniILi7xmBXFJnANiijhRuM4BAAAAASoF8gAAF6kUIUgXxch89mjFY+aFBdmAk9d8GcmHAQQWABTs8/AAycufhZ2FR4uYndwqd1C7ogv8CGVsZW1lbnRzAAgA8gUqAQAAAAv8CGVsZW1lbnRzAiBc57lj03+PLVHK+7qSiqqeIguLvGYFcUmcA2KKOFG4zgABABYAFMFIn/H6YCLLR2ukTXG9evUf5T5VC/wIZWxlbWVudHMGIQMYlbtO8ZBg4wdFP1vS+d59msC7iEjmr/VATyVestonAwABABYAFJpBlksv6mEJcXOPlyskNv1O3yn+C/wIZWxlbWVudHMGIQLkIFPXDMnWVGXBPhDwpi5zMF/WmosNkQLltvC445AA2QAA", + "len": 546 + }] +} diff --git a/src/ecdh.c b/src/ecdh.c index 88844c519..b01c43bdf 100644 --- a/src/ecdh.c +++ b/src/ecdh.c @@ -4,30 +4,29 @@ #include "secp256k1/include/secp256k1_ecdh.h" int wally_ecdh(const unsigned char *pub_key, size_t pub_key_len, - const unsigned char *bytes, size_t bytes_len, + const unsigned char *priv_key, size_t priv_key_len, unsigned char *bytes_out, size_t len) { const secp256k1_context *ctx = secp_ctx(); secp256k1_pubkey pub; + int ret = WALLY_OK; if (!ctx) return WALLY_ENOMEM; if (!pub_key || pub_key_len != EC_PUBLIC_KEY_LEN || - !pubkey_parse(ctx, &pub, pub_key, pub_key_len) || - !bytes || bytes_len != EC_PRIVATE_KEY_LEN || - !secp256k1_ec_seckey_verify(ctx, bytes) || - !bytes_out || len != SHA256_LEN) { - wally_clear(&pub, sizeof(pub)); + !priv_key || priv_key_len != EC_PRIVATE_KEY_LEN || + !bytes_out || len != SHA256_LEN) return WALLY_EINVAL; - } - if (!secp256k1_ecdh(ctx, bytes_out, &pub, bytes, NULL, NULL)) { - wally_clear(&pub, sizeof(pub)); + if (!pubkey_parse(ctx, &pub, pub_key, pub_key_len) || + !secp256k1_ec_seckey_verify(ctx, priv_key)) { + ret = WALLY_EINVAL; + } else if (!secp256k1_ecdh(ctx, bytes_out, &pub, priv_key, NULL, NULL)) { wally_clear(bytes_out, len); - return WALLY_ERROR; + ret = WALLY_ERROR; } wally_clear(&pub, sizeof(pub)); - return WALLY_OK; + return ret; } diff --git a/src/elements.c b/src/elements.c index 1327c173f..e14a86799 100644 --- a/src/elements.c +++ b/src/elements.c @@ -9,7 +9,6 @@ #include "src/secp256k1/include/secp256k1_surjectionproof.h" #include "src/secp256k1/include/secp256k1_whitelist.h" #include "secp256k1/include/secp256k1_ecdh.h" -#include "ccan/ccan/crypto/sha256/sha256.h" #include #ifdef BUILD_ELEMENTS @@ -39,29 +38,23 @@ static int get_commitment(const secp256k1_context *ctx, static int get_nonce_hash(const secp256k1_context *ctx, const unsigned char *pub_key, size_t pub_key_len, const unsigned char *priv_key, size_t priv_key_len, - struct sha256 *dest) { + unsigned char *bytes_out, size_t len) { secp256k1_pubkey pub; unsigned char nonce[32]; int ret = WALLY_EINVAL; - if (!pub_key || pub_key_len != EC_PUBLIC_KEY_LEN || - !pubkey_parse(ctx, &pub, pub_key, pub_key_len) || - wally_ec_private_key_verify(priv_key, priv_key_len) != WALLY_OK || - !dest) - goto cleanup; - - /* Create the nonce */ - if (!secp256k1_ecdh(ctx, nonce, &pub, priv_key, NULL, NULL)) { - ret = WALLY_ERROR; - goto cleanup; + /* Note that only compressed public keys are supported */ + if (pub_key && pub_key_len == EC_PUBLIC_KEY_LEN && + pubkey_parse(ctx, &pub, pub_key, pub_key_len) && + wally_ec_private_key_verify(priv_key, priv_key_len) == WALLY_OK && + bytes_out && len == SHA256_LEN) { + /* Create the nonce */ + if (secp256k1_ecdh(ctx, nonce, &pub, priv_key, NULL, NULL)) + ret = wally_sha256(nonce, sizeof(nonce), bytes_out, len); + else + ret = WALLY_ERROR; } - wally_sha256(nonce, sizeof(nonce), dest->u.u8, sizeof(*dest)); - - ret = WALLY_OK; - -cleanup: wally_clear_2(&pub, sizeof(pub), nonce, sizeof(nonce)); - return ret; } @@ -76,7 +69,7 @@ int wally_asset_generator_from_bytes(const unsigned char *asset, size_t asset_le if (!ctx) return WALLY_ENOMEM; - if (!asset || asset_len != ASSET_TAG_LEN || !abf || abf_len != ASSET_TAG_LEN || + if (!asset || asset_len != ASSET_TAG_LEN || !abf || abf_len != BLINDING_FACTOR_LEN || !bytes_out || len != ASSET_GENERATOR_LEN) return WALLY_EINVAL; @@ -103,8 +96,8 @@ int wally_asset_final_vbf(const uint64_t *values, size_t values_len, size_t num_ if (!values || values_len < 2u || num_inputs >= values_len || - !abf || abf_len != (values_len * ASSET_TAG_LEN) || - !vbf || vbf_len != ((values_len - 1) * ASSET_TAG_LEN) || + !abf || abf_len != (values_len * BLINDING_FACTOR_LEN) || + !vbf || vbf_len != ((values_len - 1) * BLINDING_FACTOR_LEN) || !bytes_out || len != ASSET_TAG_LEN) return WALLY_EINVAL; @@ -117,8 +110,8 @@ int wally_asset_final_vbf(const uint64_t *values, size_t values_len, size_t num_ } for (i = 0; i < values_len; i++) { - abf_p[i] = abf + i * ASSET_TAG_LEN; - vbf_p[i] = vbf + i * ASSET_TAG_LEN; + abf_p[i] = abf + i * BLINDING_FACTOR_LEN; + vbf_p[i] = vbf + i * BLINDING_FACTOR_LEN; } vbf_p[values_len - 1] = bytes_out; wally_clear(bytes_out, len); @@ -129,8 +122,8 @@ int wally_asset_final_vbf(const uint64_t *values, size_t values_len, size_t num_ ret = WALLY_OK; cleanup: - wally_free(abf_p); - wally_free(vbf_p); + clear_and_free(abf_p, values_len * sizeof(unsigned char *)); + clear_and_free(vbf_p, values_len * sizeof(unsigned char *)); return ret; } @@ -184,8 +177,8 @@ int wally_asset_rangeproof_with_nonce(uint64_t value, if (!nonce_hash || nonce_hash_len != SHA256_LEN || !asset || asset_len != ASSET_TAG_LEN || - !abf || abf_len != ASSET_TAG_LEN || - !vbf || vbf_len != ASSET_TAG_LEN || + !abf || abf_len != BLINDING_FACTOR_LEN || + !vbf || vbf_len != BLINDING_FACTOR_LEN || !bytes_out || len < ASSET_RANGEPROOF_MAX_LEN || !written || get_commitment(ctx, commitment, commitment_len, &commit) != WALLY_OK || /* FIXME: Is there an upper size limit on the extra commitment? */ @@ -232,30 +225,27 @@ int wally_asset_rangeproof(uint64_t value, size_t *written) { const secp256k1_context *ctx = secp_ctx(); - struct sha256 nonce_hash; - int ret = WALLY_EINVAL; + unsigned char nonce_hash[SHA256_LEN]; + int ret; if (!ctx) return WALLY_ENOMEM; - ret = get_nonce_hash(ctx, pub_key, pub_key_len, priv_key, priv_key_len, &nonce_hash); - if (ret != WALLY_OK) - goto cleanup; - - ret = wally_asset_rangeproof_with_nonce(value, - nonce_hash.u.u8, SHA256_LEN, - asset, asset_len, - abf, abf_len, - vbf, vbf_len, - commitment, commitment_len, - extra, extra_len, - generator, generator_len, - min_value, exp, min_bits, - bytes_out, len, written); - -cleanup: - wally_clear(&nonce_hash, sizeof(nonce_hash)); - + ret = get_nonce_hash(ctx, pub_key, pub_key_len, priv_key, priv_key_len, + nonce_hash, sizeof(nonce_hash)); + if (ret == WALLY_OK) + ret = wally_asset_rangeproof_with_nonce(value, + nonce_hash, sizeof(nonce_hash), + asset, asset_len, + abf, abf_len, + vbf, vbf_len, + commitment, commitment_len, + extra, extra_len, + generator, generator_len, + min_value, exp, min_bits, + bytes_out, len, written); + + wally_clear(nonce_hash, sizeof(nonce_hash)); return ret; } @@ -286,8 +276,8 @@ int wally_asset_unblind_with_nonce(const unsigned char *nonce_hash, size_t nonce (extra_len && !extra) || get_generator(ctx, generator, generator_len, &gen) != WALLY_OK || !asset_out || asset_out_len != ASSET_TAG_LEN || - !abf_out || abf_out_len != ASSET_TAG_LEN || - !vbf_out || vbf_out_len != ASSET_TAG_LEN || !value_out) + !abf_out || abf_out_len != BLINDING_FACTOR_LEN || + !vbf_out || vbf_out_len != BLINDING_FACTOR_LEN || !value_out) goto cleanup; /* Extract the value blinding factor, value and message from the rangeproof */ @@ -324,29 +314,26 @@ int wally_asset_unblind(const unsigned char *pub_key, size_t pub_key_len, uint64_t *value_out) { const secp256k1_context *ctx = secp_ctx(); - struct sha256 nonce_hash; - int ret = WALLY_EINVAL; + unsigned char nonce_hash[SHA256_LEN]; + int ret; if (!ctx) return WALLY_ENOMEM; - ret = get_nonce_hash(ctx, pub_key, pub_key_len, priv_key, priv_key_len, &nonce_hash); - if (ret != WALLY_OK) - goto cleanup; - - ret = wally_asset_unblind_with_nonce(nonce_hash.u.u8, SHA256_LEN, - proof, proof_len, - commitment, commitment_len, - extra, extra_len, - generator, generator_len, - asset_out, asset_out_len, - abf_out, abf_out_len, - vbf_out, vbf_out_len, - value_out); - -cleanup: - wally_clear(&nonce_hash, sizeof(nonce_hash)); - + ret = get_nonce_hash(ctx, pub_key, pub_key_len, priv_key, priv_key_len, + nonce_hash, sizeof(nonce_hash)); + if (ret == WALLY_OK) + ret = wally_asset_unblind_with_nonce(nonce_hash, sizeof(nonce_hash), + proof, proof_len, + commitment, commitment_len, + extra, extra_len, + generator, generator_len, + asset_out, asset_out_len, + abf_out, abf_out_len, + vbf_out, vbf_out_len, + value_out); + + wally_clear(nonce_hash, sizeof(nonce_hash)); return ret; } @@ -387,11 +374,11 @@ int wally_asset_surjectionproof(const unsigned char *output_asset, size_t output return WALLY_ENOMEM; if (!output_asset || output_asset_len != ASSET_TAG_LEN || - !output_abf || output_abf_len != ASSET_TAG_LEN || + !output_abf || output_abf_len != BLINDING_FACTOR_LEN || get_generator(ctx, output_generator, output_generator_len, &gen) != WALLY_OK || !bytes || bytes_len != 32u || !asset || !num_inputs || (asset_len % ASSET_TAG_LEN != 0) || - !abf || abf_len != num_inputs * ASSET_TAG_LEN || + !abf || abf_len != num_inputs * BLINDING_FACTOR_LEN || !generator || generator_len != num_inputs * ASSET_GENERATOR_LEN || !bytes_out || len != SECP256K1_SURJECTIONPROOF_SERIALIZATION_BYTES(num_inputs, num_used) || !written) @@ -423,7 +410,7 @@ int wally_asset_surjectionproof(const unsigned char *output_asset, size_t output if (!secp256k1_surjectionproof_generate(ctx, &proof, generators, num_inputs, &gen, actual_index, - abf + actual_index * ASSET_TAG_LEN, + abf + actual_index * BLINDING_FACTOR_LEN, output_abf)) { ret = WALLY_ERROR; /* Caller must retry with different entropy/outputs */ goto cleanup; @@ -436,8 +423,7 @@ int wally_asset_surjectionproof(const unsigned char *output_asset, size_t output cleanup: wally_clear_2(&gen, sizeof(gen), &proof, sizeof(proof)); if (generators) - wally_clear(generators, num_inputs * sizeof(secp256k1_generator)); - wally_free(generators); + clear_and_free(generators, num_inputs * sizeof(secp256k1_generator)); return ret; } @@ -545,20 +531,14 @@ int wally_asset_blinding_key_from_seed( size_t len) { unsigned char root[HMAC_SHA512_LEN]; - int ret = WALLY_OK; - - if (!bytes || !bytes_out || len != HMAC_SHA512_LEN) - return WALLY_EINVAL; - - if ((ret = wally_symmetric_key_from_seed(bytes, bytes_len, root, sizeof(root))) != WALLY_OK) - return ret; - - if ((ret = wally_symmetric_key_from_parent(root, sizeof(root), 0, LABEL_STR, sizeof(LABEL_STR), - bytes_out, len)) != WALLY_OK) - goto cleanup; + int ret; -cleanup: - wally_clear(root, sizeof(root)); + ret = wally_symmetric_key_from_seed(bytes, bytes_len, root, sizeof(root)); + if (ret == WALLY_OK) { + ret = wally_symmetric_key_from_parent(root, sizeof(root), 0, LABEL_STR, sizeof(LABEL_STR), + bytes_out, len); + wally_clear(root, sizeof(root)); + } return ret; } @@ -571,15 +551,16 @@ int wally_asset_blinding_key_to_ec_private_key( unsigned char *bytes_out, size_t len) { - int ret = WALLY_OK; + int ret; if (!bytes || bytes_len != HMAC_SHA512_LEN || !script || !script_len || !bytes_out || len != EC_PRIVATE_KEY_LEN) return WALLY_EINVAL; - if ((ret = wally_hmac_sha256(bytes + SYMMETRIC_KEY_LEN, SYMMETRIC_KEY_LEN, script, script_len, bytes_out, len)) != WALLY_OK) - return ret; + ret = wally_hmac_sha256(bytes + HMAC_SHA512_LEN / 2, HMAC_SHA512_LEN / 2, script, script_len, bytes_out, len); + if (ret == WALLY_OK) + ret = wally_ec_private_key_verify(bytes_out, EC_PRIVATE_KEY_LEN); - return wally_ec_private_key_verify(bytes_out, EC_PRIVATE_KEY_LEN); + return ret; } int wally_asset_pak_whitelistproof_size( @@ -610,43 +591,60 @@ int wally_asset_pak_whitelistproof( size_t len, size_t *written) { + const secp256k1_context *ctx = secp_ctx(); secp256k1_pubkey online_secp_keys[SECP256K1_WHITELIST_MAX_N_KEYS]; secp256k1_pubkey offline_secp_keys[SECP256K1_WHITELIST_MAX_N_KEYS]; - const secp256k1_context *ctx = secp_ctx(); secp256k1_pubkey pubkey; secp256k1_whitelist_signature sig; const size_t num_keys = offline_keys_len / EC_PUBLIC_KEY_LEN; - size_t expected_sig_size = (1 + 32 * (1 + num_keys)); + size_t sig_size = (1 + 32 * (1 + num_keys)); size_t i; + int ret; - if (!online_keys || online_keys_len != offline_keys_len || !offline_keys || !offline_keys_len || - offline_keys_len % EC_PUBLIC_KEY_LEN || key_index >= num_keys || num_keys > SECP256K1_WHITELIST_MAX_N_KEYS || + if (written) + *written = 0; + + if (!ctx) + return WALLY_ENOMEM; + + if (!online_keys || online_keys_len != offline_keys_len || + !offline_keys || !offline_keys_len || + offline_keys_len % EC_PUBLIC_KEY_LEN || key_index >= num_keys || + num_keys > SECP256K1_WHITELIST_MAX_N_KEYS || !sub_pubkey || sub_pubkey_len != EC_PUBLIC_KEY_LEN || !online_priv_key || online_priv_key_len != EC_PRIVATE_KEY_LEN || !summed_key || summed_key_len != EC_PRIVATE_KEY_LEN || !pubkey_parse(ctx, &pubkey, sub_pubkey, sub_pubkey_len) || - len < expected_sig_size || !written) + !bytes_out || !len || !written) return WALLY_EINVAL; + if (len < sig_size) { + *written = sig_size; + return WALLY_OK; /* Tell the caller the required size */ + } + for (i = 0; i < num_keys; ++i) { if (!pubkey_parse(ctx, &online_secp_keys[i], online_keys + i * EC_PUBLIC_KEY_LEN, EC_PUBLIC_KEY_LEN) || - !pubkey_parse(ctx, &offline_secp_keys[i], offline_keys + i * EC_PUBLIC_KEY_LEN, EC_PUBLIC_KEY_LEN)) - return WALLY_ERROR; + !pubkey_parse(ctx, &offline_secp_keys[i], offline_keys + i * EC_PUBLIC_KEY_LEN, EC_PUBLIC_KEY_LEN)) { + ret = WALLY_EINVAL; + goto fail; + } } - if (!secp256k1_whitelist_sign(ctx, &sig, online_secp_keys, offline_secp_keys, num_keys, - &pubkey, online_priv_key, summed_key, key_index, NULL, NULL)) - return WALLY_ERROR; - - if (!secp256k1_whitelist_verify(ctx, &sig, online_secp_keys, offline_secp_keys, num_keys, &pubkey)) - return WALLY_ERROR; - - if (!secp256k1_whitelist_signature_serialize(ctx, bytes_out, &expected_sig_size, &sig)) - return WALLY_ERROR; - - *written = expected_sig_size; + if (secp256k1_whitelist_sign(ctx, &sig, online_secp_keys, offline_secp_keys, num_keys, + &pubkey, online_priv_key, summed_key, key_index, NULL, NULL) && + secp256k1_whitelist_verify(ctx, &sig, online_secp_keys, offline_secp_keys, num_keys, &pubkey) && + secp256k1_whitelist_signature_serialize(ctx, bytes_out, &sig_size, &sig)) { + ret = WALLY_OK; + *written = sig_size; + } else + ret = WALLY_ERROR; - return WALLY_OK; +fail: + wally_clear_3(online_secp_keys, sizeof(online_secp_keys), + offline_secp_keys, (sizeof(offline_secp_keys)), + &pubkey, sizeof(pubkey)); + return ret; } #endif /* BUILD_ELEMENTS */ diff --git a/src/internal.c b/src/internal.c index 76e75eb05..8e8458d13 100644 --- a/src/internal.c +++ b/src/internal.c @@ -231,6 +231,13 @@ void *wally_malloc(size_t size) return _ops.malloc_fn(size); } +void *wally_calloc(size_t size) +{ + void *p = _ops.malloc_fn(size); + (void) wally_bzero(p, size); + return p; +} + void wally_free(void *ptr) { _ops.free_fn(ptr); @@ -271,14 +278,14 @@ int wally_set_operations(const struct wally_operations *ops) return WALLY_OK; } -int wally_is_elements_build(uint64_t *value_out) +int wally_is_elements_build(size_t *written) { - if (!value_out) + if (!written) return WALLY_EINVAL; #ifdef BUILD_ELEMENTS - *value_out = 1; + *written = 1; #else - *value_out = 0; + *written = 0; #endif return WALLY_OK; } @@ -328,6 +335,14 @@ void wally_clear_6(void *p, size_t len, void *p2, size_t len2, _ops.bzero_fn(p6, len6); } +void clear_and_free(void *p, size_t len) +{ + if (p) { + wally_clear(p, len); + wally_free(p); + } +} + static bool wally_init_done = false; int wally_init(uint32_t flags) diff --git a/src/internal.h b/src/internal.h index d501f8a60..92a99b562 100644 --- a/src/internal.h +++ b/src/internal.h @@ -36,14 +36,18 @@ void wally_clear_6(void *p, size_t len, void *p2, size_t len2, void *p3, size_t len3, void *p4, size_t len4, void *p5, size_t len5, void *p6, size_t len6); +void clear_and_free(void *p, size_t len); + /* Fetch our internal operations function pointers */ const struct wally_operations *wally_ops(void); void *wally_malloc(size_t size); +void *wally_calloc(size_t size); void wally_free(void *ptr); char *wally_strdup(const char *str); #define malloc(size) __use_wally_malloc_internally__ +#define calloc(size) __use_wally_calloc_internally__ #define free(ptr) __use_wally_free_internally__ #ifdef strdup #undef strdup @@ -51,4 +55,3 @@ char *wally_strdup(const char *str); #define strdup(ptr) __use_wally_strdup_internally__ #endif /* LIBWALLY_INTERNAL_H */ - diff --git a/src/mnemonic.c b/src/mnemonic.c index 06f5f908a..0679315c8 100644 --- a/src/mnemonic.c +++ b/src/mnemonic.c @@ -62,18 +62,20 @@ char *mnemonic_from_bytes(const struct words *w, const unsigned char *bytes, siz int mnemonic_to_bytes(const struct words *w, const char *mnemonic, unsigned char *bytes_out, size_t len, size_t *written) { - struct words *mnemonic_w = wordlist_init(mnemonic); + struct words *mnemonic_w = NULL; size_t i; if (written) *written = 0; - if (!mnemonic_w) - return WALLY_ENOMEM; - if (!w || !bytes_out || !len) return WALLY_EINVAL; + mnemonic_w = wordlist_init(mnemonic); + + if (!mnemonic_w) + return WALLY_ENOMEM; + if ((mnemonic_w->len * w->bits + 7u) / 8u > len) goto cleanup; /* Return the length we would have written */ diff --git a/src/psbt.c b/src/psbt.c index 34a5e0244..092dc5ac0 100644 --- a/src/psbt.c +++ b/src/psbt.c @@ -1,44 +1,77 @@ #include "internal.h" #include "ccan/ccan/base64/base64.h" -#include "ccan/ccan/build_assert/build_assert.h" -#include +#include #include -#include #include #include #include #include "transaction_shared.h" +#include "psbt_int.h" #include "script_int.h" #include "script.h" +#include "pullpush.h" -const uint8_t WALLY_PSBT_MAGIC[5] = {'p', 's', 'b', 't', 0xff}; +/* FIXME: In input getters and setters, as well as in pubkey keyed maps, + * Check the validity of the values being set (e.g. the length is correct + * for the type, the pubkey is valid etc etc) + */ +static const uint8_t WALLY_PSBT_MAGIC[5] = {'p', 's', 'b', 't', 0xff}; +static const uint8_t WALLY_ELEMENTS_PSBT_MAGIC[5] = {'p', 's', 'e', 't', 0xff}; -static bool pubkey_is_compressed(unsigned char pubkey[EC_PUBLIC_KEY_UNCOMPRESSED_LEN]) { - return pubkey[0] == 0x02 || pubkey[0] == 0x03; +#ifdef BUILD_ELEMENTS +static const uint8_t WALLY_ELEMENTS_ID[8] = {'e', 'l', 'e', 'm', 'e', 'n', 't', 's'}; +static const size_t WALLY_ELEMENTS_ID_LEN = 8; +#endif /* BUILD_ELEMENTS */ + +static bool pubkey_is_compressed(const unsigned char pub_key[EC_PUBLIC_KEY_UNCOMPRESSED_LEN]) { + return pub_key[0] == 0x02 || pub_key[0] == 0x03; +} + +static size_t get_pubkey_len(const unsigned char *pub_key, size_t pub_key_len) +{ + if (!pub_key_len) + return 0; + return pubkey_is_compressed(pub_key) ? EC_PUBLIC_KEY_LEN : EC_PUBLIC_KEY_UNCOMPRESSED_LEN; +} + +static bool is_valid_pubkey_len(size_t len) +{ + return len == EC_PUBLIC_KEY_UNCOMPRESSED_LEN || len == EC_PUBLIC_KEY_LEN; +} + +static bool is_valid_optional_pubkey_len(size_t len) +{ + return !len || is_valid_pubkey_len(len); } +static bool is_equal_pubkey(const unsigned char *l, size_t l_len, const unsigned char *r, size_t r_len) +{ + if (!l || !r) + return l == r; /* Equal if both NULL only */ + + return l_len == r_len && memcmp(l, r, l_len) == 0; +} -int wally_keypath_map_init_alloc(size_t alloc_len, struct wally_keypath_map **output) +int wally_keypath_map_init_alloc(size_t allocation_len, struct wally_keypath_map **output) { struct wally_keypath_map *result; TX_CHECK_OUTPUT; TX_OUTPUT_ALLOC(struct wally_keypath_map); - if (alloc_len) { - result->items = wally_malloc(alloc_len * sizeof(*result->items)); + if (allocation_len) { + result->items = wally_calloc(allocation_len * sizeof(*result->items)); if (!result->items) { wally_free(result); *output = NULL; return WALLY_ENOMEM; } - wally_clear(result->items, alloc_len * sizeof(*result->items)); } - result->items_allocation_len = alloc_len; + result->items_allocation_len = allocation_len; result->num_items = 0; return WALLY_OK; } @@ -49,7 +82,7 @@ int wally_keypath_map_free(struct wally_keypath_map *keypaths) if (keypaths) { for (i = 0; i < keypaths->num_items; ++i) { - clear_and_free(keypaths->items[i].origin.path, keypaths->items[i].origin.path_len * sizeof(*keypaths->items[i].origin.path)); + clear_and_free(keypaths->items[i].path, keypaths->items[i].path_len * sizeof(*keypaths->items[i].path)); } clear_and_free(keypaths->items, keypaths->items_allocation_len * sizeof(*keypaths->items)); clear_and_free(keypaths, sizeof(*keypaths)); @@ -57,110 +90,127 @@ int wally_keypath_map_free(struct wally_keypath_map *keypaths) return WALLY_OK; } -static struct wally_keypath_map *clone_keypath_map(const struct wally_keypath_map *keypaths) +int wally_keypath_map_find(const struct wally_keypath_map *keypaths, + const unsigned char *pub_key, size_t pub_key_len, + size_t *written) { - struct wally_keypath_map *result; size_t i; - if (wally_keypath_map_init_alloc(keypaths->items_allocation_len, &result) != WALLY_OK) { - return NULL; - } + if (written) + *written = 0; + + if (!keypaths || !pub_key || !is_valid_pubkey_len(pub_key_len) || !written) + return WALLY_EINVAL; for (i = 0; i < keypaths->num_items; ++i) { - memcpy(&result->items[i].pubkey, keypaths->items[i].pubkey, EC_PUBLIC_KEY_UNCOMPRESSED_LEN); - memcpy(&result->items[i].origin.fingerprint, keypaths->items[i].origin.fingerprint, 4); - if (keypaths->items[i].origin.path) { - if (!clone_bytes((unsigned char **)&result->items[i].origin.path, (unsigned char *)keypaths->items[i].origin.path, keypaths->items[i].origin.path_len * sizeof(*keypaths->items[i].origin.path))) { - goto fail; - } - result->items[i].origin.path_len = keypaths->items[i].origin.path_len; + const struct wally_keypath_item *item = &keypaths->items[i]; + + if (is_equal_pubkey(pub_key, pub_key_len, + item->pubkey, get_pubkey_len(item->pubkey, sizeof(item->pubkey)))) { + *written = i + 1; /* Found */ + break; } } - result->num_items = keypaths->num_items; - - return result; - -fail: - wally_keypath_map_free(result); - return NULL; + return WALLY_OK; } -int wally_add_new_keypath(struct wally_keypath_map *keypaths, - unsigned char *pubkey, - size_t pubkey_len, - unsigned char *fingerprint, - size_t fingerprint_len, - uint32_t *path, - size_t path_len) +static int add_keypath_item(struct wally_keypath_map *keypaths, const struct wally_keypath_item *item) { - size_t latest; + const size_t pub_key_len = get_pubkey_len(item->pubkey, EC_PUBLIC_KEY_UNCOMPRESSED_LEN); + return wally_keypath_map_add(keypaths, item->pubkey, pub_key_len, + item->fingerprint, BIP32_KEY_FINGERPRINT_LEN, + item->path, item->path_len); +} - if (fingerprint_len != FINGERPRINT_LEN || (pubkey_len != EC_PUBLIC_KEY_UNCOMPRESSED_LEN && pubkey_len != EC_PUBLIC_KEY_LEN)) { - return WALLY_EINVAL; - } +static int replace_keypaths(const struct wally_keypath_map *src, + struct wally_keypath_map **dst) +{ + struct wally_keypath_map *result = NULL; + size_t i; + int ret = WALLY_OK; - if (keypaths->num_items == keypaths->items_allocation_len) { - struct wally_keypath_item *new_items; - size_t new_alloc_len = 1; - size_t orig_num_items = keypaths->num_items; - if (keypaths->items_allocation_len != 0) { - new_alloc_len = keypaths->items_allocation_len * 2; - } - new_items = wally_malloc(new_alloc_len * sizeof(struct wally_keypath_item)); - if (!new_items) { - return WALLY_ENOMEM; - } - wally_bzero(new_items, new_alloc_len * sizeof(*new_items)); - memcpy(new_items, keypaths->items, keypaths->items_allocation_len * sizeof(*keypaths->items)); + if (src) { + ret = wally_keypath_map_init_alloc(src->items_allocation_len, &result); - clear_and_free(keypaths->items, keypaths->items_allocation_len * sizeof(*keypaths->items)); - keypaths->items = new_items; - keypaths->num_items = orig_num_items; - keypaths->items_allocation_len = new_alloc_len; + for (i = 0; ret == WALLY_OK && i < src->num_items; ++i) + ret = add_keypath_item(result, src->items + i); } - latest = keypaths->num_items; + if (ret != WALLY_OK) { + wally_keypath_map_free(result); + } else { + wally_keypath_map_free(*dst); + *dst = result; + } + return ret; +} - memcpy(&keypaths->items[latest].pubkey, pubkey, pubkey_len); - memcpy(&keypaths->items[latest].origin.fingerprint, fingerprint, fingerprint_len); - if (path) { - if (!clone_bytes((unsigned char **)&keypaths->items[latest].origin.path, (unsigned char *)path, path_len * sizeof(*path))) { +static int array_grow(void **src, size_t num_items, size_t *allocation_len, size_t item_size) +{ + if (num_items == *allocation_len) { + /* Array is full, allocate more space */ + const size_t n = (*allocation_len == 0 ? 1 : *allocation_len) * 2; + void *p = realloc_array(*src, *allocation_len, n, item_size); + if (!p) return WALLY_ENOMEM; - } - keypaths->items[latest].origin.path_len = path_len; + /* Free and replace the old array with the new enlarged copy */ + clear_and_free(*src, num_items * item_size); + *src = p; + *allocation_len = n; } - keypaths->num_items++; - return WALLY_OK; } -static int add_keypath_item(struct wally_keypath_map *keypaths, struct wally_keypath_item *item) +int wally_keypath_map_add(struct wally_keypath_map *keypaths, + const unsigned char *pub_key, size_t pub_key_len, + const unsigned char *fingerprint, size_t fingerprint_len, + const uint32_t *path, size_t path_len) { - return wally_add_new_keypath(keypaths, item->pubkey, - EC_PUBLIC_KEY_UNCOMPRESSED_LEN, - item->origin.fingerprint, - FINGERPRINT_LEN, - item->origin.path, - item->origin.path_len); + size_t is_found; + int ret; + + if (!keypaths || !pub_key || !is_valid_pubkey_len(pub_key_len) || + !fingerprint || fingerprint_len != BIP32_KEY_FINGERPRINT_LEN || + BYTES_INVALID(path, path_len)) + return WALLY_EINVAL; + + ret = wally_keypath_map_find(keypaths, pub_key, pub_key_len, &is_found); + if (ret != WALLY_OK || is_found) + return ret; /* Return WALLY_OK and do nothing if already present */ + + ret = array_grow((void *)&keypaths->items, keypaths->num_items, + &keypaths->items_allocation_len, sizeof(struct wally_keypath_item)); + if (ret == WALLY_OK) { + struct wally_keypath_item *new_item = keypaths->items + keypaths->num_items; + + if (path) { + if (!clone_bytes((unsigned char **)&new_item->path, (unsigned char *)path, path_len * sizeof(*path))) + return WALLY_ENOMEM; + new_item->path_len = path_len; + } + memcpy(new_item->pubkey, pub_key, pub_key_len); + memcpy(new_item->fingerprint, fingerprint, fingerprint_len); + keypaths->num_items++; + } + return ret; } -int wally_partial_sigs_map_init_alloc(size_t alloc_len, struct wally_partial_sigs_map **output) +int wally_partial_sigs_map_init_alloc(size_t allocation_len, struct wally_partial_sigs_map **output) { struct wally_partial_sigs_map *result; TX_CHECK_OUTPUT; TX_OUTPUT_ALLOC(struct wally_partial_sigs_map); - if (alloc_len) { - result->items = wally_malloc(alloc_len * sizeof(*result->items)); + if (allocation_len) { + result->items = wally_calloc(allocation_len * sizeof(*result->items)); if (!result->items) { wally_free(result); *output = NULL; return WALLY_ENOMEM; } - wally_clear(result->items, alloc_len * sizeof(*result->items)); } - result->items_allocation_len = alloc_len; + result->items_allocation_len = allocation_len; result->num_items = 0; return WALLY_OK; } @@ -170,113 +220,113 @@ int wally_partial_sigs_map_free(struct wally_partial_sigs_map *sigs) size_t i; if (sigs) { - for (i = 0; i < sigs->num_items; ++i) { - if (sigs->items[i].sig) { - clear_and_free(sigs->items[i].sig, sigs->items[i].sig_len); - } - } + for (i = 0; i < sigs->num_items; ++i) + clear_and_free(sigs->items[i].sig, sigs->items[i].sig_len); clear_and_free(sigs->items, sigs->items_allocation_len * sizeof(*sigs->items)); clear_and_free(sigs, sizeof(*sigs)); } return WALLY_OK; } -static struct wally_partial_sigs_map *clone_partial_sigs_map(const struct wally_partial_sigs_map *sigs) +int wally_partial_sigs_map_find(const struct wally_partial_sigs_map *partial_sigs, + const unsigned char *pub_key, size_t pub_key_len, + size_t *written) { - struct wally_partial_sigs_map *result; size_t i; - if (wally_partial_sigs_map_init_alloc(sigs->items_allocation_len, &result) != WALLY_OK) { - return NULL; - } + if (written) + *written = 0; - for (i = 0; i < sigs->num_items; ++i) { - memcpy(&result->items[i].pubkey, sigs->items[i].pubkey, EC_PUBLIC_KEY_UNCOMPRESSED_LEN); - if (sigs->items[i].sig) { - if (!clone_bytes(&result->items[i].sig, sigs->items[i].sig, sigs->items[i].sig_len)) { - goto fail; - } - result->items[i].sig_len = sigs->items[i].sig_len; + if (!partial_sigs || !pub_key || !is_valid_pubkey_len(pub_key_len) || !written) + return WALLY_EINVAL; + + for (i = 0; i < partial_sigs->num_items; ++i) { + const struct wally_partial_sigs_item *item = &partial_sigs->items[i]; + + if (is_equal_pubkey(pub_key, pub_key_len, + item->pubkey, get_pubkey_len(item->pubkey, sizeof(item->pubkey)))) { + *written = i + 1; /* Found */ + break; } } - result->num_items = sigs->num_items; - return result; + return WALLY_OK; +} -fail: - wally_partial_sigs_map_free(result); - return NULL; +static int add_partial_sig_item(struct wally_partial_sigs_map *sigs, const struct wally_partial_sigs_item *item) +{ + const size_t pub_key_len = get_pubkey_len(item->pubkey, EC_PUBLIC_KEY_UNCOMPRESSED_LEN); + return wally_partial_sigs_map_add(sigs, item->pubkey, pub_key_len, + item->sig, item->sig_len); } -int wally_add_new_partial_sig(struct wally_partial_sigs_map *sigs, - unsigned char *pubkey, - size_t pubkey_len, - unsigned char *sig, - size_t sig_len) +static int replace_partial_sigs(const struct wally_partial_sigs_map *src, + struct wally_partial_sigs_map **dst) { - size_t latest; - if (pubkey_len != EC_PUBLIC_KEY_LEN && pubkey_len != EC_PUBLIC_KEY_UNCOMPRESSED_LEN) { - return WALLY_EINVAL; - } + struct wally_partial_sigs_map *result = NULL; + size_t i; + int ret = WALLY_OK; - if (sigs->num_items == sigs->items_allocation_len) { - struct wally_partial_sigs_item *new_items; - size_t new_alloc_len = 1; - size_t orig_num_items = sigs->num_items; - if (sigs->items_allocation_len != 0) { - new_alloc_len = sigs->items_allocation_len * 2; - } - new_items = wally_malloc(new_alloc_len * sizeof(struct wally_partial_sigs_item)); - if (!new_items) { - return WALLY_ENOMEM; - } - wally_bzero(new_items, new_alloc_len * sizeof(*new_items)); - memcpy(new_items, sigs->items, sigs->items_allocation_len * sizeof(*sigs->items)); + if (src) { + ret = wally_partial_sigs_map_init_alloc(src->items_allocation_len, &result); - clear_and_free(sigs->items, sigs->items_allocation_len * sizeof(*sigs->items)); - sigs->items = new_items; - sigs->num_items = orig_num_items; - sigs->items_allocation_len = new_alloc_len; + for (i = 0; ret == WALLY_OK && i < src->num_items; ++i) + ret = add_partial_sig_item(result, src->items + i); } - latest = sigs->num_items; - - memcpy(&sigs->items[latest].pubkey, pubkey, EC_PUBLIC_KEY_UNCOMPRESSED_LEN); - if (sig) { - if (!clone_bytes(&sigs->items[latest].sig, sig, sig_len)) { - return WALLY_ENOMEM; - } - sigs->items[latest].sig_len = sig_len; + if (ret != WALLY_OK) { + wally_partial_sigs_map_free(result); + } else { + wally_partial_sigs_map_free(*dst); + *dst = result; } - sigs->num_items++; - - return WALLY_OK; + return ret; } -static int add_partial_sig_item(struct wally_partial_sigs_map *sigs, struct wally_partial_sigs_item *item) +int wally_partial_sigs_map_add(struct wally_partial_sigs_map *sigs, + const unsigned char *pub_key, size_t pub_key_len, + const unsigned char *sig, size_t sig_len) { - return wally_add_new_partial_sig(sigs, item->pubkey, - EC_PUBLIC_KEY_UNCOMPRESSED_LEN, - item->sig, - item->sig_len); + size_t is_found; + int ret; + + if (!sigs || !pub_key || !is_valid_pubkey_len(pub_key_len) || + BYTES_INVALID(sig, sig_len)) + return WALLY_EINVAL; + + ret = wally_partial_sigs_map_find(sigs, pub_key, pub_key_len, &is_found); + if (ret != WALLY_OK || is_found) + return ret; /* Return WALLY_OK and do nothing if already present */ + + ret = array_grow((void *)&sigs->items, sigs->num_items, + &sigs->items_allocation_len, sizeof(struct wally_partial_sigs_item)); + if (ret == WALLY_OK) { + struct wally_partial_sigs_item *new_item = sigs->items + sigs->num_items; + + if (sig && !clone_bytes(&new_item->sig, sig, sig_len)) + return WALLY_ENOMEM; + new_item->sig_len = sig_len; + memcpy(&new_item->pubkey, pub_key, pub_key_len); + sigs->num_items++; + } + return ret; } -int wally_unknowns_map_init_alloc(size_t alloc_len, struct wally_unknowns_map **output) +int wally_unknowns_map_init_alloc(size_t allocation_len, struct wally_unknowns_map **output) { struct wally_unknowns_map *result; TX_CHECK_OUTPUT; TX_OUTPUT_ALLOC(struct wally_unknowns_map); - if (alloc_len) { - result->items = wally_malloc(alloc_len * sizeof(*result->items)); + if (allocation_len) { + result->items = wally_calloc(allocation_len * sizeof(*result->items)); if (!result->items) { wally_free(result); *output = NULL; return WALLY_ENOMEM; } - wally_clear(result->items, alloc_len * sizeof(*result->items)); } - result->items_allocation_len = alloc_len; + result->items_allocation_len = allocation_len; result->num_items = 0; return WALLY_OK; } @@ -287,12 +337,8 @@ int wally_unknowns_map_free(struct wally_unknowns_map *unknowns) if (unknowns) { for (i = 0; i < unknowns->num_items; ++i) { - if (unknowns->items[i].key) { - wally_clear(unknowns->items[i].key, unknowns->items[i].key_len); - } - if (unknowns->items[i].value) { - wally_clear(unknowns->items[i].value, unknowns->items[i].value_len); - } + clear_and_free(unknowns->items[i].key, unknowns->items[i].key_len); + clear_and_free(unknowns->items[i].value, unknowns->items[i].value_len); } clear_and_free(unknowns->items, unknowns->num_items * sizeof(*unknowns->items)); clear_and_free(unknowns, sizeof(*unknowns)); @@ -300,290 +346,292 @@ int wally_unknowns_map_free(struct wally_unknowns_map *unknowns) return WALLY_OK; } -static struct wally_unknowns_map *clone_unknowns_map(const struct wally_unknowns_map *unknowns) +int wally_unknowns_map_find(const struct wally_unknowns_map *unknowns, + const unsigned char *key, size_t key_len, + size_t *written) { - struct wally_unknowns_map *result; size_t i; - if (wally_unknowns_map_init_alloc(unknowns->items_allocation_len, &result) != WALLY_OK) { - return NULL; - } - - for (i = 0; i < unknowns->num_items; ++i) { - if (unknowns->items[i].key) { - if (!clone_bytes(&result->items[i].key, unknowns->items[i].key, unknowns->items[i].key_len)) { - goto fail; - } - result->items[i].key_len = unknowns->items[i].key_len; - } - if (unknowns->items[i].value) { - if (!clone_bytes(&result->items[i].value, unknowns->items[i].value, unknowns->items[i].value_len)) { - goto fail; - } - result->items[i].value_len = unknowns->items[i].value_len; - } - } - result->num_items = unknowns->num_items; - return result; -fail: - wally_unknowns_map_free(result); - return NULL; -} - -int wally_add_new_unknown(struct wally_unknowns_map *unknowns, - unsigned char *key, - size_t key_len, - unsigned char *value, - size_t value_len) -{ - size_t latest; - - if (unknowns->num_items == unknowns->items_allocation_len) { - struct wally_unknowns_item *new_items; - size_t new_alloc_len = 1; - size_t orig_num_items = unknowns->num_items; - if (unknowns->items_allocation_len != 0) { - new_alloc_len = unknowns->items_allocation_len * 2; - } - new_items = wally_malloc(new_alloc_len * sizeof(struct wally_unknowns_item)); - if (!new_items) { - return WALLY_ENOMEM; - } - wally_bzero(new_items, new_alloc_len * sizeof(*new_items)); - memcpy(new_items, unknowns->items, unknowns->items_allocation_len * sizeof(*unknowns->items)); + if (written) + *written = 0; - clear_and_free(unknowns->items, unknowns->items_allocation_len * sizeof(*unknowns->items)); - unknowns->items = new_items; - unknowns->num_items = orig_num_items; - unknowns->items_allocation_len = new_alloc_len; - } + if (!unknowns || !key || BYTES_INVALID(key, key_len) || !written) + return WALLY_EINVAL; - latest = unknowns->num_items; + for (i = 0; i < unknowns->num_items; ++i) { + const struct wally_unknowns_item *item = &unknowns->items[i]; - if (key) { - if (!clone_bytes(&unknowns->items[latest].key, key, key_len)) { - return WALLY_ENOMEM; - } - unknowns->items[latest].key_len = key_len; - } - if (value) { - if (!clone_bytes(&unknowns->items[latest].value, value, value_len)) { - return WALLY_ENOMEM; + if (key_len == item->key_len && memcmp(key, item->key, key_len) == 0) { + *written = i + 1; /* Found */ + break; } - unknowns->items[latest].value_len = value_len; } - unknowns->num_items++; - return WALLY_OK; } -static int add_unknowns_item(struct wally_unknowns_map *unknowns, struct wally_unknowns_item *item) +static int add_unknowns_item(struct wally_unknowns_map *unknowns, const struct wally_unknowns_item *item) { - return wally_add_new_unknown(unknowns, item->key, item->key_len, item->value, item->value_len); + return wally_unknowns_map_add(unknowns, item->key, item->key_len, item->value, item->value_len); } -int wally_psbt_input_init_alloc( - struct wally_tx *non_witness_utxo, - struct wally_tx_output *witness_utxo, - unsigned char *redeem_script, - size_t redeem_script_len, - unsigned char *witness_script, - size_t witness_script_len, - unsigned char *final_script_sig, - size_t final_script_sig_len, - struct wally_tx_witness_stack *final_witness, - struct wally_keypath_map *keypaths, - struct wally_partial_sigs_map *partial_sigs, - struct wally_unknowns_map *unknowns, - uint32_t sighash_type, - struct wally_psbt_input **output) +static int replace_unknowns(const struct wally_unknowns_map *src, + struct wally_unknowns_map **dst) { - struct wally_psbt_input *result; + struct wally_unknowns_map *result = NULL; + size_t i; int ret = WALLY_OK; - TX_CHECK_OUTPUT; - TX_OUTPUT_ALLOC(struct wally_psbt_input); + if (src) { + ret = wally_unknowns_map_init_alloc(src->items_allocation_len, &result); - if (non_witness_utxo && (ret = wally_psbt_input_set_non_witness_utxo(result, non_witness_utxo)) != WALLY_OK) { - goto fail; - } - if (witness_utxo && (ret = wally_psbt_input_set_witness_utxo(result, witness_utxo)) != WALLY_OK) { - goto fail; - } - if (redeem_script && (ret = wally_psbt_input_set_redeem_script(result, redeem_script, redeem_script_len)) != WALLY_OK) { - goto fail; - } - if (witness_script && (ret = wally_psbt_input_set_witness_script(result, witness_script, witness_script_len)) != WALLY_OK) { - goto fail; - } - if (final_script_sig && (ret = wally_psbt_input_set_final_script_sig(result, final_script_sig, final_script_sig_len)) != WALLY_OK) { - goto fail; - } - if (final_witness && (ret = wally_psbt_input_set_final_witness(result, final_witness)) != WALLY_OK) { - goto fail; - } - if (keypaths && (ret = wally_psbt_input_set_keypaths(result, keypaths)) != WALLY_OK) { - goto fail; - } - if (partial_sigs && (ret = wally_psbt_input_set_partial_sigs(result, partial_sigs)) != WALLY_OK) { - goto fail; - } - if (unknowns && (ret = wally_psbt_input_set_unknowns(result, unknowns)) != WALLY_OK) { - goto fail; + for (i = 0; ret == WALLY_OK && i < src->num_items; ++i) + ret = add_unknowns_item(result, src->items + i); } - ret = wally_psbt_input_set_sighash_type(result, sighash_type); + if (ret != WALLY_OK) { + wally_unknowns_map_free(result); + } else { + wally_unknowns_map_free(*dst); + *dst = result; + } return ret; +} -fail: - wally_psbt_input_free(result); - *output = NULL; +int wally_unknowns_map_add(struct wally_unknowns_map *unknowns, + const unsigned char *key, size_t key_len, + const unsigned char *value, size_t value_len) +{ + size_t is_found; + int ret; + + if (!unknowns || !key || BYTES_INVALID(key, key_len) || BYTES_INVALID(value, value_len)) + return WALLY_EINVAL; + + ret = wally_unknowns_map_find(unknowns, key, key_len, &is_found); + if (ret != WALLY_OK || is_found) + return ret; /* Return WALLY_OK and do nothing if already present */ + + ret = array_grow((void *)&unknowns->items, unknowns->num_items, + &unknowns->items_allocation_len, sizeof(struct wally_unknowns_item)); + if (ret == WALLY_OK) { + struct wally_unknowns_item *new_item = unknowns->items + unknowns->num_items; + + if (!clone_bytes(&new_item->key, key, key_len)) + return WALLY_ENOMEM; + if (value && !clone_bytes(&new_item->value, value, value_len)) { + clear_and_free(new_item->key, key_len); + new_item->key = NULL; + return WALLY_ENOMEM; + } + new_item->key_len = key_len; + new_item->value_len = value_len; + unknowns->num_items++; + } return ret; } -int wally_psbt_input_set_non_witness_utxo( - struct wally_psbt_input *input, - struct wally_tx *non_witness_utxo) +int wally_psbt_input_set_non_witness_utxo(struct wally_psbt_input *input, + const struct wally_tx *non_witness_utxo) { int ret = WALLY_OK; - struct wally_tx *result_non_witness_utxo; + struct wally_tx *new_tx = NULL; + + if (!input) + return WALLY_EINVAL; - if ((ret = clone_tx(non_witness_utxo, &result_non_witness_utxo)) != WALLY_OK) { + if (non_witness_utxo && + (ret = wally_tx_clone(non_witness_utxo, 0, &new_tx)) != WALLY_OK) return ret; - } + wally_tx_free(input->non_witness_utxo); - input->non_witness_utxo = result_non_witness_utxo; + input->non_witness_utxo = new_tx; return ret; } -int wally_psbt_input_set_witness_utxo( - struct wally_psbt_input *input, - struct wally_tx_output *witness_utxo) +int wally_psbt_input_set_witness_utxo(struct wally_psbt_input *input, + const struct wally_tx_output *witness_utxo) { int ret = WALLY_OK; - struct wally_tx_output *result_witness_utxo; + struct wally_tx_output *new_output = NULL; + + if (!input) + return WALLY_EINVAL; - if ((ret = wally_tx_output_init_alloc(witness_utxo->satoshi, witness_utxo->script, witness_utxo->script_len, &result_witness_utxo)) != WALLY_OK) { + if (witness_utxo && + (ret = wally_tx_output_clone_alloc(witness_utxo, &new_output) != WALLY_OK)) return ret; - } + wally_tx_output_free(input->witness_utxo); - input->witness_utxo = result_witness_utxo; + input->witness_utxo = new_output; return ret; } -int wally_psbt_input_set_redeem_script( - struct wally_psbt_input *input, - unsigned char *redeem_script, - size_t redeem_script_len) +int wally_psbt_input_set_redeem_script(struct wally_psbt_input *input, + const unsigned char *script, + size_t script_len) { - unsigned char *result_redeem_script; + if (!input) + return WALLY_EINVAL; + return replace_bytes(script, script_len, + &input->redeem_script, &input->redeem_script_len); +} - if (!clone_bytes(&result_redeem_script, redeem_script, redeem_script_len)) { - return WALLY_ENOMEM; - } - wally_free(input->redeem_script); - input->redeem_script = result_redeem_script; - input->redeem_script_len = redeem_script_len; - return WALLY_OK; +int wally_psbt_input_set_witness_script(struct wally_psbt_input *input, + const unsigned char *script, + size_t script_len) +{ + if (!input) + return WALLY_EINVAL; + return replace_bytes(script, script_len, + &input->witness_script, &input->witness_script_len); +} + +int wally_psbt_input_set_final_script_sig(struct wally_psbt_input *input, + const unsigned char *final_script_sig, + size_t final_script_sig_len) +{ + if (!input) + return WALLY_EINVAL; + return replace_bytes(final_script_sig, final_script_sig_len, + &input->final_script_sig, &input->final_script_sig_len); } -int wally_psbt_input_set_witness_script( - struct wally_psbt_input *input, - unsigned char *witness_script, - size_t witness_script_len) +int wally_psbt_input_set_final_witness(struct wally_psbt_input *input, + const struct wally_tx_witness_stack *final_witness) { - unsigned char *result_witness_script; + struct wally_tx_witness_stack *new_witness = NULL; + + if (!input) + return WALLY_EINVAL; - if (!clone_bytes(&result_witness_script, witness_script, witness_script_len)) { + if (final_witness && + (wally_tx_witness_stack_clone_alloc(final_witness, &new_witness) != WALLY_OK)) return WALLY_ENOMEM; - } - wally_free(input->witness_script); - input->witness_script = result_witness_script; - input->witness_script_len = witness_script_len; + + wally_tx_witness_stack_free(input->final_witness); + input->final_witness = new_witness; return WALLY_OK; } -int wally_psbt_input_set_final_script_sig( - struct wally_psbt_input *input, - unsigned char *final_script_sig, - size_t final_script_sig_len) +int wally_psbt_input_set_keypaths(struct wally_psbt_input *input, + const struct wally_keypath_map *keypaths) { - unsigned char *result_final_script_sig; + return input ? replace_keypaths(keypaths, &input->keypaths) : WALLY_EINVAL; +} - if (!clone_bytes(&result_final_script_sig, final_script_sig, final_script_sig_len)) { - return WALLY_ENOMEM; - } - wally_free(input->final_script_sig); - input->final_script_sig = result_final_script_sig; - input->final_script_sig_len = final_script_sig_len; - return WALLY_OK; +int wally_psbt_input_set_partial_sigs(struct wally_psbt_input *input, + const struct wally_partial_sigs_map *partial_sigs) +{ + return input ? replace_partial_sigs(partial_sigs, &input->partial_sigs) : WALLY_EINVAL; } -int wally_psbt_input_set_final_witness( - struct wally_psbt_input *input, - struct wally_tx_witness_stack *final_witness) +int wally_psbt_input_set_unknowns(struct wally_psbt_input *input, + const struct wally_unknowns_map *unknowns) { - struct wally_tx_witness_stack *result_final_witness; + return input ? replace_unknowns(unknowns, &input->unknowns) : WALLY_EINVAL; +} - if (!(result_final_witness = clone_witness(final_witness))) { - return WALLY_ENOMEM; - } - wally_tx_witness_stack_free(input->final_witness); - input->final_witness = result_final_witness; +int wally_psbt_input_set_sighash_type(struct wally_psbt_input *input, uint32_t sighash_type) +{ + if (!input) + return WALLY_EINVAL; + input->sighash_type = sighash_type; return WALLY_OK; } -int wally_psbt_input_set_keypaths( - struct wally_psbt_input *input, - struct wally_keypath_map *keypaths) +#ifdef BUILD_ELEMENTS +int wally_psbt_input_set_value(struct wally_psbt_input *input, uint64_t value) { - struct wally_keypath_map *result_keypaths; + if (!input) + return WALLY_EINVAL; + input->value = value; + input->has_value = 1u; + return WALLY_OK; +} - if (!(result_keypaths = clone_keypath_map(keypaths))) { - return WALLY_ENOMEM; - } - wally_keypath_map_free(input->keypaths); - input->keypaths = result_keypaths; +int wally_psbt_input_clear_value(struct wally_psbt_input *input) +{ + if (!input) + return WALLY_EINVAL; + input->value = 0; + input->has_value = 0; return WALLY_OK; } -int wally_psbt_input_set_partial_sigs( - struct wally_psbt_input *input, - struct wally_partial_sigs_map *partial_sigs) +int wally_psbt_input_set_vbf(struct wally_psbt_input *input, + const unsigned char *vbf, size_t vbf_len) { - struct wally_partial_sigs_map *result_partial_sigs; + if (!input || (vbf && vbf_len != BLINDING_FACTOR_LEN)) + return WALLY_EINVAL; + return replace_bytes(vbf, vbf_len, &input->vbf, &input->vbf_len); +} - if (!(result_partial_sigs = clone_partial_sigs_map(partial_sigs))) { - return WALLY_ENOMEM; - } - wally_partial_sigs_map_free(input->partial_sigs); - input->partial_sigs = result_partial_sigs; - return WALLY_OK; +int wally_psbt_input_set_asset(struct wally_psbt_input *input, + const unsigned char *asset, size_t asset_len) +{ + if (!input || (asset && asset_len != ASSET_TAG_LEN)) + return WALLY_EINVAL; + return replace_bytes(asset, asset_len, &input->asset, &input->asset_len); } -int wally_psbt_input_set_unknowns( - struct wally_psbt_input *input, - struct wally_unknowns_map *unknowns) +int wally_psbt_input_set_abf(struct wally_psbt_input *input, + const unsigned char *abf, size_t abf_len) { - struct wally_unknowns_map *result_unknowns; + if (!input || (abf && abf_len != BLINDING_FACTOR_LEN)) + return WALLY_EINVAL; + return replace_bytes(abf, abf_len, &input->abf, &input->abf_len); +} - if (!(result_unknowns = clone_unknowns_map(unknowns))) { - return WALLY_ENOMEM; - } - wally_unknowns_map_free(input->unknowns); - input->unknowns = result_unknowns; - return WALLY_OK; +int wally_psbt_input_set_peg_in_tx(struct wally_psbt_input *input, + const struct wally_tx *peg_in_tx) +{ + int ret = WALLY_OK; + struct wally_tx *new_tx = NULL; + + if (!input) + return WALLY_EINVAL; + + if (peg_in_tx && + (ret = wally_tx_clone(peg_in_tx, 0, &new_tx)) != WALLY_OK) + return ret; + + wally_tx_free(input->peg_in_tx); + input->peg_in_tx = new_tx; + return ret; } -int wally_psbt_input_set_sighash_type( - struct wally_psbt_input *input, - uint32_t sighash_type) +int wally_psbt_input_set_txoutproof(struct wally_psbt_input *input, + const unsigned char *txoutproof, + size_t txoutproof_len) { - input->sighash_type = sighash_type; - return WALLY_OK; + if (!input) + return WALLY_EINVAL; + return replace_bytes(txoutproof, txoutproof_len, + &input->txoutproof, &input->txoutproof_len); +} + +int wally_psbt_input_set_genesis_blockhash(struct wally_psbt_input *input, + const unsigned char *genesis_blockhash, + size_t genesis_blockhash_len) +{ + if (!input || (genesis_blockhash && genesis_blockhash_len != SHA256_LEN)) + return WALLY_EINVAL; + return replace_bytes(genesis_blockhash, genesis_blockhash_len, + &input->genesis_blockhash, &input->genesis_blockhash_len); } -int wally_psbt_input_free(struct wally_psbt_input *input) +int wally_psbt_input_set_claim_script(struct wally_psbt_input *input, + const unsigned char *script, + size_t script_len) +{ + if (!input) + return WALLY_EINVAL; + return replace_bytes(script, script_len, + &input->claim_script, &input->claim_script_len); +} +#endif /* BUILD_ELEMENTS */ + +static int psbt_input_free(struct wally_psbt_input *input, bool free_parent) { if (input) { wally_tx_free(input->non_witness_utxo); @@ -595,942 +643,958 @@ int wally_psbt_input_free(struct wally_psbt_input *input) wally_keypath_map_free(input->keypaths); wally_partial_sigs_map_free(input->partial_sigs); wally_unknowns_map_free(input->unknowns); + +#ifdef BUILD_ELEMENTS + clear_and_free(input->vbf, input->vbf_len); + clear_and_free(input->asset, input->asset_len); + clear_and_free(input->abf, input->abf_len); + wally_tx_free(input->peg_in_tx); + clear_and_free(input->txoutproof, input->txoutproof_len); + clear_and_free(input->genesis_blockhash, input->genesis_blockhash_len); + clear_and_free(input->claim_script, input->claim_script_len); +#endif /* BUILD_ELEMENTS */ + + wally_clear(input, sizeof(*input)); + if (free_parent) + wally_free(input); } return WALLY_OK; } -int wally_psbt_output_init_alloc( - unsigned char *redeem_script, - size_t redeem_script_len, - unsigned char *witness_script, - size_t witness_script_len, - struct wally_keypath_map *keypaths, - struct wally_unknowns_map *unknowns, - struct wally_psbt_output **output) +int wally_psbt_output_set_redeem_script(struct wally_psbt_output *output, + const unsigned char *script, + size_t script_len) { - struct wally_psbt_output *result; - int ret = WALLY_OK; - - TX_CHECK_OUTPUT; - TX_OUTPUT_ALLOC(struct wally_psbt_output); - - if (redeem_script && (ret = wally_psbt_output_set_redeem_script(result, redeem_script, redeem_script_len)) != WALLY_OK) { - goto fail; - } - if (witness_script && (ret = wally_psbt_output_set_witness_script(result, witness_script, witness_script_len)) != WALLY_OK) { - goto fail; - } - if (keypaths && (ret = wally_psbt_output_set_keypaths(result, keypaths)) != WALLY_OK) { - goto fail; - } - if (unknowns && (ret = wally_psbt_output_set_unknowns(result, unknowns)) != WALLY_OK) { - goto fail; - } - - return ret; - -fail: - wally_psbt_output_free(result); - *output = NULL; - return ret; + if (!output) + return WALLY_EINVAL; + return replace_bytes(script, script_len, + &output->redeem_script, &output->redeem_script_len); } -int wally_psbt_output_set_redeem_script( - struct wally_psbt_output *output, - unsigned char *redeem_script, - size_t redeem_script_len) +int wally_psbt_output_set_witness_script(struct wally_psbt_output *output, + const unsigned char *script, + size_t script_len) { - unsigned char *result_redeem_script; + if (!output) + return WALLY_EINVAL; + return replace_bytes(script, script_len, + &output->witness_script, &output->witness_script_len); +} - if (!clone_bytes(&result_redeem_script, redeem_script, redeem_script_len)) { - return WALLY_ENOMEM; - } - wally_free(output->redeem_script); - output->redeem_script = result_redeem_script; - output->redeem_script_len = redeem_script_len; - return WALLY_OK; +int wally_psbt_output_set_keypaths(struct wally_psbt_output *output, + const struct wally_keypath_map *keypaths) +{ + return output ? replace_keypaths(keypaths, &output->keypaths) : WALLY_EINVAL; } -int wally_psbt_output_set_witness_script( - struct wally_psbt_output *output, - unsigned char *witness_script, - size_t witness_script_len) +int wally_psbt_output_set_unknowns(struct wally_psbt_output *output, + const struct wally_unknowns_map *unknowns) { - unsigned char *result_witness_script; + return output ? replace_unknowns(unknowns, &output->unknowns) : WALLY_EINVAL; +} - if (!clone_bytes(&result_witness_script, witness_script, witness_script_len)) { - return WALLY_ENOMEM; - } - wally_free(output->witness_script); - output->witness_script = result_witness_script; - output->witness_script_len = witness_script_len; - return WALLY_OK; +#ifdef BUILD_ELEMENTS +int wally_psbt_output_set_blinding_pubkey(struct wally_psbt_output *output, + const unsigned char *pub_key, + size_t pub_key_len) +{ + if (!output || !is_valid_optional_pubkey_len(pub_key_len)) + return WALLY_EINVAL; + return replace_bytes(pub_key, pub_key_len, + &output->blinding_pubkey, &output->blinding_pubkey_len); } -int wally_psbt_output_set_keypaths( - struct wally_psbt_output *output, - struct wally_keypath_map *keypaths) +int wally_psbt_output_set_value_commitment(struct wally_psbt_output *output, + const unsigned char *commitment, + size_t commitment_len) { - struct wally_keypath_map *result_keypaths; + if (!output || (commitment && commitment_len != ASSET_COMMITMENT_LEN)) + return WALLY_EINVAL; + return replace_bytes(commitment, commitment_len, + &output->value_commitment, &output->value_commitment_len); +} - if (!(result_keypaths = clone_keypath_map(keypaths))) { - return WALLY_ENOMEM; - } - wally_keypath_map_free(output->keypaths); - output->keypaths = result_keypaths; - return WALLY_OK; +int wally_psbt_output_set_vbf(struct wally_psbt_output *output, + const unsigned char *vbf, size_t vbf_len) +{ + if (!output || (vbf && vbf_len != BLINDING_FACTOR_LEN)) + return WALLY_EINVAL; + return replace_bytes(vbf, vbf_len, &output->vbf, &output->vbf_len); } -int wally_psbt_output_set_unknowns( - struct wally_psbt_output *output, - struct wally_unknowns_map *unknowns) +int wally_psbt_output_set_asset_commitment(struct wally_psbt_output *output, + const unsigned char *commitment, + size_t commitment_len) { - struct wally_unknowns_map *result_unknowns; + if (!output || (commitment && commitment_len != ASSET_COMMITMENT_LEN)) + return WALLY_EINVAL; + return replace_bytes(commitment, commitment_len, + &output->asset_commitment, &output->asset_commitment_len); +} - if (!(result_unknowns = clone_unknowns_map(unknowns))) { - return WALLY_ENOMEM; - } - wally_unknowns_map_free(output->unknowns); - output->unknowns = result_unknowns; - return WALLY_OK; +int wally_psbt_output_set_abf(struct wally_psbt_output *output, + const unsigned char *abf, size_t abf_len) +{ + if (!output || (abf && abf_len != BLINDING_FACTOR_LEN)) + return WALLY_EINVAL; + return replace_bytes(abf, abf_len, &output->abf, &output->abf_len); } -int wally_psbt_output_free(struct wally_psbt_output *output) +int wally_psbt_output_set_nonce(struct wally_psbt_output *output, + const unsigned char *nonce, + size_t nonce_len) +{ + if (!output || (nonce_len && nonce_len != WALLY_TX_ASSET_CT_NONCE_LEN)) + return WALLY_EINVAL; + return replace_bytes(nonce, nonce_len, + &output->nonce, &output->nonce_len); +} + +int wally_psbt_output_set_rangeproof(struct wally_psbt_output *output, + const unsigned char *rangeproof, + size_t rangeproof_len) +{ + if (!output) + return WALLY_EINVAL; + return replace_bytes(rangeproof, rangeproof_len, + &output->rangeproof, &output->rangeproof_len); +} + +int wally_psbt_output_set_surjectionproof(struct wally_psbt_output *output, + const unsigned char *surjectionproof, + size_t surjectionproof_len) +{ + if (!output) + return WALLY_EINVAL; + return replace_bytes(surjectionproof, surjectionproof_len, + &output->surjectionproof, &output->surjectionproof_len); +} +#endif/* BUILD_ELEMENTS */ + +static int psbt_output_free(struct wally_psbt_output *output, bool free_parent) { if (output) { clear_and_free(output->redeem_script, output->redeem_script_len); clear_and_free(output->witness_script, output->witness_script_len); wally_keypath_map_free(output->keypaths); wally_unknowns_map_free(output->unknowns); + +#ifdef BUILD_ELEMENTS + clear_and_free(output->value_commitment, output->value_commitment_len); + clear_and_free(output->vbf, output->vbf_len); + clear_and_free(output->asset_commitment, output->asset_commitment_len); + clear_and_free(output->abf, output->abf_len); + clear_and_free(output->nonce, output->nonce_len); + clear_and_free(output->rangeproof, output->rangeproof_len); + clear_and_free(output->surjectionproof, output->surjectionproof_len); +#endif /* BUILD_ELEMENTS */ + + wally_clear(output, sizeof(*output)); + if (free_parent) + wally_free(output); } return WALLY_OK; } -int wally_psbt_init_alloc( - size_t inputs_allocation_len, - size_t outputs_allocation_len, - size_t global_unknowns_allocation_len, - struct wally_psbt **output) +int wally_psbt_init_alloc(uint32_t version, size_t inputs_allocation_len, + size_t outputs_allocation_len, + size_t global_unknowns_allocation_len, + struct wally_psbt **output) { - struct wally_psbt_input *new_inputs = NULL; - struct wally_psbt_output *new_outputs = NULL; struct wally_psbt *result; + int ret; TX_CHECK_OUTPUT; + if (version) + return WALLY_EINVAL; /* Only version 0 is specified/supported */ TX_OUTPUT_ALLOC(struct wally_psbt); - if (inputs_allocation_len) { - new_inputs = wally_malloc(inputs_allocation_len * sizeof(struct wally_psbt_input)); - wally_bzero(new_inputs, inputs_allocation_len * sizeof(*new_inputs)); - } - if (outputs_allocation_len) { - new_outputs = wally_malloc(outputs_allocation_len * sizeof(struct wally_psbt_output)); - wally_bzero(new_outputs, outputs_allocation_len * sizeof(*new_outputs)); - } - wally_unknowns_map_init_alloc(global_unknowns_allocation_len, &result->unknowns); - if ((inputs_allocation_len && !new_inputs) || - (outputs_allocation_len && !new_outputs) || - (global_unknowns_allocation_len && !result->unknowns)) { - wally_free(new_inputs); - wally_free(new_outputs); - wally_free(result->unknowns); - wally_free(result); - *output = NULL; - return WALLY_ENOMEM; + if (inputs_allocation_len) + result->inputs = wally_calloc(inputs_allocation_len * sizeof(struct wally_psbt_input)); + if (outputs_allocation_len) + result->outputs = wally_calloc(outputs_allocation_len * sizeof(struct wally_psbt_output)); + + ret = wally_unknowns_map_init_alloc(global_unknowns_allocation_len, &result->unknowns); + + if (ret != WALLY_OK || + (inputs_allocation_len && !result->inputs) || (outputs_allocation_len && !result->outputs)) { + wally_psbt_free(result); + return ret != WALLY_OK ? ret : WALLY_ENOMEM; } - result->inputs = new_inputs; - result->num_inputs = 0; + result->version = version; + memcpy(result->magic, WALLY_PSBT_MAGIC, sizeof(WALLY_PSBT_MAGIC)); result->inputs_allocation_len = inputs_allocation_len; - result->outputs = new_outputs; - result->num_outputs = 0; result->outputs_allocation_len = outputs_allocation_len; result->tx = NULL; return WALLY_OK; } +#ifdef BUILD_ELEMENTS +int wally_psbt_elements_init_alloc( + uint32_t version, + size_t inputs_allocation_len, + size_t outputs_allocation_len, + size_t global_unknowns_allocation_len, + struct wally_psbt **output) +{ + int ret = wally_psbt_init_alloc(version, inputs_allocation_len, + outputs_allocation_len, + global_unknowns_allocation_len, output); + if (ret == WALLY_OK) + memcpy((*output)->magic, WALLY_ELEMENTS_PSBT_MAGIC, sizeof(WALLY_ELEMENTS_PSBT_MAGIC)); + + return ret; +} +#endif /* BUILD_ELEMENTS */ + int wally_psbt_free(struct wally_psbt *psbt) { size_t i; if (psbt) { wally_tx_free(psbt->tx); - for (i = 0; i < psbt->num_inputs; ++i) { - wally_psbt_input_free(&psbt->inputs[i]); - } + for (i = 0; i < psbt->num_inputs; ++i) + psbt_input_free(&psbt->inputs[i], false); + wally_free(psbt->inputs); - for (i = 0; i < psbt->num_outputs; ++i) { - wally_psbt_output_free(&psbt->outputs[i]); - } + for (i = 0; i < psbt->num_outputs; ++i) + psbt_output_free(&psbt->outputs[i], false); + wally_free(psbt->outputs); wally_unknowns_map_free(psbt->unknowns); - wally_free(psbt); + clear_and_free(psbt, sizeof(*psbt)); } return WALLY_OK; } -int wally_psbt_set_global_tx( - struct wally_psbt *psbt, - struct wally_tx *tx) +int wally_psbt_get_global_tx_alloc(const struct wally_psbt *psbt, struct wally_tx **output) { - size_t i; - int ret = WALLY_OK; - - /* Needs a psbt that is completely empty, i.e. no tx, no inputs, and no outputs. */ - if (!tx || !psbt || psbt->tx || psbt->num_inputs != 0 || psbt->num_outputs != 0) { + TX_CHECK_OUTPUT; + if (!psbt) return WALLY_EINVAL; - } + if (!psbt->tx) + return WALLY_OK; /* Return a NULL tx if not present */ + return wally_tx_clone(psbt->tx, 0, output); +} - /* tx cannot have any scriptSigs or witnesses */ - for (i = 0; i < tx->num_inputs; ++i) { - if (tx->inputs[i].script || tx->inputs[i].witness) { - return WALLY_EINVAL; - } +#define PSBT_GET(name) \ + int wally_psbt_get_ ## name(const struct wally_psbt *psbt, size_t *written) { \ + if (written) \ + *written = 0; \ + if (!psbt || !written) \ + return WALLY_EINVAL; \ + *written = psbt->name; \ + return WALLY_OK; \ } - if ((ret = clone_tx(tx, &psbt->tx)) != WALLY_OK) { - goto fail; +PSBT_GET(version) +PSBT_GET(num_inputs) +PSBT_GET(num_outputs) + +static int psbt_set_global_tx(struct wally_psbt *psbt, struct wally_tx *tx, bool do_clone) +{ + struct wally_tx *new_tx = NULL; + struct wally_psbt_input *new_inputs = NULL; + struct wally_psbt_output *new_outputs = NULL; + size_t i; + int ret; + + if (!psbt || psbt->tx || psbt->num_inputs || psbt->num_outputs || !tx) + return WALLY_EINVAL; /* PSBT must be completely empty */ + + for (i = 0; i < tx->num_inputs; ++i) + if (tx->inputs[i].script || tx->inputs[i].witness) + return WALLY_EINVAL; /* tx mustn't have scriptSigs or witnesses */ + + if (do_clone && (ret = wally_tx_clone(tx, 0, &new_tx)) != WALLY_OK) + return ret; + + if (psbt->inputs_allocation_len < tx->num_inputs) + new_inputs = wally_calloc(tx->num_inputs * sizeof(struct wally_psbt_input)); + + if (psbt->outputs_allocation_len < tx->num_outputs) + new_outputs = wally_calloc(tx->num_outputs * sizeof(struct wally_psbt_output)); + + if ((psbt->inputs_allocation_len < tx->num_inputs && !new_inputs) || + (psbt->outputs_allocation_len < tx->num_outputs && !new_outputs)) { + wally_free(new_inputs); + wally_free(new_outputs); + wally_tx_free(new_tx); + return WALLY_ENOMEM; } - if (psbt->inputs_allocation_len < tx->num_inputs) { - if (psbt->inputs) { - wally_free(psbt->inputs); - } - psbt->inputs_allocation_len = 0; - psbt->inputs = wally_malloc(tx->num_inputs * sizeof(struct wally_psbt_input)); - if (!psbt->inputs) { - ret = WALLY_ENOMEM; - goto fail; - } + if (new_inputs) { + wally_free(psbt->inputs); + psbt->inputs = new_inputs; psbt->inputs_allocation_len = tx->num_inputs; } - wally_bzero(psbt->inputs, psbt->inputs_allocation_len * sizeof(*psbt->inputs)); - psbt->num_inputs = tx->num_inputs; - - if (psbt->outputs_allocation_len < tx->num_outputs) { - if (psbt->outputs) { - wally_free(psbt->outputs); - } - psbt->outputs_allocation_len = 0; - psbt->outputs = wally_malloc(tx->num_outputs * sizeof(struct wally_psbt_output)); + if (new_outputs) { + wally_free(psbt->outputs); + psbt->outputs = new_outputs; psbt->outputs_allocation_len = tx->num_outputs; - if (!psbt->outputs) { - ret = WALLY_ENOMEM; - goto fail; - } } - wally_bzero(psbt->outputs, psbt->outputs_allocation_len * sizeof(*psbt->outputs)); + psbt->num_inputs = tx->num_inputs; psbt->num_outputs = tx->num_outputs; + psbt->tx = do_clone ? new_tx : tx; + return WALLY_OK; +} - return ret; +int wally_psbt_set_global_tx(struct wally_psbt *psbt, const struct wally_tx *tx) +{ + return psbt_set_global_tx(psbt, (struct wally_tx *)tx, true); +} -fail: - if (psbt->tx) { - wally_tx_free(psbt->tx); - psbt->tx = NULL; +/* Stricter version of pull_subfield_end which insists there's nothing left. */ +static void subfield_nomore_end(const unsigned char **cursor, size_t *max, + const unsigned char *subcursor, + const size_t submax) +{ + if (submax) { + pull_failed(cursor, max); + } else { + pull_subfield_end(cursor, max, subcursor, submax); } - return ret; } -struct psbt_input_counts { - size_t num_unknowns; - size_t num_keypaths; - size_t num_partial_sigs; -}; +/* The remainder of the key is a public key, the value is a keypath */ +static int pull_keypath(const unsigned char **cursor, size_t *max, + const unsigned char *key, size_t key_len, + struct wally_keypath_map **keypaths) +{ + const unsigned char *val; + size_t i, val_max, is_found; + const unsigned char *fingerprint; + int ret; -struct psbt_output_counts { - size_t num_unknowns; - size_t num_keypaths; -}; + if (!is_valid_pubkey_len(key_len)) + return WALLY_EINVAL; -struct psbt_counts { - size_t num_global_unknowns; - struct psbt_input_counts *input_counts; - size_t num_inputs; - struct psbt_output_counts *output_counts; - size_t num_outputs; -}; + if (!*keypaths && (ret = wally_keypath_map_init_alloc(1, keypaths)) != WALLY_OK) + return ret; -static void free_psbt_count(struct psbt_counts *counts) -{ - if (counts) { - clear_and_free(counts->input_counts, counts->num_inputs * sizeof(*counts->input_counts)); - clear_and_free(counts->output_counts, counts->num_outputs * sizeof(*counts->output_counts)); - clear_and_free(counts, sizeof(*counts)); - } -} + ret = wally_keypath_map_find(*keypaths, key, key_len, &is_found); + if (ret == WALLY_OK && is_found) + ret = WALLY_EINVAL; /* Duplicates are invalid */ + if (ret != WALLY_OK) + return ret; + + pull_subfield_end(cursor, max, key, key_len); -/* Check that the bytes already read + bytes to be read < total len */ -#define CHECK_BUF_BOUNDS(p, i, begin, tl) if ((p - begin) + i > tl) { \ - ret = WALLY_EINVAL; \ - goto fail; \ + /* Start parsing the value field. */ + pull_subfield_start(cursor, max, pull_varint(cursor, max), &val, &val_max); + + /* Read the fingerprint */ + fingerprint = pull_skip(&val, &val_max, sizeof(BIP32_KEY_FINGERPRINT_LEN)); + + ret = wally_keypath_map_add(*keypaths, key, key_len, + fingerprint, BIP32_KEY_FINGERPRINT_LEN, NULL, 0); + if (ret == WALLY_OK) { + /* Remainder is the path */ + struct wally_keypath_item *kpitem; + kpitem = (*keypaths)->items + (*keypaths)->num_items - 1; + if ((kpitem->path = wally_malloc(val_max)) == NULL) + return WALLY_ENOMEM; + + kpitem->path_len = val_max / sizeof(uint32_t); + for (i = 0; val_max >= sizeof(uint32_t); ++i) { + kpitem->path[i] = pull_le32(&val, &val_max); + } + subfield_nomore_end(cursor, max, val, val_max); + } + return ret; } -static int count_psbt_parts( - const unsigned char *bytes, - size_t bytes_len, - struct psbt_counts **output) +/* The remainder of the key is a public key, the value is a signature */ +static int pull_partial_sig(const unsigned char **cursor, size_t *max, + const unsigned char *key, size_t key_len, + struct wally_partial_sigs_map **partial_sigs) { - struct psbt_counts *result; - size_t i, vl; - const unsigned char *key; - uint64_t key_len, value_len; - uint8_t type; - int ret = WALLY_OK; - const unsigned char *p = bytes, *end = bytes + bytes_len; + const unsigned char *val; + size_t val_len, is_found; + int ret; - TX_CHECK_OUTPUT; - TX_OUTPUT_ALLOC(struct psbt_counts); + if (!is_valid_pubkey_len(key_len)) + return WALLY_EINVAL; - result->num_global_unknowns = 0; - result->num_inputs = 0; - result->num_outputs = 0; + if (!*partial_sigs && wally_partial_sigs_map_init_alloc(1, partial_sigs) != WALLY_OK) + return WALLY_ENOMEM; - /* Skip the magic */ - CHECK_BUF_BOUNDS(p, (size_t)5, bytes, bytes_len) - p += 5; + ret = wally_partial_sigs_map_find(*partial_sigs, key, key_len, &is_found); + if (ret == WALLY_OK && is_found) + ret = WALLY_EINVAL; /* Duplicates are invalid */ + if (ret != WALLY_OK) + return ret; - /* Go through globals and count */ - while (p < end) { - /* Read the key length */ - vl = varint_from_bytes(p, &key_len); - CHECK_BUF_BOUNDS(p, key_len + vl, bytes, bytes_len) - p += vl; + pull_subfield_end(cursor, max, key, key_len); - if (key_len == 0) { - break; - } + val_len = pull_varlength(cursor, max); + val = pull_skip(cursor, max, val_len); - /* Read the key itself */ - key = p; - type = key[0]; - p += key_len; + return wally_partial_sigs_map_add(*partial_sigs, key, key_len, val, val_len); +} - /* Read value length */ - vl = varint_from_bytes(p, &value_len); - CHECK_BUF_BOUNDS(p, value_len + vl, bytes, bytes_len) - p += vl; +/* Rewind cursor to prekey, and append unknown key/value to unknowns */ +static int pull_unknown_key_value(const unsigned char **cursor, + size_t *max, + const unsigned char *pre_key, + struct wally_unknowns_map **unknowns) +{ + const unsigned char *key, *val; + size_t key_len, val_len, is_found; + int ret; - /* Process based on type */ - switch (type) { - case WALLY_PSBT_GLOBAL_UNSIGNED_TX: { - bool expect_wit; - if (analyze_tx(p, value_len, 0, &result->num_inputs, &result->num_outputs, &expect_wit) != WALLY_OK) { - ret = WALLY_EINVAL; - goto fail; - } - if ((result->input_counts = wally_malloc(result->num_inputs * sizeof(struct psbt_input_counts))) == NULL || - (result->output_counts = wally_malloc(result->num_outputs * sizeof(struct psbt_output_counts))) == NULL) { - ret = WALLY_ENOMEM; - goto fail; - } - break; - } - /* Unknowns */ - default: - result->num_global_unknowns++; - } + /* If we've already failed, it's invalid */ + if (!*cursor) + return WALLY_EINVAL; - /* Increment past value length */ - p += value_len; - } + if (!*unknowns && wally_unknowns_map_init_alloc(1, unknowns) != WALLY_OK) + return WALLY_ENOMEM; - /* Go through each input */ - for (i = 0; i < result->num_inputs && p < end; ++i) { - struct psbt_input_counts *input = &result->input_counts[i]; - input->num_keypaths = 0; - input->num_partial_sigs = 0; - input->num_unknowns = 0; - while (p < end) { - /* Read the key length */ - vl = varint_from_bytes(p, &key_len); - CHECK_BUF_BOUNDS(p, key_len + vl, bytes, bytes_len) - p += vl; + /* We have to unwind a bit, to get entire key again. */ + *max += (*cursor - pre_key); + *cursor = pre_key; - if (key_len == 0) { - break; - } + key_len = pull_varlength(cursor, max); + key = pull_skip(cursor, max, key_len); + val_len = pull_varlength(cursor, max); + val = pull_skip(cursor, max, val_len); - /* Read the key itself */ - key = p; - type = key[0]; - p += key_len; - - /* Read value length */ - vl = varint_from_bytes(p, &value_len); - CHECK_BUF_BOUNDS(p, value_len + vl, bytes, bytes_len) - p += vl; - - /* Process based on type */ - switch (type) { - case WALLY_PSBT_IN_NON_WITNESS_UTXO: - case WALLY_PSBT_IN_WITNESS_UTXO: - case WALLY_PSBT_IN_SIGHASH_TYPE: - case WALLY_PSBT_IN_REDEEM_SCRIPT: - case WALLY_PSBT_IN_WITNESS_SCRIPT: - case WALLY_PSBT_IN_FINAL_SCRIPTSIG: - case WALLY_PSBT_IN_FINAL_SCRIPTWITNESS: - break; - case WALLY_PSBT_IN_PARTIAL_SIG: - input->num_partial_sigs++; - break; - case WALLY_PSBT_IN_BIP32_DERIVATION: - input->num_keypaths++; - break; - /* Unknowns */ - default: - input->num_unknowns++; - } + ret = wally_unknowns_map_find(*unknowns, key, key_len, &is_found); + if (ret == WALLY_OK && is_found) + ret = WALLY_EINVAL; /* Duplicates are invalid */ + if (ret != WALLY_OK) + return ret; - /* Increment past value length */ - p += value_len; - } - } + return wally_unknowns_map_add(*unknowns, key, key_len, val, val_len); +} - /* Go through each output */ - for (i = 0; i < result->num_outputs && p < end; ++i) { - struct psbt_output_counts *psbt_output = &result->output_counts[i]; - psbt_output->num_keypaths = 0; - psbt_output->num_unknowns = 0; - while (p < end) { - /* Read the key length */ - vl = varint_from_bytes(p, &key_len); - CHECK_BUF_BOUNDS(p, key_len + vl, bytes, bytes_len) - p += vl; +#ifdef BUILD_ELEMENTS +static size_t push_elements_bytes_size(const struct wally_tx_output *out) +{ + size_t size = 0; + size += out->asset_len == 0 ? 1 : out->asset_len; + size += out->value_len == 0 ? 1 : out->value_len; + size += out->nonce_len == 0 ? 1 : out->nonce_len; + size += out->script_len == 0 ? 1 : out->script_len + 1; + return size; +} - if (key_len == 0) { - break; - } +static void push_elements_bytes(unsigned char **cursor, + size_t *max, + unsigned char *value, + size_t val_len) +{ + unsigned char empty = 0; + push_bytes(cursor, max, value ? value : &empty, value ? val_len : sizeof(empty)); +} - /* Read the key itself */ - key = p; - type = key[0]; - p += key_len; +static int pull_elements_confidential(const unsigned char **cursor, + size_t *max, + const unsigned char **value, + size_t *val_len, + size_t prefixA, size_t prefixB, + size_t prefixed_size, size_t explicit_size) +{ + /* First byte is always the 'version' which tells you what the value is */ + const uint8_t type = peek_u8(cursor, max); + size_t size; + + if (type == 0) { + /* Empty, Pop off the type */ + pull_u8(cursor, max); + *value = NULL; + *val_len = 0; + return WALLY_OK; + } + + if (type == 1) + size = explicit_size; + else if (type == prefixA || type == prefixB) + size = prefixed_size; + else + return WALLY_EINVAL; - /* Read value length */ - vl = varint_from_bytes(p, &value_len); - CHECK_BUF_BOUNDS(p, value_len + vl, bytes, bytes_len) - p += vl; + *value = pull_skip(cursor, max, size); + if (!*cursor) + return WALLY_EINVAL; + *val_len = size; + return WALLY_OK; +} - /* Process based on type */ - switch (type) { - case WALLY_PSBT_OUT_REDEEM_SCRIPT: - case WALLY_PSBT_OUT_WITNESS_SCRIPT: - break; - case WALLY_PSBT_OUT_BIP32_DERIVATION: - psbt_output->num_keypaths++; - break; - /* Unknowns */ - default: - psbt_output->num_unknowns++; - } +/* Either returns a 33-byte commitment to a confidential value, or + * a 64-bit explicit value. */ +static int pull_confidential_value(const unsigned char **cursor, + size_t *max, + const unsigned char **value, + size_t *val_len) - /* Increment past value length */ - p += value_len; - } - } +{ + return pull_elements_confidential(cursor, max, value, val_len, + WALLY_TX_ASSET_CT_VALUE_PREFIX_A, WALLY_TX_ASSET_CT_VALUE_PREFIX_B, + WALLY_TX_ASSET_CT_VALUE_LEN, WALLY_TX_ASSET_CT_VALUE_UNBLIND_LEN); +} - if (p != end) { - ret = WALLY_EINVAL; - goto fail; - } +static int pull_confidential_asset(const unsigned char **cursor, + size_t *max, + const unsigned char **asset, + size_t *asset_len) - return WALLY_OK; +{ + return pull_elements_confidential(cursor, max, asset, asset_len, + WALLY_TX_ASSET_CT_ASSET_PREFIX_A, WALLY_TX_ASSET_CT_ASSET_PREFIX_B, + WALLY_TX_ASSET_CT_ASSET_LEN, WALLY_TX_ASSET_CT_ASSET_LEN); +} -fail: - free_psbt_count(result); - *output = NULL; - return ret; +static int pull_nonce(const unsigned char **cursor, + size_t *max, + const unsigned char **nonce, + size_t *nonce_len) + +{ + return pull_elements_confidential(cursor, max, nonce, nonce_len, + WALLY_TX_ASSET_CT_NONCE_PREFIX_A, WALLY_TX_ASSET_CT_NONCE_PREFIX_B, + WALLY_TX_ASSET_CT_NONCE_LEN, WALLY_TX_ASSET_CT_NONCE_LEN); } -static int psbt_input_from_bytes( - const unsigned char *bytes, - size_t bytes_len, - struct psbt_input_counts counts, - size_t *bytes_read, - struct wally_psbt_input *result) +#endif /* BUILD_ELEMENTS */ + +static void fetch_varlength_ptr(const unsigned char **dst, size_t *len, + const unsigned char **cursor, size_t *max) { - const unsigned char *p = bytes, *end = bytes + bytes_len, *key, *value; - uint64_t key_len, value_len; - uint8_t type; - int ret = WALLY_OK; - size_t i, vl; - bool found_sep = false; + *len = pull_varlength(cursor, max); + *dst = pull_skip(cursor, max, *len); +} - /* Init and alloc the maps */ - if (counts.num_keypaths > 0) { - if ((ret = wally_keypath_map_init_alloc(counts.num_keypaths, &result->keypaths)) != WALLY_OK) { - return ret; - } - } - if (counts.num_partial_sigs > 0) { - if ((ret = wally_partial_sigs_map_init_alloc(counts.num_partial_sigs, &result->partial_sigs)) != WALLY_OK) { - return ret; - } - } - if (counts.num_unknowns > 0) { - if ((ret = wally_unknowns_map_init_alloc(counts.num_unknowns, &result->unknowns)) != WALLY_OK) { - return ret; - } - } +/* Pull and set a variable length byte buffer */ +#define PSBT_PULL_B(typ, name) \ + if (result->name) \ + return WALLY_EINVAL; /* Duplicate value */ \ + subfield_nomore_end(cursor, max, key, key_len); \ + fetch_varlength_ptr(&vl_p, &vl_len, cursor, max); \ + if (!vl_len) \ + result->name = wally_malloc(1); /* TODO: handle empty values more elegantly */ \ + else if ((ret = wally_psbt_ ## typ ## _set_ ## name(result, vl_p, vl_len)) != WALLY_OK) \ + return ret + +static int pull_psbt_input(const unsigned char **cursor, size_t *max, + uint32_t flags, struct wally_psbt_input *result) +{ + int ret; + size_t key_len, vl_len; + const unsigned char *pre_key, *vl_p; /* Read key value pairs */ - while (p < end) { - /* Read the key length */ - vl = varint_from_bytes(p, &key_len); - CHECK_BUF_BOUNDS(p, key_len + vl, bytes, bytes_len) - p += vl; - - if (key_len == 0) { - found_sep = true; - break; - } - - /* Read the key itself */ - key = p; - type = key[0]; - p += key_len; + pre_key = *cursor; + while ((key_len = pull_varlength(cursor, max)) != 0) { + const unsigned char *key, *val; + size_t val_max; - /* Pre-read the value length but don't increment for a sanity check */ - vl = varint_from_bytes(p, &value_len); - CHECK_BUF_BOUNDS(p, value_len + vl, bytes, bytes_len) + /* Start parsing key */ + pull_subfield_start(cursor, max, key_len, &key, &key_len); /* Process based on type */ - switch (type) { + switch (pull_varint(&key, &key_len)) { case WALLY_PSBT_IN_NON_WITNESS_UTXO: { - if (result->non_witness_utxo) { + if (result->non_witness_utxo) return WALLY_EINVAL; /* We already have a non witness utxo */ - } else if (key_len != 1) { - return WALLY_EINVAL; /* Global tx key is one byte type */ - } - p += varint_from_bytes(p, &value_len); - value = p; - wally_tx_from_bytes(value, value_len, 0, &result->non_witness_utxo); - p += value_len; + + subfield_nomore_end(cursor, max, key, key_len); + + /* Start parsing the value field. */ + pull_subfield_start(cursor, max, pull_varint(cursor, max), + &val, &val_max); + if ((ret = wally_tx_from_bytes(val, val_max, flags, + &result->non_witness_utxo)) != WALLY_OK) + return ret; + + pull_subfield_end(cursor, max, val, val_max); break; } case WALLY_PSBT_IN_WITNESS_UTXO: { - uint64_t amount = -1, script_len; - size_t script_len_len; - if (result->witness_utxo) { - return WALLY_EINVAL; /* We already have a witness utxo */ - } else if (key_len != 1) { - return WALLY_EINVAL; /* Global tx key is one byte type */ - } - p += varint_from_bytes(p, &value_len); - p += uint64_from_le_bytes(p, &amount); - script_len_len = varint_from_bytes(p, &script_len); - p += script_len_len; - ret = wally_tx_output_init_alloc(amount, p, script_len, &result->witness_utxo); - if (ret != WALLY_OK) { - return ret; + uint64_t amount, script_len; + const unsigned char *script; + + if (result->witness_utxo) + return WALLY_EINVAL; /* Duplicate value */ + + subfield_nomore_end(cursor, max, key, key_len); + + /* Start parsing the value field. */ + pull_subfield_start(cursor, max, pull_varint(cursor, max), + &val, &val_max); +#ifdef BUILD_ELEMENTS + if (flags & WALLY_TX_FLAG_USE_ELEMENTS) { + const unsigned char *asset, *value, *nonce; + size_t asset_len, value_len, nonce_len; + if ((ret = pull_confidential_asset(&val, &val_max, &asset, &asset_len)) != WALLY_OK) + return ret; + if ((ret = pull_confidential_value(&val, &val_max, &value, &value_len)) != WALLY_OK) + return ret; + if ((ret = pull_nonce(&val, &val_max, &nonce, &nonce_len)) != WALLY_OK) + return ret; + + script_len = pull_varint(&val, &val_max); + script = pull_skip(&val, &val_max, script_len); + if (!script || !script_len) + return WALLY_EINVAL; + + ret = wally_tx_elements_output_init_alloc(script, script_len, + asset, asset_len, + value, value_len, + nonce, nonce_len, + NULL, 0, NULL, 0, + &result->witness_utxo); + if (ret != WALLY_OK) + return ret; + + subfield_nomore_end(cursor, max, val, val_max); + break; } - p += script_len; - /* amount length (8 bytes) + script CSUint + script length = value length */ - if (8 + script_len_len + script_len != value_len) { +#endif /* BUILD_ELEMENTS */ + + amount = pull_le64(&val, &val_max); + script_len = pull_varint(&val, &val_max); + script = pull_skip(&val, &val_max, script_len); + if (!script || !script_len) return WALLY_EINVAL; - } + ret = wally_tx_output_init_alloc(amount, script, script_len, + &result->witness_utxo); + if (ret != WALLY_OK) + return ret; + + subfield_nomore_end(cursor, max, val, val_max); break; } case WALLY_PSBT_IN_PARTIAL_SIG: { - struct wally_partial_sigs_map *partial_sigs = result->partial_sigs; - if (key_len != 66 && key_len != 34) { - return WALLY_EINVAL; /* Size of key is unexpected */ - } - /* Check for duplicates */ - for (i = 0; i < partial_sigs->num_items; ++i) { - if (memcmp(partial_sigs->items[i].pubkey, &key[1], key_len - 1) == 0) { - return WALLY_EINVAL; /* Duplicate key */ - } - } - - memcpy(partial_sigs->items[partial_sigs->num_items].pubkey, &key[1], key_len - 1); - - /* Read the signature */ - p += varint_from_bytes(p, &value_len); - clone_bytes(&partial_sigs->items[partial_sigs->num_items].sig, p, value_len); - partial_sigs->items[partial_sigs->num_items].sig_len = value_len; - - partial_sigs->num_items++; - p += value_len; + ret = pull_partial_sig(cursor, max, key, key_len, &result->partial_sigs); + if (ret != WALLY_OK) + return ret; break; } case WALLY_PSBT_IN_SIGHASH_TYPE: { - if (result->sighash_type > 0) { - return WALLY_EINVAL; /* Sighash already provided */ - } else if (key_len != 1) { - return WALLY_EINVAL; /* Type is more than one byte */ - } - p += varint_from_bytes(p, &value_len); - p += uint32_from_le_bytes(p, &result->sighash_type); - break; - } - case WALLY_PSBT_IN_REDEEM_SCRIPT: { - if (result->redeem_script_len != 0) { - return WALLY_EINVAL; /* Already have a redeem script */ - } else if (key_len != 1) { - return WALLY_EINVAL; /* Type is more than one byte */ - } - p += varint_from_bytes(p, &value_len); - clone_bytes(&result->redeem_script, p, value_len); - result->redeem_script_len = value_len; + if (result->sighash_type != 0) + return WALLY_EINVAL; /* Duplicate value */ + + subfield_nomore_end(cursor, max, key, key_len); - p += value_len; + /* Start parsing the value field. */ + pull_subfield_start(cursor, max, + pull_varint(cursor, max), + &val, &val_max); + result->sighash_type = pull_le32(&val, &val_max); + subfield_nomore_end(cursor, max, val, val_max); break; } + case WALLY_PSBT_IN_REDEEM_SCRIPT: + PSBT_PULL_B(input, redeem_script); + break; case WALLY_PSBT_IN_WITNESS_SCRIPT: { - if (result->witness_script_len != 0) { - return WALLY_EINVAL; /* Already have a witness script */ - } else if (key_len != 1) { - return WALLY_EINVAL; /* Type is more than one byte */ - } - p += varint_from_bytes(p, &value_len); - clone_bytes(&result->witness_script, p, value_len); - result->witness_script_len = value_len; - - p += value_len; + PSBT_PULL_B(input, witness_script); break; } case WALLY_PSBT_IN_BIP32_DERIVATION: { - struct wally_keypath_map *keypaths = result->keypaths; - size_t path_len; - if (key_len != 66 && key_len != 34) { - return WALLY_EINVAL; /* Size of key is unexpected */ - } - /* Check for duplicates */ - for (i = 0; i < keypaths->num_items; ++i) { - if (memcmp(keypaths->items[i].pubkey, &key[1], key_len - 1) == 0) { - return WALLY_EINVAL; /* Duplicate key */ - } - } - - memcpy(keypaths->items[keypaths->num_items].pubkey, &key[1], key_len - 1); - - /* Read the path length */ - p += varint_from_bytes(p, &value_len); - if (value_len % 4 != 0 || value_len == 0) { - return WALLY_EINVAL; /* Invalid length for keypaths */ - } - path_len = (value_len / 4) - 1; - - /* Read the fingerprint */ - memcpy(keypaths->items[keypaths->num_items].origin.fingerprint, p, 4); - p += 4; - - /* Read the path itself */ - keypaths->items[keypaths->num_items].origin.path = wally_malloc(path_len * sizeof(uint32_t)); - for (i = 0; i < path_len; ++i) { - p += uint32_from_le_bytes(p, &keypaths->items[keypaths->num_items].origin.path[i]); - } - keypaths->items[keypaths->num_items].origin.path_len = path_len; - - keypaths->num_items++; + ret = pull_keypath(cursor, max, key, key_len, &result->keypaths); + if (ret != WALLY_OK) + return ret; break; } - case WALLY_PSBT_IN_FINAL_SCRIPTSIG: { - if (result->final_script_sig_len != 0) { - return WALLY_EINVAL; /* Already have a scriptSig */ - } else if (key_len != 1) { - return WALLY_EINVAL; /* Type is more than one byte */ - } - p += varint_from_bytes(p, &value_len); - clone_bytes(&result->final_script_sig, p, value_len); - result->final_script_sig_len = value_len; - - p += value_len; + case WALLY_PSBT_IN_FINAL_SCRIPTSIG: + PSBT_PULL_B(input, final_script_sig); break; - } case WALLY_PSBT_IN_FINAL_SCRIPTWITNESS: { uint64_t num_witnesses; - if (result->final_witness) { - return WALLY_EINVAL; /* Already have a scriptWitness */ - } else if (key_len != 1) { - return WALLY_EINVAL; /* Type is more than one byte */ - } - p += varint_from_bytes(p, &value_len); - p += varint_from_bytes(p, &num_witnesses); + size_t i; + if (result->final_witness) + return WALLY_EINVAL; /* Duplicate value */ + subfield_nomore_end(cursor, max, key, key_len); + + /* Start parsing the value field. */ + pull_subfield_start(cursor, max, + pull_varint(cursor, max), + &val, &val_max); + num_witnesses = pull_varint(&val, &val_max); ret = wally_tx_witness_stack_init_alloc(num_witnesses, &result->final_witness); - if (ret != WALLY_OK) { + if (ret != WALLY_OK) return ret; - } for (i = 0; i < num_witnesses; ++i) { - uint64_t witness_len; - p += varint_from_bytes(p, &witness_len); - ret = wally_tx_witness_stack_set(result->final_witness, i, p, witness_len); + uint64_t witness_len = pull_varint(&val, &val_max); + ret = wally_tx_witness_stack_set(result->final_witness, i, + pull_skip(&val, &val_max, witness_len), + witness_len); + if (ret != WALLY_OK) + return ret; + } + subfield_nomore_end(cursor, max, val, val_max); + break; + } +#ifdef BUILD_ELEMENTS + case WALLY_PSBT_PROPRIETARY_TYPE: { + const uint64_t id_len = pull_varlength(&key, &key_len); + + if (id_len != WALLY_ELEMENTS_ID_LEN || memcmp(key, WALLY_ELEMENTS_ID, id_len)) + goto unknown_type; + + /* Skip the elements_id prefix */ + pull_skip(&key, &key_len, WALLY_ELEMENTS_ID_LEN); + + switch (pull_varint(&key, &key_len)) { + case WALLY_PSBT_IN_ELEMENTS_VALUE: { + if (result->has_value) + return WALLY_EINVAL; /* Duplicate value */ + + subfield_nomore_end(cursor, max, key, key_len); + + /* Start parsing the value field. */ + pull_subfield_start(cursor, max, pull_varint(cursor, max), + &val, &val_max); + result->value = pull_le64(&val, &val_max); + subfield_nomore_end(cursor, max, val, val_max); + result->has_value = true; + break; + } + case WALLY_PSBT_IN_ELEMENTS_VALUE_BLINDER: + PSBT_PULL_B(input, vbf); + break; + case WALLY_PSBT_IN_ELEMENTS_ASSET: + PSBT_PULL_B(input, asset); + break; + case WALLY_PSBT_IN_ELEMENTS_ASSET_BLINDER: + PSBT_PULL_B(input, abf); + break; + case WALLY_PSBT_IN_ELEMENTS_PEG_IN_TX: { + if (result->peg_in_tx) + return WALLY_EINVAL; /* Duplicate value */ + + subfield_nomore_end(cursor, max, key, key_len); + + /* Start parsing the value field. */ + pull_subfield_start(cursor, max, + pull_varint(cursor, max), + &val, &val_max); + + ret = wally_tx_from_bytes(val, val_max, flags, &result->peg_in_tx); if (ret != WALLY_OK) return ret; - p += witness_len; + + pull_subfield_end(cursor, max, val, val_max); + break; + } + case WALLY_PSBT_IN_ELEMENTS_TXOUT_PROOF: + PSBT_PULL_B(input, txoutproof); + break; + case WALLY_PSBT_IN_ELEMENTS_GENESIS_HASH: + PSBT_PULL_B(input, genesis_blockhash); + break; + case WALLY_PSBT_IN_ELEMENTS_CLAIM_SCRIPT: + PSBT_PULL_B(input, claim_script); + break; + default: + goto unknown_type; } break; } - /* Unknowns */ +#endif /* BUILD_ELEMENTS */ default: { - struct wally_unknowns_map *unknowns = result->unknowns; - clone_bytes(&unknowns->items[unknowns->num_items].key, key, key_len); - unknowns->items[unknowns->num_items].key_len = key_len; - - p += varint_from_bytes(p, &value_len); - value = p; - clone_bytes(&unknowns->items[unknowns->num_items].value, value, value_len); - unknowns->items[unknowns->num_items].value_len = value_len; - - unknowns->num_items++; - p += value_len; +unknown_type: + /* Unknown case without elements or for unknown proprietary types */ + ret = pull_unknown_key_value(cursor, max, pre_key, &result->unknowns); + if (ret != WALLY_OK) + return ret; break; } } + pre_key = *cursor; } - if (!found_sep) { - return WALLY_EINVAL; - } - - *bytes_read = p - bytes; -fail: - return ret; + return WALLY_OK; } -static int psbt_output_from_bytes( - const unsigned char *bytes, - size_t bytes_len, - struct psbt_output_counts counts, - size_t *bytes_read, - struct wally_psbt_output *result) +static int pull_psbt_output(const unsigned char **cursor, size_t *max, + struct wally_psbt_output *result) { - const unsigned char *p = bytes, *end = bytes + bytes_len, *key, *value; - uint64_t key_len, value_len; - uint8_t type; - size_t i, vl; - bool found_sep = false; - int ret = WALLY_OK; - - /* Init and alloc the maps */ - if (counts.num_keypaths > 0) { - wally_keypath_map_init_alloc(counts.num_keypaths, &result->keypaths); - } - if (counts.num_unknowns > 0) { - wally_unknowns_map_init_alloc(counts.num_unknowns, &result->unknowns); - } - - /* Read key value pairs */ - while (p < end) { - /* Read the key length */ - vl = varint_from_bytes(p, &key_len); - CHECK_BUF_BOUNDS(p, key_len + vl, bytes, bytes_len) - p += vl; - - if (key_len == 0) { - found_sep = true; - break; - } + int ret; + size_t key_len, vl_len; + const unsigned char *pre_key, *vl_p; - /* Read the key itself */ - key = p; - type = key[0]; - p += key_len; + /* Read key value */ + pre_key = *cursor; + while ((key_len = pull_varlength(cursor, max)) != 0) { + const unsigned char *key; - /* Pre-read the value length but don't increment for a sanity check */ - vl = varint_from_bytes(p, &value_len); - CHECK_BUF_BOUNDS(p, value_len + vl, bytes, bytes_len) + /* Start parsing key */ + pull_subfield_start(cursor, max, key_len, &key, &key_len); /* Process based on type */ - switch (type) { - case WALLY_PSBT_OUT_REDEEM_SCRIPT: { - if (result->redeem_script_len != 0) { - return WALLY_EINVAL; /* Already have a redeem script */ - } else if (key_len != 1) { - return WALLY_EINVAL; /* Type is more than one byte */ - } - p += varint_from_bytes(p, &value_len); - clone_bytes(&result->redeem_script, p, value_len); - result->redeem_script_len = value_len; - - p += value_len; + switch (pull_varint(&key, &key_len)) { + case WALLY_PSBT_OUT_REDEEM_SCRIPT: + PSBT_PULL_B(output, redeem_script); break; - } - case WALLY_PSBT_OUT_WITNESS_SCRIPT: { - if (result->witness_script_len != 0) { - return WALLY_EINVAL; /* Already have a witness script */ - } else if (key_len != 1) { - return WALLY_EINVAL; /* Type is more than one byte */ - } - p += varint_from_bytes(p, &value_len); - clone_bytes(&result->witness_script, p, value_len); - result->witness_script_len = value_len; - - p += value_len; + case WALLY_PSBT_OUT_WITNESS_SCRIPT: + PSBT_PULL_B(output, witness_script); break; - } case WALLY_PSBT_OUT_BIP32_DERIVATION: { - struct wally_keypath_map *keypaths = result->keypaths; - size_t path_len; - if (key_len != 66 && key_len != 34) { - return WALLY_EINVAL; /* Size of key is unexpected */ - } - /* Check for duplicates */ - for (i = 0; i < keypaths->num_items; ++i) { - if (memcmp(keypaths->items[i].pubkey, &key[1], key_len - 1) == 0) { - return WALLY_EINVAL; /* Duplicate key */ - } - } - - memcpy(keypaths->items[keypaths->num_items].pubkey, &key[1], key_len - 1); + ret = pull_keypath(cursor, max, key, key_len, &result->keypaths); + if (ret != WALLY_OK) + return ret; + break; + } +#ifdef BUILD_ELEMENTS + case WALLY_PSBT_PROPRIETARY_TYPE: { + const uint64_t id_len = pull_varlength(&key, &key_len); - /* Read the path length */ - p += varint_from_bytes(p, &value_len); - if (value_len % 4 != 0 || value_len == 0) { - return WALLY_EINVAL; /* Invalid length for keypaths */ - } - path_len = (value_len / 4) - 1; + if (id_len != WALLY_ELEMENTS_ID_LEN || memcmp(key, WALLY_ELEMENTS_ID, id_len)) + goto unknown_type; - /* Read the fingerprint */ - memcpy(keypaths->items[keypaths->num_items].origin.fingerprint, p, 4); - p += 4; + /* Skip the elements_id prefix */ + pull_skip(&key, &key_len, WALLY_ELEMENTS_ID_LEN); - /* Read the path itself */ - keypaths->items[keypaths->num_items].origin.path = wally_malloc(path_len * sizeof(uint32_t)); - for (i = 0; i < path_len; ++i) { - p += uint32_from_le_bytes(p, &keypaths->items[keypaths->num_items].origin.path[i]); + switch (pull_varint(&key, &key_len)) { + case WALLY_PSBT_OUT_ELEMENTS_VALUE_COMMITMENT: + PSBT_PULL_B(output, value_commitment); + break; + case WALLY_PSBT_OUT_ELEMENTS_VALUE_BLINDER: + PSBT_PULL_B(output, vbf); + break; + case WALLY_PSBT_OUT_ELEMENTS_ASSET_COMMITMENT: + PSBT_PULL_B(output, asset_commitment); + break; + case WALLY_PSBT_OUT_ELEMENTS_ASSET_BLINDER: + PSBT_PULL_B(output, abf); + break; + case WALLY_PSBT_OUT_ELEMENTS_RANGE_PROOF: + PSBT_PULL_B(output, rangeproof); + break; + case WALLY_PSBT_OUT_ELEMENTS_SURJECTION_PROOF: + PSBT_PULL_B(output, surjectionproof); + break; + case WALLY_PSBT_OUT_ELEMENTS_BLINDING_PUBKEY: + PSBT_PULL_B(output, blinding_pubkey); + break; + case WALLY_PSBT_OUT_ELEMENTS_NONCE_COMMITMENT: + PSBT_PULL_B(output, nonce); + break; + default: + goto unknown_type; } - keypaths->items[keypaths->num_items].origin.path_len = path_len; - - keypaths->num_items++; break; } - /* Unknowns */ +#endif /* BUILD_ELEMENTS */ default: { - struct wally_unknowns_map *unknowns = result->unknowns; - clone_bytes(&unknowns->items[unknowns->num_items].key, key, key_len); - unknowns->items[unknowns->num_items].key_len = key_len; - - p += varint_from_bytes(p, &value_len); - value = p; - clone_bytes(&unknowns->items[unknowns->num_items].value, value, value_len); - unknowns->items[unknowns->num_items].value_len = value_len; - - unknowns->num_items++; - p += value_len; +unknown_type: + /* Unknown case without elements or for unknown proprietary types */ + ret = pull_unknown_key_value(cursor, max, pre_key, &result->unknowns); + if (ret != WALLY_OK) + return ret; break; } } + pre_key = *cursor; } - if (!found_sep) { - return WALLY_EINVAL; - } - - *bytes_read = p - bytes; -fail: - return ret; + return WALLY_OK; } -int wally_psbt_from_bytes( - const unsigned char *bytes, - size_t bytes_len, - struct wally_psbt **output) +int wally_psbt_from_bytes(const unsigned char *bytes, size_t len, + struct wally_psbt **output) { - const unsigned char *p = bytes, *end = bytes + bytes_len, *key, *value; - uint64_t key_len, value_len; - uint8_t type; - size_t i, vl; - int ret = WALLY_OK; - struct psbt_counts *counts = NULL; + const unsigned char *magic, *pre_key; + int ret; + size_t i, key_len; struct wally_psbt *result = NULL; - bool found_sep; + uint32_t flags = 0; TX_CHECK_OUTPUT; - /* Check the magic */ - if (bytes_len <= 5) { + magic = pull_skip(&bytes, &len, sizeof(WALLY_PSBT_MAGIC)); + if (!magic) { ret = WALLY_EINVAL; /* Not enough bytes */ goto fail; } - if (memcmp(p, WALLY_PSBT_MAGIC, 5) != 0 ) { + if (memcmp(magic, WALLY_PSBT_MAGIC, sizeof(WALLY_PSBT_MAGIC)) != 0 ) { +#ifdef BUILD_ELEMENTS + if (memcmp(magic, WALLY_ELEMENTS_PSBT_MAGIC, sizeof(WALLY_ELEMENTS_PSBT_MAGIC)) != 0) { + ret = WALLY_EINVAL; /* Invalid Magic */ + goto fail; + } + flags |= WALLY_TX_FLAG_USE_ELEMENTS; +#else ret = WALLY_EINVAL; /* Invalid Magic */ goto fail; - } - p += 5; - - /* Get a count of the psbt parts */ - if (count_psbt_parts(bytes, bytes_len, &counts) != WALLY_OK) { - ret = WALLY_EINVAL; - goto fail; +#endif /* BUILD_ELEMENTS */ } /* Make the wally_psbt */ - ret = wally_psbt_init_alloc(counts->num_inputs, counts->num_outputs, counts->num_global_unknowns, &result); - if (ret != WALLY_OK) { + ret = wally_psbt_init_alloc(0, 0, 0, 8, &result); + if (ret != WALLY_OK) goto fail; - } - *output = result; - /* Read globals first */ - found_sep = false; - while (p < end) { - /* Read the key length */ - vl = varint_from_bytes(p, &key_len); - CHECK_BUF_BOUNDS(p, key_len + vl, bytes, bytes_len) - p += vl; - - if (key_len == 0) { - found_sep = true; - break; - } + /* Set the magic */ + memcpy(result->magic, magic, sizeof(WALLY_PSBT_MAGIC)); - /* Read the key itself */ - key = p; - type = key[0]; - p += key_len; + /* Read globals first */ + pre_key = bytes; + while ((key_len = pull_varlength(&bytes, &len)) != 0) { + const unsigned char *key, *val; + size_t val_max; - /* Pre-read the value length but don't increment for a sanity check */ - vl = varint_from_bytes(p, &value_len); - CHECK_BUF_BOUNDS(p, value_len + vl, bytes, bytes_len) + /* Start parsing key */ + pull_subfield_start(&bytes, &len, key_len, &key, &key_len); /* Process based on type */ - switch (type) { + switch (pull_varint(&key, &key_len)) { case WALLY_PSBT_GLOBAL_UNSIGNED_TX: { - size_t j; - if (result->tx) { - ret = WALLY_EINVAL; /* We already have a global tx */ + struct wally_tx *tx; + + subfield_nomore_end(&bytes, &len, key, key_len); + + /* Start parsing the value field. */ + pull_subfield_start(&bytes, &len, + pull_varint(&bytes, &len), + &val, &val_max); + ret = wally_tx_from_bytes(val, val_max, flags, &tx); + if (ret == WALLY_OK) { + ret = psbt_set_global_tx(result, tx, false); + if (ret != WALLY_OK) + wally_tx_free(tx); + } + if (ret != WALLY_OK) goto fail; - } else if (key_len != 1) { - ret = WALLY_EINVAL; /* Global tx key is one byte type */ + pull_subfield_end(&bytes, &len, val, val_max); + break; + } + case WALLY_PSBT_GLOBAL_VERSION: { + if (result->version > 0) { + ret = WALLY_EINVAL; /* Version already provided */ goto fail; } - p += varint_from_bytes(p, &value_len); - value = p; - if ((ret = wally_tx_from_bytes(value, value_len, 0, &result->tx)) != WALLY_OK) { + subfield_nomore_end(&bytes, &len, key, key_len); + + /* Start parsing the value field. */ + pull_subfield_start(&bytes, &len, + pull_varint(&bytes, &len), + &val, &val_max); + result->version = pull_le32(&val, &val_max); + subfield_nomore_end(&bytes, &len, val, val_max); + if (result->version > WALLY_PSBT_HIGHEST_VERSION) { + ret = WALLY_EINVAL; /* Unsupported version number */ goto fail; } - p += value_len; - /* Make sure there are no scriptSigs and scriptWitnesses */ - for (j = 0; j < result->tx->num_inputs; ++j) { - if (result->tx->inputs[j].script_len != 0 || (result->tx->inputs[j].witness && result->tx->inputs[j].witness->num_items != 0)) { - ret = WALLY_EINVAL; /* Unsigned tx needs empty scriptSigs and scriptWtinesses */ - goto fail; - } - } break; } /* Unknowns */ default: { - struct wally_unknowns_map *unknowns = result->unknowns; - clone_bytes(&unknowns->items[unknowns->num_items].key, key, key_len); - unknowns->items[unknowns->num_items].key_len = key_len; - - p += varint_from_bytes(p, &value_len); - value = p; - clone_bytes(&unknowns->items[unknowns->num_items].value, value, value_len); - unknowns->items[unknowns->num_items].value_len = value_len; - - unknowns->num_items++; - p += value_len; + ret = pull_unknown_key_value(&bytes, &len, pre_key, &result->unknowns); + if (ret != WALLY_OK) + goto fail; break; } } + pre_key = bytes; } - if (!found_sep) { + /* We don't technically need to test here, but it's a minor optimization */ + if (!bytes) { ret = WALLY_EINVAL; /* Missing global separator */ goto fail; } @@ -1541,612 +1605,466 @@ int wally_psbt_from_bytes( } /* Read inputs */ - for (i = 0; i < counts->num_inputs && p < end; ++i) { - size_t bytes_read; - - ret = psbt_input_from_bytes(p, end - p, counts->input_counts[i], &bytes_read, &result->inputs[i]); - if (ret != WALLY_OK) { + for (i = 0; i < result->tx->num_inputs; ++i) { + ret = pull_psbt_input(&bytes, &len, flags, &result->inputs[i]); + if (ret != WALLY_OK) goto fail; - } - p += bytes_read; - result->num_inputs++; - } - - /* Make sure that the number of inputs matches the number of inputs in the transaction */ - if (result->num_inputs != result->tx->num_inputs) { - ret = WALLY_EINVAL; - goto fail; } /* Read outputs */ - for (i = 0; i < counts->num_outputs && p < end; ++i) { - size_t bytes_read; - - ret = psbt_output_from_bytes(p, end - p, counts->output_counts[i], &bytes_read, &result->outputs[i]); - if (ret != WALLY_OK) { + for (i = 0; i < result->tx->num_outputs; ++i) { + ret = pull_psbt_output(&bytes, &len, &result->outputs[i]); + if (ret != WALLY_OK) goto fail; - } - p += bytes_read; - result->num_outputs++; } - /* Make sure that the number of outputs matches the number ot outputs in the transaction */ - if (result->num_outputs != result->tx->num_outputs) { + /* If we ran out of data anywhere, fail. */ + if (!bytes) { ret = WALLY_EINVAL; goto fail; } - free_psbt_count(counts); + *output = result; return WALLY_OK; fail: - free_psbt_count(counts); wally_psbt_free(result); - *output = NULL; return ret; } -static int psbt_input_get_length( - const struct wally_psbt_input *input, - size_t *len) +int wally_psbt_get_length(const struct wally_psbt *psbt, uint32_t flags, size_t *written) { - int ret; - size_t out, tx_len, i; - if (!len) { - return WALLY_EINVAL; - } - - *len = 0; - out = 0; - - /* Non witness utxo */ - if (input->non_witness_utxo) { - out += 2; /* Key len and one byte type */ - ret = wally_tx_get_length(input->non_witness_utxo, WALLY_TX_FLAG_USE_WITNESS, &tx_len); - if (ret != WALLY_OK) { - return ret; - } - out += varbuff_get_length(tx_len); - } - /* Witness utxo */ - if (input->witness_utxo) { - size_t wit_size = 0; - out += 2; /* Key len and one byte type */ - wit_size += sizeof(input->witness_utxo->satoshi); - wit_size += varbuff_get_length(input->witness_utxo->script_len); - out += varbuff_get_length(wit_size); - } - /* Partial sigs */ - if (input->partial_sigs) { - struct wally_partial_sigs_map *partial_sigs = input->partial_sigs; - for (i = 0; i < partial_sigs->num_items; ++i) { - struct wally_partial_sigs_item *item = &partial_sigs->items[i]; - if (pubkey_is_compressed(item->pubkey)) { - out += varint_get_length(34); - out += 34; /* Compressed pubkey + 1 byte type */ - } else { - out += varint_get_length(66); - out += 66; /* Uncompressed pubkey + 1 byte type */ - } - out += varbuff_get_length(item->sig_len); - } - } - /* Sighash type */ - if (input->sighash_type > 0) { - out += 2; /* Key len and one byte type */ - out += varbuff_get_length(sizeof(input->sighash_type)); - } - /* Redeem script */ - if (input->redeem_script) { - out += 2; /* Key len and one byte type */ - out += varbuff_get_length(input->redeem_script_len); - } - /* Witness script */ - if (input->witness_script) { - out += 2; /* Key len and one byte type */ - out += varbuff_get_length(input->witness_script_len); - } - /* Keypaths */ - if (input->keypaths) { - struct wally_keypath_map *keypaths = input->keypaths; - for (i = 0; i < keypaths->num_items; ++i) { - size_t origin_len; - struct wally_keypath_item *item = &keypaths->items[i]; - if (pubkey_is_compressed(item->pubkey)) { - out += varint_get_length(34); - out += 34; /* Compressed pubkey + 1 byte type */ - } else { - out += varint_get_length(66); - out += 66; /* Uncompressed pubkey + 1 byte type */ - } - - origin_len = 4; /* Start with 4 bytes for fingerprint */ - origin_len += item->origin.path_len * sizeof(uint32_t); - out += varint_get_length(origin_len); - out += origin_len; - } - } - /* Final scriptSig */ - if (input->final_script_sig) { - out += 2; /* Key len and one byte type */ - out += varbuff_get_length(input->final_script_sig_len); - } - /* Final scriptWitness */ - if (input->final_witness) { - struct wally_tx_witness_stack *witness = input->final_witness; - size_t wit_len = varint_get_length(witness->num_items); - out += 2; /* Key len and one byte type */ - out += varint_get_length(witness->num_items); - for (i = 0; i < witness->num_items; ++i) { - out += varbuff_get_length(witness->items[i].witness_len); - wit_len += varbuff_get_length(witness->items[i].witness_len); - } - out += varint_get_length(wit_len); - } - /* Unknowns */ - if (input->unknowns) { - for (i = 0; i < input->unknowns->num_items; ++i) { - struct wally_unknowns_item *unknown = &input->unknowns->items[i]; - out += varbuff_get_length(unknown->key_len); - out += varbuff_get_length(unknown->value_len); - } - } - - /* Separator */ - out += 1; + return wally_psbt_to_bytes(psbt, flags, NULL, 0, written); +} - *len = out; - return WALLY_OK; +/* Literally a varbuff containing only type as a varint, then optional data */ +static void push_psbt_key( + unsigned char **cursor, size_t *max, + uint64_t type, const void *extra, size_t extra_len) +{ + push_varint(cursor, max, varint_get_length(type) + extra_len); + push_varint(cursor, max, type); + push_bytes(cursor, max, extra, extra_len); } -static int psbt_output_get_length( - const struct wally_psbt_output *output, - size_t *len) +#ifdef BUILD_ELEMENTS +/* Common case of pushing elements proprietary type keys */ +static void push_psbt_elements_key( + unsigned char **cursor, size_t *max, + uint64_t type, const void *extra, size_t extra_len) { - size_t out, i; - if (!len) { - return WALLY_EINVAL; - } + push_varint(cursor, max, varint_get_length(WALLY_PSBT_PROPRIETARY_TYPE) + + varint_get_length(WALLY_ELEMENTS_ID_LEN) + + WALLY_ELEMENTS_ID_LEN + varint_get_length(type) + extra_len); + push_varint(cursor, max, WALLY_PSBT_PROPRIETARY_TYPE); + push_varbuff(cursor, max, WALLY_ELEMENTS_ID, WALLY_ELEMENTS_ID_LEN); + push_varint(cursor, max, type); + push_bytes(cursor, max, extra, extra_len); +} +#endif /* BUILD_ELEMENTS */ - *len = 0; - out = 0; +static int push_length_and_tx( + unsigned char **cursor, size_t *max, + const struct wally_tx *tx, uint32_t flags) +{ + int ret; + size_t txlen; + unsigned char *p; - /* Redeem script */ - if (output->redeem_script) { - out += 2; /* Key len and one byte type */ - out += varbuff_get_length(output->redeem_script_len); - } - /* Witness script */ - if (output->witness_script) { - out += 2; /* Key len and one byte type */ - out += varbuff_get_length(output->witness_script_len); + ret = wally_tx_get_length(tx, flags, &txlen); + if (ret != WALLY_OK) { + return ret; } - /* Keypaths */ - if (output->keypaths) { - struct wally_keypath_map *keypaths = output->keypaths; - for (i = 0; i < keypaths->num_items; ++i) { - size_t origin_len; - struct wally_keypath_item *item = &keypaths->items[i]; - if (pubkey_is_compressed(item->pubkey)) { - out += varint_get_length(34); - out += 34; /* Compressed pubkey + 1 byte type */ - } else { - out += varint_get_length(66); - out += 66; /* Uncompressed pubkey + 1 byte type */ - } - origin_len = 4; /* Start with 4 bytes for fingerprint */ - origin_len += item->origin.path_len * sizeof(uint32_t); - out += varint_get_length(origin_len); - out += origin_len; - } - } - /* Unknowns */ - if (output->unknowns) { - for (i = 0; i < output->unknowns->num_items; ++i) { - struct wally_unknowns_item *unknown = &output->unknowns->items[i]; - out += varbuff_get_length(unknown->key_len); - out += varbuff_get_length(unknown->value_len); - } - } + push_varint(cursor, max, txlen); - /* Separator */ - out += 1; + /* FIXME: convert wally_tx to use push */ + p = push_bytes(cursor, max, NULL, txlen); + if (!p) { + /* We catch this in caller. */ + return WALLY_OK; + } - *len = out; - return WALLY_OK; + return wally_tx_to_bytes(tx, flags, p, txlen, &txlen); } -int wally_psbt_get_length( - const struct wally_psbt *psbt, - size_t *len) +static void push_witness_stack( + unsigned char **cursor, size_t *max, + const struct wally_tx_witness_stack *witness) { - int ret; - size_t out, tx_len, i; - if (!len) { - return WALLY_EINVAL; - } - - *len = 0; - out = 5; /* Start with 5 byte magic */ + size_t i; - /* Global tx */ - out += 2; - ret = wally_tx_get_length(psbt->tx, 0, &tx_len); - if (ret != WALLY_OK) { - return ret; + push_varint(cursor, max, witness->num_items); + for (i = 0; i < witness->num_items; ++i) { + push_varbuff(cursor, max, witness->items[i].witness, + witness->items[i].witness_len); } - out += varbuff_get_length(tx_len); +} - /* Global unknowns */ - if (psbt->unknowns) { - for (i = 0; i < psbt->unknowns->num_items; ++i) { - struct wally_unknowns_item *unknown = &psbt->unknowns->items[i]; - out += varbuff_get_length(unknown->key_len); - out += varbuff_get_length(unknown->value_len); - } - } +static void push_keypath_item( + unsigned char **cursor, size_t *max, + uint64_t type, + const struct wally_keypath_item *item) +{ + size_t origin_len, i; - /* Separator */ - out += 1; + push_psbt_key(cursor, max, type, item->pubkey, + get_pubkey_len(item->pubkey, sizeof(item->pubkey))); - /* Get lengths of each input and output */ - for (i = 0; i < psbt->num_inputs; ++i) { - struct wally_psbt_input *input = &psbt->inputs[i]; - size_t input_len; - psbt_input_get_length(input, &input_len); - out += input_len; - } - for (i = 0; i < psbt->num_outputs; ++i) { - struct wally_psbt_output *output = &psbt->outputs[i]; - size_t output_len; - psbt_output_get_length(output, &output_len); - out += output_len; - } + origin_len = BIP32_KEY_FINGERPRINT_LEN; + origin_len += item->path_len * sizeof(uint32_t); + push_varint(cursor, max, origin_len); - *len = out; - return WALLY_OK; + push_bytes(cursor, max, item->fingerprint, sizeof(item->fingerprint)); + for (i = 0; i < item->path_len; ++i) { + push_bytes(cursor, max, &item->path[i], sizeof(uint32_t)); + } } -static int psbt_input_to_bytes( - const struct wally_psbt_input *input, - unsigned char *bytes_out, size_t len, - size_t *bytes_written) +static int push_psbt_input( + unsigned char **cursor, size_t *max, + uint32_t flags, + const struct wally_psbt_input *input) { - unsigned char type, *p = bytes_out, *end = bytes_out + len; int ret; - size_t i, tx_len; + size_t i; + + (void)flags; /* Non witness utxo */ if (input->non_witness_utxo) { - type = WALLY_PSBT_IN_NON_WITNESS_UTXO; - p += varbuff_to_bytes(&type, 1, p); - ret = wally_tx_get_length(input->non_witness_utxo, WALLY_TX_FLAG_USE_WITNESS, &tx_len); + push_psbt_key(cursor, max, WALLY_PSBT_IN_NON_WITNESS_UTXO, NULL, 0); + ret = push_length_and_tx(cursor, max, + input->non_witness_utxo, + WALLY_TX_FLAG_USE_WITNESS); if (ret != WALLY_OK) { return ret; } - p += varint_to_bytes(tx_len, p); - ret = wally_tx_to_bytes(input->non_witness_utxo, WALLY_TX_FLAG_USE_WITNESS, p, end - p, &tx_len); - if (ret != WALLY_OK) { - return ret; - } - p += tx_len; } + /* Witness utxo */ +#ifdef BUILD_ELEMENTS + if ((flags & WALLY_TX_FLAG_USE_ELEMENTS) && input->witness_utxo) { + struct wally_tx_output *utxo = input->witness_utxo; + const size_t buff_len = push_elements_bytes_size(utxo); + size_t remaining = buff_len; + unsigned char buff[1024], *buff_p = buff, *ptr; + + if (buff_len > sizeof(buff) && !(buff_p = wally_malloc(buff_len))) + return WALLY_ENOMEM; + ptr = buff_p; + + /* Push the asset, value, nonce, then scriptpubkey */ + push_psbt_key(cursor, max, WALLY_PSBT_IN_WITNESS_UTXO, NULL, 0); + + push_elements_bytes(&ptr, &remaining, utxo->asset, utxo->asset_len); + push_elements_bytes(&ptr, &remaining, utxo->value, utxo->value_len); + push_elements_bytes(&ptr, &remaining, utxo->nonce, utxo->nonce_len); + push_varbuff(&ptr, &remaining, utxo->script, utxo->script_len); + + if (!remaining) + push_varbuff(cursor, max, buff_p, buff_len); + if (buff_p != buff) + clear_and_free(buff_p, buff_len); + if (remaining) + return WALLY_ERROR; /* Should not happen! */ + } else +#endif /* BUILD_ELEMENTS */ if (input->witness_utxo) { unsigned char wit_bytes[50], *w = wit_bytes; /* Witness outputs can be no larger than 50 bytes as specified in BIP 141 */ - size_t wit_len; - type = WALLY_PSBT_IN_WITNESS_UTXO; - p += varbuff_to_bytes(&type, 1, p); + size_t wit_max = sizeof(wit_bytes); - /* Serialize the output to the temp buffer; */ - w += uint64_to_le_bytes(input->witness_utxo->satoshi, w); - w += varbuff_to_bytes(input->witness_utxo->script, input->witness_utxo->script_len, w); - wit_len = w - wit_bytes; + push_psbt_key(cursor, max, WALLY_PSBT_IN_WITNESS_UTXO, NULL, 0); - p += varint_to_bytes(wit_len, p); - memcpy(p, wit_bytes, wit_len); - p += wit_len; + push_le64(&w, &wit_max, input->witness_utxo->satoshi); + push_varbuff(&w, &wit_max, + input->witness_utxo->script, + input->witness_utxo->script_len); + + if (!w) { + return WALLY_EINVAL; + } + push_varbuff(cursor, max, wit_bytes, w - wit_bytes); } /* Partial sigs */ if (input->partial_sigs) { struct wally_partial_sigs_map *partial_sigs = input->partial_sigs; for (i = 0; i < partial_sigs->num_items; ++i) { - struct wally_partial_sigs_item *item = &partial_sigs->items[i]; - if (pubkey_is_compressed(item->pubkey)) { - p += varint_to_bytes(34, p); - *p = WALLY_PSBT_IN_PARTIAL_SIG; - p++; - memcpy(p, item->pubkey, EC_PUBLIC_KEY_LEN); - p += EC_PUBLIC_KEY_LEN; - } else { - p += varint_to_bytes(66, p); - *p = WALLY_PSBT_IN_PARTIAL_SIG; - p++; - memcpy(p, item->pubkey, EC_PUBLIC_KEY_UNCOMPRESSED_LEN); - p += EC_PUBLIC_KEY_UNCOMPRESSED_LEN; - } - p += varbuff_to_bytes(item->sig, item->sig_len, p); + const struct wally_partial_sigs_item *p = &partial_sigs->items[i]; + + push_psbt_key(cursor, max, WALLY_PSBT_IN_PARTIAL_SIG, + p->pubkey, get_pubkey_len(p->pubkey, sizeof(p->pubkey))); + push_varbuff(cursor, max, p->sig, p->sig_len); } } /* Sighash type */ if (input->sighash_type > 0) { - type = WALLY_PSBT_IN_SIGHASH_TYPE; - p += varbuff_to_bytes(&type, 1, p); - p += varint_to_bytes(sizeof(uint32_t), p); - p += uint32_to_le_bytes(input->sighash_type, p); + push_psbt_key(cursor, max, WALLY_PSBT_IN_SIGHASH_TYPE, NULL, 0); + push_varint(cursor, max, sizeof(uint32_t)); + push_le32(cursor, max, input->sighash_type); } /* Redeem script */ if (input->redeem_script) { - type = WALLY_PSBT_IN_REDEEM_SCRIPT; - p += varbuff_to_bytes(&type, 1, p); - p += varbuff_to_bytes(input->redeem_script, input->redeem_script_len, p); + push_psbt_key(cursor, max, WALLY_PSBT_IN_REDEEM_SCRIPT, NULL, 0); + push_varbuff(cursor, max, + input->redeem_script, input->redeem_script_len); } /* Witness script */ if (input->witness_script) { - type = WALLY_PSBT_IN_WITNESS_SCRIPT; - p += varbuff_to_bytes(&type, 1, p); - p += varbuff_to_bytes(input->witness_script, input->witness_script_len, p); + push_psbt_key(cursor, max, WALLY_PSBT_IN_WITNESS_SCRIPT, NULL, 0); + push_varbuff(cursor, max, + input->witness_script, input->witness_script_len); } /* Keypaths */ if (input->keypaths) { - struct wally_keypath_map *keypaths = input->keypaths; - for (i = 0; i < keypaths->num_items; ++i) { - size_t origin_len, j; - struct wally_keypath_item *item = &keypaths->items[i]; - if (pubkey_is_compressed(item->pubkey)) { - p += varint_to_bytes(34, p); - *p = WALLY_PSBT_IN_BIP32_DERIVATION; - p++; - memcpy(p, item->pubkey, EC_PUBLIC_KEY_LEN); - p += EC_PUBLIC_KEY_LEN; - } else { - p += varint_to_bytes(66, p); - *p = WALLY_PSBT_IN_BIP32_DERIVATION; - p++; - memcpy(p, item->pubkey, EC_PUBLIC_KEY_UNCOMPRESSED_LEN); - p += EC_PUBLIC_KEY_UNCOMPRESSED_LEN; - } - - origin_len = 4; /* Start with 4 bytes for fingerprint */ - origin_len += item->origin.path_len * sizeof(uint32_t); - p += varint_to_bytes(origin_len, p); - - memcpy(p, item->origin.fingerprint, 4); - p += 4; - for (j = 0; j < item->origin.path_len; ++j) { - memcpy(p, &item->origin.path[j], sizeof(uint32_t)); - p += 4; - } + for (i = 0; i < input->keypaths->num_items; ++i) { + push_keypath_item(cursor, max, + WALLY_PSBT_IN_BIP32_DERIVATION, + &input->keypaths->items[i]); } } /* Final scriptSig */ if (input->final_script_sig) { - type = WALLY_PSBT_IN_FINAL_SCRIPTSIG; - p += varbuff_to_bytes(&type, 1, p); - p += varbuff_to_bytes(input->final_script_sig, input->final_script_sig_len, p); + push_psbt_key(cursor, max, WALLY_PSBT_IN_FINAL_SCRIPTSIG, NULL, 0); + push_varbuff(cursor, max, + input->final_script_sig, input->final_script_sig_len); } /* Final scriptWitness */ if (input->final_witness) { - struct wally_tx_witness_stack *witness = input->final_witness; - size_t wit_len = varint_get_length(witness->num_items); - type = WALLY_PSBT_IN_FINAL_SCRIPTWITNESS; - p += varbuff_to_bytes(&type, 1, p); - for (i = 0; i < witness->num_items; ++i) { - const struct wally_tx_witness_item *stack; - stack = witness->items + i; - wit_len += varint_get_length(stack->witness_len); - wit_len += stack->witness_len; - } + size_t wit_len; - p += varint_to_bytes(wit_len, p); - p += varint_to_bytes(witness->num_items, p); - for (i = 0; i < witness->num_items; ++i) { - const struct wally_tx_witness_item *stack; - stack = witness->items + i; - p += varbuff_to_bytes(stack->witness, stack->witness_len, p); + push_psbt_key(cursor, max, WALLY_PSBT_IN_FINAL_SCRIPTWITNESS, NULL, 0); + + /* First pass simply calculates length */ + wit_len = 0; + push_witness_stack(NULL, &wit_len, input->final_witness); + + push_varint(cursor, max, wit_len); + push_witness_stack(cursor, max, input->final_witness); + } +#ifdef BUILD_ELEMENTS + /* Confidential Assets blinding data */ + if (input->has_value) { + push_psbt_elements_key(cursor, max, WALLY_PSBT_IN_ELEMENTS_VALUE, NULL, 0); + push_varint(cursor, max, sizeof(leint64_t)); + push_le64(cursor, max, input->value); + } + if (input->vbf) { + push_psbt_elements_key(cursor, max, WALLY_PSBT_IN_ELEMENTS_VALUE_BLINDER, NULL, 0); + push_varbuff(cursor, max, input->vbf, input->vbf_len); + } + if (input->asset) { + push_psbt_elements_key(cursor, max, WALLY_PSBT_IN_ELEMENTS_ASSET, NULL, 0); + push_varbuff(cursor, max, input->asset, input->asset_len); + } + if (input->abf) { + push_psbt_elements_key(cursor, max, WALLY_PSBT_IN_ELEMENTS_ASSET_BLINDER, NULL, 0); + push_varbuff(cursor, max, input->abf, input->abf_len); + } + /* Peg ins */ + if (input->peg_in_tx) { + push_psbt_elements_key(cursor, max, WALLY_PSBT_IN_ELEMENTS_PEG_IN_TX, NULL, 0); + ret = push_length_and_tx(cursor, max, + input->peg_in_tx, + WALLY_TX_FLAG_USE_WITNESS); + if (ret != WALLY_OK) { + return ret; } } + if (input->txoutproof) { + push_psbt_elements_key(cursor, max, WALLY_PSBT_IN_ELEMENTS_TXOUT_PROOF, NULL, 0); + push_varbuff(cursor, max, input->txoutproof, input->txoutproof_len); + } + if (input->genesis_blockhash) { + push_psbt_elements_key(cursor, max, WALLY_PSBT_IN_ELEMENTS_GENESIS_HASH, NULL, 0); + push_varbuff(cursor, max, input->genesis_blockhash, input->genesis_blockhash_len); + } + if (input->claim_script) { + push_psbt_elements_key(cursor, max, WALLY_PSBT_IN_ELEMENTS_CLAIM_SCRIPT, NULL, 0); + push_varbuff(cursor, max, input->claim_script, input->claim_script_len); + } +#endif /* BUILD_ELEMENTS */ /* Unknowns */ if (input->unknowns) { for (i = 0; i < input->unknowns->num_items; ++i) { struct wally_unknowns_item *unknown = &input->unknowns->items[i]; - p += varint_to_bytes(unknown->key_len, p); - memcpy(p, unknown->key, unknown->key_len); - p += unknown->key_len; - p += varint_to_bytes(unknown->value_len, p); - memcpy(p, unknown->value, unknown->value_len); - p += unknown->value_len; + push_varbuff(cursor, max, unknown->key, unknown->key_len); + push_varbuff(cursor, max, unknown->value, unknown->value_len); } } /* Separator */ - *p = WALLY_PSBT_SEPARATOR; - p++; - - *bytes_written = p - bytes_out; - + push_u8(cursor, max, WALLY_PSBT_SEPARATOR); return WALLY_OK; } -static int psbt_output_to_bytes( - const struct wally_psbt_output *output, - unsigned char *bytes_out, - size_t *bytes_written) +static int push_psbt_output( + unsigned char **cursor, size_t *max, + const struct wally_psbt_output *output) { - unsigned char type, *p = bytes_out; size_t i; /* Redeem script */ if (output->redeem_script) { - type = WALLY_PSBT_OUT_REDEEM_SCRIPT; - p += varbuff_to_bytes(&type, 1, p); - p += varbuff_to_bytes(output->redeem_script, output->redeem_script_len, p); + push_psbt_key(cursor, max, WALLY_PSBT_OUT_REDEEM_SCRIPT, NULL, 0); + push_varbuff(cursor, max, + output->redeem_script, output->redeem_script_len); } /* Witness script */ if (output->witness_script) { - type = WALLY_PSBT_OUT_WITNESS_SCRIPT; - p += varbuff_to_bytes(&type, 1, p); - p += varbuff_to_bytes(output->witness_script, output->witness_script_len, p); + push_psbt_key(cursor, max, WALLY_PSBT_OUT_WITNESS_SCRIPT, NULL, 0); + push_varbuff(cursor, max, + output->witness_script, output->witness_script_len); } /* Keypaths */ if (output->keypaths) { - struct wally_keypath_map *keypaths = output->keypaths; - for (i = 0; i < keypaths->num_items; ++i) { - size_t origin_len, j; - struct wally_keypath_item *item = &keypaths->items[i]; - if (pubkey_is_compressed(item->pubkey)) { - p += varint_to_bytes(34, p); - *p = WALLY_PSBT_OUT_BIP32_DERIVATION; - p++; - memcpy(p, item->pubkey, EC_PUBLIC_KEY_LEN); - p += EC_PUBLIC_KEY_LEN; - } else { - p += varint_to_bytes(66, p); - *p = WALLY_PSBT_OUT_BIP32_DERIVATION; - p++; - memcpy(p, item->pubkey, EC_PUBLIC_KEY_UNCOMPRESSED_LEN); - p += EC_PUBLIC_KEY_UNCOMPRESSED_LEN; - } - - origin_len = 4; /* Start with 4 bytes for fingerprint */ - origin_len += item->origin.path_len * sizeof(uint32_t); - p += varint_to_bytes(origin_len, p); - - memcpy(p, item->origin.fingerprint, 4); - p += 4; - for (j = 0; j < item->origin.path_len; ++j) { - memcpy(p, &item->origin.path[j], sizeof(uint32_t)); - p += 4; - } + for (i = 0; i < output->keypaths->num_items; ++i) { + push_keypath_item(cursor, max, + WALLY_PSBT_OUT_BIP32_DERIVATION, + &output->keypaths->items[i]); } } +#ifdef BUILD_ELEMENTS + if (output->value_commitment) { + push_psbt_elements_key(cursor, max, WALLY_PSBT_OUT_ELEMENTS_VALUE_COMMITMENT, NULL, 0); + push_varbuff(cursor, max, output->value_commitment, output->value_commitment_len); + } + if (output->vbf) { + push_psbt_elements_key(cursor, max, WALLY_PSBT_OUT_ELEMENTS_VALUE_BLINDER, NULL, 0); + push_varbuff(cursor, max, output->vbf, output->vbf_len); + } + if (output->asset_commitment) { + push_psbt_elements_key(cursor, max, WALLY_PSBT_OUT_ELEMENTS_ASSET_COMMITMENT, NULL, 0); + push_varbuff(cursor, max, output->asset_commitment, output->asset_commitment_len); + } + if (output->abf) { + push_psbt_elements_key(cursor, max, WALLY_PSBT_OUT_ELEMENTS_ASSET_BLINDER, NULL, 0); + push_varbuff(cursor, max, output->abf, output->abf_len); + } + if (output->rangeproof) { + push_psbt_elements_key(cursor, max, WALLY_PSBT_OUT_ELEMENTS_RANGE_PROOF, NULL, 0); + push_varbuff(cursor, max, output->rangeproof, output->rangeproof_len); + } + if (output->surjectionproof) { + push_psbt_elements_key(cursor, max, WALLY_PSBT_OUT_ELEMENTS_SURJECTION_PROOF, NULL, 0); + push_varbuff(cursor, max, output->surjectionproof, output->surjectionproof_len); + } + if (output->blinding_pubkey) { + push_psbt_elements_key(cursor, max, WALLY_PSBT_OUT_ELEMENTS_BLINDING_PUBKEY, NULL, 0); + push_varbuff(cursor, max, output->blinding_pubkey, output->blinding_pubkey_len); + } + if (output->nonce) { + push_psbt_elements_key(cursor, max, WALLY_PSBT_OUT_ELEMENTS_NONCE_COMMITMENT, NULL, 0); + push_varbuff(cursor, max, output->nonce, output->nonce_len); + } +#endif /* BUILD_ELEMENTS */ /* Unknowns */ if (output->unknowns) { for (i = 0; i < output->unknowns->num_items; ++i) { struct wally_unknowns_item *unknown = &output->unknowns->items[i]; - p += varint_to_bytes(unknown->key_len, p); - memcpy(p, unknown->key, unknown->key_len); - p += unknown->key_len; - p += varint_to_bytes(unknown->value_len, p); - memcpy(p, unknown->value, unknown->value_len); - p += unknown->value_len; + push_varbuff(cursor, max, unknown->key, unknown->key_len); + push_varbuff(cursor, max, unknown->value, unknown->value_len); } } /* Separator */ - *p = WALLY_PSBT_SEPARATOR; - p++; - - *bytes_written = p - bytes_out; - + push_u8(cursor, max, WALLY_PSBT_SEPARATOR); return WALLY_OK; } -int wally_psbt_to_bytes( - const struct wally_psbt *psbt, - unsigned char *bytes_out, size_t len, - size_t *bytes_written) +int wally_psbt_to_bytes(const struct wally_psbt *psbt, uint32_t flags, + unsigned char *bytes_out, size_t len, + size_t *written) { - unsigned char type, *p = bytes_out, *end = bytes_out + len; - size_t calc_len, tx_len, i; + unsigned char *cursor = bytes_out; + size_t max = len, i, is_elements; + uint32_t tx_flags; int ret; - if (bytes_written) { - *bytes_written = 0; - } + if (written) + *written = 0; - ret = wally_psbt_get_length(psbt, &calc_len); - if (ret != WALLY_OK) { + if (flags != 0 || !written) + return WALLY_EINVAL; + + if ((ret = wally_psbt_is_elements(psbt, &is_elements)) != WALLY_OK) return ret; - } - if (calc_len > len) { - return WALLY_EINVAL; /* Buffer is not big enough */ - } - /* Magic */ - memcpy(p, WALLY_PSBT_MAGIC, 5); - p += 5; + tx_flags = is_elements ? WALLY_TX_FLAG_USE_ELEMENTS : 0; + push_bytes(&cursor, &max, psbt->magic, sizeof(psbt->magic)); /* Global tx */ - type = WALLY_PSBT_GLOBAL_UNSIGNED_TX; - p += varbuff_to_bytes(&type, 1, p); - ret = wally_tx_get_length(psbt->tx, 0, &tx_len); - if (ret != WALLY_OK) { - return ret; - } - p += varint_to_bytes(tx_len, p); - ret = wally_tx_to_bytes(psbt->tx, 0, p, end - p, &tx_len); - if (ret != WALLY_OK) { - return ret; + push_psbt_key(&cursor, &max, WALLY_PSBT_GLOBAL_UNSIGNED_TX, NULL, 0); + push_length_and_tx(&cursor, &max, psbt->tx, WALLY_TX_FLAG_ALLOW_PARTIAL); + + /* version */ + if (psbt->version > 0) { + push_psbt_key(&cursor, &max, WALLY_PSBT_GLOBAL_VERSION, NULL, 0); + push_varint(&cursor, &max, sizeof(uint32_t)); + push_le32(&cursor, &max, psbt->version); } - p += tx_len; /* Unknowns */ if (psbt->unknowns) { for (i = 0; i < psbt->unknowns->num_items; ++i) { struct wally_unknowns_item *unknown = &psbt->unknowns->items[i]; - p += varint_to_bytes(unknown->key_len, p); - memcpy(p, unknown->key, unknown->key_len); - p += unknown->key_len; - p += varint_to_bytes(unknown->value_len, p); - memcpy(p, unknown->value, unknown->value_len); - p += unknown->value_len; + push_varbuff(&cursor, &max, unknown->key, unknown->key_len); + push_varbuff(&cursor, &max, unknown->value, unknown->value_len); } } /* Separator */ - *p = WALLY_PSBT_SEPARATOR; - p++; + push_u8(&cursor, &max, WALLY_PSBT_SEPARATOR); - /* Get lengths of each input and output */ + /* Push each input and output */ for (i = 0; i < psbt->num_inputs; ++i) { struct wally_psbt_input *input = &psbt->inputs[i]; - size_t input_len; - ret = psbt_input_to_bytes(input, p, end - p, &input_len); + ret = push_psbt_input(&cursor, &max, tx_flags, input); if (ret != WALLY_OK) { return ret; } - p += input_len; } for (i = 0; i < psbt->num_outputs; ++i) { struct wally_psbt_output *output = &psbt->outputs[i]; - size_t output_len; - ret = psbt_output_to_bytes(output, p, &output_len); + ret = push_psbt_output(&cursor, &max, output); if (ret != WALLY_OK) { return ret; } - p += output_len; } - *bytes_written = p - bytes_out; + + if (cursor == NULL) { + /* Once cursor was NULL, max accumulates hm bytes we needed */ + *written = len + max; + } else { + *written = len - max; + } + return WALLY_OK; } -int wally_psbt_from_base64( - const char *string, - struct wally_psbt **output) +int wally_psbt_from_base64(const char *base64, struct wally_psbt **output) { char *decoded; - size_t safe_len, string_len; + size_t safe_len, base64_len; ssize_t decoded_len; int ret; - if (!string) { + TX_CHECK_OUTPUT; + if (!base64) return WALLY_EINVAL; - } - string_len = strlen(string); + base64_len = strlen(base64); /* Allocate the decoded buffer */ - safe_len = base64_decoded_length(string_len); + safe_len = base64_decoded_length(base64_len); if ((decoded = wally_malloc(safe_len)) == NULL) { ret = WALLY_ENOMEM; goto done; } /* Decode the base64 psbt */ - decoded_len = base64_decode(decoded, safe_len, string, string_len); - if (decoded_len <= 5) { /* Make sure we also have enough bytes for the magic */ - ret = WALLY_EINVAL; + decoded_len = base64_decode(decoded, safe_len, base64, base64_len); + if (decoded_len <= (ssize_t)sizeof(WALLY_PSBT_MAGIC)) { + ret = WALLY_EINVAL; /* Not enough bytes for the magic */ goto done; } @@ -2154,35 +2072,33 @@ int wally_psbt_from_base64( ret = wally_psbt_from_bytes((unsigned char *)decoded, decoded_len, output); done: - if (decoded) { - wally_free(decoded); - } + clear_and_free(decoded, safe_len); return ret; } -int wally_psbt_to_base64( - struct wally_psbt *psbt, - char **output) +int wally_psbt_to_base64(const struct wally_psbt *psbt, uint32_t flags, char **output) { unsigned char *buff; char *result = NULL; - size_t len, written, b64_safe_len; - ssize_t b64_len; + size_t len, written, b64_safe_len = 0; int ret = WALLY_OK; - if (!output || !psbt) { + TX_CHECK_OUTPUT; + if (!psbt) return WALLY_EINVAL; - } - if ((ret = wally_psbt_get_length(psbt, &len)) != WALLY_OK) { + if ((ret = wally_psbt_get_length(psbt, flags, &len)) != WALLY_OK) return ret; - } - if ((buff = wally_malloc(len)) == NULL) { + + if ((buff = wally_malloc(len)) == NULL) return WALLY_ENOMEM; - } /* Get psbt bytes */ - if ((ret = wally_psbt_to_bytes(psbt, buff, len, &written)) != WALLY_OK) { + if ((ret = wally_psbt_to_bytes(psbt, flags, buff, len, &written)) != WALLY_OK) + goto done; + + if (written != len) { + ret = WALLY_ERROR; /* Length calculated incorrectly */ goto done; } @@ -2192,7 +2108,7 @@ int wally_psbt_to_base64( ret = WALLY_ENOMEM; goto done; } - if ((b64_len = base64_encode(result, b64_safe_len, (char *)buff, written)) <= 0) { + if (base64_encode(result, b64_safe_len, (char *)buff, written) <= 0) { ret = WALLY_EINVAL; goto done; } @@ -2200,339 +2116,229 @@ int wally_psbt_to_base64( result = NULL; done: - if (result) { - clear_and_free(result, b64_safe_len); - } - if (buff) { - clear_and_free(buff, len); - } + clear_and_free(result, b64_safe_len); + clear_and_free(buff, len); return ret; } -static int get_txid( - struct wally_tx *tx, - unsigned char *txid, - size_t txid_len) +static int combine_unknowns(struct wally_unknowns_map **dst, + const struct wally_unknowns_map *src) { - unsigned char *bytes = NULL; - size_t calc, written; int ret = WALLY_OK; + size_t i; - if (!tx || !txid || txid_len != SHA256_LEN) { + if (!dst) return WALLY_EINVAL; - } - if ((ret = wally_tx_get_length(tx, 0, &calc)) != WALLY_OK) { - return ret; - } - if ((bytes = wally_malloc(calc)) == NULL) { - return WALLY_ENOMEM; - } - if ((ret = wally_tx_to_bytes(tx, 0, bytes, calc, &written)) == WALLY_OK) { - ret = wally_sha256d(bytes, written, txid, SHA256_LEN); - } + if (!src) + return WALLY_OK; /* No-op */ + + if (!*dst) + ret = wally_unknowns_map_init_alloc(src->items_allocation_len, dst); + + for (i = 0; ret == WALLY_OK && i < src->num_items; ++i) + ret = add_unknowns_item(*dst, &src->items[i]); - wally_free(bytes); return ret; } -static int merge_unknowns_into( - struct wally_unknowns_map *dst, - const struct wally_unknowns_map *src) +static int combine_keypath(struct wally_keypath_map **dst, + const struct wally_keypath_map *src) { int ret = WALLY_OK; - size_t i, j; + size_t i; - if (!src || !dst) { + if (!dst) return WALLY_EINVAL; - } - for (i = 0; i < src->num_items; ++i) { - bool found = false; - for (j = 0; j < dst->num_items; ++j) { - if (src->items[i].key_len == dst->items[j].key_len && - memcmp((char *)dst->items[j].key, (char *)src->items[i].key, src->items[i].key_len) == 0) { - found = true; - break; - } - } - if (found) { - continue; - } - if ((ret = add_unknowns_item(dst, &src->items[i])) != WALLY_OK) { - return ret; - } - } - return ret; -} + if (!src) + return WALLY_OK; /* No-op */ -static int merge_keypaths_into( - struct wally_keypath_map *dst, - const struct wally_keypath_map *src) -{ - int ret = WALLY_OK; - size_t i, j; + if (!*dst) + ret = wally_keypath_map_init_alloc(src->items_allocation_len, dst); - if (!src || !dst) { - return WALLY_EINVAL; - } + for (i = 0; ret == WALLY_OK && i < src->num_items; ++i) + ret = add_keypath_item(*dst, &src->items[i]); - for (i = 0; i < src->num_items; ++i) { - bool found = false; - for (j = 0; j < dst->num_items; ++j) { - if (memcmp((char *)dst->items[j].pubkey, (char *)src->items[i].pubkey, 65) == 0) { - found = true; - break; - } - } - if (found) { - continue; - } - if ((ret = add_keypath_item(dst, &src->items[i])) != WALLY_OK) { - return ret; - } - } return ret; } -static int merge_input_into( - struct wally_psbt_input *dst, - const struct wally_psbt_input *src) +static int combine_partial_sigs(struct wally_partial_sigs_map **dst, + const struct wally_partial_sigs_map *src) { int ret = WALLY_OK; - size_t i, j; - - if (!dst->non_witness_utxo && src->non_witness_utxo && (ret = clone_tx(src->non_witness_utxo, &dst->non_witness_utxo)) != WALLY_OK) { - return ret; - } - if (!dst->witness_utxo && src->witness_utxo && (ret = wally_tx_output_init_alloc(src->witness_utxo->satoshi, src->witness_utxo->script, src->witness_utxo->script_len, &dst->witness_utxo)) != WALLY_OK) { - return ret; - } - - if (src->partial_sigs) { - if (!dst->partial_sigs) { - if ((ret = wally_partial_sigs_map_init_alloc(src->partial_sigs->items_allocation_len, &dst->partial_sigs)) != WALLY_OK) { - return ret; - } - } - - for (i = 0; i < src->partial_sigs->num_items; ++i) { - bool found = false; - for (j = 0; j < dst->partial_sigs->num_items; ++j) { - if (memcmp((char *)dst->partial_sigs->items[j].pubkey, (char *)src->partial_sigs->items[i].pubkey, 65) == 0) { - found = true; - break; - } - } - if (found) { - continue; - } - if ((ret = add_partial_sig_item(dst->partial_sigs, &src->partial_sigs->items[i])) != WALLY_OK) { - return ret; - } - } - } - - if (src->keypaths) { - if (!dst->keypaths) { - if ((ret = wally_keypath_map_init_alloc(src->keypaths->items_allocation_len, &dst->keypaths)) != WALLY_OK) { - return ret; - } - } + size_t i; - if ((ret = merge_keypaths_into(dst->keypaths, src->keypaths)) != WALLY_OK) { - return ret; - } - } + if (!dst) + return WALLY_EINVAL; - if (src->unknowns) { - if (!dst->unknowns) { - if ((ret = wally_unknowns_map_init_alloc(src->unknowns->items_allocation_len, &dst->unknowns)) != WALLY_OK) { - return ret; - } - } + if (!src) + return WALLY_OK; /* No-op */ - if ((ret = merge_unknowns_into(dst->unknowns, src->unknowns)) != WALLY_OK) { - return ret; - } - } + if (!*dst) + ret = wally_partial_sigs_map_init_alloc(src->items_allocation_len, dst); - if (dst->redeem_script_len == 0 && src->redeem_script_len > 0) { - if (!clone_bytes(&dst->redeem_script, src->redeem_script, src->redeem_script_len)) { - return WALLY_ENOMEM; - } - dst->redeem_script_len = src->redeem_script_len; - } + for (i = 0; ret == WALLY_OK && i < src->num_items; ++i) + ret = add_partial_sig_item(*dst, &src->items[i]); - if (dst->witness_script_len == 0 && src->witness_script_len > 0) { - if (!clone_bytes(&dst->witness_script, src->witness_script, src->witness_script_len)) { - return WALLY_ENOMEM; - } - dst->witness_script_len = src->witness_script_len; - } + return ret; +} - if (dst->final_script_sig_len == 0 && src->final_script_sig_len > 0) { - if (!clone_bytes(&dst->final_script_sig, src->final_script_sig, src->final_script_sig_len)) { - return WALLY_ENOMEM; - } - dst->final_script_sig_len = src->final_script_sig_len; - } +#define COMBINE_BYTES(typ, member) \ + if (!dst->member && src->member && \ + (ret = wally_psbt_ ## typ ## _set_ ## member(dst, src->member, src->member ## _len)) != WALLY_OK) \ + return ret - if (!dst->final_witness && src->final_witness) { - dst->final_witness = clone_witness(src->final_witness); - if (!dst->final_witness) { - return WALLY_ENOMEM; - } - } +static int combine_txs(struct wally_tx **dst, struct wally_tx *src) +{ + if (!dst) + return WALLY_EINVAL; - if (src->sighash_type > dst->sighash_type) { - dst->sighash_type = src->sighash_type; - } + if (!*dst && src) + return wally_tx_clone(src, 0, dst); return WALLY_OK; } -static int merge_output_into( - struct wally_psbt_output *dst, - const struct wally_psbt_output *src) +static int combine_inputs(struct wally_psbt_input *dst, + const struct wally_psbt_input *src) { - int ret = WALLY_OK; + int ret; - if (src->keypaths) { - if (!dst->keypaths) { - if ((ret = wally_keypath_map_init_alloc(src->keypaths->items_allocation_len, &dst->keypaths)) != WALLY_OK) { - return ret; - } - } + if ((ret = combine_txs(&dst->non_witness_utxo, src->non_witness_utxo)) != WALLY_OK) + return ret; - if ((ret = merge_keypaths_into(dst->keypaths, src->keypaths)) != WALLY_OK) { + if (!dst->witness_utxo && src->witness_utxo) { + const struct wally_tx_output *src_utxo = src->witness_utxo; +#ifdef BUILD_ELEMENTS + ret = wally_tx_elements_output_init_alloc( + src_utxo->script, src_utxo->script_len, + src_utxo->asset, src_utxo->asset_len, + src_utxo->value, src_utxo->value_len, + src_utxo->nonce, src_utxo->nonce_len, + src_utxo->surjectionproof, src_utxo->surjectionproof_len, + src_utxo->rangeproof, src_utxo->rangeproof_len, +#else + ret = wally_tx_output_init_alloc( + src_utxo->satoshi, + src_utxo->script, + src_utxo->script_len, +#endif + &dst->witness_utxo); + if (ret != WALLY_OK) return ret; - } } - if (src->unknowns) { - if (!dst->unknowns) { - if ((ret = wally_unknowns_map_init_alloc(src->unknowns->items_allocation_len, &dst->unknowns)) != WALLY_OK) { - return ret; - } - } - - if ((ret = merge_unknowns_into(dst->unknowns, src->unknowns)) != WALLY_OK) { - return ret; - } - } + COMBINE_BYTES(input, redeem_script); + COMBINE_BYTES(input, witness_script); + COMBINE_BYTES(input, final_script_sig); - if (dst->redeem_script_len == 0 && src->redeem_script_len > 0) { - if (!clone_bytes(&dst->redeem_script, src->redeem_script, src->redeem_script_len)) { - return WALLY_ENOMEM; - } - dst->redeem_script_len = src->redeem_script_len; - } + if (!dst->final_witness && src->final_witness && + (ret = wally_psbt_input_set_final_witness(dst, src->final_witness)) != WALLY_OK) + return ret; + if ((ret = combine_keypath(&dst->keypaths, src->keypaths)) != WALLY_OK) + return ret; + if ((ret = combine_partial_sigs(&dst->partial_sigs, src->partial_sigs)) != WALLY_OK) + return ret; + if ((ret = combine_unknowns(&dst->unknowns, src->unknowns)) != WALLY_OK) + return ret; + if (!dst->sighash_type && src->sighash_type) + dst->sighash_type = src->sighash_type; - if (dst->witness_script_len == 0 && src->witness_script_len > 0) { - if (!clone_bytes(&dst->witness_script, src->witness_script, src->witness_script_len)) { - return WALLY_ENOMEM; - } - dst->witness_script_len = src->witness_script_len; +#ifdef BUILD_ELEMENTS + if (!dst->has_value && src->has_value) { + dst->value = src->value; + dst->has_value = true; } - + COMBINE_BYTES(input, vbf); + COMBINE_BYTES(input, asset); + COMBINE_BYTES(input, abf); + if ((ret = combine_txs(&dst->peg_in_tx, src->peg_in_tx)) != WALLY_OK) + return ret; + COMBINE_BYTES(input, txoutproof); + COMBINE_BYTES(input, genesis_blockhash); + COMBINE_BYTES(input, claim_script); +#endif return WALLY_OK; } -int wally_combine_psbts( - const struct wally_psbt *psbts, - size_t psbts_len, - struct wally_psbt **output) +static int combine_outputs(struct wally_psbt_output *dst, + const struct wally_psbt_output *src) { - struct wally_psbt *result; - unsigned char global_txid[SHA256_LEN]; - size_t i, j; - int ret = WALLY_OK; - - TX_CHECK_OUTPUT; - - if (!psbts) { - return WALLY_EINVAL; - } + int ret; - /* Get info from the first psbt and use it as the template */ - if ((ret = get_txid(psbts->tx, global_txid, SHA256_LEN)) != WALLY_OK) { + if ((ret = combine_keypath(&dst->keypaths, src->keypaths)) != WALLY_OK) return ret; - } - - if ((ret = wally_psbt_init_alloc(psbts[0].inputs_allocation_len, psbts[0].outputs_allocation_len, psbts[0].unknowns->items_allocation_len, &result)) != WALLY_OK) { + if ((ret = combine_unknowns(&dst->unknowns, src->unknowns)) != WALLY_OK) return ret; - } - if ((ret = clone_tx(psbts[0].tx, &result->tx)) != WALLY_OK) { - goto fail; - } - result->num_inputs = psbts[0].num_inputs; - result->num_outputs = psbts[0].num_outputs; + COMBINE_BYTES(output, redeem_script); + COMBINE_BYTES(output, witness_script); + +#ifdef BUILD_ELEMENTS + COMBINE_BYTES(output, blinding_pubkey); + COMBINE_BYTES(output, value_commitment); + COMBINE_BYTES(output, vbf); + COMBINE_BYTES(output, asset_commitment); + COMBINE_BYTES(output, abf); + COMBINE_BYTES(output, nonce); + COMBINE_BYTES(output, rangeproof); + COMBINE_BYTES(output, surjectionproof); +#endif + return WALLY_OK; +} +#undef COMBINE_BYTES + +int wally_psbt_combine(struct wally_psbt *psbt, const struct wally_psbt *src) +{ + unsigned char txid[WALLY_TXHASH_LEN], src_txid[WALLY_TXHASH_LEN]; + size_t i; + int ret; - for (i = 0; i < psbts_len; ++i) { - unsigned char txid[SHA256_LEN]; + if (!psbt || !psbt->tx || !src || !src->tx) + return WALLY_EINVAL; - /* Compare the txids */ - if ((ret = get_txid(psbts[i].tx, txid, SHA256_LEN)) != WALLY_OK) { - goto fail; - } - if (memcmp(global_txid, txid, SHA256_LEN) != 0) { - ret = WALLY_EINVAL; - goto fail; - } + ret = wally_tx_get_txid(psbt->tx, txid, sizeof(txid)); + if (ret == WALLY_OK) + ret = wally_tx_get_txid(src->tx, src_txid, sizeof(src_txid)); - /* Now start merging */ - for (j = 0; j < result->num_inputs; ++j) { - if ((ret = merge_input_into(&result->inputs[j], &psbts[i].inputs[j])) != WALLY_OK) { - goto fail; - } - } - for (j = 0; j < result->num_outputs; ++j) { - if ((ret = merge_output_into(&result->outputs[j], &psbts[i].outputs[j])) != WALLY_OK) { - goto fail; - } - } + if (ret == WALLY_OK && memcmp(txid, src_txid, sizeof(txid)) != 0) + ret = WALLY_EINVAL; /* Transactions don't match */ - if (psbts[i].unknowns) { - if (!result->unknowns) { - if ((ret = wally_unknowns_map_init_alloc(psbts[i].unknowns->items_allocation_len, &result->unknowns)) != WALLY_OK) { - goto fail; - } - } + for (i = 0; ret == WALLY_OK && i < psbt->num_inputs; ++i) + ret = combine_inputs(&psbt->inputs[i], &src->inputs[i]); - if ((ret = merge_unknowns_into(result->unknowns, psbts[i].unknowns)) != WALLY_OK) { - return ret; - } - } - } + for (i = 0; ret == WALLY_OK && i < psbt->num_outputs; ++i) + ret = combine_outputs(&psbt->outputs[i], &src->outputs[i]); - *output = result; - return WALLY_OK; + if (ret == WALLY_OK) + ret = combine_unknowns(&psbt->unknowns, src->unknowns); -fail: - wally_psbt_free(result); return ret; } -int wally_sign_psbt( - struct wally_psbt *psbt, - const unsigned char *key, - size_t key_len) +int wally_psbt_sign(struct wally_psbt *psbt, + const unsigned char *key, size_t key_len, uint32_t flags) { - unsigned char pubkey[EC_PUBLIC_KEY_LEN], uncomp_pubkey[EC_PUBLIC_KEY_UNCOMPRESSED_LEN], sig[EC_SIGNATURE_LEN], der_sig[EC_SIGNATURE_DER_MAX_LEN + 1]; - size_t i, j, der_sig_len; + unsigned char pubkey[EC_PUBLIC_KEY_LEN], full_pubkey[EC_PUBLIC_KEY_UNCOMPRESSED_LEN]; + unsigned char sig[EC_SIGNATURE_LEN], der_sig[EC_SIGNATURE_DER_MAX_LEN + 1]; + const size_t pubkey_len = sizeof(pubkey), full_pubkey_len = sizeof(full_pubkey); + size_t i, der_sig_len, is_elements; int ret; - if (!psbt || !psbt->tx || !key || key_len != EC_PRIVATE_KEY_LEN) { + if (!psbt || !psbt->tx || !key || key_len != EC_PRIVATE_KEY_LEN || + (flags & ~EC_FLAGS_ALL)) { return WALLY_EINVAL; } + if ((ret = wally_psbt_is_elements(psbt, &is_elements)) != WALLY_OK) + return ret; + /* Get the pubkey */ - if ((ret = wally_ec_public_key_from_private_key(key, key_len, pubkey, EC_PUBLIC_KEY_LEN)) != WALLY_OK) { + if ((ret = wally_ec_public_key_from_private_key(key, key_len, pubkey, pubkey_len)) != WALLY_OK) { return ret; } - if ((ret = wally_ec_public_key_decompress(pubkey, EC_PUBLIC_KEY_LEN, uncomp_pubkey, EC_PUBLIC_KEY_UNCOMPRESSED_LEN)) != WALLY_OK) { + if ((ret = wally_ec_public_key_decompress(pubkey, pubkey_len, full_pubkey, full_pubkey_len)) != WALLY_OK) { return ret; } @@ -2541,54 +2347,38 @@ int wally_sign_psbt( struct wally_psbt_input *input = &psbt->inputs[i]; struct wally_tx_input *txin = &psbt->tx->inputs[i]; unsigned char sighash[SHA256_LEN], *scriptcode, wpkh_sc[WALLY_SCRIPTPUBKEY_P2PKH_LEN]; - size_t scriptcode_len; - bool match = false, comp = false, already_signed = false; - uint32_t sighash_type = WALLY_SIGHASH_ALL; - - if (!input->keypaths) { - /* Can't do anything without the keypaths */ - continue; + size_t keypath_index = 0, scriptcode_len; + bool is_compressed; + uint32_t sighash_type; + + /* See if this input has a keypath matching the pubkey of the private key supplied */ + if (input->keypaths) { + ret = wally_keypath_map_find(input->keypaths, full_pubkey, full_pubkey_len, &keypath_index); + if (ret == WALLY_OK && !keypath_index) + ret = wally_keypath_map_find(input->keypaths, pubkey, pubkey_len, &keypath_index); + if (ret != WALLY_OK) + return ret; } - /* Go through each listed pubkey and see if it matches. */ - for (j = 0; j < input->keypaths->num_items; ++j) { - struct wally_keypath_item *item = &input->keypaths->items[j]; - if (item->pubkey[0] == 0x04 && memcmp((char *)item->pubkey, (char *)uncomp_pubkey, EC_PUBLIC_KEY_UNCOMPRESSED_LEN) == 0) { - match = true; - break; - } else if (memcmp((char *)item->pubkey, (char *)pubkey, EC_PUBLIC_KEY_LEN) == 0) { - match = true; - comp = true; - break; - } - } + if (!keypath_index) + continue; /* Didn't find a keypath matching this pubkey: skip it */ - /* Did not find pubkey, skip */ - if (!match) { - continue; - } + is_compressed = pubkey_is_compressed(input->keypaths->items[keypath_index - 1].pubkey); /* Make sure we don't already have a sig for this input ?! */ if (input->partial_sigs) { - for (j = 0; j < input->partial_sigs->num_items; j++) { - struct wally_partial_sigs_item *item = &input->partial_sigs->items[j]; - if (memcmp((char *)item->pubkey, (char *)uncomp_pubkey, EC_PUBLIC_KEY_UNCOMPRESSED_LEN) == 0 - || memcmp((char *)item->pubkey, (char *)pubkey, EC_PUBLIC_KEY_LEN) == 0) { - already_signed = true; - break; - } - } - } + size_t is_found; + ret = wally_partial_sigs_map_find(input->partial_sigs, full_pubkey, full_pubkey_len, &is_found); + if (ret == WALLY_OK && !is_found) + ret = wally_partial_sigs_map_find(input->partial_sigs, pubkey, pubkey_len, &is_found); + if (ret != WALLY_OK) + return ret; - /* We've already got a partial sig for this pubkey on this input */ - if (already_signed) { - continue; + if (is_found) + continue; /* Already got a partial sig for this pubkey on this input */ } - /* Sighash type */ - if (input->sighash_type > 0) { - sighash_type = input->sighash_type; - } + sighash_type = input->sighash_type ? input->sighash_type : WALLY_SIGHASH_ALL; /* Get scriptcode and sighash */ if (input->redeem_script) { @@ -2626,12 +2416,12 @@ int wally_sign_psbt( } if (input->non_witness_utxo) { - unsigned char txid[SHA256_LEN]; + unsigned char txid[WALLY_TXHASH_LEN]; - if ((ret = get_txid(input->non_witness_utxo, txid, SHA256_LEN)) != WALLY_OK) { + if ((ret = wally_tx_get_txid(input->non_witness_utxo, txid, sizeof(txid))) != WALLY_OK) { return ret; } - if (memcmp((char *)txid, (char *)txin->txhash, SHA256_LEN) != 0) { + if (memcmp(txid, txin->txhash, sizeof(txid)) != 0) { return WALLY_EINVAL; } @@ -2658,7 +2448,7 @@ int wally_sign_psbt( return ret; } if (scriptcode_len != WALLY_SCRIPTPUBKEY_P2WSH_LEN || - memcmp((char *)wsh, (char *)scriptcode, WALLY_SCRIPTPUBKEY_P2WSH_LEN) != 0) { + memcmp(wsh, scriptcode, WALLY_SCRIPTPUBKEY_P2WSH_LEN) != 0) { return WALLY_EINVAL; } scriptcode = input->witness_script; @@ -2668,41 +2458,47 @@ int wally_sign_psbt( continue; } - if ((ret = wally_tx_get_btc_signature_hash(psbt->tx, i, scriptcode, scriptcode_len, input->witness_utxo->satoshi, sighash_type, WALLY_TX_FLAG_USE_WITNESS, sighash, SHA256_LEN)) != WALLY_OK) { + if (is_elements) { +#ifdef BUILD_ELEMENTS + if ((ret = wally_tx_get_elements_signature_hash(psbt->tx, i, scriptcode, scriptcode_len, input->witness_utxo->value, input->witness_utxo->value_len, sighash_type, WALLY_TX_FLAG_USE_WITNESS, sighash, SHA256_LEN)) != WALLY_OK) { + return ret; + } +#else + return WALLY_ERROR; +#endif /* BUILD_ELEMENTS */ + } else if ((ret = wally_tx_get_btc_signature_hash(psbt->tx, i, scriptcode, scriptcode_len, input->witness_utxo->satoshi, sighash_type, WALLY_TX_FLAG_USE_WITNESS, sighash, SHA256_LEN)) != WALLY_OK) { return ret; } } /* Sign the sighash */ - if ((ret = wally_ec_sig_from_bytes(key, key_len, sighash, SHA256_LEN, EC_FLAG_ECDSA | EC_FLAG_GRIND_R, sig, EC_SIGNATURE_LEN)) != WALLY_OK) { + flags = flags & EC_FLAG_GRIND_R; /* Only grinding flag is relevant */ + if ((ret = wally_ec_sig_from_bytes(key, key_len, sighash, SHA256_LEN, EC_FLAG_ECDSA | flags, sig, EC_SIGNATURE_LEN)) != WALLY_OK) return ret; - } - if ((ret = wally_ec_sig_normalize(sig, EC_SIGNATURE_LEN, sig, EC_SIGNATURE_LEN)) != WALLY_OK) { - return ret; - } - if ((ret = wally_ec_sig_to_der(sig, EC_SIGNATURE_LEN, der_sig, EC_SIGNATURE_DER_MAX_LEN, &der_sig_len)) != WALLY_OK) { + if ((ret = wally_ec_sig_to_der(sig, EC_SIGNATURE_LEN, der_sig, EC_SIGNATURE_DER_MAX_LEN, &der_sig_len)) != WALLY_OK) return ret; - } /* Add the sighash type to the end of the sig */ der_sig[der_sig_len] = (unsigned char)sighash_type; der_sig_len++; /* Copy the DER sig into the psbt */ - if (!input->partial_sigs) { - if ((ret = wally_partial_sigs_map_init_alloc(1, &input->partial_sigs)) != WALLY_OK) { - return ret; - } - } - if ((ret = wally_add_new_partial_sig(input->partial_sigs, comp ? pubkey : uncomp_pubkey, comp ? EC_PUBLIC_KEY_LEN : EC_PUBLIC_KEY_UNCOMPRESSED_LEN, der_sig, der_sig_len)) != WALLY_OK) { + if (!input->partial_sigs && + (ret = wally_partial_sigs_map_init_alloc(1, &input->partial_sigs)) != WALLY_OK) + return ret; + + ret = wally_partial_sigs_map_add(input->partial_sigs, + is_compressed ? pubkey : full_pubkey, + is_compressed ? pubkey_len : full_pubkey_len, + der_sig, der_sig_len); + if (ret != WALLY_OK) return ret; - } } return WALLY_OK; } -int wally_finalize_psbt(struct wally_psbt *psbt) +int wally_psbt_finalize(struct wally_psbt *psbt) { size_t i; int ret; @@ -2787,6 +2583,9 @@ int wally_finalize_psbt(struct wally_psbt *psbt) /* P2SH wrapped witness requires final scriptsig of pushing the redeemScript */ script_sig_len = varint_get_length(input->redeem_script_len) + input->redeem_script_len; input->final_script_sig = wally_malloc(script_sig_len); + if (!input->final_script_sig) { + return WALLY_ENOMEM; + } if ((ret = wally_script_push_from_bytes(input->redeem_script, input->redeem_script_len, 0, input->final_script_sig, script_sig_len, &written)) != WALLY_OK) { wally_free(input->final_script_sig); return ret; @@ -2897,6 +2696,9 @@ int wally_finalize_psbt(struct wally_psbt *psbt) /* P2SH wrapped witness requires final scriptsig of pushing the redeemScript */ script_sig_len = varint_get_length(input->redeem_script_len) + input->redeem_script_len; input->final_script_sig = wally_malloc(script_sig_len); + if (!input->final_script_sig) { + return WALLY_ENOMEM; + } if ((ret = wally_script_push_from_bytes(input->redeem_script, input->redeem_script_len, 0, input->final_script_sig, script_sig_len, &written)) != WALLY_OK) { wally_free(input->final_script_sig); return ret; @@ -2928,39 +2730,41 @@ int wally_finalize_psbt(struct wally_psbt *psbt) return WALLY_OK; } -int wally_extract_psbt( - struct wally_psbt *psbt, +int wally_psbt_extract( + const struct wally_psbt *psbt, struct wally_tx **output) { struct wally_tx *result = NULL; size_t i; - int ret = WALLY_OK; + int ret; TX_CHECK_OUTPUT; - if (!psbt || !psbt->tx || psbt->num_inputs == 0 || psbt->num_outputs == 0) { + if (!psbt || !psbt->tx || !psbt->num_inputs || !psbt->num_outputs || + psbt->tx->num_inputs < psbt->num_inputs || psbt->tx->num_outputs < psbt->num_outputs) return WALLY_EINVAL; - } - clone_tx(psbt->tx, &result); + if ((ret = wally_tx_clone(psbt->tx, 0, &result)) != WALLY_OK) + return ret; for (i = 0; i < psbt->num_inputs; ++i) { - struct wally_psbt_input *input = &psbt->inputs[i]; + const struct wally_psbt_input *input = &psbt->inputs[i]; struct wally_tx_input *vin = &result->inputs[i]; + if (!input->final_script_sig && !input->final_witness) { ret = WALLY_EINVAL; - goto fail; + break; } if (input->final_script_sig) { if (vin->script) { /* Our global tx shouldn't have a scriptSig */ ret = WALLY_EINVAL; - goto fail; + break; } if (!clone_bytes(&vin->script, input->final_script_sig, input->final_script_sig_len)) { ret = WALLY_ENOMEM; - goto fail; + break; } vin->script_len = input->final_script_sig_len; } @@ -2968,21 +2772,101 @@ int wally_extract_psbt( if (vin->witness) { /* Our global tx shouldn't have a witness */ ret = WALLY_EINVAL; - goto fail; - } - if (!(vin->witness = clone_witness(input->final_witness))) { - ret = WALLY_ENOMEM; - goto fail; + break; } + ret = wally_tx_witness_stack_clone_alloc(input->final_witness, &vin->witness); + if (ret != WALLY_OK) + break; } } - *output = result; - return ret; - -fail: - if (result) { + if (ret == WALLY_OK) + *output = result; + else wally_tx_free(result); - } return ret; } + +int wally_psbt_is_elements(const struct wally_psbt *psbt, size_t *written) +{ + if (!psbt || !written) + return WALLY_EINVAL; + + *written = memcmp(psbt->magic, WALLY_ELEMENTS_PSBT_MAGIC, sizeof(psbt->magic)) ? 0 : 1; + return WALLY_OK; +} + +#if defined(SWIG) || defined (SWIG_JAVA_BUILD) || defined (SWIG_PYTHON_BUILD) || defined (SWIG_JAVASCRIPT_BUILD) + +static struct wally_psbt_input *psbt_get_input(const struct wally_psbt *psbt, size_t index) +{ + return psbt && index < psbt->num_inputs ? &psbt->inputs[index] : NULL; +} + +static struct wally_psbt_output *psbt_get_output(const struct wally_psbt *psbt, size_t index) +{ + return psbt && index < psbt->num_outputs ? &psbt->outputs[index] : NULL; +} + +/* Set a binary buffer value on an input/output */ +#define PSBT_SET_B(typ, name) \ + int wally_psbt_set_ ## typ ## _ ## name(struct wally_psbt *psbt, size_t index, \ + const unsigned char *name, size_t name ## _len) { \ + return wally_psbt_ ## typ ## _set_ ## name(psbt_get_ ## typ(psbt, index), name, name ## _len); \ + } + +/* Set an integer value on an input/output */ +#define PSBT_SET_I(typ, name, inttyp) \ + int wally_psbt_set_ ## typ ## _ ## name(struct wally_psbt *psbt, size_t index, \ + inttyp v) { \ + return wally_psbt_ ## typ ## _set_ ## name(psbt_get_ ## typ(psbt, index), v); \ + } + +/* Set a struct on an input/output */ +#define PSBT_SET_S(typ, name, structtyp) \ + int wally_psbt_set_ ## typ ## _ ## name(struct wally_psbt *psbt, size_t index, \ + const struct structtyp *p) { \ + return wally_psbt_ ## typ ## _set_ ## name(psbt_get_ ## typ(psbt, index), p); \ + } + + +PSBT_SET_S(input, non_witness_utxo, wally_tx) +PSBT_SET_S(input, witness_utxo, wally_tx_output) +PSBT_SET_B(input, redeem_script) +PSBT_SET_B(input, witness_script) +PSBT_SET_B(input, final_script_sig) +PSBT_SET_S(input, final_witness, wally_tx_witness_stack) +PSBT_SET_S(input, keypaths, wally_keypath_map) +PSBT_SET_S(input, partial_sigs, wally_partial_sigs_map) +PSBT_SET_S(input, unknowns, wally_unknowns_map) +PSBT_SET_I(input, sighash_type, uint32_t) +#ifdef BUILD_ELEMENTS +PSBT_SET_I(input, value, uint64_t) +int wally_psbt_clear_input_value(struct wally_psbt *psbt, size_t index) { + return wally_psbt_input_clear_value(psbt_get_input(psbt, index)); +} +PSBT_SET_B(input, vbf) +PSBT_SET_B(input, asset) +PSBT_SET_B(input, abf) +PSBT_SET_S(input, peg_in_tx, wally_tx) +PSBT_SET_B(input, txoutproof) +PSBT_SET_B(input, genesis_blockhash) +PSBT_SET_B(input, claim_script) +#endif /* BUILD_ELEMENTS */ + +PSBT_SET_B(output, redeem_script) +PSBT_SET_B(output, witness_script) +PSBT_SET_S(output, keypaths, wally_keypath_map) +PSBT_SET_S(output, unknowns, wally_unknowns_map) +#ifdef BUILD_ELEMENTS +PSBT_SET_B(output, blinding_pubkey) +PSBT_SET_B(output, value_commitment) +PSBT_SET_B(output, vbf) +PSBT_SET_B(output, asset_commitment) +PSBT_SET_B(output, abf) +PSBT_SET_B(output, nonce) +PSBT_SET_B(output, rangeproof) +PSBT_SET_B(output, surjectionproof) +#endif /* BUILD_ELEMENTS */ + +#endif /* SWIG/SWIG_JAVA_BUILD/SWIG_PYTHON_BUILD/SWIG_JAVASCRIPT_BUILD */ diff --git a/src/psbt_int.h b/src/psbt_int.h new file mode 100644 index 000000000..2eecc0c35 --- /dev/null +++ b/src/psbt_int.h @@ -0,0 +1,64 @@ +#ifndef LIBWALLY_CORE_PSBT_INT_H +#define LIBWALLY_CORE_PSBT_INT_H 1 + +#if defined(SWIG) || defined (SWIG_JAVA_BUILD) || defined (SWIG_PYTHON_BUILD) || defined(SWIG_JAVASCRIPT_BUILD) + +#ifdef __cplusplus +extern "C" { +#endif + +/* PSBT */ + +WALLY_CORE_API int wally_psbt_get_global_tx_alloc(const struct wally_psbt *psbt, struct wally_tx **output); +WALLY_CORE_API int wally_psbt_get_version(const struct wally_psbt *psbt, size_t *written); +WALLY_CORE_API int wally_psbt_get_num_inputs(const struct wally_psbt *psbt, size_t *written); +WALLY_CORE_API int wally_psbt_get_num_outputs(const struct wally_psbt *psbt, size_t *written); + +/* Inputs */ +WALLY_CORE_API int wally_psbt_set_input_non_witness_utxo(struct wally_psbt *psbt, size_t index, const struct wally_tx *non_witness_utxo); +WALLY_CORE_API int wally_psbt_set_input_witness_utxo(struct wally_psbt *psbt, size_t index, const struct wally_tx_output *witness_utxo); +WALLY_CORE_API int wally_psbt_set_input_redeem_script(struct wally_psbt *psbt, size_t index, const unsigned char *redeem_script, size_t redeem_script_len); +WALLY_CORE_API int wally_psbt_set_input_witness_script(struct wally_psbt *psbt, size_t index, const unsigned char *witness_script, size_t witness_script_len); +WALLY_CORE_API int wally_psbt_set_input_final_script_sig(struct wally_psbt *psbt, size_t index, const unsigned char *final_script_sig, size_t final_script_sig_len); +WALLY_CORE_API int wally_psbt_set_input_final_witness(struct wally_psbt *psbt, size_t index, const struct wally_tx_witness_stack *final_witness); +WALLY_CORE_API int wally_psbt_set_input_keypaths(struct wally_psbt *psbt, size_t index, const struct wally_keypath_map *keypaths); +WALLY_CORE_API int wally_psbt_set_input_partial_sigs(struct wally_psbt *psbt, size_t index, const struct wally_partial_sigs_map *partial_sigs); +WALLY_CORE_API int wally_psbt_set_input_unknowns(struct wally_psbt *psbt, size_t index, const struct wally_unknowns_map *unknowns); +WALLY_CORE_API int wally_psbt_set_input_sighash_type(struct wally_psbt *psbt, size_t index, uint32_t sighash_type); +#ifdef BUILD_ELEMENTS +WALLY_CORE_API int wally_psbt_set_input_value(struct wally_psbt *psbt, size_t index, uint64_t value); +WALLY_CORE_API int wally_psbt_clear_input_value(struct wally_psbt *psbt, size_t index); +WALLY_CORE_API int wally_psbt_set_input_vbf(struct wally_psbt *psbt, size_t index, const unsigned char *vbf, size_t vbf_len); +WALLY_CORE_API int wally_psbt_set_input_asset(struct wally_psbt *psbt, size_t index, const unsigned char *asset, size_t asset_len); +WALLY_CORE_API int wally_psbt_set_input_abf(struct wally_psbt *psbt, size_t index, const unsigned char *abf, size_t abf_len); +WALLY_CORE_API int wally_psbt_set_input_peg_in_tx(struct wally_psbt *psbt, size_t index, const struct wally_tx *peg_in_tx); +WALLY_CORE_API int wally_psbt_set_input_txoutproof(struct wally_psbt *psbt, size_t index, const unsigned char *proof, size_t proof_len); +WALLY_CORE_API int wally_psbt_set_input_genesis_blockhash(struct wally_psbt *psbt, size_t index, const unsigned char *genesis_blockhash, size_t genesis_blockhash_len); +WALLY_CORE_API int wally_psbt_set_input_claim_script(struct wally_psbt *psbt, size_t index, const unsigned char *script, size_t script_len); +#endif /* BUILD_ELEMENTS */ + +/* Outputs */ + +WALLY_CORE_API int wally_psbt_set_output_redeem_script(struct wally_psbt *psbt, size_t index, const unsigned char *redeem_script, size_t redeem_script_len); +WALLY_CORE_API int wally_psbt_set_output_witness_script(struct wally_psbt *psbt, size_t index, const unsigned char *witness_script, size_t witness_script_len); +WALLY_CORE_API int wally_psbt_set_output_keypaths(struct wally_psbt *psbt, size_t index, const struct wally_keypath_map *keypaths); +WALLY_CORE_API int wally_psbt_set_output_unknowns(struct wally_psbt *psbt, size_t index, const struct wally_unknowns_map *unknowns); + +#ifdef BUILD_ELEMENTS +WALLY_CORE_API int wally_psbt_set_output_blinding_pubkey(struct wally_psbt *psbt, size_t index, const unsigned char *pub_key, size_t pub_key_len); +WALLY_CORE_API int wally_psbt_set_output_value_commitment(struct wally_psbt *psbt, size_t index, const unsigned char *commitment, size_t commitment_len); +WALLY_CORE_API int wally_psbt_set_output_vbf(struct wally_psbt *psbt, size_t index, const unsigned char *vbf, size_t vbf_len); +WALLY_CORE_API int wally_psbt_set_output_asset_commitment(struct wally_psbt *psbt, size_t index, const unsigned char *commitment, size_t commitment_len); +WALLY_CORE_API int wally_psbt_set_output_abf(struct wally_psbt *psbt, size_t index, const unsigned char *abf, size_t abf_len); +WALLY_CORE_API int wally_psbt_set_output_nonce(struct wally_psbt *psbt, size_t index, const unsigned char *nonce, size_t nonce_len); +WALLY_CORE_API int wally_psbt_set_output_rangeproof(struct wally_psbt *psbt, size_t index, const unsigned char *proof, size_t proof_len); +WALLY_CORE_API int wally_psbt_set_output_surjectionproof(struct wally_psbt *psbt, size_t index, const unsigned char *proof, size_t proof_len); +#endif /* BUILD_ELEMENTS */ + +#ifdef __cplusplus +} +#endif + +#endif /* SWIG/SWIG_JAVA_BUILD/SWIG_PYTHON_BUILD/SWIG_JAVASCRIPT_BUILD */ + +#endif /* LIBWALLY_CORE_PSBT_INT_H */ diff --git a/src/pullpush.c b/src/pullpush.c new file mode 100644 index 000000000..6721f4da6 --- /dev/null +++ b/src/pullpush.c @@ -0,0 +1,185 @@ +#include "internal.h" +#include "script_int.h" + +#include +#include +#include +#include "pullpush.h" + +unsigned char *push_bytes(unsigned char **cursor, size_t *max, + const void *src, size_t len) +{ + if (cursor == NULL || *cursor == NULL) { + *max += len; + return NULL; + } + if (len > *max) { + if (src) + memcpy(*cursor, src, *max); + /* From now on, max records the room we *needed* */ + *max = len - *max; + *cursor = NULL; + return NULL; + } + if (src) + memcpy(*cursor, src, len); + + *cursor += len; + *max -= len; + + return *cursor - len; +} + +void pull_bytes(void *dst, size_t len, + const unsigned char **cursor, size_t *max) +{ + if (len > *max) { + memcpy(dst, *cursor, *max); + memset((char *)dst + *max, 0, len - *max); + pull_failed(cursor, max); + return; + } + memcpy(dst, *cursor, len); + *cursor += len; + *max -= len; +} + +const unsigned char *pull_skip(const unsigned char **cursor, size_t *max, + size_t len) +{ + const unsigned char *p; + + if (*cursor == NULL) { + return NULL; + } + + if (len > *max) { + pull_failed(cursor, max); + return NULL; + } + + p = *cursor; + *cursor += len; + *max -= len; + return p; +} + +void pull_failed(const unsigned char **cursor, size_t *max) +{ + *cursor = NULL; + *max = 0; +} + +void push_le64(unsigned char **cursor, size_t *max, uint64_t v) +{ + leint64_t lev = cpu_to_le64(v); + push_bytes(cursor, max, &lev, sizeof(lev)); +} + +uint64_t pull_le64(const unsigned char **cursor, size_t *max) +{ + leint64_t lev; + pull_bytes(&lev, sizeof(lev), cursor, max); + return le64_to_cpu(lev); +} + +void push_le32(unsigned char **cursor, size_t *max, uint32_t v) +{ + leint32_t lev = cpu_to_le32(v); + push_bytes(cursor, max, &lev, sizeof(lev)); +} + +uint32_t pull_le32(const unsigned char **cursor, size_t *max) +{ + leint32_t lev; + pull_bytes(&lev, sizeof(lev), cursor, max); + return le32_to_cpu(lev); +} + +void push_u8(unsigned char **cursor, size_t *max, uint8_t v) +{ + push_bytes(cursor, max, &v, sizeof(uint8_t)); +} + +uint8_t pull_u8(const unsigned char **cursor, size_t *max) +{ + uint8_t v; + pull_bytes(&v, sizeof(v), cursor, max); + return v; +} + +uint8_t peek_u8(const unsigned char **cursor, size_t *max) +{ + uint8_t v = pull_u8(cursor, max); + if (*cursor) { + *cursor -= sizeof(v); + *max += sizeof(v); + } + return v; +} + +void push_varint(unsigned char **cursor, size_t *max, uint64_t v) +{ + unsigned char buf[sizeof(uint8_t) + sizeof(uint64_t)]; + size_t len = varint_to_bytes(v, buf); + + push_bytes(cursor, max, buf, len); +} + +uint64_t pull_varint(const unsigned char **cursor, size_t *max) +{ + unsigned char buf[sizeof(uint8_t) + sizeof(uint64_t)]; + uint64_t v; + + /* FIXME: Would be more efficient to opencode varint here! */ + pull_bytes(buf, 1, cursor, max); + pull_bytes(buf + 1, varint_length_from_bytes(buf) - 1, cursor, max); + varint_from_bytes(buf, &v); + + return v; +} + +void push_varbuff(unsigned char **cursor, size_t *max, + const unsigned char *bytes, size_t bytes_len) +{ + push_varint(cursor, max, bytes_len); + push_bytes(cursor, max, bytes, bytes_len); +} + +size_t pull_varlength(const unsigned char **cursor, size_t *max) +{ + uint64_t len = pull_varint(cursor, max); + + if (len > *max) { + /* Impossible length. */ + pull_failed(cursor, max); + return 0; + } + return len; +} + +void pull_subfield_start(const unsigned char *const *cursor, const size_t *max, + size_t subfield_len, + const unsigned char **subcursor, size_t *submax) +{ + if (subfield_len > *max) { + pull_failed(subcursor, submax); + } else { + *subcursor = *cursor; + *submax = subfield_len; + } +} + +void pull_subfield_end(const unsigned char **cursor, size_t *max, + const unsigned char *subcursor, size_t submax) +{ + if (subcursor == NULL) { + pull_failed(cursor, max); + } else if (*cursor != NULL) { + const unsigned char *subend = subcursor + submax; + assert(subcursor >= *cursor); + assert(subend <= *cursor + *max); + *max -= (subend - *cursor); + *cursor = subend; + } +} diff --git a/src/pullpush.h b/src/pullpush.h new file mode 100644 index 000000000..e811bb9b3 --- /dev/null +++ b/src/pullpush.h @@ -0,0 +1,89 @@ +#ifndef LIBWALLY_CORE_PULLPUSH_H +#define LIBWALLY_CORE_PULLPUSH_H 1 +/** + * Safely copy @len bytes from @src into @cursor. + * + * If @cursor is NULL or *@cursor is NULL, then nothing will be + * written to it (obv), but *@max will be increased @len. + * + * Otherwise, if @len > *@max, *@max bytes will be copied from @src to + * *@cursor if @src is not NULL, then *@cursor will be set to NULL and + * @max will be set to the remainder. + * + * Otherwise, @len bytes will be copied from @src to *@cursor if @src + * is not NULL, *@max decreased by @len and @cursor increased by @len. + * + * This means you can call it repeatedly, and if it fails, *@cursor will be + * NULL, and *@max will indicate how many additional bytes you need. + * + * On success, this returns *@cursor before it was updated, otherwise NULL. + */ +unsigned char *push_bytes(unsigned char **cursor, size_t *max, + const void *src, size_t len); + +/** + * Safely copy @len bytes from @cursor into @dst. + * + * If @len > *@max, *@max bytes will be copied from *@cursor, the + * remainder of @dst will be zeroed, then *@cursor will be set to NULL + * and @max will be set to 0. + * Otherwise, @len bytes will be copied from @cursor, *@max decreased + * by @len and @cursor increased by @len. + */ +void pull_bytes(void *dst, size_t len, + const unsigned char **cursor, size_t *max); + + +/** + * Return a pointer to (and skip over) some bytes. + * + * Returns NULL (and maybe calls pull_failed()) if there are not enough left. + */ +const unsigned char *pull_skip(const unsigned char **cursor, size_t *max, + size_t len); + + +/** + * Convenience function to indicate a pull failed (eg. type decode failed) + * + * Sets *cursor to NULL, *max to 0. + */ +void pull_failed(const unsigned char **cursor, size_t *max); + +/** + * Convenience functions. + */ +void push_le64(unsigned char **cursor, size_t *max, uint64_t v); +uint64_t pull_le64(const unsigned char **cursor, size_t *max); +void push_le32(unsigned char **cursor, size_t *max, uint32_t v); +uint32_t pull_le32(const unsigned char **cursor, size_t *max); +void push_u8(unsigned char **cursor, size_t *max, uint8_t v); +uint8_t pull_u8(const unsigned char **cursor, size_t *max); +uint8_t peek_u8(const unsigned char **cursor, size_t *max); + +void push_varint(unsigned char **cursor, size_t *max, uint64_t v); +uint64_t pull_varint(const unsigned char **cursor, size_t *max); + +void push_varbuff(unsigned char **cursor, size_t *max, + const unsigned char *bytes, size_t bytes_len); + +/* Calls pull_failed() (and returns 0) if length would exceed remaining *max */ +size_t pull_varlength(const unsigned char **cursor, size_t *max); + +/** + * Functions to parse a subfield within an area. + * + * pull_subfield_start: initializes subcursor/submax to subfield_len at + * cursor. These can then be used with pull_ methods like normal. + * + * pull_subfield_end: updates *cursor and *max to point after the subfield has + * been parsed. If *subcursor is NULL, it's equivalent to pull_failed. + */ +void pull_subfield_start(const unsigned char *const *cursor, const size_t *max, + size_t subfield_len, + const unsigned char **subcursor, size_t *submax); + +void pull_subfield_end(const unsigned char **cursor, size_t *max, + const unsigned char *subcursor, size_t submax); + +#endif /* LIBWALLY_CORE_PULLPUSH_H */ diff --git a/src/pyexample/liquid/receive-send.py b/src/pyexample/liquid/receive-send.py index fc745cd6e..3f3a18514 100644 --- a/src/pyexample/liquid/receive-send.py +++ b/src/pyexample/liquid/receive-send.py @@ -207,7 +207,7 @@ # start-sign vout = 0 -prev_txid = wally.sha256d(wally.tx_to_bytes(tx, 0)) +prev_txid = wally.tx_get_txid(tx) for vin, script_pubkey in zip(vouts_in, script_pubkeys_in): wally.tx_add_elements_raw_input( diff --git a/src/script.c b/src/script.c index ef5e9feeb..fe2494909 100644 --- a/src/script.c +++ b/src/script.c @@ -553,13 +553,13 @@ int wally_scriptpubkey_multisig_from_bytes( size_t n_pubkeys = bytes_len / EC_PUBLIC_KEY_LEN; size_t script_len = 3 + (n_pubkeys * (EC_PUBLIC_KEY_LEN + 1)); size_t i; - unsigned char pubkey_bytes[16 * EC_PUBLIC_KEY_LEN]; + unsigned char pubkey_bytes[15 * EC_PUBLIC_KEY_LEN]; if (written) *written = 0; if (!bytes || !bytes_len || bytes_len % EC_PUBLIC_KEY_LEN || - n_pubkeys < 1 || n_pubkeys > 16 || threshold < 1 || threshold > 16 || + n_pubkeys < 1 || n_pubkeys > 15 || threshold < 1 || threshold > 15 || threshold > n_pubkeys || (flags & ~WALLY_SCRIPT_MULTISIG_SORTED) || !bytes_out || !written) return WALLY_EINVAL; @@ -594,8 +594,8 @@ int wally_scriptsig_multisig_from_bytes( unsigned char *bytes_out, size_t len, size_t *written) { #define MAX_DER (EC_SIGNATURE_DER_MAX_LEN + 1) - unsigned char der_buff[16 * MAX_DER], *p = bytes_out; - size_t der_len[16]; + unsigned char der_buff[15 * MAX_DER], *p = bytes_out; + size_t der_len[15]; size_t i, required = 0, n_sigs = bytes_len / EC_SIGNATURE_LEN; int ret = WALLY_OK; @@ -603,7 +603,7 @@ int wally_scriptsig_multisig_from_bytes( *written = 0; if (!script || !script_len || !bytes || !bytes_len || bytes_len % EC_SIGNATURE_LEN || - n_sigs < 1 || n_sigs > 16 || !sighash || sighash_len != n_sigs || + n_sigs < 1 || n_sigs > 15 || !sighash || sighash_len != n_sigs || flags || !bytes_out || !written) return WALLY_EINVAL; @@ -885,37 +885,36 @@ int wally_witness_program_from_bytes(const unsigned char *bytes, size_t bytes_le return ret; } -int wally_elements_pegout_script_size(size_t parent_genesis_blockhash_len, +int wally_elements_pegout_script_size(size_t genesis_blockhash_len, size_t mainchain_script_len, size_t sub_pubkey_len, - size_t whitelist_proof_len, + size_t whitelistproof_len, size_t *written) { - if (!written) - return WALLY_EINVAL; - *written = 1 - + parent_genesis_blockhash_len + calc_push_opcode_size(parent_genesis_blockhash_len) + + genesis_blockhash_len + calc_push_opcode_size(genesis_blockhash_len) + mainchain_script_len + calc_push_opcode_size(mainchain_script_len) + sub_pubkey_len + calc_push_opcode_size(sub_pubkey_len) - + whitelist_proof_len + calc_push_opcode_size(whitelist_proof_len); + + whitelistproof_len + calc_push_opcode_size(whitelistproof_len); return WALLY_OK; } -int wally_elements_pegout_script_from_bytes(const unsigned char *parent_genesis_blockhash, - size_t parent_genesis_blockhash_len, +int wally_elements_pegout_script_from_bytes(const unsigned char *genesis_blockhash, + size_t genesis_blockhash_len, const unsigned char *mainchain_script, size_t mainchain_script_len, const unsigned char *sub_pubkey, size_t sub_pubkey_len, - const unsigned char *whitelist_proof, - size_t whitelist_proof_len, + const unsigned char *whitelistproof, + size_t whitelistproof_len, uint32_t flags, unsigned char *bytes_out, size_t len, size_t *written) { #define pegout_script_push(bytes, bytes_len) \ + if (len < bytes_written) \ + return WALLY_OK; \ bytes_out += bytes_written; \ len -= bytes_written; \ if ((ret = wally_script_push_from_bytes(bytes, bytes_len, 0, bytes_out, len, &bytes_written)) != WALLY_OK) \ @@ -924,28 +923,24 @@ int wally_elements_pegout_script_from_bytes(const unsigned char *parent_genesis_ *written += bytes_written; size_t bytes_written = 1; /* OP_RETURN */ - size_t required_size; int ret; if (written) *written = 0; - if ((ret = wally_elements_pegout_script_size(parent_genesis_blockhash_len, mainchain_script_len, sub_pubkey_len, whitelist_proof_len, &required_size)) != WALLY_OK) - return ret; - - if (!parent_genesis_blockhash || parent_genesis_blockhash_len != 32 || + if (!genesis_blockhash || genesis_blockhash_len != SHA256_LEN || !mainchain_script || !mainchain_script_len || !sub_pubkey || sub_pubkey_len != EC_PUBLIC_KEY_LEN || - !whitelist_proof || !whitelist_proof_len || flags || !bytes_out || len < required_size) + !whitelistproof || !whitelistproof_len || flags || !bytes_out || !len) return WALLY_EINVAL; *bytes_out = OP_RETURN; if (written) *written += bytes_written; - pegout_script_push(parent_genesis_blockhash, parent_genesis_blockhash_len); + pegout_script_push(genesis_blockhash, genesis_blockhash_len); pegout_script_push(mainchain_script, mainchain_script_len); pegout_script_push(sub_pubkey, sub_pubkey_len); - pegout_script_push(whitelist_proof, whitelist_proof_len); + pegout_script_push(whitelistproof, whitelistproof_len); return WALLY_OK; @@ -1000,6 +995,8 @@ int wally_elements_pegin_contract_script_from_bytes(const unsigned char *redeem_ secp256k1_pubkey pub_key_tweaked; const secp256k1_pubkey *pub_key_combination[2]; secp256k1_pubkey pub_key_combined; + size_t push_size; + if (!pubkey_parse(ctx, &pub_key, p + 1, EC_PUBLIC_KEY_LEN)) return WALLY_ERROR; memcpy(&pub_key_tweaked, &pub_key, sizeof(pub_key)); @@ -1009,9 +1006,8 @@ int wally_elements_pegin_contract_script_from_bytes(const unsigned char *redeem_ return WALLY_ERROR; if (!pubkey_serialize(ctx, ser_pub_key, &ser_len, &pub_key_tweaked, PUBKEY_COMPRESSED)) return WALLY_ERROR; - if ((ret = wally_script_push_from_bytes(ser_pub_key, ser_len, 0, q, bytes_len, written)) != WALLY_OK) + if ((ret = wally_script_push_from_bytes(ser_pub_key, ser_len, 0, q, bytes_len, &push_size)) != WALLY_OK) return ret; - /* sanity checks as per elementsd */ if (!pubkey_create(ctx, &pub_key_from_tweak, tweak)) return WALLY_ERROR; @@ -1096,18 +1092,15 @@ int wally_witness_p2wpkh_from_der( struct wally_tx_witness_stack **witness) { unsigned char script_sig[WALLY_SCRIPTSIG_P2PKH_MAX_LEN]; + size_t written; int ret; - size_t script_sig_len; - if ((ret = wally_scriptsig_p2pkh_from_der(pub_key, pub_key_len, sig, sig_len, script_sig, WALLY_SCRIPTSIG_P2PKH_MAX_LEN, &script_sig_len)) != WALLY_OK) { - return ret; - } + ret = wally_scriptsig_p2pkh_from_der(pub_key, pub_key_len, sig, sig_len, script_sig, sizeof(script_sig), &written); - if ((ret = scriptsig_to_witness(script_sig, script_sig_len, witness)) != WALLY_OK) { - return ret; - } + if (ret == WALLY_OK) + ret = scriptsig_to_witness(script_sig, written, witness); - return WALLY_OK; + return ret; } int wally_witness_p2wpkh_from_sig( @@ -1119,18 +1112,15 @@ int wally_witness_p2wpkh_from_sig( struct wally_tx_witness_stack **witness) { unsigned char script_sig[WALLY_SCRIPTSIG_P2PKH_MAX_LEN]; + size_t written; int ret; - size_t script_sig_len; - if ((ret = wally_scriptsig_p2pkh_from_sig(pub_key, pub_key_len, sig, sig_len, sighash, script_sig, WALLY_SCRIPTSIG_P2PKH_MAX_LEN, &script_sig_len)) != WALLY_OK) { - return ret; - } + ret = wally_scriptsig_p2pkh_from_sig(pub_key, pub_key_len, sig, sig_len, sighash, script_sig, sizeof(script_sig), &written); - if ((ret = scriptsig_to_witness(script_sig, script_sig_len, witness)) != WALLY_OK) { - return ret; - } + if (ret == WALLY_OK) + ret = scriptsig_to_witness(script_sig, written, witness); - return WALLY_OK; + return ret; } int wally_witness_multisig_from_bytes( @@ -1147,19 +1137,21 @@ int wally_witness_multisig_from_bytes( int ret = WALLY_OK; size_t script_sig_len, n_sigs, buf_len; - if (!script || !script_len || !bytes || !bytes_len || !sighash || !sighash_len || !witness || !script_is_op_n(script[0], false, &n_sigs)) { + if (!script || !script_len || !bytes || !bytes_len || !sighash || !sighash_len || + !witness || !script_is_op_n(script[0], false, &n_sigs)) return WALLY_EINVAL; - } buf_len = n_sigs * (EC_SIGNATURE_DER_MAX_LEN + 2) + script_len; - if (!(script_sig = wally_malloc(buf_len))) { + if (!(script_sig = wally_malloc(buf_len))) return WALLY_ENOMEM; - } - if ((ret = wally_scriptsig_multisig_from_bytes(script, script_len, bytes, bytes_len, sighash, sighash_len, flags, script_sig, buf_len, &script_sig_len)) == WALLY_OK) { + ret = wally_scriptsig_multisig_from_bytes(script, script_len, + bytes, bytes_len, + sighash, sighash_len, flags, + script_sig, buf_len, &script_sig_len); + if (ret == WALLY_OK) ret = scriptsig_to_witness(script_sig, script_sig_len, witness); - } - wally_free(script_sig); + clear_and_free(script_sig, script_sig_len); return ret; } diff --git a/src/sign.c b/src/sign.c index 523a77ef6..00ec61cbb 100644 --- a/src/sign.c +++ b/src/sign.c @@ -8,7 +8,6 @@ #include #define EC_FLAGS_TYPES (EC_FLAG_ECDSA | EC_FLAG_SCHNORR) -#define EC_FLAGS_ALL (EC_FLAG_ECDSA | EC_FLAG_SCHNORR | EC_FLAG_GRIND_R | EC_FLAG_RECOVERABLE) #define MSG_ALL_FLAGS (BITCOIN_MESSAGE_FLAG_HASH) @@ -28,6 +27,10 @@ static bool is_valid_ec_type(uint32_t flags) ((flags & EC_FLAGS_TYPES) == EC_FLAG_SCHNORR); } +static size_t get_expected_sig_len(uint32_t flags) +{ + return flags & EC_FLAG_RECOVERABLE ? EC_SIGNATURE_RECOVERABLE_LEN : EC_SIGNATURE_LEN; +} int wally_ec_private_key_verify(const unsigned char *priv_key, size_t priv_key_len) { @@ -215,26 +218,26 @@ int wally_ec_sig_from_bytes(const unsigned char *priv_key, size_t priv_key_len, if (!priv_key || priv_key_len != EC_PRIVATE_KEY_LEN || !bytes || bytes_len != EC_MESSAGE_HASH_LEN || !is_valid_ec_type(flags) || flags & ~EC_FLAGS_ALL || - (flags & EC_FLAG_SCHNORR && flags & EC_FLAG_RECOVERABLE) || - !bytes_out || - (len != EC_SIGNATURE_LEN && len != EC_SIGNATURE_RECOVERABLE_LEN) || - (len == EC_SIGNATURE_LEN && flags & EC_FLAG_RECOVERABLE) || - (len == EC_SIGNATURE_RECOVERABLE_LEN && ~flags & EC_FLAG_RECOVERABLE)) + !bytes_out || len != get_expected_sig_len(flags)) return WALLY_EINVAL; if (!ctx) return WALLY_ENOMEM; if (flags & EC_FLAG_SCHNORR) { - return WALLY_EINVAL; + if (flags & EC_FLAG_RECOVERABLE) + return WALLY_EINVAL; /* Only ECDSA is supported for recoverable sigs */ + #if 0 /*FIXME: Schnorr is unavailable in secp for now*/ if (!secp256k1_schnorr_sign(ctx, bytes_out, bytes, priv_key, nonce_fn, NULL)) return WALLY_EINVAL; /* Failed to sign */ return WALLY_OK; #endif + return WALLY_EINVAL; } else { unsigned char extra_entropy[32] = {0}, *entropy_p = NULL; + unsigned char *bytes_out_p = flags & EC_FLAG_RECOVERABLE ? bytes_out + 1 : bytes_out; uint32_t counter = 0; secp256k1_ecdsa_recoverable_signature sig_secp; int recid; @@ -248,14 +251,13 @@ int wally_ec_sig_from_bytes(const unsigned char *priv_key, size_t priv_key_len, } /* Note this function is documented as never failing */ - secp256k1_ecdsa_recoverable_signature_serialize_compact(ctx, flags & EC_FLAG_RECOVERABLE ? bytes_out + 1 : bytes_out, &recid, &sig_secp); + secp256k1_ecdsa_recoverable_signature_serialize_compact(ctx, bytes_out_p, &recid, &sig_secp); - if (!(flags & EC_FLAG_GRIND_R) || bytes_out[0] < 0x80) { + if (!(flags & EC_FLAG_GRIND_R) || *bytes_out_p < 0x80) { wally_clear(&sig_secp, sizeof(sig_secp)); /* Note the following assumes the key is compressed */ - if (flags & EC_FLAG_RECOVERABLE) { + if (flags & EC_FLAG_RECOVERABLE) bytes_out[0] = 27 + recid + 4; - } return WALLY_OK; } diff --git a/src/swig_java/jni_elements_extra.java_in b/src/swig_java/jni_elements_extra.java_in index 462d8e16c..abac435a1 100644 --- a/src/swig_java/jni_elements_extra.java_in +++ b/src/swig_java/jni_elements_extra.java_in @@ -128,8 +128,8 @@ public final static byte[] asset_pak_whitelistproof(byte[] on_keys, byte[] off_keys, long idx, byte[] sub_pubkey, byte[] priv_key, byte[] summed_key) { final int required_len = asset_pak_whitelistproof_size(off_keys.length / Wally.EC_PUBLIC_KEY_LEN); final byte[] buf = new byte[required_len]; - asset_pak_whitelistproof(on_keys, off_keys, idx, sub_pubkey, priv_key, summed_key, buf); - return buf; + final int len = asset_pak_whitelistproof(on_keys, off_keys, idx, sub_pubkey, priv_key, summed_key, buf); + return checkBuffer(buf, len); } public final static byte[] elements_pegout_script_from_bytes(byte[] bh, byte[] mcs, byte[] pk, byte[] whl, long flags) { diff --git a/src/swig_java/jni_extra.java_in b/src/swig_java/jni_extra.java_in index 3f91335f3..a3d18522e 100644 --- a/src/swig_java/jni_extra.java_in +++ b/src/swig_java/jni_extra.java_in @@ -56,6 +56,10 @@ return bip32_key_get_priv_key(jarg1, null); } + public final static byte[] bip32_key_get_fingerprint(Object jarg1) { + return bip32_key_get_fingerprint(jarg1, null); + } + public final static byte[] bip32_key_get_hash160(Object jarg1) { return bip32_key_get_hash160(jarg1, null); } @@ -76,6 +80,10 @@ return bip38_to_private_key(jarg1, jarg2, jarg3, null); } + public final static byte[] ecdh(byte[] jarg1, byte[] jarg2) { + return ecdh(jarg1, jarg2, null); + } + public final static byte[] sha256(byte[] jarg1) { return sha256(jarg1, null); } @@ -119,6 +127,10 @@ return ec_public_key_from_private_key(jarg1, null); } + public final static byte[] ec_public_key_negate(byte[] jarg1) { + return ec_public_key_negate(jarg1, null); + } + public final static byte[] ec_sig_from_bytes(byte[] jarg1, byte[] jarg2, long jarg3) { return ec_sig_from_bytes(jarg1, jarg2, jarg3, null); } @@ -139,6 +151,10 @@ return tx_get_input_txhash(jarg1, jarg2, null); } + public final static byte[] tx_input_get_txhash(Object jarg1) { + return tx_input_get_txhash(jarg1, null); + } + public final static byte[] ec_sig_to_der(byte[] sig) { final byte[] buf = new byte[EC_SIGNATURE_DER_MAX_LEN]; final int len = ec_sig_to_der(sig, buf); @@ -174,19 +190,19 @@ return ret; } - public static final byte[] scriptpubkey_p2pkh_from_bytes(byte[] bytes, long flags) { + public final static byte[] scriptpubkey_p2pkh_from_bytes(byte[] bytes, long flags) { final byte[] buf = new byte[WALLY_SCRIPTPUBKEY_P2PKH_LEN]; final int len = scriptpubkey_p2pkh_from_bytes(bytes, flags, buf); return checkBuffer(buf, len); } - public static final byte[] scriptpubkey_p2sh_from_bytes(byte[] bytes, long flags) { + public final static byte[] scriptpubkey_p2sh_from_bytes(byte[] bytes, long flags) { final byte[] buf = new byte[WALLY_SCRIPTPUBKEY_P2SH_LEN]; final int len = scriptpubkey_p2sh_from_bytes(bytes, flags, buf); return checkBuffer(buf, len); } - public static final byte[] scriptpubkey_multisig_from_bytes(byte[] bytes, long threshold, long flags, int num_sigs) { + public final static byte[] scriptpubkey_multisig_from_bytes(byte[] bytes, long threshold, long flags, int num_sigs) { final int required_len = 3 + num_sigs * (Wally.EC_PUBLIC_KEY_LEN + 1); final byte[] buf = new byte[required_len]; final int len = scriptpubkey_multisig_from_bytes(bytes, threshold, flags, buf); @@ -205,7 +221,7 @@ return ret; } - public static final byte[] addr_segwit_to_bytes(String jarg1, String jarg2, long jarg3) { + public final static byte[] addr_segwit_to_bytes(String jarg1, String jarg2, long jarg3) { final byte[] buf = new byte[32 + 2]; /* Largest v0 witness script possible */ final int len = addr_segwit_to_bytes(jarg1, jarg2, jarg3, buf); return trimBuffer(buf, len); @@ -215,6 +231,10 @@ return _wif_is_uncompressed(wif) != 0; } + public final static byte[] tx_get_txid(final Object tx) { + return tx_get_txid(tx, null); + } + public static final byte[] tx_to_bytes(final Object tx, long flags) { final int txlength = Wally.tx_get_length(tx, flags); final byte[] buf = new byte[txlength]; @@ -274,6 +294,14 @@ return _is_elements_build() != 0; } + public final static byte[] symmetric_key_from_seed(byte[] jarg1) { + return symmetric_key_from_seed(jarg1, null); + } + + public final static byte[] symmetric_key_from_parent(byte[] jarg1, long jarg2, byte[] jarg3) { + return symmetric_key_from_parent(jarg1, jarg2, jarg3, null); + } + public final static void cleanup() { _cleanup(0); } diff --git a/src/swig_java/src/com/blockstream/test/test_assets.java b/src/swig_java/src/com/blockstream/test/test_assets.java index 9f3f9c183..e453c637e 100644 --- a/src/swig_java/src/com/blockstream/test/test_assets.java +++ b/src/swig_java/src/com/blockstream/test/test_assets.java @@ -40,6 +40,13 @@ public void test_blinding_keys() { throw new RuntimeException("Unexpected public_blinding_key result"); } + public void test_symmetric() { + // Just test our wrappers; the values are tested by test_blinding_keys() above + final byte[] seed = h("fecd7938b912091cdedb47f70d4f3742f59f77e3bac780c0c498e2aaf6f9f4ab"); + final byte[] master_key = Wally.symmetric_key_from_seed(seed); + final byte[] child_key = Wally.symmetric_key_from_parent(master_key, 0, new String("foo").getBytes()); + } + private void test_confidential_address() { // hexes from local regtest testing final String addr = "Q7qcjTLsYGoMA7TjUp97R6E6AM5VKqBik6"; @@ -79,6 +86,7 @@ public static void main(final String[] args) { final test_assets t = new test_assets(); t.test_blinding(); t.test_blinding_keys(); + t.test_symmetric(); t.test_confidential_address(); t.test_confidential_values(); } diff --git a/src/swig_java/src/com/blockstream/test/test_bip32.java b/src/swig_java/src/com/blockstream/test/test_bip32.java index 45251672b..c6512f2bb 100644 --- a/src/swig_java/src/com/blockstream/test/test_bip32.java +++ b/src/swig_java/src/com/blockstream/test/test_bip32.java @@ -59,14 +59,29 @@ public void test() { message, EC_FLAG_ECDSA | EC_FLAG_RECOVERABLE); - Arrays.equals(signature, Arrays.copyOfRange(signatureRecoverable, 1, 65)); + if (!Arrays.equals(signature, Arrays.copyOfRange(signatureRecoverable, 1, 65))) { + throw new RuntimeException("Recoverable signature does not match"); + } final byte[] pubkey = Wally.bip32_key_get_pub_key(derivedKey); Wally.ec_sig_verify(pubkey, message, EC_FLAG_ECDSA, signature); Wally.ec_sig_verify(pubkey, message, EC_FLAG_ECDSA, Arrays.copyOfRange(signatureRecoverable, 1, 65)); final byte[] pubkey_recovered = Wally.ec_sig_to_public_key(message, signatureRecoverable); - Arrays.equals(pubkey, pubkey_recovered); + if (!Arrays.equals(pubkey, pubkey_recovered)) { + throw new RuntimeException("Failed to recover pubkey from signature"); + } + + // Test pubkey negation + final byte[] pubkey_negated = Wally.ec_public_key_negate(pubkey_recovered); + if (Arrays.equals(pubkey_recovered, pubkey_negated)) { + throw new RuntimeException("Failed to negate pubkey"); + } + + final byte[] pubkey_unnegated = Wally.ec_public_key_negate(pubkey_negated); + if (!Arrays.equals(pubkey_recovered, pubkey_unnegated)) { + throw new RuntimeException("Double negation did not return original pubkey"); + } Wally.bip32_key_free(initKey); Wally.bip32_key_free(derivedKey); diff --git a/src/swig_java/src/com/blockstream/test/test_tx.java b/src/swig_java/src/com/blockstream/test/test_tx.java index f8d73a127..7a87ac063 100644 --- a/src/swig_java/src/com/blockstream/test/test_tx.java +++ b/src/swig_java/src/com/blockstream/test/test_tx.java @@ -31,6 +31,7 @@ public void test() { final Object tx_input_wit_null = Wally.tx_input_init(tx_get_input_txhash, 0, 4294967295L, tx_get_input_script, null); final Object tx_out = Wally.tx_output_init(100, tx_get_output_script); final byte[] tx_input_get_script = Wally.tx_input_get_script(tx_input); + final byte[] txid = Wally.tx_get_txid(tx); assert_eq(p2pkh_hex, tx_string, "hex ser/der doesn't match original"); assert_eq(p2pkh_hex, h(tx_bytes), "hex(bytes) doesn't match original"); @@ -46,7 +47,7 @@ public void test() { assert_eq(25, tx_get_output_script.length, "output script length mismatch"); assert_eq("76a9142bc89c2702e0e618db7d59eb5ce2f0f147b4075488ac", h(tx_get_output_script), "output script mismatch"); assert_eq( 0, Wally.tx_get_witness_count(tx), "witness count mismatch"); - assert_eq(p2pkh_hex_first_input_hash, h(Wally.tx_input_get_txhash(tx_input, null)), "hash of prevout 0 from tx_input does not match"); + assert_eq(p2pkh_hex_first_input_hash, h(Wally.tx_input_get_txhash(tx_input)), "hash of prevout 0 from tx_input does not match"); assert_eq(p2pkh_hex_first_input_script, h(tx_input_get_script), "script hex mismatch"); assert_eq(4294967295L, Wally.tx_input_get_sequence(tx_input), "sequence mismatch from tx_input"); assert_eq(118307L, Wally.tx_get_output_satoshi(tx,0), "output 0, satoshi mismatch"); @@ -55,6 +56,8 @@ public void test() { assert_eq(72, Wally.tx_get_input_witness(tx_wit, 0, 1).length, "witness buffer mismatch"); assert_eq(h(tx_get_output_script), h(Wally.tx_output_get_script(tx_out)), "script hex mismatch"); assert_eq(100L, Wally.tx_output_get_satoshi(tx_out), "total output mismatch"); + /* Note that the hex used here is reversed from the typical txid display order */ + assert_eq("26641caee29b3ce14d0888ad3cfdd2f73f32f0c41d3da85127639009b38f1b21", h(txid), "txid mismatch"); Wally.tx_add_input(tx, tx_input); assert_eq(2, Wally.tx_get_num_inputs(tx), "after adding number of inputs is not 2"); diff --git a/src/swig_java/swig.i b/src/swig_java/swig.i index d78b190fc..c29356f52 100644 --- a/src/swig_java/swig.i +++ b/src/swig_java/swig.i @@ -94,14 +94,6 @@ static unsigned char* malloc_or_throw(JNIEnv *jenv, size_t len) { return p; } -static void clear_and_free(void *p, size_t len) -{ - if (p) { - wally_bzero(p, len); - wally_free(p); - } -} - static jbyteArray create_array(JNIEnv *jenv, const unsigned char* p, size_t len) { jbyteArray ret = (*jenv)->NewByteArray(jenv, len); if (ret) @@ -234,6 +226,7 @@ static jbyteArray create_array(JNIEnv *jenv, const unsigned char* p, size_t len) %apply(char *STRING, size_t LENGTH) { (const unsigned char *output_asset, size_t output_asset_len) }; %apply(char *STRING, size_t LENGTH) { (const unsigned char *output_generator, size_t output_generator_len) }; %apply(char *STRING, size_t LENGTH) { (const unsigned char *nonce, size_t nonce_len) }; +%apply(char *STRING, size_t LENGTH) { (const unsigned char *nonce_hash, size_t nonce_hash_len) }; %apply(char *STRING, size_t LENGTH) { (const unsigned char *pass, size_t pass_len) }; %apply(char *STRING, size_t LENGTH) { (const unsigned char *parent160, size_t parent160_len) }; %apply(char *STRING, size_t LENGTH) { (const unsigned char *priv_key, size_t priv_key_len) }; @@ -250,10 +243,10 @@ static jbyteArray create_array(JNIEnv *jenv, const unsigned char* p, size_t len) %apply(char *STRING, size_t LENGTH) { (const unsigned char *vbf, size_t vbf_len) }; %apply(char *STRING, size_t LENGTH) { (const unsigned char *witness, size_t witness_len) }; %apply(char *STRING, size_t LENGTH) { (const unsigned char *label, size_t label_len) }; -%apply(char *STRING, size_t LENGTH) { (const unsigned char *parent_genesis_blockhash, size_t parent_genesis_blockhash_len) }; +%apply(char *STRING, size_t LENGTH) { (const unsigned char *genesis_blockhash, size_t genesis_blockhash_len) }; %apply(char *STRING, size_t LENGTH) { (const unsigned char *mainchain_script, size_t mainchain_script_len) }; %apply(char *STRING, size_t LENGTH) { (const unsigned char *sub_pubkey, size_t sub_pubkey_len) }; -%apply(char *STRING, size_t LENGTH) { (const unsigned char *whitelist_proof, size_t whitelist_proof_len) }; +%apply(char *STRING, size_t LENGTH) { (const unsigned char *whitelistproof, size_t whitelistproof_len) }; %apply(char *STRING, size_t LENGTH) { (const unsigned char *online_keys, size_t online_keys_len) }; %apply(char *STRING, size_t LENGTH) { (const unsigned char *offline_keys, size_t offline_keys_len) }; %apply(char *STRING, size_t LENGTH) { (const unsigned char *online_priv_key, size_t online_priv_key_len) }; @@ -379,12 +372,11 @@ static jbyteArray create_array(JNIEnv *jenv, const unsigned char* p, size_t len) %returns_struct(bip32_key_from_parent_path_alloc, ext_key); %rename("bip32_key_from_parent_path") bip32_key_from_parent_path_alloc; %returns_struct(bip32_key_from_seed_alloc, ext_key); -%returns_struct(bip32_key_with_tweak_from_parent_path_alloc, ext_key); -%rename("bip32_key_with_tweak_from_parent_path") bip32_key_with_tweak_from_parent_path_alloc; %rename("bip32_key_from_seed") bip32_key_from_seed_alloc; %returns_array_(bip32_key_get_chain_code, 2, 3, member_size(ext_key, chain_code)); %returns_size_t(bip32_key_get_child_num); %returns_size_t(bip32_key_get_depth); +%returns_array_(bip32_key_get_fingerprint, 2, 3, BIP32_KEY_FINGERPRINT_LEN); %returns_array_(bip32_key_get_hash160, 2, 3, member_size(ext_key, hash160)); %returns_array_(bip32_key_get_parent160, 2, 3, member_size(ext_key, parent160)); %returns_array_(bip32_key_get_priv_key, 2, 3, member_size(ext_key, priv_key) - 1); @@ -394,9 +386,12 @@ static jbyteArray create_array(JNIEnv *jenv, const unsigned char* p, size_t len) %returns_struct(bip32_key_init_alloc, ext_key); %rename("bip32_key_init") bip32_key_init_alloc; %returns_array_(bip32_key_serialize, 3, 4, BIP32_SERIALIZED_LEN); +%returns_void__(bip32_key_strip_private_key); %returns_string(bip32_key_to_base58); %returns_struct(bip32_key_unserialize_alloc, ext_key); %rename("bip32_key_unserialize") bip32_key_unserialize_alloc; +%returns_struct(bip32_key_with_tweak_from_parent_path_alloc, ext_key); +%rename("bip32_key_with_tweak_from_parent_path") bip32_key_with_tweak_from_parent_path_alloc; %returns_array_(bip38_raw_from_private_key, 6, 7, BIP38_SERIALIZED_LEN); %returns_string(bip38_from_private_key); %returns_array_(bip38_raw_to_private_key, 6, 7, 32); @@ -412,6 +407,7 @@ static jbyteArray create_array(JNIEnv *jenv, const unsigned char* p, size_t len) %returns_size_t(bip39_mnemonic_to_seed); %returns_string(wally_addr_segwit_from_bytes); %returns_size_t(wally_addr_segwit_to_bytes); +%returns_size_t(wally_address_to_scriptpubkey); %returns_array_(wally_aes, 6, 7, AES_BLOCK_LEN); %returns_size_t(wally_aes_cbc); %returns_array_(wally_asset_final_vbf, 8, 9, ASSET_TAG_LEN); @@ -551,11 +547,13 @@ static jbyteArray create_array(JNIEnv *jenv, const unsigned char* p, size_t len) %returns_size_t(wally_tx_get_output_value_len); %returns_array_(wally_tx_get_signature_hash, 12, 13, SHA256_LEN); %returns_uint64(wally_tx_get_total_output_satoshi); +%returns_array_(wally_tx_get_txid, 2, 3, WALLY_TXHASH_LEN); %returns_size_t(wally_tx_get_version); %returns_size_t(wally_tx_get_vsize); %returns_size_t(wally_tx_get_weight); %returns_size_t(wally_tx_get_witness_count); %returns_struct(wally_tx_init_alloc, wally_tx); +%returns_struct(wally_tx_clone, wally_tx); %rename("tx_init") wally_tx_init_alloc; %returns_void__(wally_tx_input_free); %returns_array_(wally_tx_input_get_blinding_nonce, 2, 3, SHA256_LEN); @@ -578,7 +576,7 @@ static jbyteArray create_array(JNIEnv *jenv, const unsigned char* p, size_t len) %returns_size_t(wally_tx_input_get_script_len); %rename("_tx_input_get_sequence") wally_tx_input_get_sequence; %returns_size_t(_tx_input_get_sequence); -%returns_array_(wally_tx_input_get_txhash, 2, 3, SHA256_LEN); +%returns_array_(wally_tx_input_get_txhash, 2, 3, WALLY_TXHASH_LEN); %rename("_tx_input_get_witness") wally_tx_input_get_witness; %returns_size_t(_tx_input_get_witness); %returns_size_t(wally_tx_input_get_witness_len); @@ -601,6 +599,8 @@ static jbyteArray create_array(JNIEnv *jenv, const unsigned char* p, size_t len) %returns_size_t(_tx_is_elements); %returns_void__(wally_tx_elements_output_commitment_set); %returns_void__(wally_tx_elements_output_commitment_free); +%returns_struct(wally_tx_output_clone_alloc, wally_tx_clone); +%rename("tx_output_clone") wally_tx_output_clone_alloc; %returns_void__(wally_tx_output_free); %rename("_tx_output_get_asset") wally_tx_output_get_asset; %returns_size_t(_tx_output_get_asset); @@ -658,6 +658,7 @@ static jbyteArray create_array(JNIEnv *jenv, const unsigned char* p, size_t len) %returns_void__(wally_tx_witness_stack_free); %returns_struct(wally_tx_witness_stack_init_alloc, wally_tx_witness_stack); %rename("tx_witness_stack_init") wally_tx_witness_stack_init_alloc; +%returns_struct(wally_tx_witness_stack_clone_alloc, wally_tx_witness_stack); %returns_void__(wally_tx_witness_stack_set); %returns_void__(wally_tx_witness_stack_set_dummy); %returns_string(wally_wif_from_bytes); diff --git a/src/swig_python/contrib/address.py b/src/swig_python/contrib/address.py deleted file mode 100644 index 6b1faab7b..000000000 --- a/src/swig_python/contrib/address.py +++ /dev/null @@ -1,24 +0,0 @@ -"""Tests for addresses""" -import unittest -from wallycore import * - - -h2b = hex_to_bytes - - -class AddressTests(unittest.TestCase): - - def test_b58_address(self): - for address, scriptpubkey, network in [ - ('mxvewdhKCenLkYgNa8irv1UM2omEWPMdEE', h2b('76a914bef5a2f9a56a94aab12459f72ad9cf8cf19c7bbe88ac'), WALLY_NETWORK_BITCOIN_TESTNET), # p2pkh - ('2N5XyEfAXtVde7mv6idZDXp5NFwajYEj9TD', h2b('a91486cc442a97817c245ce90ed0d31d6dbcde3841f987'), WALLY_NETWORK_BITCOIN_TESTNET), # p2sh - ('1JQheacLPdM5ySCkrZkV66G2ApAXe1mqLj', h2b('76a914bef5a2f9a56a94aab12459f72ad9cf8cf19c7bbe88ac'), WALLY_NETWORK_BITCOIN_MAINNET), # p2pkh - ('3DymAvEWH38HuzHZ3VwLus673bNZnYwNXu', h2b('a91486cc442a97817c245ce90ed0d31d6dbcde3841f987'), WALLY_NETWORK_BITCOIN_MAINNET), # p2sh - ('XYtnYoGoSeE9ouMEVi6mfeujhjT2VnJncA', h2b('a914ec51ffb65120594389733bf8625f542446d97f7987'), WALLY_NETWORK_LIQUID_REGTEST), - ('H5nswXhfo8AMt159sgA5FWT35De34hVR4o', h2b('a914f80278b2011573a2ac59c83fadf929b0fc57ad0187'), WALLY_NETWORK_LIQUID), - ]: - self.assertEqual(address_to_scriptpubkey(address, network), scriptpubkey) - self.assertEqual(scriptpubkey_to_address(scriptpubkey, network), address) - -if __name__ == '__main__': - unittest.main() diff --git a/src/swig_python/contrib/elements_tx.py b/src/swig_python/contrib/elements_tx.py index 3a292ec4a..639981057 100644 --- a/src/swig_python/contrib/elements_tx.py +++ b/src/swig_python/contrib/elements_tx.py @@ -82,13 +82,10 @@ def test_tx(self): tx_add_elements_raw_output(tx, script, None, ct_value, None, None, None, 0) size = tx_get_length(tx, 0) vsize = tx_vsize_from_weight(tx_get_weight(tx)) - tx_hex = tx_to_hex(tx, WALLY_TX_FLAG_USE_WITNESS) - tx_bytes = tx_to_bytes(tx, WALLY_TX_FLAG_USE_WITNESS) - self.assertEqual(tx_hex, hex_from_bytes(tx_bytes)) - with self.assertRaises(ValueError): - tx_to_hex(tx, WALLY_TX_FLAG_USE_ELEMENTS) - with self.assertRaises(ValueError): - tx_to_bytes(tx, WALLY_TX_FLAG_USE_ELEMENTS) + for extra_flags in (0, WALLY_TX_FLAG_USE_ELEMENTS, WALLY_TX_FLAG_ALLOW_PARTIAL): + tx_hex = tx_to_hex(tx, WALLY_TX_FLAG_USE_WITNESS | extra_flags) + tx_bytes = tx_to_bytes(tx, WALLY_TX_FLAG_USE_WITNESS | extra_flags) + self.assertEqual(tx_hex, hex_from_bytes(tx_bytes)) def test_coinbase(self): txhash, seq, script = bytearray(b'\x00'*32), 0xffffffff, b'0000' diff --git a/src/swig_python/contrib/psbt.py b/src/swig_python/contrib/psbt.py new file mode 100644 index 000000000..609fa96be --- /dev/null +++ b/src/swig_python/contrib/psbt.py @@ -0,0 +1,117 @@ +"""Tests for PSBT wrappers""" +import unittest +from wallycore import * + +SAMPLE = "cHNidP8BAFICAAAAAZ38ZijCbFiZ/hvT3DOGZb/VXXraEPYiCXPfLTht7BJ2AQAAAAD/////AfA9zR0AAAAAFgAUezoAv9wU0neVwrdJAdCdpu8TNXkAAAAATwEENYfPAto/0AiAAAAAlwSLGtBEWx7IJ1UXcnyHtOTrwYogP/oPlMAVZr046QADUbdDiH7h1A3DKmBDck8tZFmztaTXPa7I+64EcvO8Q+IM2QxqT64AAIAAAACATwEENYfPAto/0AiAAAABuQRSQnE5zXjCz/JES+NTzVhgXj5RMoXlKLQH+uP2FzUD0wpel8itvFV9rCrZp+OcFyLrrGnmaLbyZnzB1nHIPKsM2QxqT64AAIABAACAAAEBKwBlzR0AAAAAIgAgLFSGEmxJeAeagU4TcV1l82RZ5NbMre0mbQUIZFuvpjIBBUdSIQKdoSzbWyNWkrkVNq/v5ckcOrlHPY5DtTODarRWKZyIcSEDNys0I07Xz5wf6l0F1EFVeSe+lUKxYusC4ass6AIkwAtSriIGAp2hLNtbI1aSuRU2r+/lyRw6uUc9jkO1M4NqtFYpnIhxENkMak+uAACAAAAAgAAAAAAiBgM3KzQjTtfPnB/qXQXUQVV5J76VQrFi6wLhqyzoAiTACxDZDGpPrgAAgAEAAIAAAAAAACICA57/H1R6HV+S36K6evaslxpL0DukpzSwMVaiVritOh75EO3kXMUAAACAAAAAgAEAAIAA" + + +class PSBTTests(unittest.TestCase): + + def _try_set(self, fn, psbt, valid_value, null_value=None): + fn(psbt, 0, valid_value) # Set + fn(psbt, 0, null_value) # Un-set + with self.assertRaises(ValueError): + fn(None, 0, valid_value) # Null PSBT + with self.assertRaises(ValueError): + fn(psbt, 1, valid_value) # Invalid index + + + def test_psbt(self): + psbt = psbt_from_base64(SAMPLE) + + self.assertIsNotNone(psbt_get_global_tx(psbt)) + + self.assertEqual(psbt_get_version(psbt), 0) + self.assertEqual(psbt_get_num_inputs(psbt), 1) + self.assertEqual(psbt_get_num_outputs(psbt), 1) + + # Conversion to base64 should round trip + self.assertEqual(psbt_to_base64(psbt, 0), SAMPLE) + + # Combining with ourselves shouldn't change the PSBT + psbt_combine(psbt, psbt) + self.assertEqual(psbt_to_base64(psbt, 0), SAMPLE) + + # Test setters + dummy_tx = psbt_get_global_tx(psbt) + self.assertIsNotNone(dummy_tx) + + dummy_txout = tx_output_init(1234567, bytearray(b'\x00' * 33)) + + dummy_witness = tx_witness_stack_init(5) + self.assertIsNotNone(dummy_witness) + + dummy_bytes = bytearray(b'\x00' * 32) + dummy_pubkey = bytearray(b'\x02'* EC_PUBLIC_KEY_LEN) + dummy_fingerprint = bytearray(b'\x00' * BIP32_KEY_FINGERPRINT_LEN) + dummy_path = [1234, 1234, 1234] + dummy_sig = bytearray(b'\x00' * 72) + if is_elements_build(): + dummy_nonce = bytearray(b'\x00' * WALLY_TX_ASSET_CT_NONCE_LEN) + dummy_bf = bytearray(b'\x00' * BLINDING_FACTOR_LEN) + dummy_commitment = bytearray(b'\x00' * ASSET_COMMITMENT_LEN) + dummy_asset = bytearray(b'\x00' * ASSET_TAG_LEN) + + dummy_keypaths = keypath_map_init(0) + self.assertIsNotNone(dummy_keypaths) + keypath_map_add(dummy_keypaths, dummy_pubkey, dummy_fingerprint, dummy_path) + self.assertEqual(keypath_map_find(dummy_keypaths, dummy_pubkey), 1) + + dummy_partial_sigs = partial_sigs_map_init(0) + self.assertIsNotNone(dummy_partial_sigs) + partial_sigs_map_add(dummy_partial_sigs, dummy_pubkey, dummy_sig) + self.assertEqual(partial_sigs_map_find(dummy_partial_sigs, dummy_pubkey), 1) + + dummy_unknowns = unknowns_map_init(1) + self.assertIsNotNone(dummy_unknowns) + unknowns_map_add(dummy_unknowns, dummy_pubkey, dummy_fingerprint) + self.assertEqual(unknowns_map_find(dummy_unknowns, dummy_pubkey), 1) + + # + # Inputs + # + self._try_set(psbt_set_input_non_witness_utxo, psbt, dummy_tx) + self._try_set(psbt_set_input_witness_utxo, psbt, dummy_txout) + self._try_set(psbt_set_input_final_witness, psbt, dummy_witness) + self._try_set(psbt_set_input_keypaths, psbt, dummy_keypaths) + self._try_set(psbt_set_input_partial_sigs, psbt, dummy_partial_sigs) + self._try_set(psbt_set_input_unknowns, psbt, dummy_unknowns) + self._try_set(psbt_set_input_sighash_type, psbt, 0xff, 0x0) + self._try_set(psbt_set_input_redeem_script, psbt, dummy_bytes) + self._try_set(psbt_set_input_witness_script, psbt, dummy_bytes) + self._try_set(psbt_set_input_final_script_sig, psbt, dummy_bytes) + if is_elements_build(): + self._try_set(psbt_set_input_value, psbt, 1234567, 0) + psbt_clear_input_value(psbt, 0) + with self.assertRaises(ValueError): + psbt_clear_input_value(None, 0) # Null PSBT + with self.assertRaises(ValueError): + psbt_clear_input_value(psbt, 1) # Invalid index + self._try_set(psbt_set_input_vbf, psbt, dummy_bf) + self._try_set(psbt_set_input_asset, psbt, dummy_asset) + self._try_set(psbt_set_input_abf, psbt, dummy_bf) + self._try_set(psbt_set_input_peg_in_tx, psbt, dummy_tx) + self._try_set(psbt_set_input_txoutproof, psbt, dummy_bytes) + self._try_set(psbt_set_input_genesis_blockhash, psbt, dummy_bytes) + self._try_set(psbt_set_input_claim_script, psbt, dummy_bytes) + + # + # Outputs + # + self._try_set(psbt_set_output_redeem_script, psbt, dummy_bytes) + self._try_set(psbt_set_output_witness_script, psbt, dummy_bytes) + self._try_set(psbt_set_output_keypaths, psbt, dummy_keypaths) + self._try_set(psbt_set_output_unknowns, psbt, dummy_unknowns) + if is_elements_build(): + self._try_set(psbt_set_output_blinding_pubkey, psbt, dummy_pubkey) + self._try_set(psbt_set_output_value_commitment, psbt, dummy_commitment) + self._try_set(psbt_set_output_vbf, psbt, dummy_bf) + self._try_set(psbt_set_output_asset_commitment, psbt, dummy_commitment) + self._try_set(psbt_set_output_abf, psbt, dummy_bf) + self._try_set(psbt_set_output_nonce, psbt, dummy_nonce) + self._try_set(psbt_set_output_rangeproof, psbt, dummy_bytes) + self._try_set(psbt_set_output_surjectionproof, psbt, dummy_bytes) + + +if __name__ == '__main__': + unittest.main() diff --git a/src/swig_python/contrib/tx.py b/src/swig_python/contrib/tx.py index eeeb570ea..28dcfc7bf 100644 --- a/src/swig_python/contrib/tx.py +++ b/src/swig_python/contrib/tx.py @@ -17,6 +17,10 @@ def test_tx_witness(self): witness = tx_witness_stack_init(0) tx_witness_stack_set(witness, 0, witness_script) + with self.assertRaises(ValueError): + tx_witness_stack_clone(None) + cloned = tx_witness_stack_clone(witness) + def test_tx_input(self): # Test invalid inputs txhash, seq, script, witness_script = b'0' * 32, 0xffffffff, b'0000', b'000000' diff --git a/src/swig_python/python_extra.py_in b/src/swig_python/python_extra.py_in index 1262b3e72..755380d82 100644 --- a/src/swig_python/python_extra.py_in +++ b/src/swig_python/python_extra.py_in @@ -133,6 +133,7 @@ address_to_scriptpubkey = _wrap_bin(address_to_scriptpubkey, 21 + 4, resize=True tx_to_bytes = _wrap_bin(tx_to_bytes, tx_get_length, resize=True) tx_get_btc_signature_hash = _wrap_bin(tx_get_btc_signature_hash, SHA256_LEN) +tx_get_txid = _wrap_bin(tx_get_txid, WALLY_TXHASH_LEN) tx_get_signature_hash = _wrap_bin(tx_get_signature_hash, SHA256_LEN) tx_input_get_txhash = _wrap_bin(tx_input_get_txhash, WALLY_TXHASH_LEN) tx_input_get_script = _wrap_bin(tx_input_get_script, tx_input_get_script_len, resize=True) diff --git a/src/swig_python/swig.i b/src/swig_python/swig.i index a01da2132..a3f5757e0 100644 --- a/src/swig_python/swig.i +++ b/src/swig_python/swig.i @@ -28,6 +28,8 @@ del swig_import_helper #include "../include/wally_bip38.h" #include "../include/wally_bip39.h" #include "../include/wally_crypto.h" +#include "../include/wally_psbt.h" +#include "psbt_int.h" #include "../include/wally_script.h" #include "../include/wally_symmetric.h" #include "../include/wally_transaction.h" @@ -83,10 +85,14 @@ static bool ulonglong_cast(PyObject *item, unsigned long long *val) if (p) fn(p); } capsule_dtor(ext_key, bip32_key_free) +capsule_dtor(wally_keypath_map, wally_keypath_map_free) +capsule_dtor(wally_partial_sigs_map, wally_partial_sigs_map_free) +capsule_dtor(wally_psbt, wally_psbt_free) capsule_dtor(wally_tx, wally_tx_free) capsule_dtor(wally_tx_input, wally_tx_input_free) capsule_dtor(wally_tx_output, wally_tx_output_free) capsule_dtor(wally_tx_witness_stack, wally_tx_witness_stack_free) +capsule_dtor(wally_unknowns_map, wally_unknowns_map_free) static void destroy_words(PyObject *obj) { (void)obj; } #define MAX_LOCAL_STACK 256u @@ -187,11 +193,11 @@ static void destroy_words(PyObject *obj) { (void)obj; } /* Input buffers with lengths are passed as python buffers */ -%pybuffer_nonnull_binary(const unsigned char *abf, size_t abf_len); +%pybuffer_nullable_binary(const unsigned char *abf, size_t abf_len); %pybuffer_nonnull_binary(const unsigned char *asset, size_t asset_len); %pybuffer_nullable_binary(const unsigned char *bytes, size_t bytes_len); %pybuffer_nonnull_binary(const unsigned char *chain_code, size_t chain_code_len); -%pybuffer_nonnull_binary(const unsigned char *commitment, size_t commitment_len); +%pybuffer_nullable_binary(const unsigned char *commitment, size_t commitment_len); %pybuffer_nullable_binary(const unsigned char *extra, size_t extra_len); %pybuffer_nonnull_binary(const unsigned char *generator, size_t generator_len); %pybuffer_nullable_binary(const unsigned char *hash160, size_t hash160_len); @@ -203,7 +209,7 @@ static void destroy_words(PyObject *obj) { (void)obj; } %pybuffer_nonnull_binary(const unsigned char *pass, size_t pass_len); %pybuffer_nullable_binary(const unsigned char *parent160, size_t parent160_len); %pybuffer_nullable_binary(const unsigned char *priv_key, size_t priv_key_len); -%pybuffer_nonnull_binary(const unsigned char *proof, size_t proof_len); +%pybuffer_nullable_binary(const unsigned char *proof, size_t proof_len); %pybuffer_nullable_binary(const unsigned char *pub_key, size_t pub_key_len); %pybuffer_nonnull_binary(const unsigned char *salt, size_t salt_len); %pybuffer_nullable_binary(const unsigned char *script, size_t script_len); @@ -211,7 +217,7 @@ static void destroy_words(PyObject *obj) { (void)obj; } %pybuffer_nonnull_binary(const unsigned char *sig, size_t sig_len); %pybuffer_nonnull_binary(const unsigned char *sighash, size_t sighash_len); %pybuffer_nonnull_binary(const unsigned char *txhash, size_t txhash_len); -%pybuffer_nonnull_binary(const unsigned char *vbf, size_t vbf_len); +%pybuffer_nullable_binary(const unsigned char *vbf, size_t vbf_len); %pybuffer_nullable_binary(const unsigned char *witness, size_t witness_len); %pybuffer_nonnull_binary(const unsigned char *nonce, size_t nonce_len); %pybuffer_nonnull_binary(const unsigned char *nonce_hash, size_t nonce_hash_len); @@ -233,10 +239,13 @@ static void destroy_words(PyObject *obj) { (void)obj; } %pybuffer_nonnull_binary(const unsigned char *sub_pubkey, size_t sub_pubkey_len); %pybuffer_nonnull_binary(const unsigned char *online_priv_key, size_t online_priv_key_len); %pybuffer_nonnull_binary(const unsigned char *summed_key, size_t summed_key_len); -%pybuffer_nonnull_binary(const unsigned char *parent_genesis_blockhash, size_t parent_genesis_blockhash_len); +%pybuffer_nullable_binary(const unsigned char *genesis_blockhash, size_t genesis_blockhash_len); %pybuffer_nonnull_binary(const unsigned char *mainchain_script, size_t mainchain_script_len); -%pybuffer_nonnull_binary(const unsigned char *whitelist_proof, size_t whitelist_proof_len); -%pybuffer_nonnull_binary(const unsigned char *redeem_script, size_t redeem_script_len); +%pybuffer_nonnull_binary(const unsigned char *whitelistproof, size_t whitelistproof_len); +%pybuffer_nullable_binary(const unsigned char *redeem_script, size_t redeem_script_len); +%pybuffer_nullable_binary(const unsigned char *witness_script, size_t witness_script_len); +%pybuffer_nullable_binary(const unsigned char *final_script_sig, size_t final_script_sig_len); +%pybuffer_nullable_binary(const unsigned char *fingerprint, size_t fingerprint_len); /* Output buffers */ %pybuffer_output_binary(unsigned char *asset_out, size_t asset_out_len); @@ -327,26 +336,37 @@ static void destroy_words(PyObject *obj) { (void)obj; } %py_int_array(uint32_t, 0xffull, sighash, sighash_len) %py_int_array(uint64_t, 0xffffffffffffffffull, values, values_len) -%py_opaque_struct(words); %py_opaque_struct(ext_key); -%py_opaque_struct(wally_tx_witness_stack); +%py_opaque_struct(wally_keypath_map) +%py_opaque_struct(wally_partial_sigs_map) +%py_opaque_struct(wally_psbt); +%py_opaque_struct(wally_tx); %py_opaque_struct(wally_tx_input); %py_opaque_struct(wally_tx_output); -%py_opaque_struct(wally_tx); +%py_opaque_struct(wally_tx_witness_stack); +%py_opaque_struct(wally_unknowns_map) +%py_opaque_struct(words); +%rename("bip32_key_from_base58") bip32_key_from_base58_alloc; %rename("bip32_key_from_parent") bip32_key_from_parent_alloc; %rename("bip32_key_from_parent_path") bip32_key_from_parent_path_alloc; -%rename("bip32_key_with_tweak_from_parent_path") bip32_key_with_tweak_from_parent_path_alloc; %rename("bip32_key_from_seed") bip32_key_from_seed_alloc; %rename("bip32_key_init") bip32_key_init_alloc; -%rename("bip32_key_from_base58") bip32_key_from_base58_alloc; %rename("bip32_key_unserialize") bip32_key_unserialize_alloc; -%rename("tx_witness_stack_init") wally_tx_witness_stack_init_alloc; -%rename("tx_input_init") wally_tx_input_init_alloc; -%rename("tx_output_init") wally_tx_output_init_alloc; -%rename("tx_init") wally_tx_init_alloc; +%rename("bip32_key_with_tweak_from_parent_path") bip32_key_with_tweak_from_parent_path_alloc; +%rename("keypath_map_init") wally_keypath_map_init_alloc; +%rename("partial_sigs_map_init") wally_partial_sigs_map_init_alloc; +%rename("psbt_get_global_tx") wally_psbt_get_global_tx_alloc; +%rename("psbt_init") wally_psbt_init_alloc; %rename("tx_elements_input_init") wally_tx_elements_input_init_alloc; %rename("tx_elements_output_init") wally_tx_elements_output_init_alloc; +%rename("tx_init") wally_tx_init_alloc; +%rename("tx_input_init") wally_tx_input_init_alloc; +%rename("tx_output_clone") wally_tx_output_clone_alloc; +%rename("tx_output_init") wally_tx_output_init_alloc; +%rename("tx_witness_stack_clone") wally_tx_witness_stack_clone_alloc; +%rename("tx_witness_stack_init") wally_tx_witness_stack_init_alloc; +%rename("unknowns_map_init") wally_unknowns_map_init_alloc; %rename("%(regex:/^wally_(.+)/\\1/)s", %$isfunction) ""; %include "../include/wally_core.h" @@ -357,6 +377,8 @@ static void destroy_words(PyObject *obj) { (void)obj; } %include "../include/wally_bip39.h" %include "../include/wally_crypto.h" %include "../include/wally_script.h" +%include "../include/wally_psbt.h" +%include "psbt_int.h" %include "../include/wally_symmetric.h" %include "../include/wally_transaction.h" %include "transaction_int.h" diff --git a/src/symmetric.c b/src/symmetric.c index 4fb7a0038..169f573ba 100644 --- a/src/symmetric.c +++ b/src/symmetric.c @@ -25,13 +25,13 @@ int wally_symmetric_key_from_seed( if (!bytes || !is_valid_seed_length(bytes_len) || !bytes_out || len != HMAC_SHA512_LEN) return WALLY_EINVAL; - return wally_hmac_sha512(DOMAIN_STR, sizeof(DOMAIN_STR), bytes, bytes_len, bytes_out, HMAC_SHA512_LEN); + return wally_hmac_sha512(DOMAIN_STR, sizeof(DOMAIN_STR), bytes, bytes_len, bytes_out, len); } int wally_symmetric_key_from_parent( const unsigned char *bytes, size_t bytes_len, - unsigned char version, + uint32_t version, const unsigned char *label, size_t label_len, unsigned char *bytes_out, @@ -55,8 +55,9 @@ int wally_symmetric_key_from_parent( *buff_p = version; memcpy(buff_p + 1, label, label_len); - ret = wally_hmac_sha512(bytes, SYMMETRIC_KEY_LEN, buff_p, buff_len, bytes_out, HMAC_SHA512_LEN); + ret = wally_hmac_sha512(bytes, HMAC_SHA512_LEN / 2, buff_p, buff_len, bytes_out, len); + wally_clear(buff_p, buff_len); if (buff_p != buff) wally_free(buff_p); diff --git a/src/test/test_address.py b/src/test/test_address.py index ce4385c04..b3e07545f 100755 --- a/src/test/test_address.py +++ b/src/test/test_address.py @@ -1,4 +1,3 @@ -#!/usr/bin/env python3 import unittest from util import * @@ -13,11 +12,14 @@ ADDRESS_VERSION_P2PKH_MAINNET = 0x00 ADDRESS_VERSION_P2PKH_TESTNET = 0x6F -ADDRESS_VERSION_P2SH_MAINNET = 0x05 -ADDRESS_VERSION_P2SH_TESTNET = 0xC4 +ADDRESS_VERSION_P2SH_MAINNET = 0x05 +ADDRESS_VERSION_P2SH_TESTNET = 0xC4 NETWORK_BITCOIN_MAINNET = 0x01 NETWORK_BITCOIN_TESTNET = 0x02 +NETWORK_LIQUID_MAINNET = 0x03 +NETWORK_LIQUID_REGTEST = 0x04 + # Vector from test_bip32.py. We only need an xpub to derive addresses. vec = { @@ -97,29 +99,29 @@ def do_test_vector(self, vec, path, network): # Address type flag is mandatory version = ADDRESS_VERSION_P2PKH_MAINNET if network == NETWORK_BITCOIN_MAINNET else ADDRESS_VERSION_P2PKH_TESTNET - ret, out = wally_bip32_key_to_address(key, 0, version) + ret, new_addr = wally_bip32_key_to_address(key, 0, version) self.assertEqual(ret, WALLY_EINVAL) # Obtain legacy address (P2PKH) - ret, out = wally_bip32_key_to_address(key, ADDRESS_TYPE_P2PKH, version) + ret, new_addr = wally_bip32_key_to_address(key, ADDRESS_TYPE_P2PKH, version) self.assertEqual(ret, WALLY_OK) - self.assertEqual(out, vec[path]['address_legacy']) + self.assertEqual(new_addr, vec[path]['address_legacy']) # Obtain wrapped SegWit address (P2SH_P2WPKH) version = ADDRESS_VERSION_P2SH_MAINNET if network == NETWORK_BITCOIN_MAINNET else ADDRESS_VERSION_P2SH_TESTNET - ret, out = wally_bip32_key_to_address(key, ADDRESS_TYPE_P2SH_P2WPKH, version) + ret, new_addr = wally_bip32_key_to_address(key, ADDRESS_TYPE_P2SH_P2WPKH, version) self.assertEqual(ret, WALLY_OK) - self.assertEqual(out, vec[path]['address_p2sh_segwit']) + self.assertEqual(new_addr, vec[path]['address_p2sh_segwit']) # wally_bip32_key_to_address does not support bech32 native SegWit (P2WPKH) - ret, out = wally_bip32_key_to_address(key, ADDRESS_TYPE_P2WPKH, version) + ret, new_addr = wally_bip32_key_to_address(key, ADDRESS_TYPE_P2WPKH, version) self.assertEqual(ret, WALLY_EINVAL) # Obtain native SegWit address (P2WPKH) bech32_prefix = 'bc' if network == NETWORK_BITCOIN_MAINNET else 'tb' - ret, out = wally_bip32_key_to_addr_segwit(key, utf8(bech32_prefix), 0) + ret, new_addr = wally_bip32_key_to_addr_segwit(key, utf8(bech32_prefix), 0) self.assertEqual(ret, WALLY_OK) - self.assertEqual(out, vec[path]['address_segwit']) + self.assertEqual(new_addr, vec[path]['address_segwit']) # Parse legacy address (P2PKH): out, out_len = make_cbuffer('00' * (25)) @@ -129,9 +131,9 @@ def do_test_vector(self, vec, path, network): self.assertEqual(hexlify(out[0:written]), utf8(vec[path]['scriptpubkey_legacy'])) # Get address for P2PKH scriptPubKey - ret, out = wally_scriptpubkey_to_address(out, written, network) + ret, new_addr = wally_scriptpubkey_to_address(out, written, network) self.assertEqual(ret, WALLY_OK) - self.assertEqual(out, vec[path]['address_legacy']) + self.assertEqual(new_addr, vec[path]['address_legacy']) # Parse wrapped SegWit address (P2SH_P2WPKH): out, out_len = make_cbuffer('00' * (25)) @@ -141,9 +143,9 @@ def do_test_vector(self, vec, path, network): self.assertEqual(hexlify(out[0:written]), utf8(vec[path]['scriptpubkey_p2sh_segwit'])) # Get address for P2SH scriptPubKey - ret, out = wally_scriptpubkey_to_address(out, written, network) + ret, new_addr = wally_scriptpubkey_to_address(out, written, network) self.assertEqual(ret, WALLY_OK) - self.assertEqual(out, vec[path]['address_p2sh_segwit']) + self.assertEqual(new_addr, vec[path]['address_p2sh_segwit']) # Parse native SegWit address (P2WPKH): out, out_len = make_cbuffer('00' * (100)) @@ -151,5 +153,21 @@ def do_test_vector(self, vec, path, network): self.assertEqual(ret, WALLY_OK) self.assertEqual(hexlify(out[0:written]), utf8(vec[path]['scriptpubkey_segwit'])) + def test_address_scriptpubkey_liquid(self): + """Check that addresses can be converted to and from scriptpubkeys for Liquid""" + for addr, scriptpubkey, network in [ + ('XYtnYoGoSeE9ouMEVi6mfeujhjT2VnJncA', 'a914ec51ffb65120594389733bf8625f542446d97f7987', NETWORK_LIQUID_REGTEST), + ('H5nswXhfo8AMt159sgA5FWT35De34hVR4o', 'a914f80278b2011573a2ac59c83fadf929b0fc57ad0187', NETWORK_LIQUID_MAINNET), + ]: + out, out_len = make_cbuffer('00' * (100)) + ret, written = wally_address_to_scriptpubkey(utf8(addr), network, out, out_len) + self.assertEqual(ret, WALLY_OK) + self.assertEqual(hexlify(out[0:written]), utf8(scriptpubkey)) + + ret, new_addr = wally_scriptpubkey_to_address(out, written, network) + self.assertEqual(ret, WALLY_OK) + self.assertEqual(utf8(new_addr), utf8(addr)) + + if __name__ == '__main__': unittest.main() diff --git a/src/test/test_psbt.py b/src/test/test_psbt.py index f9d07258d..80fb5c679 100644 --- a/src/test/test_psbt.py +++ b/src/test/test_psbt.py @@ -1,15 +1,15 @@ import binascii -import base64 import json -import os import unittest from util import * +FLAG_GRIND_R = 0x4 + class PSBTTests(unittest.TestCase): def test_serialization(self): """Testing serialization and deserialization""" - with open(os.path.join(os.path.dirname(os.path.realpath(__file__)), 'data/psbt.json')) as f: + with open(root_dir + 'src/data/psbt.json', 'r') as f: d = json.load(f) invalids = d['invalid'] valids = d['valid'] @@ -26,24 +26,24 @@ def test_serialization(self): for valid in valids: psbt = pointer(wally_psbt()) self.assertEqual(WALLY_OK, wally_psbt_from_base64(valid['psbt'].encode('utf-8'), psbt)) - ret, reser = wally_psbt_to_base64(psbt) + ret, reser = wally_psbt_to_base64(psbt, 0) self.assertEqual(WALLY_OK, ret) self.assertEqual(valid['psbt'], reser) - ret, length = wally_psbt_get_length(psbt) + ret, length = wally_psbt_get_length(psbt, 0) self.assertEqual(WALLY_OK, ret) self.assertEqual(length, valid['len']) for creator in creators: psbt = pointer(wally_psbt()) - self.assertEqual(WALLY_OK, wally_psbt_init_alloc(2, 2, 0, psbt)) + self.assertEqual(WALLY_OK, wally_psbt_init_alloc(0, 2, 2, 0, psbt)) tx = pointer(wally_tx()) self.assertEqual(WALLY_OK, wally_tx_init_alloc(2, 0, 2, 2, tx)) for txin in creator['inputs']: - input = pointer(wally_tx_input()) + tx_in = pointer(wally_tx_input()) txid = binascii.unhexlify(txin['txid'])[::-1] - self.assertEqual(WALLY_OK, wally_tx_input_init_alloc(txid, len(txid), txin['vout'], 0xffffffff, None, 0, None, input)) - self.assertEqual(WALLY_OK, wally_tx_add_input(tx, input)) + self.assertEqual(WALLY_OK, wally_tx_input_init_alloc(txid, len(txid), txin['vout'], 0xffffffff, None, 0, None, tx_in)) + self.assertEqual(WALLY_OK, wally_tx_add_input(tx, tx_in)) for txout in creator['outputs']: addr = txout['addr'] amt = txout['amt'] @@ -55,20 +55,25 @@ def test_serialization(self): self.assertEqual(WALLY_OK, wally_tx_add_output(tx, output)) self.assertEqual(WALLY_OK, wally_psbt_set_global_tx(psbt, tx)) - ret, ser = wally_psbt_to_base64(psbt) + # wally_psbt_set_global_tx() reserves space for but does not add + # PSBT input and output values. Set the count here to use the + # empty reserved ones for this test. + psbt.contents.num_inputs = psbt.contents.tx.contents.num_inputs + psbt.contents.num_outputs = psbt.contents.tx.contents.num_outputs + ret, ser = wally_psbt_to_base64(psbt, 0) self.assertEqual(WALLY_OK, ret) self.assertEqual(creator['result'], ser) for combiner in combiners: - to_combine = [] - for comb in combiner['combine']: - psbt = pointer(wally_psbt()) - self.assertEqual(WALLY_OK, wally_psbt_from_base64(comb.encode('utf-8'), psbt)) - to_combine.append(psbt.contents) - combined = pointer(wally_psbt()) - self.assertEqual(WALLY_OK, wally_combine_psbts((wally_psbt * len(to_combine))(*to_combine), len(to_combine), combined)) - ret, comb_ser = wally_psbt_to_base64(combined) - self.assertEqual(combiner['result'], comb_ser) + psbt = pointer(wally_psbt()) + self.assertEqual(WALLY_OK, wally_psbt_from_base64(combiner['combine'][0].encode('utf-8'), psbt)) + for src_b64 in combiner['combine'][1:]: + src = pointer(wally_psbt()) + self.assertEqual(WALLY_OK, wally_psbt_from_base64(src_b64.encode('utf-8'), src)) + self.assertEqual(WALLY_OK, wally_psbt_combine(psbt, src)) + self.assertEqual(WALLY_OK, wally_psbt_free(src)) + ret, psbt_b64 = wally_psbt_to_base64(psbt, 0) + self.assertEqual(combiner['result'], psbt_b64) for signer in signers: psbt = pointer(wally_psbt()) @@ -76,9 +81,9 @@ def test_serialization(self): for priv in signer['privkeys']: buf, buf_len = make_cbuffer('00'*32) self.assertEqual(WALLY_OK, wally_wif_to_bytes(priv.encode('utf-8'), 0xEF, 0, buf, buf_len)) - self.assertEqual(WALLY_OK, wally_sign_psbt(psbt, buf, buf_len)) + self.assertEqual(WALLY_OK, wally_psbt_sign(psbt, buf, buf_len, FLAG_GRIND_R)) - ret, reser = wally_psbt_to_base64(psbt) + ret, reser = wally_psbt_to_base64(psbt, 0) self.assertEqual(WALLY_OK, ret) # Check that we can *demarshal* the signed PSBT (some bugs only appear here) self.assertEqual(WALLY_OK, wally_psbt_from_base64(reser, psbt)) @@ -91,13 +96,13 @@ def test_serialization(self): for priv in inval_signer['privkeys']: buf, buf_len = make_cbuffer('00'*32) self.assertEqual(WALLY_OK, wally_wif_to_bytes(priv.encode('utf-8'), 0xEF, 0, buf, buf_len)) - self.assertEqual(WALLY_EINVAL, wally_sign_psbt(psbt, buf, buf_len)) + self.assertEqual(WALLY_EINVAL, wally_psbt_sign(psbt, buf, buf_len, FLAG_GRIND_R)) for finalizer in finalizers: psbt = pointer(wally_psbt()) self.assertEqual(WALLY_OK, wally_psbt_from_base64(finalizer['finalize'].encode('utf-8'), psbt)) - self.assertEqual(WALLY_OK, wally_finalize_psbt(psbt)) - ret, reser = wally_psbt_to_base64(psbt) + self.assertEqual(WALLY_OK, wally_psbt_finalize(psbt)) + ret, reser = wally_psbt_to_base64(psbt, 0) self.assertEqual(WALLY_OK, ret) self.assertEqual(finalizer['result'], reser) @@ -105,7 +110,7 @@ def test_serialization(self): psbt = pointer(wally_psbt()) tx = pointer(wally_tx()) self.assertEqual(WALLY_OK, wally_psbt_from_base64(extractor['extract'].encode('utf-8'), psbt)) - self.assertEqual(WALLY_OK, wally_extract_psbt(psbt, tx)) + self.assertEqual(WALLY_OK, wally_psbt_extract(psbt, tx)) ret, reser = wally_tx_to_hex(tx, 1) self.assertEqual(WALLY_OK, ret) self.assertEqual(extractor['result'], reser) diff --git a/src/test/test_pset.py b/src/test/test_pset.py new file mode 100644 index 000000000..ed54d6569 --- /dev/null +++ b/src/test/test_pset.py @@ -0,0 +1,28 @@ +import json +import unittest +from util import * + +class PSETTests(unittest.TestCase): + + def test_serialization(self): + """Testing serialization and deserialization""" + + with open(root_dir + 'src/data/pset.json', 'r') as f: + d = json.load(f) + valids = d['valid'] + + for valid in valids: + psbt_out = pointer(wally_psbt()) + self.assertEqual(WALLY_OK, wally_psbt_from_base64(utf8(valid['pset']), psbt_out)) + ret, b64 = wally_psbt_to_base64(psbt_out, 0) + self.assertEqual(WALLY_OK, ret) + self.assertEqual(valid['pset'], b64) + ret, length = wally_psbt_get_length(psbt_out, 0) + self.assertEqual(WALLY_OK, ret) + self.assertEqual(length, valid['len']) + + +if __name__ == '__main__': + _, val = wally_is_elements_build() + if val != 0: + unittest.main() diff --git a/src/test/test_script.py b/src/test/test_script.py index ed3e73513..c9cc9849b 100755 --- a/src/test/test_script.py +++ b/src/test/test_script.py @@ -6,7 +6,7 @@ SCRIPT_TYPE_P2SH = 0x4 SCRIPT_TYPE_MULTISIG = 0x20 -WALLY_SCRIPT_MULTISIG_SORTED = 0x8 +SCRIPT_MULTISIG_SORTED = 0x8 SCRIPT_HASH160 = 0x1 SCRIPT_SHA256 = 0x2 @@ -24,10 +24,11 @@ SH, SH_LEN = make_cbuffer('11' * 20) # Fake script hash MPK_2, MPK_2_LEN = make_cbuffer('11' * 33 * 2) # Fake multiple (2) pubkeys MPK_3, MPK_3_LEN = make_cbuffer('11' * 33 * 3) # Fake multiple (3) pubkeys -MPK_3_SORTED, MPK_3_SORTED_LEN = make_cbuffer('01'*33 + '10'*33 + '11'*33) # Fake multiple (3) sorted pubkeys -MPK_3_SORTED_REVERSE, MPK_3_SORTED_LEN = make_cbuffer('11'*33 + '10'*33 + '01'*33) # Fake multiple (3) sorted pubkeys, in reverse order -MPK_3_SORTED_KEY_PUSH = '21'+'01'*33 + '21'+'10'*33 + '21'+'11'*33 -MPK_17, MPK_17_LEN = make_cbuffer('11' * 33 * 17) # Fake multiple (17) pubkeys +SPK, SPK_LEN = make_cbuffer('01'*33 + '10'*33 + '11'*33) # Fake multiple (3) sorted pubkeys +RPK, _ = make_cbuffer('11'*33 + '10'*33 + '01'*33) # Fake multiple (3) sorted pubkeys, in reverse order +SPK_KEY_PUSH = '21'+'01'*33 + '21'+'10'*33 + '21'+'11'*33 +MPK_15, MPK_15_LEN = make_cbuffer('11' * 33 * 15) # Fake multiple (15) pubkeys +MPK_16, MPK_16_LEN = make_cbuffer('11' * 33 * 16) # Fake multiple (16) pubkeys SIG, SIG_LEN = make_cbuffer('11' * 64) # Fake signature SIG_LARGE, SIG_LARGE_LEN = make_cbuffer('ff' * 64) # Fake out of range signature @@ -142,7 +143,7 @@ def test_scriptpubkey_multisig_from_bytes(self): (MPK_2, 0, 1, 0, out, out_len), # Empty bytes (MPK_2, MPK_2_LEN+1, 1, 0, out, out_len), # Unsupported bytes len (SH, SH_LEN, 1, 0, out, out_len), # Too few pubkeys - (MPK_17, MPK_17_LEN, 1, 0, out, out_len), # Too many pubkeys + (MPK_16, MPK_16_LEN, 1, 0, out, out_len), # Too many pubkeys (MPK_2, MPK_2_LEN, 0, 0, out, out_len), # Too low threshold (MPK_2, MPK_2_LEN, 17, 0, out, out_len), # Too high threshold (MPK_2, MPK_2_LEN, 3, 0, out, out_len), # Inconsistent threshold @@ -154,28 +155,34 @@ def test_scriptpubkey_multisig_from_bytes(self): self.assertEqual(ret, (WALLY_EINVAL, 0)) # Valid cases - out, out_len = make_cbuffer('00' * 33 * 4) + out, out_len = make_cbuffer('00' * 33 * 16) valid_args = [ - [(MPK_2, MPK_2_LEN, 1, 0, out, out_len), '51'+('21'+'11'*33)*2+'52ae'], # 1of2 - [(MPK_2, MPK_2_LEN, 2, 0, out, out_len), '52'+('21'+'11'*33)*2+'52ae'], # 2of2 - [(MPK_3, MPK_3_LEN, 1, 0, out, out_len), '51'+('21'+'11'*33)*3+'53ae'], # 1of3 - [(MPK_3, MPK_3_LEN, 2, 0, out, out_len), '52'+('21'+'11'*33)*3+'53ae'], # 2of3 - [(MPK_3, MPK_3_LEN, 3, 0, out, out_len), '53'+('21'+'11'*33)*3+'53ae'], # 3of3 - [(MPK_3_SORTED, MPK_3_SORTED_LEN, 1, 0, out, out_len), '51'+ MPK_3_SORTED_KEY_PUSH + '53ae'], # 1of3 sorted - [(MPK_3_SORTED, MPK_3_SORTED_LEN, 1, WALLY_SCRIPT_MULTISIG_SORTED, out, out_len), '51'+ MPK_3_SORTED_KEY_PUSH + '53ae'], # 1of3 sorted (WALLY_SCRIPT_MULTISIG_SORTED should have no effect) - [(MPK_3_SORTED_REVERSE, MPK_3_SORTED_LEN, 1, WALLY_SCRIPT_MULTISIG_SORTED, out, out_len), '51'+ MPK_3_SORTED_KEY_PUSH + '53ae'], # 1of3 sorted reverse (BIP67) + [(MPK_2, MPK_2_LEN, 1, 0, out, out_len), '51'+('21'+'11'*33)*2+'52ae'], # 1of2 + [(MPK_2, MPK_2_LEN, 2, 0, out, out_len), '52'+('21'+'11'*33)*2+'52ae'], # 2of2 + [(MPK_3, MPK_3_LEN, 1, 0, out, out_len), '51'+('21'+'11'*33)*3+'53ae'], # 1of3 + [(MPK_3, MPK_3_LEN, 2, 0, out, out_len), '52'+('21'+'11'*33)*3+'53ae'], # 2of3 + [(MPK_3, MPK_3_LEN, 3, 0, out, out_len), '53'+('21'+'11'*33)*3+'53ae'], # 3of3 + [(MPK_15, MPK_15_LEN, 1, 0, out, out_len), '51'+('21'+'11'*33)*15+'5fae'], # 1of15 + [(MPK_15, MPK_15_LEN, 15, 0, out, out_len), '5f'+('21'+'11'*33)*15+'5fae'], # 15of15 + # 1of3 sorted + [(SPK, SPK_LEN, 1, 0, out, out_len), '51'+ SPK_KEY_PUSH + '53ae'], + # 1of3 sorted (SCRIPT_MULTISIG_SORTED should have no effect) + [(SPK, SPK_LEN, 1, SCRIPT_MULTISIG_SORTED, out, out_len), '51'+ SPK_KEY_PUSH + '53ae'], + # 1of3 sorted reverse (BIP67) + [(RPK, SPK_LEN, 1, SCRIPT_MULTISIG_SORTED, out, out_len), '51'+ SPK_KEY_PUSH + '53ae'], ] for args, exp_script in valid_args: - script_len = 3 + (args[1] // 33 * (33 + 1)) + (pubkeys, pubkeys_len, threshold, flags, out, out_len) = args + script_len = 3 + (pubkeys_len // 33 * (33 + 1)) ret = wally_scriptpubkey_multisig_from_bytes(*args) self.assertEqual(ret, (WALLY_OK, script_len)) - self.assertEqual(args[4][:script_len], unhexlify(exp_script)) + self.assertEqual(out[:script_len], unhexlify(exp_script)) # Check the script is identified by scriptpubkey_get_type ret = wally_scriptpubkey_get_type(out, script_len) self.assertEqual(ret, (WALLY_OK, SCRIPT_TYPE_MULTISIG)) # Check a too-short output buffer short_out, short_out_len = make_cbuffer('00' * (script_len - 1)) - short_args = (args[0], args[1], args[2], args[3], short_out, short_out_len) + short_args = (pubkeys, pubkeys_len, threshold, flags, short_out, short_out_len) ret = wally_scriptpubkey_multisig_from_bytes(*short_args) self.assertEqual(ret, (WALLY_OK, script_len)) @@ -311,7 +318,7 @@ def c_sighash(s): (RS_1of2, RS_1of2_LEN, None, SIG_LEN, c_sighash([0x01]), 1, 0, out, out_len), # Null bytes (RS_1of2, RS_1of2_LEN, SIG, 0, c_sighash([0x01]), 1, 0, out, out_len), # Empty bytes or too few sigs (RS_1of2, RS_1of2_LEN, SIG, SIG_LEN+1, c_sighash([0x01]), 1, 0, out, out_len), # Unsupported bytes len - (RS_1of2, RS_1of2_LEN, SIG, 17, c_sighash([0x01]), 1, 0, out, out_len), # Too many sigs + (RS_1of2, RS_1of2_LEN, SIG, 16, c_sighash([0x01]), 1, 0, out, out_len), # Too many sigs (RS_1of2, RS_1of2_LEN, SIG, SIG_LEN, None, 1, 0, out, out_len), # Null sighash (RS_1of2, RS_1of2_LEN, SIG, SIG_LEN, c_sighash([0x01]), 2, 0, out, out_len), # Inconsistent sighash length (RS_1of2, RS_1of2_LEN, SIG, SIG_LEN, c_sighash([0x01]), 1, 1, out, out_len), # Unsupported flags diff --git a/src/test/test_sign.py b/src/test/test_sign.py index 6497be0c0..f01d20fd9 100755 --- a/src/test/test_sign.py +++ b/src/test/test_sign.py @@ -1,6 +1,5 @@ import unittest from util import * -from hashlib import sha256 FLAG_ECDSA, FLAG_SCHNORR, FLAG_GRIND_R, FLAG_RECOVERABLE = 1, 2, 4, 8 EX_PRIV_KEY_LEN, EC_PUBLIC_KEY_LEN, EC_PUBLIC_KEY_UNCOMPRESSED_LEN = 32, 33, 65 @@ -177,7 +176,9 @@ def test_format_message(self): for flags in (0, BITCOIN_MESSAGE_HASH_FLAG): expected = PREFIX + varint + msg if flags: - expected = sha256(sha256(expected).digest()).digest() + buf, buf_len = make_cbuffer('00'*32) + self.assertEqual(WALLY_OK, wally_sha256d(expected, len(expected), buf, buf_len)) + expected = buf ret, written = fn(flags, out_len) self.assertEqual((ret, written), (WALLY_OK, len(expected))) diff --git a/src/test/test_symmetric.py b/src/test/test_symmetric.py new file mode 100755 index 000000000..bddf2cc20 --- /dev/null +++ b/src/test/test_symmetric.py @@ -0,0 +1,67 @@ +import unittest +from util import * + +ENTROPY_LEN_128, ENTROPY_LEN_256, ENTROPY_LEN_512 = 16, 32, 64 +HMAC_SHA512_LEN = 64 + +class SymmetricTests(unittest.TestCase): + + def test_symmetric_key(self): + seed128, seed128_len = make_cbuffer('01' * ENTROPY_LEN_128) + seed256, seed256_len = make_cbuffer('01' * ENTROPY_LEN_256) + seed512, seed512_len = make_cbuffer('01' * ENTROPY_LEN_512) + label, label_len = make_cbuffer('0f0000') + key_out, key_out_len = make_cbuffer('00' * HMAC_SHA512_LEN) + + # wally_symmetric_key_from_seed + # Invalid args + cases = [ + (None, seed128_len, key_out, key_out_len), # Null bytes + (seed128, 0, key_out, key_out_len), # 0 Length bytes + (seed128, seed128_len-1, key_out, key_out_len), # Bad bytes length + (seed128, seed128_len, None, key_out_len), # Null dest + (seed128, seed128_len, key_out, 0), # 0 length dest + (seed128, seed128_len, key_out, key_out_len+1), # Bad dest length + ] + for bytes_in, bytes_len, out, out_len in cases: + ret = wally_symmetric_key_from_seed(bytes_in, bytes_len, out, out_len) + self.assertEqual(ret, WALLY_EINVAL) + + # Valid args + for bytes_in, bytes_len in [(seed128, seed128_len), + (seed256, seed256_len), + (seed512, seed512_len)]: + ret = wally_symmetric_key_from_seed(bytes_in, bytes_len, key_out, key_out_len) + self.assertEqual(ret, WALLY_OK) + + # wally_symmetric_key_from_parent + key_in, key_len = make_cbuffer('01' * HMAC_SHA512_LEN) + # Invalid args + cases = [ + (None, key_len, 0, label, label_len, key_out, key_out_len), # Null key + (key_in, 0, 0, label, label_len, key_out, key_out_len), # 0 Length key + (key_in, key_len-1, 1, label, label_len, key_out, key_out_len), # Bad key length + (key_in, key_len, 1, label, label_len, key_out, key_out_len), # Bad version + (key_in, key_len, 0, None, label_len, key_out, key_out_len), # Null label + (key_in, key_len, 0, label, 0, key_out, key_out_len), # Bad label length + (key_in, key_len, 0, label, label_len, None, key_out_len), # Null dest + (key_in, key_len, 0, label, label_len, key_out, 0), # 0 length dest + (key_in, key_len, 0, label, label_len, key_out, key_out_len+1), # Bad dest length + ] + for bytes_in, bytes_len, ver, l, l_len, out, out_len in cases: + ret = wally_symmetric_key_from_parent(bytes_in, bytes_len, ver, l, l_len, out, out_len) + self.assertEqual(ret, WALLY_EINVAL) + + # Valid args + ret = wally_symmetric_key_from_parent(key_in, key_len, 0, label, label_len, key_out, key_out_len) + self.assertEqual(ret, WALLY_OK) + + # Check labels around length LABEL_SIZE (64) + label, label_len = make_cbuffer('0f' * 65) + for l_len in (label_len-1, label_len, label_len+1): + ret = wally_symmetric_key_from_parent(key_in, key_len, 0, label, l_len, key_out, key_out_len) + self.assertEqual(ret, WALLY_OK) + + +if __name__ == '__main__': + unittest.main() diff --git a/src/test/test_transaction.py b/src/test/test_transaction.py index ef5b038da..a1b1542d4 100644 --- a/src/test/test_transaction.py +++ b/src/test/test_transaction.py @@ -14,43 +14,61 @@ class TransactionTests(unittest.TestCase): def tx_deserialize_hex(self, hex_): tx_p = pointer(wally_tx()) - self.assertEqual(WALLY_OK, wally_tx_from_hex(hex_, 0, tx_p)) + self.assertEqual(WALLY_OK, wally_tx_from_hex(hex_, 0x0, tx_p)) return tx_p[0] def tx_serialize_hex(self, tx): - ret, hex_ = wally_tx_to_hex(tx, 1) + ret, hex_ = wally_tx_to_hex(tx, 0x1) self.assertEqual(ret, WALLY_OK) return hex_ def test_serialization(self): """Testing serialization and deserialization""" + tx_out = pointer(wally_tx()) + tx_copy = pointer(wally_tx()) + + # Invalid arguments for args in [ - (utf8(''), 0, pointer(wally_tx())), # Empty hex - (utf8('00'*5), 0, pointer(wally_tx())), # Short hex + (None, 0, tx_out), # Null hex + (utf8(''), 0, tx_out), # Empty hex + (utf8('00'*5), 0, tx_out), # Short hex (TX_FAKE_HEX, 0, None), # Empty output - (TX_FAKE_HEX, 4, pointer(wally_tx())), # Unsupported flag - (TX_WITNESS_HEX[:11]+utf8('0')+TX_WITNESS_HEX[12:], 0, pointer(wally_tx())), # Invalid witness flag + (TX_FAKE_HEX, 8, tx_out), # Unsupported flag + (TX_WITNESS_HEX[:11]+utf8('0')+TX_WITNESS_HEX[12:], 0, tx_out), # Invalid witness flag ]: self.assertEqual(WALLY_EINVAL, wally_tx_from_hex(*args)) - # deserialization is allowed, but the opposite is not - for args in [ - (TX_FAKE_HEX[:9]+utf8('0')+TX_FAKE_HEX[92:], 0, pointer(wally_tx())), # No inputs - (TX_FAKE_HEX[:93]+utf8('0')+TX_FAKE_HEX[112:], 0, pointer(wally_tx())), # No outputs - (TX_FAKE_HEX, 2, pointer(wally_tx())), # Elements flag must not be set for serialization - ]: - self.assertEqual(WALLY_OK, wally_tx_from_hex(*args)) - self.assertEqual(WALLY_EINVAL, wally_tx_to_hex(args[2][0], 0)[0]) - - for args in [ - (TX_HEX, 0, pointer(wally_tx())), - (utf8('00')+TX_HEX[2:], 0, pointer(wally_tx())), - (utf8('ff')+TX_FAKE_HEX[2:], 0, pointer(wally_tx())), - (TX_FAKE_HEX, 0, pointer(wally_tx())), - (TX_WITNESS_HEX, 0, pointer(wally_tx())), + # No-input/no-output transactions + for tx_hex in [ + TX_FAKE_HEX[:9]+utf8('0')+TX_FAKE_HEX[92:], # No inputs + TX_FAKE_HEX[:93]+utf8('0')+TX_FAKE_HEX[112:], # No outputs ]: - self.assertEqual(WALLY_OK, wally_tx_from_hex(*args)) - self.assertEqual(args[0], utf8(self.tx_serialize_hex(args[2][0]))) + self.assertEqual(WALLY_OK, wally_tx_from_hex(tx_hex, 0, tx_out)) + # Partial transactions cannot be dumped by default + self.assertEqual(WALLY_EINVAL, wally_tx_to_hex(tx_out, 0)[0]) + # Check the partial transaction can be cloned + self.assertEqual(WALLY_OK, wally_tx_clone(tx_out, 0, tx_copy)) + if tx_out.contents.num_inputs != 0: + # Partial txs with inputs can be dumped with ALLOW_PARTIAL:0x4 + ret, hex_ = wally_tx_to_hex(tx_out, 0x1|0x4) + self.assertEqual(WALLY_OK, ret) + self.assertEqual(tx_hex, utf8(hex_)) + + # Valid transactions + for tx_hex in [ TX_HEX, + utf8('00')+TX_HEX[2:], + utf8('ff')+TX_FAKE_HEX[2:], + TX_FAKE_HEX, + TX_WITNESS_HEX ]: + self.assertEqual(WALLY_OK, wally_tx_from_hex(tx_hex, 0 ,tx_out)) + hex_ = utf8(self.tx_serialize_hex(tx_out)) + self.assertEqual(tx_hex, hex_) + # Check the transaction can be cloned and serializes to the same hex + self.assertEqual(WALLY_OK, wally_tx_clone(tx_out, 0, tx_copy)) + self.assertEqual(hex_, utf8(self.tx_serialize_hex(tx_copy))) + # Check that the txid can be computed + txid, txid_len = make_cbuffer('00' * 32) + self.assertEqual(WALLY_OK, wally_tx_get_txid(tx_out, txid, txid_len)) def test_lengths(self): """Testing functions measuring different lengths for a tx""" @@ -66,7 +84,7 @@ def test_lengths(self): vsize = (weight + 3) // 4 self.assertEqual((WALLY_OK, length), wally_tx_get_length(byref(tx), 0)) self.assertEqual((WALLY_OK, length_with_witness), wally_tx_get_length(byref(tx), 1)) - self.assertEqual((WALLY_EINVAL, 0), wally_tx_get_length(byref(tx), 2)) # Unsupported flag + self.assertEqual((WALLY_EINVAL, 0), wally_tx_get_length(byref(tx), 8)) # Unsupported flag self.assertEqual((WALLY_OK, weight), wally_tx_get_weight(byref(tx))) self.assertEqual((WALLY_OK, vsize), wally_tx_get_vsize(byref(tx))) self.assertEqual((WALLY_OK, vsize), wally_tx_vsize_from_weight(weight)) @@ -175,16 +193,16 @@ def test_get_signature_hash(self): (tx, 0, script, 0, 1, 1, 0, out, out_len), # Invalid script length (tx, 0, script, script_len, MAX_SATOSHI+1, 1, 1, out, out_len), # Invalid amount (only with segwit) (tx, 0, script, script_len, 1, 0x100, 0, out, out_len), # Invalid sighash - (tx, 0, script, script_len, 1, 1, 2, out, out_len), # Invalid flags + (tx, 0, script, script_len, 1, 1, 8, out, out_len), # Invalid flags (tx, 0, script, script_len, 1, 1, 0, None, out_len), # Empty bytes (tx, 0, script, script_len, 1, 1, 0, out, 31), # Short len ]: self.assertEqual(WALLY_EINVAL, wally_tx_get_btc_signature_hash(*args)) def sha256d(hex_): - input, input_len = make_cbuffer(hex_) + bin_input, bin_input_len = make_cbuffer(hex_) buf, buf_len = make_cbuffer('00'*32) - self.assertEqual(WALLY_OK, wally_sha256d(input, input_len, buf, buf_len)) + self.assertEqual(WALLY_OK, wally_sha256d(bin_input, bin_input_len, buf, buf_len)) return h(buf) script, script_len = make_cbuffer('00') diff --git a/src/test/test_wif.py b/src/test/test_wif.py index f28a5b646..5b0f3841d 100644 --- a/src/test/test_wif.py +++ b/src/test/test_wif.py @@ -1,4 +1,3 @@ -#!/usr/bin/env python import unittest from util import * diff --git a/src/test/util.py b/src/test/util.py index 0b197e77f..1bd541f97 100755 --- a/src/test/util.py +++ b/src/test/util.py @@ -27,7 +27,7 @@ _bzero_fn_t = CFUNCTYPE(c_void_p, c_ulong) _ec_nonce_fn_t = CFUNCTYPE(c_int, c_void_p, c_void_p, c_void_p, c_void_p, c_void_p, c_uint) -class operations(Structure): +class wally_operations(Structure): _fields_ = [('malloc_fn', _malloc_fn_t), ('free_fn', _free_fn_t), ('bzero_fn', _bzero_fn_t), @@ -53,6 +53,9 @@ class c_char_p_p_class(object): class c_ulong_p_class(object): pass c_ulong_p = c_ulong_p_class() +class c_uint64_p_class(object): + pass +c_uint64_p = c_uint64_p_class() # ctypes is missing this for some reason c_uint_p = POINTER(c_uint) @@ -87,7 +90,7 @@ class wally_tx_input(Structure): ('pegin_witness', POINTER(wally_tx_witness_stack))] class wally_tx_output(Structure): - _fields_ = [('satoshi', c_ulonglong), + _fields_ = [('satoshi', c_uint64), ('script', c_void_p), ('script_len', c_ulong), ('features', c_ubyte), @@ -112,38 +115,35 @@ class wally_tx(Structure): ('num_outputs', c_ulong), ('outputs_allocation_len', c_ulong),] -class key_origin_info(Structure): - _fields_ = [('fingerprint', c_ubyte * 4), - ('items', POINTER(c_ulong)), - ('path_len', c_ulong)] - -class keypath_item(Structure): - _fields_ = [('pubkey', c_ubyte * 65), - ('origin', key_origin_info)] +class wally_keypath_item(Structure): + _fields_ = [('path', POINTER(c_ulong)), + ('path_len', c_ulong), + ('fingerprint', c_ubyte * 4), + ('pubkey', c_ubyte * 65)] -class keypath_map(Structure): - _fields_ = [('items', POINTER(keypath_item)), +class wally_keypath_map(Structure): + _fields_ = [('items', POINTER(wally_keypath_item)), ('num_items', c_ulong), ('items_allocation_len', c_ulong)] -class partial_sigs_item(Structure): +class wally_partial_sigs_item(Structure): _fields_ = [('pubkey', c_ubyte * 65), ('sig', c_void_p), ('sig_len', c_ulong)] -class partial_sigs_map(Structure): - _fields_ = [('items', POINTER(partial_sigs_item)), +class wally_partial_sigs_map(Structure): + _fields_ = [('items', POINTER(wally_partial_sigs_item)), ('num_items', c_ulong), ('items_allocation_len', c_ulong)] -class unknowns_item(Structure): +class wally_unknowns_item(Structure): _fields_ = [('key', c_void_p), ('key_len', c_ulong), ('value', c_void_p), ('value_len', c_ulong)] -class unknowns_map(Structure): - _fields_ = [('items', POINTER(unknowns_item)), +class wally_unknowns_map(Structure): + _fields_ = [('items', POINTER(wally_unknowns_item)), ('num_items', c_ulong), ('items_allocation_len', c_ulong)] @@ -157,180 +157,300 @@ class wally_psbt_input(Structure): ('final_script_sig', c_void_p), ('final_script_sig_len', c_ulong), ('final_witness', POINTER(wally_tx_witness_stack)), - ('keypaths', POINTER(keypath_map)), - ('partial_sigs', POINTER(partial_sigs_map)), - ('unknowns', POINTER(unknowns_map)), - ('sighash_type', c_ulong)] + ('keypaths', POINTER(wally_keypath_map)), + ('partial_sigs', POINTER(wally_partial_sigs_map)), + ('unknowns', POINTER(wally_unknowns_map)), + ('sighash_type', c_ulong), + ('value', c_uint64), + ('has_value', c_ulong), + ('vbf', c_void_p), + ('vbf_len', c_ulong), + ('asset', c_void_p), + ('asset_len', c_ulong), + ('abf', c_void_p), + ('abf_len', c_ulong), + ('peg_in_tx', POINTER(wally_tx)), + ('txoutproof', c_void_p), + ('txoutproof_len', c_ulong), + ('genesis_blockhash', c_void_p), + ('genesis_blockhash_len', c_ulong), + ('claim_script', c_void_p), + ('claim_script_len', c_ulong)] class wally_psbt_output(Structure): _fields_ = [('redeem_script', c_void_p), ('redeem_script_len', c_ulong), ('witness_script', c_void_p), ('witness_script_len', c_ulong), - ('keypaths', POINTER(keypath_map)), - ('unknowns', POINTER(unknowns_map))] + ('keypaths', POINTER(wally_keypath_map)), + ('unknowns', POINTER(wally_unknowns_map)), + ('blinding_pubkey', c_ubyte * 65), + ('has_blinding_pubkey', c_ulong), + ('value_commitment', c_void_p), + ('value_commitment_len', c_ulong), + ('vbf', c_void_p), + ('vbf_len', c_ulong), + ('asset_commitment', c_void_p), + ('asset_commitment_len', c_ulong), + ('abf', c_void_p), + ('abf_len', c_ulong), + ('nonce', c_void_p), + ('nonce_len', c_ulong), + ('rangeproof', c_void_p), + ('rangeproof_len', c_ulong), + ('surjectionproof', c_void_p), + ('surjectionproof_len', c_ulong)] class wally_psbt(Structure): - _fields_ = [('tx', POINTER(wally_tx)), + _fields_ = [('magic', c_ubyte * 5), + ('tx', POINTER(wally_tx)), ('inputs', POINTER(wally_psbt_input)), ('num_inputs', c_ulong), ('inputs_allocation_len', c_ulong), ('outputs', POINTER(wally_psbt_output)), ('num_outputs', c_ulong), ('outputs_allocation_len', c_ulong), - ('unknowns', POINTER(unknowns_map))] + ('unknowns', POINTER(wally_unknowns_map)), + ('version', c_ulong)] for f in ( - ('wally_init', c_int, [c_uint]), - ('wally_cleanup', c_int, [c_uint]), - ('wally_is_elements_build', c_int, [c_ulong_p]), - ('wordlist_init', c_void_p, [c_char_p]), - ('wordlist_lookup_word', c_ulong, [c_void_p, c_char_p]), - ('wordlist_lookup_index', c_char_p, [c_void_p, c_ulong]), - ('wordlist_free', None, [c_void_p]), + # Internal functions ('mnemonic_from_bytes', c_char_p, [c_void_p, c_void_p, c_ulong]), ('mnemonic_to_bytes', c_int, [c_void_p, c_char_p, c_void_p, c_ulong, c_ulong_p]), - ('wally_base58_from_bytes', c_int, [c_void_p, c_ulong, c_uint, c_char_p_p]), - ('wally_base58_get_length', c_int, [c_char_p, c_ulong_p]), - ('wally_base58_to_bytes', c_int, [c_char_p, c_uint, c_void_p, c_ulong, c_ulong_p]), + ('wordlist_free', None, [c_void_p]), + ('wordlist_init', c_void_p, [c_char_p]), + ('wordlist_lookup_index', c_char_p, [c_void_p, c_ulong]), + ('wordlist_lookup_word', c_ulong, [c_void_p, c_char_p]), + # Exported functions ('bip32_key_free', c_int, [POINTER(ext_key)]), + ('bip32_key_from_base58_alloc', c_int, [c_char_p, POINTER(POINTER(ext_key))]), + ('bip32_key_from_base58', c_int, [c_char_p, POINTER(ext_key)]), + ('bip32_key_from_parent_alloc', c_int, [POINTER(ext_key), c_uint, c_uint, POINTER(POINTER(ext_key))]), + ('bip32_key_from_parent', c_int, [POINTER(ext_key), c_uint, c_uint, POINTER(ext_key)]), + ('bip32_key_from_parent_path_alloc', c_int, [POINTER(ext_key), c_uint_p, c_ulong, c_uint, POINTER(POINTER(ext_key))]), + ('bip32_key_from_parent_path', c_int, [POINTER(ext_key), c_uint_p, c_ulong, c_uint, POINTER(ext_key)]), + ('bip32_key_from_seed_alloc', c_int, [c_void_p, c_ulong, c_uint, c_uint, POINTER(POINTER(ext_key))]), ('bip32_key_from_seed', c_int, [c_void_p, c_ulong, c_uint, c_uint, POINTER(ext_key)]), + ('bip32_key_get_fingerprint', c_int, [POINTER(ext_key), c_void_p, c_ulong]), + ('bip32_key_init_alloc', c_int, [c_uint, c_uint, c_uint, c_void_p, c_ulong, c_void_p, c_ulong, c_void_p, c_ulong, c_void_p, c_ulong, c_void_p, c_ulong, POINTER(POINTER(ext_key))]), ('bip32_key_serialize', c_int, [POINTER(ext_key), c_uint, c_void_p, c_ulong]), - ('bip32_key_unserialize', c_int, [c_void_p, c_uint, POINTER(ext_key)]), - ('bip32_key_from_parent', c_int, [c_void_p, c_uint, c_uint, POINTER(ext_key)]), - ('bip32_key_from_parent_path', c_int, [c_void_p, c_uint_p, c_ulong, c_uint, POINTER(ext_key)]), - ('bip32_key_with_tweak_from_parent_path', c_int, [POINTER(ext_key), c_uint_p, c_ulong, c_uint, POINTER(ext_key)]), - ('bip32_key_to_base58', c_int, [POINTER(ext_key), c_uint, c_char_p_p]), - ('bip32_key_from_base58', c_int, [c_char_p, POINTER(ext_key)]), - ('bip32_key_from_base58_alloc', c_int, [c_char_p, POINTER(POINTER(ext_key))]), ('bip32_key_strip_private_key', c_int, [POINTER(ext_key)]), - ('bip32_key_get_fingerprint', c_int, [POINTER(ext_key), c_void_p, c_ulong]), - ('bip38_raw_from_private_key', c_int, [c_void_p, c_ulong, c_void_p, c_ulong, c_uint, c_void_p, c_ulong]), + ('bip32_key_to_base58', c_int, [POINTER(ext_key), c_uint, c_char_p_p]), + ('bip32_key_unserialize_alloc', c_int, [c_void_p, c_ulong, POINTER(POINTER(ext_key))]), + ('bip32_key_unserialize', c_int, [c_void_p, c_ulong, POINTER(ext_key)]), + ('bip32_key_with_tweak_from_parent_path_alloc', c_int, [POINTER(ext_key), c_uint_p, c_ulong, c_uint, POINTER(POINTER(ext_key))]), + ('bip32_key_with_tweak_from_parent_path', c_int, [POINTER(ext_key), c_uint_p, c_ulong, c_uint, POINTER(ext_key)]), ('bip38_from_private_key', c_int, [c_void_p, c_ulong, c_void_p, c_ulong, c_uint, c_char_p_p]), - ('bip38_to_private_key', c_int, [c_char_p, c_void_p, c_ulong, c_uint, c_void_p, c_ulong]), - ('bip38_raw_to_private_key', c_int, [c_void_p, c_ulong, c_void_p, c_ulong, c_uint, c_void_p, c_ulong]), - ('bip38_raw_get_flags', c_int, [c_void_p, c_ulong, c_ulong_p]), ('bip38_get_flags', c_int, [c_char_p, c_ulong_p]), + ('bip38_raw_from_private_key', c_int, [c_void_p, c_ulong, c_void_p, c_ulong, c_uint, c_void_p, c_ulong]), + ('bip38_raw_get_flags', c_int, [c_void_p, c_ulong, c_ulong_p]), + ('bip38_raw_to_private_key', c_int, [c_void_p, c_ulong, c_void_p, c_ulong, c_uint, c_void_p, c_ulong]), + ('bip38_to_private_key', c_int, [c_char_p, c_void_p, c_ulong, c_uint, c_void_p, c_ulong]), ('bip39_get_languages', c_int, [c_char_p_p]), - ('bip39_get_wordlist', c_int, [c_char_p, POINTER(c_void_p)]), ('bip39_get_word', c_int, [c_void_p, c_ulong, c_char_p_p]), + ('bip39_get_wordlist', c_int, [c_char_p, POINTER(c_void_p)]), ('bip39_mnemonic_from_bytes', c_int, [c_void_p, c_void_p, c_ulong, c_char_p_p]), ('bip39_mnemonic_to_bytes', c_int, [c_void_p, c_char_p, c_void_p, c_ulong, c_ulong_p]), - ('bip39_mnemonic_validate', c_int, [c_void_p, c_char_p]), ('bip39_mnemonic_to_seed', c_int, [c_char_p, c_char_p, c_void_p, c_ulong, c_ulong_p]), - ('wally_addr_segwit_from_bytes', c_int, [c_void_p, c_ulong, c_char_p, c_uint, c_char_p_p]), - ('wally_addr_segwit_to_bytes', c_int, [c_void_p, c_char_p, c_uint, c_void_p, c_ulong, c_ulong_p]), + ('bip39_mnemonic_validate', c_int, [c_void_p, c_char_p]), ('wally_address_to_scriptpubkey', c_int, [c_char_p, c_uint, c_void_p, c_ulong, c_ulong_p]), - ('wally_scriptpubkey_to_address', c_int, [c_void_p, c_ulong, c_uint, c_char_p_p]), + ('wally_addr_segwit_from_bytes', c_int, [c_void_p, c_ulong, c_char_p, c_uint, c_char_p_p]), + ('wally_addr_segwit_to_bytes', c_int, [c_char_p, c_char_p, c_uint, c_void_p, c_ulong, c_ulong_p]), + ('wally_aes_cbc', c_int, [c_void_p, c_ulong, c_void_p, c_ulong, c_void_p, c_ulong, c_uint, c_void_p, c_ulong, c_ulong_p]), + ('wally_aes', c_int, [c_void_p, c_ulong, c_void_p, c_ulong, c_uint, c_void_p, c_ulong]), + ('wally_asset_blinding_key_from_seed', c_int, [c_void_p, c_ulong, c_void_p, c_ulong]), + ('wally_asset_blinding_key_to_ec_private_key', c_int, [c_void_p, c_ulong, c_void_p, c_ulong, c_void_p, c_ulong]), + ('wally_asset_final_vbf', c_int, [POINTER(c_uint64), c_ulong, c_ulong, c_void_p, c_ulong, c_void_p, c_ulong, c_void_p, c_ulong]), + ('wally_asset_generator_from_bytes', c_int, [c_void_p, c_ulong, c_void_p, c_ulong, c_void_p, c_ulong]), + ('wally_asset_pak_whitelistproof', c_int, [c_void_p, c_ulong, c_void_p, c_ulong, c_ulong, c_void_p, c_ulong, c_void_p, c_ulong, c_void_p, c_ulong, c_void_p, c_ulong, c_ulong_p]), + ('wally_asset_pak_whitelistproof_size', c_int, [c_ulong, c_ulong_p]), + ('wally_asset_rangeproof', c_int, [c_uint64, c_void_p, c_ulong, c_void_p, c_ulong, c_void_p, c_ulong, c_void_p, c_ulong, c_void_p, c_ulong, c_void_p, c_ulong, c_void_p, c_ulong, c_void_p, c_ulong, c_uint64, c_int, c_int, c_void_p, c_ulong, c_ulong_p]), + ('wally_asset_surjectionproof', c_int, [c_void_p, c_ulong, c_void_p, c_ulong, c_void_p, c_ulong, c_void_p, c_ulong, c_void_p, c_ulong, c_void_p, c_ulong, c_void_p, c_ulong, c_void_p, c_ulong, c_ulong_p]), + ('wally_asset_surjectionproof_size', c_int, [c_ulong, c_ulong_p]), + ('wally_asset_unblind', c_int, [c_void_p, c_ulong, c_void_p, c_ulong, c_void_p, c_ulong, c_void_p, c_ulong, c_void_p, c_ulong, c_void_p, c_ulong, c_void_p, c_ulong, c_void_p, c_ulong, c_void_p, c_ulong, c_uint64_p]), + ('wally_asset_unblind_with_nonce', c_int, [c_void_p, c_ulong, c_void_p, c_ulong, c_void_p, c_ulong, c_void_p, c_ulong, c_void_p, c_ulong, c_void_p, c_ulong, c_void_p, c_ulong, c_void_p, c_ulong, c_uint64_p]), + ('wally_asset_value_commitment', c_int, [c_uint64, c_void_p, c_ulong, c_void_p, c_ulong, c_void_p, c_ulong]), + ('wally_base58_from_bytes', c_int, [c_void_p, c_ulong, c_uint, c_char_p_p]), + ('wally_base58_get_length', c_int, [c_char_p, c_ulong_p]), + ('wally_base58_to_bytes', c_int, [c_char_p, c_uint, c_void_p, c_ulong, c_ulong_p]), ('wally_bip32_key_to_address', c_int, [POINTER(ext_key), c_uint, c_uint, c_char_p_p]), ('wally_bip32_key_to_addr_segwit', c_int, [POINTER(ext_key), c_char_p, c_uint, c_char_p_p]), + ('wally_bzero', c_int, [c_void_p, c_ulong]), + ('wally_cleanup', c_int, [c_uint]), ('wally_confidential_addr_from_addr', c_int, [c_char_p, c_uint, c_void_p, c_ulong, c_char_p_p]), + ('wally_confidential_addr_from_addr_segwit', c_int, [c_char_p, c_char_p, c_char_p, c_void_p, c_ulong, c_char_p_p]), + ('wally_confidential_addr_segwit_to_ec_public_key', c_int, [c_char_p, c_char_p, c_void_p, c_ulong]), ('wally_confidential_addr_to_addr', c_int, [c_char_p, c_uint, c_char_p_p]), + ('wally_confidential_addr_to_addr_segwit', c_int, [c_char_p, c_char_p, c_char_p, c_char_p_p]), ('wally_confidential_addr_to_ec_public_key', c_int, [c_char_p, c_uint, c_void_p, c_ulong]), - ('wally_asset_blinding_key_from_seed', c_int, [c_void_p, c_ulong, c_void_p, c_ulong]), - ('wally_asset_blinding_key_to_ec_private_key', c_int, [c_void_p, c_ulong, c_void_p, c_ulong, c_void_p, c_ulong]), - ('wally_asset_unblind', c_int, [c_char_p, c_ulong, c_char_p, c_ulong, c_char_p, c_ulong, c_char_p, c_ulong, c_char_p, c_ulong, c_char_p, c_ulong, c_void_p, c_ulong, c_void_p, c_ulong, c_void_p, c_ulong, c_ulong_p]), - ('wally_asset_unblind_with_nonce', c_int, [c_char_p, c_ulong, c_char_p, c_ulong, c_char_p, c_ulong, c_char_p, c_ulong, c_char_p, c_ulong, c_void_p, c_ulong, c_void_p, c_ulong, c_void_p, c_ulong, c_ulong_p]), - ('wally_asset_pak_whitelistproof', c_int, [c_void_p, c_ulong, c_void_p, c_ulong, c_ulong, c_void_p, c_ulong, c_void_p, c_ulong, c_void_p, c_ulong, c_void_p, c_ulong, c_ulong_p]), - ('wally_sha256', c_int, [c_void_p, c_ulong, c_void_p, c_ulong]), - ('wally_sha256d', c_int, [c_void_p, c_ulong, c_void_p, c_ulong]), - ('wally_sha512', c_int, [c_void_p, c_ulong, c_void_p, c_ulong]), - ('wally_hash160', c_int, [c_void_p, c_ulong, c_void_p, c_ulong]), - ('wally_hex_from_bytes', c_int, [c_void_p, c_ulong, c_char_p_p]), - ('wally_hex_to_bytes', c_int, [c_char_p, c_void_p, c_ulong, c_ulong_p]), - ('wally_hmac_sha256', c_int, [c_void_p, c_ulong, c_void_p, c_ulong, c_void_p]), - ('wally_hmac_sha512', c_int, [c_void_p, c_ulong, c_void_p, c_ulong, c_void_p]), - ('wally_aes', c_int, [c_void_p, c_ulong, c_void_p, c_ulong, c_uint, c_void_p, c_ulong]), - ('wally_aes_cbc', c_int, [c_void_p, c_ulong, c_void_p, c_ulong, c_void_p, c_ulong, c_uint, c_void_p, c_ulong, c_ulong_p]), - ('wally_pbkdf2_hmac_sha256', c_int, [c_void_p, c_ulong, c_void_p, c_ulong, c_uint, c_ulong, c_void_p, c_ulong]), - ('wally_pbkdf2_hmac_sha512', c_int, [c_void_p, c_ulong, c_void_p, c_ulong, c_uint, c_ulong, c_void_p, c_ulong]), - ('wally_scrypt', c_int, [c_void_p, c_ulong, c_void_p, c_ulong, c_uint, c_uint, c_uint, c_void_p, c_ulong]), - ('wally_secp_randomize', c_int, [c_void_p, c_ulong]), + ('wally_ecdh', c_int, [c_void_p, c_ulong, c_void_p, c_ulong, c_void_p, c_ulong]), ('wally_ec_private_key_verify', c_int, [c_void_p, c_ulong]), - ('wally_ec_public_key_verify', c_int, [c_void_p, c_ulong]), ('wally_ec_public_key_decompress', c_int, [c_void_p, c_ulong, c_void_p, c_ulong]), - ('wally_ec_public_key_negate', c_int, [c_void_p, c_ulong, c_void_p, c_ulong]), ('wally_ec_public_key_from_private_key', c_int, [c_void_p, c_ulong, c_void_p, c_ulong]), + ('wally_ec_public_key_negate', c_int, [c_void_p, c_ulong, c_void_p, c_ulong]), + ('wally_ec_public_key_verify', c_int, [c_void_p, c_ulong]), ('wally_ec_sig_from_bytes', c_int, [c_void_p, c_ulong, c_void_p, c_ulong, c_uint, c_void_p, c_ulong]), ('wally_ec_sig_from_der', c_int, [c_void_p, c_ulong, c_void_p, c_ulong]), ('wally_ec_sig_normalize', c_int, [c_void_p, c_ulong, c_void_p, c_ulong]), ('wally_ec_sig_to_der', c_int, [c_void_p, c_ulong, c_void_p, c_ulong, c_ulong_p]), - ('wally_ec_sig_to_public_key', c_int, [c_void_p, c_ulong, c_void_p, c_ulong, c_void_p]), + ('wally_ec_sig_to_public_key', c_int, [c_void_p, c_ulong, c_void_p, c_ulong, c_void_p, c_ulong]), ('wally_ec_sig_verify', c_int, [c_void_p, c_ulong, c_void_p, c_ulong, c_uint, c_void_p, c_ulong]), - ('wally_ecdh', c_int, [c_void_p, c_ulong, c_void_p, c_ulong, c_void_p]), - ('wally_get_operations', c_int, [POINTER(operations)]), - ('wally_set_operations', c_int, [POINTER(operations)]), + ('wally_elements_pegin_contract_script_from_bytes', c_int, [c_void_p, c_ulong, c_void_p, c_ulong, c_uint, c_void_p, c_ulong, c_ulong_p]), + ('wally_elements_pegout_script_from_bytes', c_int, [c_void_p, c_ulong, c_void_p, c_ulong, c_void_p, c_ulong, c_void_p, c_ulong, c_uint, c_void_p, c_ulong, c_ulong_p]), + ('wally_elements_pegout_script_size', c_int, [c_ulong, c_ulong, c_ulong, c_ulong, c_ulong_p]), ('wally_format_bitcoin_message', c_int, [c_void_p, c_ulong, c_uint, c_void_p, c_ulong, c_ulong_p]), + ('wally_free_string', c_int, [c_char_p]), + ('wally_get_operations', c_int, [POINTER(wally_operations)]), + ('wally_hash160', c_int, [c_void_p, c_ulong, c_void_p, c_ulong]), + ('wally_hex_from_bytes', c_int, [c_void_p, c_ulong, c_char_p_p]), + ('wally_hex_to_bytes', c_int, [c_char_p, c_void_p, c_ulong, c_ulong_p]), + ('wally_hmac_sha256', c_int, [c_void_p, c_ulong, c_void_p, c_ulong, c_void_p, c_ulong]), + ('wally_hmac_sha512', c_int, [c_void_p, c_ulong, c_void_p, c_ulong, c_void_p, c_ulong]), + ('wally_init', c_int, [c_uint]), + ('wally_is_elements_build', c_int, [c_ulong_p]), + ('wally_keypath_map_add', c_int, [POINTER(wally_keypath_map), c_void_p, c_ulong, c_void_p, c_ulong, c_uint_p, c_ulong]), + ('wally_keypath_map_find', c_int, [POINTER(wally_keypath_map), c_void_p, c_ulong, c_ulong_p]), + ('wally_keypath_map_free', c_int, [POINTER(wally_keypath_map)]), + ('wally_keypath_map_init_alloc', c_int, [c_ulong, POINTER(POINTER(wally_keypath_map))]), + ('wally_partial_sigs_map_add', c_int, [POINTER(wally_partial_sigs_map), c_void_p, c_ulong, c_void_p, c_ulong]), + ('wally_partial_sigs_map_find', c_int, [POINTER(wally_partial_sigs_map), c_void_p, c_ulong, c_ulong_p]), + ('wally_partial_sigs_map_free', c_int, [POINTER(wally_partial_sigs_map)]), + ('wally_partial_sigs_map_init_alloc', c_int, [c_ulong, POINTER(POINTER(wally_partial_sigs_map))]), + ('wally_pbkdf2_hmac_sha256', c_int, [c_void_p, c_ulong, c_void_p, c_ulong, c_uint, c_uint, c_void_p, c_ulong]), + ('wally_pbkdf2_hmac_sha512', c_int, [c_void_p, c_ulong, c_void_p, c_ulong, c_uint, c_uint, c_void_p, c_ulong]), + ('wally_psbt_combine', c_int, [POINTER(wally_psbt), POINTER(wally_psbt)]), + ('wally_psbt_elements_init_alloc', c_int, [c_uint, c_ulong, c_ulong, c_ulong, POINTER(POINTER(wally_psbt))]), + ('wally_psbt_input_clear_value', c_int, [POINTER(wally_psbt_input)]), + ('wally_psbt_input_set_abf', c_int, [POINTER(wally_psbt_input), c_void_p, c_ulong]), + ('wally_psbt_input_set_asset', c_int, [POINTER(wally_psbt_input), c_void_p, c_ulong]), + ('wally_psbt_input_set_claim_script', c_int, [POINTER(wally_psbt_input), c_void_p, c_ulong]), + ('wally_psbt_input_set_genesis_blockhash', c_int, [POINTER(wally_psbt_input), c_void_p, c_ulong]), + ('wally_psbt_input_set_peg_in_tx', c_int, [POINTER(wally_psbt_input), POINTER(wally_tx)]), + ('wally_psbt_input_set_txoutproof', c_int, [POINTER(wally_psbt_input), c_void_p, c_ulong]), + ('wally_psbt_input_set_vbf', c_int, [POINTER(wally_psbt_input), c_void_p, c_ulong]), + ('wally_psbt_input_set_value', c_int, [POINTER(wally_psbt_input), c_uint64]), + ('wally_psbt_output_set_abf', c_int, [POINTER(wally_psbt_output), c_void_p, c_ulong]), + ('wally_psbt_output_set_asset_commitment', c_int, [POINTER(wally_psbt_output), c_void_p, c_ulong]), + ('wally_psbt_output_set_blinding_pubkey', c_int, [POINTER(wally_psbt_output), c_void_p, c_ulong]), + ('wally_psbt_output_set_nonce', c_int, [POINTER(wally_psbt_output), c_void_p, c_ulong]), + ('wally_psbt_output_set_rangeproof', c_int, [POINTER(wally_psbt_output), c_void_p, c_ulong]), + ('wally_psbt_output_set_surjectionproof', c_int, [POINTER(wally_psbt_output), c_void_p, c_ulong]), + ('wally_psbt_output_set_vbf', c_int, [POINTER(wally_psbt_output), c_void_p, c_ulong]), + ('wally_psbt_output_set_value_commitment', c_int, [POINTER(wally_psbt_output), c_void_p, c_ulong]), + ('wally_psbt_extract', c_int, [POINTER(wally_psbt), POINTER(POINTER(wally_tx))]), + ('wally_psbt_finalize', c_int, [POINTER(wally_psbt)]), + ('wally_psbt_free', c_int, [POINTER(wally_psbt)]), + ('wally_psbt_from_base64', c_int, [c_char_p, POINTER(POINTER(wally_psbt))]), + ('wally_psbt_from_bytes', c_int, [c_void_p, c_ulong, POINTER(POINTER(wally_psbt))]), + ('wally_psbt_get_length', c_int, [POINTER(wally_psbt), c_uint, c_ulong_p]), + ('wally_psbt_init_alloc', c_int, [c_uint, c_ulong, c_ulong, c_ulong, POINTER(POINTER(wally_psbt))]), + ('wally_psbt_input_set_final_script_sig', c_int, [POINTER(wally_psbt_input), c_void_p, c_ulong]), + ('wally_psbt_input_set_final_witness', c_int, [POINTER(wally_psbt_input), POINTER(wally_tx_witness_stack)]), + ('wally_psbt_input_set_keypaths', c_int, [POINTER(wally_psbt_input), POINTER(wally_keypath_map)]), + ('wally_psbt_input_set_non_witness_utxo', c_int, [POINTER(wally_psbt_input), POINTER(wally_tx)]), + ('wally_psbt_input_set_partial_sigs', c_int, [POINTER(wally_psbt_input), POINTER(wally_partial_sigs_map)]), + ('wally_psbt_input_set_redeem_script', c_int, [POINTER(wally_psbt_input), c_void_p, c_ulong]), + ('wally_psbt_input_set_sighash_type', c_int, [POINTER(wally_psbt_input), c_uint]), + ('wally_psbt_input_set_unknowns', c_int, [POINTER(wally_psbt_input), POINTER(wally_unknowns_map)]), + ('wally_psbt_input_set_witness_script', c_int, [POINTER(wally_psbt_input), c_void_p, c_ulong]), + ('wally_psbt_input_set_witness_utxo', c_int, [POINTER(wally_psbt_input), POINTER(wally_tx_output)]), + ('wally_psbt_is_elements', c_int, [POINTER(wally_psbt), c_ulong_p]), + ('wally_psbt_output_set_keypaths', c_int, [POINTER(wally_psbt_output), POINTER(wally_keypath_map)]), + ('wally_psbt_output_set_redeem_script', c_int, [POINTER(wally_psbt_output), c_void_p, c_ulong]), + ('wally_psbt_output_set_unknowns', c_int, [POINTER(wally_psbt_output), POINTER(wally_unknowns_map)]), + ('wally_psbt_output_set_witness_script', c_int, [POINTER(wally_psbt_output), c_void_p, c_ulong]), + ('wally_psbt_set_global_tx', c_int, [POINTER(wally_psbt), POINTER(wally_tx)]), + ('wally_psbt_sign', c_int, [POINTER(wally_psbt), c_void_p, c_ulong, c_uint]), + ('wally_psbt_to_base64', c_int, [POINTER(wally_psbt), c_uint, c_char_p_p]), + ('wally_psbt_to_bytes', c_int, [POINTER(wally_psbt), c_uint, c_void_p, c_ulong, c_ulong_p]), + ('wally_scriptpubkey_csv_2of2_then_1_from_bytes', c_int, [c_void_p, c_ulong, c_uint, c_uint, c_void_p, c_ulong, c_ulong_p]), + ('wally_scriptpubkey_csv_2of3_then_2_from_bytes', c_int, [c_void_p, c_ulong, c_uint, c_uint, c_void_p, c_ulong, c_ulong_p]), ('wally_scriptpubkey_get_type', c_int, [c_void_p, c_ulong, c_ulong_p]), - ('wally_script_push_from_bytes', c_int, [c_void_p, c_ulong, c_uint, c_void_p, c_ulong, c_ulong_p]), + ('wally_scriptpubkey_multisig_from_bytes', c_int, [c_void_p, c_ulong, c_uint, c_uint, c_void_p, c_ulong, c_ulong_p]), ('wally_scriptpubkey_op_return_from_bytes', c_int, [c_void_p, c_ulong, c_uint, c_void_p, c_ulong, c_ulong_p]), ('wally_scriptpubkey_p2pkh_from_bytes', c_int, [c_void_p, c_ulong, c_uint, c_void_p, c_ulong, c_ulong_p]), ('wally_scriptpubkey_p2sh_from_bytes', c_int, [c_void_p, c_ulong, c_uint, c_void_p, c_ulong, c_ulong_p]), - ('wally_scriptpubkey_multisig_from_bytes', c_int, [c_void_p, c_ulong, c_uint, c_uint, c_void_p, c_ulong, c_ulong_p]), - ('wally_scriptpubkey_csv_2of2_then_1_from_bytes', c_int, [c_void_p, c_ulong, c_uint, c_uint, c_void_p, c_ulong, c_ulong_p]), - ('wally_scriptpubkey_csv_2of3_then_2_from_bytes', c_int, [c_void_p, c_ulong, c_uint, c_uint, c_void_p, c_ulong, c_ulong_p]), + ('wally_scriptpubkey_to_address', c_int, [c_void_p, c_ulong, c_uint, c_char_p_p]), + ('wally_script_push_from_bytes', c_int, [c_void_p, c_ulong, c_uint, c_void_p, c_ulong, c_ulong_p]), + ('wally_scriptsig_multisig_from_bytes', c_int, [c_void_p, c_ulong, c_void_p, c_ulong, c_uint_p, c_ulong, c_uint, c_void_p, c_ulong, c_ulong_p]), ('wally_scriptsig_p2pkh_from_der', c_int, [c_void_p, c_ulong, c_void_p, c_ulong, c_void_p, c_ulong, c_ulong_p]), ('wally_scriptsig_p2pkh_from_sig', c_int, [c_void_p, c_ulong, c_void_p, c_ulong, c_uint, c_void_p, c_ulong, c_ulong_p]), - ('wally_scriptsig_multisig_from_bytes', c_int, [c_void_p, c_ulong, c_void_p, c_ulong, c_uint_p, c_ulong, c_uint, c_void_p, c_ulong, c_ulong_p]), - ('wally_elements_pegout_script_from_bytes', c_int, [c_void_p, c_ulong, c_void_p, c_ulong, c_void_p, c_ulong, c_void_p, c_ulong, c_uint, c_void_p, c_ulong, c_ulong_p]), - ('wally_elements_pegin_contract_script_from_bytes', c_int, [c_void_p, c_ulong, c_void_p, c_ulong, c_uint, c_void_p, c_ulong, c_ulong_p]), - ('wally_witness_program_from_bytes', c_int, [c_void_p, c_ulong, c_uint, c_void_p, c_ulong, c_ulong_p]), - ('wally_tx_to_hex', c_int, [POINTER(wally_tx), c_uint, c_char_p_p]), - ('wally_tx_from_hex', c_int, [c_char_p, c_uint, POINTER(POINTER(wally_tx))]), - ('wally_tx_to_bytes', c_int, [POINTER(wally_tx), c_uint, c_void_p, c_ulong, c_ulong_p]), - ('wally_tx_from_bytes', c_int, [c_void_p, c_ulong, c_uint, POINTER(POINTER(wally_tx))]), - ('wally_tx_init_alloc', c_int, [c_uint, c_uint, c_ulong, c_ulong, POINTER(POINTER(wally_tx))]), + ('wally_scrypt', c_int, [c_void_p, c_ulong, c_void_p, c_ulong, c_uint, c_uint, c_uint, c_void_p, c_ulong]), + ('wally_secp_randomize', c_int, [c_void_p, c_ulong]), + ('wally_set_operations', c_int, [POINTER(wally_operations)]), + ('wally_sha256', c_int, [c_void_p, c_ulong, c_void_p, c_ulong]), + ('wally_sha256d', c_int, [c_void_p, c_ulong, c_void_p, c_ulong]), + ('wally_sha256_midstate', c_int, [c_void_p, c_ulong, c_void_p, c_ulong]), + ('wally_sha512', c_int, [c_void_p, c_ulong, c_void_p, c_ulong]), + ('wally_symmetric_key_from_parent', c_int, [c_void_p, c_ulong, c_uint, c_void_p, c_ulong, c_void_p, c_ulong]), + ('wally_symmetric_key_from_seed', c_int, [c_void_p, c_ulong, c_void_p, c_ulong]), + ('wally_tx_add_elements_raw_input', c_int, [POINTER(wally_tx), c_void_p, c_ulong, c_uint, c_uint, c_void_p, c_ulong, POINTER(wally_tx_witness_stack), c_void_p, c_ulong, c_void_p, c_ulong, c_void_p, c_ulong, c_void_p, c_ulong, c_void_p, c_ulong, c_void_p, c_ulong, POINTER(wally_tx_witness_stack), c_uint]), + ('wally_tx_add_elements_raw_output', c_int, [POINTER(wally_tx), c_void_p, c_ulong, c_void_p, c_ulong, c_void_p, c_ulong, c_void_p, c_ulong, c_void_p, c_ulong, c_void_p, c_ulong, c_uint]), + ('wally_tx_add_input', c_int, [POINTER(wally_tx), POINTER(wally_tx_input)]), + ('wally_tx_add_output', c_int, [POINTER(wally_tx), POINTER(wally_tx_output)]), + ('wally_tx_add_raw_input', c_int, [POINTER(wally_tx), c_void_p, c_ulong, c_uint, c_uint, c_void_p, c_ulong, POINTER(wally_tx_witness_stack), c_uint]), + ('wally_tx_add_raw_output', c_int, [POINTER(wally_tx), c_uint64, c_void_p, c_ulong, c_uint]), + ('wally_tx_clone', c_int, [POINTER(wally_tx), c_uint, POINTER(POINTER(wally_tx))]), + ('wally_tx_confidential_value_from_satoshi', c_int, [c_uint64, c_void_p, c_ulong]), + ('wally_tx_confidential_value_to_satoshi', c_int, [c_void_p, c_ulong, c_uint64_p]), + ('wally_tx_elements_input_init_alloc', c_int, [c_void_p, c_ulong, c_uint, c_uint, c_void_p, c_ulong, POINTER(wally_tx_witness_stack), c_void_p, c_ulong, c_void_p, c_ulong, c_void_p, c_ulong, c_void_p, c_ulong, c_void_p, c_ulong, c_void_p, c_ulong, POINTER(wally_tx_witness_stack), POINTER(POINTER(wally_tx_input))]), + ('wally_tx_elements_input_is_pegin', c_int, [POINTER(wally_tx_input), c_ulong_p]), + ('wally_tx_elements_input_issuance_free', c_int, [POINTER(wally_tx_input)]), + ('wally_tx_elements_input_issuance_set', c_int, [POINTER(wally_tx_input), c_void_p, c_ulong, c_void_p, c_ulong, c_void_p, c_ulong, c_void_p, c_ulong, c_void_p, c_ulong, c_void_p, c_ulong]), + ('wally_tx_elements_issuance_calculate_asset', c_int, [c_void_p, c_ulong, c_void_p, c_ulong]), + ('wally_tx_elements_issuance_calculate_reissuance_token', c_int, [c_void_p, c_ulong, c_uint, c_void_p, c_ulong]), + ('wally_tx_elements_issuance_generate_entropy', c_int, [c_void_p, c_ulong, c_uint, c_void_p, c_ulong, c_void_p, c_ulong]), + ('wally_tx_elements_output_commitment_free', c_int, [POINTER(wally_tx_output)]), + ('wally_tx_elements_output_commitment_set', c_int, [POINTER(wally_tx_output), c_void_p, c_ulong, c_void_p, c_ulong, c_void_p, c_ulong, c_void_p, c_ulong, c_void_p, c_ulong]), + ('wally_tx_elements_output_init_alloc', c_int, [c_void_p, c_ulong, c_void_p, c_ulong, c_void_p, c_ulong, c_void_p, c_ulong, c_void_p, c_ulong, c_void_p, c_ulong, POINTER(POINTER(wally_tx_output))]), ('wally_tx_free', c_int, [POINTER(wally_tx)]), + ('wally_tx_from_bytes', c_int, [c_void_p, c_ulong, c_uint, POINTER(POINTER(wally_tx))]), + ('wally_tx_from_hex', c_int, [c_char_p, c_uint, POINTER(POINTER(wally_tx))]), + ('wally_tx_get_btc_signature_hash', c_int, [POINTER(wally_tx), c_ulong, c_void_p, c_ulong, c_uint64, c_uint, c_uint, c_void_p, c_ulong]), + ('wally_tx_get_elements_signature_hash', c_int, [POINTER(wally_tx), c_ulong, c_void_p, c_ulong, c_void_p, c_ulong, c_uint, c_uint, c_void_p, c_ulong]), ('wally_tx_get_length', c_int, [POINTER(wally_tx), c_uint, c_ulong_p]), + ('wally_tx_get_signature_hash', c_int, [POINTER(wally_tx), c_ulong, c_void_p, c_ulong, c_void_p, c_ulong, c_uint, c_uint64, c_uint, c_uint, c_uint, c_void_p, c_ulong]), + ('wally_tx_get_total_output_satoshi', c_int, [POINTER(wally_tx), c_uint64_p]), + ('wally_tx_get_txid', c_int, [POINTER(wally_tx), c_void_p, c_ulong]), ('wally_tx_get_vsize', c_int, [POINTER(wally_tx), c_ulong_p]), ('wally_tx_get_weight', c_int, [POINTER(wally_tx), c_ulong_p]), - ('wally_tx_vsize_from_weight', c_int, [c_ulong, c_ulong_p]), - ('wally_tx_get_total_output_satoshi', c_int, [POINTER(wally_tx), POINTER(c_ulonglong)]), ('wally_tx_get_witness_count', c_int, [POINTER(wally_tx), c_ulong_p]), - ('wally_tx_get_btc_signature_hash', c_int, [POINTER(wally_tx), c_ulong, c_void_p, c_ulong, c_ulonglong, c_uint, c_uint, c_void_p, c_ulong]), - ('wally_tx_get_elements_signature_hash', c_int, [POINTER(wally_tx), c_ulong, c_void_p, c_ulong, c_void_p, c_ulong, c_uint, c_uint, c_void_p, c_ulong]), - ('wally_tx_witness_stack_init_alloc', c_int, [c_ulong, POINTER(POINTER(wally_tx_witness_stack))]), - ('wally_tx_witness_stack_free', c_int, [POINTER(wally_tx_witness_stack)]), - ('wally_tx_witness_stack_add', c_int, [POINTER(wally_tx_witness_stack), c_void_p, c_ulong]), - ('wally_tx_witness_stack_add_dummy', c_int, [POINTER(wally_tx_witness_stack), c_uint]), - ('wally_tx_witness_stack_set', c_int, [POINTER(wally_tx_witness_stack), c_ulong, c_void_p, c_ulong]), - ('wally_tx_witness_stack_set_dummy', c_int, [POINTER(wally_tx_witness_stack), c_ulong, c_uint]), - ('wally_tx_output_init_alloc', c_int, [c_ulonglong, c_void_p, c_ulong, POINTER(POINTER(wally_tx_output))]), - ('wally_tx_output_free', c_int, [POINTER(wally_tx_output)]), - ('wally_tx_add_output', c_int, [POINTER(wally_tx), POINTER(wally_tx_output)]), - ('wally_tx_add_raw_output', c_int, [POINTER(wally_tx), c_ulonglong, c_void_p, c_ulong, c_uint]), - ('wally_tx_add_elements_raw_output', c_int, [POINTER(wally_tx), c_void_p, c_ulong, c_void_p, c_ulong, c_void_p, c_ulong, c_void_p, c_ulong, c_void_p, c_ulong, c_void_p, c_ulong, c_uint]), - ('wally_tx_remove_output', c_int, [POINTER(wally_tx), c_ulong]), - ('wally_tx_input_init_alloc', c_int, [c_void_p, c_ulong, c_uint, c_uint, c_void_p, c_ulong, POINTER(wally_tx_witness_stack), POINTER(POINTER(wally_tx_input))]), + ('wally_tx_init_alloc', c_int, [c_uint, c_uint, c_ulong, c_ulong, POINTER(POINTER(wally_tx))]), ('wally_tx_input_free', c_int, [POINTER(wally_tx_input)]), - ('wally_tx_add_input', c_int, [POINTER(wally_tx), POINTER(wally_tx_input)]), - ('wally_tx_add_raw_input', c_int, [POINTER(wally_tx), c_void_p, c_ulong, c_uint, c_uint, c_void_p, c_ulong, POINTER(wally_tx_witness_stack), c_uint]), - ('wally_tx_add_elements_raw_input', c_int, [POINTER(wally_tx), c_void_p, c_ulong, c_uint, c_uint, c_void_p, c_ulong, POINTER(wally_tx_witness_stack), c_void_p, c_ulong, c_void_p, c_ulong, c_void_p, c_ulong, c_void_p, c_ulong, c_void_p, c_ulong, c_void_p, c_ulong, POINTER(wally_tx_witness_stack), c_uint]), + ('wally_tx_input_init_alloc', c_int, [c_void_p, c_ulong, c_uint, c_uint, c_void_p, c_ulong, POINTER(wally_tx_witness_stack), POINTER(POINTER(wally_tx_input))]), + ('wally_tx_is_coinbase', c_int, [POINTER(wally_tx), c_ulong_p]), + ('wally_tx_is_elements', c_int, [POINTER(wally_tx), c_ulong_p]), + ('wally_tx_output_clone_alloc', c_int, [POINTER(wally_tx_output), POINTER(POINTER(wally_tx_output))]), + ('wally_tx_output_clone', c_int, [POINTER(wally_tx_output), POINTER(wally_tx_output)]), + ('wally_tx_output_free', c_int, [POINTER(wally_tx_output)]), + ('wally_tx_output_init_alloc', c_int, [c_uint64, c_void_p, c_ulong, POINTER(POINTER(wally_tx_output))]), ('wally_tx_remove_input', c_int, [POINTER(wally_tx), c_ulong]), + ('wally_tx_remove_output', c_int, [POINTER(wally_tx), c_ulong]), ('wally_tx_set_input_script', c_int, [POINTER(wally_tx), c_ulong, c_void_p, c_ulong]), ('wally_tx_set_input_witness', c_int, [POINTER(wally_tx), c_ulong, POINTER(wally_tx_witness_stack)]), - ('wally_tx_confidential_value_from_satoshi', c_int, [c_ulonglong, c_void_p, c_ulong]), + ('wally_tx_to_bytes', c_int, [POINTER(wally_tx), c_uint, c_void_p, c_ulong, c_ulong_p]), + ('wally_tx_to_hex', c_int, [POINTER(wally_tx), c_uint, c_char_p_p]), + ('wally_tx_vsize_from_weight', c_int, [c_ulong, c_ulong_p]), + ('wally_tx_witness_stack_add', c_int, [POINTER(wally_tx_witness_stack), c_void_p, c_ulong]), + ('wally_tx_witness_stack_add_dummy', c_int, [POINTER(wally_tx_witness_stack), c_uint]), + ('wally_tx_witness_stack_clone_alloc', c_int, [POINTER(wally_tx_witness_stack), POINTER(POINTER(wally_tx_witness_stack))]), + ('wally_tx_witness_stack_free', c_int, [POINTER(wally_tx_witness_stack)]), + ('wally_tx_witness_stack_init_alloc', c_int, [c_ulong, POINTER(POINTER(wally_tx_witness_stack))]), + ('wally_tx_witness_stack_set', c_int, [POINTER(wally_tx_witness_stack), c_ulong, c_void_p, c_ulong]), + ('wally_tx_witness_stack_set_dummy', c_int, [POINTER(wally_tx_witness_stack), c_ulong, c_uint]), + ('wally_unknowns_map_add', c_int, [POINTER(wally_unknowns_map), c_void_p, c_ulong, c_void_p, c_ulong]), + ('wally_unknowns_map_find', c_int, [POINTER(wally_unknowns_map), c_void_p, c_ulong, c_ulong_p]), + ('wally_unknowns_map_free', c_int, [POINTER(wally_unknowns_map)]), + ('wally_unknowns_map_init_alloc', c_int, [c_ulong, POINTER(POINTER(wally_unknowns_map))]), ('wally_wif_from_bytes', c_int, [c_void_p, c_ulong, c_uint, c_uint, c_char_p_p]), + ('wally_wif_is_uncompressed', c_int, [c_char_p, c_ulong_p]), ('wally_wif_to_address', c_int, [c_char_p, c_uint, c_uint, c_char_p_p]), ('wally_wif_to_bytes', c_int, [c_char_p, c_uint, c_uint, c_void_p, c_ulong]), ('wally_wif_to_public_key', c_int, [c_char_p, c_uint, c_void_p, c_ulong, c_ulong_p]), - ('wally_wif_is_uncompressed', c_int, [c_char_p, c_ulong_p]), - ('wally_psbt_input_init_alloc', c_int, [POINTER(wally_tx), POINTER(wally_tx_output), c_void_p, c_ulong, c_void_p, c_ulong, c_void_p, c_ulong, POINTER(wally_tx_witness_stack), POINTER(keypath_map), POINTER(partial_sigs_map), POINTER(unknowns_map), c_ulong, POINTER(POINTER(wally_psbt_input))]), - ('wally_psbt_input_free', c_int, [POINTER(wally_psbt_input)]), - ('wally_psbt_output_init_alloc', c_int, [c_void_p, c_ulong, c_void_p, c_ulong, POINTER(keypath_map), POINTER(unknowns_map), c_ulong, POINTER(POINTER(wally_psbt_output))]), - ('wally_psbt_output_free', c_int, [POINTER(wally_psbt_output)]), - ('wally_psbt_init_alloc', c_int, [c_ulong, c_ulong, c_ulong, POINTER(POINTER(wally_psbt))]), - ('wally_psbt_free', c_int, [POINTER(wally_psbt)]), - ('wally_psbt_from_bytes', c_int, [c_void_p, c_ulong, POINTER(POINTER(wally_psbt))]), - ('wally_psbt_to_bytes', c_int, [POINTER(wally_psbt), c_void_p, c_ulong, c_ulong_p]), - ('wally_psbt_get_length', c_int, [POINTER(wally_psbt), c_ulong_p]), - ('wally_psbt_from_base64', c_int, [c_char_p, POINTER(POINTER(wally_psbt))]), - ('wally_psbt_to_base64', c_int, [POINTER(wally_psbt), c_char_p_p]), - ('wally_psbt_set_global_tx', c_int, [POINTER(wally_psbt), POINTER(wally_tx)]), - ('wally_combine_psbts', c_int, [POINTER(wally_psbt), c_ulong, POINTER(POINTER(wally_psbt))]), - ('wally_sign_psbt', c_int, [POINTER(wally_psbt), c_void_p, c_ulong]), - ('wally_finalize_psbt', c_int, [POINTER(wally_psbt)]), - ('wally_extract_psbt', c_int, [POINTER(wally_psbt), POINTER(POINTER(wally_tx))]) + ('wally_witness_multisig_from_bytes', c_int, [c_void_p, c_ulong, c_void_p, c_ulong, c_uint_p, c_ulong, c_uint, POINTER(POINTER(wally_tx_witness_stack))]), + ('wally_witness_p2wpkh_from_der', c_int, [c_void_p, c_ulong, c_void_p, c_ulong, POINTER(POINTER(wally_tx_witness_stack))]), + ('wally_witness_p2wpkh_from_sig', c_int, [c_void_p, c_ulong, c_void_p, c_ulong, c_uint, POINTER(POINTER(wally_tx_witness_stack))]), + ('wally_witness_program_from_bytes', c_int, [c_void_p, c_ulong, c_uint, c_void_p, c_ulong, c_ulong_p]), ): def bind_fn(name, res, args): @@ -339,7 +459,8 @@ def bind_fn(name, res, args): fn.restype, fn.argtypes = res, args return fn except AttributeError: - # Internal function and 'configure --enable-export-all' not used + # Internal function and 'configure --enable-export-all' not used, + # or an Elements function and Elements support not enabled. return None def in_string_fn_wrapper(fn, pos, *args): @@ -364,22 +485,34 @@ def int_fn_wrapper(fn, *args): ret = fn(*new_args) return [p.value, (ret, p.value)][fn.restype is not None] + def int64_fn_wrapper(fn, *args): + p = c_uint64() + new_args = [a for a in args] + [byref(p)] + ret = fn(*new_args) + return [p.value, (ret, p.value)][fn.restype is not None] + name, restype, argtypes = f is_str_fn = len(argtypes) and type(argtypes[-1]) is c_char_p_p_class is_int_fn = len(argtypes) and type(argtypes[-1]) is c_ulong_p_class + is_int64_fn = len(argtypes) and type(argtypes[-1]) is c_uint64_p_class in_str_pos = [i for (i, t) in enumerate(argtypes) if t == c_char_p] if is_str_fn: argtypes[-1] = POINTER(c_char_p) elif is_int_fn: argtypes[-1] = POINTER(c_ulong) + elif is_int64_fn: + argtypes[-1] = POINTER(c_uint64) fn = bind_fn(name, restype, argtypes) def mkstr(f): return lambda *args: string_fn_wrapper(f, *args) def mkint(f): return lambda *args: int_fn_wrapper(f, *args) + def mkint64(f): return lambda *args: int64_fn_wrapper(f, *args) def mkinstr(f, pos): return lambda *args: in_string_fn_wrapper(f, pos, *args) if is_str_fn: fn = mkstr(fn) elif is_int_fn: fn = mkint(fn) + elif is_int64_fn: + fn = mkint64(fn) if len(in_str_pos) > 0 and fn: for pos in in_str_pos: fn = mkinstr(fn, pos) @@ -410,8 +543,8 @@ def make_cbuffer(hex_in): assert wally_secp_randomize(urandom(32), 32) == WALLY_OK, 'Random init failed' -_original_ops = operations() -_new_ops = operations() +_original_ops = wally_operations() +_new_ops = wally_operations() for ops in (_original_ops, _new_ops): assert wally_get_operations(byref(ops)) == WALLY_OK diff --git a/src/transaction.c b/src/transaction.c index e87ec6d3c..23a416f99 100644 --- a/src/transaction.c +++ b/src/transaction.c @@ -11,7 +11,8 @@ #include "transaction_shared.h" #include "script_int.h" -#define WALLY_TX_ALL_FLAGS (WALLY_TX_FLAG_USE_WITNESS | WALLY_TX_FLAG_USE_ELEMENTS) +#define WALLY_TX_ALL_FLAGS \ + (WALLY_TX_FLAG_USE_WITNESS | WALLY_TX_FLAG_USE_ELEMENTS | WALLY_TX_FLAG_ALLOW_PARTIAL) /* We use the maximum DER sig length (plus a byte for the sighash) so that * we overestimate the size by a byte or two per tx sig. This allows using @@ -31,10 +32,6 @@ static const unsigned char DUMMY_SIG[EC_SIGNATURE_DER_MAX_LEN + 1]; /* +1 for si else \ wally_clear(dst, siz); -#define BYTES_VALID(p, len) ((p != NULL) == (len != 0)) -#define BYTES_INVALID(p, len) (!BYTES_VALID(p, len)) -#define BYTES_INVALID_N(p, len, siz) ((p != NULL) != (len == siz)) - #define MAX_INVALID_SATOSHI ((uint64_t) -1) /* Extra options when serializing for hashing */ @@ -144,6 +141,9 @@ static bool is_valid_elements_tx(const struct wally_tx *tx) { size_t i; + if (!tx->num_inputs && !tx->num_outputs) + return false; /* No inputs & no outputs, treat as non-elements tx */ + for (i = 0; i < tx->num_inputs; ++i) if (!is_valid_elements_tx_input(tx->inputs + i)) return false; @@ -167,15 +167,7 @@ bool clone_bytes(unsigned char **dst, const unsigned char *src, size_t len) return *dst != NULL; } -void clear_and_free(void *p, size_t len) -{ - if (p) { - wally_clear(p, len); - wally_free(p); - } -} - -static void *realloc_array(const void *src, size_t old_n, size_t new_n, size_t size) +void *realloc_array(const void *src, size_t old_n, size_t new_n, size_t size) { unsigned char *p = wally_malloc(new_n * size); if (!p) @@ -186,40 +178,47 @@ static void *realloc_array(const void *src, size_t old_n, size_t new_n, size_t s return p; } -static int replace_script(const unsigned char *script, size_t script_len, - unsigned char **script_out, size_t *script_len_out) +int replace_bytes(const unsigned char *bytes, size_t bytes_len, + unsigned char **bytes_out, size_t *bytes_len_out) { - /* TODO: Avoid reallocation if new script is smaller than the existing one */ - unsigned char *new_script = NULL; - if (!clone_bytes(&new_script, script, script_len)) + unsigned char *new_bytes = NULL; + + if (BYTES_INVALID(bytes, bytes_len) || BYTES_INVALID(*bytes_out, *bytes_len_out)) + return WALLY_EINVAL; + + /* TODO: Avoid reallocation if new bytes is smaller than the existing one */ + if (!clone_bytes(&new_bytes, bytes, bytes_len)) return WALLY_ENOMEM; - clear_and_free(*script_out, *script_len_out); - *script_out = new_script; - *script_len_out = script_len; + clear_and_free(*bytes_out, *bytes_len_out); + *bytes_out = new_bytes; + *bytes_len_out = bytes_len; return WALLY_OK; } -struct wally_tx_witness_stack *clone_witness( - const struct wally_tx_witness_stack *stack) +int wally_tx_witness_stack_clone_alloc(const struct wally_tx_witness_stack *stack, + struct wally_tx_witness_stack **output) { struct wally_tx_witness_stack *result; size_t i; int ret; - ret = wally_tx_witness_stack_init_alloc(stack->items_allocation_len, &result); + TX_CHECK_OUTPUT; + if (!stack) + return WALLY_EINVAL; - if (ret == WALLY_OK) { - for (i = 0; i < stack->num_items && ret == WALLY_OK; ++i) { - ret = wally_tx_witness_stack_set(result, i, - stack->items[i].witness, - stack->items[i].witness_len); - if (ret != WALLY_OK) - wally_tx_witness_stack_free(result); - } + ret = wally_tx_witness_stack_init_alloc(stack->items_allocation_len, &result); + for (i = 0; ret == WALLY_OK && i < stack->num_items; ++i) { + ret = wally_tx_witness_stack_set(result, i, + stack->items[i].witness, + stack->items[i].witness_len); } - return ret == WALLY_OK ? result : NULL; + if (ret == WALLY_OK) + *output = result; + else + wally_tx_witness_stack_free(result); + return ret; } int wally_tx_witness_stack_init_alloc(size_t allocation_len, @@ -231,13 +230,12 @@ int wally_tx_witness_stack_init_alloc(size_t allocation_len, TX_OUTPUT_ALLOC(struct wally_tx_witness_stack); if (allocation_len) { - result->items = wally_malloc(allocation_len * sizeof(*result->items)); + result->items = wally_calloc(allocation_len * sizeof(*result->items)); if (!result->items) { wally_free(result); *output = NULL; return WALLY_ENOMEM; } - wally_clear(result->items, allocation_len * sizeof(*result->items)); } result->items_allocation_len = allocation_len; result->num_items = 0; @@ -347,14 +345,16 @@ static bool clone_input_to( #ifdef BUILD_ELEMENTS unsigned char *new_issuance_amount = NULL, *new_inflation_keys = NULL, *new_issuance_amount_rangeproof = NULL, *new_inflation_keys_rangeproof = NULL; + struct wally_tx_witness_stack *new_pegin_witness = NULL; #endif + struct wally_tx_witness_stack *new_witness = NULL; - struct wally_tx_witness_stack *new_witness; - new_witness = src->witness ? clone_witness(src->witness) : NULL; + if (src->witness) + wally_tx_witness_stack_clone_alloc(src->witness, &new_witness); #ifdef BUILD_ELEMENTS - struct wally_tx_witness_stack *new_pegin_witness; - new_pegin_witness = src->pegin_witness ? clone_witness(src->pegin_witness) : NULL; + if (src->pegin_witness) + wally_tx_witness_stack_clone_alloc(src->pegin_witness, &new_pegin_witness); #endif if (!clone_bytes(&new_script, src->script, src->script_len) || @@ -586,7 +586,7 @@ static int tx_elements_input_init( struct wally_tx_witness_stack *new_witness = NULL; struct wally_tx_witness_stack *new_pegin_witness = NULL; unsigned char *new_script = NULL; - int ret, old_features; + int ret = WALLY_OK, old_features; if (!txhash || txhash_len != WALLY_TXHASH_LEN || BYTES_INVALID(script, script_len) || !output) @@ -594,11 +594,13 @@ static int tx_elements_input_init( old_features = output->features; - if ((witness && !(new_witness = clone_witness(witness))) || - (pegin_witness && !(new_pegin_witness = clone_witness(pegin_witness))) || - !clone_bytes(&new_script, script, script_len)) + if (witness) + ret = wally_tx_witness_stack_clone_alloc(witness, &new_witness); + if (ret == WALLY_OK && pegin_witness) + ret = wally_tx_witness_stack_clone_alloc(pegin_witness, &new_pegin_witness); + if (ret == WALLY_OK && !clone_bytes(&new_script, script, script_len)) ret = WALLY_ENOMEM; - else { + if (ret == WALLY_OK) { output->features = 0; ret = tx_elements_input_issuance_init(output, nonce, @@ -775,16 +777,16 @@ int wally_tx_input_free(struct wally_tx_input *input) return tx_input_free(input, true); } -static bool clone_output_to(struct wally_tx_output *dst, - const struct wally_tx_output *src) +int wally_tx_output_clone(const struct wally_tx_output *src, + struct wally_tx_output *output) { unsigned char *new_script = NULL; #ifdef BUILD_ELEMENTS unsigned char *new_asset = NULL, *new_value = NULL, *new_nonce = NULL, *new_surjectionproof = NULL, *new_rangeproof = NULL; #endif - if (!dst || !src) - return false; + if (!src || !output) + return WALLY_EINVAL; #ifdef BUILD_ELEMENTS if (!clone_bytes(&new_asset, src->asset, src->asset_len) || @@ -804,19 +806,36 @@ static bool clone_output_to(struct wally_tx_output *dst, clear_and_free(new_surjectionproof, src->surjectionproof_len); clear_and_free(new_rangeproof, src->rangeproof_len); #endif - return false; + return WALLY_ENOMEM; } - memcpy(dst, src, sizeof(*src)); - dst->script = new_script; + memcpy(output, src, sizeof(*src)); + output->script = new_script; #ifdef BUILD_ELEMENTS - dst->asset = new_asset; - dst->value = new_value; - dst->nonce = new_nonce; - dst->surjectionproof = new_surjectionproof; - dst->rangeproof = new_rangeproof; + output->asset = new_asset; + output->value = new_value; + output->nonce = new_nonce; + output->surjectionproof = new_surjectionproof; + output->rangeproof = new_rangeproof; #endif - return true; + return WALLY_OK; +} + +int wally_tx_output_clone_alloc(const struct wally_tx_output *src, + struct wally_tx_output **output) +{ + struct wally_tx_output *result; + int ret; + + TX_CHECK_OUTPUT; + TX_OUTPUT_ALLOC(struct wally_tx_output); + + ret = wally_tx_output_clone(src, result); + if (ret != WALLY_OK) { + wally_free(result); + *output = NULL; + } + return ret; } static int tx_elements_output_proof_init( @@ -826,10 +845,10 @@ static int tx_elements_output_proof_init( const unsigned char *rangeproof, size_t rangeproof_len) { - (void) output; #ifdef BUILD_ELEMENTS unsigned char *new_surjectionproof = NULL, *new_rangeproof = NULL; #endif + (void) output; if (BYTES_INVALID(surjectionproof, surjectionproof_len) || BYTES_INVALID(rangeproof, rangeproof_len)) @@ -1358,6 +1377,7 @@ int wally_tx_remove_input(struct wally_tx *tx, size_t index) int wally_tx_add_output(struct wally_tx *tx, const struct wally_tx_output *output) { uint64_t total; + int ret; const bool is_elements = output->features & WALLY_TX_IS_ELEMENTS; if (!is_elements) { if (!is_valid_tx(tx) || !is_valid_tx_output(output) || @@ -1379,8 +1399,8 @@ int wally_tx_add_output(struct wally_tx *tx, const struct wally_tx_output *outpu tx->outputs = p; tx->outputs_allocation_len += 1; } - if (!clone_output_to(tx->outputs + tx->num_outputs, output)) - return WALLY_ENOMEM; + if ((ret = wally_tx_output_clone(output, tx->outputs + tx->num_outputs)) != WALLY_OK) + return ret; tx->num_outputs += 1; return WALLY_OK; @@ -1538,6 +1558,9 @@ static int tx_get_lengths(const struct wally_tx *tx, *witness_count = 0; + if (!is_valid_tx(tx)) + return WALLY_EINVAL; + if (opts) { if (flags & WALLY_TX_FLAG_USE_WITNESS) return WALLY_ERROR; /* Segwit tx hashing uses bip143 opts member */ @@ -1565,7 +1588,7 @@ static int tx_get_lengths(const struct wally_tx *tx, } } - if ((flags & ~WALLY_TX_FLAG_USE_WITNESS) || + if ((flags & ~WALLY_TX_ALL_FLAGS) || ((flags & WALLY_TX_FLAG_USE_WITNESS) && wally_tx_get_witness_count(tx, witness_count) != WALLY_OK)) return WALLY_EINVAL; @@ -1983,11 +2006,17 @@ static int tx_to_bytes(const struct wally_tx *tx, if (written) *written = 0; - if (!is_valid_tx(tx) || !tx->num_inputs || !tx->num_outputs || - (flags & ~WALLY_TX_FLAG_USE_WITNESS) || !bytes_out || !written || + if (!is_valid_tx(tx) || !tx->num_inputs || + (flags & ~WALLY_TX_ALL_FLAGS) || !bytes_out || !written || tx_get_length(tx, opts, flags, &n, is_elements) != WALLY_OK) return WALLY_EINVAL; + /* If requested, 0-output txs can be written. 0-input txs are not + * currently supported since they conflict due to segwit tx markers + * when serialized */ + if (!(flags & WALLY_TX_FLAG_ALLOW_PARTIAL) && !tx->num_outputs) + return WALLY_EINVAL; + if (opts && (flags & WALLY_TX_FLAG_USE_WITNESS)) return WALLY_ERROR; /* Segwit tx hashing is handled elsewhere */ @@ -2151,14 +2180,21 @@ int wally_tx_to_bytes(const struct wally_tx *tx, uint32_t flags, return tx_to_bytes(tx, NULL, flags, bytes_out, len, written, is_elements); } -static int tx_to_hex(const struct wally_tx *tx, uint32_t flags, - char **output, bool is_elements) +/* Common implementation for hex conversion and txid calculation */ +static int tx_to_hex_or_txid(const struct wally_tx *tx, uint32_t flags, + char **output, + unsigned char *bytes_out, size_t len, + bool is_elements) { unsigned char buff[TX_STACK_SIZE], *buff_p = buff; size_t n, written; int ret; - if (!output) + if (output) + *output = NULL; + + if ((output && (bytes_out || len)) || + (!output && (!bytes_out || len != WALLY_TXHASH_LEN))) return WALLY_EINVAL; ret = tx_to_bytes(tx, NULL, flags, buff_p, sizeof(buff), &n, is_elements); @@ -2170,12 +2206,15 @@ static int tx_to_hex(const struct wally_tx *tx, uint32_t flags, if (n != written) ret = WALLY_ERROR; /* Length calculated incorrectly */ } - if (ret == WALLY_OK) - ret = wally_hex_from_bytes(buff_p, n, output); + if (ret == WALLY_OK) { + if (output) + ret = wally_hex_from_bytes(buff_p, n, output); + else + ret = wally_sha256d(buff_p, n, bytes_out, len); + } + wally_clear(buff_p, n); if (buff_p != buff) - clear_and_free(buff_p, n); - else - wally_clear(buff, n); + wally_free(buff_p); } return ret; } @@ -2189,12 +2228,23 @@ int wally_tx_to_hex(const struct wally_tx *tx, uint32_t flags, if (wally_tx_is_elements(tx, &is_elements) != WALLY_OK) return WALLY_EINVAL; #endif - return tx_to_hex(tx, flags, output, is_elements); + return tx_to_hex_or_txid(tx, flags, output, NULL, 0, is_elements); +} + +int wally_tx_get_txid(const struct wally_tx *tx, unsigned char *bytes_out, size_t len) +{ + size_t is_elements = 0; + +#ifdef BUILD_ELEMENTS + if (wally_tx_is_elements(tx, &is_elements) != WALLY_OK) + return WALLY_EINVAL; +#endif + return tx_to_hex_or_txid(tx, 0, NULL, bytes_out, len, is_elements); } -int analyze_tx(const unsigned char *bytes, size_t bytes_len, - uint32_t flags, size_t *num_inputs, size_t *num_outputs, - bool *expect_witnesses) +static int analyze_tx(const unsigned char *bytes, size_t bytes_len, + uint32_t flags, size_t *num_inputs, size_t *num_outputs, + bool *expect_witnesses) { const unsigned char *p = bytes, *end = bytes + bytes_len; uint64_t v, num_witnesses; @@ -2209,8 +2259,7 @@ int analyze_tx(const unsigned char *bytes, size_t bytes_len, if (expect_witnesses) *expect_witnesses = false; - if (!bytes || bytes_len < sizeof(uint32_t) + 2 || - (flags & ~WALLY_TX_FLAG_USE_ELEMENTS) || + if (!bytes || bytes_len < sizeof(uint32_t) + 2 || (flags & ~WALLY_TX_ALL_FLAGS) || !num_inputs || !num_outputs || !expect_witnesses) return WALLY_EINVAL; @@ -2382,12 +2431,11 @@ static int witness_stack_from_bytes(const unsigned char *bytes, struct wally_tx_ } static int tx_from_bytes(const unsigned char *bytes, size_t bytes_len, - uint32_t flags, struct wally_tx **output, - bool is_elements) + uint32_t flags, struct wally_tx **output) { const unsigned char *p = bytes; + const bool is_elements = flags & WALLY_TX_FLAG_USE_ELEMENTS; bool expect_witnesses; - uint32_t analyze_flags = flags & ~WALLY_TX_FLAG_USE_WITNESS; size_t i, j, num_inputs, num_outputs; uint64_t tmp, num_witnesses; int ret; @@ -2395,7 +2443,7 @@ static int tx_from_bytes(const unsigned char *bytes, size_t bytes_len, TX_CHECK_OUTPUT; - if (analyze_tx(bytes, bytes_len, analyze_flags, &num_inputs, &num_outputs, + if (analyze_tx(bytes, bytes_len, flags, &num_inputs, &num_outputs, &expect_witnesses) != WALLY_OK) return WALLY_EINVAL; @@ -2554,7 +2602,7 @@ static int tx_from_bytes(const unsigned char *bytes, size_t bytes_len, int wally_tx_from_bytes(const unsigned char *bytes, size_t bytes_len, uint32_t flags, struct wally_tx **output) { - return tx_from_bytes(bytes, bytes_len, flags, output, flags & WALLY_TX_FLAG_USE_ELEMENTS); + return tx_from_bytes(bytes, bytes_len, flags, output); } int wally_tx_from_hex(const char *hex, uint32_t flags, @@ -2576,8 +2624,7 @@ int wally_tx_from_hex(const char *hex, uint32_t flags, } ret = wally_hex_to_bytes(hex, buff_p, bin_len, &written); if (ret == WALLY_OK) - ret = tx_from_bytes(buff_p, bin_len, flags, output, - flags & WALLY_TX_FLAG_USE_ELEMENTS); + ret = tx_from_bytes(buff_p, bin_len, flags, output); if (buff_p != buff) clear_and_free(buff_p, bin_len); @@ -2641,7 +2688,7 @@ static int tx_get_signature_hash(const struct wally_tx *tx, if (!is_valid_tx(tx) || BYTES_INVALID(script, script_len) || BYTES_INVALID(extra, extra_len) || satoshi > WALLY_SATOSHI_MAX || (sighash & 0xffffff00) || - (flags & ~WALLY_TX_FLAG_USE_WITNESS) || !bytes_out || len < SHA256_LEN) + (flags & ~WALLY_TX_ALL_FLAGS) || !bytes_out || len < SHA256_LEN) return WALLY_EINVAL; if (extra || extra_len || extra_offset) @@ -2753,28 +2800,25 @@ int wally_tx_elements_issuance_generate_entropy(const unsigned char *txhash, unsigned char *bytes_out, size_t len) { - unsigned char buff_1[2 * SHA256_LEN], *buff_p1 = buff_1; - unsigned char buff_2[WALLY_TXHASH_LEN + sizeof(uint32_t)], *buff_p2 = buff_2; - int ret = WALLY_OK; + unsigned char buff[2 * SHA256_LEN]; + unsigned char buff_2[WALLY_TXHASH_LEN + sizeof(uint32_t)]; + int ret; if (!txhash || txhash_len != WALLY_TXHASH_LEN || !contract_hash || contract_hash_len != SHA256_LEN || !bytes_out || len != SHA256_LEN) return WALLY_EINVAL; - memcpy(buff_p2, txhash, txhash_len); - buff_p2 += txhash_len; - buff_p2 += uint32_to_le_bytes(index, buff_p2); + memcpy(buff_2, txhash, txhash_len); + uint32_to_le_bytes(index, buff_2 + txhash_len); - if ((ret = wally_sha256d(buff_2, WALLY_TXHASH_LEN + sizeof(uint32_t), buff_p1, SHA256_LEN)) != WALLY_OK) - goto fail; - - memcpy(buff_p1 + SHA256_LEN, contract_hash, contract_hash_len); + ret = wally_sha256d(buff_2, sizeof(buff_2), buff, SHA256_LEN); + if (ret == WALLY_OK) { + memcpy(buff + SHA256_LEN, contract_hash, contract_hash_len); + ret = wally_sha256_midstate(buff, sizeof(buff), bytes_out, len); + } - ret = wally_sha256_midstate(buff_p1, 2 * SHA256_LEN, bytes_out, len); -fail: - wally_clear(buff_1, sizeof(buff_1)); - wally_clear(buff_2, sizeof(buff_2)); + wally_clear_2(buff, sizeof(buff), buff_2, sizeof(buff_2)); return ret; } @@ -2785,7 +2829,7 @@ static int tx_elements_token_from_bytes(const unsigned char *entropy, unsigned char *bytes_out, size_t len) { - unsigned char buff[2 * SHA256_LEN], *buff_p = buff; + unsigned char buff[2 * SHA256_LEN]; int ret; if (!entropy || entropy_len != SHA256_LEN || @@ -2793,10 +2837,10 @@ static int tx_elements_token_from_bytes(const unsigned char *entropy, !bytes_out || len != SHA256_LEN) return WALLY_EINVAL; - memcpy(buff_p, entropy, entropy_len); - memcpy(buff_p + SHA256_LEN, bytes, bytes_len); + memcpy(buff, entropy, entropy_len); + memcpy(buff + SHA256_LEN, bytes, bytes_len); - ret = wally_sha256_midstate(buff_p, sizeof(buff), bytes_out, len); + ret = wally_sha256_midstate(buff, sizeof(buff), bytes_out, len); wally_clear(buff, sizeof(buff)); return ret; @@ -2821,7 +2865,7 @@ int wally_tx_elements_issuance_calculate_reissuance_token(const unsigned char *e { unsigned char buff[SHA256_LEN] = { 0 }; - if ((flags & ~(WALLY_TX_FLAG_BLINDED_INITIAL_ISSUANCE))) + if ((flags & ~WALLY_TX_FLAG_BLINDED_INITIAL_ISSUANCE)) return WALLY_EINVAL; /* 32-byte '1' constant for unblinded and '2' for confidential */ @@ -2883,19 +2927,20 @@ static int tx_getb_impl(const void *input, return WALLY_OK; } -#define GET_TX_ARRAY(typ, name, siz) \ +#define GET_TX_B_FIXED(typ, name, siz, n) \ int wally_ ## typ ## _get_ ## name(const struct wally_ ## typ *input, \ unsigned char *bytes_out, size_t len) { \ size_t written; \ - if (!input || len != siz) \ + if (!input || len != n) \ return WALLY_EINVAL; \ return tx_getb_impl(input, input->name, siz, bytes_out, len, &written); \ } -GET_TX_ARRAY(tx_input, txhash, WALLY_TXHASH_LEN) + +GET_TX_B_FIXED(tx_input, txhash, WALLY_TXHASH_LEN, WALLY_TXHASH_LEN) #ifdef BUILD_ELEMENTS -GET_TX_ARRAY(tx_input, blinding_nonce, SHA256_LEN) -GET_TX_ARRAY(tx_input, entropy, SHA256_LEN) +GET_TX_B_FIXED(tx_input, blinding_nonce, SHA256_LEN, SHA256_LEN) +GET_TX_B_FIXED(tx_input, entropy, SHA256_LEN, SHA256_LEN) #endif /* BUILD_ELEMENTS */ @@ -2907,16 +2952,6 @@ GET_TX_ARRAY(tx_input, entropy, SHA256_LEN) return tx_getb_impl(input, input->name, siz, bytes_out, len, written); \ } -#define GET_TX_B_FIXED(typ, name, siz, n) \ - int wally_ ## typ ## _get_ ## name(const struct wally_ ## typ *input, \ - unsigned char *bytes_out, size_t len) { \ - size_t written; \ - if (!input) \ - return WALLY_EINVAL; \ - int ret = len != n ? WALLY_EINVAL : tx_getb_impl(input, input->name, siz, bytes_out, len, &written); \ - return ret; \ - } - #define GET_TX_I(typ, name, outtyp) \ int wally_ ## typ ## _get_ ## name(const struct wally_ ## typ *input, outtyp * written) { \ if (written) *written = 0; \ @@ -3056,9 +3091,9 @@ int wally_tx_input_set_txhash(struct wally_tx_input *input, int wally_tx_output_set_script(struct wally_tx_output *output, const unsigned char *script, size_t script_len) { - if (!is_valid_tx_output(output) || BYTES_INVALID(script, script_len)) + if (!is_valid_tx_output(output)) return WALLY_EINVAL; - return replace_script(script, script_len, &output->script, &output->script_len); + return replace_bytes(script, script_len, &output->script, &output->script_len); } int wally_tx_output_set_satoshi(struct wally_tx_output *output, uint64_t satoshi) @@ -3220,7 +3255,8 @@ int wally_tx_input_set_witness(struct wally_tx_input *input, if (!is_valid_tx_input(input) || (stack && !is_valid_witness_stack(stack))) return WALLY_EINVAL; - if (stack && (new_witness = clone_witness(stack)) == NULL) + if (stack && + wally_tx_witness_stack_clone_alloc(stack, &new_witness) != WALLY_OK) return WALLY_ENOMEM; tx_witness_stack_free(input->witness, true); @@ -3238,41 +3274,36 @@ int wally_tx_set_input_witness(const struct wally_tx *tx, size_t index, int wally_tx_input_set_script(struct wally_tx_input *input, const unsigned char *script, size_t script_len) { - if (!is_valid_tx_input(input) || BYTES_INVALID(script, script_len)) + if (!is_valid_tx_input(input)) return WALLY_EINVAL; - return replace_script(script, script_len, &input->script, &input->script_len); + return replace_bytes(script, script_len, &input->script, &input->script_len); } TX_SET_B(input, script) -int clone_tx(struct wally_tx *tx, struct wally_tx **output) +int wally_tx_clone(const struct wally_tx *tx, uint32_t flags, struct wally_tx **output) { - int ret = WALLY_OK; size_t i; struct wally_tx *result = NULL; + int ret; TX_CHECK_OUTPUT; - if ((ret = wally_tx_init_alloc(tx->version, tx->locktime, tx->num_inputs, tx->num_outputs, &result)) != WALLY_OK) { - goto fail; - } - for (i = 0; i < tx->num_inputs; ++i) { - if ((ret = wally_tx_add_input(result, &tx->inputs[i])) != WALLY_OK) { - goto fail; - } - } - for (i = 0; i < tx->num_outputs; ++i) { - if ((ret = wally_tx_add_output(result, &tx->outputs[i])) != WALLY_OK) { - goto fail; - } - } - *output = result; + if (!is_valid_tx(tx) || flags != 0) + return WALLY_EINVAL; - return WALLY_OK; + ret = wally_tx_init_alloc(tx->version, tx->locktime, tx->num_inputs, tx->num_outputs, &result); -fail: - if (result) { + for (i = 0; ret == WALLY_OK && i < tx->num_inputs; ++i) + ret = wally_tx_add_input(result, &tx->inputs[i]); + + for (i = 0; ret == WALLY_OK && i < tx->num_outputs; ++i) + ret = wally_tx_add_output(result, &tx->outputs[i]); + + if (ret == WALLY_OK) + *output = result; + else wally_tx_free(result); - } + return ret; } diff --git a/src/transaction_int.h b/src/transaction_int.h index 07aaf738b..f58452d9c 100644 --- a/src/transaction_int.h +++ b/src/transaction_int.h @@ -136,6 +136,6 @@ WALLY_CORE_API int wally_tx_set_output_rangeproof(const struct wally_tx *tx_in, } #endif -#endif /* SWIG_JAVA_BUILD/SWIG_JAVA_BUILD/SWIG_PYTHON_BUILD */ +#endif /* SWIG/SWIG_JAVA_BUILD/SWIG_PYTHON_BUILD/SWIG_JAVASCRIPT_BUILD */ #endif /* LIBWALLY_CORE_TRANSACTION_INT_H */ diff --git a/src/transaction_shared.h b/src/transaction_shared.h index 109b7c0f1..4b90f5f15 100644 --- a/src/transaction_shared.h +++ b/src/transaction_shared.h @@ -7,19 +7,18 @@ extern "C" { #define TX_CHECK_OUTPUT if (!output) return WALLY_EINVAL; else *output = NULL #define TX_OUTPUT_ALLOC(typ) \ - *output = wally_malloc(sizeof(typ)); \ + *output = wally_calloc(sizeof(typ)); \ if (!*output) return WALLY_ENOMEM; \ - wally_clear((void *)*output, sizeof(typ)); \ result = (typ *) *output; +#define BYTES_VALID(p, len) ((p != NULL) == (len != 0)) +#define BYTES_INVALID(p, len) (!BYTES_VALID(p, len)) +#define BYTES_INVALID_N(p, len, siz) ((p != NULL) != (len == siz)) + bool clone_bytes(unsigned char **dst, const unsigned char *src, size_t len); -void clear_and_free(void *p, size_t len); -int analyze_tx(const unsigned char *bytes, size_t bytes_len, - uint32_t flags, size_t *num_inputs, size_t *num_outputs, - bool *expect_witnesses); -struct wally_tx_witness_stack *clone_witness( - const struct wally_tx_witness_stack *stack); -int clone_tx(struct wally_tx *tx, struct wally_tx **output); +int replace_bytes(const unsigned char *bytes, size_t bytes_len, + unsigned char **bytes_out, size_t *bytes_len_out); +void *realloc_array(const void *src, size_t old_n, size_t new_n, size_t size); #ifdef __cplusplus } diff --git a/src/wif.c b/src/wif.c index 4a4535ca0..4e487acb1 100644 --- a/src/wif.c +++ b/src/wif.c @@ -74,7 +74,7 @@ int wally_wif_to_bytes(const char *wif, ret = is_uncompressed(wif, buf, sizeof(buf), &uncompressed); - if (ret || + if (ret != WALLY_OK || (buf[0] != prefix) || (uncompressed && flags != WALLY_WIF_FLAG_UNCOMPRESSED) || (!uncompressed && flags != WALLY_WIF_FLAG_COMPRESSED)) { @@ -139,7 +139,7 @@ int wally_wif_to_public_key(const char *wif, } else ret = wally_ec_public_key_from_private_key(&buf[1], EC_PRIVATE_KEY_LEN, bytes_out, EC_PUBLIC_KEY_LEN); - if (ret) + if (ret != WALLY_OK) *written = 0; wally_clear_2(buf, sizeof(buf), pub_key, sizeof(pub_key)); diff --git a/src/wordlist.c b/src/wordlist.c index fb1481931..6c45dbae0 100644 --- a/src/wordlist.c +++ b/src/wordlist.c @@ -7,7 +7,7 @@ static int bstrcmp(const void *l, const void *r) } /* https://graphics.stanford.edu/~seander/bithacks.html#IntegerLogObvious */ -static int get_bits(size_t n) +static size_t get_bits(size_t n) { size_t bits = 0; while (n >>= 1) @@ -20,6 +20,7 @@ static struct words *wordlist_alloc(const char *words, size_t len) { struct words *w = wally_malloc(sizeof(struct words)); if (w) { + wally_clear(w, sizeof(*w)); w->str = wally_strdup(words); if (w->str) { w->str_len = strlen(w->str); @@ -29,7 +30,6 @@ static struct words *wordlist_alloc(const char *words, size_t len) if (w->indices) return w; } - w->str_len = 0; wordlist_free(w); } return NULL; @@ -92,14 +92,14 @@ const char *wordlist_lookup_index(const struct words *w, size_t idx) void wordlist_free(struct words *w) { - if (w && w->str_len) { + if (w) { if (w->str) { - wally_clear((void *)w->str, w->str_len); + if (w->str_len) + wally_clear((void *)w->str, w->str_len); wally_free((void *)w->str); } if (w->indices) wally_free((void *)w->indices); /* No need to clear */ - wally_clear(w, sizeof(*w)); - wally_free(w); + clear_and_free(w, sizeof(*w)); } } diff --git a/src/wrap_js/src/combined.c b/src/wrap_js/src/combined.c index b8469ca23..9b8bcf0db 100644 --- a/src/wrap_js/src/combined.c +++ b/src/wrap_js/src/combined.c @@ -14,6 +14,8 @@ #include "hmac.c" #include "mnemonic.c" #include "pbkdf2.c" +#include "pullpush.c" +#include "psbt.c" #include "script.c" #include "scrypt.c" #include "sign.c" @@ -36,6 +38,7 @@ void wally_silence_unused_warnings(void) assert_bip32_assumptions(); assert_bip38_assumptions(); assert_tx_assumptions(); + secp256k1_fe_inv_all_var(NULL, NULL, 0); secp256k1_ge_set_all_gej_var(NULL, NULL, 0); secp256k1_gej_has_quad_y_var(NULL); secp256k1_gej_is_valid_var(NULL); @@ -43,6 +46,8 @@ void wally_silence_unused_warnings(void) secp256k1_ecmult_multi_var(NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0); secp256k1_ecmult_strauss_batch_single(NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0); secp256k1_ecmult_pippenger_batch_single(NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0); + secp256k1_pippenger_scratch_size(0, 0); + secp256k1_scalar_chacha20(NULL, NULL, NULL, 0); tx_elements_input_issuance_proof_init(NULL, NULL, 0, NULL, 0); tx_elements_output_proof_init(NULL, NULL, 0, NULL, 0); witness_stack_from_bytes(NULL, NULL, NULL); diff --git a/src/wrap_js/src/combined_ccan2.c b/src/wrap_js/src/combined_ccan2.c index fbf19b50b..e74d46429 100644 --- a/src/wrap_js/src/combined_ccan2.c +++ b/src/wrap_js/src/combined_ccan2.c @@ -1,2 +1,3 @@ #include "internal.h" #include "ccan/ccan/crypto/ripemd160/ripemd160.c" +#include "src/ccan/ccan/base64/base64.c" diff --git a/tools/build_python_cffi.sh b/tools/build_python_cffi.sh new file mode 100755 index 000000000..bb9da9106 --- /dev/null +++ b/tools/build_python_cffi.sh @@ -0,0 +1,35 @@ +#!/bin/bash +# Generate the CFFI function list used in src/tests/util.py +# Run to print the updated list and update util.py as needed. +# Only generates entries for documented functions, and requires +# that the user has sphinx documentation tool installed (package +# sphinx-doc on debian). + +# FIXME: 'int' is used only by wally_asset_rangeproof/wally_asset_rangeproof_with_nonce + +# This expression just replaces the various argument types with their +# CFFI type. struct 'words' is special cases as it is an opaque type +# and no struct definition is exposed to library users. +WALLY_DOC_DUMP_FUNCS="1" sphinx-build -b html -a -c docs/source docs/source docs/build/html 2>&1 | \ + grep '^int ' | \ + sed -e "s/(/',c_int,[/g" \ + -e "s/^int / ('/g" \ + -e 's/, /,/g' -e 's/const //g' | \ + perl -pe 's/int .*?[,)]/c_int,/g' | \ + perl -pe 's/size_t \*.*?[,)]/c_ulong_p,/g' | \ + perl -pe 's/size_t .*?[,)]/c_ulong,/g' | \ + perl -pe 's/uint32_t \*.*?[,)]/c_uint_p,/g' | \ + perl -pe 's/uint32_t .*?[,)]/c_uint,/g' | \ + perl -pe 's/uint64_t \*.*?,/POINTER(c_uint64),/g' | \ + perl -pe 's/uint64_t \*.*?\)/c_uint64_p,/g' | \ + perl -pe 's/uint64_t .*?[,)]/c_uint64,/g' | \ + perl -pe 's/unsigned char \*.*?[,)]/c_void_p,/g' | \ + perl -pe 's/char \*\*.*?[,)]/c_char_p_p,/g' | \ + perl -pe 's/char \*.*?[,)]/c_char_p,/g' | \ + perl -pe 's/void \*.*?[,)]/c_void_p,/g' | \ + perl -pe 's/struct ([a-z0-9_]*?) \*\*(.*?)[,)]/POINTER(POINTER(\1)),/g' | \ + perl -pe 's/struct ([a-z0-9_]*?) \*(.*?)[,)]/POINTER(\1),/g' | \ + sed -e 's/POINTER(words)/c_void_p/g' \ + -e 's/,/, /g' \ + -e 's/, $/]),/g' | sort + diff --git a/tools/cleanup.sh b/tools/cleanup.sh index 6c3be201f..5c5b6323f 100755 --- a/tools/cleanup.sh +++ b/tools/cleanup.sh @@ -58,6 +58,6 @@ rm -f tools/build-aux/missing rm -f tools/build-aux/m4/l*.m4 rm -f tools/build-aux/test-driver rm -rf autom4te.cache/ src/secp256k1/autom4te.cache -rm -rf docs/build docs/source/address.rst docs/source/bip32.rst docs/source/bip38.rst docs/source/bip39.rst docs/source/core.rst docs/source/crypto.rst docs/source/elements.rst docs/source/script.rst docs/source/transaction.rst +rm -rf docs/build docs/source/address.rst docs/source/bip32.rst docs/source/bip38.rst docs/source/bip39.rst docs/source/core.rst docs/source/crypto.rst docs/source/elements.rst docs/source/psbt.rst docs/source/script.rst docs/source/symmetric.rst docs/source/transaction.rst rm -rf .venv exit 0 diff --git a/tools/travis_build.sh b/tools/travis_build.sh index 638c9e4dc..b218b3f37 100755 --- a/tools/travis_build.sh +++ b/tools/travis_build.sh @@ -1,21 +1,6 @@ #! /usr/bin/env bash -function show_err() -{ - if [ -f $1 ]; then - cat $1 - fi -} - -function show_test_err() -{ - tests="test_bech32 test_clear test_tx test_elements_tx test_blech32" - for i in $tests; do - show_err src/$i.log - done -} - -trap "show_test_err" ERR +trap "cat src/test_*.log" ERR ENABLE_SWIG_PYTHON="--enable-swig-python" ENABLE_SWIG_JAVA="--enable-swig-java"