値の表現
最終更新日: 2024/12/11
数値は 2の補数の little endian で表す。
固定長の場合はそのバイト数のデータ型、可変長は Compact Size型が使われている。
Compact Size型はあまり見慣れないと思う。
例えば 0xfc
までなら 1バイトでそのまま表現できるが、0xfd
は 0xfdfd00
(little endian)になる。
データ長を表すのに使われることがほとんどだと思う。
0x00 - 0xfc
- 長さ:
0x00
-0xfc
- 変換: そのまま
uint8_t
にする
- 長さ:
0xfdfd00 - 0xfdffff
- 長さ:
0xfd
-0xffff
- 変換: 先頭の
fd
は捨て、残り 2byte をuint16_t
にする
- 長さ:
0xfe00000100 - 0xfeffffffff
- 長さ:
0x010000
-0xffffffff
- 変換: 先頭の
fe
は捨て、残り 4byte をuint32_t
にする
- 長さ:
0xff0000000001000000 - 0xffffffffffffffffff
- 長さ:
0x0100000000
-0xffffffffffffffff
- 変換: 先頭の
ff
は捨て、残り 8byte をuint64_t
にする
- 長さ:
uint64_t varint(const uint8_t *p_varint)
{
uint64_t val;
if (p_varint[0] < 0xfd) {
val = p_varint[0];
} else if (p_varint[0] == 0xfd) {
val = ((uint16_t)p_varint[2] << 8) | (uint16_t)p_varint[1];
} else if (p_varint[0] == 0xfe) {
val = ((uint32_t)p_varint[4] << 24) |
((uint32_t)p_varint[3] << 16) |
((uint32_t)p_varint[2] << 8) |
(uint32_t)p_varint[1];
} else {
val = ((uint64_t)p_varint[8] << 56) |
((uint64_t)p_varint[7] << 48) |
((uint64_t)p_varint[6] << 40) |
((uint64_t)p_varint[5] << 32) |
((uint64_t)p_varint[4] << 24) |
((uint64_t)p_varint[3] << 16) |
((uint64_t)p_varint[2] << 8) |
(uint64_t)p_varint[1];
}
return val;
}
VarInt
, varint
, var_int
Compact Size型という名称だが、BIP には VarInt
や varint
もあれば var_int
として書かれているところもある。
GitHub の BIP を検索したところこういう状況だった。
あまり区別されていないようなので、Bitcoin 関連でこれらの型が出てきたらだいたい Compact Size型だと思ってよいのではなかろうか。
var_int
が使われている BIPVarInt
/varint
が使われている BIP- BIP-10
- BIP-23
- BIP-37
- BIP-98
- BIP-154
- BIP-180
- BIP-337
スクリプトの中に数値が使われる場合は命令と組み合わせて使うため Compact Size型とは別の表現になる(Constants)。
LevelDBにVarIntがあるが、あれとは関係ない。