Comprimir string hexadecimal de transação

Sep 06 2020

Percebi que a transação hexadecimal pode ser muito longa e você precisa dela para transmitir um tx usando a API blockstream.info:

https://blockstream.info/testnet/api/tx

https://github.com/Blockstream/esplora/blob/master/API.md

Se o usuário deseja enviar este hex através de mensagem de texto que permite 160 caracteres em uma mensagem, qual a melhor forma de solucionar este problema? Tentei pesquisar sobre como compactá-lo, enviar para um número que encaminha para o servidor web executando um código PHP, a string hexadecimal é descompactada e enviada para blockstream.info para transmissão tx. A codificação Base64 posterior gzcompress()não conseguiu reduzir o número de caracteres para menos de 160.

Exemplo:

Hex:

02000000000101e939fb23e9991ebbc75fd08c736da32ca12d98a4ff1b8e970e97f5661927ee410100000000fdffffff02b0a90a000000000016001421e2f997b3bd36e273eaca365da8515a389444ae40420f0000000000160014829e2dbcf6b7f31bc93633971f71f6f6b9b5f89e0247304402200f8e3e573be749caf1964a85707bf540de2e7b367ae46c23bd4f21932ff82346022062dc3007072cd5a19b45e479525f4829bc48be4fd3c21b5a9ae34bcf9a3a3ccf0121020f88c7db36cbb492e80d3062fc19db55bed82687498f8cfe6d0cf47adf6687aa49f31b00

Compactado e codificado em Base64:

eNpdkNmJBEAIRFPyarsNxzP/ENZZGBZW9Eew6pVA8C0EbGObIG4zw47Ie6bg5WUtZ0pHKnsuMxiv7cLOHFU0ut2yCl+xqfktoAA3cPiz0R0hbBqzGxzF2nS5PZ31lL+Dx/mZiHgLCMH8v35kTRU5GncYI42V2S7Otu7W4syzBpLLIAK0Mec197kcfcXSB01lzS7cmCNQTb04etdUk5ZLhtCYZh6x6EdDqZIB9oSyjqOFnJZrh858oCLlRcsUJ2EcN2+WxTRn58wBJITN8/altV4ZIUb9oHi1J9EqzomuR/qW8s3LaS3Ikes1ult3sU9mgB8sW3Vy

Respostas

2 RedGrittyBrick Sep 06 2020 at 23:44

Comprimir um número mais ou menos aleatório é inútil. Sua melhor opção é simplesmente usar uma codificação mais compacta. Base64 é melhor do que Hex, mas existem muitas outras codificações que funcionam melhor

A Wikipedia lista muitos e os classifica em ordem de eficiência

Encoding            Data type                    Efficiency
yEnc                Arbitrary, mostly non-text   ~98%
Ascii85             Arbitrary                     80%
Base85 (RFC 1924)   Arbitrary                     80%
Base64              Arbitrary                     75%
...

Obviamente, você pode fazer melhor se usar 8 bits (por exemplo, pontos de código para impressão Unicode que têm codificações de byte único em UTF-8), mas como o SMS usa um conjunto de caracteres de 7 bits (até onde eu sei), você não fará muito melhorar

CodingEnthusiast Sep 07 2020 at 13:50

Se o usuário deseja enviar este hex através de mensagem de texto que permite 160 caracteres em uma mensagem, qual a melhor forma de solucionar este problema?

Transformar 222 bytes em 160 caracteres será muito desafiador, então nosso foco não pode ser apenas na codificação, mas deve ser direcionado ao próprio 222 byte. Como não são bytes exatamente aleatórios e a estrutura de transação de bitcoin não é exatamente a estrutura mais eficiente, há oportunidades para compactar esses bytes (ou, mais precisamente, para se livrar de alguns bytes "inúteis").
Vamos primeiro decompô-lo e ver de quais bytes podemos nos livrar:

1) 02000000
2) 0001
3) 01
4) e939fb23e9991ebbc75fd08c736da32ca12d98a4ff1b8e970e97f5661927ee41
5) 01000000
6) 00
7) fdffffff
8) 02
9) b0a90a0000000000
10) 16001421e2f997b3bd36e273eaca365da8515a389444ae
11) 40420f0000000000
12) 160014829e2dbcf6b7f31bc93633971f71f6f6b9b5f89e
13) 02
14) 47304402200f8e3e573be749caf1964a85707bf540de2e7b367ae46c23bd4f21932ff82346022062dc3007072cd5a19b45e479525f4829bc48be4fd3c21b5a9ae34bcf9a3a3ccf01
15) 21020f88c7db36cbb492e80d3062fc19db55bed82687498f8cfe6d0cf47adf6687aa
16) 49f31b00
  1. A versão
    pode se transformar em 1 byte codificado como CompactInt ->02
  2. Sinalizador de testemunha
    pode ser ignorado -> (funciona modificando # 6)
  3. Contagem de entrada
    Sem alteração ->01
  4. Hash da transação de entrada
    Sem alteração ->e939fb23e9991ebbc75fd08c736da32ca12d98a4ff1b8e970e97f5661927ee41
  5. Índice de entrada
    Outro CompactInt ->01
  6. Script de assinatura
    Como regra, todos os scripts podem começar com um sinalizador 1 = P2PKH, 2 = P2WPKH, 3 = P2SH, ... 255 = não definido, e quando eles não são definidos, o script exato é colocado aqui com o tamanho e tudo mais. Como todas as outras partes, o receptor deve construir o script corretamente (definir o sinalizador de testemunha # 2, movê-los para os itens de testemunha # 14 e # 15, adicionar comprimentos para cada push push, assinatura de codificação DER) A
    testemunha torna-se: <sinalizador de 1 byte > <32-byte-r> <32-byte-s> <33-byte-pubkey>
    <02><0f8e3e573be749caf1964a85707bf540de2e7b367ae46c23bd4f21932ff82346><62dc3007072cd5a19b45e479525f4829bc48be4fd3c21b5a9ae34bcf9a3a3ccf><01><020f88c7db36cbb492e80d3062fc19db55bed82687498f8cfe6d0cf47adf6687aa>
    Se pubkey foi descompactado, o primeiro byte é alterado para 0x82=0b10000010(conjunto de bits mais significativo) para indicar que pubkey descompactado deve ser construído.
  7. A sequência
    pode ser codificada como "StackInt" (um número que é colocado na pilha que pode ser negativo)
    1 = OP_1, 2 = OP_2 -1 = OP_NegativeOne -2 = 0x82, 321321 = 0x4e29e70400
    Visto que 0xfdffffff é UInt32.Max-2 - >82
  8. Contagem de saída
    Sem alteração ->02
  9. Quantidade
    como um CompactInt->feb0a90a00
  10. Script Pubkey
    Semelhante ao script de assinatura, podemos usar sinalizadores para scripts padrão, por exemplo. 0x03 podem ser scripts P2WPKH ->0321e2f997b3bd36e273eaca365da8515a389444ae
  11. Quantidade
    como um CompactInt->fe40420f00
  12. Script Pubkey O
    mesmo de antes03829e2dbcf6b7f31bc93633971f71f6f6b9b5f89e
  13. Contagem de itens de testemunhas
    removida ->
  14. Testemunha
    removida (já está colocada em # 6) ->
  15. Testemunha
    removida (já está colocada em # 6) ->
  16. Tempo de bloqueio
    sem alteração ->49f31b00

Agora, os 222 bytes são compactados em 192 bytes (13,5%), que podem ser codificados com uma codificação mais eficiente para obter o melhor resultado possível.
Isso também pode ser mais compactado se você enviar esta transação para o destinatário real dos fundos, ignorando sua (s) produção (ões). Por exemplo, quando você deveria pagar 698800satoshi para bc1qy830n9anh5mwyul2egm9m2z3tgufg39wk4g0eu, o receptor já sabe disso e você não precisa dizer a ele novamente. Isso significa que 26 bytes em # 11 e # 12 podem ser ignorados, reduzindo o tamanho para 166 bytes (25,2%) . Mas deve-se concordar que a saída de recebimento é a primeira, por exemplo.
Isso poderia ser compactado ainda mais com mais acordos:

  • A versão Tx deve ser sempre 2 -> 165 bytes
  • SigHashType deve ser sempre SigHashAll -> 164 bytes (remova de cada entrada # 6 aqui)
  • Cada sequência de entrada deve ser definida para int predefinido -> 163 bytes (pular # 7)
  • Tx deve sempre ter 2 saídas -> 162 bytes (pular # 8)
  • O tempo de bloqueio deve ser sempre 0 -> 158 bytes (pular # 16) ( 28,8% )