├── src ├── ccan │ ├── ccan │ │ ├── compiler │ │ │ ├── LICENSE │ │ │ ├── test │ │ │ │ ├── run-is_compile_constant.c │ │ │ │ └── compile_fail-printf.c │ │ │ └── _info │ │ ├── endian │ │ │ ├── LICENSE │ │ │ ├── test │ │ │ │ ├── compile_ok-constant.c │ │ │ │ └── run.c │ │ │ └── _info │ │ ├── base64 │ │ │ ├── LICENSE │ │ │ ├── _info │ │ │ └── test │ │ │ │ └── moretap.h │ │ ├── build_assert │ │ │ ├── LICENSE │ │ │ ├── test │ │ │ │ ├── compile_ok.c │ │ │ │ ├── compile_fail.c │ │ │ │ ├── compile_fail-expr.c │ │ │ │ └── run-BUILD_ASSERT_OR_ZERO.c │ │ │ ├── build_assert.h │ │ │ └── _info │ │ ├── str │ │ │ └── hex │ │ │ │ ├── LICENSE │ │ │ │ ├── _info │ │ │ │ ├── hex.c │ │ │ │ ├── test │ │ │ │ └── run.c │ │ │ │ └── hex.h │ │ ├── crypto │ │ │ ├── ripemd160 │ │ │ │ ├── LICENSE │ │ │ │ ├── test │ │ │ │ │ ├── run-lotsa-data.c │ │ │ │ │ ├── run-types.c │ │ │ │ │ └── run-test-vectors.c │ │ │ │ └── _info │ │ │ ├── sha256 │ │ │ │ ├── LICENSE │ │ │ │ ├── test │ │ │ │ │ ├── run-lotsa-data.c │ │ │ │ │ ├── run-types.c │ │ │ │ │ ├── run-33-bit-test.c │ │ │ │ │ └── run-test-vectors.c │ │ │ │ └── _info │ │ │ └── sha512 │ │ │ │ ├── LICENSE │ │ │ │ └── _info │ │ └── tap │ │ │ └── _info │ ├── README │ └── licenses │ │ └── BSD-MIT ├── wasm_package │ ├── .gitignore │ ├── src │ │ ├── browser │ │ │ ├── crypto.js │ │ │ └── assert.js │ │ ├── exports.js │ │ ├── index.js │ │ └── util.js │ ├── .npmignore │ ├── build.sh │ ├── webpack.config.js │ ├── package.json │ ├── test │ │ ├── bip39.js │ │ ├── base58.js │ │ ├── confidential_address.js │ │ ├── scrypt.js │ │ └── script.js │ └── README.md ├── swig_python │ ├── wallycore │ │ └── README │ └── contrib │ │ ├── coinselection.py │ │ ├── descriptor.py │ │ ├── signmessage.py │ │ ├── sha.py │ │ ├── mnemonic.py │ │ ├── aes.py │ │ ├── bip32.py │ │ └── reconcile_sigs.py ├── ctest │ ├── amalgamation_compile_test.c │ ├── test_bech32.c │ └── _CMakeLists.txt ├── data │ └── wordlists │ │ └── README ├── wallycore.pc.in ├── base58.h ├── cpufeatures │ └── NOTICE ├── amalgamation │ └── windows_config │ │ └── config.h ├── pyexample │ └── anti-exfil.py ├── tx_io.h ├── script.h ├── ecdh.c ├── pbkdf2.c ├── mnemonic.h ├── hmac.h ├── ctaes │ ├── COPYING │ ├── README.md │ └── ctaes.h ├── hmac.c ├── test │ ├── test_mnemonic.py │ ├── test_coinselection.py │ ├── test_wordlist.py │ ├── test_ecdh.py │ ├── test_internal.py │ ├── test_scrypt.py │ ├── test_hex.py │ ├── test_pbkdf2.py │ └── test_symmetric.py ├── ccan_config.h ├── wordlist.h ├── bip32_int.h ├── symmetric.c ├── hex_.c ├── swig_java │ └── src │ │ └── com │ │ └── blockstream │ │ └── test │ │ ├── test_descriptor.java │ │ └── test_scripts.java ├── hmac.inl ├── base_64.c ├── pbkdf2.inl ├── scrypt.c ├── _CMakeLists.txt ├── wordlist.c └── mnemonic.c ├── Makefile.am ├── pyproject.toml ├── contrib ├── requirements.txt ├── Dockerfile_bookworm ├── Dockerfile_bullseye ├── gitian-descriptors │ ├── libwally-core-android.yml │ └── libwally-core-linux.yml ├── wally_js_example.html ├── bullseye_deps.sh └── bookworm_deps.sh ├── .gitmodules ├── tools ├── run-gcov.sh ├── update_generated.sh ├── uncrustify ├── msvc │ ├── swig.bat │ ├── build.bat │ └── wheel.bat ├── autogen.sh ├── swigjavapost.sh ├── coverage.sh ├── update_wasm_package.sh ├── build_psbt_ctests.py ├── install_swig.sh ├── update_version.sh ├── build_android_libraries.sh ├── build_wasm.sh ├── wordlist_cc.py ├── cleanup.sh ├── android_helpers.sh └── build-aux │ └── m4 │ └── ax_check_link_flag.m4 ├── INSTALL ├── MANIFEST.in ├── .readthedocs.yaml ├── docs └── source │ ├── index.rst │ ├── conventions.rst │ └── anti_exfil_protocol.rst ├── _cmake ├── wallycore-config.cmake.in ├── utils.cmake └── config.h.in ├── LICENSE ├── .github └── workflows │ ├── wasm-package.yml │ └── wheels.yml ├── include ├── wally_symmetric.h ├── wally_coinselection.h └── wally_bip85.h ├── _CMakeLists.txt └── .gitignore /src/ccan/ccan/compiler/LICENSE: -------------------------------------------------------------------------------- 1 | ../../licenses/CC0 -------------------------------------------------------------------------------- /src/ccan/ccan/endian/LICENSE: -------------------------------------------------------------------------------- 1 | ../../licenses/CC0 -------------------------------------------------------------------------------- /src/ccan/ccan/base64/LICENSE: -------------------------------------------------------------------------------- 1 | ../../licenses/BSD-MIT -------------------------------------------------------------------------------- /src/ccan/ccan/build_assert/LICENSE: -------------------------------------------------------------------------------- 1 | ../../licenses/CC0 -------------------------------------------------------------------------------- /src/ccan/ccan/str/hex/LICENSE: -------------------------------------------------------------------------------- 1 | ../../../licenses/CC0 -------------------------------------------------------------------------------- /src/ccan/ccan/crypto/ripemd160/LICENSE: -------------------------------------------------------------------------------- 1 | ../../../licenses/BSD-MIT -------------------------------------------------------------------------------- /src/ccan/ccan/crypto/sha256/LICENSE: -------------------------------------------------------------------------------- 1 | ../../../licenses/BSD-MIT -------------------------------------------------------------------------------- /src/ccan/ccan/crypto/sha512/LICENSE: -------------------------------------------------------------------------------- 1 | ../../../licenses/BSD-MIT -------------------------------------------------------------------------------- /src/wasm_package/.gitignore: -------------------------------------------------------------------------------- 1 | libwally_wasm 2 | node_modules 3 | -------------------------------------------------------------------------------- /src/swig_python/wallycore/README: -------------------------------------------------------------------------------- 1 | https://github.com/ElementsProject/libwally-core 2 | -------------------------------------------------------------------------------- /Makefile.am: -------------------------------------------------------------------------------- 1 | ACLOCAL_AMFLAGS = -I tools/build-aux/m4 2 | AUTOMAKE_OPTIONS = foreign 3 | SUBDIRS = src 4 | -------------------------------------------------------------------------------- /pyproject.toml: -------------------------------------------------------------------------------- 1 | [build-system] 2 | requires = ["setuptools >= 42.0.0"] 3 | build-backend = "setuptools.build_meta" 4 | -------------------------------------------------------------------------------- /contrib/requirements.txt: -------------------------------------------------------------------------------- 1 | build 2 | sphinx 3 | sphinx-rtd-theme 4 | readthedocs-sphinx-ext 5 | docutils 6 | mkdocs 7 | jinja2 8 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "src/secp256k1"] 2 | path = src/secp256k1 3 | url = https://github.com/BlockstreamResearch/secp256k1-zkp.git 4 | -------------------------------------------------------------------------------- /tools/run-gcov.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Set GCOV to e.g. llvm-gov, llvm-gov-11 etc for clang, 3 | # leave it unset for gcc 4 | exec $GCOV gcov "$@" 5 | -------------------------------------------------------------------------------- /src/wasm_package/src/browser/crypto.js: -------------------------------------------------------------------------------- 1 | // So that require('crypto').webcrypto works in both NodeJS and the browser 2 | export const webcrypto = window.crypto -------------------------------------------------------------------------------- /src/wasm_package/src/exports.js: -------------------------------------------------------------------------------- 1 | export * from './core.js' 2 | export * from './const.js' 3 | export * from './functions.js' 4 | export * from './util.js' 5 | -------------------------------------------------------------------------------- /src/wasm_package/.npmignore: -------------------------------------------------------------------------------- 1 | # Intentionally left blank, to override the .gitignore matches 2 | # The libwally_wasm directory should be kept off git but published to npm. 3 | -------------------------------------------------------------------------------- /src/ccan/ccan/build_assert/test/compile_ok.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int main(int argc, char *argv[]) 4 | { 5 | BUILD_ASSERT(1 == 1); 6 | return 0; 7 | } 8 | -------------------------------------------------------------------------------- /src/ccan/ccan/build_assert/test/compile_fail.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int main(int argc, char *argv[]) 4 | { 5 | #ifdef FAIL 6 | BUILD_ASSERT(1 == 0); 7 | #endif 8 | return 0; 9 | } 10 | -------------------------------------------------------------------------------- /src/ccan/ccan/build_assert/test/compile_fail-expr.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int main(int argc, char *argv[]) 4 | { 5 | #ifdef FAIL 6 | return BUILD_ASSERT_OR_ZERO(1 == 0); 7 | #else 8 | return 0; 9 | #endif 10 | } 11 | -------------------------------------------------------------------------------- /tools/update_generated.sh: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env bash 2 | ./tools/build_wrappers.py 3 | jq . src/data/psbt.json >.foo && mv .foo src/data/psbt.json 4 | ./tools/build_psbt_ctests.py >src/ctest/psbts.h 5 | 6 | # Update WASM package constants and version 7 | ./tools/update_wasm_package.sh 8 | -------------------------------------------------------------------------------- /src/ccan/ccan/build_assert/test/run-BUILD_ASSERT_OR_ZERO.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int main(int argc, char *argv[]) 5 | { 6 | plan_tests(1); 7 | ok1(BUILD_ASSERT_OR_ZERO(1 == 1) == 0); 8 | return exit_status(); 9 | } 10 | -------------------------------------------------------------------------------- /src/ccan/ccan/endian/test/compile_ok-constant.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | struct foo { 4 | char one[BSWAP_16(0xFF00)]; 5 | char two[BSWAP_32(0xFF000000)]; 6 | char three[BSWAP_64(0xFF00000000000000ULL)]; 7 | }; 8 | 9 | int main(void) 10 | { 11 | return 0; 12 | } 13 | -------------------------------------------------------------------------------- /tools/uncrustify: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # Use uncrustify to reformat the source 3 | if test -z "$1"; then 4 | files=`ls src/*.c src/*.h src/ctest/*.c include/*.h include/*.hpp | grep -v src/config.h | grep -v wally.hpp` 5 | else 6 | files="$*" 7 | fi 8 | uncrustify --replace --no-backup -c tools/uncrustify.cfg $files 9 | -------------------------------------------------------------------------------- /src/ctest/amalgamation_compile_test.c: -------------------------------------------------------------------------------- 1 | /* Tests that including the entire library as a single source file works */ 2 | #include "../amalgamation/combined.c" 3 | 4 | int main(int argc, char *argv[]) 5 | { 6 | (void) argc; 7 | (void) argv; 8 | 9 | wally_init(0); 10 | return wally_cleanup(0); 11 | } 12 | -------------------------------------------------------------------------------- /INSTALL: -------------------------------------------------------------------------------- 1 | 2 | Use the following commands to build and install the library: 3 | 4 | $ ./tools/autogen.sh 5 | $ ./configure [options] 6 | $ make 7 | $ make install 8 | 9 | Note that ./configure --help can be used to determine configuration options. 10 | 11 | To fully clean the library, run: 12 | 13 | $ ./tools/cleanup.sh 14 | -------------------------------------------------------------------------------- /src/ccan/README: -------------------------------------------------------------------------------- 1 | The C Code Archive Network: http://ccodearchive.net 2 | 3 | You can find a set of helper utilities under tools/ and the modules 4 | under ccan/. The recommended way to add ccan modules to your project 5 | is to create a ccan/ directory and add one module per subdirectory 6 | (see tools/create-ccan-tree). 7 | 8 | Enjoy! 9 | -------------------------------------------------------------------------------- /src/data/wordlists/README: -------------------------------------------------------------------------------- 1 | These lists have been taken from the reference implementation at: 2 | 3 | https://github.com/bitcoin/bips/blob/master/bip-0039/bip-0039-wordlists.md 4 | 5 | With some minor changes (BOM removal). 6 | 7 | The c files are generated using: 8 | 9 | python3 tools/wordlist_cc.py /path/to/language.txt shortname 10 | -------------------------------------------------------------------------------- /MANIFEST.in: -------------------------------------------------------------------------------- 1 | recursive-include . configure* Makefile.am Makefile.am.include Makefile.in *.c *.h *.inl *.pc.in 2 | include tools/autogen.sh tools/cleanup.sh tools/msvc/*.bat ./tools/build-aux/* ./tools/build-aux/m4/* src/wallycore.pc.in ./src/secp256k1/build-aux/* ./src/secp256k1/build-aux/m4/* src/secp256k1/autogen.sh ./src/swig_python/swig.i ./src/swig_python/python_extra.py_in 3 | -------------------------------------------------------------------------------- /src/wasm_package/src/browser/assert.js: -------------------------------------------------------------------------------- 1 | // Minimal shim for nodejs's assert module, for the browser 2 | // For some reason, this doesn't work with the https://github.com/browserify/commonjs-assert shim, 3 | // which causes the webpack bundle to hang when attempting to import it. 4 | 5 | export default function assert(val, err='assertion failed') { 6 | if (!val) throw err 7 | } 8 | -------------------------------------------------------------------------------- /src/wallycore.pc.in: -------------------------------------------------------------------------------- 1 | prefix=@prefix@ 2 | exec_prefix=@exec_prefix@ 3 | libdir=@libdir@ 4 | includedir=@includedir@ 5 | 6 | Name: libwallycore 7 | Description: Wally is a collection of useful primitives for cryptocurrency wallets 8 | URL: https://github.com/ElementsProject/libwally-core 9 | Version: @PACKAGE_VERSION@ 10 | Cflags: -I${includedir} 11 | Libs: -L${libdir} -lwallycore 12 | -------------------------------------------------------------------------------- /src/base58.h: -------------------------------------------------------------------------------- 1 | #ifndef LIBWALLY_BASE58_H 2 | #define LIBWALLY_BASE58_H 3 | 4 | /** 5 | * Calculate the base58 checksum of a block of binary data. 6 | * 7 | * @bytes: Binary data to calculate the checksum for. 8 | * @len: The length of @bytes in bytes. 9 | */ 10 | uint32_t base58_get_checksum( 11 | const unsigned char *bytes, 12 | size_t len); 13 | 14 | #endif /* LIBWALLY_BASE58_H */ 15 | -------------------------------------------------------------------------------- /tools/msvc/swig.bat: -------------------------------------------------------------------------------- 1 | REM You need to set SWIG_PATH to the location where the swig zip 2 | REM file is expanded to 3 | %SWIG_PATH%\swig -python -Isrc -I%SWIG_PATH%\Lib\python -DBUILD_ELEMENTS=1 -outdir src\swig_python -o src\swig_python\swig_python_wrap.c src\swig_python\swig.i 4 | copy src\swig_python\wallycore.py + src\swig_python\python_extra.py_in src\swig_python\wallycore\__init__.py /B 5 | del src\swig_python\wallycore.py 6 | -------------------------------------------------------------------------------- /src/ccan/ccan/compiler/test/run-is_compile_constant.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int main(int argc, char *argv[]) 5 | { 6 | plan_tests(2); 7 | 8 | ok1(!IS_COMPILE_CONSTANT(argc)); 9 | #if HAVE_BUILTIN_CONSTANT_P 10 | ok1(IS_COMPILE_CONSTANT(7)); 11 | #else 12 | pass("If !HAVE_BUILTIN_CONSTANT_P, IS_COMPILE_CONSTANT always false"); 13 | #endif 14 | return exit_status(); 15 | } 16 | -------------------------------------------------------------------------------- /.readthedocs.yaml: -------------------------------------------------------------------------------- 1 | # .readthedocs.yaml 2 | # Read the Docs configuration file 3 | # See https://docs.readthedocs.io/en/stable/config-file/v2.html for details 4 | 5 | version: 2 6 | 7 | build: 8 | os: ubuntu-22.04 9 | tools: 10 | python: "3.11" 11 | 12 | # Build documentation in the docs/ directory with Sphinx 13 | sphinx: 14 | configuration: docs/source/conf.py 15 | 16 | python: 17 | install: 18 | - requirements: contrib/requirements.txt 19 | -------------------------------------------------------------------------------- /tools/msvc/build.bat: -------------------------------------------------------------------------------- 1 | set LIBWALLY_DIR=%cd% 2 | 3 | if "%ELEMENTS_BUILD%" == "elements" ( 4 | set OPTS=/DBUILD_ELEMENTS 5 | ) else ( 6 | set OPTS= 7 | ) 8 | 9 | REM Compile everything (wally, ccan, libsecp256k) in one lump. 10 | cl /utf-8 /DWALLY_CORE_BUILD %OPTS% /I%LIBWALLY_DIR% /I%LIBWALLY_DIR%\src /I%LIBWALLY_DIR%\include /I%LIBWALLY_DIR%\src\ccan /I%LIBWALLY_DIR%\src\ccan\base64 /I%LIBWALLY_DIR%\src\secp256k1 /Zi /LD src/amalgamation/combined.c /Fewally.dll 11 | -------------------------------------------------------------------------------- /src/wasm_package/build.sh: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env bash 2 | set -xeo pipefail 3 | 4 | # Build WASM (Note Elements is always enabled) 5 | (cd ../.. && ./tools/build_wasm.sh) 6 | mkdir -p libwally_wasm && cp ../../dist/wallycore.{js,wasm} libwally_wasm/ 7 | touch libwally_wasm/index # necessary for webpack to work (fixes "Can't resolve './' in 'wasm_package/libwally_wasm'") 8 | 9 | # Build browser bundle (to dist/wallycore.bundle.js, see webpack.config.js) 10 | webpack --mode production 11 | -------------------------------------------------------------------------------- /src/ccan/ccan/compiler/test/compile_fail-printf.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | static void PRINTF_FMT(2,3) my_printf(int x, const char *fmt, ...) 4 | { 5 | } 6 | 7 | int main(int argc, char *argv[]) 8 | { 9 | unsigned int i = 0; 10 | 11 | my_printf(1, "Not a pointer " 12 | #ifdef FAIL 13 | "%p", 14 | #if !HAVE_ATTRIBUTE_PRINTF 15 | #error "Unfortunately we don't fail if !HAVE_ATTRIBUTE_PRINTF." 16 | #endif 17 | #else 18 | "%i", 19 | #endif 20 | i); 21 | return 0; 22 | } 23 | -------------------------------------------------------------------------------- /tools/autogen.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | autoreconf --install --force --warnings=all 3 | if uname | grep "Darwin" >/dev/null 2>&1; then 4 | # Hack libtool to work around OSX requiring AR set to /usr/bin/libtool 5 | for f in ./tools/build-aux/ltmain.sh ./src/secp256k1/build-aux/ltmain.sh; do 6 | for a in x t; do 7 | gsed -i -e "s/\$AR $a /ar $a /" $f 8 | done 9 | done 10 | fi 11 | 12 | if [ -x src/secp256k1/autogen.sh ] ; then 13 | cd src/secp256k1 && ./autogen.sh 14 | fi 15 | -------------------------------------------------------------------------------- /src/wasm_package/webpack.config.js: -------------------------------------------------------------------------------- 1 | import webpack from 'webpack' 2 | import path from 'path' 3 | 4 | export default { 5 | entry: './src/index.js', 6 | experiments: { 7 | topLevelAwait: true, 8 | }, 9 | output: { 10 | path: path.resolve('browser-dist'), 11 | filename: 'wallycore.bundle.js', 12 | library: { 13 | type: 'var', 14 | name: 'WallyInit' 15 | } 16 | }, 17 | plugins: [ 18 | new webpack.ProvidePlugin({ 19 | Buffer: ['buffer', 'Buffer'], 20 | }) 21 | ] 22 | } 23 | -------------------------------------------------------------------------------- /src/cpufeatures/NOTICE: -------------------------------------------------------------------------------- 1 | Copyright (C) 2016 The Android Open Source Project 2 | 3 | Licensed under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. 5 | You may obtain a copy of the License at 6 | 7 | http://www.apache.org/licenses/LICENSE-2.0 8 | 9 | Unless required by applicable law or agreed to in writing, software 10 | distributed under the License is distributed on an "AS IS" BASIS, 11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and 13 | limitations under the License. 14 | -------------------------------------------------------------------------------- /src/amalgamation/windows_config/config.h: -------------------------------------------------------------------------------- 1 | #ifndef LIBWALLYCORE_CONFIG_H 2 | #define LIBWALLYCORE_CONFIG_H 3 | 4 | /* config.h for Windows. Assumes a little-endian intel-ish target */ 5 | #include 6 | 7 | #ifndef _WIN32 8 | #error windows_config/config.h is only intended for windows builds 9 | #endif 10 | 11 | #define HAVE_UNALIGNED_ACCESS 1 12 | 13 | #if defined (_WIN32) && !defined(_SSIZE_T_DECLARED) && !defined(_ssize_t) && !defined(ssize_t) 14 | #if defined(_WIN64) 15 | typedef __int64 ssize_t; 16 | #else 17 | typedef long ssize_t; 18 | #endif 19 | #endif 20 | 21 | #include "ccan_config.h" 22 | 23 | #endif /* LIBWALLYCORE_CONFIG_H */ 24 | -------------------------------------------------------------------------------- /src/ccan/ccan/crypto/sha256/test/run-lotsa-data.c: -------------------------------------------------------------------------------- 1 | #include 2 | /* Include the C files directly. */ 3 | #include 4 | #include 5 | 6 | int main(void) 7 | { 8 | struct sha256 h, expected; 9 | static const char zeroes[1000]; 10 | size_t i; 11 | 12 | plan_tests(63); 13 | 14 | /* Test different alignments. */ 15 | sha256(&expected, zeroes, sizeof(zeroes) - 64); 16 | for (i = 1; i < 64; i++) { 17 | sha256(&h, zeroes + i, sizeof(zeroes) - 64); 18 | ok1(memcmp(&h, &expected, sizeof(h)) == 0); 19 | } 20 | 21 | /* This exits depending on whether all tests passed */ 22 | return exit_status(); 23 | } 24 | -------------------------------------------------------------------------------- /src/ccan/ccan/crypto/ripemd160/test/run-lotsa-data.c: -------------------------------------------------------------------------------- 1 | #include 2 | /* Include the C files directly. */ 3 | #include 4 | #include 5 | 6 | int main(void) 7 | { 8 | struct ripemd160 h, expected; 9 | static const char zeroes[1000]; 10 | size_t i; 11 | 12 | plan_tests(63); 13 | 14 | /* Test different alignments. */ 15 | ripemd160(&expected, zeroes, sizeof(zeroes) - 64); 16 | for (i = 1; i < 64; i++) { 17 | ripemd160(&h, zeroes + i, sizeof(zeroes) - 64); 18 | ok1(memcmp(&h, &expected, sizeof(h)) == 0); 19 | } 20 | 21 | /* This exits depending on whether all tests passed */ 22 | return exit_status(); 23 | } 24 | -------------------------------------------------------------------------------- /docs/source/index.rst: -------------------------------------------------------------------------------- 1 | libwally-core documentation 2 | =========================== 3 | 4 | .. toctree:: 5 | :maxdepth: 2 6 | :caption: Contents: 7 | 8 | core 9 | crypto 10 | address 11 | bip32 12 | bip38 13 | bip39 14 | bip85 15 | coinselection 16 | map 17 | psbt 18 | script 19 | descriptor 20 | symmetric 21 | transaction 22 | elements 23 | anti_exfil 24 | 25 | .. toctree:: 26 | :maxdepth: 2 27 | :caption: Developer Guides 28 | 29 | Library Conventions 30 | Liquid 31 | Anti Exfil Protocol 32 | 33 | Indices and tables 34 | ================== 35 | 36 | * :ref:`genindex` 37 | * :ref:`search` 38 | -------------------------------------------------------------------------------- /src/wasm_package/src/index.js: -------------------------------------------------------------------------------- 1 | // Combining functions.js + const.js + core.js as the default export requires a separate 2 | // exports.js file that unifies them as named exports. 3 | // With this, library users can `import wally from 'wallycore'`, without `* as` 4 | 5 | export * from './exports.js' 6 | export * as default from './exports.js' 7 | 8 | import { webcrypto } from 'crypto' 9 | import { init, secp_randomize } from './functions.js' 10 | import { WALLY_SECP_RANDOMIZE_LEN } from './const.js' 11 | 12 | // Initialize libwally and seed it with the browser/nodejs's CSPRNG 13 | 14 | init(0) 15 | 16 | const randomBytes = new Uint8Array(WALLY_SECP_RANDOMIZE_LEN) 17 | webcrypto.getRandomValues(randomBytes) 18 | secp_randomize(randomBytes) -------------------------------------------------------------------------------- /tools/swigjavapost.sh: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env bash 2 | 3 | sed_exe=$1 4 | elements=$2 5 | 6 | result="swig_java/src/com/blockstream/libwally/Wally.java" 7 | 8 | mkdir -p `dirname $result` 9 | 10 | # Merge the constants and JNI interface into Wally.java 11 | grep -v '^}$' swig_java/wallycoreJNI.java | $sed_exe 's/wallycoreJNI/Wally/g' >$result 12 | grep 'public final static' swig_java/wallycoreConstants.java >>$result 13 | # Append our extra functionality 14 | cat swig_java/jni_extra.java_in >>$result 15 | if [ -n "$elements" ]; then 16 | # Include elements functionality wrappers in the generated result 17 | cat swig_java/jni_elements_extra.java_in >>$result 18 | fi 19 | echo "}" >>$result 20 | # Clean up 21 | rm -f swig_java/*.java 22 | -------------------------------------------------------------------------------- /src/wasm_package/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "wallycore", 3 | "version": "1.5.1", 4 | "description": "JavaScript bindings for libwally", 5 | "main": "src/index.js", 6 | "type": "module", 7 | "scripts": { 8 | "test": "node--test test/", 9 | "prepare": "./build.sh" 10 | }, 11 | "files": [ 12 | "src", 13 | "libwally_wasm", 14 | "webpack.config.js" 15 | ], 16 | "author": "Blockstream", 17 | "license": "(MIT or BSD)", 18 | "devDependencies": { 19 | "buffer": "^6.0.3", 20 | "test": "^3.2.1", 21 | "webpack": "^5.75.0", 22 | "webpack-cli": "^5.0.0" 23 | }, 24 | "browser": { 25 | "module": false, 26 | "assert": "./src/browser/assert.js", 27 | "crypto": "./src/browser/crypto.js" 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /contrib/Dockerfile_bookworm: -------------------------------------------------------------------------------- 1 | # 2 | # Dockerfile for wally builds on Debian bookworm (stable). 3 | # build from this directory with e.g: 4 | # docker buildx build --platform linux/arm64,linux/amd64 -f Dockerfile_bullseye -t greenaddress/wallycore:bookworm . 5 | # 6 | # Note that to build both platforms you need to: 7 | # apt install qemu-user-static binfmt-support 8 | # 9 | FROM debian:bookworm@sha256:10901ccd8d249047f9761845b4594f121edef079cfd8224edebd9ea726f0a7f6 10 | WORKDIR /root 11 | COPY bookworm_deps.sh ./deps.sh 12 | COPY requirements.txt ./contrib/requirements.txt 13 | ARG TARGETARCH 14 | ENV TARGETARCH=${TARGETARCH} 15 | ENV JAVA_HOME=/usr/lib/jvm/java-1.17.0-openjdk-${TARGETARCH} 16 | RUN ./deps.sh && rm ./deps.sh 17 | ENV ANDROID_NDK=/opt/android-ndk-r26b 18 | -------------------------------------------------------------------------------- /_cmake/wallycore-config.cmake.in: -------------------------------------------------------------------------------- 1 | @PACKAGE_INIT@ 2 | 3 | set_and_check(WALLYCORE_LIB_DIR @PACKAGE_LIB_CMAKE_INSTALL_DIR@) 4 | 5 | if("wallycore" IN_LIST wallycore_FIND_COMPONENTS) 6 | include(${WALLYCORE_LIB_DIR}/wallycore-targets.cmake) 7 | set(wallycore_wallycore_FOUND TRUE) 8 | endif() 9 | 10 | if("libsecp256k1" IN_LIST wallycore_FIND_COMPONENTS) 11 | if(TARGET wallycore::libsecp256k1) 12 | message(FATAL_ERROR "wallycore::libsecp256k1 already defined") 13 | endif() 14 | find_package(libsecp256k1 CONFIG REQUIRED) 15 | add_library(wallycore::libsecp256k1 ALIAS libsecp256k1::libsecp256k1) 16 | set(wallycore_libsecp256k1_FOUND TRUE) 17 | endif() 18 | 19 | set(wallycore_COMPONENT_FOUND TRUE) 20 | 21 | check_required_components(wallycore) 22 | -------------------------------------------------------------------------------- /src/pyexample/anti-exfil.py: -------------------------------------------------------------------------------- 1 | import wallycore as wally 2 | import os 3 | 4 | rho = os.urandom(32) 5 | priv_key = os.urandom(32) 6 | message_hash = os.urandom(32) 7 | pub_key = wally.ec_public_key_from_private_key(priv_key) 8 | 9 | # start-step-1 10 | host_commitment = wally.ae_host_commit_from_bytes(rho, wally.EC_FLAG_ECDSA) 11 | # end-step-1 12 | 13 | # start-step-2 14 | signer_commitment = wally.ae_signer_commit_from_bytes(priv_key, message_hash, host_commitment, wally.EC_FLAG_ECDSA) 15 | # end-step-2 16 | 17 | # start-step-4 18 | signature = wally.ae_sig_from_bytes(priv_key, message_hash, rho, wally.EC_FLAG_ECDSA) 19 | # end-step-4 20 | 21 | # start-step-5 22 | wally.ae_verify(pub_key, message_hash, rho, signer_commitment, wally.EC_FLAG_ECDSA, signature) 23 | # end-step-5 24 | -------------------------------------------------------------------------------- /tools/coverage.sh: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env bash 2 | 3 | # Helper to generate coverage reports. 4 | # ./tools/coverage.sh clean : Sets coverage stats to 0. 5 | # ./tools/coverage.sh : Calculates coverage stats, produces 6 | # src/lcov/index.html as output. 7 | 8 | lcov="lcov --directory=src/ --base-directory src/ --gcov-tool $PWD/tools/run-gcov.sh" 9 | 10 | if [ "$1" = "clean" ]; then 11 | $lcov --zerocounters 12 | $lcov --output-file src/lcov_base --capture --initial 13 | else 14 | $lcov --output-file src/lcov_result --capture --ignore-errors=gcov 15 | $lcov --output-file src/lcov_total --add-tracefile src/lcov_base --add-tracefile src/lcov_result --ignore-errors=gcov 16 | genhtml --demangle-cpp -o src/lcov/ src/lcov_total 17 | fi 18 | -------------------------------------------------------------------------------- /contrib/Dockerfile_bullseye: -------------------------------------------------------------------------------- 1 | # 2 | # Dockerfile for wally builds on Debian bullseye (oldstable). 3 | # build from this directory with e.g: 4 | # DOCKER_BUILDKIT=1 docker build . -t greenaddress/wallycore -f Dockerfile_bullseye 5 | # and for linux/arm64: 6 | # DOCKER_BUILDKIT=1 docker build . -t greenaddress/wallycore -f Dockerfile_bullseye --platform linux/arm64 --build-arg TARGETARCH=arm64 7 | # 8 | FROM debian:bullseye@sha256:01559430c84e6bc864bed554345d1bfbfa94ac108ab68f39915cae34604b15c3 9 | WORKDIR /root 10 | COPY bullseye_deps.sh ./deps.sh 11 | COPY requirements.txt ./contrib/requirements.txt 12 | ARG TARGETARCH=amd64 13 | ENV TARGETARCH=${TARGETARCH} 14 | ENV JAVA_HOME=/usr/lib/jvm/java-1.11.0-openjdk-${TARGETARCH} 15 | RUN ./deps.sh && rm ./deps.sh 16 | ENV ANDROID_NDK=/opt/android-ndk-r26b 17 | -------------------------------------------------------------------------------- /src/tx_io.h: -------------------------------------------------------------------------------- 1 | #ifndef LIBWALLY_CORE_TX_IO_H 2 | #define LIBWALLY_CORE_TX_IO_H 1 3 | 4 | #include 5 | #include "ccan/ccan/crypto/sha256/sha256.h" 6 | 7 | /* Suggested initial size of a signing cache to avoid re-allocations */ 8 | #define TXIO_CACHE_INITIAL_SIZE 16 9 | 10 | /* A cursor for pushing/pulling tx bytes for hashing */ 11 | typedef struct cursor_io 12 | { 13 | struct sha256_ctx ctx; 14 | struct wally_map *cache; 15 | unsigned char *cursor; 16 | size_t max; 17 | } cursor_io; 18 | 19 | /* Hash helpers */ 20 | void tagged_hash_init(struct sha256_ctx *ctx, 21 | const unsigned char *hash, size_t hash_len); 22 | 23 | void hash_varbuff(struct sha256_ctx *ctx, 24 | const unsigned char *bytes, size_t bytes_len); 25 | 26 | #endif /* LIBWALLY_CORE_TX_IO_H */ 27 | -------------------------------------------------------------------------------- /tools/update_wasm_package.sh: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env bash 2 | 3 | # Extract WALLY_ constants into const.js 4 | (echo '// AUTOGENERATED by update_wasm_package.sh' \ 5 | && egrep -r '#define [^ (]* ' include/*.h \ 6 | | grep -v '#define LIBWALLY_CORE_' \ 7 | | grep -v '#define OP_' \ 8 | | sed -r 's~.*#define ([^ ]*) *~export const \1 = ~; s~( /\*)| *$~;\1~' \ 9 | | LC_ALL=C sort \ 10 | ) > src/wasm_package/src/const.js 11 | 12 | 13 | # Update version number to match libwally's 14 | current_version=$(grep -oP 'AC_INIT\(\[libwallycore\],\[\K[^\]]+' configure.ac) 15 | (cd src/wasm_package && npm version --no-git-tag-version --allow-same-version "$current_version") 16 | 17 | 18 | # Calling build_wrappers.py is also necessary to update the wasm functions.js file. 19 | # This is handled by update_generated.sh which calls this script. 20 | -------------------------------------------------------------------------------- /src/wasm_package/test/bip39.js: -------------------------------------------------------------------------------- 1 | import { fileURLToPath } from 'url' 2 | import fs from 'fs' 3 | import path from 'path' 4 | import assert from 'assert' 5 | import test from 'test' 6 | 7 | import wally from '../src/index.js' 8 | 9 | const filepath = path.resolve(fileURLToPath(import.meta.url), '../../../data/wordlists/vectors.json') 10 | , cases = JSON.parse(fs.readFileSync(filepath, 'utf8'))['english'] 11 | , passphrase = 'TREZOR' 12 | 13 | test('BIP39', () => { 14 | assert.equal(wally.bip39_get_languages(), 'en es fr it jp zhs zht') 15 | 16 | const english = wally.bip39_get_wordlist('en') 17 | 18 | cases.forEach(item => { 19 | assert.equal(wally.bip39_mnemonic_from_bytes(english, Buffer.from(item[0], 'hex')), item[1]) 20 | assert.deepEqual(wally.bip39_mnemonic_to_seed512(item[1], passphrase).toString('hex'), item[2]) 21 | }) 22 | }) -------------------------------------------------------------------------------- /src/ccan/ccan/str/hex/_info: -------------------------------------------------------------------------------- 1 | #include "config.h" 2 | #include 3 | #include 4 | 5 | /** 6 | * str/hex - hex-to-string conversions and vice-versa 7 | * 8 | * This code contains simple routines for hexidecimal strings. 9 | * 10 | * License: CC0 (Public domain) 11 | * Author: Rusty Russell 12 | * 13 | * Example: 14 | * int main(int argc, char *argv[]) 15 | * { 16 | * int i; 17 | * 18 | * for (i = 1; i < argc; i++) { 19 | * char str[hex_str_size(strlen(argv[i]))]; 20 | * 21 | * hex_encode(str, sizeof(str), argv[i], strlen(argv[i])); 22 | * printf("%s ", str); 23 | * } 24 | * printf("\n"); 25 | * return 0; 26 | * } 27 | */ 28 | int main(int argc, char *argv[]) 29 | { 30 | /* Expect exactly one argument */ 31 | if (argc != 2) 32 | return 1; 33 | 34 | if (strcmp(argv[1], "depends") == 0) { 35 | return 0; 36 | } 37 | 38 | return 1; 39 | } 40 | -------------------------------------------------------------------------------- /src/script.h: -------------------------------------------------------------------------------- 1 | #ifndef LIBWALLY_CORE_SCRIPT_INTERNAL_H 2 | #define LIBWALLY_CORE_SCRIPT_INTERNAL_H 1 3 | 4 | #include 5 | 6 | /* Get the size of a push from the script push opcode(s) */ 7 | int script_get_push_size_from_bytes( 8 | const unsigned char *bytes, 9 | size_t bytes_len, 10 | size_t *size); 11 | 12 | /* Get the size of a push opcode from the script push opcode(s) */ 13 | int script_get_push_opcode_size_from_bytes( 14 | const unsigned char *bytes, 15 | size_t bytes_len, 16 | size_t *size); 17 | 18 | /* Get OP_N */ 19 | bool script_is_op_n(unsigned char op, bool allow_zero, size_t *n); 20 | 21 | bool scriptpubkey_is_p2tr(const unsigned char *bytes, size_t bytes_len); 22 | 23 | /* Convert 0-16 to OP_ */ 24 | size_t value_to_op_n(uint64_t v); 25 | 26 | /* Get the length of a script pushing 'n' bytes */ 27 | size_t script_get_push_size(size_t n); 28 | 29 | #endif /* LIBWALLY_CORE_SCRIPT_INTERNAL_H */ 30 | -------------------------------------------------------------------------------- /src/ctest/test_bech32.c: -------------------------------------------------------------------------------- 1 | #include "config.h" 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | static const char *invalid = "abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefg"; 9 | 10 | static bool check_segwit_to_bytes(void) 11 | { 12 | unsigned char *mem = calloc(90, sizeof(unsigned char)); 13 | size_t written; 14 | int ret; 15 | 16 | if (!mem) 17 | return false; 18 | 19 | ret = wally_addr_segwit_to_bytes(invalid, "tb", 0, mem, 90, &written); 20 | 21 | if (ret != WALLY_EINVAL) 22 | return false; 23 | 24 | free(mem); 25 | 26 | return true; 27 | } 28 | 29 | int main(void) 30 | { 31 | bool tests_ok = true; 32 | 33 | if (!check_segwit_to_bytes()) { 34 | printf("check_segwit_to_bytes test failed!\n"); 35 | tests_ok = false; 36 | } 37 | 38 | return tests_ok ? 0 : 1; 39 | } 40 | -------------------------------------------------------------------------------- /tools/msvc/wheel.bat: -------------------------------------------------------------------------------- 1 | REM Run swig to generate the wrapper source files required by 2 | REM setup.py build step 3 | call "%~dp0"\swig.bat || echo ERRORSWIG && exit /b 1 4 | 5 | REM Install virtualenv - this should possibly be on the CI box 6 | python -m pip install virtualenv 7 | 8 | REM Create a new venv and install wheel required for building wheels 9 | rmdir /s /q venv 10 | python -m virtualenv venv 11 | venv\Scripts\pip install wheel || echo ERRORWHEEL && exit /b 1 12 | 13 | REM Build the wheel 14 | mkdir dist 15 | venv\Scripts\pip wheel --wheel-dir=dist . || echo ERRORPACK && exit /b 1 16 | 17 | REM smoketest: create a new venv, install the wheel we just created and 18 | REM check it works 19 | rmdir /s /q venv-smoketest 20 | python -m virtualenv venv-smoketest 21 | venv-smoketest\Scripts\pip install --find-links=.\dist wallycore 22 | venv-smoketest\Scripts\python -c "import wallycore as wally; assert wally.hex_from_bytes(wally.hex_to_bytes('ff')) == 'ff'" || echo ERRORSMOKE && exit /b 1 23 | -------------------------------------------------------------------------------- /tools/build_psbt_ctests.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # Generate the PSBT c-test header file src/ctest/psbts.h 3 | import json 4 | 5 | def dump(cases): 6 | for case in cases: 7 | print(' /* {} */'.format(case['comment'])) 8 | round_trip = 'true' if case.get('can_round_trip', True) else 'false' 9 | is_pset = 'true' if case.get('is_pset', False) else 'false' 10 | print(' {{"{}", {}, {}}},'.format(case['psbt'], is_pset, round_trip)) 11 | if case != cases[-1]: 12 | print() 13 | 14 | with open('src/data/psbt.json', 'r') as f: 15 | JSON = json.load(f) 16 | 17 | print('''/* Generated file - do not edit! */ 18 | struct psbt_test { 19 | const char *base64; 20 | const bool is_pset; 21 | const bool can_round_trip; 22 | }; 23 | 24 | static const struct psbt_test invalid_psbts[] = 25 | {''') 26 | dump(JSON['invalid']) 27 | print('''}; 28 | 29 | static const struct psbt_test valid_psbts[] = 30 | {''') 31 | dump(JSON['valid']) 32 | print('};\n') 33 | -------------------------------------------------------------------------------- /src/swig_python/contrib/coinselection.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | from wallycore import * 3 | 4 | # Simple test cases; we only want to check that the Python binding is OK 5 | ASSET_CASES = [ 6 | ( 7 | 'Cores hard_test_case(12) io_ratio=4', 8 | [2049, 2048, 1026, 1024, 516, 512, 264, 256, 144, 128, 96, 64], 9 | 2048 + 1024 + 512 + 256 + 128 + 64, 0xffffffff, 4, 10 | [1, 3, 5, 7, 9, 11] 11 | ) 12 | ] 13 | 14 | 15 | class CoinSelectionTests(unittest.TestCase): 16 | """Tests for coin selection functions""" 17 | 18 | def test_coinselect_assets(self): 19 | if not is_elements_build(): 20 | self.skipTest('No asset coinselection for non-elements builds') 21 | 22 | for case in ASSET_CASES: 23 | comment, values, target, attempts, io_ratio, expected = case 24 | ret = coinselect_assets(values, target, attempts, io_ratio) 25 | self.assertEqual(expected, ret) 26 | 27 | 28 | if __name__ == '__main__': 29 | unittest.main() 30 | -------------------------------------------------------------------------------- /src/ecdh.c: -------------------------------------------------------------------------------- 1 | #include "internal.h" 2 | #include 3 | #include 4 | 5 | int wally_ecdh(const unsigned char *pub_key, size_t pub_key_len, 6 | const unsigned char *priv_key, size_t priv_key_len, 7 | unsigned char *bytes_out, size_t len) 8 | { 9 | const secp256k1_context *ctx = secp_ctx(); 10 | secp256k1_pubkey pub; 11 | int ret = WALLY_OK; 12 | 13 | if (!ctx) 14 | return WALLY_ENOMEM; 15 | 16 | if (!pub_key || pub_key_len != EC_PUBLIC_KEY_LEN || 17 | !priv_key || priv_key_len != EC_PRIVATE_KEY_LEN || 18 | !bytes_out || len != SHA256_LEN) 19 | return WALLY_EINVAL; 20 | 21 | wally_clear(bytes_out, len); 22 | if (!pubkey_parse(&pub, pub_key, pub_key_len)) 23 | ret = WALLY_EINVAL; 24 | else if (!seckey_verify(priv_key) || 25 | !secp256k1_ecdh(ctx, bytes_out, &pub, priv_key, NULL, NULL)) 26 | ret = WALLY_ERROR; 27 | 28 | wally_clear(&pub, sizeof(pub)); 29 | return ret; 30 | } 31 | -------------------------------------------------------------------------------- /src/pbkdf2.c: -------------------------------------------------------------------------------- 1 | #include "internal.h" 2 | #include "hmac.h" 3 | #include "ccan/ccan/endian/endian.h" 4 | #include "ccan/ccan/crypto/sha256/sha256.h" 5 | #include "ccan/ccan/crypto/sha512/sha512.h" 6 | #include "ccan/ccan/build_assert/build_assert.h" 7 | #include 8 | #include 9 | 10 | #ifdef SHA_T 11 | #undef SHA_T 12 | #endif 13 | #define SHA_T sha256 14 | #define SHA_ALIGN_T uint32_t 15 | #define SHA_MEM u32 16 | #define SHA_POST(name) name ## sha256 17 | #define SHA_POST_IMPL(name) name ## sha256_impl 18 | #define PBKDF2_HMAC_SHA_LEN PBKDF2_HMAC_SHA256_LEN 19 | #include "pbkdf2.inl" 20 | 21 | #undef SHA_T 22 | #define SHA_T sha512 23 | #undef SHA_ALIGN_T 24 | #define SHA_ALIGN_T uint64_t 25 | #undef SHA_MEM 26 | #define SHA_MEM u64 27 | #undef SHA_POST 28 | #define SHA_POST(name) name ## sha512 29 | #undef SHA_POST_IMPL 30 | #define SHA_POST_IMPL(name) name ## sha512_impl 31 | #undef PBKDF2_HMAC_SHA_LEN 32 | #define PBKDF2_HMAC_SHA_LEN PBKDF2_HMAC_SHA512_LEN 33 | #include "pbkdf2.inl" 34 | 35 | -------------------------------------------------------------------------------- /src/mnemonic.h: -------------------------------------------------------------------------------- 1 | #ifndef LIBWALLY_MNEMONIC_H 2 | #define LIBWALLY_MNEMONIC_H 3 | 4 | struct words; 5 | 6 | /** 7 | * Return a mnemonic representation of a block of bytes. 8 | * 9 | * @w: List of words. 10 | * @bytes: Bytes to convert to a mnemonic sentence. 11 | * @len: The length of @bytes in bytes. 12 | * 13 | * @bytes must be an even multiple of the number of bits in the wordlist used. 14 | */ 15 | char *mnemonic_from_bytes( 16 | const struct words *w, 17 | const unsigned char *bytes, 18 | size_t len); 19 | 20 | /** 21 | * Convert a mnemonic representation into bytes. 22 | * 23 | * @w: List of words. 24 | * @mnemonic: Mnemonic sentence to store. 25 | * @bytes_out: Destination for the resulting bytes. 26 | * @len: The length of @bytes_out in bytes. 27 | * @written: Destination for the number of bytes written to ``bytes_out``. 28 | */ 29 | int mnemonic_to_bytes( 30 | const struct words *w, 31 | const char *mnemonic, 32 | unsigned char *bytes_out, 33 | size_t len, 34 | size_t *written); 35 | 36 | #endif /* LIBWALLY_MNEMONIC_H */ 37 | -------------------------------------------------------------------------------- /src/hmac.h: -------------------------------------------------------------------------------- 1 | #ifndef LIBWALLY_HMAC_H 2 | #define LIBWALLY_HMAC_H 3 | 4 | struct sha256; 5 | struct sha512; 6 | 7 | /** 8 | * hmac_sha256 - Compute an HMAC using SHA-256 9 | * 10 | * @sha: Destination for the resulting HMAC. 11 | * @key: The key for the hash 12 | * @key_len: The length of @key in bytes. 13 | * @msg: The message to hash 14 | * @msg_len: The length of @msg in bytes. 15 | */ 16 | void hmac_sha256_impl(struct sha256 *sha, 17 | const unsigned char *key, size_t key_len, 18 | const unsigned char *msg, size_t msg_len); 19 | 20 | /** 21 | * hmac_sha512 - Compute an HMAC using SHA-512 22 | * 23 | * @sha: Destination for the resulting HMAC. 24 | * @key: The key for the hash 25 | * @key_len: The length of @key in bytes. 26 | * @msg: The message to hash 27 | * @msg_len: The length of @msg in bytes. 28 | */ 29 | void hmac_sha512_impl(struct sha512 *sha, 30 | const unsigned char *key, size_t key_len, 31 | const unsigned char *msg, size_t msg_len); 32 | 33 | #endif /* LIBWALLY_HMAC_H */ 34 | -------------------------------------------------------------------------------- /src/ccan/licenses/BSD-MIT: -------------------------------------------------------------------------------- 1 | Permission is hereby granted, free of charge, to any person obtaining a copy 2 | of this software and associated documentation files (the "Software"), to deal 3 | in the Software without restriction, including without limitation the rights 4 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 5 | copies of the Software, and to permit persons to whom the Software is 6 | furnished to do so, subject to the following conditions: 7 | 8 | The above copyright notice and this permission notice shall be included in 9 | all copies or substantial portions of the Software. 10 | 11 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 12 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 13 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 14 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 15 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 16 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 17 | THE SOFTWARE. 18 | -------------------------------------------------------------------------------- /src/wasm_package/test/base58.js: -------------------------------------------------------------------------------- 1 | import wally from '../src/index.js' 2 | import test from 'test' 3 | import assert from 'assert' 4 | 5 | const cases = [] 6 | // Leading zeros become ones 7 | for (let i = 1; i < 10; ++i) { 8 | let ones = '' 9 | for (let j = 0; j < i; ++j) ones += '1' 10 | cases.push([[new Uint8Array(i), 0], ones]) 11 | } 12 | cases.push([[Buffer.from('00CEF022FA', 'hex'), 0], '16Ho7Hs']) 13 | cases.push([[Buffer.from('45046252208D', 'hex'), 1], '4stwEBjT6FYyVV']) 14 | 15 | test('base58 from bytes', () => { 16 | cases.forEach((testCase) => { 17 | const s = wally.base58_from_bytes(testCase[0][0], testCase[0][1]) 18 | assert.deepEqual(s, testCase[1], 19 | 'base58_from_bytes(' + 20 | Buffer.from(testCase[0][0]).toString('hex') + ',' + testCase[0][1] + ')') 21 | }) 22 | }) 23 | 24 | test('base58 to bytes', () => { 25 | cases.forEach((testCase) => { 26 | const d = wally.base58_to_bytes(testCase[1], testCase[0][1]) 27 | assert.deepEqual(Buffer.from(d), Buffer.from(testCase[0][0]), 28 | 'base58_to_bytes(' + testCase[1] + ',' + testCase[0][1] + ')') 29 | }) 30 | }) -------------------------------------------------------------------------------- /src/ctaes/COPYING: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 Pieter Wuille 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /src/hmac.c: -------------------------------------------------------------------------------- 1 | #include "internal.h" 2 | #include "hmac.h" 3 | #include 4 | #include 5 | #include 6 | 7 | #ifdef SHA_T 8 | #undef SHA_T 9 | #endif 10 | #define SHA_T sha256 11 | #define SHA_PRE(name) sha256 ## name 12 | #define HMAC_FUNCTION hmac_sha256_impl 13 | #define WALLY_HMAC_FUNCTION wally_hmac_sha256 14 | #ifdef CCAN_CRYPTO_SHA256_USE_MBEDTLS 15 | #ifndef CONFIG_MBEDTLS_HARDWARE_SHA 16 | #define SHA_CTX_BUFF c.MBEDTLS_PRIVATE(buffer) 17 | #else 18 | #define SHA_CTX_BUFF c.buffer 19 | #endif 20 | #else 21 | #define SHA_CTX_BUFF buf.u8 22 | #endif 23 | #include "hmac.inl" 24 | 25 | #undef SHA_T 26 | #define SHA_T sha512 27 | #undef SHA_PRE 28 | #define SHA_PRE(name) sha512 ## name 29 | #undef HMAC_FUNCTION 30 | #define HMAC_FUNCTION hmac_sha512_impl 31 | #undef WALLY_HMAC_FUNCTION 32 | #define WALLY_HMAC_FUNCTION wally_hmac_sha512 33 | #undef SHA_CTX_BUFF 34 | #ifdef CCAN_CRYPTO_SHA512_USE_MBEDTLS 35 | #ifndef CONFIG_MBEDTLS_HARDWARE_SHA 36 | #define SHA_CTX_BUFF c.MBEDTLS_PRIVATE(buffer) 37 | #else 38 | #define SHA_CTX_BUFF c.buffer 39 | #endif 40 | #else 41 | #define SHA_CTX_BUFF buf.u8 42 | #endif 43 | #include "hmac.inl" 44 | -------------------------------------------------------------------------------- /src/test/test_mnemonic.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | from util import * 3 | 4 | class MnemonicTests(unittest.TestCase): 5 | 6 | words_list, wl = None, None 7 | 8 | def setUp(self): 9 | if self.wl is None and wordlist_init is not None: 10 | self.words_list, words = load_words('english') 11 | self.wl = wordlist_init(utf8(words)) 12 | 13 | 14 | @internal_only() 15 | def test_mnemonic(self): 16 | 17 | LEN = 16 18 | PHRASES = LEN * 8 // 11 # 11 bits per phrase 19 | PHRASES_BYTES = (PHRASES * 11 + 7) // 8 # Bytes needed to store 20 | self.assertEqual(LEN, PHRASES_BYTES) 21 | 22 | buf = create_string_buffer(LEN) 23 | 24 | # Test round tripping 25 | for i in range(len(self.words_list) - PHRASES): 26 | phrase = utf8(' '.join(self.words_list[i : i + PHRASES])) 27 | 28 | ret, written = mnemonic_to_bytes(self.wl, phrase, buf, LEN) 29 | self.assertEqual(ret, 0) 30 | self.assertEqual(written, PHRASES_BYTES) 31 | generated = mnemonic_from_bytes(self.wl, buf, LEN) 32 | self.assertEqual(phrase, generated) 33 | 34 | 35 | if __name__ == '__main__': 36 | unittest.main() 37 | -------------------------------------------------------------------------------- /src/ccan/ccan/base64/_info: -------------------------------------------------------------------------------- 1 | #include "config.h" 2 | 3 | /** 4 | * base64 - base64 encoding and decoding (rfc4648). 5 | * 6 | * base64 encoding is used to encode data in a 7-bit clean manner. 7 | * Commonly used for escaping data before encapsulation or transfer 8 | * 9 | * Example: 10 | * #include 11 | * #include 12 | * #include 13 | * 14 | * int main(int argc, char *argv[]) 15 | * { 16 | * char *base64_encoded_string; 17 | * int i; 18 | * 19 | * // print the base64-encoded form of the program arguments 20 | * for(i=1;i { 6 | // The (Liquid) address that is to be blinded 7 | const addr = 'Q7qcjTLsYGoMA7TjUp97R6E6AM5VKqBik6' 8 | // The blinding pubkey 9 | const pubkey_hex = '02dce16018bbbb8e36de7b394df5b5166e9adb7498be7d881a85a09aeecf76b623' 10 | // The resulting confidential address 11 | const addr_c = 'VTpz1bNuCALgavJKgbAw9Lpp9A72rJy64XPqgqfnaLpMjRcPh5UHBqyRUE4WMZ3asjqu7YEPVAnWw2EK' 12 | 13 | test('can extract the original address', () => { 14 | const res = wally.confidential_addr_to_addr(addr_c, wally.WALLY_CA_PREFIX_LIQUID) 15 | assert.equal(res, addr, 'Conf addr to addr') 16 | }) 17 | 18 | test('can extract the blinding pubkey then re-generate the confidential address from its inputs', () => { 19 | const ecpubkey = wally.confidential_addr_to_ec_public_key(addr_c, wally.WALLY_CA_PREFIX_LIQUID) 20 | assert.equal(ecpubkey.toString('hex'), pubkey_hex, 'Extract blinding key') 21 | 22 | const res = wally.confidential_addr_from_addr(addr, wally.WALLY_CA_PREFIX_LIQUID, ecpubkey) 23 | assert.equal(res, addr_c, 'Addr to conf addr') 24 | }) 25 | }) 26 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Note: the modules in the src/ccan/ directory have their own licenses, but 2 | except where noted in an individual source file, the rest of the code is 3 | covered by the following (BSD-MIT) license: 4 | 5 | Copyright Jon Griffiths (Blockstream) 2016. 6 | 7 | Permission is hereby granted, free of charge, to any person obtaining a copy 8 | of this software and associated documentation files (the "Software"), to deal 9 | in the Software without restriction, including without limitation the rights 10 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | copies of the Software, and to permit persons to whom the Software is 12 | furnished to do so, subject to the following conditions: 13 | 14 | The above copyright notice and this permission notice shall be included in 15 | all copies or substantial portions of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 23 | THE SOFTWARE. 24 | -------------------------------------------------------------------------------- /src/swig_python/contrib/descriptor.py: -------------------------------------------------------------------------------- 1 | """Tests for output descriptors""" 2 | import unittest 3 | from wallycore import * 4 | 5 | class DescriptorTests(unittest.TestCase): 6 | 7 | def test_descriptor_to_addresses(self): 8 | """Test the SWIG string array mapping works for descriptor_to_addresses""" 9 | descriptor_str = "wsh(multi(1,xpub661MyMwAqRbcFW31YEwpkMuc5THy2PSt5bDMsktWQcFF8syAmRUapSCGu8ED9W6oDMSgv6Zz8idoc4a6mr8BDzTJY47LJhkJ8UB7WEGuduB/1/0/*,xpub69H7F5d8KSRgmmdJg2KhpAK8SR3DjMwAdkxj3ZuxV27CprR9LgpeyGmXUbC6wb7ERfvrnKZjXoUmmDznezpbZb7ap6r1D3tgFxHmwMkQTPH/0/0/*))#t2zpj2eu" 10 | variant = 0 11 | multi_index = 0 12 | child_num = 0 13 | flags = 0 14 | network = WALLY_NETWORK_BITCOIN_MAINNET 15 | expected = [ 16 | 'bc1qvjtfmrxu524qhdevl6yyyasjs7xmnzjlqlu60mrwepact60eyz9s9xjw0c', 17 | 'bc1qp6rfclasvmwys7w7j4svgc2mrujq9m73s5shpw4e799hwkdcqlcsj464fw', 18 | 'bc1qsflxzyj2f2evshspl9n5n745swcvs5k7p5t8qdww5unxpjwdvw5qx53ms4' 19 | ] 20 | descriptor = descriptor_parse(descriptor_str, None, network, flags) 21 | addrs = descriptor_to_addresses(descriptor, variant, multi_index, 22 | child_num, 0, len(expected)) 23 | self.assertEqual(addrs, expected) 24 | 25 | 26 | if __name__ == '__main__': 27 | unittest.main() 28 | -------------------------------------------------------------------------------- /src/wasm_package/src/util.js: -------------------------------------------------------------------------------- 1 | import { map_get_num_items, map_get_item_key, map_get_item_key_length, map_get_item_integer_key, map_get_item, map_init, map_add, map_add_integer } from "./functions.js" 2 | 3 | export function fromWallyMap(wally_map) { 4 | const js_map = new Map, map_len = map_get_num_items(wally_map) 5 | 6 | for (let i = 0; i < map_len; i++) { 7 | const is_int_key = map_get_item_key_length(wally_map, i) == 0 8 | , key = is_int_key ? map_get_item_integer_key(wally_map, i) 9 | : map_get_item_key(wally_map, i).toString() 10 | js_map.set(key, map_get_item(wally_map, i)) 11 | } 12 | 13 | return js_map 14 | } 15 | 16 | export function toWallyMap(js_map) { 17 | if (js_map && js_map.constructor == Object) { 18 | // Convert plain objects into a Map 19 | js_map = new Map(Object.entries(js_map)) 20 | } else if (!(js_map instanceof Map)) { 21 | throw new Error('Invalid map for toWallyMap') 22 | } 23 | 24 | const wally_map = map_init(js_map.size, null) 25 | 26 | js_map.forEach((val, key) => { 27 | val = Buffer.from(val) 28 | if (typeof key == 'number') { 29 | map_add_integer(wally_map, key, val) 30 | } else { 31 | map_add(wally_map, Buffer.from(key), val) 32 | } 33 | }) 34 | 35 | return wally_map 36 | } -------------------------------------------------------------------------------- /tools/install_swig.sh: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env bash 2 | set -e 3 | 4 | if [ $(command -v swig) ]; then 5 | # Already installed 6 | exit 0 7 | fi 8 | 9 | if [ $(command -v apt) ]; then 10 | # Debian/Ubuntu 11 | apt install swig 12 | exit 0 13 | fi 14 | 15 | if [ -d /etc/yum.repos.d ]; then 16 | # Redhat/Fedora 17 | if grep -- mirror.centos.org /etc/yum.repos.d/*.repo >/dev/null 2>&1; then 18 | # mirror.centos.org has been nuked. Attempt to update the repo spec 19 | # for older manylinux docker builds 20 | sed -i s/mirror.centos.org/vault.centos.org/g /etc/yum.repos.d/*.repo 21 | sed -i s/^#.*baseurl=http/baseurl=http/g /etc/yum.repos.d/*.repo 22 | sed -i s/^mirrorlist=http/#mirrorlist=http/g /etc/yum.repos.d/*.repo 23 | fi 24 | yum install -y swig 25 | exit 0 26 | fi 27 | 28 | if [ $(command -v brew) ]; then 29 | # MacOS 30 | brew install swig 31 | exit 0 32 | fi 33 | 34 | if [ $(command -v apk) ]; then 35 | # Alpine 36 | apk add swig 37 | exit 0 38 | fi 39 | 40 | # Unknown - install from source 41 | SWIG_URL='https://downloads.sourceforge.net/project/swig/swig/swig-3.0.12/swig-3.0.12.tar.gz?use_mirror=autoselect' 42 | curl -sSL ${SWIG_URL} | tar xz 43 | pushd swig-3.0.12 >/dev/null 44 | ./configure 45 | make -j4 46 | make install 47 | popd >/dev/null 48 | rm -rf swig-3.0.12 49 | exit 0 50 | -------------------------------------------------------------------------------- /tools/update_version.sh: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env bash 2 | # Update the library version in dependent source files. 3 | 4 | # The master source of the version numbers is the wally_core.h header 5 | MAJOR=$(grep '#define WALLY_MAJOR_VER ' include/wally_core.h | cut -d' ' -f 3) 6 | MINOR=$(grep '#define WALLY_MINOR_VER ' include/wally_core.h | cut -d' ' -f 3) 7 | PATCH=$(grep '#define WALLY_PATCH_VER ' include/wally_core.h | cut -d' ' -f 3) 8 | # Compute the build version from the sub versions 9 | BUILD=$(($MAJOR * 256 * 256 + $MINOR * 256 + $PATCH)); 10 | BUILD=$(printf '0x%x' $BUILD) 11 | sed -i "s/BUILD_VER .*$/BUILD_VER $BUILD/g" include/wally_core.h 12 | 13 | DOTTED="$MAJOR.$MINOR.$PATCH" 14 | sed -i "s/^AC_INIT.*$/AC_INIT\(\[libwallycore],\[$DOTTED\]\)/g" configure.ac 15 | sed -i "s/wallycore==.*$/wallycore==$DOTTED/g" README.md 16 | sed -i "s/^ VERSION .*$/ VERSION $DOTTED/g" _CMakeLists.txt 17 | sed -i "s/^version = .*$/version = u'$DOTTED'/g" docs/source/conf.py 18 | sed -i "s/^ 'version': .*$/ 'version': '$DOTTED',/g" setup.py 19 | sed -i "s/^ \"version\": .*$/ \"version\": \"$DOTTED\",/g" src/wasm_package/package.json src/wasm_package/package-lock.json 20 | jq --arg dotted "$DOTTED" '(.packages."".version) = $dotted' src/wasm_package/package-lock.json > src/wasm_package/package-lock.json.tmp 21 | mv src/wasm_package/package-lock.json.tmp src/wasm_package/package-lock.json 22 | ./tools/update_generated.sh 23 | -------------------------------------------------------------------------------- /src/ctaes/README.md: -------------------------------------------------------------------------------- 1 | ctaes 2 | ===== 3 | 4 | Simple C module for constant-time AES encryption and decryption. 5 | 6 | Features: 7 | * Simple, pure C code without any dependencies. 8 | * No tables or data-dependent branches whatsoever, but using bit sliced approach from https://eprint.iacr.org/2009/129.pdf. 9 | * Very small object code: slightly over 4k of executable code when compiled with -Os. 10 | * Slower than implementations based on precomputed tables or specialized instructions, but can do ~15 MB/s on modern CPUs. 11 | 12 | Performance 13 | ----------- 14 | 15 | Compiled with GCC 5.3.1 with -O3, on an Intel(R) Core(TM) i7-4800MQ CPU, numbers in CPU cycles: 16 | 17 | | Algorithm | Key schedule | Encryption per byte | Decryption per byte | 18 | | --------- | ------------:| -------------------:| -------------------:| 19 | | AES-128 | 2.8k | 154 | 161 | 20 | | AES-192 | 3.1k | 169 | 181 | 21 | | AES-256 | 4.0k | 191 | 203 | 22 | 23 | Build steps 24 | ----------- 25 | 26 | Object code: 27 | 28 | $ gcc -O3 ctaes.c -c -o ctaes.o 29 | 30 | Tests: 31 | 32 | $ gcc -O3 ctaes.c test.c -o test 33 | 34 | Benchmark: 35 | 36 | $ gcc -O3 ctaes.c bench.c -o bench 37 | 38 | Review 39 | ------ 40 | 41 | Results of a formal review of the code can be found in http://bitcoin.sipa.be/ctaes/review.zip 42 | -------------------------------------------------------------------------------- /src/ccan/ccan/build_assert/build_assert.h: -------------------------------------------------------------------------------- 1 | /* CC0 (Public domain) - see LICENSE file for details */ 2 | #ifndef CCAN_BUILD_ASSERT_H 3 | #define CCAN_BUILD_ASSERT_H 4 | 5 | /** 6 | * BUILD_ASSERT - assert a build-time dependency. 7 | * @cond: the compile-time condition which must be true. 8 | * 9 | * Your compile will fail if the condition isn't true, or can't be evaluated 10 | * by the compiler. This can only be used within a function. 11 | * 12 | * Example: 13 | * #include 14 | * ... 15 | * static char *foo_to_char(struct foo *foo) 16 | * { 17 | * // This code needs string to be at start of foo. 18 | * BUILD_ASSERT(offsetof(struct foo, string) == 0); 19 | * return (char *)foo; 20 | * } 21 | */ 22 | #define BUILD_ASSERT(cond) \ 23 | do { (void) sizeof(char [1 - 2*!(cond)]); } while(0) 24 | 25 | /** 26 | * BUILD_ASSERT_OR_ZERO - assert a build-time dependency, as an expression. 27 | * @cond: the compile-time condition which must be true. 28 | * 29 | * Your compile will fail if the condition isn't true, or can't be evaluated 30 | * by the compiler. This can be used in an expression: its value is "0". 31 | * 32 | * Example: 33 | * #define foo_to_char(foo) \ 34 | * ((char *)(foo) \ 35 | * + BUILD_ASSERT_OR_ZERO(offsetof(struct foo, string) == 0)) 36 | */ 37 | #define BUILD_ASSERT_OR_ZERO(cond) \ 38 | (sizeof(char [1 - 2*!(cond)]) - 1) 39 | 40 | #endif /* CCAN_BUILD_ASSERT_H */ 41 | -------------------------------------------------------------------------------- /src/test/test_coinselection.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | import unittest 3 | from util import * 4 | 5 | 6 | class CoinSelectionTests(unittest.TestCase): 7 | 8 | def test_invalid(self): 9 | """Test invalid arguments""" 10 | if not wally_is_elements_build()[1]: 11 | return # # No Elements support, skip this test case 12 | values = (c_uint64 * 4)(4, 3, 2, 1) 13 | values_len = len(values) 14 | out, out_len = (c_uint32 * values_len)(), values_len 15 | attempts, target, ratio = 0xffffffff, 1, 5 16 | bad_args = [ 17 | (None, values_len, target, attempts, ratio, out, out_len), # Null values 18 | (values, 0, target, attempts, ratio, out, out_len), # Empty values 19 | (values, values_len, 0, attempts, ratio, out, out_len), # Zero target 20 | (values, values_len, target, values_len, ratio, out, out_len), # Too few attempts 21 | (values, values_len, target, attempts, 0, out, out_len), # Zero ratio 22 | (values, values_len, target, attempts, ratio, None, out_len), # Null output 23 | (values, values_len, target, attempts, ratio, out, out_len-1), # Output too small 24 | ] 25 | for args in bad_args: 26 | ret = wally_coinselect_assets(*args) 27 | self.assertEqual(ret, (WALLY_EINVAL, 0)) 28 | 29 | 30 | if __name__ == '__main__': 31 | unittest.main() 32 | -------------------------------------------------------------------------------- /_cmake/utils.cmake: -------------------------------------------------------------------------------- 1 | include(CheckCCompilerFlag) 2 | include(CheckIncludeFile) 3 | include(CheckFunctionExists) 4 | include(CheckCSourceRuns) 5 | 6 | function(generate_config_file) 7 | check_function_exists("explicit_bzero" HAVE_EXPLICIT_BZERO) 8 | check_function_exists("explicit_memset" HAVE_EXPLICIT_MEMSET) 9 | check_c_source_compiles( 10 | "int main(void) {int a = 42; int *pnt = &a; __asm__ __volatile__ (\"\" : : \"r\"(pnt) : \"memory\");}" 11 | HAVE_INLINE_ASM 12 | ) 13 | check_include_file("mbedtls/sha512.h" HAVE_MBEDTLS_SHA512_H) 14 | check_function_exists("mmap" HAVE_MMAP) 15 | check_function_exists("posix_memalign" HAVE_POSIX_MEMALIGN) 16 | check_include_file("sys/mman.h" HAVE_SYS_MMAN_H) 17 | if(CMAKE_CROSSCOMPILING) 18 | unset(HAVE_UNALIGNED_ACCESS) 19 | else() 20 | check_c_source_runs( 21 | "int main(void){static int a[2];return *((int*)(((char*)a)+1)) != 0;}" HAVE_UNALIGNED_ACCESS 22 | ) 23 | endif() 24 | set(PACKAGE \"${CMAKE_PROJECT_NAME}\") 25 | set(PACKAGE_BUGREPORT \"\") 26 | set(PACKAGE_NAME \"${CMAKE_PROJECT_NAME}\") 27 | set(PACKAGE_STRING "\"${CMAKE_PROJECT_NAME} ${CMAKE_PROJECT_VERSION}\"") 28 | set(PACKAGE_TARNAME \"${CMAKE_PROJECT_NAME}\") 29 | set(PACKAGE_URL \"${CMAKE_PROJECT_URL}\") 30 | set(PACKAGE_VERSION \"${CMAKE_PROJECT_VERSION}\") 31 | set(VERSION \"${CMAKE_PROJECT_VERSION}\") 32 | 33 | configure_file(cmake/config.h.in config.h) 34 | endfunction() 35 | -------------------------------------------------------------------------------- /src/ccan/ccan/crypto/sha256/_info: -------------------------------------------------------------------------------- 1 | #include "config.h" 2 | #include 3 | #include 4 | 5 | /** 6 | * crypto/sha256 - implementation of SHA-2 with 256 bit digest. 7 | * 8 | * This code is either a wrapper for openssl (if CCAN_CRYPTO_SHA256_USE_OPENSSL 9 | * is defined) or an open-coded implementation based on Bitcoin's. 10 | * 11 | * License: BSD-MIT 12 | * Maintainer: Rusty Russell 13 | * 14 | * Example: 15 | * #include 16 | * #include 17 | * #include 18 | * #include 19 | * 20 | * // Simple demonstration: idential strings will have the same hash, but 21 | * // two different strings will not. 22 | * int main(int argc, char *argv[]) 23 | * { 24 | * struct sha256 hash1, hash2; 25 | * 26 | * if (argc != 3) 27 | * errx(1, "Usage: %s ", argv[0]); 28 | * 29 | * sha256(&hash1, argv[1], strlen(argv[1])); 30 | * sha256(&hash2, argv[2], strlen(argv[2])); 31 | * printf("Hash is %s\n", memcmp(&hash1, &hash2, sizeof(hash1)) 32 | * ? "different" : "same"); 33 | * return 0; 34 | * } 35 | */ 36 | int main(int argc, char *argv[]) 37 | { 38 | /* Expect exactly one argument */ 39 | if (argc != 2) 40 | return 1; 41 | 42 | if (strcmp(argv[1], "depends") == 0) { 43 | printf("ccan/endian\n"); 44 | return 0; 45 | } 46 | 47 | if (strcmp(argv[1], "libs") == 0) { 48 | #ifdef CCAN_CRYPTO_SHA256_USE_OPENSSL 49 | printf("crypto\n"); 50 | #endif 51 | return 0; 52 | } 53 | 54 | return 1; 55 | } 56 | -------------------------------------------------------------------------------- /src/ccan/ccan/crypto/sha512/_info: -------------------------------------------------------------------------------- 1 | #include "config.h" 2 | #include 3 | #include 4 | 5 | /** 6 | * crypto/sha512 - implementation of SHA-2 with 512 bit digest. 7 | * 8 | * This code is either a wrapper for openssl (if CCAN_CRYPTO_SHA512_USE_OPENSSL 9 | * is defined) or an open-coded implementation based on Bitcoin's. 10 | * 11 | * License: BSD-MIT 12 | * Maintainer: Rusty Russell 13 | * 14 | * Example: 15 | * #include 16 | * #include 17 | * #include 18 | * #include 19 | * 20 | * // Simple demonstration: idential strings will have the same hash, but 21 | * // two different strings will not. 22 | * int main(int argc, char *argv[]) 23 | * { 24 | * struct sha512 hash1, hash2; 25 | * 26 | * if (argc != 3) 27 | * errx(1, "Usage: %s ", argv[0]); 28 | * 29 | * sha512(&hash1, argv[1], strlen(argv[1])); 30 | * sha512(&hash2, argv[2], strlen(argv[2])); 31 | * printf("Hash is %s\n", memcmp(&hash1, &hash2, sizeof(hash1)) 32 | * ? "different" : "same"); 33 | * return 0; 34 | * } 35 | */ 36 | int main(int argc, char *argv[]) 37 | { 38 | /* Expect exactly one argument */ 39 | if (argc != 2) 40 | return 1; 41 | 42 | if (strcmp(argv[1], "depends") == 0) { 43 | printf("ccan/endian\n"); 44 | return 0; 45 | } 46 | 47 | if (strcmp(argv[1], "libs") == 0) { 48 | #ifdef CCAN_CRYPTO_SHA512_USE_OPENSSL 49 | printf("crypto\n"); 50 | #endif 51 | return 0; 52 | } 53 | 54 | return 1; 55 | } 56 | -------------------------------------------------------------------------------- /src/ccan/ccan/str/hex/hex.c: -------------------------------------------------------------------------------- 1 | /* CC0 license (public domain) - see LICENSE file for details */ 2 | #include 3 | #if 0 4 | #include 5 | #endif 6 | #include 7 | #include 8 | 9 | static bool char_to_hex(unsigned char *val, char c) 10 | { 11 | if (c >= '0' && c <= '9') { 12 | *val = c - '0'; 13 | return true; 14 | } 15 | if (c >= 'a' && c <= 'f') { 16 | *val = c - 'a' + 10; 17 | return true; 18 | } 19 | if (c >= 'A' && c <= 'F') { 20 | *val = c - 'A' + 10; 21 | return true; 22 | } 23 | return false; 24 | } 25 | 26 | bool hex_decode(const char *str, size_t slen, void *buf, size_t bufsize) 27 | { 28 | unsigned char v1, v2; 29 | unsigned char *p = buf; 30 | 31 | while (slen > 1) { 32 | if (!char_to_hex(&v1, str[0]) || !char_to_hex(&v2, str[1])) 33 | return false; 34 | if (!bufsize) 35 | return false; 36 | *(p++) = (v1 << 4) | v2; 37 | str += 2; 38 | slen -= 2; 39 | bufsize--; 40 | } 41 | return slen == 0 && bufsize == 0; 42 | } 43 | 44 | static char hexchar(unsigned int val) 45 | { 46 | if (val < 10) 47 | return '0' + val; 48 | return 'a' + val - 10; 49 | } 50 | 51 | bool hex_encode(const void *buf, size_t bufsize, char *dest, size_t destsize) 52 | { 53 | size_t i; 54 | 55 | if (destsize < hex_str_size(bufsize)) 56 | return false; 57 | 58 | for (i = 0; i < bufsize; i++) { 59 | unsigned int c = ((const unsigned char *)buf)[i]; 60 | *(dest++) = hexchar(c >> 4); 61 | *(dest++) = hexchar(c & 0xF); 62 | } 63 | *dest = '\0'; 64 | 65 | return true; 66 | } 67 | -------------------------------------------------------------------------------- /src/ccan/ccan/crypto/ripemd160/_info: -------------------------------------------------------------------------------- 1 | #include "config.h" 2 | #include 3 | #include 4 | 5 | /** 6 | * crypto/ripemd160 - implementation of RIPEMD 160 bit digest algorithm. 7 | * 8 | * This code is either a wrapper for openssl (if CCAN_CRYPTO_RIPEMD160_USE_OPENSSL 9 | * is defined) or an open-coded implementation based on Bitcoin's. 10 | * 11 | * License: BSD-MIT 12 | * Maintainer: Rusty Russell 13 | * 14 | * Example: 15 | * #include 16 | * #include 17 | * #include 18 | * #include 19 | * 20 | * // Simple demonstration: idential strings will have the same hash, but 21 | * // two different strings will not. 22 | * int main(int argc, char *argv[]) 23 | * { 24 | * struct ripemd160 hash1, hash2; 25 | * 26 | * if (argc != 3) 27 | * errx(1, "Usage: %s ", argv[0]); 28 | * 29 | * ripemd160(&hash1, argv[1], strlen(argv[1])); 30 | * ripemd160(&hash2, argv[2], strlen(argv[2])); 31 | * printf("Hash is %s\n", memcmp(&hash1, &hash2, sizeof(hash1)) 32 | * ? "different" : "same"); 33 | * return 0; 34 | * } 35 | */ 36 | int main(int argc, char *argv[]) 37 | { 38 | /* Expect exactly one argument */ 39 | if (argc != 2) 40 | return 1; 41 | 42 | if (strcmp(argv[1], "depends") == 0) { 43 | printf("ccan/endian\n"); 44 | return 0; 45 | } 46 | 47 | if (strcmp(argv[1], "libs") == 0) { 48 | #ifdef CCAN_CRYPTO_RIPEMD160_USE_OPENSSL 49 | printf("crypto\n"); 50 | #endif 51 | return 0; 52 | } 53 | 54 | return 1; 55 | } 56 | -------------------------------------------------------------------------------- /src/ccan/ccan/build_assert/_info: -------------------------------------------------------------------------------- 1 | #include "config.h" 2 | #include 3 | #include 4 | 5 | /** 6 | * build_assert - routines for build-time assertions 7 | * 8 | * This code provides routines which will cause compilation to fail should some 9 | * assertion be untrue: such failures are preferable to run-time assertions, 10 | * but much more limited since they can only depends on compile-time constants. 11 | * 12 | * These assertions are most useful when two parts of the code must be kept in 13 | * sync: it is better to avoid such cases if possible, but seconds best is to 14 | * detect invalid changes at build time. 15 | * 16 | * For example, a tricky piece of code might rely on a certain element being at 17 | * the start of the structure. To ensure that future changes don't break it, 18 | * you would catch such changes in your code like so: 19 | * 20 | * Example: 21 | * #include 22 | * #include 23 | * 24 | * struct foo { 25 | * char string[5]; 26 | * int x; 27 | * }; 28 | * 29 | * static char *foo_string(struct foo *foo) 30 | * { 31 | * // This trick requires that the string be first in the structure 32 | * BUILD_ASSERT(offsetof(struct foo, string) == 0); 33 | * return (char *)foo; 34 | * } 35 | * 36 | * License: CC0 (Public domain) 37 | * Author: Rusty Russell 38 | */ 39 | int main(int argc, char *argv[]) 40 | { 41 | if (argc != 2) 42 | return 1; 43 | 44 | if (strcmp(argv[1], "depends") == 0) 45 | /* Nothing. */ 46 | return 0; 47 | 48 | return 1; 49 | } 50 | -------------------------------------------------------------------------------- /.github/workflows/wasm-package.yml: -------------------------------------------------------------------------------- 1 | name: Build NPM package 2 | 3 | on: 4 | push: 5 | branches: 6 | - master 7 | pull_request: 8 | branches: 9 | - master 10 | 11 | jobs: 12 | build: 13 | runs-on: ubuntu-22.04 14 | 15 | steps: 16 | - uses: actions/checkout@v5 17 | with: 18 | submodules: true 19 | 20 | # Needed for build_wrappers.py, to extract function signatures from source code 21 | # We sed out azure to attempt to mitigate apt network failues. 22 | - run: sudo sed -i 's/azure\.//' /etc/apt/sources.list 23 | 24 | # bullseye_deps.sh is written for Debian, but works as-is on Ubuntu too. 25 | # Skip installing Java (-j), the Android NDK (-n) and MinGW (-w) which 26 | # we don't need for building the NPM package. 27 | - run: sudo contrib/bullseye_deps.sh -j -n -w 28 | 29 | # Build NPM package into a tgz file (pack internally triggers the build/prepare script) 30 | - run: cd src/wasm_package && npm ci && npm pack --foreground-scripts 31 | name: Build & Pack 32 | 33 | # Report the SHA256 digest of the final package. This should be deterministic (including generated WASM), 34 | # so it should match the package published to the NPM registry and can be used to cross-check its integrity. 35 | - run: 'echo SHA256 digest: && sha256sum src/wasm_package/wallycore-*.tgz' 36 | 37 | - run: cd src/wasm_package && npm test 38 | 39 | - uses: actions/upload-artifact@v4 40 | with: 41 | name: libwally-npm 42 | path: src/wasm_package/wallycore-*.tgz 43 | -------------------------------------------------------------------------------- /src/ccan/ccan/str/hex/test/run.c: -------------------------------------------------------------------------------- 1 | #include 2 | /* Include the C files directly. */ 3 | #include 4 | #include 5 | #include 6 | 7 | int main(void) 8 | { 9 | const char teststr[] = "0123456789abcdefABCDEF"; 10 | const char bad_teststr[] = "0123456789abcdefABCDEF1O"; 11 | const unsigned char testdata[] = { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 12 | 0xcd, 0xef, 0xAB, 0xCD, 0xEF }; 13 | unsigned char data[11]; 14 | char str[23]; 15 | size_t i; 16 | 17 | plan_tests(10 + sizeof(str)); 18 | 19 | ok1(hex_str_size(sizeof(testdata)) == sizeof(teststr)); 20 | /* This gives right result with or without nul included */ 21 | ok1(hex_data_size(strlen(teststr)) == sizeof(testdata)); 22 | ok1(hex_data_size(sizeof(teststr)) == sizeof(testdata)); 23 | 24 | ok1(hex_decode(teststr, strlen(teststr), data, sizeof(data))); 25 | ok1(memcmp(data, testdata, sizeof(testdata)) == 0); 26 | ok1(hex_encode(testdata, sizeof(testdata), str, sizeof(str))); 27 | ok1(strcmp(str, "0123456789abcdefabcdef") == 0); 28 | 29 | /* Bad char */ 30 | ok1(!hex_decode(bad_teststr, strlen(bad_teststr), data, sizeof(data))); 31 | /* Bad hex string len */ 32 | ok1(!hex_decode(teststr, strlen(teststr) - 1, data, sizeof(data))); 33 | /* Bad buffer len */ 34 | ok1(!hex_decode(teststr, strlen(teststr), data, sizeof(data) - 1)); 35 | 36 | /* Bad deststring size. */ 37 | for (i = 1; i <= sizeof(str); i++) 38 | ok1(!hex_encode(testdata, sizeof(testdata), str, sizeof(str)-i)); 39 | 40 | /* This exits depending on whether all tests passed */ 41 | return exit_status(); 42 | } 43 | -------------------------------------------------------------------------------- /include/wally_symmetric.h: -------------------------------------------------------------------------------- 1 | #ifndef LIBWALLY_CORE_SYMMETRIC_H 2 | #define LIBWALLY_CORE_SYMMETRIC_H 3 | 4 | #include "wally_core.h" 5 | 6 | #ifdef __cplusplus 7 | extern "C" { 8 | #endif 9 | 10 | /** 11 | * Create a new symmetric parent key from entropy. 12 | * 13 | * :param bytes: Entropy to use. 14 | * :param bytes_len: Size of ``bytes`` in bytes. Must be one of `BIP32_ENTROPY_LEN_128`, 15 | *| `BIP32_ENTROPY_LEN_256` or `BIP32_ENTROPY_LEN_512`. 16 | * :param bytes_out: Destination for the resulting parent key. 17 | * FIXED_SIZED_OUTPUT(len, bytes_out, HMAC_SHA512_LEN) 18 | */ 19 | WALLY_CORE_API int wally_symmetric_key_from_seed( 20 | const unsigned char *bytes, 21 | size_t bytes_len, 22 | unsigned char *bytes_out, 23 | size_t len); 24 | 25 | /** 26 | * 27 | * Create a new child symmetric key from a parent key. 28 | * 29 | * :param bytes: Parent key to use. 30 | * :param bytes_len: Size of ``bytes`` in bytes. Must be `HMAC_SHA512_LEN`. 31 | * :param version: Version byte to prepend to ``label``. Must be zero. 32 | * :param label: Label to use for the child. 33 | * :param label_len: Size of ``label`` in bytes. 34 | * :param bytes_out: Destination for the resulting key. 35 | * FIXED_SIZED_OUTPUT(len, bytes_out, HMAC_SHA512_LEN) 36 | */ 37 | WALLY_CORE_API int wally_symmetric_key_from_parent( 38 | const unsigned char *bytes, 39 | size_t bytes_len, 40 | uint32_t version, 41 | const unsigned char *label, 42 | size_t label_len, 43 | unsigned char *bytes_out, 44 | size_t len); 45 | 46 | #ifdef __cplusplus 47 | } 48 | #endif 49 | 50 | #endif /* LIBWALLY_CORE_SYMMETRIC_H */ 51 | -------------------------------------------------------------------------------- /src/ccan/ccan/endian/_info: -------------------------------------------------------------------------------- 1 | #include "config.h" 2 | #include 3 | #include 4 | 5 | /** 6 | * endian - endian conversion macros for simple types 7 | * 8 | * Portable protocols (such as on-disk formats, or network protocols) 9 | * are often defined to be a particular endian: little-endian (least 10 | * significant bytes first) or big-endian (most significant bytes 11 | * first). 12 | * 13 | * Similarly, some CPUs lay out values in memory in little-endian 14 | * order (most commonly, Intel's 8086 and derivatives), or big-endian 15 | * order (almost everyone else). 16 | * 17 | * This module provides conversion routines, inspired by the linux kernel. 18 | * It also provides leint32_t, beint32_t etc typedefs, which are annotated for 19 | * the sparse checker. 20 | * 21 | * Example: 22 | * #include 23 | * #include 24 | * #include 25 | * 26 | * // 27 | * int main(int argc, char *argv[]) 28 | * { 29 | * uint32_t value; 30 | * 31 | * if (argc != 2) 32 | * errx(1, "Usage: %s ", argv[0]); 33 | * 34 | * value = atoi(argv[1]); 35 | * printf("native: %08x\n", value); 36 | * printf("little-endian: %08x\n", cpu_to_le32(value)); 37 | * printf("big-endian: %08x\n", cpu_to_be32(value)); 38 | * printf("byte-reversed: %08x\n", bswap_32(value)); 39 | * exit(0); 40 | * } 41 | * 42 | * License: License: CC0 (Public domain) 43 | * Author: Rusty Russell 44 | */ 45 | int main(int argc, char *argv[]) 46 | { 47 | if (argc != 2) 48 | return 1; 49 | 50 | if (strcmp(argv[1], "depends") == 0) 51 | /* Nothing */ 52 | return 0; 53 | 54 | return 1; 55 | } 56 | -------------------------------------------------------------------------------- /src/ccan/ccan/crypto/sha256/test/run-types.c: -------------------------------------------------------------------------------- 1 | #include 2 | /* Include the C files directly. */ 3 | #include 4 | #include 5 | 6 | static unsigned char arr[] = { 7 | 0x12, 8 | #if HAVE_BIG_ENDIAN 9 | /* u16 */ 10 | 0x12, 0x34, 11 | /* u32 */ 12 | 0x12, 0x34, 0x56, 0x78, 13 | /* u64 */ 14 | 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 15 | #else 16 | /* u16 */ 17 | 0x34, 0x12, 18 | /* u32 */ 19 | 0x78, 0x56, 0x34, 0x12, 20 | /* u64 */ 21 | 0xf0, 0xde, 0xbc, 0x9a, 0x78, 0x56, 0x34, 0x12, 22 | #endif 23 | /* le16 */ 24 | 0x34, 0x12, 25 | /* le32 */ 26 | 0x78, 0x56, 0x34, 0x12, 27 | /* le64 */ 28 | 0xf0, 0xde, 0xbc, 0x9a, 0x78, 0x56, 0x34, 0x12, 29 | /* be16 */ 30 | 0x12, 0x34, 31 | /* be32 */ 32 | 0x12, 0x34, 0x56, 0x78, 33 | /* be64 */ 34 | 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0 35 | }; 36 | 37 | int main(void) 38 | { 39 | struct sha256 h, expected; 40 | struct sha256_ctx ctx; 41 | 42 | /* This is how many tests you plan to run */ 43 | plan_tests(1); 44 | 45 | sha256_init(&ctx); 46 | sha256_u8(&ctx, 0x12); 47 | sha256_u16(&ctx, 0x1234); 48 | sha256_u32(&ctx, 0x12345678); 49 | sha256_u64(&ctx, 0x123456789abcdef0ULL); 50 | sha256_le16(&ctx, 0x1234); 51 | sha256_le32(&ctx, 0x12345678); 52 | sha256_le64(&ctx, 0x123456789abcdef0ULL); 53 | sha256_be16(&ctx, 0x1234); 54 | sha256_be32(&ctx, 0x12345678); 55 | sha256_be64(&ctx, 0x123456789abcdef0ULL); 56 | sha256_done(&ctx, &h); 57 | 58 | sha256(&expected, arr, sizeof(arr)); 59 | ok1(memcmp(&h, &expected, sizeof(h)) == 0); 60 | 61 | /* This exits depending on whether all tests passed */ 62 | return exit_status(); 63 | } 64 | -------------------------------------------------------------------------------- /src/ctest/_CMakeLists.txt: -------------------------------------------------------------------------------- 1 | 2 | 3 | add_executable(test_bech32 test_bech32.c) 4 | target_include_directories(test_bech32 PRIVATE ${CMAKE_BINARY_DIR}) 5 | target_link_libraries(test_bech32 PRIVATE wallycore) 6 | add_test(test_bech32 test_bech32) 7 | 8 | if(NOT WIN32) 9 | add_executable(test_clear test_clear.c) 10 | target_include_directories(test_clear PRIVATE ${CMAKE_BINARY_DIR}) 11 | target_link_libraries(test_clear PRIVATE wallycore pthread) 12 | add_test(test_clear test_clear) 13 | endif() 14 | 15 | add_executable(test_coinselection test_coinselection.c) 16 | target_include_directories(test_coinselection PRIVATE ${CMAKE_BINARY_DIR}) 17 | target_link_libraries(test_coinselection PRIVATE wallycore) 18 | add_test(test_coinselection test_coinselection) 19 | 20 | add_executable(test_descriptor test_descriptor.c) 21 | target_include_directories(test_descriptor PRIVATE ${CMAKE_BINARY_DIR}) 22 | target_link_libraries(test_descriptor PRIVATE wallycore) 23 | add_test(test_descriptor test_descriptor) 24 | 25 | add_executable(test_elements_tx test_elements_tx.c) 26 | target_include_directories(test_elements_tx PRIVATE ${CMAKE_BINARY_DIR}) 27 | target_link_libraries(test_elements_tx PRIVATE wallycore) 28 | add_test(test_elements_tx test_elements_tx) 29 | 30 | add_executable(test_psbt test_psbt.c) 31 | target_include_directories(test_psbt PRIVATE ${CMAKE_BINARY_DIR}) 32 | target_link_libraries(test_psbt PRIVATE wallycore) 33 | add_test(test_psbt test_psbt) 34 | 35 | add_executable(test_psbt_limits test_psbt_limits.c) 36 | target_include_directories(test_psbt_limits PRIVATE ${CMAKE_BINARY_DIR}) 37 | target_link_libraries(test_psbt_limits PRIVATE wallycore) 38 | add_test(test_psbt_limits test_psbt_limits) 39 | -------------------------------------------------------------------------------- /src/test/test_wordlist.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | from util import * 3 | 4 | class Wordlist: 5 | 6 | def __init__(self, words): 7 | 8 | self.wl = wordlist_init(utf8(words)) 9 | self.lookup_word = lambda w: wordlist_lookup_word(self.wl, w) 10 | self.lookup_index = lambda i: wordlist_lookup_index(self.wl, i) 11 | 12 | def free(self): 13 | if self.is_valid(): 14 | wordlist_free(self.wl) 15 | self.wl = None 16 | 17 | def is_valid(self): 18 | return self.wl is not None 19 | 20 | 21 | 22 | class WordlistTests(unittest.TestCase): 23 | 24 | words_list = None 25 | 26 | def setUp(self): 27 | if self.words_list is None and wordlist_init is not None: 28 | self.words_list, _ = load_words('english') 29 | 30 | @internal_only() 31 | def test_wordlist(self): 32 | 33 | for n in range(17): 34 | # Build a wordlist of n words 35 | test_list = self.words_list[0 : n] 36 | 37 | wl = Wordlist(' '.join(test_list)) 38 | self.assertTrue(wl.is_valid()) 39 | 40 | for idx, word in enumerate(test_list): 41 | w = utf8(word) 42 | # Verify lookup by word and index 43 | self.assertEqual(idx + 1, wl.lookup_word(w)) 44 | check_word = utf8(self.words_list[n + 1]) 45 | self.assertEqual(wl.lookup_word(check_word), 0) 46 | self.assertEqual(wl.lookup_index(idx), w) 47 | # Lookup of a non-present word 48 | self.assertIsNone(wl.lookup_index(n + 1)) 49 | 50 | wl.free() 51 | 52 | 53 | if __name__ == '__main__': 54 | unittest.main() 55 | -------------------------------------------------------------------------------- /src/ctaes/ctaes.h: -------------------------------------------------------------------------------- 1 | /********************************************************************* 2 | * Copyright (c) 2016 Pieter Wuille * 3 | * Distributed under the MIT software license, see the accompanying * 4 | * file COPYING or http://www.opensource.org/licenses/mit-license.php.* 5 | **********************************************************************/ 6 | 7 | #ifndef _CTAES_H_ 8 | #define _CTAES_H_ 1 9 | 10 | #include 11 | #include 12 | 13 | typedef struct { 14 | uint16_t slice[8]; 15 | } AES_state; 16 | 17 | typedef struct { 18 | AES_state rk[11]; 19 | } AES128_ctx; 20 | 21 | typedef struct { 22 | AES_state rk[13]; 23 | } AES192_ctx; 24 | 25 | typedef struct { 26 | AES_state rk[15]; 27 | } AES256_ctx; 28 | 29 | void AES128_init(AES128_ctx* ctx, const unsigned char* key16); 30 | void AES128_encrypt(const AES128_ctx* ctx, size_t blocks, unsigned char* cipher16, const unsigned char* plain16); 31 | void AES128_decrypt(const AES128_ctx* ctx, size_t blocks, unsigned char* plain16, const unsigned char* cipher16); 32 | 33 | void AES192_init(AES192_ctx* ctx, const unsigned char* key24); 34 | void AES192_encrypt(const AES192_ctx* ctx, size_t blocks, unsigned char* cipher16, const unsigned char* plain16); 35 | void AES192_decrypt(const AES192_ctx* ctx, size_t blocks, unsigned char* plain16, const unsigned char* cipher16); 36 | 37 | void AES256_init(AES256_ctx* ctx, const unsigned char* key32); 38 | void AES256_encrypt(const AES256_ctx* ctx, size_t blocks, unsigned char* cipher16, const unsigned char* plain16); 39 | void AES256_decrypt(const AES256_ctx* ctx, size_t blocks, unsigned char* plain16, const unsigned char* cipher16); 40 | 41 | #endif 42 | -------------------------------------------------------------------------------- /_CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.18) 2 | 3 | project( 4 | libwallycore 5 | VERSION 1.5.1 6 | DESCRIPTION "A collection of useful primitives for cryptocurrency wallets" 7 | LANGUAGES C 8 | ) 9 | set(CMAKE_EXPORT_COMPILE_COMMANDS ON) 10 | 11 | option(BUILD_SHARED_LIBS "Build as shared library" OFF) 12 | option(WALLYCORE_ENABLE_TESTS "Build tests" OFF) 13 | option(WALLYCORE_INSTALL "Enable install" OFF) 14 | option(WALLYCORE_COVERAGE "Enable coverage" OFF) 15 | option(WALLYCORE_BUILD_ELEMENTS "Build elements" ON) 16 | 17 | include(cmake/utils.cmake) 18 | generate_config_file() 19 | configure_file(src/ccan_config.h ccan_config.h COPYONLY) 20 | 21 | # libsec256k1-zkp 22 | set(SECP256K1_ENABLE_MODULE_ECDH ON) 23 | set(SECP256K1_ENABLE_MODULE_RECOVERY ON) 24 | set(SECP256K1_ENABLE_MODULE_EXTRAKEYS ON) 25 | set(SECP256K1_ENABLE_MODULE_SCHNORRSIG ON) 26 | set(SECP256K1_ENABLE_MODULE_ELLSWIFT OFF) 27 | set(SECP256K1_ENABLE_MODULE_GENERATOR ON) 28 | set(SECP256K1_ENABLE_MODULE_RANGEPROOF ON) 29 | set(SECP256K1_ENABLE_MODULE_SURJECTIONPROOF ON) 30 | set(SECP256K1_ENABLE_MODULE_WHITELIST ON) 31 | set(SECP256K1_ENABLE_MODULE_MUSIG OFF) 32 | set(SECP256K1_ENABLE_MODULE_ECDSA_ADAPTOR OFF) 33 | set(SECP256K1_ENABLE_MODULE_ECDSA_S2C ON) 34 | set(SECP256K1_ENABLE_MODULE_BPPP OFF) 35 | set(SECP256K1_BUILD_BENCHMARK OFF) 36 | set(SECP256K1_BUILD_TESTS OFF) 37 | set(SECP256K1_BUILD_EXHAUSTIVE_TESTS OFF) 38 | set(SECP256K1_BUILD_CTIME_TESTS OFF) 39 | set(SECP256K1_BUILD_EXAMPLES OFF) 40 | set(SECP256K1_INSTALL ${WALLYCORE_INSTALL}) 41 | add_subdirectory(./src/secp256k1/) 42 | 43 | add_subdirectory(./src) 44 | 45 | if(NOT WALLYCORE_ENABLE_TESTS) 46 | return() 47 | endif() 48 | 49 | enable_testing() 50 | add_subdirectory(src/ctest) 51 | -------------------------------------------------------------------------------- /src/ccan/ccan/crypto/ripemd160/test/run-types.c: -------------------------------------------------------------------------------- 1 | #include 2 | /* Include the C files directly. */ 3 | #include 4 | #include 5 | 6 | static unsigned char arr[] = { 7 | 0x12, 8 | #if HAVE_BIG_ENDIAN 9 | /* u16 */ 10 | 0x12, 0x34, 11 | /* u32 */ 12 | 0x12, 0x34, 0x56, 0x78, 13 | /* u64 */ 14 | 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 15 | #else 16 | /* u16 */ 17 | 0x34, 0x12, 18 | /* u32 */ 19 | 0x78, 0x56, 0x34, 0x12, 20 | /* u64 */ 21 | 0xf0, 0xde, 0xbc, 0x9a, 0x78, 0x56, 0x34, 0x12, 22 | #endif 23 | /* le16 */ 24 | 0x34, 0x12, 25 | /* le32 */ 26 | 0x78, 0x56, 0x34, 0x12, 27 | /* le64 */ 28 | 0xf0, 0xde, 0xbc, 0x9a, 0x78, 0x56, 0x34, 0x12, 29 | /* be16 */ 30 | 0x12, 0x34, 31 | /* be32 */ 32 | 0x12, 0x34, 0x56, 0x78, 33 | /* be64 */ 34 | 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0 35 | }; 36 | 37 | int main(void) 38 | { 39 | struct ripemd160 h, expected; 40 | struct ripemd160_ctx ctx; 41 | 42 | /* This is how many tests you plan to run */ 43 | plan_tests(1); 44 | 45 | ripemd160_init(&ctx); 46 | ripemd160_u8(&ctx, 0x12); 47 | ripemd160_u16(&ctx, 0x1234); 48 | ripemd160_u32(&ctx, 0x12345678); 49 | ripemd160_u64(&ctx, 0x123456789abcdef0ULL); 50 | ripemd160_le16(&ctx, 0x1234); 51 | ripemd160_le32(&ctx, 0x12345678); 52 | ripemd160_le64(&ctx, 0x123456789abcdef0ULL); 53 | ripemd160_be16(&ctx, 0x1234); 54 | ripemd160_be32(&ctx, 0x12345678); 55 | ripemd160_be64(&ctx, 0x123456789abcdef0ULL); 56 | ripemd160_done(&ctx, &h); 57 | 58 | ripemd160(&expected, arr, sizeof(arr)); 59 | ok1(memcmp(&h, &expected, sizeof(h)) == 0); 60 | 61 | /* This exits depending on whether all tests passed */ 62 | return exit_status(); 63 | } 64 | -------------------------------------------------------------------------------- /src/ccan/ccan/tap/_info: -------------------------------------------------------------------------------- 1 | #include "config.h" 2 | #include 3 | #include 4 | 5 | /** 6 | * tap - Test Anything Protocol 7 | * 8 | * The tap package produces simple-to-parse mainly-human-readable test 9 | * output to assist in the writing of test cases. It is based on the 10 | * (now-defunct) libtap, which is based on Perl's CPAN TAP module. Its 11 | * output can be parsed by a harness such as CPAN's Prove. 12 | * 13 | * CCAN testcases are expected to output the TAP format, usually using 14 | * this package. 15 | * 16 | * For more information about TAP, see: 17 | * http://en.wikipedia.org/wiki/Test_Anything_Protocol 18 | * 19 | * Based on the original libtap, Copyright (c) 2004 Nik Clayton. 20 | * 21 | * License: BSD (2 clause) 22 | * 23 | * Example: 24 | * #include 25 | * #include 26 | * 27 | * // Run some simple (but overly chatty) tests on strcmp(). 28 | * int main(int argc, char *argv[]) 29 | * { 30 | * const char a[] = "a", another_a[] = "a"; 31 | * const char b[] = "b"; 32 | * const char ab[] = "ab"; 33 | * 34 | * plan_tests(4); 35 | * diag("Testing different pointers (%p/%p) with same contents", 36 | * a, another_a); 37 | * ok1(strcmp(a, another_a) == 0); 38 | * 39 | * diag("'a' comes before 'b'"); 40 | * ok1(strcmp(a, b) < 0); 41 | * ok1(strcmp(b, a) > 0); 42 | * 43 | * diag("'ab' comes after 'a'"); 44 | * ok1(strcmp(ab, a) > 0); 45 | * return exit_status(); 46 | * } 47 | * 48 | * Maintainer: Rusty Russell 49 | */ 50 | int main(int argc, char *argv[]) 51 | { 52 | if (argc != 2) 53 | return 1; 54 | 55 | if (strcmp(argv[1], "depends") == 0) { 56 | printf("ccan/compiler\n"); 57 | return 0; 58 | } 59 | 60 | return 1; 61 | } 62 | -------------------------------------------------------------------------------- /src/swig_python/contrib/signmessage.py: -------------------------------------------------------------------------------- 1 | """A simple example of signing and verifying a message as in Bitcoin Core""" 2 | import unittest 3 | import base64 4 | from wallycore import * 5 | 6 | 7 | class SignMessageTest(unittest.TestCase): 8 | 9 | WIF_PREFIX = 0xef 10 | ADD_PREFIX = 0x6f 11 | 12 | def signmessage(self, priv_key_wif, message): 13 | priv_key = wif_to_bytes(priv_key_wif, self.WIF_PREFIX, WALLY_WIF_FLAG_COMPRESSED) 14 | msg_fmt = format_bitcoin_message(message, BITCOIN_MESSAGE_FLAG_HASH) 15 | sig_bytes = ec_sig_from_bytes(priv_key, msg_fmt, EC_FLAG_ECDSA | EC_FLAG_RECOVERABLE) 16 | return base64.b64encode(sig_bytes) 17 | 18 | def verifymessage(self, address, signature, message): 19 | msg_fmt = format_bitcoin_message(message, BITCOIN_MESSAGE_FLAG_HASH) 20 | sig_bytes = base64.b64decode(signature) 21 | pub_key_rec = ec_sig_to_public_key(msg_fmt, sig_bytes) 22 | address_rec = base58check_from_bytes(bytearray([self.ADD_PREFIX]) + hash160(pub_key_rec)) 23 | return address == address_rec 24 | 25 | def test_signmessage(self): 26 | # values from Bitcoin Core tests 27 | message = 'This is just a test message'.encode('ascii') 28 | priv_key_wif = 'cUeKHd5orzT3mz8P9pxyREHfsWtVfgsfDjiZZBcjUBAaGk1BTj7N' 29 | address = 'mpLQjfK79b7CCV4VMJWEWAj5Mpx8Up5zxB' 30 | expected_signature = b'INbVnW4e6PeRmsv2Qgu8NuopvrVjkcxob+sX8OcZG0SALhWybUjzMLPdAsXI46YZGb0KQTRii+wWIQzRpG/U+S0=' 31 | 32 | signature = self.signmessage(priv_key_wif, message) 33 | self.assertEqual(signature, expected_signature) 34 | self.assertTrue(self.verifymessage(address, signature, message)) 35 | 36 | 37 | if __name__ == '__main__': 38 | unittest.main() 39 | -------------------------------------------------------------------------------- /contrib/gitian-descriptors/libwally-core-android.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: "libwally-core-linux" 3 | enable_cache: false 4 | suites: 5 | - "trusty" 6 | architectures: 7 | - "amd64" 8 | packages: 9 | - "gcc-arm-linux-androideabi" 10 | - "git-core" 11 | - "pkg-config" 12 | - "autoconf" 13 | - "libtool" 14 | - "automake" 15 | - "faketime" 16 | - "bsdmainutils" 17 | - "ca-certificates" 18 | - "python" 19 | remotes: 20 | - "dir": "libwally-core" 21 | "url": "https://github.com/ElementsProject/libwally-core.git" 22 | files: [] 23 | script: | 24 | 25 | HOSTS="arm-linux-androideabi" 26 | CONFIGFLAGS="CFLAGS=-D__STDC_INT64__" 27 | DISTNAME='libwally-core' 28 | 29 | export GZIP="-9n" 30 | export TAR_OPTIONS="--mtime="$REFERENCE_DATE\\\ $REFERENCE_TIME"" 31 | export TZ="UTC" 32 | export BUILD_DIR=`pwd` 33 | 34 | SOURCEDIST="$HOME/libwallet-core.tar" 35 | 36 | cd "${DISTNAME}" 37 | tools/autogen.sh 38 | tar -cvpf "${SOURCEDIST}" . --exclude=.git 39 | 40 | ORIGPATH="$PATH" 41 | # Extract the release tarball into a dir for each host and build 42 | for i in ${HOSTS}; do 43 | export PATH=${BASEPREFIX}/${i}/native/bin:${ORIGPATH} 44 | mkdir -p distsrc-${i} 45 | cd distsrc-${i} 46 | INSTALLPATH=`pwd`/installed/${DISTNAME} 47 | mkdir -p ${INSTALLPATH} 48 | tar -xf $SOURCEDIST 49 | 50 | ./configure --host="$i" --prefix=/ --disable-maintainer-mode --disable-dependency-tracking ${CONFIGFLAGS} 51 | make ${MAKEOPTS} 52 | 53 | make install DESTDIR=${INSTALLPATH} 54 | cd installed 55 | "${i}-strip" --strip-unneeded "${DISTNAME}"/lib/libwallycore.so 56 | ls "${DISTNAME}"/lib/libwallycore* | sort | tar --no-recursion --mode='u+rw,go+r-w,a+X' --owner=0 --group=0 -c -T - | gzip -9n > ${OUTDIR}/${DISTNAME}-${i}.tar.gz 57 | cd ../../ 58 | rm -rf distsrc-${i} 59 | done 60 | -------------------------------------------------------------------------------- /src/ccan_config.h: -------------------------------------------------------------------------------- 1 | #ifndef _WALLY_CCAN_CONFIG_H_ 2 | #define _WALLY_CCAN_CONFIG_H_ 1 3 | 4 | /* Config directives for ccan */ 5 | 6 | #include 7 | 8 | #ifdef WORDS_BIGENDIAN 9 | # define HAVE_BIG_ENDIAN 1 10 | # define HAVE_LITTLE_ENDIAN 0 11 | #else 12 | # define HAVE_BIG_ENDIAN 0 13 | # define HAVE_LITTLE_ENDIAN 1 14 | #endif 15 | 16 | #ifdef __GNUC__ 17 | # define HAVE_ATTRIBUTE_COLD 1 18 | # define HAVE_ATTRIBUTE_NORETURN 1 19 | # define HAVE_ATTRIBUTE_PRINTF 1 20 | # define HAVE_ATTRIBUTE_CONST 1 21 | # define HAVE_ATTRIBUTE_PURE 1 22 | # define HAVE_ATTRIBUTE_UNUSED 1 23 | # define HAVE_ATTRIBUTE_USED 1 24 | # define HAVE_BUILTIN_CONSTANT_P 1 25 | # define HAVE_WARN_UNUSED_RESULT 1 26 | #endif 27 | 28 | #ifdef HAVE_BYTESWAP_H 29 | #define HAVE_BSWAP_64 1 30 | #else 31 | #define HAVE_BYTESWAP_H 0 32 | #define HAVE_BSWAP_64 0 33 | #endif 34 | 35 | #if defined(HAVE_UNALIGNED_ACCESS) && defined(__arm__) 36 | /* arm unaligned access is incomplete, in that e.g. byte swap instructions 37 | * can fault on unaligned addresses where a normal load/store would be fine. 38 | * Since the compiler can optimise some of our accesses into operations like 39 | * byte swaps, treat this platform as though it doesn't have unaligned access. 40 | */ 41 | #undef HAVE_UNALIGNED_ACCESS 42 | #define HAVE_UNALIGNED_ACCESS 0 43 | #endif 44 | 45 | #if HAVE_UNALIGNED_ACCESS 46 | #define alignment_ok(p, n) 1 47 | #else 48 | #define alignment_ok(p, n) ((size_t)(p) % (n) == 0) 49 | #endif 50 | 51 | #ifdef HAVE_MBEDTLS_SHA256_H 52 | #define CCAN_CRYPTO_SHA256_USE_MBEDTLS 1 53 | #endif 54 | 55 | #ifdef HAVE_MBEDTLS_SHA512_H 56 | #define CCAN_CRYPTO_SHA512_USE_MBEDTLS 1 57 | #endif 58 | 59 | void wally_clear(void *p, size_t len); 60 | 61 | #define CCAN_CLEAR_MEMORY(p, len) wally_clear(p, len) 62 | 63 | #endif /*_WALLY_CCAN_CONFIG_H_ */ 64 | -------------------------------------------------------------------------------- /tools/build_android_libraries.sh: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env bash 2 | # 3 | # Build native android libraries with JNI bindings, for use with C or Java. 4 | # Requires JAVA_HOME and ANDROID_NDK to be set. 5 | # 6 | set -e 7 | 8 | if [ ! -f "src/secp256k1/Makefile.am" ]; then 9 | git submodule sync --recursive 10 | git submodule update --init --recursive 11 | fi 12 | 13 | if [ -z "$ANDROID_NDK" ]; then 14 | export ANDROID_NDK=$(dirname `command -v ndk-build 2>/dev/null`) 15 | fi 16 | echo ${ANDROID_NDK:?} 17 | if [ -z "$JAVA_HOME" ]; then 18 | export JAVA_HOME=$JAVA7_HOME 19 | fi 20 | echo ${JAVA_HOME:?} 21 | 22 | source $PWD/tools/android_helpers.sh 23 | 24 | $PWD/tools/cleanup.sh && $PWD/tools/autogen.sh 25 | 26 | # Build everything unless the user passed a single target name 27 | ARCH_LIST=$(android_get_arch_list) 28 | if [ -n "$1" ]; then 29 | ARCH_LIST="$1" 30 | fi 31 | 32 | for arch in $ARCH_LIST; do 33 | # Use API level 23 34 | api="23" 35 | 36 | # Location of the NDK tools to build with 37 | toolsdir=$(android_get_build_tools_dir) 38 | 39 | # Extra configure options 40 | useropts="" 41 | 42 | # Configure and build with the above options 43 | android_build_wally $arch $toolsdir $api $useropts 44 | 45 | # Copy and strip the build result 46 | archdir=$PWD/release/lib/$arch 47 | mkdir -p $archdir 48 | $toolsdir/bin/llvm-strip -o $archdir/libwallycore.so $PWD/src/.libs/libwallycore.so 49 | done 50 | 51 | # Copy headers and Java wrapper 52 | # The android release files can be used from Java or in native code 53 | mkdir -p $PWD/release/include $PWD/release/src/swig_java/src/com/blockstream/libwally 54 | cp $PWD/include/*.h $PWD/release/include 55 | cp $PWD/src/swig_java/src/com/blockstream/libwally/Wally.java $PWD/release/src/swig_java/src/com/blockstream/libwally 56 | -------------------------------------------------------------------------------- /src/ccan/ccan/compiler/_info: -------------------------------------------------------------------------------- 1 | #include "config.h" 2 | #include 3 | #include 4 | 5 | /** 6 | * compiler - macros for common compiler extensions 7 | * 8 | * Abstracts away some compiler hints. Currently these include: 9 | * - COLD 10 | * For functions not called in fast paths (aka. cold functions) 11 | * - PRINTF_FMT 12 | * For functions which take printf-style parameters. 13 | * - CONST_FUNCTION 14 | * For functions which return the same value for same parameters. 15 | * - NEEDED 16 | * For functions and variables which must be emitted even if unused. 17 | * - UNNEEDED 18 | * For functions and variables which need not be emitted if unused. 19 | * - UNUSED 20 | * For parameters which are not used. 21 | * - IS_COMPILE_CONSTANT() 22 | * For using different tradeoffs for compiletime vs runtime evaluation. 23 | * 24 | * License: CC0 (Public domain) 25 | * Author: Rusty Russell 26 | * 27 | * Example: 28 | * #include 29 | * #include 30 | * #include 31 | * 32 | * // Example of a (slow-path) logging function. 33 | * static int log_threshold = 2; 34 | * static void COLD PRINTF_FMT(2,3) 35 | * logger(int level, const char *fmt, ...) 36 | * { 37 | * va_list ap; 38 | * va_start(ap, fmt); 39 | * if (level >= log_threshold) 40 | * vfprintf(stderr, fmt, ap); 41 | * va_end(ap); 42 | * } 43 | * 44 | * int main(int argc, char *argv[]) 45 | * { 46 | * if (argc != 1) { 47 | * logger(3, "Don't want %i arguments!\n", argc-1); 48 | * return 1; 49 | * } 50 | * return 0; 51 | * } 52 | */ 53 | int main(int argc, char *argv[]) 54 | { 55 | /* Expect exactly one argument */ 56 | if (argc != 2) 57 | return 1; 58 | 59 | if (strcmp(argv[1], "depends") == 0) { 60 | return 0; 61 | } 62 | 63 | return 1; 64 | } 65 | -------------------------------------------------------------------------------- /src/wasm_package/test/scrypt.js: -------------------------------------------------------------------------------- 1 | import test from 'test' 2 | import assert from 'assert' 3 | import wally from '../src/index.js' 4 | 5 | const cases = [ 6 | ["", "", 7 | 16, 1, 1, 64, 8 | '77 d6 57 62 38 65 7b 20 3b 19 ca 42 c1 8a 04 97' + 9 | 'f1 6b 48 44 e3 07 4a e8 df df fa 3f ed e2 14 42' + 10 | 'fc d0 06 9d ed 09 48 f8 32 6a 75 3a 0f c8 1f 17' + 11 | 'e8 d3 e0 fb 2e 0d 36 28 cf 35 e2 0c 38 d1 89 06'], 12 | 13 | ['password', 'NaCl', 14 | 1024, 8, 16, 64, 15 | 'fd ba be 1c 9d 34 72 00 78 56 e7 19 0d 01 e9 fe' + 16 | '7c 6a d7 cb c8 23 78 30 e7 73 76 63 4b 37 31 62' + 17 | '2e af 30 d9 2e 22 a3 88 6f f1 09 27 9d 98 30 da' + 18 | 'c7 27 af b9 4a 83 ee 6d 83 60 cb df a2 cc 06 40'], 19 | 20 | /* These require too much memory for a WASM env and fail with OOM 21 | ['pleaseletmein', 'SodiumChloride', 22 | 16384, 8, 1, 64, 23 | '70 23 bd cb 3a fd 73 48 46 1c 06 cd 81 fd 38 eb' + 24 | 'fd a8 fb ba 90 4f 8e 3e a9 b5 43 f6 54 5d a1 f2' + 25 | 'd5 43 29 55 61 3f 0f cf 62 d4 97 05 24 2a 9a f9' + 26 | 'e6 1e 85 dc 0d 65 1e 40 df cf 01 7b 45 57 58 87'] 27 | ['pleaseletmein', 'SodiumChloride', 28 | 1048576, 8, 1, 64, 29 | '21 01 cb 9b 6a 51 1a ae ad db be 09 cf 70 f8 81' + 30 | 'ec 56 8d 57 4a 2f fd 4d ab e5 ee 98 20 ad aa 47' + 31 | '8e 56 fd 8f 4b a5 d0 9f fa 1c 6d 92 7c 40 f4 c3' + 32 | '37 30 40 49 e8 a9 52 fb cb f4 5c 6f a7 7a 41 a4'] */ 33 | ] 34 | 35 | test('scrypt', () => { 36 | cases.forEach(c => { 37 | c[0] = Buffer.from(c[0]) 38 | c[1] = Buffer.from(c[1]) 39 | const expected = Buffer.from(c.pop().replace(/ /g, ''), 'hex') 40 | const result = wally.scrypt(...c) 41 | assert.deepEqual(result, expected, 'scrypt(' + c + ')') 42 | }) 43 | }) -------------------------------------------------------------------------------- /src/wasm_package/README.md: -------------------------------------------------------------------------------- 1 | # libwally JS 2 | 3 | Official Blockstream WASM-based JavaScript bindings for [libwally](https://github.com/elementsproject/libwally-core), 4 | for nodejs and the browser. 5 | 6 | ## Installation 7 | 8 | ```bash 9 | $ npm install wallycore 10 | ``` 11 | 12 | ## Example use 13 | 14 | With ES modules: 15 | 16 | ```js 17 | import wally from 'wallycore' 18 | 19 | const word = wally.bip39_get_word(null, 10) 20 | 21 | const script = wally.address_to_scriptpubkey("1EMBaSSyxMQPV2fmUsdB7mMfMoocgfiMNw", wally.WALLY_NETWORK_BITCOIN_MAINNET) 22 | 23 | const tx = wally.tx_from_hex('020000000100000000000000000000000000000000000000000000000000000000000000000000000000fdffffff0101000000000000000000000000', 0) 24 | console.log(wally.tx_get_txid(tx).toString('hex')) 25 | wally.tx_free(tx) 26 | ``` 27 | 28 | If you're using CommonJS, the module can be loaded asynchronously using `const wally = await import('wallycore')` or `import('wallycore').then(wally => { ... })`. 29 | 30 | For browser use, you may use a bundler like [webpack](https://webpack.js.org/), 31 | or use the pre-bundled [`wallycore.bundle.js`](wallycore.bundle.js) file which exposes a global `WallyInit` promise that resolves to the module. For example: 32 | 33 | ```html 34 | 35 | 41 | ``` 42 | 43 | ## Limitations 44 | 45 | - BIP38 (passphrase-protected keys) [related functions](https://wally.readthedocs.io/en/latest/bip38/) are disabled due to WASM memory restrictions, which are insufficient for running Scrypt with the BIP38 parameters. 46 | 47 | ## License 48 | [BSD/MIT](https://github.com/ElementsProject/libwally-core/blob/master/LICENSE) 49 | -------------------------------------------------------------------------------- /tools/build_wasm.sh: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env bash 2 | 3 | set -e 4 | 5 | DISABLE_ELEMENTS="" 6 | if [ "$1" = "--disable-elements" ]; then 7 | DISABLE_ELEMENTS="--disable-elements --disable-elements-abi" 8 | shift 9 | fi 10 | 11 | num_jobs=4 12 | if [ -f /proc/cpuinfo ]; then 13 | num_jobs=$(grep ^processor /proc/cpuinfo | wc -l) 14 | fi 15 | 16 | if ! type -P emcc > /dev/null; then 17 | # Setup the emsdk environment if it isn't already 18 | source /opt/emsdk/emsdk_env.sh 19 | fi 20 | 21 | $PWD/tools/cleanup.sh && $PWD/tools/autogen.sh 22 | 23 | # Note: This doesn't work yet, see https://github.com/emscripten-core/emscripten/issues/6233 24 | # we pass --enable-export-all to prevent library symbols from being hidden, 25 | # the wasm build then makes visible only the functions marked EMSCRIPTEN_KEEPALIVE. 26 | #trap "sed -i 's/EMSCRIPTEN_KEEPALIVE/WALLY_CORE_API/g' include/*.h src/*.h" ERR EXIT 27 | #sed -i 's/WALLY_CORE_API/EMSCRIPTEN_KEEPALIVE/g' include/*.h src/*.h 28 | 29 | export CFLAGS="-fno-stack-protector" 30 | emconfigure ./configure --build=$HOST_OS ac_cv_c_bigendian=no --disable-swig-python --disable-swig-java $DISABLE_ELEMENTS --disable-tests --enable-export-all --enable-wasm-interface 31 | emmake make -j $num_jobs 32 | 33 | : ${EMCC_OPTIONS:="-s EXPORT_ES6=1 -s WASM_BIGINT"} 34 | : ${OPTIMIZATION_LEVEL:=3} 35 | : ${EXPORTED_RUNTIME_METHODS:='cwrap,ccall,getValue,UTF8ToString'} 36 | # Get the list of functions to export 37 | source ./tools/wasm_exports.sh 38 | 39 | mkdir -p dist 40 | 41 | emcc -O$OPTIMIZATION_LEVEL \ 42 | -s "EXPORTED_RUNTIME_METHODS=$EXPORTED_RUNTIME_METHODS" \ 43 | -s "EXPORTED_FUNCTIONS=$EXPORTED_FUNCTIONS" \ 44 | -s FILESYSTEM=0 \ 45 | $EMCC_OPTIONS \ 46 | ./src/.libs/*.o src/secp256k1/src/*.o src/ccan/ccan/*/.libs/*.o src/ccan/ccan/*/*/.libs/*.o \ 47 | -o dist/wallycore.js 48 | -------------------------------------------------------------------------------- /src/wordlist.h: -------------------------------------------------------------------------------- 1 | #ifndef LIBWALLY_WORDLIST_H 2 | #define LIBWALLY_WORDLIST_H 3 | 4 | #include 5 | #include 6 | 7 | /** 8 | * struct words- structure representing a parsed list of words 9 | */ 10 | struct words { 11 | /* Number of words in the list */ 12 | size_t len; 13 | /* Number of bits representable by this word list */ 14 | size_t bits; 15 | /* Is the word list sorted by unicode code point order? */ 16 | bool sorted; 17 | /* The underlying string (tokenised, containing embedded NULs) */ 18 | const char *str; 19 | /* The length of str, or 0 if str points to constant storage */ 20 | size_t str_len; 21 | /* Pointers to the individual words */ 22 | const char **indices; 23 | }; 24 | 25 | /** 26 | * Initialize a words structure. 27 | * 28 | * @text: List of words to initialize from, split by whitespace and 29 | * NUL terminated. Must be UTF-8 encoded. 30 | * 31 | * The returned structure contains a copy of @text. 32 | */ 33 | struct words *wordlist_init(const char *text); 34 | 35 | /** 36 | * Find a word in a wordlist. 37 | * 38 | * @w: Parsed list of words to look up in. 39 | * @word: The word to look up. 40 | * 41 | * Returns 0 if not found, idx + 1 otherwise. 42 | * @see wordlist_init. 43 | */ 44 | size_t wordlist_lookup_word( 45 | const struct words *w, 46 | const char *word); 47 | 48 | /** 49 | * Return the Nth word in a wordlist. 50 | * 51 | * @w: Parsed list of words to look up in. 52 | * @idx: The index to look up. 53 | * 54 | * Returns NULL if not found, the word otherwise. 55 | */ 56 | const char *wordlist_lookup_index( 57 | const struct words *w, 58 | size_t idx); 59 | 60 | /** 61 | * wordlist_free - Free a words structure. 62 | * @w: structure to free. 63 | */ 64 | void wordlist_free(struct words *w); 65 | 66 | #endif /* LIBWALLY_WORDLIST_H */ 67 | -------------------------------------------------------------------------------- /src/ccan/ccan/crypto/sha256/test/run-33-bit-test.c: -------------------------------------------------------------------------------- 1 | #include 2 | /* Include the C files directly. */ 3 | #include 4 | #include 5 | #include 6 | 7 | /* This is the test introduced for SHA-3, which checks for 33-bit overflow: 8 | "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmno" 9 | 16777216 times. 10 | */ 11 | static uint32_t expected[] = { 12 | CPU_TO_BE32(0x50e72a0e), CPU_TO_BE32(0x26442fe2), 13 | CPU_TO_BE32(0x552dc393), CPU_TO_BE32(0x8ac58658), 14 | CPU_TO_BE32(0x228c0cbf), CPU_TO_BE32(0xb1d2ca87), 15 | CPU_TO_BE32(0x2ae43526), CPU_TO_BE32(0x6fcd055e) 16 | }; 17 | 18 | /* Produced by actually running the code on x86. */ 19 | static const struct sha256_ctx after_16M_by_64 = { 20 | #ifdef CCAN_CRYPTO_SHA256_USE_OPENSSL 21 | { { LE32_TO_CPU(0x515e3215), LE32_TO_CPU(0x592f4ae0), 22 | LE32_TO_CPU(0xd407a8fc), LE32_TO_CPU(0x1fad409b), 23 | LE32_TO_CPU(0x51fa46cc), LE32_TO_CPU(0xea528ae5), 24 | LE32_TO_CPU(0x5fa58ebb), LE32_TO_CPU(0x8be97931) }, 25 | 0x0, 0x2, 26 | { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, 27 | 0x0, 0x20 } 28 | #else 29 | { LE32_TO_CPU(0x515e3215), LE32_TO_CPU(0x592f4ae0), 30 | LE32_TO_CPU(0xd407a8fc), LE32_TO_CPU(0x1fad409b), 31 | LE32_TO_CPU(0x51fa46cc), LE32_TO_CPU(0xea528ae5), 32 | LE32_TO_CPU(0x5fa58ebb), LE32_TO_CPU(0x8be97931) }, 33 | 1073741824, 34 | { .u32 = { 0x64636261, 0x68676665, 0x65646362, 0x69686766, 35 | 0x66656463, 0x6a696867, 0x67666564, 0x6b6a6968 } } 36 | #endif 37 | }; 38 | 39 | int main(void) 40 | { 41 | struct sha256 h; 42 | struct sha256_ctx ctx; 43 | 44 | /* This is how many tests you plan to run */ 45 | plan_tests(1); 46 | 47 | ctx = after_16M_by_64; 48 | sha256_done(&ctx, &h); 49 | 50 | ok1(memcmp(&h.u, expected, sizeof(expected)) == 0); 51 | 52 | /* This exits depending on whether all tests passed */ 53 | return exit_status(); 54 | } 55 | -------------------------------------------------------------------------------- /tools/wordlist_cc.py: -------------------------------------------------------------------------------- 1 | import sys 2 | 3 | def as_hex(s): 4 | return ','.join([hex(c) for c in s.encode('utf8')]) 5 | 6 | if __name__ == "__main__": 7 | 8 | bits = { 2 ** x : x for x in range(12) } # Up to 4k words 9 | wordlist = sys.argv[1] 10 | struct_name = '%s_words' % sys.argv[2] 11 | string_name = '%s' % sys.argv[2] 12 | 13 | with open(wordlist, 'r') as f: 14 | 15 | words = [l.strip() for l in f.readlines()] 16 | is_sorted = sorted(words) == words 17 | assert len(words) >= 2 18 | assert len(words) in bits 19 | 20 | lengths = [ 0 ] 21 | for w in words: 22 | lengths.append(lengths[-1] + len(w.encode('utf-8')) + 1) 23 | idxs = ['{0}+{1}'.format(string_name, n) for n in lengths] 24 | 25 | print('/* Generated file - do not edit! */') 26 | print('#include ') 27 | print() 28 | 29 | print('static const unsigned char %s_[] = {' % string_name) 30 | grouped = [words[i : i + 4] for i in range(0, len(words), 4)] 31 | for w in words: 32 | print(' %s,0,' % as_hex(w)) 33 | print('};') 34 | 35 | print('#define %s ((const char*)%s_)' % (string_name, string_name)) 36 | 37 | print('static const char *%s_i[] = {' % (string_name)) 38 | grouped = [idxs[i : i + 6] for i in range(0, len(idxs), 6)] 39 | for g in grouped: 40 | print(' %s,' % (', '.join(g))) 41 | print(' };') 42 | print('#undef %s' % string_name) 43 | 44 | print() 45 | print('static const struct words %s = {' % struct_name) 46 | print(' {0},'.format(len(words))) 47 | print(' {0},'.format(bits[len(words)])) 48 | print(' {0},'.format(str(is_sorted).lower())) 49 | print(' (const char *)%s_,' % string_name) 50 | print(' 0, /* Constant string */') 51 | print(' %s_i' % string_name) 52 | print('};') 53 | -------------------------------------------------------------------------------- /docs/source/conventions.rst: -------------------------------------------------------------------------------- 1 | Library Conventions 2 | =================== 3 | 4 | .. _error-codes: 5 | 6 | Error Codes 7 | ----------- 8 | 9 | The following values can be returned by library functions: 10 | 11 | ================ ============================================= 12 | Code Meaning 13 | ================ ============================================= 14 | ``WALLY_OK`` The function completed without error. 15 | See :ref:`variable-length-output-buffers` if 16 | applicable for the function. 17 | ``WALLY_ERROR`` An internal or unexpected error happened in 18 | the library. In some cases this code may 19 | indicate a specific error condition which 20 | will be documented with the function. 21 | ``WALLY_EINVAL`` One or more parameters passed to the function 22 | is not valid. For example, a required buffer 23 | value is NULL or of the wrong length. 24 | ``WALLY_ENOMEM`` The function required memory allocation but 25 | no memory could be allocated from the O/S. 26 | ================ ============================================= 27 | 28 | 29 | .. _variable-length-output-buffers: 30 | 31 | Variable Length Output Buffers 32 | ------------------------------ 33 | 34 | Some functions write output that can vary in length to user supplied buffers. 35 | In these cases, the number of written bytes is placed in the ``written`` 36 | output parameter when the function completes. 37 | 38 | If the user supplied buffer is of insufficient size, these functions will 39 | still return ``WALLY_OK``, but will place the required size in the ``written`` 40 | output parameter. 41 | 42 | Callers must check not only that the function succeeds, but also that the 43 | number of bytes written is less than or equal to the supplied buffer size. 44 | If the buffer is too small, it should be resized to the returned size and the 45 | call retried. 46 | -------------------------------------------------------------------------------- /src/test/test_ecdh.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | from util import * 3 | 4 | 5 | class ECDHTests(unittest.TestCase): 6 | 7 | def priv_to_pub(self, priv): 8 | pub, _ = make_cbuffer('00'*33) 9 | ret = wally_ec_public_key_from_private_key(priv, len(priv), pub, len(pub)) 10 | self.assertEqual(ret, WALLY_OK) 11 | return pub 12 | 13 | def test_ecdh(self): 14 | """Tests for ECDH""" 15 | 16 | priv1, _ = make_cbuffer('aa'*32) 17 | priv2, _ = make_cbuffer('bb'*32) 18 | pub1 = self.priv_to_pub(priv1) 19 | pub2 = self.priv_to_pub(priv2) 20 | 21 | out12, _ = make_cbuffer('00'*32) 22 | out21, _ = make_cbuffer('00'*32) 23 | ret = wally_ecdh(pub1, len(pub1), priv2, len(priv2), out12, len(out12)) 24 | self.assertEqual(ret, WALLY_OK) 25 | ret = wally_ecdh(pub2, len(pub2), priv1, len(priv1), out21, len(out21)) 26 | self.assertEqual(ret, WALLY_OK) 27 | 28 | self.assertEqual(out12, out21) 29 | 30 | out, _ = make_cbuffer('00'*32) 31 | priv_bad, _ = make_cbuffer('00'*32) 32 | pub_bad, _ = make_cbuffer('02' + '00'*32) 33 | 34 | for args in [ 35 | (None, 32, pub1, 32, out, 32), # Missing private key 36 | (priv_bad, 32, pub1, 33, out, 32), # Invalid private key 37 | (priv1, 31, pub1, 32, out, 32), # Invalid private key length 38 | (priv1, 32, None, 33, out, 32), # Missing public key 39 | (priv1, 32, pub_bad, 33, out, 32), # Invalid public key 40 | (priv1, 32, pub1, 32, out, 32), # Invalid public key length 41 | (priv1, 32, pub1, 32, None, 32), # Missing output 42 | (priv1, 32, pub1, 33, out, 31), # Invalid output length 43 | ]: 44 | self.assertEqual(WALLY_EINVAL, wally_ecdh(*args)) 45 | self.assertEqual(h(out), utf8('00'*32)) 46 | 47 | 48 | if __name__ == '__main__': 49 | unittest.main() 50 | -------------------------------------------------------------------------------- /src/bip32_int.h: -------------------------------------------------------------------------------- 1 | #ifndef LIBWALLY_CORE_BIP32_INT_H 2 | #define LIBWALLY_CORE_BIP32_INT_H 1 3 | 4 | #ifdef __cplusplus 5 | extern "C" { 6 | #endif 7 | 8 | #if defined(SWIG) || defined (SWIG_JAVA_BUILD) || defined (SWIG_PYTHON_BUILD) || defined(SWIG_JAVASCRIPT_BUILD) || defined(WASM_BUILD) 9 | 10 | /** 11 | * FIXED_SIZED_OUTPUT(len, bytes_out, WALLY_BIP32_CHAIN_CODE_LEN) 12 | */ 13 | WALLY_CORE_API int bip32_key_get_chain_code(const struct ext_key *hdkey, unsigned char *bytes_out, size_t len); 14 | 15 | /** 16 | * FIXED_SIZED_OUTPUT(len, bytes_out, HASH160_LEN) 17 | */ 18 | WALLY_CORE_API int bip32_key_get_parent160(const struct ext_key *hdkey, unsigned char *bytes_out, size_t len); 19 | 20 | /** 21 | * FIXED_SIZED_OUTPUT(len, bytes_out, EC_PRIVATE_KEY_LEN) 22 | */ 23 | WALLY_CORE_API int bip32_key_get_priv_key(const struct ext_key *hdkey, unsigned char *bytes_out, size_t len); 24 | 25 | /** 26 | * FIXED_SIZED_OUTPUT(len, bytes_out, HASH160_LEN) 27 | */ 28 | WALLY_CORE_API int bip32_key_get_hash160(const struct ext_key *hdkey, unsigned char *bytes_out, size_t len); 29 | 30 | /** 31 | * FIXED_SIZED_OUTPUT(len, bytes_out, EC_PUBLIC_KEY_LEN) 32 | */ 33 | WALLY_CORE_API int bip32_key_get_pub_key(const struct ext_key *hdkey, unsigned char *bytes_out, size_t len); 34 | 35 | #ifndef WALLY_ABI_NO_ELEMENTS 36 | 37 | /** 38 | * FIXED_SIZED_OUTPUT(len, bytes_out, WALLY_BIP32_TWEAK_SUM_LEN) 39 | */ 40 | WALLY_CORE_API int bip32_key_get_pub_key_tweak_sum(const struct ext_key *hdkey, unsigned char *bytes_out, size_t len); 41 | 42 | #endif /* WALLY_ABI_NO_ELEMENTS */ 43 | 44 | WALLY_CORE_API int bip32_key_get_depth(const struct ext_key *hdkey, size_t *written); 45 | WALLY_CORE_API int bip32_key_get_child_num(const struct ext_key *hdkey, size_t *written); 46 | WALLY_CORE_API int bip32_key_get_version(const struct ext_key *hdkey, size_t *written); 47 | 48 | #endif /* SWIG/SWIG_JAVA_BUILD/SWIG_JAVA_BUILD/SWIG_PYTHON_BUILD */ 49 | 50 | #ifdef __cplusplus 51 | } 52 | #endif 53 | 54 | 55 | #endif /* LIBWALLY_CORE_BIP32_INT_H */ 56 | -------------------------------------------------------------------------------- /tools/cleanup.sh: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env bash 2 | 3 | # Clean up all generated files 4 | make -o configure distclean >/dev/null 2>&1 5 | 6 | find src -name Makefile -exec rm {} \; 7 | find src -name Makefile.in -exec rm {} \; 8 | find . -name "*.class" -exec rm {} \; 9 | find . -name "*.gcno" -exec rm {} \; 10 | find . -name "*.gcda" -exec rm {} \; 11 | find . -name "*.egg-info" -exec rm -rf {} 2>/dev/null \; 12 | find . -name "__pycache__" -exec rm -rf {} 2>/dev/null \; 13 | 14 | rm -f */*~ 15 | rm -f *~ 16 | rm -f a.* 17 | rm -f aclocal.m4 18 | rm -rf build/ 19 | rm -f config.h.in 20 | rm -f configure 21 | rm -rf dist/ 22 | rm -rf src/wallycore.pc 23 | rm -f src/*pyc 24 | rm -f src/test/*pyc 25 | rm -f src/config.h.in 26 | rm -rf src/lcov* 27 | rm -f src/test_* 28 | rm -f src/test-suite.log 29 | rm -f src/swig_java/swig_java_wrap.c 30 | rm -f src/swig_java/*java 31 | rm -f src/swig_java/*jar 32 | rm -rf src/swig_java/src/com/blockstream/libwally 33 | rm -f src/swig_python/wallycore.py 34 | rm -f src/swig_python/wallycore/__init__.py* 35 | rm -f src/swig_python/swig_python_wrap.c 36 | rm -rf src/.libs 37 | rm -f src/secp256k1/build-aux/ltmain.sh-e 38 | rm -f src/secp256k1/a.* 39 | rm -rf src/wasm_package/browser-dist/ 40 | rm -f src/wasm_package/wallycore*.tgz 41 | rm -f tools/build-aux/ar-lib 42 | rm -f tools/build-aux/compile 43 | rm -f tools/build-aux/config.guess 44 | rm -f tools/build-aux/config.sub 45 | rm -f tools/build-aux/depcomp 46 | rm -f tools/build-aux/install-sh 47 | rm -f tools/build-aux/ltmain.sh 48 | rm -f tools/build-aux/ltmain.sh-e 49 | rm -f tools/build-aux/missing 50 | rm -f tools/build-aux/m4/l*.m4 51 | rm -f tools/build-aux/test-driver 52 | rm -rf autom4te.cache/ src/secp256k1/autom4te.cache 53 | rm -rf docs/build docs/source/address.rst docs/source/anti_exfil.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 54 | rm -rf .venv 55 | exit 0 56 | -------------------------------------------------------------------------------- /src/symmetric.c: -------------------------------------------------------------------------------- 1 | #include "internal.h" 2 | #include 3 | #include 4 | #include 5 | 6 | #define LABEL_SIZE 64 7 | 8 | static const unsigned char DOMAIN_STR[] = { 9 | 'S', 'y', 'm', 'm', 'e', 't', 'r', 'i', 'c', ' ', 'k', 'e', 'y', ' ', 's', 'e', 'e', 'd' 10 | }; 11 | 12 | /* TODO: move to a common header */ 13 | static bool is_valid_seed_length(size_t len) { 14 | return len == BIP32_ENTROPY_LEN_512 || len == BIP32_ENTROPY_LEN_256 || 15 | len == BIP32_ENTROPY_LEN_128; 16 | } 17 | 18 | int wally_symmetric_key_from_seed( 19 | const unsigned char *bytes, 20 | size_t bytes_len, 21 | unsigned char *bytes_out, 22 | size_t len) 23 | { 24 | if (!bytes || !is_valid_seed_length(bytes_len) || !bytes_out || len != HMAC_SHA512_LEN) 25 | return WALLY_EINVAL; 26 | 27 | return wally_hmac_sha512(DOMAIN_STR, sizeof(DOMAIN_STR), bytes, bytes_len, bytes_out, len); 28 | } 29 | 30 | int wally_symmetric_key_from_parent( 31 | const unsigned char *bytes, 32 | size_t bytes_len, 33 | uint32_t version, 34 | const unsigned char *label, 35 | size_t label_len, 36 | unsigned char *bytes_out, 37 | size_t len) 38 | { 39 | unsigned char buff[LABEL_SIZE], *buff_p = buff; 40 | int ret = WALLY_OK; 41 | size_t buff_len; 42 | 43 | if (!bytes || bytes_len != HMAC_SHA512_LEN || version != 0 || !label || 44 | !label_len || !bytes_out || len != HMAC_SHA512_LEN) 45 | return WALLY_EINVAL; 46 | 47 | buff_len = label_len + 1; 48 | if (buff_len > LABEL_SIZE) { 49 | buff_p = wally_malloc(buff_len); 50 | if (buff_p == NULL) 51 | return WALLY_ENOMEM; 52 | } 53 | 54 | *buff_p = version; 55 | memcpy(buff_p + 1, label, label_len); 56 | 57 | ret = wally_hmac_sha512(bytes, HMAC_SHA512_LEN / 2, buff_p, buff_len, bytes_out, len); 58 | 59 | wally_clear(buff_p, buff_len); 60 | if (buff_p != buff) 61 | wally_free(buff_p); 62 | 63 | return ret; 64 | } 65 | 66 | -------------------------------------------------------------------------------- /.github/workflows/wheels.yml: -------------------------------------------------------------------------------- 1 | name: Build 2 | 3 | on: 4 | push: 5 | branches: 6 | - master 7 | pull_request: 8 | branches: 9 | - master 10 | 11 | jobs: 12 | build_wheels: 13 | name: Build wheels on ${{ matrix.os }} 14 | runs-on: ${{ matrix.os }} 15 | strategy: 16 | fail-fast: false 17 | matrix: 18 | os: [ubuntu-22.04, windows-2022, macos-14] 19 | env: 20 | CIBW_BEFORE_ALL_LINUX: ./tools/install_swig.sh 21 | CIBW_BEFORE_ALL_MACOS: brew install gnu-sed swig automake libtool 22 | CIBW_BEFORE_ALL_WINDOWS: choco install swig --version=3.0.12 --no-progress --allow-downgrade -y 23 | CIBW_BEFORE_BUILD_WINDOWS: .\tools\msvc\swig.bat 24 | CIBW_REPAIR_WHEEL_COMMAND_LINUX: auditwheel repair --only-plat -w {dest_dir} {wheel} 25 | LIBWALLY_DIR: "." 26 | SWIG_PATH: "C:\\ProgramData\\chocolatey\\lib\\swig\\tools\\install\\swigwin-3.0.12" 27 | 28 | steps: 29 | - uses: actions/checkout@v5 30 | with: 31 | submodules: true 32 | fetch-depth: 0 33 | 34 | - name: Install MSVC 35 | if: runner.os == 'Windows' 36 | uses: ilammy/msvc-dev-cmd@v1.13.0 37 | 38 | - name: Install qemu aarch64 39 | if: runner.os == 'Linux' 40 | uses: docker/setup-qemu-action@v3 41 | with: 42 | platforms: arm64 43 | 44 | - name: Build Wheels 45 | uses: pypa/cibuildwheel@v3.1.4 46 | env: 47 | CIBW_SKIP: "cp38* cp314* *-win32 *-musllinux_aarch64 pp* gp* cp3??t-*" 48 | CIBW_ARCHS_LINUX: "x86_64 aarch64" 49 | CIBW_ARCHS_MACOS: "x86_64 arm64 universal2" 50 | 51 | - uses: actions/upload-artifact@v4 52 | with: 53 | name: wheels-${{ matrix.os }}-${{ strategy.job-index }} 54 | path: ./wheelhouse/*.whl 55 | 56 | merge: 57 | runs-on: ubuntu-latest 58 | needs: build_wheels 59 | steps: 60 | - name: Merge Artifacts 61 | uses: actions/upload-artifact/merge@v4 62 | with: 63 | name: all-wheels 64 | pattern: wheels-* 65 | -------------------------------------------------------------------------------- /src/hex_.c: -------------------------------------------------------------------------------- 1 | #include "internal.h" 2 | #include "ccan/ccan/str/hex/hex.h" 3 | 4 | int wally_hex_n_verify(const char *hex, size_t hex_len) 5 | { 6 | if (!hex || !hex_len || hex_len & 0x1) 7 | return WALLY_EINVAL; 8 | 9 | while (hex_len--) { 10 | char c = *hex++; 11 | if (!((c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F'))) 12 | return WALLY_EINVAL; 13 | } 14 | return WALLY_OK; 15 | } 16 | 17 | int wally_hex_verify(const char *hex) 18 | { 19 | return wally_hex_n_verify(hex, hex ? strlen(hex) : 0); 20 | } 21 | 22 | int wally_hex_from_bytes(const unsigned char *bytes, size_t bytes_len, 23 | char **output) 24 | { 25 | if (output) 26 | *output = NULL; 27 | 28 | if (!bytes || !output) 29 | return WALLY_EINVAL; 30 | 31 | *output = wally_malloc(hex_str_size(bytes_len)); 32 | if (!*output) 33 | return WALLY_ENOMEM; 34 | 35 | /* Note we ignore the return value as this call cannot fail */ 36 | hex_encode(bytes, bytes_len, *output, hex_str_size(bytes_len)); 37 | return WALLY_OK; 38 | } 39 | 40 | int wally_hex_n_to_bytes(const char *hex, size_t hex_len, 41 | unsigned char *bytes_out, size_t len, size_t *written) 42 | { 43 | if (written) 44 | *written = 0; 45 | 46 | if (!hex || !bytes_out || !len || hex_len & 0x1) 47 | return WALLY_EINVAL; 48 | 49 | if (len < hex_len / 2) { 50 | if (written) 51 | *written = hex_len / 2; 52 | return WALLY_OK; /* Not enough room in bytes_out, or empty string */ 53 | } 54 | 55 | len = hex_len / 2; /* hex_decode expects exact length */ 56 | if (!hex_decode(hex, hex_len, bytes_out, len)) 57 | return WALLY_EINVAL; 58 | 59 | if (written) 60 | *written = len; 61 | 62 | return WALLY_OK; 63 | } 64 | 65 | int wally_hex_to_bytes(const char *hex, 66 | unsigned char *bytes_out, size_t len, size_t *written) 67 | { 68 | return wally_hex_n_to_bytes(hex, hex ? strlen(hex) : 0, bytes_out, len, written); 69 | } 70 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | bld 2 | *.pyc 3 | *.swp 4 | src/test/__pycache__/ 5 | *~ 6 | *.class 7 | *.gcno 8 | *.gcda 9 | *.o 10 | *.lo 11 | *.la 12 | *.deps 13 | *.dirstamp 14 | *.libs 15 | *.venv 16 | Makefile 17 | Makefile.in 18 | aclocal.m4 19 | autom4te.cache/ 20 | build 21 | compile 22 | config.guess 23 | config.log 24 | config.status 25 | config.sub 26 | configure 27 | depcomp 28 | dist 29 | install-sh 30 | libtool 31 | ltmain.sh 32 | missing 33 | src/*~ 34 | src/lcov* 35 | src/Makefile 36 | src/Makefile.in 37 | src/config.h 38 | src/config.h.in 39 | src/stamp-h1 40 | src/test/Makefile 41 | src/test/Makefile.in 42 | src/wallycore.pc 43 | src/test_* 44 | src/test-suite.log 45 | src/swig_java/swig_java_wrap.c 46 | src/swig_java/*.java 47 | src/swig_java/*.jar 48 | src/swig_java/src/com/blockstream/libwally 49 | src/swig_python/swig_python_wrap.c 50 | src/swig_python/wallycore/__init__.py 51 | src/swig_python/wallycore/wallycore.egg-info 52 | tools/build-aux/m4/l*.m4 53 | tools/build-aux/test-driver 54 | tools/build-aux/*-e 55 | tools/build-aux/ar-lib 56 | src/secp256k1/build-aux/*-e 57 | src/secp256k1/test-suite.log 58 | src/secp256k1/*.log 59 | src/secp256k1/*.trs 60 | wallycore.egg-info/ 61 | wally*.gz 62 | wally*.sha256 63 | wally*.asc 64 | wally*.whl 65 | docs/source/address.rst 66 | docs/source/anti_exfil.rst 67 | docs/source/bip32.rst 68 | docs/source/bip38.rst 69 | docs/source/bip39.rst 70 | docs/source/bip85.rst 71 | docs/source/coinselection.rst 72 | docs/source/core.rst 73 | docs/source/crypto.rst 74 | docs/source/map.rst 75 | docs/source/descriptor.rst 76 | docs/source/psbt.rst 77 | docs/source/psbt_members.rst 78 | docs/source/script.rst 79 | docs/source/symmetric.rst 80 | docs/source/transaction.rst 81 | docs/source/transaction_members.rst 82 | docs/source/elements.rst 83 | docs/source/*_int.rst 84 | .idea/ 85 | 86 | # ctags 87 | tags 88 | 89 | # MacOS 90 | **/.DS_Store 91 | # WebAssembly 92 | wallycore.html 93 | wallycore.js 94 | wallycore.wasm 95 | 96 | # Windows 97 | *.obj 98 | *.dll 99 | *.lib 100 | *.pdb 101 | *.ilk 102 | *.exp 103 | -------------------------------------------------------------------------------- /contrib/gitian-descriptors/libwally-core-linux.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: "libwally-core-linux" 3 | enable_cache: false 4 | suites: 5 | - "trusty" 6 | architectures: 7 | - "amd64" 8 | packages: 9 | - "g++-aarch64-linux-gnu" 10 | - "g++-4.8-aarch64-linux-gnu" 11 | - "gcc-4.8-aarch64-linux-gnu" 12 | - "binutils-aarch64-linux-gnu" 13 | - "g++-arm-linux-gnueabihf" 14 | - "g++-4.8-arm-linux-gnueabihf" 15 | - "gcc-4.8-arm-linux-gnueabihf" 16 | - "binutils-arm-linux-gnueabihf" 17 | - "g++-4.8-multilib" 18 | - "gcc-4.8-multilib" 19 | - "binutils-gold" 20 | - "git-core" 21 | - "pkg-config" 22 | - "autoconf" 23 | - "libtool" 24 | - "automake" 25 | - "faketime" 26 | - "bsdmainutils" 27 | - "ca-certificates" 28 | - "python" 29 | remotes: 30 | - "dir": "libwally-core" 31 | "url": "https://github.com/ElementsProject/libwally-core.git" 32 | files: [] 33 | script: | 34 | 35 | HOSTS="x86_64-linux-gnu arm-linux-gnueabihf aarch64-linux-gnu" 36 | CONFIGFLAGS="" 37 | DISTNAME='libwally-core' 38 | 39 | export GZIP="-9n" 40 | export TAR_OPTIONS="--mtime="$REFERENCE_DATE\\\ $REFERENCE_TIME"" 41 | export TZ="UTC" 42 | export BUILD_DIR=`pwd` 43 | 44 | SOURCEDIST="$HOME/libwallet-core.tar" 45 | 46 | cd "${DISTNAME}" 47 | tools/autogen.sh 48 | tar -cvpf "${SOURCEDIST}" . --exclude=.git 49 | 50 | ORIGPATH="$PATH" 51 | # Extract the release tarball into a dir for each host and build 52 | for i in ${HOSTS}; do 53 | export PATH=${BASEPREFIX}/${i}/native/bin:${ORIGPATH} 54 | mkdir -p distsrc-${i} 55 | cd distsrc-${i} 56 | INSTALLPATH=`pwd`/installed/${DISTNAME} 57 | mkdir -p ${INSTALLPATH} 58 | tar -xf $SOURCEDIST 59 | 60 | ./configure --host="$i" --prefix=/ --disable-maintainer-mode --disable-dependency-tracking ${CONFIGFLAGS} 61 | make ${MAKEOPTS} 62 | 63 | make install DESTDIR=${INSTALLPATH} 64 | cd installed 65 | "${i}-strip" --strip-unneeded "${DISTNAME}"/lib/libwallycore.so 66 | ls "${DISTNAME}"/lib/libwallycore* | sort | tar --no-recursion --mode='u+rw,go+r-w,a+X' --owner=0 --group=0 -c -T - | gzip -9n > ${OUTDIR}/${DISTNAME}-${i}.tar.gz 67 | cd ../../ 68 | rm -rf distsrc-${i} 69 | done 70 | -------------------------------------------------------------------------------- /src/swig_python/contrib/sha.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | from wallycore import init, cleanup, sha256, sha256d, sha512 3 | 4 | 5 | class SHATests(unittest.TestCase): 6 | 7 | def test_sha_functions(self): 8 | """Test python wrappers for SHA hash functions""" 9 | # Ensure empty and valid buffers work correctly 10 | msg1 = 'This is a test message to hash'.encode() 11 | msg2 = bytes.fromhex('3e8379862d658e168c71f083bc05169b3b58ca3212e11c838b08629c5ca48a42') 12 | cases = [ 13 | (sha256, None, 'e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855'), 14 | (sha256, msg1, '726ca2c10e9d8b76e5b79f2961c3069a09fdd0a3b9bf8650e091e39b3c6c35be'), 15 | (sha256, msg2, '2f7d292595788655c5288b6e1dc698440d9c12559e3bc1e3cc38005a4add132f'), 16 | (sha256d, None, '5df6e0e2761359d30a8275058e299fcc0381534545f55cf43e41983f5d4c9456'), 17 | (sha256d, msg1, '29e04e90a1075caaa06573ea701913148d99fb0b7d6928e33f1aabe6032761a0'), 18 | (sha256d, msg2, '26e30f19dc2b29d8c220766fd5835d8256c87c32804d19b8307e21d6685c9d3e'), 19 | (sha512, None, 'cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce' 20 | '47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e'), 21 | (sha512, msg1, '2ed34644ddfcf76ca4de13e4632aa61376fbce813fecc5a043a479daaab17b2f' 22 | '8c3f376468d4637cb2e7c9e2b99ad08b8cb56fe6e724e476826f2aa210872c32'), 23 | (sha512, msg2, 'd51342efcb114c11045c12f7fede6f9a5fdb11051032bd520a99d79023423f4a' 24 | 'c3ab706ce5fa88c0aac46bbbf15bde720cf49eae5be0def3b39e6d3abb29a67b'), 25 | ] 26 | for sha_fn, src, expected in cases: 27 | result = sha_fn(src) 28 | self.assertEqual(result.hex(), expected) 29 | 30 | # Ensure passing an incorrect type (a) throws and (b) doesn't crash 31 | for sha_fn in [sha256, sha256d, sha512]: 32 | with self.assertRaises(TypeError): 33 | sha_fn('not bytes') 34 | 35 | 36 | if __name__ == '__main__': 37 | init(0) 38 | unittest.main() 39 | cleanup(0) 40 | -------------------------------------------------------------------------------- /include/wally_coinselection.h: -------------------------------------------------------------------------------- 1 | #ifndef LIBWALLY_CORE_COINSELECTION_H 2 | #define LIBWALLY_CORE_COINSELECTION_H 3 | 4 | #include "wally_core.h" 5 | 6 | #ifdef __cplusplus 7 | extern "C" { 8 | #endif 9 | 10 | /** The maximum number of asset values that can be returned in a coin selection */ 11 | #define WALLY_CS_MAX_ASSETS 256 12 | 13 | #ifndef WALLY_ABI_NO_ELEMENTS 14 | 15 | /** 16 | * Select input asset values to meet a given payment target. 17 | * 18 | * :param values: The UTXO asset values to select from. Must be ordered from 19 | *| largest to smallest. 20 | * :param num_values: The number of asset values in ``values``. 21 | * :param target: The desired payment value target. 22 | * :param attempts: The maximum number of permutations to check. Must be at 23 | *| least ``num_values`` + 1. 24 | * :param io_ratio: The approximate expected ratio of input to output sizes 25 | *| in the resulting transaction. Larger values will result in more 26 | *| input permutations being searched for exact matches. Must be non-zero, 27 | *| a good default value is ``5``. 28 | * :param indices_out: Destination for the zero-based indices into ``values`` 29 | *| making up the chosen solution. Must be at least the smaller 30 | *| of ``num_values`` and `WALLY_CS_MAX_ASSETS`. 31 | * MAX_SIZED_OUTPUT(indices_out_len, indices_out, WALLY_CS_MAX_ASSETS) 32 | * :param written: Destination for the the number of indices written 33 | *| to ``indices_out``. 34 | * 35 | * This function always finds a solution if one is available. If the given 36 | * values are insufficient to reach the target then zero elements will be 37 | * returned. If the sum of the values returned is not equal to ``target`` 38 | * then a change output for the remainder will be required. 39 | */ 40 | WALLY_CORE_API int wally_coinselect_assets( 41 | const uint64_t *values, 42 | size_t num_values, 43 | uint64_t target, 44 | uint64_t attempts, 45 | uint32_t io_ratio, 46 | uint32_t *indices_out, 47 | size_t indices_out_len, 48 | size_t *written); 49 | 50 | #endif /* WALLY_ABI_NO_ELEMENTS */ 51 | 52 | #ifdef __cplusplus 53 | } 54 | #endif 55 | 56 | #endif /* LIBWALLY_CORE_COINSELECTION_H */ 57 | -------------------------------------------------------------------------------- /src/swig_python/contrib/mnemonic.py: -------------------------------------------------------------------------------- 1 | """A wallycore version of https://github.com/trezor/python-mnemonic""" 2 | import wallycore 3 | 4 | BIP39_ENTROPY_LEN_128 = wallycore.BIP39_ENTROPY_LEN_128 5 | BIP39_ENTROPY_LEN_160 = wallycore.BIP39_ENTROPY_LEN_160 6 | BIP39_ENTROPY_LEN_192 = wallycore.BIP39_ENTROPY_LEN_192 7 | BIP39_ENTROPY_LEN_224 = wallycore.BIP39_ENTROPY_LEN_224 8 | BIP39_ENTROPY_LEN_256 = wallycore.BIP39_ENTROPY_LEN_256 9 | 10 | class Mnemonic(object): 11 | 12 | def __init__(self, language): 13 | self.wordlist = wallycore.bip39_get_wordlist(language) 14 | 15 | 16 | @staticmethod 17 | def list_languages(): 18 | return wallycore.bip39_get_languages().split() 19 | 20 | 21 | def generate(self, strength = wallycore.BIP39_ENTROPY_LEN_128): 22 | from os import urandom 23 | return self.to_mnemonic(bytearray(urandom(strength))) 24 | 25 | 26 | def to_entropy(self, words): 27 | if isinstance(words, list): 28 | words = ' '.join(words) 29 | return wallycore.bip39_mnemonic_to_bytes(self.wordlist, words) 30 | 31 | 32 | def to_mnemonic(self, data): 33 | return wallycore.bip39_mnemonic_from_bytes(self.wordlist, data) 34 | 35 | 36 | def check(self, mnemonic): 37 | wallycore.bip39_mnemonic_validate(self.wordlist, mnemonic) 38 | 39 | 40 | def to_seed(self, mnemonic, passphrase = ''): 41 | return wallycore.bip39_mnemonic_to_seed512(mnemonic, passphrase) 42 | 43 | 44 | if __name__ == "__main__": 45 | # Just make sure the basics work 46 | for lang in Mnemonic.list_languages(): 47 | m = Mnemonic(lang) 48 | phrase = m.generate() 49 | m.check(phrase) 50 | try: 51 | m.generate(BIP39_ENTROPY_LEN_256 - 1) 52 | assert False 53 | except Exception as _: 54 | pass 55 | try: 56 | m.check(phrase + ' foo') 57 | assert False 58 | except Exception as _: 59 | pass 60 | assert m.to_entropy(phrase) == m.to_entropy(phrase.split()) 61 | assert m.to_mnemonic(m.to_entropy(phrase)) == phrase 62 | assert m.to_seed(phrase, 'foo') != m.to_seed(phrase, 'bar') 63 | 64 | -------------------------------------------------------------------------------- /src/wasm_package/test/script.js: -------------------------------------------------------------------------------- 1 | import test from 'test' 2 | import assert from 'assert' 3 | import wally from '../src/index.js' 4 | 5 | test('scriptpubkey_multisig_from_bytes', () => { 6 | const pubkeys = [ 7 | '02ad4199d0c53b564b39798c4c064a6e6093abbb71d56cc153abf75a02f85c8e99', 8 | '03afeefeba0806711b6d3fc7c8b0b6a3eff5ea2ecf938aea1b6a093898097875f3' 9 | ] 10 | const pubkey_bytes = Buffer.from(pubkeys[0] + pubkeys[1], 'hex') 11 | const redeem_script = '522102ad4199d0c53b564b39798c4c064a6e6093abbb71d56cc153abf75a02f85c8e992103afeefeba0806711b6d3fc7c8b0b6a3eff5ea2ecf938aea1b6a093898097875f352ae' 12 | 13 | const res = wally.scriptpubkey_multisig_from_bytes(pubkey_bytes, 2, 0) 14 | assert.equal(res.toString('hex'), redeem_script) 15 | }) 16 | 17 | test('scriptpubkey_p2pkh_from_bytes', () => { 18 | const redeem1 = Buffer.from("111111111111111111111111111111111111111111111111111111111111111111", "hex") 19 | assert.equal(wally.scriptpubkey_p2pkh_from_bytes(redeem1, wally.WALLY_SCRIPT_HASH160).toString('hex'), "76a9148ec4cf3ee160b054e0abb6f5c8177b9ee56fa51e88ac", 20 | "Unexpected p2pkh result") 21 | 22 | const redeem2 = Buffer.from("1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111", "hex") 23 | assert.equal(wally.scriptpubkey_p2pkh_from_bytes(redeem2, wally.WALLY_SCRIPT_HASH160).toString('hex'), "76a914e723a0f62396b8b03dbd9e48e9b9efe2eb704aab88ac", 24 | "Unexpected p2pkh result") 25 | }) 26 | 27 | test('scriptpubkey_p2sh_from_bytes', () => { 28 | const redeem1 = Buffer.from("0020a22f2fcda841261e29973ad0191130911c5fd95eeec58de8e9367223b5dc040e", "hex") 29 | assert.equal(wally.scriptpubkey_p2sh_from_bytes(redeem1, wally.WALLY_SCRIPT_HASH160).toString('hex'), "a914822866d2b6a573a313e124bb1881a2f7ac4954ec87", 30 | "Unexpected p2sh result") 31 | 32 | const redeem2 = Buffer.from("002028a8fc70e1299f8728f62f2fe4ab98ef3af6e1af0bd46b2b924fa22092af00b8", "hex") 33 | assert.equal(wally.scriptpubkey_p2sh_from_bytes(redeem2, wally.WALLY_SCRIPT_HASH160).toString('hex'), "a914faf609ab5e82fbe8f6fcf0dcb2d4359dd044d2d387", 34 | "Unexpected p2sh result") 35 | }) -------------------------------------------------------------------------------- /src/ccan/ccan/str/hex/hex.h: -------------------------------------------------------------------------------- 1 | /* CC0 (Public domain) - see LICENSE file for details */ 2 | #ifndef CCAN_HEX_H 3 | #define CCAN_HEX_H 4 | #include "config.h" 5 | #include 6 | #include 7 | 8 | /** 9 | * hex_decode - Unpack a hex string. 10 | * @str: the hexidecimal string 11 | * @slen: the length of @str 12 | * @buf: the buffer to write the data into 13 | * @bufsize: the length of @buf 14 | * 15 | * Returns false if there are any characters which aren't 0-9, a-f or A-F, 16 | * of the string wasn't the right length for @bufsize. 17 | * 18 | * Example: 19 | * unsigned char data[20]; 20 | * 21 | * if (!hex_decode(argv[1], strlen(argv[1]), data, 20)) 22 | * printf("String is malformed!\n"); 23 | */ 24 | bool hex_decode(const char *str, size_t slen, void *buf, size_t bufsize); 25 | 26 | /** 27 | * hex_encode - Create a nul-terminated hex string 28 | * @buf: the buffer to read the data from 29 | * @bufsize: the length of @buf 30 | * @dest: the string to fill 31 | * @destsize: the max size of the string 32 | * 33 | * Returns true if the string, including terminator, fit in @destsize; 34 | * 35 | * Example: 36 | * unsigned char buf[] = { 0x1F, 0x2F }; 37 | * char str[5]; 38 | * 39 | * if (!hex_encode(buf, sizeof(buf), str, sizeof(str))) 40 | * abort(); 41 | */ 42 | bool hex_encode(const void *buf, size_t bufsize, char *dest, size_t destsize); 43 | 44 | /** 45 | * hex_str_size - Calculate how big a nul-terminated hex string is 46 | * @bytes: bytes of data to represent 47 | * 48 | * Example: 49 | * unsigned char buf[] = { 0x1F, 0x2F }; 50 | * char str[hex_str_size(sizeof(buf))]; 51 | * 52 | * hex_encode(buf, sizeof(buf), str, sizeof(str)); 53 | */ 54 | static inline size_t hex_str_size(size_t bytes) 55 | { 56 | return 2 * bytes + 1; 57 | } 58 | 59 | /** 60 | * hex_data_size - Calculate how many bytes of data in a hex string 61 | * @strlen: the length of the string (with or without NUL) 62 | * 63 | * Example: 64 | * const char str[] = "1F2F"; 65 | * unsigned char buf[hex_data_size(sizeof(str))]; 66 | * 67 | * hex_decode(str, strlen(str), buf, sizeof(buf)); 68 | */ 69 | static inline size_t hex_data_size(size_t strlen) 70 | { 71 | return strlen / 2; 72 | } 73 | #endif /* CCAN_HEX_H */ 74 | -------------------------------------------------------------------------------- /src/test/test_internal.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | from util import * 3 | 4 | class InternalTests(unittest.TestCase): 5 | 6 | def test_secp_context(self): 7 | """Tests for secp context functions""" 8 | # Allocate and free a secp context 9 | ctx = wally_get_new_secp_context() 10 | wally_secp_context_free(ctx) 11 | 12 | # Freeing a NULL context is a no-op 13 | wally_secp_context_free(None) 14 | 15 | def test_operations(self): 16 | """Tests for overriding the libraries default operations""" 17 | # get_operations 18 | # NULL output 19 | self.assertEqual(wally_get_operations(None), WALLY_EINVAL) 20 | # Incorrect struct size 21 | ops = wally_operations() 22 | ops.struct_size = 0 23 | self.assertEqual(wally_get_operations(byref(ops)), WALLY_EINVAL) 24 | # Correct struct size succeeds 25 | ops.struct_size = sizeof(wally_operations) 26 | self.assertEqual(wally_get_operations(byref(ops)), WALLY_OK) 27 | 28 | # set_operations 29 | # NULL input 30 | self.assertEqual(wally_set_operations(None), WALLY_EINVAL) 31 | # Incorrect struct size 32 | ops.struct_size = 0 33 | self.assertEqual(wally_set_operations(byref(ops)), WALLY_EINVAL) 34 | # Correct struct size succeeds 35 | ops.struct_size = sizeof(wally_operations) 36 | # Set a secp context function that returns NULL 37 | def null_secp_context(): 38 | return None 39 | secp_context_fn_t = CFUNCTYPE(c_void_p) 40 | ops.secp_context_fn = secp_context_fn_t(null_secp_context) 41 | self.assertEqual(wally_set_operations(byref(ops)), WALLY_OK) 42 | 43 | # Verify that the function was set correctly 44 | self.assertEqual(wally_secp_randomize(urandom(32), 32), WALLY_ENOMEM) 45 | 46 | # Verify that NULL members are unchanged when setting 47 | # TODO: OSX function casting results in a non-null pointer on OSX 48 | #ops.secp_context_fn = cast(0, secp_context_fn_t) 49 | #self.assertEqual(wally_set_operations(byref(ops)), WALLY_OK) 50 | #self.assertEqual(wally_secp_randomize(urandom(32), 32), WALLY_ENOMEM) 51 | 52 | 53 | if __name__ == '__main__': 54 | unittest.main() 55 | -------------------------------------------------------------------------------- /src/swig_python/contrib/aes.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | from wallycore import init, cleanup, \ 3 | ec_public_key_from_private_key, aes_cbc_with_ecdh_key, \ 4 | AES_FLAG_ENCRYPT, AES_FLAG_DECRYPT 5 | 6 | 7 | class AESTests(unittest.TestCase): 8 | 9 | def test_aes_cbc_ecdh(self): 10 | """Test python wrappers for aes_cbc_with_ecdh_key """ 11 | # Alice generates an ephemeral keypair for her request. 12 | alice_priv = bytes.fromhex('1c6a837d1ac663fdc7f1002327ca38452766eaf4fe3b80ce620bf7cd3f584cf6') 13 | alice_pub = ec_public_key_from_private_key(alice_priv) 14 | # Bob generates an ephemeral keypair for his response. 15 | bob_priv = bytes.fromhex('0b6b3dc90d203d854100110788ac87d43aa00620c9cdb361b281b09022ef4b53') 16 | bob_pub = ec_public_key_from_private_key(bob_priv) 17 | # Bob also generates a secure random IV for encrypting the response. 18 | iv = bytes.fromhex('bd5d4724243880738e7e8b0c02658700') 19 | # Both parties must agree on a shared label to use. 20 | label = 'a sample label'.encode() 21 | # This is the example payload we are using. 22 | payload = 'This is an example response/payload to encrypt'.encode() 23 | 24 | # Test we handle messages up to and over AES_BLOCK_LEN boundaries 25 | for i in range(1, len(payload) + 1): 26 | # The protocol: 27 | # 1) Alice requests some data using her pubkey. 28 | # 2) Bob encrypts the response (payload) with his private key, 29 | # a random IV, a shared label and Alice's pubkey. 30 | encrypted = aes_cbc_with_ecdh_key(bob_priv, iv, payload[0:i], 31 | alice_pub, label, AES_FLAG_ENCRYPT) 32 | # 3) Bob sends the encrypted data and his pubkey to Alice. 33 | # 4) Alice decrypts the payload with her private key and Bobs pubkey. 34 | decrypted = aes_cbc_with_ecdh_key(alice_priv, None, encrypted, 35 | bob_pub, label, AES_FLAG_DECRYPT) 36 | # Alice now has the unencrypted payload. 37 | self.assertEqual(decrypted.hex(), payload[0:i].hex()) 38 | 39 | 40 | if __name__ == '__main__': 41 | init(0) 42 | unittest.main() 43 | cleanup(0) 44 | -------------------------------------------------------------------------------- /src/swig_java/src/com/blockstream/test/test_descriptor.java: -------------------------------------------------------------------------------- 1 | package com.blockstream.test; 2 | 3 | import com.blockstream.libwally.Wally; 4 | 5 | public class test_descriptor { 6 | 7 | static final String descriptor_str = "wsh(multi(1,xpub661MyMwAqRbcFW31YEwpkMuc5THy2PSt5bDMsktWQcFF8syAmRUapSCGu8ED9W6oDMSgv6Zz8idoc4a6mr8BDzTJY47LJhkJ8UB7WEGuduB/1/0/*,xpub69H7F5d8KSRgmmdJg2KhpAK8SR3DjMwAdkxj3ZuxV27CprR9LgpeyGmXUbC6wb7ERfvrnKZjXoUmmDznezpbZb7ap6r1D3tgFxHmwMkQTPH/0/0/*))#t2zpj2eu"; 8 | final String expected_addrs[] = { "bc1qvjtfmrxu524qhdevl6yyyasjs7xmnzjlqlu60mrwepact60eyz9s9xjw0c", 9 | "bc1qp6rfclasvmwys7w7j4svgc2mrujq9m73s5shpw4e799hwkdcqlcsj464fw", 10 | "bc1qsflxzyj2f2evshspl9n5n745swcvs5k7p5t8qdww5unxpjwdvw5qx53ms4" }; 11 | 12 | public test_descriptor() { } 13 | 14 | public static void assert_eq(final Object expected, final Object actual, final String message) { 15 | if(!expected.equals(actual)) { 16 | System.out.println(expected); 17 | System.out.println(actual); 18 | throw new RuntimeException(message); 19 | } 20 | } 21 | 22 | public void test_descriptor_to_addresses() { 23 | final int child_num = 0; 24 | final int flags = 0; 25 | final int variant = 0; 26 | final int multi_index = 0; 27 | final Object descriptor = Wally.descriptor_parse(descriptor_str, Wally.map_init(0), 28 | Wally.WALLY_NETWORK_BITCOIN_MAINNET, 29 | flags); 30 | final String[] addrs = Wally.descriptor_to_addresses(descriptor, variant, multi_index, 31 | child_num, flags, 32 | expected_addrs.length); 33 | assert_eq(expected_addrs.length, addrs.length, "Addresses size mismatch"); 34 | for (int i = 0; i < expected_addrs.length; i++) { 35 | assert_eq(expected_addrs[i], addrs[i], "Addresses mismatch"); 36 | } 37 | 38 | Wally.descriptor_free(descriptor); 39 | Wally.cleanup(); 40 | } 41 | 42 | public static void main(final String[] args) { 43 | final test_descriptor t = new test_descriptor(); 44 | t.test_descriptor_to_addresses(); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /include/wally_bip85.h: -------------------------------------------------------------------------------- 1 | #ifndef LIBWALLY_CORE_BIP85_H 2 | #define LIBWALLY_CORE_BIP85_H 3 | 4 | #include "wally_core.h" 5 | 6 | #ifdef __cplusplus 7 | extern "C" { 8 | #endif 9 | 10 | struct ext_key; 11 | 12 | /** 13 | * Get the list of default supported languages for BIP85. 14 | * 15 | * .. note:: The string returned should be freed using `wally_free_string`. 16 | */ 17 | WALLY_CORE_API int bip85_get_languages( 18 | char **output); 19 | 20 | /** 21 | * Generate BIP39 mnemonic entropy according to BIP85. 22 | * 23 | * :param hdkey: The parent extended key to derive mnemonic entropy from. 24 | * :param lang: The intended language. Pass NULL to use the default English value. 25 | * :param num_words: The intended number of words. Must be 12, 18 or 24. 26 | * :param index: The index used to create the entropy. Must be less than 27 | *| `BIP32_INITIAL_HARDENED_CHILD`. 28 | * :param bytes_out: Destination for the resulting entropy. 29 | * MAX_SIZED_OUTPUT(len, bytes_out, HMAC_SHA512_LEN) 30 | * :param written: Destination for the number of bytes written to ``bytes_out``. 31 | */ 32 | WALLY_CORE_API int bip85_get_bip39_entropy( 33 | const struct ext_key *hdkey, 34 | const char *lang, 35 | uint32_t num_words, 36 | uint32_t index, 37 | unsigned char *bytes_out, 38 | size_t len, 39 | size_t *written); 40 | 41 | /** 42 | * Generate entropy for seeding RSA key generation according to BIP85. 43 | * 44 | * :param hdkey: The parent extended key to derive RSA entropy from. 45 | * :param key_bits: The intended RSA key size in bits. 46 | * :param index: The index used to create the entropy. Must be less than 47 | *| `BIP32_INITIAL_HARDENED_CHILD`. 48 | * :param bytes_out: Destination for the resulting entropy. 49 | * MAX_SIZED_OUTPUT(len, bytes_out, HMAC_SHA512_LEN) 50 | * :param written: Destination for the number of bytes written to ``bytes_out``. 51 | * 52 | * .. note:: This function always returns HMAC_SHA512_LEN bytes on success. 53 | * 54 | * .. note:: The returned entropy must be given to BIP85-DRNG in order 55 | *| to derive the RSA key to use. It MUST NOT be used directly. 56 | */ 57 | WALLY_CORE_API int bip85_get_rsa_entropy( 58 | const struct ext_key *hdkey, 59 | uint32_t key_bits, 60 | uint32_t index, 61 | unsigned char *bytes_out, 62 | size_t len, 63 | size_t *written); 64 | 65 | #ifdef __cplusplus 66 | } 67 | #endif 68 | 69 | #endif /* LIBWALLY_CORE_BIP85_H */ 70 | -------------------------------------------------------------------------------- /src/hmac.inl: -------------------------------------------------------------------------------- 1 | /* MIT (BSD) license - see LICENSE file for details */ 2 | /* HMAC code adapted from the Bitcoin project's C++: 3 | * 4 | * src/crypto/hmac_sha512.cpp f914f1a746d7f91951c1da262a4a749dd3ebfa71 5 | * Copyright (c) 2014 The Bitcoin Core developers 6 | * Distributed under the MIT software license, see the accompanying 7 | * file COPYING or http://www.opensource.org/licenses/mit-license.php. 8 | * 9 | * https://en.wikipedia.org/wiki/Hash-based_message_authentication_code 10 | */ 11 | static void SHA_PRE(_mix)(struct SHA_T *sha, const unsigned char *pad, 12 | const unsigned char *data, size_t data_len) 13 | { 14 | struct SHA_PRE(_ctx) ctx; 15 | SHA_PRE(_init)(&ctx); 16 | SHA_PRE(_update)(&ctx, pad, sizeof(ctx.SHA_CTX_BUFF)); 17 | SHA_PRE(_update)(&ctx, data, data_len); 18 | SHA_PRE(_done)(&ctx, sha); 19 | wally_clear(&ctx, sizeof(ctx)); 20 | } 21 | 22 | void HMAC_FUNCTION(struct SHA_T *sha, 23 | const unsigned char *key, size_t key_len, 24 | const unsigned char *msg, size_t msg_len) 25 | { 26 | struct SHA_PRE(_ctx) ctx; 27 | unsigned char ipad[sizeof(ctx.SHA_CTX_BUFF)]; 28 | unsigned char opad[sizeof(ctx.SHA_CTX_BUFF)]; 29 | size_t i; 30 | 31 | wally_clear(ctx.SHA_CTX_BUFF, sizeof(ctx.SHA_CTX_BUFF)); 32 | 33 | if (key_len <= sizeof(ctx.SHA_CTX_BUFF)) 34 | memcpy(ctx.SHA_CTX_BUFF, key, key_len); 35 | else 36 | SHA_T((struct SHA_T *)ctx.SHA_CTX_BUFF, key, key_len); 37 | 38 | for (i = 0; i < sizeof(ctx.SHA_CTX_BUFF); ++i) { 39 | opad[i] = ctx.SHA_CTX_BUFF[i] ^ 0x5c; 40 | ipad[i] = ctx.SHA_CTX_BUFF[i] ^ 0x36; 41 | } 42 | 43 | SHA_PRE(_mix)((struct SHA_T *)ctx.SHA_CTX_BUFF, ipad, msg, msg_len); 44 | SHA_PRE(_mix)(sha, opad, ctx.SHA_CTX_BUFF, sizeof(*sha)); 45 | wally_clear_3(&ctx, sizeof(ctx), ipad, sizeof(ipad), opad, sizeof(opad)); 46 | } 47 | 48 | int WALLY_HMAC_FUNCTION(const unsigned char *key, size_t key_len, 49 | const unsigned char *bytes, size_t bytes_len, 50 | unsigned char *bytes_out, size_t len) 51 | { 52 | struct SHA_T sha; 53 | bool aligned = alignment_ok(bytes_out, sizeof(sha.u.u8)); 54 | struct SHA_T *sha_p = aligned ? (void *)bytes_out : (void*)&sha; 55 | 56 | if (!key || !key_len || !bytes || !bytes_len || 57 | !bytes_out || len != sizeof(struct SHA_T)) 58 | return WALLY_EINVAL; 59 | 60 | HMAC_FUNCTION(sha_p, key, key_len, bytes, bytes_len); 61 | if (!aligned) { 62 | memcpy(bytes_out, sha_p, sizeof(*sha_p)); 63 | wally_clear(sha_p, sizeof(*sha_p)); 64 | } 65 | return WALLY_OK; 66 | } 67 | -------------------------------------------------------------------------------- /src/base_64.c: -------------------------------------------------------------------------------- 1 | #include "internal.h" 2 | #include "ccan/ccan/base64/base64.h" 3 | 4 | int wally_base64_from_bytes(const unsigned char *bytes, size_t bytes_len, 5 | uint32_t flags, char **output) 6 | { 7 | char *encoded; 8 | size_t encoded_len; 9 | 10 | if (output) 11 | *output = NULL; 12 | 13 | if (!bytes || !bytes_len || flags || !output) 14 | return WALLY_EINVAL; 15 | 16 | encoded_len = base64_encoded_length(bytes_len) + 1; /* +1 for NUL */ 17 | if ((encoded = wally_malloc(encoded_len)) == NULL) 18 | return WALLY_ENOMEM; 19 | 20 | if (base64_encode(encoded, encoded_len, (const char *)bytes, bytes_len) < 0) { 21 | clear_and_free(encoded, encoded_len); 22 | return WALLY_EINVAL; 23 | } 24 | *output = encoded; 25 | return WALLY_OK; 26 | } 27 | 28 | int wally_base64_n_get_maximum_length(const char *str_in, size_t str_len, uint32_t flags, size_t *written) 29 | { 30 | if (written) 31 | *written = 0; 32 | 33 | if (!str_in || !str_len || flags || !written) 34 | return WALLY_EINVAL; 35 | 36 | *written = base64_decoded_length(str_len); 37 | return WALLY_OK; 38 | } 39 | 40 | int wally_base64_get_maximum_length(const char *str_in, uint32_t flags, size_t *written) 41 | { 42 | size_t str_len = str_in ? strlen(str_in) : 0; 43 | return wally_base64_n_get_maximum_length(str_in, str_len, flags, written); 44 | } 45 | 46 | int wally_base64_n_to_bytes(const char *str_in, size_t str_len, uint32_t flags, 47 | unsigned char *bytes_out, size_t len, 48 | size_t *written) 49 | { 50 | size_t decode_len; 51 | ssize_t actual_len; 52 | 53 | if (written) 54 | *written = 0; 55 | 56 | if (!str_in || !str_len || flags || !bytes_out || !len || !written) 57 | return WALLY_EINVAL; 58 | 59 | decode_len = base64_decoded_length(str_len); 60 | if (len < decode_len) { 61 | /* Not enough space; return the amount required */ 62 | *written = decode_len; 63 | return WALLY_OK; 64 | } 65 | 66 | actual_len = base64_decode((char *)bytes_out, decode_len, str_in, str_len); 67 | if (actual_len < 0) 68 | return WALLY_EINVAL; /* Invalid base64 data */ 69 | *written = actual_len; 70 | return WALLY_OK; 71 | } 72 | 73 | int wally_base64_to_bytes(const char *str_in, uint32_t flags, 74 | unsigned char *bytes_out, size_t len, 75 | size_t *written) 76 | { 77 | size_t str_len = str_in ? strlen(str_in) : 0; 78 | return wally_base64_n_to_bytes(str_in, str_len, flags, bytes_out, len, written); 79 | } 80 | -------------------------------------------------------------------------------- /src/swig_java/src/com/blockstream/test/test_scripts.java: -------------------------------------------------------------------------------- 1 | package com.blockstream.test; 2 | 3 | import com.blockstream.libwally.Wally; 4 | 5 | public class test_scripts { 6 | 7 | public void test_p2pkh() { 8 | final byte[] redeem1 = h("111111111111111111111111111111111111111111111111111111111111111111"); 9 | if (!h(Wally.scriptpubkey_p2pkh_from_bytes(redeem1, Wally.WALLY_SCRIPT_HASH160)).equals("76a9148ec4cf3ee160b054e0abb6f5c8177b9ee56fa51e88ac")) 10 | throw new RuntimeException("Unexpected p2pkh result"); 11 | 12 | final byte[] redeem2 = h("1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111"); 13 | if (!h(Wally.scriptpubkey_p2pkh_from_bytes(redeem2, Wally.WALLY_SCRIPT_HASH160)).equals("76a914e723a0f62396b8b03dbd9e48e9b9efe2eb704aab88ac")) 14 | throw new RuntimeException("Unexpected p2pkh result"); 15 | } 16 | 17 | public void test_p2sh() { 18 | // hexes from local regtest testing 19 | final byte[] redeem1 = h("0020a22f2fcda841261e29973ad0191130911c5fd95eeec58de8e9367223b5dc040e"); 20 | if (!h(Wally.scriptpubkey_p2sh_from_bytes(redeem1, Wally.WALLY_SCRIPT_HASH160)).equals("a914822866d2b6a573a313e124bb1881a2f7ac4954ec87")) 21 | throw new RuntimeException("Unexpected p2sh result"); 22 | 23 | final byte[] redeem2 = h("002028a8fc70e1299f8728f62f2fe4ab98ef3af6e1af0bd46b2b924fa22092af00b8"); 24 | if (!h(Wally.scriptpubkey_p2sh_from_bytes(redeem2, Wally.WALLY_SCRIPT_HASH160)).equals("a914faf609ab5e82fbe8f6fcf0dcb2d4359dd044d2d387")) 25 | throw new RuntimeException("Unexpected p2sh result"); 26 | } 27 | 28 | public void test_multisig() { 29 | // hexes from local regtest testing 30 | final byte[] pubkeys = h("0351aa9225259d7c10fe606c66e0511ec766b7861c5caf9ef6247bcd9d117d92ef03d5a4d76608543b09c0bba4f496f6d24baa8f07b9f65bdadde978e4f1208fc6a10249674f61c45b47767937f2142db44d0e87e5e9a0ada986c35bd588ac7074afae"); 31 | if (!h(Wally.scriptpubkey_multisig_from_bytes(pubkeys, 2, 0, 3)).equals("52210351aa9225259d7c10fe606c66e0511ec766b7861c5caf9ef6247bcd9d117d92ef2103d5a4d76608543b09c0bba4f496f6d24baa8f07b9f65bdadde978e4f1208fc6a1210249674f61c45b47767937f2142db44d0e87e5e9a0ada986c35bd588ac7074afae53ae")) 32 | throw new RuntimeException("Unexpected multisig result"); 33 | } 34 | 35 | private String h(final byte[] bytes) { return Wally.hex_from_bytes(bytes); } 36 | private byte[] h(final String hex) { return Wally.hex_to_bytes(hex); } 37 | 38 | public static void main(final String[] args) { 39 | final test_scripts t = new test_scripts(); 40 | t.test_p2pkh(); 41 | t.test_p2sh(); 42 | t.test_multisig(); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/pbkdf2.inl: -------------------------------------------------------------------------------- 1 | /* 2 | * This is a heavily modified version of openBSDs pkcs5_pbkdf2 from 3 | * libutil/pkcs5_pbkdf2.c, whose copyright appears here: 4 | * 5 | * Copyright (c) 2008 Damien Bergamini 6 | * 7 | * Permission to use, copy, modify, and distribute this software for any 8 | * purpose with or without fee is hereby granted, provided that the above 9 | * copyright notice and this permission notice appear in all copies. 10 | */ 11 | 12 | /* Extra bytes required at the end of salt for pbkdf2 functions */ 13 | #define PBKDF2_HMAC_EXTRA_LEN 4 14 | 15 | int SHA_POST(wally_pbkdf2_hmac_)(const unsigned char *pass, size_t pass_len, 16 | const unsigned char *salt, size_t salt_len, 17 | uint32_t flags, uint32_t cost, 18 | unsigned char *bytes_out, size_t len) 19 | { 20 | unsigned char *tmp_salt = NULL; 21 | struct SHA_T d1, d2, *sha_cp; 22 | size_t n, c, j; 23 | 24 | BUILD_ASSERT(sizeof(beint32_t) == PBKDF2_HMAC_EXTRA_LEN); 25 | BUILD_ASSERT(sizeof(d1) == PBKDF2_HMAC_SHA_LEN); 26 | 27 | if (!bytes_out || !len) 28 | return WALLY_EINVAL; 29 | 30 | if (flags) 31 | return WALLY_EINVAL; /* Invalid flag */ 32 | 33 | if (!len || len % PBKDF2_HMAC_SHA_LEN) 34 | return WALLY_EINVAL; 35 | 36 | tmp_salt = wally_malloc(salt_len + PBKDF2_HMAC_EXTRA_LEN); 37 | if (!tmp_salt) 38 | return WALLY_ENOMEM; 39 | memcpy(tmp_salt, salt, salt_len); 40 | salt_len += PBKDF2_HMAC_EXTRA_LEN; 41 | 42 | /* If bytes out is suitably aligned, we can work on it directly */ 43 | if (alignment_ok(bytes_out, sizeof(SHA_ALIGN_T))) 44 | sha_cp = (void *)bytes_out; 45 | else 46 | sha_cp = &d2; 47 | 48 | for (n = 0; n < len / PBKDF2_HMAC_SHA_LEN; ++n) { 49 | beint32_t block = cpu_to_be32(n + 1); /* Block number */ 50 | 51 | memcpy(tmp_salt + salt_len - sizeof(block), &block, sizeof(block)); 52 | SHA_POST_IMPL(hmac_)(&d1, pass, pass_len, tmp_salt, salt_len); 53 | memcpy(sha_cp, &d1, sizeof(d1)); 54 | 55 | for (c = 0; cost && c < cost - 1; ++c) { 56 | SHA_POST_IMPL(hmac_)(&d1, pass, pass_len, d1.u.u8, sizeof(d1)); 57 | for (j = 0; j < sizeof(d1.u.SHA_MEM)/sizeof(d1.u.SHA_MEM[0]); ++j) 58 | sha_cp->u.SHA_MEM[j] ^= d1.u.SHA_MEM[j]; 59 | } 60 | if (sha_cp == &d2) 61 | memcpy(bytes_out, sha_cp, sizeof(*sha_cp)); 62 | else 63 | ++sha_cp; 64 | 65 | bytes_out += PBKDF2_HMAC_SHA_LEN; 66 | } 67 | 68 | wally_clear_2(&d1, sizeof(d1), &d2, sizeof(d2)); 69 | if (tmp_salt) { 70 | wally_clear(tmp_salt, salt_len); 71 | wally_free(tmp_salt); 72 | } 73 | return WALLY_OK; 74 | } 75 | -------------------------------------------------------------------------------- /src/scrypt.c: -------------------------------------------------------------------------------- 1 | #include "internal.h" 2 | #include 3 | #include 4 | #include "hmac.h" 5 | #include "ccan/ccan/endian/endian.h" 6 | 7 | /* Use scrypts internal malloc/free */ 8 | #undef malloc 9 | #undef free 10 | 11 | /* Implement functions required by the scrypt core */ 12 | static uint32_t le32dec(const void *p) 13 | { 14 | leint32_t tmp; 15 | memcpy(&tmp, p, sizeof(tmp)); 16 | return le32_to_cpu(tmp); 17 | } 18 | 19 | static void le32enc(void *p, uint32_t value) 20 | { 21 | leint32_t tmp = cpu_to_le32(value); 22 | memcpy(p, &tmp, sizeof(tmp)); 23 | } 24 | 25 | static void PBKDF2_SHA256(const unsigned char *pass, size_t pass_len, 26 | const unsigned char *salt, size_t salt_len, 27 | uint64_t cost, 28 | unsigned char *bytes_out, size_t len) 29 | { 30 | const uint32_t flags = 0; 31 | wally_pbkdf2_hmac_sha256(pass, pass_len, (unsigned char *)salt, salt_len, 32 | flags, (uint32_t)cost, bytes_out, len); 33 | } 34 | 35 | /* Include a suitable smix function/functions */ 36 | #if defined(__ARM_NEON__) || defined(__ARM_NEON) 37 | # include 38 | # include "scrypt/crypto_scrypt_smix_neon.c" 39 | # if !defined(__ANDROID__) 40 | /* No way to check for support, assume Neon present */ 41 | # define crypto_scrypt_smix_fn crypto_scrypt_smix_neon 42 | # else 43 | /* On Android, detect Neon support at runtime */ 44 | # include "cpufeatures/cpu-features.h" 45 | # include "scrypt/crypto_scrypt_smix.c" 46 | static void 47 | crypto_scrypt_smix_fn(uint8_t *B, size_t r, uint64_t N, void *_V, void *XY) 48 | { 49 | if (android_getCpuFeatures() & ANDROID_CPU_ARM_FEATURE_NEON) 50 | crypto_scrypt_smix_neon(B, r, N, _V, XY); 51 | else 52 | crypto_scrypt_smix_c(B, r, N, _V, XY); 53 | } 54 | # endif 55 | #elif defined(__SSE2__) 56 | /* Use the SSE2 version */ 57 | # include "scrypt/crypto_scrypt_smix_sse2.c" 58 | # define crypto_scrypt_smix_fn crypto_scrypt_smix_sse2 59 | #else 60 | /* Use the C version */ 61 | # include "scrypt/crypto_scrypt_smix.c" 62 | # define crypto_scrypt_smix_fn crypto_scrypt_smix_c 63 | #endif 64 | 65 | #include "scrypt/crypto_scrypt.c" 66 | 67 | /* Our scrypt wrapper. */ 68 | int wally_scrypt(const unsigned char *pass, size_t pass_len, 69 | const unsigned char *salt, size_t salt_len, 70 | uint32_t cost, uint32_t block_size, uint32_t parallelism, 71 | unsigned char *bytes_out, size_t len) 72 | { 73 | if (!bytes_out || !len || len % PBKDF2_HMAC_SHA256_LEN) 74 | return WALLY_EINVAL; 75 | 76 | return _crypto_scrypt(pass, pass_len, salt, salt_len, 77 | cost, block_size, parallelism, 78 | bytes_out, len, crypto_scrypt_smix_fn); 79 | } 80 | -------------------------------------------------------------------------------- /contrib/wally_js_example.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Wallycore JS Example 7 | 10 | 11 | 12 | 13 | 14 | 51 | 55 | 56 | 57 | -------------------------------------------------------------------------------- /docs/source/anti_exfil_protocol.rst: -------------------------------------------------------------------------------- 1 | Anti-Exfil Protocol 2 | ==================== 3 | 4 | .. _anti-exfil-protocol: 5 | 6 | The following walkthrough demonstrates how to use libwally to implement the 7 | ECDSA Anti-Exfil Protocol to prevent a signing device from exfiltrating the 8 | secret signing keys through biased signature nonces. 9 | For the full details, see 10 | `here `_. 11 | 12 | The example code here is written in python using the generated python swig 13 | wrappers. 14 | 15 | Step 1 16 | ------ 17 | 18 | The host draws randomness ``rho`` and computes a commitment to it: 19 | 20 | .. literalinclude:: ../../src/pyexample/anti-exfil.py 21 | :start-after: start-step-1 22 | :end-before: end-step-1 23 | 24 | Host sends ``host_commitment`` to the signer. 25 | 26 | Step 2 27 | ------ 28 | 29 | The signing device computes the original nonce ``R``, i.e. ``signer commitment``: 30 | 31 | .. literalinclude:: ../../src/pyexample/anti-exfil.py 32 | :start-after: start-step-2 33 | :end-before: end-step-2 34 | 35 | Signing device sends ``signer_commitment`` to the host. 36 | 37 | .. warning:: 38 | If, at any point from this step onward, the hardware device fails, it is 39 | okay to restart the protocol using **exactly the same** ``rho`` and checking 40 | that the hardware device proposes **exactly the same** ``R``. Otherwise, the 41 | hardware device may be selectively aborting and thereby biasing the set of 42 | nonces that are used in actual signatures. 43 | 44 | It takes many (>100) such aborts before there is a plausible attack, given 45 | current knowledge in 2020. However such aborts accumulate even across a total 46 | replacement of all relevant devices (but not across replacement of the actual 47 | signing keys with new independently random ones). 48 | 49 | In case the hardware device cannot be made to sign with the given ``rho``, ``R`` 50 | pair, wallet authors should alert the user and present a very scary message 51 | implying that if this happens more than even a few times, say 20 or more times 52 | EVER, they should change hardware vendors and perhaps sweep their coins. 53 | 54 | Step 3 55 | ------ 56 | 57 | The host replies with ``rho`` generated at `Step 1`_. 58 | 59 | Step 4 60 | ------ 61 | 62 | The signing device signs and provide the signature to the host: 63 | 64 | .. literalinclude:: ../../src/pyexample/anti-exfil.py 65 | :start-after: start-step-4 66 | :end-before: end-step-4 67 | 68 | Step 5 69 | ------ 70 | 71 | The host verifies that the signature's public nonce matches the signer 72 | commitment ``R`` from `Step 2`_ and its original randomness ``rho``: 73 | 74 | .. literalinclude:: ../../src/pyexample/anti-exfil.py 75 | :start-after: start-step-5 76 | :end-before: end-step-5 77 | -------------------------------------------------------------------------------- /src/swig_python/contrib/bip32.py: -------------------------------------------------------------------------------- 1 | """A simple demonstration/test of BIP32 derivation using wally""" 2 | import unittest 3 | from wallycore import * 4 | 5 | # BIP32 test vector 1 6 | # FIXME: Put this in a data file to share with src/test/test_bip32.py 7 | vec_1 = { 8 | 'seed': '000102030405060708090a0b0c0d0e0f', 9 | 10 | 'm': { 11 | BIP32_FLAG_KEY_PUBLIC: '0488B21E000000000000000000873DFF' 12 | '81C02F525623FD1FE5167EAC3A55A049' 13 | 'DE3D314BB42EE227FFED37D5080339A3' 14 | '6013301597DAEF41FBE593A02CC513D0' 15 | 'B55527EC2DF1050E2E8FF49C85C2AB473B21', 16 | 17 | BIP32_FLAG_KEY_PRIVATE: '0488ADE4000000000000000000873DFF' 18 | '81C02F525623FD1FE5167EAC3A55A049' 19 | 'DE3D314BB42EE227FFED37D50800E8F3' 20 | '2E723DECF4051AEFAC8E2C93C9C5B214' 21 | '313817CDB01A1494B917C8436B35E77E9D71' 22 | }, 23 | } 24 | 25 | class BIP32Tests(unittest.TestCase): 26 | 27 | def compare_keys(self, key, expected, flags): 28 | for fn in [bip32_key_get_chain_code, bip32_key_get_pub_key, 29 | bip32_key_get_parent160, bip32_key_get_depth, 30 | bip32_key_get_child_num]: 31 | self.assertEqual(fn(key), fn(expected)) 32 | self.assertEqual(bip32_key_get_version(key), BIP32_VER_MAIN_PRIVATE) 33 | if flags == BIP32_FLAG_KEY_PRIVATE: 34 | self.assertEqual(bip32_key_get_priv_key(key), 35 | bip32_key_get_priv_key(expected)) 36 | 37 | def test_bip32(self): 38 | seed_data = hex_to_bytes(vec_1['seed']) 39 | master = bip32_key_from_seed(seed_data, BIP32_VER_MAIN_PRIVATE, 0) 40 | 41 | for flags in [BIP32_FLAG_KEY_PUBLIC, BIP32_FLAG_KEY_PRIVATE]: 42 | serialized_data = hex_to_bytes(vec_1['m'][flags]) 43 | serialized_data = serialized_data[:BIP32_SERIALIZED_LEN] # Trim checksum 44 | expected_key = bip32_key_unserialize(serialized_data) 45 | self.compare_keys(master, expected_key, flags) 46 | 47 | # Test our SWIG integer conversions for overflow etc in path derivation 48 | for p, valid in [([2**32-1], True), # 0xffffffff is valid 49 | ([float(1)], False), # We don't support float casting 50 | ([2**32], False), # Overflow 51 | ([-1], False)]: # Underflow 52 | if valid: 53 | bip32_key_from_parent_path(master, p, 0) 54 | else: 55 | with self.assertRaises(OverflowError): 56 | bip32_key_from_parent_path(master, p, 0) 57 | 58 | 59 | 60 | if __name__ == '__main__': 61 | unittest.main() 62 | -------------------------------------------------------------------------------- /src/test/test_scrypt.py: -------------------------------------------------------------------------------- 1 | import os 2 | import unittest 3 | from util import * 4 | 5 | # Test cases from 6 | # https://tools.ietf.org/html/draft-josefsson-scrypt-kdf-04 7 | cases = [ 8 | ["", "", 9 | 16, 1, 1, 64, 10 | '77 d6 57 62 38 65 7b 20 3b 19 ca 42 c1 8a 04 97' 11 | 'f1 6b 48 44 e3 07 4a e8 df df fa 3f ed e2 14 42' 12 | 'fc d0 06 9d ed 09 48 f8 32 6a 75 3a 0f c8 1f 17' 13 | 'e8 d3 e0 fb 2e 0d 36 28 cf 35 e2 0c 38 d1 89 06'], 14 | 15 | ['password', 'NaCl', 16 | 1024, 8, 16, 64, 17 | 'fd ba be 1c 9d 34 72 00 78 56 e7 19 0d 01 e9 fe' 18 | '7c 6a d7 cb c8 23 78 30 e7 73 76 63 4b 37 31 62' 19 | '2e af 30 d9 2e 22 a3 88 6f f1 09 27 9d 98 30 da' 20 | 'c7 27 af b9 4a 83 ee 6d 83 60 cb df a2 cc 06 40'], 21 | 22 | ['pleaseletmein', 'SodiumChloride', 23 | 16384, 8, 1, 64, 24 | '70 23 bd cb 3a fd 73 48 46 1c 06 cd 81 fd 38 eb' 25 | 'fd a8 fb ba 90 4f 8e 3e a9 b5 43 f6 54 5d a1 f2' 26 | 'd5 43 29 55 61 3f 0f cf 62 d4 97 05 24 2a 9a f9' 27 | 'e6 1e 85 dc 0d 65 1e 40 df cf 01 7b 45 57 58 87'], 28 | 29 | ['pleaseletmein', 'SodiumChloride', 30 | 1048576, 8, 1, 64, 31 | '21 01 cb 9b 6a 51 1a ae ad db be 09 cf 70 f8 81' 32 | 'ec 56 8d 57 4a 2f fd 4d ab e5 ee 98 20 ad aa 47' 33 | '8e 56 fd 8f 4b a5 d0 9f fa 1c 6d 92 7c 40 f4 c3' 34 | '37 30 40 49 e8 a9 52 fb cb f4 5c 6f a7 7a 41 a4'] 35 | ] 36 | 37 | class ScryptTests(unittest.TestCase): 38 | 39 | def test_scrypt(self): 40 | 41 | if os.getenv('WALLY_SKIP_EXPENSIVE_TESTS', None): 42 | self.skipTest('Skipping expensive scrypt test') 43 | 44 | # Invalid arguments 45 | pwd, salt, cost, block, p, l, _ = cases[0] 46 | pwd, salt = utf8(pwd), utf8(salt) 47 | out_buf, out_len = make_cbuffer('0' * l) 48 | invalid = [ 49 | [pwd, len(pwd), salt, len(salt), cost, block, p, None, out_len], # Null output 50 | [pwd, len(pwd), salt, len(salt), cost, block, p, out_buf, 0], # Empty output 51 | [pwd, len(pwd), salt, len(salt), cost, block, p, out_buf, 33], # Len not % 32 52 | ] 53 | for c in invalid: 54 | ret = wally_scrypt(*c) 55 | self.assertEqual(wally_scrypt(*c), WALLY_EINVAL) 56 | 57 | # Test vectors 58 | for c in cases: 59 | pwd, salt, cost, block, parallel, length, expected = c 60 | pwd = utf8(pwd) 61 | salt = utf8(salt) 62 | expected = expected.replace(' ', '') 63 | assert len(expected) == length * 2 64 | out_buf, out_len = make_cbuffer('0' * len(expected)) 65 | 66 | ret = wally_scrypt(pwd, len(pwd), salt, len(salt), 67 | cost, block, parallel, out_buf, out_len) 68 | self.assertEqual(ret, WALLY_OK) 69 | self.assertEqual(h(out_buf), utf8(expected)) 70 | 71 | 72 | if __name__ == '__main__': 73 | unittest.main() 74 | -------------------------------------------------------------------------------- /src/_CMakeLists.txt: -------------------------------------------------------------------------------- 1 | file( 2 | GLOB ccan_srcs 3 | RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} 4 | "ccan/ccan/base64/*.[ch]" 5 | "ccan/ccan/build_assert/*.h" 6 | "ccan/ccan/compiler/*.h" 7 | "ccan/ccan/crypto/sha256/*.[ch]" 8 | "ccan/ccan/crypto/sha512/*.[ch]" 9 | "ccan/ccan/crypto/ripemd160/*.[ch]" 10 | "ccan/ccan/endian/*.h" 11 | "ccan/ccan/str/hex/*.[ch]" 12 | "ccan/ccan/tap/*.[ch]" 13 | ) 14 | file( 15 | GLOB wallycore_srcs 16 | RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} 17 | "*.[ch]" 18 | ) 19 | list(REMOVE_ITEM ccan_srcs ccan/ccan/crypto/sha256/sha256_sse4.c) 20 | message("ccan_srcs: ${ccan_srcs}") 21 | file( 22 | GLOB wallycore_public_headers 23 | RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} 24 | "${CMAKE_SOURCE_DIR}/include/*.h" 25 | ) 26 | 27 | # wallycore 28 | add_library(wallycore) 29 | target_sources(wallycore PRIVATE ${ccan_srcs} ${wallycore_srcs}) 30 | set_target_properties(wallycore PROPERTIES PUBLIC_HEADER "${wallycore_public_headers}") 31 | target_include_directories( 32 | wallycore 33 | PUBLIC $ $ $ 34 | PRIVATE ${CMAKE_BINARY_DIR} ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/ccan 35 | ) 36 | target_link_libraries(wallycore PUBLIC secp256k1) 37 | if(WALLYCORE_ENABLE_COVERAGE AND CMAKE_BUILD_TYPE STREQUAL "Debug") 38 | target_compile_options(wallycore PRIVATE --coverage) 39 | target_link_options(wallycore PUBLIC --coverage) 40 | endif() 41 | 42 | if (WALLYCORE_BUILD_ELEMENTS) 43 | target_compile_definitions(wallycore PRIVATE BUILD_ELEMENTS) 44 | endif() 45 | 46 | if(NOT WALLYCORE_INSTALL) 47 | return() 48 | endif() 49 | 50 | # install directives 51 | include(GNUInstallDirs) 52 | include(CMakePackageConfigHelpers) 53 | 54 | set(LIB_CMAKE_INSTALL_DIR ${CMAKE_INSTALL_LIBDIR}/cmake/wallycore) 55 | 56 | configure_package_config_file( 57 | ${CMAKE_SOURCE_DIR}/cmake/wallycore-config.cmake.in "${CMAKE_CURRENT_BINARY_DIR}/wallycore-config.cmake" 58 | INSTALL_DESTINATION ${LIB_CMAKE_INSTALL_DIR} 59 | PATH_VARS LIB_CMAKE_INSTALL_DIR 60 | ) 61 | write_basic_package_version_file( 62 | wallycore-config-version.cmake 63 | VERSION ${PROJECT_VERSION} 64 | COMPATIBILITY SameMajorVersion 65 | ) 66 | 67 | install(FILES "${CMAKE_CURRENT_BINARY_DIR}/wallycore-config.cmake" 68 | "${CMAKE_CURRENT_BINARY_DIR}/wallycore-config-version.cmake" DESTINATION ${LIB_CMAKE_INSTALL_DIR} 69 | ) 70 | install( 71 | TARGETS wallycore 72 | EXPORT "wallycore-target" 73 | COMPONENT wallycore 74 | RUNTIME EXCLUDE_FROM_ALL 75 | OBJECTS EXCLUDE_FROM_ALL 76 | ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} 77 | PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} 78 | ) 79 | install( 80 | EXPORT "wallycore-target" 81 | DESTINATION ${LIB_CMAKE_INSTALL_DIR} 82 | NAMESPACE wallycore:: 83 | FILE "wallycore-targets.cmake" 84 | ) 85 | -------------------------------------------------------------------------------- /contrib/bullseye_deps.sh: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env bash 2 | # Install required dependencies for building wally 3 | # Options: 4 | # -e : Don't install emsdk (used for JS builds) 5 | # -j : Don't install Java SDK (used for Java builds) 6 | # -n : Don't install Android NDK (used for Android builds) 7 | # -w : Don't install MinGW (used for Windows cross compiles) 8 | set -e 9 | 10 | skip_emsdk= 11 | skip_ndk= 12 | skip_java= 13 | skip_windows= 14 | while getopts enjw name 15 | do 16 | case $name in 17 | e) skip_emsdk=1;; 18 | n) skip_ndk=1;; 19 | j) skip_java=1;; 20 | w) skip_windows=1;; 21 | *) echo "Invalid flag"; exit 1;; 22 | esac 23 | done 24 | shift $(($OPTIND - 1)) 25 | 26 | apt update -qq 27 | apt upgrade -yqq 28 | 29 | java_packages= 30 | if [ -z "$skip_java" ]; then 31 | java_packages="openjdk-11-jdk openjdk-11-jre" 32 | fi 33 | windows_packages= 34 | if [ -z "$skip_windows" ]; then 35 | windows_packages="g++-mingw-w64-x86-64" 36 | fi 37 | apt install --no-install-recommends unzip autoconf automake autotools-dev pkg-config build-essential libtool python3{,-dev,-pip,-virtualenv} python{,-dev}-is-python3 clang{,-format,-tidy} git swig curl cmake libssl-dev libtool-bin $java_packages curl $windows_packages valgrind jq -yqq 38 | 39 | if [ -z "$skip_java" ]; then 40 | update-java-alternatives -s $(basename ${JAVA_HOME}) 41 | fi 42 | 43 | pip3 install valgrind-codequality -r contrib/requirements.txt 44 | 45 | pushd /opt 46 | 47 | if [ -z "$skip_ndk" ]; then 48 | curl -L -o ndk.zip https://dl.google.com/android/repository/android-ndk-r26b-linux.zip 49 | echo "ad73c0370f0b0a87d1671ed2fd5a9ac9acfd1eb5c43a7fbfbd330f85d19dd632 ndk.zip" | shasum -a 256 -c 50 | unzip ndk.zip 51 | rm ndk.zip 52 | fi 53 | 54 | if [ -z "$skip_emsdk" ]; then 55 | # Install node 20 56 | curl -fsSL https://deb.nodesource.com/setup_20.x | bash - 57 | apt install nodejs -yqq 58 | # Install emsdk 59 | git clone https://github.com/emscripten-core/emsdk 60 | cd emsdk 61 | EMSDK_VERSION=3.1.52 62 | if [ "${TARGETARCH}" = "arm64" ]; then 63 | # very few versions of emsdk are available for linux-arm64 64 | # https://github.com/emscripten-core/emsdk/issues/547 65 | EMSDK_VERSION=3.1.33 66 | fi 67 | ./emsdk install ${EMSDK_VERSION} 68 | ./emsdk activate ${EMSDK_VERSION} 69 | # Force emsdk to use the installed node version instead of its own 70 | sed -i "s/^NODE_JS = .*$/NODE_JS = 'node'/g" /opt/emsdk/.emscripten 71 | # Make emsdk commands available 72 | source ./emsdk_env.sh 73 | fi 74 | 75 | if [ -f /.dockerenv ]; then 76 | # Installing dependencies into a docker image. 77 | # Purge uneeded files to keep the image as small as possible. 78 | apt remove --purge curl unzip -yqq 79 | apt -yqq autoremove 80 | apt -yqq clean 81 | rm -rf /var/lib/apt/lists/* /var/cache/* /tmp/* /usr/share/locale/* /usr/share/man /usr/share/doc /lib/xtables/libip6* /root/.cache 82 | fi 83 | 84 | popd 85 | -------------------------------------------------------------------------------- /src/ccan/ccan/crypto/ripemd160/test/run-test-vectors.c: -------------------------------------------------------------------------------- 1 | #include 2 | /* Include the C files directly. */ 3 | #include 4 | #include 5 | 6 | /* Test vectors. */ 7 | struct test { 8 | const char *test; 9 | size_t repetitions; 10 | beint32_t result[5]; 11 | }; 12 | 13 | /* Test vectors from: http://homes.esat.kuleuven.be/~bosselae/ripemd160.html */ 14 | static struct test tests[] = { 15 | { "", 1, 16 | { CPU_TO_BE32(0x9c1185a5), CPU_TO_BE32(0xc5e9fc54), 17 | CPU_TO_BE32(0x61280897), CPU_TO_BE32(0x7ee8f548), 18 | CPU_TO_BE32(0xb2258d31) } }, 19 | { "abc", 1, 20 | { CPU_TO_BE32(0x8eb208f7), CPU_TO_BE32(0xe05d987a), 21 | CPU_TO_BE32(0x9b044a8e), CPU_TO_BE32(0x98c6b087), 22 | CPU_TO_BE32(0xf15a0bfc) } }, 23 | { "message digest", 1, 24 | { CPU_TO_BE32(0x5d0689ef), CPU_TO_BE32(0x49d2fae5), 25 | CPU_TO_BE32(0x72b881b1), CPU_TO_BE32(0x23a85ffa), 26 | CPU_TO_BE32(0x21595f36) } }, 27 | { "abcdefghijklmnopqrstuvwxyz", 1, 28 | { CPU_TO_BE32(0xf71c2710), CPU_TO_BE32(0x9c692c1b), 29 | CPU_TO_BE32(0x56bbdceb), CPU_TO_BE32(0x5b9d2865), 30 | CPU_TO_BE32(0xb3708dbc) } }, 31 | { "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq", 1, 32 | { CPU_TO_BE32(0x12a05338), CPU_TO_BE32(0x4a9c0c88), 33 | CPU_TO_BE32(0xe405a06c), CPU_TO_BE32(0x27dcf49a), 34 | CPU_TO_BE32(0xda62eb2b) } }, 35 | { "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789", 1, 36 | { CPU_TO_BE32(0xb0e20b6e), CPU_TO_BE32(0x31166402), 37 | CPU_TO_BE32(0x86ed3a87), CPU_TO_BE32(0xa5713079), 38 | CPU_TO_BE32(0xb21f5189) } }, 39 | { "1234567890", 8, 40 | { CPU_TO_BE32(0x9b752e45), CPU_TO_BE32(0x573d4b39), 41 | CPU_TO_BE32(0xf4dbd332), CPU_TO_BE32(0x3cab82bf), 42 | CPU_TO_BE32(0x63326bfb) } }, 43 | { "a", 1000000, 44 | { CPU_TO_BE32(0x52783243), CPU_TO_BE32(0xc1697bdb), 45 | CPU_TO_BE32(0xe16d37f9), CPU_TO_BE32(0x7f68f083), 46 | CPU_TO_BE32(0x25dc1528) } } 47 | }; 48 | 49 | static bool do_test(const struct test *t, bool single) 50 | { 51 | struct ripemd160 h; 52 | 53 | if (single) { 54 | if (t->repetitions != 1) 55 | return true; 56 | ripemd160(&h, t->test, strlen(t->test)); 57 | } else { 58 | struct ripemd160_ctx ctx = RIPEMD160_INIT; 59 | size_t i; 60 | 61 | for (i = 0; i < t->repetitions; i++) 62 | ripemd160_update(&ctx, t->test, strlen(t->test)); 63 | ripemd160_done(&ctx, &h); 64 | } 65 | 66 | return memcmp(&h.u, t->result, sizeof(t->result)) == 0; 67 | } 68 | 69 | int main(void) 70 | { 71 | size_t i; 72 | 73 | /* This is how many tests you plan to run */ 74 | plan_tests(sizeof(tests) / sizeof(struct test) * 2); 75 | 76 | for (i = 0; i < sizeof(tests) / sizeof(struct test); i++) 77 | ok1(do_test(&tests[i], false)); 78 | 79 | for (i = 0; i < sizeof(tests) / sizeof(struct test); i++) 80 | ok1(do_test(&tests[i], true)); 81 | 82 | /* This exits depending on whether all tests passed */ 83 | return exit_status(); 84 | } 85 | -------------------------------------------------------------------------------- /tools/android_helpers.sh: -------------------------------------------------------------------------------- 1 | # Source this file from your build scripts to use the functions provided 2 | 3 | # List the android architectures supported by wally 4 | function android_get_arch_list() { 5 | echo "armeabi-v7a arm64-v8a x86 x86_64" 6 | } 7 | 8 | 9 | # Get the location of the android NDK build tools to build with 10 | function android_get_build_tools_dir() { 11 | if [ "$(uname)" == "Darwin" ]; then 12 | echo $ANDROID_NDK/toolchains/llvm/prebuilt/darwin-x86_64 13 | else 14 | echo $ANDROID_NDK/toolchains/llvm/prebuilt/linux-x86_64 15 | fi 16 | } 17 | 18 | 19 | # Get the cross compile target for a given android architecture, 20 | # used to determine the build tools to use. 21 | # arch: An architecture from android_get_arch_list() 22 | function android_get_cross_compile_target() { 23 | local arch=$1 24 | case $arch in 25 | armeabi-v7a) echo "armv7a-linux-androideabi";; 26 | arm64-v8a) echo "aarch64-linux-android";; 27 | x86) echo "i686-linux-android";; 28 | x86_64) echo "x86_64-linux-android";; 29 | *) 30 | echo "ERROR: Unknown arch $arch" >&2 31 | exit 1 32 | ;; 33 | esac 34 | } 35 | 36 | 37 | # Get the cross compile triplet for a given android architecture, 38 | # passed as --host to configure 39 | # arch: An architecture from android_get_arch_list() 40 | # api: The minimum Android API level to build for (e.g. 21) 41 | function android_get_cross_compile_triplet() { 42 | local arch=$1 api=$3 43 | case $arch in 44 | armeabi-v7a) echo "armv7-none-linux-androideabi$api";; 45 | arm64-v8a) echo "aarch64-none-linux-android$api";; 46 | x86) echo "i686-none-linux-android$api";; 47 | x86_64) echo "x86_64-none-linux-android$api";; 48 | *) 49 | echo "ERROR: Unknown arch $arch" >&2 50 | exit 1 51 | ;; 52 | esac 53 | } 54 | 55 | 56 | # Create a toolchain configure and build wally for Android 57 | # arch: An architecture from android_get_arch_list() 58 | # toolsdir: The directory for the NDK toolchain 59 | # api: The minimum Android API level to build for (e.g. 21) 60 | # useropts: The users configure options e.g. --enable-swig-java 61 | function android_build_wally() { 62 | local arch=$1 toolsdir=$2 api=$3 63 | shift 3 64 | local useropts=$* 65 | local target=$(android_get_cross_compile_target $arch) 66 | 67 | AR=$toolsdir/bin/llvm-ar \ 68 | CC=$toolsdir/bin/$target$api-clang \ 69 | AS=$toolsdir/bin/$target$api-clang \ 70 | LD=$toolsdir/bin/ld \ 71 | RANLIB=$toolsdir/bin/llvm-ranlib \ 72 | STRIP=$toolsdir/bin/llvm-strip \ 73 | ./configure --host=$(android_get_cross_compile_triplet $arch $api) \ 74 | --enable-swig-java --disable-swig-python $useropts 75 | local num_jobs=4 76 | if [ -f /proc/cpuinfo ]; then 77 | num_jobs=$(grep ^processor /proc/cpuinfo | wc -l) 78 | fi 79 | PATH="$toolsdir/bin:$PATH" make -o configure clean 80 | PATH="$toolsdir/bin:$PATH" make -o configure -j $num_jobs 81 | } 82 | -------------------------------------------------------------------------------- /contrib/bookworm_deps.sh: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env bash 2 | # Install required dependencies for building wally 3 | # Options: 4 | # -e : Don't install emsdk (used for JS builds) 5 | # -j : Don't install Java SDK (used for Java builds) 6 | # -n : Don't install Android NDK (used for Android builds) 7 | # -w : Don't install MinGW (used for Windows cross compiles) 8 | set -e 9 | 10 | skip_emsdk= 11 | skip_ndk= 12 | skip_java= 13 | skip_windows= 14 | while getopts enjw name 15 | do 16 | case $name in 17 | e) skip_emsdk=1;; 18 | n) skip_ndk=1;; 19 | j) skip_java=1;; 20 | w) skip_windows=1;; 21 | *) echo "Invalid flag"; exit 1;; 22 | esac 23 | done 24 | shift $(($OPTIND - 1)) 25 | 26 | apt update -qq 27 | apt upgrade -yqq 28 | 29 | java_packages= 30 | if [ -z "$skip_java" ]; then 31 | java_packages="openjdk-17-jdk openjdk-17-jre" 32 | fi 33 | windows_packages= 34 | if [ -z "$skip_windows" ]; then 35 | windows_packages="g++-mingw-w64-x86-64" 36 | fi 37 | apt install --no-install-recommends unzip autoconf automake autotools-dev pkg-config build-essential libtool python3{,-dev,-pip,-virtualenv} python{,-dev}-is-python3 clang{,-format,-tidy} git swig curl cmake libssl-dev libtool-bin $java_packages curl $windows_packages valgrind jq -yqq 38 | 39 | if [ -z "$skip_java" ]; then 40 | update-java-alternatives -s $(basename ${JAVA_HOME}) 41 | fi 42 | 43 | # Note --break-system-packages to allow installing our requirements system-wide 44 | pip install valgrind-codequality -r contrib/requirements.txt --break-system-packages 45 | 46 | pushd /opt 47 | 48 | if [ -z "$skip_ndk" ]; then 49 | curl -L -o ndk.zip https://dl.google.com/android/repository/android-ndk-r26b-linux.zip 50 | echo "ad73c0370f0b0a87d1671ed2fd5a9ac9acfd1eb5c43a7fbfbd330f85d19dd632 ndk.zip" | shasum -a 256 -c 51 | unzip ndk.zip 52 | rm ndk.zip 53 | fi 54 | 55 | if [ -z "$skip_emsdk" ]; then 56 | # Install node 20 57 | curl -fsSL https://deb.nodesource.com/setup_20.x | bash - 58 | apt install nodejs -yqq 59 | # Install emsdk 60 | git clone https://github.com/emscripten-core/emsdk 61 | cd emsdk 62 | EMSDK_VERSION=3.1.52 63 | if [ "${TARGETARCH}" = "arm64" ]; then 64 | # very few versions of emsdk are available for linux-arm64 65 | # https://github.com/emscripten-core/emsdk/issues/547 66 | EMSDK_VERSION=3.1.33 67 | fi 68 | ./emsdk install ${EMSDK_VERSION} 69 | ./emsdk activate ${EMSDK_VERSION} 70 | # Force emsdk to use the installed node version instead of its own 71 | sed -i "s/^NODE_JS = .*$/NODE_JS = 'node'/g" /opt/emsdk/.emscripten 72 | # Make emsdk commands available 73 | source ./emsdk_env.sh 74 | fi 75 | 76 | if [ -f /.dockerenv ]; then 77 | # Installing dependencies into a docker image. 78 | # Purge uneeded files to keep the image as small as possible. 79 | apt remove --purge curl unzip -yqq 80 | apt -yqq autoremove 81 | apt -yqq clean 82 | rm -rf /var/lib/apt/lists/* /var/cache/* /tmp/* /usr/share/locale/* /usr/share/man /usr/share/doc /lib/xtables/libip6* /root/.cache 83 | fi 84 | 85 | popd 86 | -------------------------------------------------------------------------------- /src/test/test_hex.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | from util import * 3 | 4 | class HexTests(unittest.TestCase): 5 | 6 | def test_hex_verify(self): 7 | # Valid inputs 8 | self.assertEqual(wally_hex_verify(utf8('00')), WALLY_OK) 9 | 10 | # Bad inputs 11 | self.assertEqual(wally_hex_verify(None), WALLY_EINVAL) # NULL hex 12 | self.assertEqual(wally_hex_verify(''), WALLY_EINVAL) # Empty hex 13 | self.assertEqual(wally_hex_verify(utf8('a')), WALLY_EINVAL) # Odd length input 14 | self.assertEqual(wally_hex_verify(utf8('xy')), WALLY_EINVAL) # Non-hex 15 | 16 | self.assertEqual(wally_hex_n_verify(None, 2), WALLY_EINVAL) # NULL hex 17 | self.assertEqual(wally_hex_n_verify(utf8('00'), 0), WALLY_EINVAL) # 0 Length 18 | self.assertEqual(wally_hex_n_verify(utf8('00'), 1), WALLY_EINVAL) # Odd Length 19 | 20 | def test_hex_to_bytes(self): 21 | LEN = 4 22 | buf, buf_len = make_cbuffer('00' * LEN) 23 | 24 | for i in range(256): 25 | for s in ("%02X" % i, "%02x" % i): # Upper/Lower 26 | hex_ = utf8(s * LEN) 27 | ret, written = wally_hex_to_bytes(hex_, buf, buf_len) 28 | self.assertEqual((ret, written), (WALLY_OK, LEN)) 29 | ret, written = wally_hex_n_to_bytes(hex_, len(hex_), buf, buf_len) 30 | self.assertEqual((ret, written), (WALLY_OK, LEN)) 31 | 32 | # Bad inputs 33 | for (s, b, l) in [(None, buf, buf_len), 34 | (utf8('00'), None, buf_len), 35 | (utf8('000'), buf, buf_len), 36 | (utf8('00'), buf, 0)]: 37 | ret, written = wally_hex_to_bytes(s, b, l) 38 | self.assertEqual((ret, written), (WALLY_EINVAL, 0)) 39 | ret, written = wally_hex_n_to_bytes(s, len(s) if s else 0, b, l) 40 | self.assertEqual((ret, written), (WALLY_EINVAL, 0)) 41 | 42 | for l in (1, # Too small, returns the required length 43 | LEN): # Too large, returns length written 44 | ret, written = wally_hex_to_bytes(utf8('0000'), buf, l) 45 | self.assertEqual((ret, written), (WALLY_OK, 2)) 46 | 47 | # Empty string 48 | ret, written = wally_hex_to_bytes(utf8(''), buf, buf_len) 49 | self.assertEqual((ret, written), (WALLY_OK, 0)) 50 | 51 | 52 | def test_hex_from_bytes(self): 53 | LEN = 4 54 | 55 | for i in range(256): 56 | s = "%02x" % i * LEN 57 | buf, buf_len = make_cbuffer(s) 58 | ret, retstr = wally_hex_from_bytes(buf, buf_len) 59 | self.assertEqual((ret, retstr), (WALLY_OK, s)) 60 | 61 | # Bad input 62 | ret, written = wally_hex_from_bytes(None, buf_len) 63 | self.assertEqual((ret, written), (WALLY_EINVAL, None)) 64 | 65 | # Empty buffer 66 | ret, written = wally_hex_from_bytes(buf, 0) 67 | self.assertEqual((ret, written), (WALLY_OK, '')) 68 | 69 | 70 | if __name__ == '__main__': 71 | unittest.main() 72 | -------------------------------------------------------------------------------- /src/swig_python/contrib/reconcile_sigs.py: -------------------------------------------------------------------------------- 1 | """Tests for reconciling pycoin and wally transaction signature hashes""" 2 | import unittest 3 | from wallycore import * 4 | try: 5 | from pycoin.tx.Tx import Tx, TxIn, TxOut 6 | from pycoin.encoding import to_bytes_32 7 | have_pycoin = True 8 | except ImportError: 9 | have_pycoin = False 10 | 11 | 12 | class TxTests(unittest.TestCase): 13 | 14 | def do_test_tx(self, sighash, index_, flags): 15 | txhash, seq, script = b'0' * 32, 0xffffffff, b'\x51' 16 | out_script, spend_script, locktime = b'\x00\x00\x51', b'\x00\x51', 999999 17 | txs_in = [TxIn(txhash, 0, script, seq), 18 | TxIn(txhash, 1, script+b'\x51', seq-1), 19 | TxIn(txhash, 2, script+b'\x51\x51', seq-2), 20 | TxIn(txhash, 3, script+b'\x51\x51\x51', seq-3)] 21 | txs_out = [TxOut(55, out_script), 22 | TxOut(54, out_script+b'\x51'), 23 | TxOut(53, out_script+b'\x51\x51')] 24 | pytx = Tx(2, txs_in, txs_out, lock_time=locktime) 25 | pytx.unspents = {0: TxOut(5000, spend_script), # FIXME: Make script unique 26 | 1: TxOut(5001, spend_script), 27 | 2: TxOut(5002, spend_script), 28 | 3: TxOut(5003, spend_script)} 29 | unspent = pytx.unspents[index_] 30 | pytx_hex = pytx.as_hex() 31 | if flags & WALLY_TX_FLAG_USE_WITNESS: 32 | pytx_hash = pytx.signature_for_hash_type_segwit(unspent.script, index_, sighash) 33 | else: 34 | pytx_hash = pytx.signature_hash(spend_script, index_, sighash) 35 | pytx_hash = hex_from_bytes(to_bytes_32(pytx_hash)) 36 | 37 | tx = tx_init(2, locktime, 3, 3) 38 | tx_add_input(tx, tx_input_init(txhash, 0, seq, script, None)) 39 | tx_add_raw_input(tx, txhash, 1, seq-1, script+b'\x51', None, 0) 40 | tx_add_raw_input(tx, txhash, 2, seq-2, script+b'\x51\x51', None, 0) 41 | tx_add_raw_input(tx, txhash, 3, seq-3, script+b'\x51\x51\x51', None, 0) 42 | tx_add_raw_output(tx, 55, out_script, 0) 43 | tx_add_raw_output(tx, 54, out_script+b'\x51', 0) 44 | tx_add_raw_output(tx, 53, out_script+b'\x51\x51', 0) 45 | tx_hex = tx_to_hex(tx, 0) 46 | tx_hash = tx_get_btc_signature_hash(tx, index_, 47 | unspent.script, unspent.coin_value, 48 | sighash, flags) 49 | tx_hash = hex_from_bytes(tx_hash) 50 | 51 | self.assertEqual(pytx_hex, tx_hex) 52 | self.assertEqual(pytx_hash, tx_hash) 53 | 54 | def test_tx(self): 55 | for sighash in [WALLY_SIGHASH_ALL, WALLY_SIGHASH_NONE, WALLY_SIGHASH_SINGLE]: 56 | for index_ in [0, 1, 2, 3]: 57 | for anyonecanpay in [0, WALLY_SIGHASH_ANYONECANPAY]: 58 | for flags in [0, WALLY_TX_FLAG_USE_WITNESS]: 59 | self.do_test_tx(sighash | anyonecanpay, index_, flags) 60 | 61 | 62 | if __name__ == '__main__': 63 | if have_pycoin: 64 | unittest.main() 65 | -------------------------------------------------------------------------------- /_cmake/config.h.in: -------------------------------------------------------------------------------- 1 | #ifndef LIBWALLYCORE_CONFIG_H 2 | #define LIBWALLYCORE_CONFIG_H 3 | 4 | /* Define if building universal (internal helper macro) */ 5 | #cmakedefine AC_APPLE_UNIVERSAL_BUILD @AC_APPLE_UNIVERSAL_BUILD@ 6 | 7 | /* Define to 1 if you have the header file. */ 8 | #cmakedefine HAVE_ASM_PAGE_H @HAVE_ASM_PAGE_H@ 9 | 10 | 11 | /* Define to 1 if you have the header file. */ 12 | #cmakedefine HAVE_BYTESWAP_H @HAVE_BYTESWAP_H@ 13 | 14 | /* Define to 1 if you have the `explicit_bzero' function. */ 15 | #cmakedefine HAVE_EXPLICIT_BZERO @HAVE_EXPLICIT_BZERO@ 16 | 17 | /* Define to 1 if you have the `explicit_memset' function. */ 18 | #cmakedefine HAVE_EXPLICIT_MEMSET @HAVE_EXPLICIT_MEMSET@ 19 | 20 | /* inline asm code can be used */ 21 | #cmakedefine HAVE_INLINE_ASM @HAVE_INLINE_ASM@ 22 | 23 | /* Define to 1 if you have the header file. */ 24 | #cmakedefine HAVE_MBEDTLS_SHA256_H_ @HAVE_MBEDTLS_SHA256_H@ 25 | 26 | /* Define to 1 if you have the header file. */ 27 | #cmakedefine HAVE_MBEDTLS_SHA512_H @HAVE_MBEDTLS_SHA512_H@ 28 | 29 | /* Define to 1 if you have the `memset_s' function. */ 30 | #cmakedefine HAVE_MEMSET_S @HAVE_MEMSET_S@ 31 | 32 | /* Define if we have mmap */ 33 | #cmakedefine HAVE_MMAP @HAVE_MMAP@ 34 | 35 | /* Define if we have posix_memalign */ 36 | #cmakedefine HAVE_POSIX_MEMALIGN @HAVE_POSIX_MEMALIGN@ 37 | 38 | /* Define to 1 if you have the header file. */ 39 | #cmakedefine HAVE_SYS_MMAN_H @HAVE_SYS_MMAN_H@ 40 | 41 | /* Define if we have unaligned access */ 42 | #cmakedefine HAVE_UNALIGNED_ACCESS @HAVE_UNALIGNED_ACCESS@ 43 | 44 | /* Name of package */ 45 | #cmakedefine PACKAGE @PACKAGE@ 46 | 47 | /* Define to the address where bug reports for this package should be sent. */ 48 | #cmakedefine PACKAGE_BUGREPORT @PACKAGE_BUGREPORT@ 49 | 50 | /* Define to the full name of this package. */ 51 | #cmakedefine PACKAGE_NAME @PACKAGE_NAME@ 52 | 53 | /* Define to the full name and version of this package. */ 54 | #cmakedefine PACKAGE_STRING @PACKAGE_STRING@ 55 | 56 | /* Define to the one symbol short name of this package. */ 57 | #cmakedefine PACKAGE_TARNAME @PACKAGE_TARNAME@ 58 | 59 | /* Define to the home page for this package. */ 60 | #cmakedefine PACKAGE_URL @PACKAGE_URL@ 61 | 62 | /* Define to the version of this package. */ 63 | #cmakedefine PACKAGE_VERSION @PACKAGE_VERSION@ 64 | 65 | /* Version number of package */ 66 | #cmakedefine VERSION @VERSION@ 67 | 68 | /* Define WORDS_BIGENDIAN to 1 if your processor stores words with the most 69 | significant byte first (like Motorola and SPARC, unlike Intel). */ 70 | #if defined AC_APPLE_UNIVERSAL_BUILD 71 | # if defined __BIG_ENDIAN__ 72 | # define WORDS_BIGENDIAN 1 73 | # endif 74 | #else 75 | # ifndef WORDS_BIGENDIAN 76 | #cmakedefine WORDS_BIGENDIAN @WORDS_BIGENDIAN@ 77 | # endif 78 | #endif 79 | 80 | #if defined (_WIN32) && !defined(_SSIZE_T_DECLARED) && !defined(_ssize_t) && !defined(ssize_t) 81 | #if defined(_WIN64) 82 | typedef __int64 ssize_t; 83 | #else 84 | typedef long ssize_t; 85 | #endif 86 | #endif 87 | 88 | #include "ccan_config.h" 89 | #endif /* LIBWALLYCORE_CONFIG_H */ 90 | -------------------------------------------------------------------------------- /src/ccan/ccan/crypto/sha256/test/run-test-vectors.c: -------------------------------------------------------------------------------- 1 | #include 2 | /* Include the C files directly. */ 3 | #include 4 | #include 5 | 6 | /* Test vectors. */ 7 | struct test { 8 | const char *test; 9 | size_t repetitions; 10 | beint32_t result[8]; 11 | }; 12 | 13 | static struct test tests[] = { 14 | { "", 1, 15 | { CPU_TO_BE32(0xe3b0c442), CPU_TO_BE32(0x98fc1c14), 16 | CPU_TO_BE32(0x9afbf4c8), CPU_TO_BE32(0x996fb924), 17 | CPU_TO_BE32(0x27ae41e4), CPU_TO_BE32(0x649b934c), 18 | CPU_TO_BE32(0xa495991b), CPU_TO_BE32(0x7852b855) } }, 19 | { "abc", 1, 20 | { CPU_TO_BE32(0xba7816bf), CPU_TO_BE32(0x8f01cfea), 21 | CPU_TO_BE32(0x414140de), CPU_TO_BE32(0x5dae2223), 22 | CPU_TO_BE32(0xb00361a3), CPU_TO_BE32(0x96177a9c), 23 | CPU_TO_BE32(0xb410ff61), CPU_TO_BE32(0xf20015ad) } }, 24 | { "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq", 1, 25 | { CPU_TO_BE32(0x248d6a61), CPU_TO_BE32(0xd20638b8), 26 | CPU_TO_BE32(0xe5c02693), CPU_TO_BE32(0x0c3e6039), 27 | CPU_TO_BE32(0xa33ce459), CPU_TO_BE32(0x64ff2167), 28 | CPU_TO_BE32(0xf6ecedd4), CPU_TO_BE32(0x19db06c1) } }, 29 | { "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu", 1, 30 | { CPU_TO_BE32(0xcf5b16a7), CPU_TO_BE32(0x78af8380), 31 | CPU_TO_BE32(0x036ce59e), CPU_TO_BE32(0x7b049237), 32 | CPU_TO_BE32(0x0b249b11), CPU_TO_BE32(0xe8f07a51), 33 | CPU_TO_BE32(0xafac4503), CPU_TO_BE32(0x7afee9d1) } }, 34 | { "a", 1000000, 35 | { CPU_TO_BE32(0xcdc76e5c), CPU_TO_BE32(0x9914fb92), 36 | CPU_TO_BE32(0x81a1c7e2), CPU_TO_BE32(0x84d73e67), 37 | CPU_TO_BE32(0xf1809a48), CPU_TO_BE32(0xa497200e), 38 | CPU_TO_BE32(0x046d39cc), CPU_TO_BE32(0xc7112cd0) } } 39 | #if 0 /* Good test, but takes ages! */ 40 | , { "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmno", 16777216, 41 | { CPU_TO_BE32(0x50e72a0e), CPU_TO_BE32(0x26442fe2), 42 | CPU_TO_BE32(0x552dc393), CPU_TO_BE32(0x8ac58658), 43 | CPU_TO_BE32(0x228c0cbf), CPU_TO_BE32(0xb1d2ca87), 44 | CPU_TO_BE32(0x2ae43526), CPU_TO_BE32(0x6fcd055e) } } 45 | #endif 46 | }; 47 | 48 | static bool do_test(const struct test *t, bool single) 49 | { 50 | struct sha256 h; 51 | 52 | if (single) { 53 | if (t->repetitions != 1) 54 | return true; 55 | sha256(&h, t->test, strlen(t->test)); 56 | } else { 57 | struct sha256_ctx ctx = SHA256_INIT; 58 | size_t i; 59 | 60 | for (i = 0; i < t->repetitions; i++) 61 | sha256_update(&ctx, t->test, strlen(t->test)); 62 | sha256_done(&ctx, &h); 63 | } 64 | 65 | return memcmp(&h.u, t->result, sizeof(t->result)) == 0; 66 | } 67 | 68 | int main(void) 69 | { 70 | size_t i; 71 | 72 | /* This is how many tests you plan to run */ 73 | plan_tests(sizeof(tests) / sizeof(struct test) * 2); 74 | 75 | for (i = 0; i < sizeof(tests) / sizeof(struct test); i++) 76 | ok1(do_test(&tests[i], false)); 77 | 78 | for (i = 0; i < sizeof(tests) / sizeof(struct test); i++) 79 | ok1(do_test(&tests[i], true)); 80 | 81 | /* This exits depending on whether all tests passed */ 82 | return exit_status(); 83 | } 84 | -------------------------------------------------------------------------------- /src/wordlist.c: -------------------------------------------------------------------------------- 1 | #include "internal.h" 2 | #include "wordlist.h" 3 | 4 | static int bstrcmp(const void *l, const void *r) 5 | { 6 | return strcmp(l, (*(const char **)r)); 7 | } 8 | 9 | /* https://graphics.stanford.edu/~seander/bithacks.html#IntegerLogObvious */ 10 | static size_t get_bits(size_t n) 11 | { 12 | size_t bits = 0; 13 | while (n >>= 1) 14 | ++bits; 15 | return bits; 16 | } 17 | 18 | /* Allocate a new words structure */ 19 | static struct words *wordlist_alloc(const char *words, size_t len) 20 | { 21 | struct words *w = wally_malloc(sizeof(struct words)); 22 | if (w) { 23 | wally_clear(w, sizeof(*w)); 24 | w->str = wally_strdup(words); 25 | if (w->str) { 26 | w->str_len = strlen(w->str); 27 | w->len = len; 28 | w->bits = get_bits(len); 29 | w->indices = wally_malloc(len * sizeof(const char *)); 30 | if (w->indices) 31 | return w; 32 | } 33 | wordlist_free(w); 34 | } 35 | return NULL; 36 | } 37 | 38 | static size_t wordlist_count(const char *words) 39 | { 40 | size_t len = 1u; /* Always 1 less separator than words, so start from 1 */ 41 | while (*words) 42 | len += *words++ == ' '; /* FIXME: utf-8 sep */ 43 | return len; 44 | } 45 | 46 | struct words *wordlist_init(const char *words) 47 | { 48 | size_t i, len = wordlist_count(words); 49 | struct words *w = wordlist_alloc(words, len); 50 | 51 | if (w) { 52 | /* Tokenise the strings into w->indices */ 53 | const char *p = w->str; 54 | for (len = 0; len < w->len; ++len) { 55 | w->indices[len] = p; 56 | while (*p && *p != ' ') /* FIXME: utf-8 sep */ 57 | ++p; 58 | *((char *)p) = '\0'; 59 | ++p; 60 | } 61 | 62 | w->sorted = true; 63 | for (i = 1; i < len && w->sorted; ++i) 64 | if (strcmp(w->indices[i - 1], w->indices[i]) > 0) 65 | w->sorted = false; 66 | } 67 | return w; 68 | } 69 | 70 | size_t wordlist_lookup_word(const struct words *w, const char *word) 71 | { 72 | const size_t size = sizeof(const char *); 73 | const char **found = NULL; 74 | 75 | if (w->sorted) 76 | found = (const char **)bsearch(word, w->indices, w->len, size, bstrcmp); 77 | else { 78 | size_t i; 79 | for (i = 0; i < w->len && !found; ++i) 80 | if (!strcmp(word, w->indices[i])) 81 | found = w->indices + i; 82 | } 83 | return found ? found - w->indices + 1u : 0u; 84 | } 85 | 86 | const char *wordlist_lookup_index(const struct words *w, size_t idx) 87 | { 88 | if (idx >= w->len) 89 | return NULL; 90 | return w->indices[idx]; 91 | } 92 | 93 | void wordlist_free(struct words *w) 94 | { 95 | if (w) { 96 | if (w->str) { 97 | if (w->str_len) 98 | wally_clear((void *)w->str, w->str_len); 99 | wally_free((void *)w->str); 100 | } 101 | if (w->indices) 102 | wally_free((void *)w->indices); /* No need to clear */ 103 | clear_and_free(w, sizeof(*w)); 104 | } 105 | } 106 | -------------------------------------------------------------------------------- /src/ccan/ccan/endian/test/run.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | int main(int argc, char *argv[]) 7 | { 8 | union { 9 | uint64_t u64; 10 | unsigned char u64_bytes[8]; 11 | } u64; 12 | union { 13 | uint32_t u32; 14 | unsigned char u32_bytes[4]; 15 | } u32; 16 | union { 17 | uint16_t u16; 18 | unsigned char u16_bytes[2]; 19 | } u16; 20 | 21 | plan_tests(48); 22 | 23 | /* Straight swap tests. */ 24 | u64.u64_bytes[0] = 0x00; 25 | u64.u64_bytes[1] = 0x11; 26 | u64.u64_bytes[2] = 0x22; 27 | u64.u64_bytes[3] = 0x33; 28 | u64.u64_bytes[4] = 0x44; 29 | u64.u64_bytes[5] = 0x55; 30 | u64.u64_bytes[6] = 0x66; 31 | u64.u64_bytes[7] = 0x77; 32 | u64.u64 = bswap_64(u64.u64); 33 | ok1(u64.u64_bytes[7] == 0x00); 34 | ok1(u64.u64_bytes[6] == 0x11); 35 | ok1(u64.u64_bytes[5] == 0x22); 36 | ok1(u64.u64_bytes[4] == 0x33); 37 | ok1(u64.u64_bytes[3] == 0x44); 38 | ok1(u64.u64_bytes[2] == 0x55); 39 | ok1(u64.u64_bytes[1] == 0x66); 40 | ok1(u64.u64_bytes[0] == 0x77); 41 | 42 | u32.u32_bytes[0] = 0x00; 43 | u32.u32_bytes[1] = 0x11; 44 | u32.u32_bytes[2] = 0x22; 45 | u32.u32_bytes[3] = 0x33; 46 | u32.u32 = bswap_32(u32.u32); 47 | ok1(u32.u32_bytes[3] == 0x00); 48 | ok1(u32.u32_bytes[2] == 0x11); 49 | ok1(u32.u32_bytes[1] == 0x22); 50 | ok1(u32.u32_bytes[0] == 0x33); 51 | 52 | u16.u16_bytes[0] = 0x00; 53 | u16.u16_bytes[1] = 0x11; 54 | u16.u16 = bswap_16(u16.u16); 55 | ok1(u16.u16_bytes[1] == 0x00); 56 | ok1(u16.u16_bytes[0] == 0x11); 57 | 58 | /* Endian tests. */ 59 | u64.u64 = cpu_to_le64(0x0011223344556677ULL); 60 | ok1(u64.u64_bytes[0] == 0x77); 61 | ok1(u64.u64_bytes[1] == 0x66); 62 | ok1(u64.u64_bytes[2] == 0x55); 63 | ok1(u64.u64_bytes[3] == 0x44); 64 | ok1(u64.u64_bytes[4] == 0x33); 65 | ok1(u64.u64_bytes[5] == 0x22); 66 | ok1(u64.u64_bytes[6] == 0x11); 67 | ok1(u64.u64_bytes[7] == 0x00); 68 | ok1(le64_to_cpu(u64.u64) == 0x0011223344556677ULL); 69 | 70 | u64.u64 = cpu_to_be64(0x0011223344556677ULL); 71 | ok1(u64.u64_bytes[7] == 0x77); 72 | ok1(u64.u64_bytes[6] == 0x66); 73 | ok1(u64.u64_bytes[5] == 0x55); 74 | ok1(u64.u64_bytes[4] == 0x44); 75 | ok1(u64.u64_bytes[3] == 0x33); 76 | ok1(u64.u64_bytes[2] == 0x22); 77 | ok1(u64.u64_bytes[1] == 0x11); 78 | ok1(u64.u64_bytes[0] == 0x00); 79 | ok1(be64_to_cpu(u64.u64) == 0x0011223344556677ULL); 80 | 81 | u32.u32 = cpu_to_le32(0x00112233); 82 | ok1(u32.u32_bytes[0] == 0x33); 83 | ok1(u32.u32_bytes[1] == 0x22); 84 | ok1(u32.u32_bytes[2] == 0x11); 85 | ok1(u32.u32_bytes[3] == 0x00); 86 | ok1(le32_to_cpu(u32.u32) == 0x00112233); 87 | 88 | u32.u32 = cpu_to_be32(0x00112233); 89 | ok1(u32.u32_bytes[3] == 0x33); 90 | ok1(u32.u32_bytes[2] == 0x22); 91 | ok1(u32.u32_bytes[1] == 0x11); 92 | ok1(u32.u32_bytes[0] == 0x00); 93 | ok1(be32_to_cpu(u32.u32) == 0x00112233); 94 | 95 | u16.u16 = cpu_to_le16(0x0011); 96 | ok1(u16.u16_bytes[0] == 0x11); 97 | ok1(u16.u16_bytes[1] == 0x00); 98 | ok1(le16_to_cpu(u16.u16) == 0x0011); 99 | 100 | u16.u16 = cpu_to_be16(0x0011); 101 | ok1(u16.u16_bytes[1] == 0x11); 102 | ok1(u16.u16_bytes[0] == 0x00); 103 | ok1(be16_to_cpu(u16.u16) == 0x0011); 104 | 105 | exit(exit_status()); 106 | } 107 | -------------------------------------------------------------------------------- /src/test/test_pbkdf2.py: -------------------------------------------------------------------------------- 1 | import os 2 | import unittest 3 | from util import * 4 | 5 | PBKDF2_HMAC_SHA256_LEN, PBKDF2_HMAC_SHA512_LEN = 32, 64 6 | 7 | class PBKDF2Case(object): 8 | def __init__(self, items): 9 | # Format: HMAC_SHA_TYPE, PASSWORD, SALT, COST, EXPECTED 10 | self.typ = int(items[0]) 11 | assert self.typ in [256, 512] 12 | self.passwd, self.passwd_len = make_cbuffer(items[1]) 13 | self.salt = items[2] 14 | self.cost = int(items[3]) 15 | self.expected, self.expected_len = make_cbuffer(items[4]) 16 | 17 | 18 | class PBKDF2Tests(unittest.TestCase): 19 | 20 | def setUp(self): 21 | if not hasattr(self, 'wally_pbkdf2_hmac_sha256'): 22 | self.cases = [] 23 | with open(root_dir + 'src/data/pbkdf2_hmac_sha_vectors.txt', 'r') as f: 24 | for l in f.readlines(): 25 | l = l.strip() 26 | if len(l) == 0 or l.startswith('#'): 27 | continue 28 | self.cases.append(PBKDF2Case(l.split(','))) 29 | 30 | 31 | def test_pbkdf2_hmac_sha(self): 32 | 33 | if os.getenv('WALLY_SKIP_EXPENSIVE_TESTS', None): 34 | self.skipTest('Skipping expensive pbkdf2 test') 35 | 36 | # Some test vectors are nuts (e.g. 2097152 cost), so only run the 37 | # first few. set these to -1 to run the whole suite (only needed 38 | # when refactoring the impl) 39 | num_crazy_256, num_crazy_512 = 8, 8 40 | 41 | for case in self.cases: 42 | 43 | if case.typ == 256: 44 | fn = wally_pbkdf2_hmac_sha256 45 | mult = PBKDF2_HMAC_SHA256_LEN 46 | if case.cost > 100: 47 | if num_crazy_256 == 0: 48 | continue 49 | num_crazy_256 -= 1 50 | else: 51 | fn = wally_pbkdf2_hmac_sha512 52 | mult = PBKDF2_HMAC_SHA512_LEN 53 | if case.cost > 100: 54 | if num_crazy_512 == 0: 55 | continue 56 | num_crazy_512 -= 1 57 | 58 | out_buf, out_len = make_cbuffer('00' * case.expected_len) 59 | if case.expected_len % mult != 0: 60 | # We only support output multiples of the hmac length 61 | continue 62 | 63 | salt, salt_len = make_cbuffer(case.salt) 64 | ret = fn(case.passwd, case.passwd_len, salt, salt_len, 65 | 0, case.cost, out_buf, out_len) 66 | 67 | self.assertEqual(ret, 0) 68 | self.assertEqual(h(out_buf), h(case.expected)) 69 | 70 | 71 | def _pbkdf2_hmac_sha_malloc_fail(self, fn, len): 72 | fake_buf, fake_len = make_cbuffer('aabbccdd') 73 | out_buf, out_len = make_cbuffer('00' * len) 74 | ret = fn(fake_buf, fake_len, fake_buf, fake_len, 0, 1, out_buf, out_len) 75 | self.assertEqual(ret, WALLY_ENOMEM) 76 | 77 | 78 | @malloc_fail([1]) 79 | def test_pbkdf2_hmac_sha256_malloc(self): 80 | self._pbkdf2_hmac_sha_malloc_fail(wally_pbkdf2_hmac_sha256, PBKDF2_HMAC_SHA256_LEN) 81 | 82 | 83 | @malloc_fail([1]) 84 | def test_pbkdf2_hmac_sha512_malloc(self): 85 | self._pbkdf2_hmac_sha_malloc_fail(wally_pbkdf2_hmac_sha512, PBKDF2_HMAC_SHA512_LEN) 86 | 87 | 88 | if __name__ == '__main__': 89 | unittest.main() 90 | -------------------------------------------------------------------------------- /src/ccan/ccan/base64/test/moretap.h: -------------------------------------------------------------------------------- 1 | #ifndef _BASE64_MORETAP_H 2 | #define _BASE64_MORETAP_H 3 | 4 | #include 5 | 6 | /** 7 | * is_str - OK if strings are equal 8 | * @e1: expression for the variable string 9 | * @e2: expression for the expected string 10 | * 11 | * If the strings are equal, the test passes. 12 | * 13 | * Example: 14 | * is_str(give_me_a_fred(),"fred"); 15 | */ 16 | static void _is_str(char *got,const char *expected, const char *got_string, const char *expected_string, const char *func, const char *file, int line) { 17 | if (streq(expected,got)) { 18 | _gen_result(1, func, file, line,"%s eq %s", 19 | got_string,expected_string); 20 | } else { 21 | _gen_result(0, func, file, line,"%s eq %s", 22 | got_string,expected_string); 23 | diag("Expected: %s",expected); 24 | diag(" Got: %s",got); 25 | } 26 | } 27 | # define is_str(got,expected) _is_str(got,expected,#got,#expected,__func__, __FILE__, __LINE__) 28 | 29 | 30 | /** 31 | * is_int - OK if arguments are equal when cast to integers 32 | * @e1: expression for the number 33 | * @e2: expression for the expected number 34 | * 35 | * If the numbers are equal, the test passes. 36 | * 37 | * Example: 38 | * is_int(give_me_17(),17); 39 | */ 40 | # define is_int(e1,e2 ...) \ 41 | (((int)e1)==((int)e2) ? \ 42 | _gen_result(1, __func__, __FILE__, __LINE__,"%s == %s",#e1,#e2) : \ 43 | (_gen_result(0, __func__, __FILE__, __LINE__,"%s == %s",#e1,#e2)) || (diag("Expected: %d",e2),diag(" Got: %d",e1),0)) /* diag is void; note commas. */ 44 | 45 | 46 | 47 | /** 48 | * is_mem - OK if arguments are identical up to length @e3 49 | * @e1: expression for the buffer 50 | * @e2: expression for the expected buffer 51 | * @e2: length to compare in buffers 52 | * 53 | * If the buffers are equal up to @e2, the test passes. 54 | * 55 | * Example: 56 | * is_mem(give_me_foo(),"foo",3); 57 | */ 58 | static void _is_mem(const char *got, const char *expected, const size_t len, 59 | const char *got_string, const char *expected_string, const char *len_string, 60 | const char *func, const char *file, int line) { 61 | size_t offset = 0; 62 | 63 | for (offset=0; offset 30 | # Copyright (c) 2011 Maarten Bosmans 31 | # 32 | # This program is free software: you can redistribute it and/or modify it 33 | # under the terms of the GNU General Public License as published by the 34 | # Free Software Foundation, either version 3 of the License, or (at your 35 | # option) any later version. 36 | # 37 | # This program is distributed in the hope that it will be useful, but 38 | # WITHOUT ANY WARRANTY; without even the implied warranty of 39 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General 40 | # Public License for more details. 41 | # 42 | # You should have received a copy of the GNU General Public License along 43 | # with this program. If not, see . 44 | # 45 | # As a special exception, the respective Autoconf Macro's copyright owner 46 | # gives unlimited permission to copy, distribute and modify the configure 47 | # scripts that are the output of Autoconf when processing the Macro. You 48 | # need not follow the terms of the GNU General Public License when using 49 | # or distributing such scripts, even though portions of the text of the 50 | # Macro appear in them. The GNU General Public License (GPL) does govern 51 | # all other use of the material that constitutes the Autoconf Macro. 52 | # 53 | # This special exception to the GPL applies to versions of the Autoconf 54 | # Macro released by the Autoconf Archive. When you make and distribute a 55 | # modified version of the Autoconf Macro, you may extend this special 56 | # exception to the GPL to apply to your modified version as well. 57 | 58 | #serial 4 59 | 60 | AC_DEFUN([AX_CHECK_LINK_FLAG], 61 | [AC_PREREQ(2.64)dnl for _AC_LANG_PREFIX and AS_VAR_IF 62 | AS_VAR_PUSHDEF([CACHEVAR],[ax_cv_check_ldflags_$4_$1])dnl 63 | AC_CACHE_CHECK([whether the linker accepts $1], CACHEVAR, [ 64 | ax_check_save_flags=$LDFLAGS 65 | LDFLAGS="$LDFLAGS $4 $1" 66 | AC_LINK_IFELSE([m4_default([$5],[AC_LANG_PROGRAM()])], 67 | [AS_VAR_SET(CACHEVAR,[yes])], 68 | [AS_VAR_SET(CACHEVAR,[no])]) 69 | LDFLAGS=$ax_check_save_flags]) 70 | AS_VAR_IF(CACHEVAR,yes, 71 | [m4_default([$2], :)], 72 | [m4_default([$3], :)]) 73 | AS_VAR_POPDEF([CACHEVAR])dnl 74 | ])dnl AX_CHECK_LINK_FLAGS 75 | -------------------------------------------------------------------------------- /src/mnemonic.c: -------------------------------------------------------------------------------- 1 | #include "internal.h" 2 | #include "mnemonic.h" 3 | #include "wordlist.h" 4 | 5 | #define U8_AT(bytes, pos) (bytes)[(pos) / 8u] 6 | #define U8_MASK(pos) (1u << (7u - (pos) % 8u)) 7 | 8 | /* Get n'th value (of w->bits length) from bytes */ 9 | static size_t extract_index(size_t bits, const unsigned char *bytes, size_t n) 10 | { 11 | size_t pos, end, value; 12 | for (pos = n * bits, end = pos + bits, value = 0; pos < end; ++pos) 13 | value = (value << 1u) | !!(U8_AT(bytes, pos) & U8_MASK(pos)); 14 | return value; 15 | } 16 | 17 | /* Store n'th value (of w->bits length) to bytes 18 | * Assumes: 1) the bits we are writing to are zero 19 | * 2) value fits within w->bits 20 | */ 21 | static void store_index(size_t bits, unsigned char *bytes_out, size_t n, size_t value) 22 | { 23 | size_t i, pos; 24 | for (pos = n * bits, i = 0; i < bits; ++i, ++pos) 25 | if (value & (1u << (bits - i - 1u))) 26 | U8_AT(bytes_out, pos) |= U8_MASK(pos); 27 | } 28 | 29 | char *mnemonic_from_bytes(const struct words *w, const unsigned char *bytes, size_t bytes_len) 30 | { 31 | size_t total_bits = bytes_len * 8u; /* bits in 'bytes' */ 32 | size_t total_mnemonics = total_bits / w->bits; /* Mnemonics in 'bytes' */ 33 | size_t i, str_len = 0; 34 | char *str = NULL; 35 | 36 | /* Compute length of result */ 37 | for (i = 0; i < total_mnemonics; ++i) { 38 | size_t idx = extract_index(w->bits, bytes, i); 39 | size_t mnemonic_len = strlen(w->indices[idx]); 40 | 41 | str_len += mnemonic_len + 1; /* +1 for following separator or NUL */ 42 | } 43 | 44 | /* Allocate and fill result */ 45 | if (str_len && (str = wally_malloc(str_len))) { 46 | char *out = str; 47 | 48 | for (i = 0; i < total_mnemonics; ++i) { 49 | size_t idx = extract_index(w->bits, bytes, i); 50 | size_t mnemonic_len = strlen(w->indices[idx]); 51 | 52 | memcpy(out, w->indices[idx], mnemonic_len); 53 | out[mnemonic_len] = ' '; /* separator */ 54 | out += mnemonic_len + 1; 55 | } 56 | str[str_len - 1] = '\0'; /* Overwrite the last separator with NUL */ 57 | } 58 | 59 | return str; 60 | } 61 | 62 | int mnemonic_to_bytes(const struct words *w, const char *mnemonic, 63 | unsigned char *bytes_out, size_t len, size_t *written) 64 | { 65 | struct words *mnemonic_w = NULL; 66 | size_t i; 67 | 68 | if (written) 69 | *written = 0; 70 | 71 | if (!w || !bytes_out || !len) 72 | return WALLY_EINVAL; 73 | 74 | mnemonic_w = wordlist_init(mnemonic); 75 | 76 | if (!mnemonic_w) 77 | return WALLY_ENOMEM; 78 | 79 | if ((mnemonic_w->len * w->bits + 7u) / 8u > len) 80 | goto cleanup; /* Return the length we would have written */ 81 | 82 | wally_clear(bytes_out, len); 83 | 84 | for (i = 0; i < mnemonic_w->len; ++i) { 85 | size_t idx = wordlist_lookup_word(w, mnemonic_w->indices[i]); 86 | if (!idx) { 87 | wordlist_free(mnemonic_w); 88 | wally_clear(bytes_out, len); 89 | return WALLY_EINVAL; 90 | } 91 | store_index(w->bits, bytes_out, i, idx - 1); 92 | } 93 | 94 | cleanup: 95 | if (written) 96 | *written = (mnemonic_w->len * w->bits + 7u) / 8u; 97 | wordlist_free(mnemonic_w); 98 | return WALLY_OK; 99 | } 100 | -------------------------------------------------------------------------------- /src/test/test_symmetric.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | from util import * 3 | 4 | ENTROPY_LEN_128, ENTROPY_LEN_256, ENTROPY_LEN_512 = 16, 32, 64 5 | HMAC_SHA512_LEN = 64 6 | 7 | class SymmetricTests(unittest.TestCase): 8 | 9 | def test_symmetric_key(self): 10 | seed128, seed128_len = make_cbuffer('01' * ENTROPY_LEN_128) 11 | seed256, seed256_len = make_cbuffer('01' * ENTROPY_LEN_256) 12 | seed512, seed512_len = make_cbuffer('01' * ENTROPY_LEN_512) 13 | label, label_len = make_cbuffer('0f0000') 14 | key_out, key_out_len = make_cbuffer('00' * HMAC_SHA512_LEN) 15 | 16 | # wally_symmetric_key_from_seed 17 | # Invalid args 18 | cases = [ 19 | (None, seed128_len, key_out, key_out_len), # Null bytes 20 | (seed128, 0, key_out, key_out_len), # 0 Length bytes 21 | (seed128, seed128_len-1, key_out, key_out_len), # Bad bytes length 22 | (seed128, seed128_len, None, key_out_len), # Null dest 23 | (seed128, seed128_len, key_out, 0), # 0 length dest 24 | (seed128, seed128_len, key_out, key_out_len+1), # Bad dest length 25 | ] 26 | for bytes_in, bytes_len, out, out_len in cases: 27 | ret = wally_symmetric_key_from_seed(bytes_in, bytes_len, out, out_len) 28 | self.assertEqual(ret, WALLY_EINVAL) 29 | 30 | # Valid args 31 | for bytes_in, bytes_len in [(seed128, seed128_len), 32 | (seed256, seed256_len), 33 | (seed512, seed512_len)]: 34 | ret = wally_symmetric_key_from_seed(bytes_in, bytes_len, key_out, key_out_len) 35 | self.assertEqual(ret, WALLY_OK) 36 | 37 | # wally_symmetric_key_from_parent 38 | key_in, key_len = make_cbuffer('01' * HMAC_SHA512_LEN) 39 | # Invalid args 40 | cases = [ 41 | (None, key_len, 0, label, label_len, key_out, key_out_len), # Null key 42 | (key_in, 0, 0, label, label_len, key_out, key_out_len), # 0 Length key 43 | (key_in, key_len-1, 1, label, label_len, key_out, key_out_len), # Bad key length 44 | (key_in, key_len, 1, label, label_len, key_out, key_out_len), # Bad version 45 | (key_in, key_len, 0, None, label_len, key_out, key_out_len), # Null label 46 | (key_in, key_len, 0, label, 0, key_out, key_out_len), # Bad label length 47 | (key_in, key_len, 0, label, label_len, None, key_out_len), # Null dest 48 | (key_in, key_len, 0, label, label_len, key_out, 0), # 0 length dest 49 | (key_in, key_len, 0, label, label_len, key_out, key_out_len+1), # Bad dest length 50 | ] 51 | for bytes_in, bytes_len, ver, l, l_len, out, out_len in cases: 52 | ret = wally_symmetric_key_from_parent(bytes_in, bytes_len, ver, l, l_len, out, out_len) 53 | self.assertEqual(ret, WALLY_EINVAL) 54 | 55 | # Valid args 56 | ret = wally_symmetric_key_from_parent(key_in, key_len, 0, label, label_len, key_out, key_out_len) 57 | self.assertEqual(ret, WALLY_OK) 58 | 59 | # Check labels around length LABEL_SIZE (64) 60 | label, label_len = make_cbuffer('0f' * 65) 61 | for l_len in (label_len-1, label_len, label_len+1): 62 | ret = wally_symmetric_key_from_parent(key_in, key_len, 0, label, l_len, key_out, key_out_len) 63 | self.assertEqual(ret, WALLY_OK) 64 | 65 | 66 | if __name__ == '__main__': 67 | unittest.main() 68 | --------------------------------------------------------------------------------