Bytes

Unidades de armazenamento para dados

Diagrama mostrando 8 bits individuais formando um único byte hexadecimal.

Este é um guia rápido para explicar o que são bytes e como são usados no bitcoin. Será útil se você está trabalhando com transações e outros dados brutos do bitcoin.

Você vai fazer alguma programação de baixo nível ao trabalhar com dados do bitcoin, então é bom saber o que está olhando.

Eu também não sou cientista da computação, mas bytes são bem simples de entender.

Conteúdo

Introdução

Ao usar bitcoin no dia a dia, você verá frequentemente bytes brutos de dados:

Ao trabalhar com bitcoin, você logo descobre que todos os dados centrais também são feitos de bytes brutos:

O Bitcoin é um programa de computador, e computadores leem e se comunicam usando bytes. Então, se você planeja trabalhar com bitcoin no nível técnico, é útil saber o que é um byte, como ele é exibido e os tipos de dados que ele armazena.

Básico

Antes de chegar aos bytes, precisamos saber o que é um "bit".

Bit

Um bit é a menor unidade de dados que um computador pode guardar. Pode ser um 1 ou um 0 (ou seja, um único transistor "ligado" ou "desligado"):

Bit

Clique no bit para alterná-lo entre 0 e 1.

desligado (0)

Esses bits são os blocos de construção para armazenar dados dentro dos computadores.

O Ben Eater tem ótimos vídeos sobre como computadores funcionam.

Se você travar ao programar, lembre que, no fim das contas, é tudo só um monte de uns e zeros.

Byte

Um byte é só um grupo de 8 bits individuais:

Byte

Clique nos bits para alterná-los e veja as diferentes interpretações de um byte.

00000000

Um byte é uma unidade conveniente de armazenamento de dados em um computador. Assim como às vezes é mais prático medir peso em quilogramas em vez de gramas, às vezes é mais prático medir dados em bytes em vez de bits.

Bytes são, na verdade, a medida padrão para dados, e a maioria dos dados com que você vai trabalhar no bitcoin é medida em bytes.

Um byte são 8 bits individuais. Então uma chave privada de 32 bytes tem 256 bits (32 × 8 = 256).

Representando Bytes

Podemos representar um byte de duas formas:

Isso funciona porque, se você dividir um byte em duas metades de 4 bits, cada metade consegue lidar com 16 combinações diferentes de 1s e 0s. Então, se você der a cada metade o seu próprio caractere hexadecimal, pode representar um byte usando apenas dois caracteres em vez de oito.

Essa representação mais curta é chamada de byte hexadecimal.

Byte → Hexadecimal

Cada metade de 4 bits (nibble) de um byte corresponde a um caractere hexadecimal.

Frequentemente exibimos bytes em formato hexadecimal para economizar espaço, o que é muito mais conveniente ao representar vários bytes de dados:

Bytes

Digite uma string hexadecimal e veja-a dividida em bytes individuais.

Bytes

Então, da próxima vez que você ver uma chave privada assim:

61dc9ff8b15450212970c6fa997338bb205dd48ffaca3a056b09a3b44a244d76

Você está, na verdade, olhando para 32 bytes individuais:

61 dc 9f f8 b1 54 50 21 29 70 c6 fa 99 73 38 bb 20 5d d4 8f fa ca 3a 05 6b 09 a3 b4 4a 24 4d 76

Quando comecei a trabalhar com Bitcoin, cometi o erro de interpretar coisas como chaves privadas como strings de letras e números individuais. Mas, na realidade, é uma sequência de bytes, em que cada dois caracteres são um byte.

Não importa se os caracteres hexadecimais são maiúsculos ou minúsculos. Por exemplo, 6b é o mesmo que 6B.

Armazenando Dados em Bytes

Então, como podemos armazenar coisas úteis como números, texto e outras coisas dentro desses bytes?

Honestamente, depende só de como você interpreta os bits.

Um byte pode conter diferentes tipos de dados dependendo de como você o interpreta. Por exemplo, o byte 01100111 poderia representar a letra "g" ou o número 103. Tudo depende de que tipo de dado você está trabalhando.

Números

Você pode usar bytes para armazenar números inteiros:

Byte → Inteiro

Converta entre um byte e o número inteiro que ele representa.

Se queremos armazenar um número em um computador, nós o armazenamos usando sua representação binária dentro dos bits de um byte. E, se queremos armazenar números maiores, simplesmente usamos mais bytes.

Exemplos

Números são muito comuns dentro dos dados do bitcoin: chave privada (número de 32 bytes), valor de saída (8 bytes), VOUT (4 bytes), nonce (4 bytes), alvo (32 bytes), locktime (4 bytes) e tempo do bloco (4 bytes, em Unix Time).

Texto

Você também pode usar bytes para armazenar texto, atribuindo a cada caractere o seu próprio byte.

Não há um padrão oficial para codificar texto dentro dos dados do bitcoin, mas o mapeamento de caracteres-para-bytes mais usado é o ASCII:

Byte → ASCII

Converta entre um byte e um caractere ASCII.

Tabela ASCII

Os caracteres a seguir são da Code Page 437, um conjunto de caracteres ASCII de 8 bits bastante popular.

Basicamente, todos os conjuntos de caracteres ASCII contêm as mesmas letras e números padrão (entre 0x20 e 0x7f). Estes são historicamente conhecidos como os caracteres imprimíveis.

A Code Page 437 estendeu isso com 128 caracteres adicionais (entre 0x80 e 0xff) para incluir também caracteres internacionais, de desenho de caixa e matemáticos. Esse conjunto adicional de caracteres é comumente chamado de "ASCII estendido".

A Code Page 437 também substituiu os caracteres de controle obsoletos (entre 0x01 e 0x1f) do ASCII original (ex.: ISO 646) por caracteres decorativos.

Não existe um conjunto de caracteres ASCII específico usado no Bitcoin, mas este é popular e serve bem para demonstrar como os bytes podem ser atribuídos a caracteres.

ASCII Padrão

Caracteres Decorativos
Binário Hexadecimal Decimal Caractere
00000000 00 0
00000001 01 1
00000010 02 2
00000011 03 3
00000100 04 4
00000101 05 5
00000110 06 6
00000111 07 7
00001000 08 8
00001001 09 9
00001010 0a 10
00001011 0b 11
00001100 0c 12
00001101 0d 13
00001110 0e 14
00001111 0f 15
00010000 10 16
00010001 11 17
00010010 12 18
00010011 13 19
00010100 14 20
00010101 15 21 §
00010110 16 22
00010111 17 23
00011000 18 24
00011001 19 25
00011010 1a 26
00011011 1b 27
00011100 1c 28
00011101 1d 29
00011110 1e 30
00011111 1f 31
Caracteres Imprimíveis
Binário Hexadecimal Decimal Caractere
00100000 20 32 (espaço)
00100001 21 33 !
00100010 22 34 "
00100011 23 35 #
00100100 24 36 $
00100101 25 37 %
00100110 26 38 &
00100111 27 39 '
00101000 28 40 (
00101001 29 41 )
00101010 2a 42 *
00101011 2b 43 +
00101100 2c 44 ,
00101101 2d 45 -
00101110 2e 46 .
00101111 2f 47 /
00110000 30 48 0
00110001 31 49 1
00110010 32 50 2
00110011 33 51 3
00110100 34 52 4
00110101 35 53 5
00110110 36 54 6
00110111 37 55 7
00111000 38 56 8
00111001 39 57 9
00111010 3a 58 :
00111011 3b 59 ;
00111100 3c 60 <
00111101 3d 61 =
00111110 3e 62 >
00111111 3f 63 ?
01000000 40 64 @
01000001 41 65 A
01000010 42 66 B
01000011 43 67 C
01000100 44 68 D
01000101 45 69 E
01000110 46 70 F
01000111 47 71 G
01001000 48 72 H
01001001 49 73 I
01001010 4a 74 J
01001011 4b 75 K
01001100 4c 76 L
01001101 4d 77 M
01001110 4e 78 N
01001111 4f 79 O
01010000 50 80 P
01010001 51 81 Q
01010010 52 82 R
01010011 53 83 S
01010100 54 84 T
01010101 55 85 U
01010110 56 86 V
01010111 57 87 W
01011000 58 88 X
01011001 59 89 Y
01011010 5a 90 Z
01011011 5b 91 [
01011100 5c 92 \
01011101 5d 93 ]
01011110 5e 94 ^
01011111 5f 95 _
01100000 60 96 `
01100001 61 97 a
01100010 62 98 b
01100011 63 99 c
01100100 64 100 d
01100101 65 101 e
01100110 66 102 f
01100111 67 103 g
01101000 68 104 h
01101001 69 105 i
01101010 6a 106 j
01101011 6b 107 k
01101100 6c 108 l
01101101 6d 109 m
01101110 6e 110 n
01101111 6f 111 o
01110000 70 112 p
01110001 71 113 q
01110010 72 114 r
01110011 73 115 s
01110100 74 116 t
01110101 75 117 u
01110110 76 118 v
01110111 77 119 w
01111000 78 120 x
01111001 79 121 y
01111010 7a 122 z
01111011 7b 123
01111100 7c 124 |
01111101 7d 125
01111110 7e 126 ~
01111111 7f 127

ASCII Estendido

Caracteres Internacionais
Binário Hexadecimal Decimal Caractere
10000000 80 128 Ç
10000001 81 129 ü
10000010 82 130 é
10000011 83 131 â
10000100 84 132 ä
10000101 85 133 à
10000110 86 134 å
10000111 87 135 ç
10001000 88 136 ê
10001001 89 137 ë
10001010 8a 138 è
10001011 8b 139 ï
10001100 8c 140 î
10001101 8d 141 ì
10001110 8e 142 Ä
10001111 8f 143 Å
10010000 90 144 É
10010001 91 145 æ
10010010 92 146 Æ
10010011 93 147 ô
10010100 94 148 ö
10010101 95 149 ò
10010110 96 150 û
10010111 97 151 ù
10011000 98 152 ÿ
10011001 99 153 Ö
10011010 9a 154 Ü
10011011 9b 155 ¢
10011100 9c 156 £
10011101 9d 157 ¥
10011110 9e 158
10011111 9f 159 ƒ
10100000 a0 160 á
10100001 a1 161 í
10100010 a2 162 ó
10100011 a3 163 ú
10100100 a4 164 ñ
10100101 a5 165 Ñ
10100110 a6 166 ª
10100111 a7 167 º
10101000 a8 168 ¿
10101001 a9 169
10101010 aa 170 ¬
10101011 ab 171 ½
10101100 ac 172 ¼
10101101 ad 173 ¡
10101110 ae 174 «
10101111 af 175 »
Caracteres de Desenho de Caixa
Binário Hexadecimal Decimal Caractere
10110000 b0 176
10110001 b1 177
10110010 b2 178
10110011 b3 179
10110100 b4 180
10110101 b5 181
10110110 b6 182
10110111 b7 183
10111000 b8 184
10111001 b9 185
10111010 ba 186
10111011 bb 187
10111100 bc 188
10111101 bd 189
10111110 be 190
10111111 bf 191
11000000 c0 192
11000001 c1 193
11000010 c2 194
11000011 c3 195
11000100 c4 196
11000101 c5 197
11000110 c6 198
11000111 c7 199
11001000 c8 200
11001001 c9 201
11001010 ca 202
11001011 cb 203
11001100 cc 204
11001101 cd 205
11001110 ce 206
11001111 cf 207
11010000 d0 208
11010001 d1 209
11010010 d2 210
11010011 d3 211
11010100 d4 212
11010101 d5 213
11010110 d6 214
11010111 d7 215
11011000 d8 216
11011001 d9 217
11011010 da 218
11011011 db 219
11011100 dc 220
11011101 dd 221
11011110 de 222
11011111 df 223
Símbolos Matemáticos
Binário Hexadecimal Decimal Caractere
11100000 e0 224 α
11100001 e1 225 ß
11100010 e2 226 Γ
11100011 e3 227 π
11100100 e4 228 Σ
11100101 e5 229 σ
11100110 e6 230 µ
11100111 e7 231 τ
11101000 e8 232 Φ
11101001 e9 233 Θ
11101010 ea 234 Ω
11101011 eb 235 δ
11101100 ec 236
11101101 ed 237 φ
11101110 ee 238 ε
11101111 ef 239
11110000 f0 240
11110001 f1 241 ±
11110010 f2 242
11110011 f3 243
11110100 f4 244
11110101 f5 245
11110110 f6 246 ÷
11110111 f7 247
11111000 f8 248 °
11111001 f9 249
11111010 fa 250 ·
11111011 fb 251
11111100 fc 252
11111101 fd 253 ²
11111110 fe 254
11111111 ff 255 (espaço não separável)

Como você pode ver, cada byte representa um caractere diferente. Você só precisa da tabela ASCII à mão para ver qual byte corresponde a qual caractere.

Exemplos

Texto não é frequentemente armazenado nos dados do Bitcoin, mas aparece em alguns lugares: OP_RETURN (dados arbitrários em uma saída), o scriptsig da transação coinbase (texto do minerador), o tipo/"comando" no cabeçalho de cada mensagem (12 bytes ASCII) e o campo User-Agent na mensagem "version".

Configurações (Bit Field)

Às vezes você pode usar os bits dentro de bytes de dados para representar várias configurações de ligado/desligado.

Isso é conhecido como bit field (campo de bits), e é uma forma eficiente de armazenar várias configurações no menor espaço possível.

Bit Field

Cada bit de um campo de 32 bits pode ser uma configuração de ligado/desligado. Clique para alterná-los.

Exemplos

Bit fields são usados em alguns lugares no bitcoin: o campo Services na mensagem "version" (8 bytes/64 bits indicando os serviços de um nó), o campo version do cabeçalho de bloco (4 bytes/32 bits para sinalizar prontidão para atualizações) e o campo sequence de uma transação (interpretado como bit field ao definir o locktime relativo).

Apenas Bytes

Às vezes os bytes não precisam representar nada em particular. Eles podem ser úteis simplesmente como um pedaço único de dados.

Exemplos

A saída de uma função de hash é só uma série única de bytes, e isso os torna úteis como "impressões digitais" de dados: TXID (identificador único de transação), hash de bloco (identificador único de bloco) e hash de chave pública. E às vezes usamos apenas um conjunto de bytes de aparência aleatória, sem significado, como os magic bytes (f9beb4d9) usados como marcador entre mensagens.

Então você não precisa interpretar bytes como nada em especial. Ter um conjunto único de bytes para usar como "impressão digital" dos dados já é útil por si só.

Um hash de bloco na verdade é interpretado tanto como um identificador único quanto como um número. Geralmente é só um identificador único para o bloco, mas também é interpretado como um número durante o processo de mineração para verificar se o hash está abaixo do valor de alvo atual.

Dados Personalizados

No fim, você pode usar bytes para representar o que quiser. Não precisa ser só números e texto (embora sejam os mais comuns). Tudo depende de como você escolhe interpretar as combinações de 1s e 0s dentro desses bytes.

Exemplos

Estas são algumas codificações exclusivas do bitcoin: Script (um byte em um scriptpubkey/scriptsig pode se referir a uma operação "OP_CODE"), Compact Size e o campo bits do cabeçalho de bloco (armazena o alvo atual de forma compacta).

Trabalhando com Bytes

Conseguir trabalhar com bytes brutos no bitcoin é especialmente importante quando se trata de rede ou quando você está fazendo o hash de dados.

A boa notícia é que você pode trabalhar com bytes brutos em qualquer linguagem de programação decente. Isso varia entre linguagens, mas normalmente envolve escrever o valor de cada byte individual em algum tipo de string ou array especial, assim:

"\xF9\xBE\xB4\xD9"
{0xF9, 0xBE, 0xB4, 0xD9}

Mas esse tipo de formato não é fácil de passar adiante, então você frequentemente vai converter esses bytes em strings hexadecimais para fins de exibição:

"f9beb4d9"

É assim que eu normalmente exibo bytes neste site, e como você normalmente verá bytes sendo exibidos em exploradores de blockchain.

Às vezes você também vai querer obter o valor inteiro que esses bytes representam:

4190024921

Então, ao trabalhar com dados do Bitcoin, você quer conseguir converter de um lado para o outro entre bytes de verdade, strings hexadecimais e inteiros na sua linguagem de programação preferida.

Aqui estão alguns exemplos rápidos de como fazer isso em algumas linguagens de programação comuns:

Ruby

# Trabalhe com bytes diretamente usando caracteres hexadecimais para representar cada byte.
bytes = "\xF9\xBE\xB4\xD9" #=> (jargão - tenta exibir a codificação de caracteres para cada valor de byte)

# Bytes -> String Hexadecimal
hex_string = bytes.unpack("H*")[0] #=> "f9beb4d9"

# String Hexadecimal -> Bytes
bytes = [hex_string].pack("H*") #=> (jargão - tenta exibir uma codificação de caracteres para cada valor de byte)

# String Hexadecimal -> Inteiro
integer = hex_string.to_i(16) #=> 4190024921

Ruby pode ser um pouco estranho ao exibir bytes. Se você tentar imprimir bytes diretamente, o Ruby tentará exibi-los usando a codificação de caracteres de cada byte (em vez de sua representação hexadecimal), então você precisa converter para hexadecimal para exibi-los ao depurar.

As funções "pack" e "unpack" são as mais úteis quando se trata de trabalhar com bytes brutos em linguagens como Ruby e Python, então vale a pena conhecê-las.

Python

# NOTA: Python 3.5+

# Cria bytes
raw_bytes = b'\xf9\xbe\xb4\xd9'

# Converte bytes para string hex
hex_string = b'\xf9\xbe\xb4\xd9'.hex()
print(hex_string) #=> f9beb4d9

# Converte string hex para bytes
raw_bytes = bytes.fromhex('f9beb4d9')
print(raw_bytes) #=> b'\xf9\xbe\xb4\xd9'

# Converte bytes para inteiro
integer = int.from_bytes(b'\xf9\xbe\xb4\xd9', byteorder="big") # segundo argumento é a endianness
print(integer) #=> 4190024921

Veja little-endian para detalhes sobre endianness no bitcoin.

Go

package main

import "fmt"
import "encoding/hex"
import "math/big"

func main() {

    // Cria um array de bytes
    bytes := []byte{0xF9, 0xBE, 0xB4, 0xD9}
    fmt.Println(bytes) //=> [249 190 180 217]

    // Converte array de bytes para string hexadecimal
    hex_string := hex.EncodeToString(bytes)
    fmt.Println(hex_string) //=> f9beb4d9

    // Converte string hexadecimal para array de bytes
    byte_array, _ := hex.DecodeString(hex_string)
    fmt.Println(byte_array) //=> [249 190 180 217]

    // Converte array de bytes para inteiro
    integer := new(big.Int).SetBytes(byte_array)
    fmt.Println(integer) //=> 4190024921

    // Converte inteiro para array de bytes
    byte_array_from_integer := integer.Bytes()
    fmt.Println(byte_array_from_integer) //=> [249 190 180 217]

}

Resumo

Um byte é apenas um grupo de 8 bits:

byte (binário):
┌─┬─┬─┬─┬─┬─┬─┬─┐
│0│1│1│0│1│0│1│1│
└─┴─┴─┴─┴─┴─┴─┴─┘

Para economizar espaço, geralmente representamos cada byte usando 2 caracteres hexadecimais em vez de usar 8 bits individuais:

byte (hexadecimal):
┌─┬─┐
│6│B│
└─┴─┘

Um bit é a menor unidade de dados (um 1 ou 0), e um byte é um grupo de 8 bits. Os bytes são a unidade básica dos dados brutos do Bitcoin.

Normalmente exibimos bytes em formato hexadecimal (2 caracteres por byte) para economizar espaço. E um byte pode armazenar diferentes tipos de dados — números, texto, configurações, impressões digitais — dependendo de como você interpreta os seus bits.

Quando você começa a trabalhar com dados brutos do Bitcoin, é tudo só uma questão de saber o que aqueles bytes representam.