Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 17 additions & 2 deletions CHANGES.md
Original file line number Diff line number Diff line change
@@ -1,12 +1,27 @@
# Changes

## Version 1.5.3

### Added
- bip32: Add updated BIP checks to bip32_key_unserialize().
- build: Add support for fuzzing wally API calls.

### Fixed
- psbt: corectly handle allocation failures in psbt_set_global_tx().
- tx: Avoid quadratic behaviour parsing txs with a huge number of witnesses.
- tx: Fix parsing Liquid transactions with short commitments.
- tx: Reject non-corresponding output as per bip341 when signing.
- map: Fix incorrect clear when reinserting an integer after removing bytes.
- js: Bump webpack, serialize-javascript and terser-webpack-plugin dependencies.
- Various minor code and build fixes.

## Version 1.5.2

### Added
- taproot: add bip341_control_block_verify().
- taproot: Add bip341_control_block_verify().

### Changed
- map: ignore duplicates in map_merkle_path_add() for consistency.
- map: Ignore duplicates in map_merkle_path_add() for consistency.

### Fixed
- build: Fix building with the Elements ABI disabled.
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,7 @@ installed.
For non-development use, you can install wally from PyPI with `pip` as follows:

```
pip install wallycore==1.5.2
pip install wallycore==1.5.3
```

For development, you can build and install wally using:
Expand Down
2 changes: 1 addition & 1 deletion _CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ cmake_minimum_required(VERSION 3.18)

project(
libwallycore
VERSION 1.5.2
VERSION 1.5.3
DESCRIPTION "A collection of useful primitives for cryptocurrency wallets"
LANGUAGES C
)
Expand Down
2 changes: 1 addition & 1 deletion configure.ac
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
AC_PREREQ([2.60])
AC_INIT([libwallycore],[1.5.2])
AC_INIT([libwallycore],[1.5.3])
AC_CONFIG_AUX_DIR([tools/build-aux])
AC_CONFIG_MACRO_DIR([tools/build-aux/m4])
AC_CONFIG_SRCDIR([src/mnemonic.h])
Expand Down
2 changes: 1 addition & 1 deletion docs/source/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -168,7 +168,7 @@ def extract_docs(infile, outfile):
# built documents.
#
# The short X.Y version.
version = u'1.5.2'
version = u'1.5.3'
# The full version, including alpha/beta/rc tags.
release = version

Expand Down
4 changes: 2 additions & 2 deletions include/wally_core.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,8 @@ extern "C" {
/** Library version */
#define WALLY_MAJOR_VER 1
#define WALLY_MINOR_VER 5
#define WALLY_PATCH_VER 2
#define WALLY_BUILD_VER 0x10502
#define WALLY_PATCH_VER 3
#define WALLY_BUILD_VER 0x10503

/**
* Initialize wally.
Expand Down
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -172,7 +172,7 @@ def _call(args, cwd=ABS_PATH):

kwargs = {
'name': 'wallycore',
'version': '1.5.2',
'version': '1.5.3',
'description': 'libwally Bitcoin library',
'long_description': 'Python bindings for the libwally Bitcoin library',
'url': 'https://github.com/ElementsProject/libwally-core',
Expand Down
4 changes: 2 additions & 2 deletions src/Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -199,11 +199,11 @@ libwallycore_la_INCLUDES = \

if SHARED_BUILD_ENABLED
# Increment at every ABI change (whether breaking or non-breaking)
LT_VER_CURRENT = 8
LT_VER_CURRENT = 9
# Increment at every release, but reset to 0 at every ABI change
LT_VER_REVISION = 0
# Increment at every ABI change, but reset to 0 if breaking
LT_VER_AGE = 2
LT_VER_AGE = 3
# The library filename will be "libwallycore.so.$((current-age)).$((age)).$((revision))",
# and the soname will be "libwallycore.so.$((current-age))".
# Do NOT try to make the library version-info follow the project release version number!
Expand Down
69 changes: 40 additions & 29 deletions src/aes.c
Original file line number Diff line number Diff line change
Expand Up @@ -5,20 +5,22 @@
#include "ctaes/ctaes.h"
#include "ctaes/ctaes.c"

#define ALL_OPS (AES_FLAG_ENCRYPT | AES_FLAG_DECRYPT)

static bool is_valid_key_len(size_t key_len)
{
return key_len == AES_KEY_LEN_128 || key_len == AES_KEY_LEN_192 ||
key_len == AES_KEY_LEN_256;
}

static bool are_valid_args(const unsigned char *key, size_t key_len,
const unsigned char *bytes, size_t bytes_len, uint32_t flags)
const unsigned char *bytes, size_t bytes_len,
uint32_t flags, size_t *written)
{
return key && is_valid_key_len(key_len) &&
(bytes != NULL || (bytes == NULL && bytes_len == 0 && (flags & AES_FLAG_ENCRYPT))) &&
(flags == AES_FLAG_ENCRYPT || flags == AES_FLAG_DECRYPT);
if (written)
*written = 0;
if (!key || !is_valid_key_len(key_len) || BYTES_INVALID(bytes, bytes_len) ||
(flags != AES_FLAG_ENCRYPT && flags != AES_FLAG_DECRYPT) || !written)
return false;
return true;
}

static void aes_enc(AES256_ctx *ctx,
Expand Down Expand Up @@ -75,10 +77,8 @@ int wally_aes_len(const unsigned char *key, size_t key_len,
const unsigned char *bytes, size_t bytes_len,
uint32_t flags, size_t *written)
{
if (written)
*written = 0;
if (!are_valid_args(key, key_len, bytes, bytes_len, flags) ||
!bytes_len || bytes_len % AES_BLOCK_LEN || !written)
if (!are_valid_args(key, key_len, bytes, bytes_len, flags, written) ||
!bytes_len || bytes_len % AES_BLOCK_LEN)
return WALLY_EINVAL;
*written = bytes_len;
return WALLY_OK;
Expand All @@ -90,8 +90,9 @@ int wally_aes(const unsigned char *key, size_t key_len,
unsigned char *bytes_out, size_t len)
{
AES256_ctx ctx;
size_t written;

if (!are_valid_args(key, key_len, bytes, bytes_len, flags) ||
if (!are_valid_args(key, key_len, bytes, bytes_len, flags, &written) ||
len % AES_BLOCK_LEN || !bytes_len || bytes_len % AES_BLOCK_LEN ||
!bytes_out || !len)
return WALLY_EINVAL;
Expand All @@ -105,43 +106,52 @@ int wally_aes(const unsigned char *key, size_t key_len,
return WALLY_OK;
}

static bool are_valid_aes_cbc_args(const unsigned char *key, size_t key_len,
const unsigned char *iv, size_t iv_len,
const unsigned char *bytes, size_t bytes_len,
uint32_t flags,
unsigned char *bytes_out, size_t len,
size_t *written)
{
if (!are_valid_args(key, key_len, bytes, bytes_len, flags, written) ||
!iv || iv_len != AES_BLOCK_LEN || BYTES_INVALID(bytes_out, len))
return false;

if (flags & AES_FLAG_ENCRYPT) {
if (len % AES_BLOCK_LEN)
return false; /* Output must be a block length multiple if given */
} else {
if (bytes_len % AES_BLOCK_LEN)
return false; /* Input must be a block length multiple if given */
}
return true;
}

int wally_aes_cbc_get_maximum_length(const unsigned char *key, size_t key_len,
const unsigned char *iv, size_t iv_len,
const unsigned char *bytes, size_t bytes_len,
uint32_t flags,
size_t *written)
{
if (written)
*written = 0;

if (!are_valid_args(key, key_len, bytes, bytes_len, flags) ||
((flags & AES_FLAG_DECRYPT) && (bytes_len % AES_BLOCK_LEN)) ||
!iv || iv_len != AES_BLOCK_LEN || !written)
if (!are_valid_aes_cbc_args(key, key_len, iv, iv_len, bytes, bytes_len,
flags, NULL, 0, written))
return WALLY_EINVAL;

*written = ((bytes_len / AES_BLOCK_LEN) + 1) * AES_BLOCK_LEN;
return WALLY_OK;
}

int wally_aes_cbc(const unsigned char *key, size_t key_len,
const unsigned char *iv, size_t iv_len,
const unsigned char *bytes, size_t bytes_len,
uint32_t flags,
unsigned char *bytes_out, size_t len,
size_t *written)
const unsigned char *bytes, size_t bytes_len, uint32_t flags,
unsigned char *bytes_out, size_t len, size_t *written)
{
unsigned char buf[AES_BLOCK_LEN];
AES256_ctx ctx;
size_t i, n, blocks;
unsigned char remainder;

if (written)
*written = 0;

if (!are_valid_args(key, key_len, bytes, bytes_len, flags) ||
((flags & AES_FLAG_ENCRYPT) && (len % AES_BLOCK_LEN)) ||
((flags & AES_FLAG_DECRYPT) && (bytes_len % AES_BLOCK_LEN)) ||
!iv || iv_len != AES_BLOCK_LEN || !written)
if (!are_valid_aes_cbc_args(key, key_len, iv, iv_len, bytes, bytes_len,
flags, bytes_out, len, written))
return WALLY_EINVAL;

blocks = bytes_len / AES_BLOCK_LEN;
Expand Down Expand Up @@ -173,6 +183,7 @@ int wally_aes_cbc(const unsigned char *key, size_t key_len,
goto finish; /* Inform caller how much space is needed */

if (!bytes_out) {
*written = 0;
wally_clear_2(buf, sizeof(buf), &ctx, sizeof(ctx));
return WALLY_EINVAL;
}
Expand Down
6 changes: 4 additions & 2 deletions src/blech32.c
Original file line number Diff line number Diff line change
Expand Up @@ -321,8 +321,10 @@ int wally_confidential_addr_from_addr_segwit(
memcpy(buf, pub_key, pub_key_len);
written -= 2; /* ignore witnessVersion & hashSize */
written += EC_PUBLIC_KEY_LEN;
if (!blech32_addr_encode(result, confidential_addr_family, witver & 0xff, buf, written))
return WALLY_ERROR;
if (!blech32_addr_encode(result, confidential_addr_family, witver & 0xff, buf, written)) {
ret = WALLY_ERROR;
goto done;
}

*output = wally_strdup(result);
ret = (*output) ? WALLY_OK : WALLY_ENOMEM;
Expand Down
8 changes: 4 additions & 4 deletions src/map.c
Original file line number Diff line number Diff line change
Expand Up @@ -252,14 +252,14 @@ int map_add(struct wally_map *map_in,
struct wally_map_item *new_item = map_in->items + map_in->num_items;

if (!key) {
/* Integer key */
if (new_item->key)
clear_and_free_bytes(&new_item->key, &new_item->key_len);
new_item->key = NULL; /* Integer key */
} else if (!clone_bytes(&new_item->key, key, key_len))
return WALLY_ENOMEM; /* Failed to allocate byte key */
new_item->key_len = key_len;

if (val) {
if (!val) {
new_item->value = NULL;
} else {
if (take_value)
new_item->value = (unsigned char *)val;
else if (!clone_bytes(&new_item->value, val, val_len)) {
Expand Down
49 changes: 43 additions & 6 deletions src/test/test_aes.py
Original file line number Diff line number Diff line change
Expand Up @@ -80,17 +80,54 @@ def get_cbc_cases(self):
return [lines[x:x+4] for x in range(0, len(lines), 4)]

def test_aes_cbc(self):
out_buf, out_len = make_cbuffer('00' * 80)
E, D = self.ENCRYPT, self.DECRYPT
# Encryption/decryption cases
for c in self.get_cbc_cases():
plain, key, iv, cypher = [make_cbuffer(s)[0] for s in c]

for p, f, o in [(plain, self.ENCRYPT, cypher),
(cypher, self.DECRYPT, plain)]:

out_buf, out_len = make_cbuffer('00' * len(o))
for p, f, o in [(plain, E, cypher), (cypher, D, plain)]:
ret, written = wally_aes_cbc(key, len(key), iv, len(iv),
p, len(p), f, out_buf, out_len)
p or None, len(p), f, out_buf, out_len)
self.assertEqual((ret, written), (0, len(o)))
self.assertEqual(h(out_buf), h(o))
self.assertEqual(h(out_buf[:written]), h(o))
# Passing a NULL output buffer with zero length returns the
# number of bytes required for encrypted/decrypted output
ret, written = wally_aes_cbc(key, len(key), iv, len(iv),
p or None, len(p), f, None, 0)
self.assertEqual((ret, written), (0, len(o)))
# wally_aes_cbc_get_maximum_length returns tha maximum
# number of bytes required.
ret, max_len = wally_aes_cbc_get_maximum_length(key, len(key), iv, len(iv),
p or None, len(p), f)
self.assertEqual(ret, 0)
self.assertTrue(max_len >= written and max_len % 16 == 0)

# Invalid args
invalid_cases = [
# NULL key
(None, len(key), iv, len(iv), cypher, len(cypher), D, out_buf, out_len),
# Empty key
(key, 0, iv, len(iv), cypher, len(cypher), D, out_buf, out_len),
# NULL IV
(key, len(key), None, len(iv), cypher, len(cypher), D, out_buf, out_len),
# Empty IV
(key, len(key), iv, 0, cypher, len(cypher), D, out_buf, out_len),
# NULL cyphertext
(key, len(key), iv, len(iv), None, len(cypher), D, out_buf, out_len),
# Empty cyphertext
(key, len(key), iv, len(iv), cypher, 0, D, out_buf, out_len),
# Invalid flags
(key, len(key), iv, len(iv), cypher, len(cypher), 3, out_buf, out_len),
# NULL out_buf
(key, len(key), iv, len(iv), cypher, len(cypher), D, None, out_len),
]
for c in invalid_cases:
if c[-1] == out_len and c[-2] == out_buf:
ret, written = wally_aes_cbc_get_maximum_length(*c[:-2])
self.assertEqual((ret, written), (WALLY_EINVAL, 0))
ret, written = wally_aes_cbc(*c)
self.assertEqual((ret, written), (WALLY_EINVAL, 0))

def test_aes_cbc_with_ecdh_key(self):
ENCRYPT, DECRYPT, _ = 1, 2, True
Expand Down
9 changes: 9 additions & 0 deletions src/test/test_map.py
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,15 @@ def test_map(self):

self.assertEqual(wally_map_free(m), WALLY_OK)

# Test re-adding an integer after removing bytes
m = pointer(wally_map())
self.assertEqual(wally_map_init_alloc(0, None, m), WALLY_OK)
self.assertEqual(wally_map_add(*[m, *cases[0]]), WALLY_OK)
self.assertEqual(wally_map_add(*[m, *cases[1]]), WALLY_OK)
self.assertEqual(wally_map_remove(m, cases[0][0], cases[0][1]), WALLY_OK)
self.assertEqual(wally_map_add_integer(m, 1, cases[0][0], cases[0][1]), WALLY_OK)
self.assertEqual(wally_map_free(m), WALLY_OK)

def test_keypath_map(self):
"""Test keypath map functions"""
#
Expand Down
4 changes: 3 additions & 1 deletion src/transaction.c
Original file line number Diff line number Diff line change
Expand Up @@ -742,7 +742,7 @@ int wally_tx_input_init_alloc(const unsigned char *txhash, size_t txhash_len,
script, script_len, witness, *output);

if (ret != WALLY_OK) {
clear_and_free(*output, sizeof(struct wally_tx_output));
clear_and_free(*output, sizeof(struct wally_tx_input));
*output = NULL;
}
return ret;
Expand Down Expand Up @@ -1857,6 +1857,8 @@ int wally_tx_get_weight(const struct wally_tx *tx, size_t *written)

int wally_tx_vsize_from_weight(size_t weight, size_t *written)
{
if (!written)
return WALLY_EINVAL;
*written = (weight + 3) / 4; /* ceil(weight/4) */
return WALLY_OK;
}
Expand Down
6 changes: 4 additions & 2 deletions src/tx_io.c
Original file line number Diff line number Diff line change
Expand Up @@ -606,7 +606,7 @@ static int legacy_signature_hash(
!bytes_out || len != SHA256_LEN)
return WALLY_EINVAL;

if (index >= tx->num_inputs || (sh_single && index >= tx->num_outputs)) {
if (index >= tx->num_inputs || (sh_single && index >= tx->num_outputs)) {
memset(bytes_out, 0, SHA256_LEN);
bytes_out[0] = 0x1;
return WALLY_OK;
Expand Down Expand Up @@ -832,7 +832,9 @@ static int bip341_signature_hash(
const bool sh_anyprevout_anyscript = bip341_is_input_hash_type(sighash, WALLY_SIGHASH_ANYPREVOUTANYSCRIPT);
cursor_io io;

if (index >= tx->num_inputs || (annex && *annex != 0x50))
if (index >= tx->num_inputs ||
(output_type == WALLY_SIGHASH_SINGLE && index >= tx->num_outputs) ||
(annex && *annex != 0x50))
return WALLY_EINVAL;

if (is_elements) {
Expand Down
4 changes: 2 additions & 2 deletions src/wasm_package/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion src/wasm_package/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "wallycore",
"version": "1.5.2",
"version": "1.5.3",
"description": "JavaScript bindings for libwally",
"main": "src/index.js",
"type": "module",
Expand Down
Loading
Loading