Bitcoin ABC 0.30.7
P2P Digital Currency
serialize_intcode.h
Go to the documentation of this file.
1// Copyright (c) 2024 The Bitcoin developers
2// Distributed under the MIT software license, see the accompanying
3// file COPYING or http://www.opensource.org/licenses/mit-license.php.
4
5#ifndef BITCOIN_SERIALIZE_INTCODE_H
6#define BITCOIN_SERIALIZE_INTCODE_H
7
8#include <crypto/common.h>
9#include <serialize.h>
10#include <tinyformat.h>
11
12#include <cstdint>
13#include <ios>
14
15const uint64_t VALID_RANGE[] = {
16 0,
17 0x80,
18 0x4000,
19 0x20'0000,
20 0x1000'0000,
21 0x08'0000'0000,
22 0x0400'0000'0000,
23 0x02'0000'0000'0000,
24 0x0100'0000'0000'0000,
25};
26
46template <typename Stream> void WriteIntcode(Stream &os, uint64_t value) {
47 // Integers below 0x80 are just represented by themselves
48 if (value < 0x80) {
49 ser_writedata8(os, value);
50 return;
51 }
52
53 // Number of bits required to represent `value`
54 const uint64_t numBits = CountBits(value);
55 // Number of bytes required to represent `value`
56 uint64_t numBytes = (numBits - 1) / 7;
57 if (numBytes >= 8) {
58 // For 0xff headers, the formula breaks, as it's not followed by a 0 bit
59 ser_writedata8(os, 0xff);
60 numBytes = 8;
61 } else {
62 // Bits to represent how many bytes are used for the data
63 const uint64_t header = (0xff << (8 - numBytes)) & 0xff;
64 // Prepend the header
65 value |= header << (8 * numBytes);
66 // Header adds 1 leading byte
67 numBytes++;
68 // Left align
69 value <<= 8 * (8 - numBytes);
70 }
71
72 // Write remaining bytes as big-endian
73 for (size_t i = 0; i < numBytes; ++i) {
74 ser_writedata8(os, value >> 56);
75 value <<= 8;
76 }
77}
78
84template <typename Stream> uint64_t ReadIntcode(Stream &is) {
85 // Read the header byte
86 const uint8_t header = ser_readdata8(is);
87
88 // If the first bit is not set, the number is the first byte itself
89 if (header < 0x80) {
90 return header;
91 }
92
93 // Number of leading ones in header (represents the number of extra bytes)
94 const uint64_t leadingOnes = 8 - CountBits(uint8_t(~header));
95
96 // Read the data bits from the header
97 const uint8_t mask = 0xff >> leadingOnes;
98 uint64_t result = header & mask;
99
100 // Read remaining bytes as big-endian
101 for (size_t i = 0; i < leadingOnes; ++i) {
102 result <<= 8;
103 result |= ser_readdata8(is);
104 }
105
106 if (result < VALID_RANGE[leadingOnes]) {
107 throw std::ios_base::failure(strprintf(
108 "non-canonical ReadMitraInt(): 0x%016x out of range for %d "
109 "leading ones",
110 result, leadingOnes));
111 }
112
113 return result;
114}
115
116#endif // BITCOIN_SERIALIZE_INTCODE_H
static uint64_t CountBits(uint64_t x)
Return the smallest number n such that (x >> n) == 0 (or 64 if the highest bit in x is set.
Definition: common.h:82
uint8_t ser_readdata8(Stream &s)
Definition: serialize.h:83
void ser_writedata8(Stream &s, uint8_t obj)
Lowest-level serialization and conversion.
Definition: serialize.h:55
const uint64_t VALID_RANGE[]
uint64_t ReadIntcode(Stream &is)
Read a 64-bit integer as intcode, see WriteIntcode.
void WriteIntcode(Stream &os, uint64_t value)
Write a 64-bit integer in intcode encoding:
#define strprintf
Format arguments and return the string or write to given std::ostream (see tinyformat::format doc for...
Definition: tinyformat.h:1202