Por favor, artistas, não pixar 🎨 🔫
RASCUNHO - Arte em blocos de criptoativo
No começo de 2024, surgiu uma arte num bloco de um dos criptoativos mais conhecidos. A criação foi realizada pela MaraPool explorando algumas possibilidades já que detém seu próprio pool de mineração. Como as transações dentro do bloco podem ser rearranjadas conforme o minerador desejar, se o mesmo for consolidado será permanentemente registrado na blockchain. Agora, quando visualizadas numa matriz considerando o valor das taxas individuais, apresentam claramente um logotipo como mostra a imagem seguinte.
Detalhes
Fonte: mempool.space
Esta proeza está permanentemente registrada no bloco 836361
inclusão de arquivos dentro do bloco
Cada bloco comporta aproximadamente 4000 transações individuais de tamanho reduzido...
Cenário | Tamanho Médio de Transação | Tamanho Máximo do Bloco | Máximo de Transações por Bloco |
---|---|---|---|
Bloco tradicional (sem SegWit) | 250 bytes | 1MB (1.000.000 bytes) | ≈ 4.000 transações |
Bloco otimizado com SegWit | 150 bytes | 4MB (4.000.000 bytes) | ≈ 26.666 transações |
Campo | Tamanho | Finalidade | Descrição |
---|---|---|---|
Versão da Transação | 4 bytes | Identificação de versão | Indica o formato da transação |
Contagem de Entradas | Variável | Número de entradas | Define quantas entradas serão usadas na transação |
Entrada 1 | Fonte de fundos | ||
- Hash da Transação | 32 bytes | Hash da transação anterior | Identifica a origem dos bitcoins |
- Índice da Saída | 4 bytes | Índice da saída anterior | Refere-se a qual saída da transação anterior |
- ScriptSig | Variável | Assinatura digital | Prova de que o remetente tem a chave para gastar |
- Número de Sequência | 4 bytes | Atualização de bloqueio | Para operações que envolvem controle temporal |
Contagem de Saídas | Variável | Número de saídas | Define quantas saídas essa transação terá |
Saída 1 | Destino dos fundos | ||
- Valor | 8 bytes | Quantidade de satoshis | Quantidade de bitcoins a ser enviada |
- ScriptPubKey | Variável | Condições para gastar fundos | Define as regras para gastar os bitcoins |
Locktime | 4 bytes | Tempo de bloqueio | Data/bloco em que a transação pode ser confirmada |
Cerca de um ano antes, o bloco 774628 teve a inclusão de uma imagem JPG (arquivo com , tornando-a uma data cujo marco está permanente dentro do maior bloco do bitcoin. A imagem original pode ser visualizada a seguir.
![image](https://ordinals.com/content/0301e0480b374b32851a9462db29dc19fe830a7f7d7a88b81612b9d42099c0aei0 =400x400)
Fonte: aqui
Para os leitores céticos fica a sugestão baixar a transação completa e fazer a extração dos cerca de 4 MB que compõem o arquivo JPEG.
Mais detalhes, vejas as matérias que veicularam na época
- https://cointelegraph.com/news/bitcoin-block-art-marathon (26.03.2024)
- https://blockworks.co/news/inside-bitcoin-biggest-block (02.02.2023)
- .
Qual deverá ser a próxima proeza?
RASCUNHO PARA DESENVOLVIMENTO (por favor, não pontuar, pois assim que publicado o conteúdo será removido)
Tendência e criptografia de última geração (State-of-the-Art Cryptography)
O estado da arte em criptografia enfatiza:
- Eficiência: Algoritmos como AES, ChaCha20 e cifras leves para dispositivos IoT.
- Segurança pós-quântica: proteção contra computação quântica com algoritmos como CRYSTALS e NTRUEncrypt.
- Criptografia Homomórfica: Executar cálculos em dados criptografados sem descriptografá-los.
- Provas de conhecimento zero: verificar uma declaração sem revelar os dados reais.
- Criptografia Blockchain: Protegendo livros contábeis descentralizados com funções hash e algoritmos de curva elíptica.
Com curiosidade, é apresentada uma pequena lista expandida contendo as cifras históricas e modernas. Cobre desde as antigas técnicas de cifragem até os mais recentes algoritmos criptográficos já conhecidos. Estão agrupados para maior clareza. Se necessário, é fornecida alguma informação sobre algumas delas.
Detalhes
- Cifras antigas e clássicas
Estas foram as primeiras técnicas de cifragem por processo manual, utilizadas por séculos antes do advento de máquinas para tal propósito:
- Caesar
- Atbash
- Affine
- Polybius
- Scytale
- Pigpen (ou Masonic Cipher)
- Substitution (geral)
- Transposition (geral)
- Grille
- Nihilist
- Four-Square
- Playfair
- Hill
- Route Transposition
- Grandpré
- ADFGX +
- ADFGVX +
- ROT13
- A1Z26
- Railfence
- Bifid
- Trifid
- Cifras da era Medieval e Renascença
- Vigenère
- Autokey
- Beaufort
- Homophonic Substitution
- Running Key
- Bacon's (Cifra Estaganográfica)
- Cardano Grille
- Cifras da era mecânica
Empregadas a partir do século XIX até a WWII.
- Enigma Machine M3 +
- Lorenz
- Jefferson Wheel (ou Bazeries Cylinder)
- M-209 (Field Cipher Machine)
- Purple (Japanese Cipher Machine)
- SIGABA (American Cipher Machine)
- Typex (British Cipher Machine)
- Cifra Estaganográfica e de Máscaras
De acordo com o senso matemático, oculta a mensagem em vez criptografá-la.
- Grille (mencionada acima)
- Nicodemus
- Book (quanto o texto encontra-se escondido dentro de um texto mais longo)
- Pollux
- Criptografia clássica moderna
Empregada de meados do século XX até o presente. Emprega algoritmos em vez de técnicas manuais.
- Data Encryption Standard (DES)
- Triple DES (3DES)
- Advanced Encryption Standard (AES)
- RSA (Rivest-Shamir-Adleman)
- Diffie-Hellman Key Exchange
- ElGamal
- Blowfish
- Twofish
- Serpent
- IDEA (International Data Encryption Algorithm)
- RC4, RC5, RC6 (Rivest Ciphers)
- Stream Ciphers
Criptografam os dados bit a bit.
- RC4
- A5/1 and A5/2 (empregada em redes móveis com tecnologia GSM)
- Salsa20/ChaCha20
- SEAL
- Block Ciphers (cifras de bloco)
Criptografam blocos de dados com tamanho predefinido.
- DES, AES (mentionado acima)
- Blowfish, Twofish (mentionado acima)
- CAST-128/CAST-256
- Camellia
- ARIA
- Rijndael (precursor do algoritmo AES)
- Criptografia Post-Quântica
Algoritmos projetados para resistir a ataques de computação quântica.
- CRYSTALS (Cryptographic Suite for Algebraic Lattices)
- CRYSTALS-Kyber (Key Encapsulation)
- CRYSTALS-Dilithium (Digital Signatures)
- NTRUEncrypt +
- Picnic
- FrodoKEM
- Hash Functions e Cryptographic Digests
Essencialmente não são considerados cifras, mas essenciais em sistemas criptográficos para conferência de mensagens a partir de uma assinatura de tamanho reduzido.
- MD5 (Message Digest 5)
- SHA-1, SHA-2, SHA-3 (Secure Hash Algorithms)
- Blake2
- Argon2 (Key Derivation Function)
- Outras
- Cifras híbricas e empregadas para fins específicos
Usadas em combinação com outras técnicas criptográficas
- Elliptic Curve Cryptography (ECC)
- Galois/Counter Mode (GCM) for AES
- Quantum Key Distribution (QKD)
- Cifras diversas e mais novas
Raras, experimentais ou específicas para determinada situação (utilidade)
- Gromark
- Myszkowski
- Syllabary
- Solitaire (desenvolvida por Bruce Schneier, emprega cartas do baralho)
- Chaocipher (cifra manual com "unique encryption wheel mechanics")
- Codificação para transmissão
Parte destas cifras são citadas no video "The Unbreakable Kryptos Code" relatando a decifragem de parte do enigma Kryptos.
Compactaçao de imagem RGB para JPEG
JPEG (Joint Photographic Experts Group). O Processo eh realizado em 6 principais etapas:
-
Transformação do espaço de cores RGB para Y'CbCr (Y' = luminance component; Cr, Cb = red and blue crominance components)
-
Transformada discreta do cosseno (DCT) sobre os canais Y', Cb e Cr
2.1 Imagem é dividida em blocos de 8 x 8 pixels
2.2 Se a imagem não tem dimensões múltiplas de 8, deve ser preenchida a partir da lateral direita e parte inferior -
Quantização de acordo com a % referente à qualidade
3.1 Canal Y' utiliza matriz de quantização Q_Y
3.2 Canais Cb e Cr utilizam matriz de quantização Q_C -
Hufmann encoding para as quantidades AC. Quantidades DC utilizam compressão diferencial
-
Compressão
-
Escrita do arquivo JPEG
1) Transformação do espaço de cores
YCbCr definida pela CCIR 601-1 com Cb e Cr normalizados para o intervalo 0..CENTER em vez de -0.5 a 0.5. CENTER = 256 / 2 = 128.
O valores da transformação RGB para Y'CbCr foram calculados a partir da matriz inversa de Y'CbCr para RGB.
CJ = 128
Y = 0,29900 * R + 0,58700 * G + 0,11400 * B
Cb = -0,16874 * R - 0,33126 * G + 0,50000 * B + CENTERJSAMPLE
Cr = 0,50000 * R - 0,41869 * G - 0,08131 * B + CENTERJSAMPLE
ou
| Y | | 0,299000 0,586998 0,114000 | | R | | 0,0 |
| Cb | = | -0,168736 -0,331263 0,500000 | x | G | + 128,0 * | 1,0 |
| Cr | | 0,500000 -0,418686 -0,081313 | | B | | 1,0 |
Transformação inversa
| R | | 1,00000 -0,000000 1,402000 | | Y | | 1,0 |
| G | = | 1,00000 -0,344140 -0,714140 | x | Cb | - 128,0 * | 1,0 |
| B | | 1,00000 1,772000 0,000000 | | Cr | | 1,0 |
2) Transformada discreta do cosseno (Discrete Cosine Transformation - DCT)
Como o próprio nome sugere, é uma transformação aplicada para valores discretos. Considerando os blocos com tamanho 8 x 8 pixel, são calculados 8 x 8 coeficientes da DCT.
Transformada direta
S[v][u] = (1/4) * C[u] * C[v] * Sum[x=0..7] Sum[y=0..7] s[y][x] \
* cos((2*x+1)*u*pi/16) * cos((2*y+1)*v*pi/16)
int N = 8
// Função para calcular os coeficientes da DCT para um bloco 8x8
// Esta função apenas calcula os coeficientes não o bloco transformado
// Código não otimizado
void dct_basis(double dct_block[N][N], int u, int v) {
// Optimization: it is a constant (u * PI) / (2 * N)
for (int x = 0; x < N; x++) {
for (int y = 0; y < N; y++) {
double coeff_x = cos(((2.0 * x + 1.0) * u * PI) / (2.0 * N));
double coeff_y = cos(((2.0 * y + 1.0) * v * PI) / (2.0 * N));
dct_block[x][y] = coeff_x * coeff_y;
}
}
}
Transformada inversa
S[y][x] = (1/4) * Sum[u=0..7] Sum[v=0..7] C[u] * C[v] * s[v][u] \
* cos((2*x+1)*u*pi/16) * cos((2*y+1)*v*pi/16)
com:
C(u), C(v) = 1.0 / sqrt(2.0) para u, v = 0
C(u), C(v) = 1.0 para outros casos
As matrizes de transformação são ortogonais, logo, a transformada inversa se dá pela simples transposta da matriz de transformação. Expressando as equações na forma matricial:
Q = T x Y x T'
onde:
S = matriz com valores de amostra (Sample values of Y' or Cb or Cr)
T = matriz de transformação da DCT
Q = matriz de valores
3) Matrizes de quantização
Os coeficientes de quantização para as componentes de luminância e crominância são apresentados em duas matrizes na referência indicada. Foram obtidos a partir de experimentos com limiares psicovisuais, derivados empiricamente usando luminância e crominância com subamostragem horizontal 2:1. Fornecem uma quantização com fator de qualidade de 50% (numa escala de 0 a 100%).
Os valores fornecidos na documentação são exemplos e não são necessariamente adequados para qualquer aplicação específica. Estes valores de quantização foram obtidos a partir da avaliação de resultados razoáveis em imagens de luminância e crominância de 8 bits por amostra. As características destas imagens podem ser conferidas na Figura 13 da referência.
Estes valores de quantização são apropriados para a normalização dos valores resultantes da DCT. Dividindo-os por 2, a imagem reconstruída resultante apresenta diferenças praticamente indistinguíveis da imagem original. Os valores resultantes devem ser arredondados para o inteiro mais próximo.
Matriz com coeficientes de quantização para frequências de luminância
16 11 10 16 124 140 151 161
12 12 14 19 126 158 160 155
14 13 16 24 140 157 169 156
14 17 22 29 151 187 180 162
18 22 37 56 168 109 103 177
24 35 55 64 181 104 113 192
49 64 78 87 103 121 120 101
72 92 95 98 112 100 103 199
Matriz com coeficientes de quantização para frequências de crominância
17 18 24 47 99 99 99 99
18 21 26 66 99 99 99 99
24 26 56 99 99 99 99 99
47 66 99 99 99 99 99 99
99 99 99 99 99 99 99 99
99 99 99 99 99 99 99 99
99 99 99 99 99 99 99 99
99 99 99 99 99 99 99 99
Diferentes valores para o fator de qualidade modulam quão agressiva ou permissiva são essas matrizes:
JPEG permite ajustar o fator de qualidade (QF) entre 1 e 100:
- QF = 100: Baixa compressão, alta qualidade.
- QF = 50: Compressão nominal padrão.
- QF < 50: Alta compressão, baixa qualidade.
Cada matriz de quantização é escalada conforme o algoritmo seguinte:
Q(u, v) = floor(Q_Y(u, v) * S / 100 + 0,5)
onde:
S = 5000 / QF para (QF < 50)
S = 200 - 2 * QF para (QF > 50)
3) Teoria
4) Exemplo numérico
As amostras 8 x 8 abaixo são dadas em formato PGM (Portable Gray Map) em modo texto. A porção da imagem é tomada de um artigo publicado em https://cgjennings.ca/articles/jpeg-compression (coordenadas rows = 88...95; cols = 48...55)
# Canal Red
P2
8 8
255
232 229 228 255 146 12 71 24
228 239 235 254 191 17 40 47
240 229 230 255 168 24 80 60
242 244 235 255 145 17 21 48
235 242 243 255 108 5 5 119
238 238 240 255 83 0 51 130
249 247 255 250 79 27 83 122
249 255 225 131 82 103 128 91
# Canal Green
P2
8 8
255
241 242 240 255 165 19 67 37
243 242 238 255 218 32 41 50
241 242 244 255 194 23 69 81
244 243 245 255 170 82 83 26
248 249 251 255 141 29 28 112
248 244 247 255 130 0 51 130
253 249 255 255 115 30 85 126
252 255 226 146 103 114 137 109
# Canal Blue
P2
8 8
255
254 251 248 255 162 20 64 39
255 255 250 255 207 16 54 49
253 253 253 255 186 18 90 79
252 252 252 255 171 64 66 45
255 255 255 255 131 20 19 121
253 255 254 255 120 0 57 131
255 252 255 255 104 21 71 103
255 255 242 140 38 64 87 46
Conversão dos canais RGB para YCbCr
# Canal Y (luminancia)
P2
8 8
255
240 239 237 255 159 17 68 33
240 243 238 255 209 26 42 49
242 239 241 255 185 23 75 74
244 244 243 255 163 61 63 35
245 248 249 255 130 21 20 115
246 243 246 255 115 0 52 130
252 249 255 254 103 28 83 122
251 255 228 141 89 105 129 96
# Canal Cb (Crominância azul)
P2
8 8
255
136 135 134 128 130 130 126 131
137 135 135 128 127 123 135 128
134 136 135 128 128 125 137 131
132 132 133 128 133 130 130 134
134 132 131 128 129 128 127 131
132 135 133 128 131 128 131 129
130 130 128 129 129 124 121 117
130 128 136 128 99 105 105 100
# Canal Cr (Crominância vermelho)
P2
8 8
255
122 121 121 128 119 124 130 121
120 125 126 127 115 122 126 127
127 121 120 128 116 129 132 118
126 128 122 128 115 97 98 137
121 124 124 128 112 117 117 131
123 124 124 128 105 128 128 128
126 127 128 125 111 127 128 128
126 128 126 121 123 127 128 124
Aplicando a transformada do cosseno para o canal Y obtém-se a matriz T
H = [
0.353553 0.353553 0.353553 0.353553 0.353553 0.353553 0.353553 0.353553
0.490393 0.415735 0.277785 0.097545 -0.097545 -0.277785 -0.415735 -0.490393
0.461940 0.191342 -0.191342 -0.461940 -0.461940 -0.191342 0.191342 0.461940
0.415735 -0.097545 -0.490393 -0.277785 0.277785 0.490393 0.097545 -0.415735
0.353553 -0.353553 -0.353553 0.353553 0.353553 -0.353553 -0.353553 0.353553
0.277785 -0.490393 0.097545 0.415735 -0.415735 -0.097545 0.490393 -0.277785
0.191342 -0.461940 0.461940 -0.191342 -0.191342 0.461940 -0.461940 0.191342
0.097545 -0.277785 0.415735 -0.490393 0.490393 -0.415735 0.277785 -0.097545
]
T = H' x Y x H = [
1332 241 -29 -134 234 87 20 70
-344 -76 -93 107 -55 -12 -65 11
270 41 66 -41 23 25 3 20
-105 27 -62 -27 40 -12 4 -17
137 20 39 28 -35 10 14 4
1 7 -39 -5 -5 38 -10 -6
71 6 32 -1 -10 19 -9 11
37 15 6 -34 21 9 3 -1
]
Nota: cálculo dos coeficiente da matriz H
#include<stdio.h>
#include<math.h>
double H(double n, double u, double x) {
return sqrt(((u==0.0)?1.0:2.0)/n)*cos( (2.0*x+1.0)*u*M_PI/(2.0*n) );
}
int main(int argc, char *argv[], char *env[]) {
double n = 8.0;
for(double u = 0; u<n; u++) {
for(double x = 0; x<n; x++) printf("%11.6f", H(n, u, x));
printf("\n");
}
return 0;
}
Matriz de quantização para a luminância (Y), fator de qualidade 50 (de 0 a 100):
Qy_50 = [
16 12 14 14 18 24 49 72
11 12 13 17 22 35 64 92
10 14 16 22 37 55 78 95
16 19 24 29 56 64 87 98
24 26 40 51 68 81 103 112
40 58 57 87 109 104 121 100
51 60 69 80 103 113 120 103
61 55 56 62 77 92 101 99
]
A matriz resultante é a divisão de cada elemento da matriz T pelo elemento correspondente na matriz de quantização Qy_50
T_Qy50 = [
83 20 -2 -10 13 4 0 1
-31 -6 -7 6 -2 0 -1 0
27 3 4 -2 1 0 0 0
-7 1 -3 -1 1 0 0 0
6 1 1 1 -1 0 0 0
0 0 -1 0 0 0 0 0
1 0 0 0 0 0 0 0
1 0 0 -1 0 0 0 0
]
Aplica-se o algoritmo de captura em zig-zag
20,-31,27,-6,-2,-10,-7,3,-7,6,1,4,6,13,4,-2,-2,-3,1,0,...,0
Prossegue com o algoritmo de Huffman para posteriormente compactar os coeficientes AC. O primeiro coeficiente em (1,1) = 83 refere-se à componente DC (contínua) e é excluído desta compactação sendo combinado com os demais de outras matrizes e codificado diferencialmente.
5) Source code
6) References
ToDo:
- Equações de transformação de espaços de cores
- Matrizes de quantização para luminância Y' e crominâncias Cb e Cr
- Como alterar o fator de qualidade
- Teoria
- Exemplo numérico
- Transcrever source code to javascript
- Incluir references
- Corrigir a ortografia e pontuação
- Particularidades (precisão, inteiros, algoritmos etc.)
O que são as constantes mágicas encontradas no algoritmo SHA-256?
SHA-256 é uma das funções hash que faz parte da família SHA-2 (sucessora da família SHA-1) definidas no U.S. National Institute of Standards and Technology - Federal Information Processing Standards Publication (FIPS PUB) 180-4 update 1 publicado em agosto de 2015 (sob revisão após receber sugestões) e previamente definido nos padrões anteriores FIPS PUB 180, FIPS PUB 180-1, FIPS PUB 180-2, 180-2 update 1, FIPS PUB 180-3, FIPS PUB 180-4. Outras funções da mesma família são: SHA-224, SHA-256, SHA-384, SHA-512, SHA-512/224, SHA-512/256, sendo o valor numérico o número de bits resultante do resumo ou digest.
Existem diferentes implementações (1, 2, 3) do algoritmo SHA-256, contendo 72 constantes hardcoded para eficiência e padronização. Tais constantes desempenham um papel crucial em determinadas funções internas, sendo 8 delas, denominadas H_j, participantes na etapa de inicialização dos valores de hash e outras 64 constantes, denominadas K_i, participantes na etapa de compressão.
Detalhes
---------------------------------- K ---------------------------------- --- H ---
428A2F98 71374491 B5C0FBCF E9B5DBA5 3956C25B 59F111F1 923F82A4 AB1C5ED5 6A09E667
D807AA98 12835B01 243185BE 550C7DC3 72BE5D74 80DEB1FE 9BDC06A7 C19BF174 BB67AE85
E49B69C1 EFBE4786 0FC19DC6 240CA1CC 2DE92C6F 4A7484AA 5CB0A9DC 76F988DA 3C6EF372
983E5152 A831C66D B00327C8 BF597FC7 C6E00BF3 D5A79147 06CA6351 14292967 A54FF53A
27B70A85 2E1B2138 4D2C6DFC 53380D13 650A7354 766A0ABB 81C2C92E 92722C85 510E527F
A2BFE8A1 A81A664B C24B8B70 C76C51A3 D192E819 D6990624 F40E3585 106AA070 9B05688C
19A4C116 1E376C08 2748774C 34B0BCB5 391C0CB3 4ED8AA4A 5B9CCA4F 682E6FF3 1F83D9AB
748F82EE 78A5636F 84C87814 8CC70208 90BEFFFA A4506CEB BEF9A3F7 C67178F2 5BE0CD19
Código elaborado para cálculo das 72 constantes
echo "" | awk --sandbox '{
j = 0; # Inicializacao do indice para constantes H
# Numeros primos de 2 a 317
primes = " 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41,"\
" 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 101,"\
"103, 107, 109, 113, 127, 131, 137, 139, 149, 151, 157, 163, 167,"\
"173, 179, 181, 191, 193, 197, 199, 211, 223, 227, 229, 233, 239,"\
"241, 251, 257, 263, 269, 271, 277, 281, 283, 293, 307, 311, 313 ";
n = split(primes, p, ","); # Transcreve para vetor os números primos dados
# Imprime um cabecalho
printf("---------------------------------- K ");
printf("---------------------------------- --- H ---\n");
for(i = 1; i = 64; i++) {
# Calcula e imprime as constantes K( 1) até K(64)
c = p[i]^(1/3); k = int(2^32*(c-int(c))); printf("%08X ", k);
if(!(i%8)) {
j++;
# Calcula e imprime as constantes H(1) até H(8)
b = p[j]^(1/2); h = int(2^32*(b - int(b))); printf(" %08X\n", h);
};
}
}'
Mas, qual é a origem, o significado e o motivo destas constantes?
Ao utilizar as partes fracionárias das raízes cúbicas dos 64 primeiros números primos (NIST.FIPS.180-4, pag. 11) para geração das constantes K e utilizar as partes fracionárias das raízes quadradas dos 8 primeiros números primos (NIST.FIPS.180-4, pag. 15) para geração das constantes H, cria-se, desta forma, um conjunto de constantes que tornam a função hash resistente a ataques, garantindo um comportamento complexo e menos previsível. Para obter as constantes, aquelas partes fracionárias são então multiplicadas por 2^32
, os resultados truncados para inteiros e então impressos na base numérica hexadecimal. Tais valores são então facilmente obtidos de maneira determinística e, para que haja consistência das saídas de hash em diferentes implementações do algoritmo, tais valores devem ser mantidos fixos. Essas constantes mágicas usadas no algoritmo de hash SHA-256 proporcionam uma não-linearidade para a função hash.
Aplicações do SHA-256
SHA-256 é amplamente utilizada como função criptográfica de hash, produzindo uma saída de 256 bits independente do número de bytes fornecidos na sua entrada (um simples caractere ou arquivos inteiros). Outra aplicação relevante é no algoritmo de mineração de um dos ativos digitais mais conhecidos, onde se aplica a função duas vezes, ou seja, sha256(sha256(conteúdo))
e por isso às vezes é denominada sha256d
.
Por que sha256(sha256(conteúdo))?
O Bitcoin encadeia o algoritmo de hash SHA-256 duas vezes no processo de criação de um hash para um determinado bloco, especificamente ao cabeçalho do bloco. O cabeçalho do bloco inclui dados importantes como o hash do bloco anterior, a estampa de hora (timestamp), o nonce (um número usado uma vez) entre outros elementos.
Estrutura de um cabeçalho
O duplo hash resultante é uma representação compacta do estado de todo o bloco e é usado no mecanismo de prova de trabalho (proof of work), onde os mineradores competem para encontrar um hash que seja inferior a um determinado limite alvo denominado difficult.
O duplo hash serve a vários propósitos:
-
Segurança aprimorada: Ao fazer hash dos dados duas vezes, o Bitcoin adiciona uma camada adicional de segurança. Embora o SHA-256 já seja considerado seguro, o hash duplo torna ainda mais difícil para os "invasores" encontrarem colisões (dois dados diferentes que produzem o mesmo hash) ou pré-imagens (encontrar uma entrada que faz hash para uma saída específica).
-
Saída Determinística: O uso de SHA-256 duplo garante que a saída seja determinística, o que significa que a mesma entrada sempre produzirá a mesma saída. Ao aplicar a mesma função hash duas vezes, quaisquer pequenas alterações na entrada levarão a saídas hash significativamente diferentes.
-
Resistência a certos ataques: o hash duplo pode mitigar certos tipos de ataques, especificamente aqueles que visam a primeira camada do processo de hash. Se um invasor puder interferir (influenciar) a entrada do primeiro hash, deverá também precisará lidar com o segundo hash, tornando-o mais complexo e demorado.
-
Consistência do comprimento de saída: Hashing duas vezes garante um comprimento de saída consistente, o que é crucial para funções criptográficas. Mesmo que a primeira função hash tivesse características diferentes, a segunda camada impõe um comprimento e estrutura de saída uniformes.
Funções hash são construídas de maneira que teoricamente não seja possível reverter o processo a partir das saídas, ou seja, recriar uma entrada (um arquivo) a partir de seu hash. Entretanto, hash de mensagens curtas ou mesmo arquivos estruturados, podem ser revertidos a partir de ataques via força bruta como rainbow tables.
Fontes consultadas...
http://csrc.nist.gov/publications/fips/fips180-3/fips180-3_final.pdf
https://csrc.nist.gov/publications/fips#fips180-4
https://datatracker.ietf.org/doc/html/rfc6234
https://eprint.iacr.org/2011/565.pdf
http://www.hashcash.org/papers/hashcash.pdf
https://bitcoin.org/bitcoin.pdf
https://armantheparman.com/sha256
https://armantheparman.com/dicev1
Rascunho - O que são Merkle trees?
merkle_blk75000.py
Detalhes
# Uses : python 2
# Dependency: hashlib
import hashlib
# Hash pairs of items recursively until a single value is obtained
def merkle(hashList):
if len(hashList) == 1:
return hashList[0]
newHashList = []
# Process pairs. For odd length, the last is skipped
for i in range(0, len(hashList)-1, 2):
newHashList.append(hash2(hashList[i], hashList[i+1]))
if len(hashList) % 2 == 1: # odd, hash last item twice
newHashList.append(hash2(hashList[-1], hashList[-1]))
return merkle(newHashList)
def hash2(a, b):
# Reverse inputs before and after hashing
# due to big-endian / little-endian nonsense
a1 = a.decode('hex')[::-1]
b1 = b.decode('hex')[::-1]
h = hashlib.sha256(hashlib.sha256(a1+b1).digest()).digest()
return h[::-1].encode('hex')
# https://blockexplorer.com/rawblock/0000000000000000e067a478024addfecdc93628978aa52d91fabd4292982a50 (outdated)
# wget -qO- https://mempool.space/api/block/00000000000ace2adaabf1baf9dc0ec54434db11e9fd63c1819d8d77df40afda/txids
# expected Merkle Root
# wget -qO- https://mempool.space/api/block/75000
# ed385c2dbc69aa24965909c7d9d11bbd99faa085cb4ec17865d9b557ffb3a68a
#
txHashes = ["5277cf3790381c2cc2b071038d8c35b3b601207c92f8aec15978a5f01ecf8319",
"182c2ed191a35ea496ce84c42d8beee6f9d82b9f063de2e45a54692bb043696a",
"707e86e5e2356cb53a2edf0be391d56cfc998bcfa05a13a5772ef474c5eba105",
"711e15a9a819de4d1269d71de9744dedf9b6c32bba36bb0196f003f6507d4bb4",
"8c1e409484e30c205698647753cca07d826c34756773bd0432202487f28e2d54",
"abfaf8e7ad6241ca5161e517baade1275cf6333d0d118d221f894813bacb4f78"]
print merkle(txHashes)
Fontes
Rotinas para operações com matrizes em C. Portável para Javascript
Por que não utilizar LAPACK?
Code in C
#include <stdio.h>
#include <math.h>
// Prototypes
void mxinverse(double* matrix, int n);
void mxmult(double* matrixA, double* matrixB, double* matrixC,
int mA, int nA, int mB, int nB);
void mxadd(double* matrixA, double* matrixB, double* matrixC,
int mA, int nA, int mB, int nB, double alpha, double beta);
// ToDo: Improve this function returning a status value
void mxinverse(double* matrix, int n) {
int i, j, k;
double sum;
for (i = 0; i < n; i++) {
for (j = i; j < n; j++) {
sum = matrix[i * n + j];
for (k = i - 1; k >= 0; k--) {
sum -= matrix[i * n + k] * matrix[j * n + k];
}
if (i == j) {
// What happen when sum < 0.0?
matrix[i * n + i] = sqrt(sum);
} else {
// What happen when matrix[i * n + i] == 0.0?
// ToDo: return a status value
matrix[j * n + i] = sum / matrix[i * n + i];
}
}
}
for (i = 0; i < n; i++) {
for (j = i; j < n; j++) {
sum = (i == j) ? 1.0 : 0.0;
for (k = j - 1; k >= i; k--) {
sum -= matrix[j * n + k] * matrix[j * n + k];
}
// What happen when matrix[i * n + i] == 0.0?
// ToDo: return a status value
matrix[j * n + i] = matrix[j * n + i] / matrix[i * n + i];
matrix[i * n + j] = sum / matrix[i * n + i];
}
}
for (i = 0; i < n; i++) {
for (j = i + 1; j < n; j++) {
for (k = i + 1; k < j; k++) {
matrix[j * n + i] -= matrix[j * n + k] * matrix[k * n + i];
}
// What happen when matrix[i * n + i] == 0.0?
// ToDo: return a status value
matrix[j * n + i] /= matrix[j * n + j];
}
}
}
// C[i,j] = alpha * ( A[i,j] * B[i,j] ) + beta * C[i,j] // C = A * B
// C[i,j] = alpha * ( A[j,i] * B[i,j] ) + beta * C[i,j] // C = A' * B
// C[i,j] = alpha * ( A[j,i] * B[j,i] ) + beta * C[i,j] // C = A' * B'
// C[i,j] = alpha * ( A[i,j] * B[j,i] ) + beta * C[i,j] // C = A * B'
//
void mxmult(double* matrixA, double* matrixB, double* matrixC,
int mA, int nA, int mB, int nB, double alpha, double beta) {
// ToDo: Implement the algorithm
}
// C[i,j] = alpha * A[i,j] + beta * B[i,j] + gamma
//
// Changing alpha and beta, it is possible to implement mxsub
void mxadd(double* matrixA, double* matrixB,
int mA, int nA, int mB, int nB,
double alpha, double beta, double gamma) {
}
É possível incluir SVG inline em postagens no Tabnews? O formato vetorial para gráficos é mais eficiente e faz parte do markdown, independente de um link para imagens externas. Imagens complexas, como fotos, ainda precisam do armazanamento em formato raster.
<svg
xmlns="http://www.w3.org/2000/svg"
width="142px"
height="23px"
fill="none"
>
<foreignObject width="142px" height="23px">
<div xmlns="http://www.w3.org/1999/xhtml">
<style>
.pill{
display: flex;
background-color: transparent;
width: max-content;
font-family: 'Open Sans', sans-serif;
border-radius: 4px;
}
.pillLabel{
display: flex;
width: max-content;
padding: 4px;
padding-left: 8px;
padding-right: 8px;
border-top-left-radius: 4px;
border-bottom-left-radius: 4px;
font-size: 12px;
color: rgb(254 215 170);
background-color: rgb(136 19 55);
}
.pillIcon{
margin-right: 4px;
width: 14px;
height: 14px;
}
.pillCount{
color: rgb(136 19 55);
background-color: rgb(254 215 170);
width: max-content;
border-top-right-radius: 4px;
border-bottom-right-radius: 4px;
padding: 4px;
padding-left: 8px;
padding-right: 8px;
letter-spacing: 1px;
font-size: 12px;
}
@keyframes heartbeat {
0% {
transform: scale(1);
}
25% {
transform: scale(1.1);
}
40% {
transform: scale(1);
}
60% {
transform: scale(1.1);
}
100% {
transform: scale(1);
}
}
.heartbeat {
display: inline-block;
animation: heartbeat 1.5s infinite;
transform-origin: center;
image-rendering: -webkit-optimize-contrast;
image-rendering: crisp-edges;
backface-visibility: hidden;
will-change: transform;
}
</style>
<div class="pill">
<span class="pillLabel">
<svg xmlns="http://www.w3.org/2000/svg" class="pillIcon heartbeat" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path name="bar" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 19v-6a2 2 0 00-2-2H5a2 2 0 00-2 2v6a2 2 0 002 2h2a2 2 0 002-2zm0 0V9a2 2 0 012-2h2a2 2 0 012 2v10m-6 0a2 2 0 002 2h2a2 2 0 002-2m0 0V5a2 2 0 012-2h2a2 2 0 012 2v14a2 2 0 01-2 2h-2a2 2 0 01-2-2z" />
</svg>
Profile Views</span>
<span class="pillCount" > 42 </span>
</div>
</div>
</foreignObject>
</svg>
RASCUNHO - É possível se livrar dos webcrawlers?
Conteúdo para ser publicado em breve.
Diferentes publicações apresentam procedimento de como baixar o conteúdo estático de um website por completo, usando recursos disponíveis na linha de comando Linux como wget
, curl
entre outras possíveis opções programadas em Python, Perl etc.
Detalhes
user_agent="Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/129.0.0.0 Safari/537.36"
wget --verbose --mirror --no-parent --continue --page-requisites \
--adjust-extension --convert-links --no-clobber --timestamping \
--server-response --limit-rate=10k --wait=10 --random-wait \
--no-cache --user-agent="${user_agent}" --no-check-certificate <website.address>
Mas existe alguma maneira de se defender dessa prática quando a mesma se torna nociva para o servidor, aumentando a carga para um propósito realizado por não-humanos? Contratar um proxy que implemente desafios (CAPTCHA) pode ser uma solução.
Mas será que é possível criar uma solução independente de proxy? E se a página web fosse dinâmica, ou seja, montada em tempo de carga usando somente javascript e uma conexão via websocket seguro com o servidor (nos códigos seguintes é ws
em vez de wss
)? Por meio do websocket o Javascript obtém o conteúdo a ser montado na página no lado do cliente. Tais recursos dinâmicos ainda não são interpretados pelos crawlers
burros.
Esta ideia é possível e o fluxo básico para realizar isso envolve os seguintes passos:
1. Conexão WebSocket com o Servidor
A primeira etapa é estabelecer uma conexão WebSocket com o servidor. O WebSocket permite uma comunicação bidirecional em tempo real, ideal para atualizar e carregar dados dinâmicos.
const socket = new WebSocket('ws://servidor.com:porta');
// Quando a conexão é aberta
socket.onopen = function(event) {
console.log("Conectado ao servidor via WebSocket.");
socket.send("Solicitando dados para a página");
};
// Quando uma mensagem é recebida do servidor
socket.onmessage = function(event) {
const data = JSON.parse(event.data);
montarPagina(data);
};
// Tratamento de erros
socket.onerror = function(error) {
console.log("Erro na conexão WebSocket:", error);
};
// Quando a conexão é fechada
socket.onclose = function(event) {
console.log("Conexão WebSocket fechada.");
};
2. Recebendo o Conteúdo
Quando o servidor envia os dados, eles podem estar no formato JSON (ou outro formato estruturado). Ao receber os dados, o JavaScript no lado do cliente pode processar e montar o conteúdo da página dinamicamente.
3. Construção da Página no Lado do Cliente
Uma vez que os dados são recebidos, você pode manipulá-los e gerar o conteúdo da página dinamicamente usando DOM (Document Object Model) ou técnicas como innerHTML.
Exemplo simples de código:
function montarPagina(data) {
const body = document.body;
// Criar elementos de acordo com os dados recebidos
const titulo = document.createElement('h1');
titulo.textContent = data.titulo;
const conteudo = document.createElement('p');
conteudo.textContent = data.conteudo;
// Adicionar os elementos na página
body.appendChild(titulo);
body.appendChild(conteudo);
}
4. Servidor WebSocket
Do lado do servidor, você precisa configurar um serviço WebSocket que envie os dados requisitados ao cliente. O servidor deve manter a conexão aberta enquanto for necessário para enviar novos dados dinamicamente ou quando solicitado.
Um exemplo básico de servidor WebSocket em Node.js:
const WebSocket = require('ws');
const wss = new WebSocket.Server({ port: 8080 });
wss.on('connection', (ws) => {
console.log('Cliente conectado');
ws.on('message', (message) => {
console.log('Mensagem recebida: %s', message);
const dadosPagina = {
titulo: "Bem-vindo à minha página!",
conteudo: "Este conteúdo foi carregado dinamicamente via WebSocket."
};
ws.send(JSON.stringify(dadosPagina));
});
ws.on('close', () => {
console.log('Cliente desconectado');
});
});
Benefícios:
- Atualização em tempo real: O WebSocket permite que o servidor envie atualizações em tempo real ao cliente sem a necessidade de recarregar a página.
- Eficiência: Reduz a sobrecarga de requisições HTTP/HTTPS repetidas, já que a conexão WebSocket permanece aberta.
- Experiência do usuário: O conteúdo pode ser carregado e atualizado dinamicamente conforme necessário.
Desafios:
- Gestão de estados e reconexão: É necessário garantir que o cliente possa lidar com a desconexão e reconectar caso a comunicação falhe.
- Segurança: A comunicação via WebSocket deve ser protegida para evitar ataques como Man-in-the-Middle (usando WSS em vez de WS).
Essa abordagem é útil para aplicações em tempo real ou dinâmicas, como sistemas de votação, chat ou dashboards de monitoramento em tempo real. Por ser um conteúdo dinâmico, os crawlers burros não conseguirão baixar o conteúdo, mas apenas a página principal contendo o mínimo, básico para que o navegador (Chrome, Firefox, Opera etc.) consiga iniciar a carga e montagem da página dinamicamente.
[Keywords: crawler, defeat, dynamic page, javascript, websocket] // for [index|filter]ing purposes
RASCUNHO: WhatsApp Web com nova interface
Na última quarta-feira (), ao abrir o WhatsApp Web, notei uma nova janela de pareamento. Será uma novidade ou um ataque man in middle?
Caso alguém também notou essa nova janela e possa compartilhar a experiência, enriquecerá esse achado.