Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Remove VLA and resolve warnings in SPV #1131

Merged
merged 2 commits into from
Mar 9, 2022
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
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