Skip to content

Commit

Permalink
Remove VLA and resolve warnings in SPV (#1131)
Browse files Browse the repository at this point in the history
* Remove VLA and resolve warnings in SPV
* Cast to void* and use std::decay.
  • Loading branch information
Bushstar authored Mar 9, 2022
1 parent 3c1ffd4 commit 50b2884
Show file tree
Hide file tree
Showing 16 changed files with 325 additions and 349 deletions.
58 changes: 29 additions & 29 deletions src/spv/bitcoin/BRMerkleBlock.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -43,36 +43,36 @@ inline static int _ceil_log2(int x)
return r;
}

// from https://en.bitcoin.it/wiki/Protocol_specification#Merkle_Trees
// Merkle trees are binary trees of hashes. Merkle trees in bitcoin use a double SHA-256, the SHA-256 hash of the
// SHA-256 hash of something. If, when forming a row in the tree (other than the root of the tree), it would have an odd
// number of elements, the final double-hash is duplicated to ensure that the row has an even number of hashes. First
// form the bottom row of the tree with the ordered double-SHA-256 hashes of the byte streams of the transactions in the
// block. Then the row above it consists of half that number of hashes. Each entry is the double-SHA-256 of the 64-byte
// concatenation of the corresponding two hashes below it in the tree. This procedure repeats recursively until we reach
// a row consisting of just a single double-hash. This is the merkle root of the tree.
//
// from https://github.com/bitcoin/bips/blob/master/bip-0037.mediawiki#Partial_Merkle_branch_format
// The encoding works as follows: we traverse the tree in depth-first order, storing a bit for each traversed node,
// signifying whether the node is the parent of at least one matched leaf txid (or a matched txid itself). In case we
// are at the leaf level, or this bit is 0, its merkle node hash is stored, and its children are not explored further.
// Otherwise, no hash is stored, but we recurse into both (or the only) child branch. During decoding, the same
// depth-first traversal is performed, consuming bits and hashes as they were written during encoding.
//
// example tree with three transactions, where only tx2 is matched by the bloom filter:
//
// merkleRoot
// / \
// m1 m2
// / \ / \
// tx1 tx2 tx3 tx3
//
// flag bits (little endian): 00001011 [merkleRoot = 1, m1 = 1, tx1 = 0, tx2 = 1, m2 = 0, byte padding = 000]
// hashes: [tx1, tx2, m2]
//
// NOTE: this merkle tree design has a security vulnerability (CVE-2012-2459), which can be defended against by
// considering the merkle root invalid if there are duplicate hashes in any rows with an even number of elements
/* from https://en.bitcoin.it/wiki/Protocol_specification#Merkle_Trees
Merkle trees are binary trees of hashes. Merkle trees in bitcoin use a double SHA-256, the SHA-256 hash of the
SHA-256 hash of something. If, when forming a row in the tree (other than the root of the tree), it would have an odd
number of elements, the final double-hash is duplicated to ensure that the row has an even number of hashes. First
form the bottom row of the tree with the ordered double-SHA-256 hashes of the byte streams of the transactions in the
block. Then the row above it consists of half that number of hashes. Each entry is the double-SHA-256 of the 64-byte
concatenation of the corresponding two hashes below it in the tree. This procedure repeats recursively until we reach
a row consisting of just a single double-hash. This is the merkle root of the tree.
from https://github.com/bitcoin/bips/blob/master/bip-0037.mediawiki#Partial_Merkle_branch_format
The encoding works as follows: we traverse the tree in depth-first order, storing a bit for each traversed node,
signifying whether the node is the parent of at least one matched leaf txid (or a matched txid itself). In case we
are at the leaf level, or this bit is 0, its merkle node hash is stored, and its children are not explored further.
Otherwise, no hash is stored, but we recurse into both (or the only) child branch. During decoding, the same
depth-first traversal is performed, consuming bits and hashes as they were written during encoding.
example tree with three transactions, where only tx2 is matched by the bloom filter:
merkleRoot
/ \
m1 m2
/ \ / \
tx1 tx2 tx3 tx3
flag bits (little endian): 00001011 [merkleRoot = 1, m1 = 1, tx1 = 0, tx2 = 1, m2 = 0, byte padding = 000]
hashes: [tx1, tx2, m2]
NOTE: this merkle tree design has a security vulnerability (CVE-2012-2459), which can be defended against by
considering the merkle root invalid if there are duplicate hashes in any rows with an even number of elements
*/
// returns a newly allocated merkle block struct that must be freed by calling BRMerkleBlockFree()
BRMerkleBlock *BRMerkleBlockNew(void)
{
Expand Down
26 changes: 12 additions & 14 deletions src/spv/bitcoin/BRPaymentProtocol.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -168,18 +168,17 @@ static void _ProtoBufSetInt(uint8_t *buf, size_t bufLen, uint64_t i, uint64_t ke
static void _ProtoBufUnknown(uint8_t **unknown, uint64_t key, uint64_t i, const void *data, size_t dataLen)
{
size_t bufLen = 10 + ((key & 0x07) == PROTOBUF_LENDELIM ? dataLen : 0);
uint8_t _buf[(bufLen <= 0x1000) ? bufLen : 0], *buf = (bufLen <= 0x1000) ? _buf : (uint8_t *)malloc(bufLen);
std::vector<uint8_t> buf(bufLen);
size_t off = 0, o = 0, l;
uint64_t k;

assert(buf != NULL);
_ProtoBufSetVarInt(buf, bufLen, key, &off);
_ProtoBufSetVarInt(buf.data(), bufLen, key, &off);

switch (key & 0x07) {
case PROTOBUF_VARINT: _ProtoBufSetVarInt(buf, bufLen, i, &off); break;
case PROTOBUF_64BIT: _ProtoBufSetFixed(buf, bufLen, i, &off, sizeof(uint64_t)); break;
case PROTOBUF_LENDELIM: _ProtoBufSetLenDelim(buf, bufLen, data, dataLen, &off); break;
case PROTOBUF_32BIT: _ProtoBufSetFixed(buf, bufLen, i, &off, sizeof(uint32_t)); break;
case PROTOBUF_VARINT: _ProtoBufSetVarInt(buf.data(), bufLen, i, &off); break;
case PROTOBUF_64BIT: _ProtoBufSetFixed(buf.data(), bufLen, i, &off, sizeof(uint64_t)); break;
case PROTOBUF_LENDELIM: _ProtoBufSetLenDelim(buf.data(), bufLen, data, dataLen, &off); break;
case PROTOBUF_32BIT: _ProtoBufSetFixed(buf.data(), bufLen, i, &off, sizeof(uint32_t)); break;
default: break;
}

Expand All @@ -195,8 +194,7 @@ static void _ProtoBufUnknown(uint8_t **unknown, uint64_t key, uint64_t i, const
if (k >= key) break;
}

array_insert_array(*unknown, o, buf, bufLen);
if (buf != _buf) free(buf);
array_insert_array(*unknown, o, buf.data(), bufLen);
}

typedef enum {
Expand Down Expand Up @@ -699,12 +697,12 @@ BRPaymentProtocolPayment *BRPaymentProtocolPaymentNew(const uint8_t *merchantDat
}

array_new(payment->refundTo, refundToCount);
std::vector<uint8_t> script;
for (size_t i = 0; i < refundToCount; i++) {
uint8_t script[BRAddressScriptPubKey(NULL, 0, refundToAddresses[i].s)];
size_t scriptLen = BRAddressScriptPubKey(script, sizeof(script), refundToAddresses[i].s);
script.resize(BRAddressScriptPubKey(NULL, 0, refundToAddresses[i].s));
size_t scriptLen = BRAddressScriptPubKey(script.data(), script.size(), refundToAddresses[i].s);

array_add(payment->refundTo, _BRPaymentProtocolOutput(refundToAmounts[i], script, scriptLen));
array_add(payment->refundTo, _BRPaymentProtocolOutput(refundToAmounts[i], script.data(), scriptLen));
}

payment->refundToCount = refundToCount;
Expand Down Expand Up @@ -1394,7 +1392,7 @@ size_t BRPaymentProtocolEncryptedMessageDecrypt(BRPaymentProtocolEncryptedMessag
if (! ctx->defaults[encrypted_msg_status_code]) {
snprintf(ad, adLen, "%" PRIu64 "%s", msg->statusCode, (msg->statusMsg) ? msg->statusMsg : "");
}
else if (msg->statusMsg) strncpy(ad, msg->statusMsg, adLen);
else if (msg->statusMsg) strcpy(ad, msg->statusMsg);

outLen = BRChacha20Poly1305AEADDecrypt(out, outLen, cek, iv, msg->message, msg->msgLen, ad, strlen(ad));
mem_clean(cek, sizeof(cek));
Expand Down
Loading

0 comments on commit 50b2884

Please sign in to comment.