summaryrefslogtreecommitdiffstats
path: root/pt-br/news/phase4-wasm-browser-verification/index.html
blob: da4605b77a9cd2ccf3239dc301f93ad792ec05b7 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
<!DOCTYPE html>
<html lang="pt-br">
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>Fase 4: Verificar Sem Instalar Nada — Tesseras</title>
    <meta name="description" content="Tesseras agora compila para WebAssembly — qualquer pessoa pode verificar integridade e autenticidade de uma tessera diretamente no navegador, sem instalar nenhum software.">
    <!-- Open Graph -->
    <meta property="og:type" content="article">
    <meta property="og:title" content="Fase 4: Verificar Sem Instalar Nada">
    <meta property="og:description" content="Tesseras agora compila para WebAssembly — qualquer pessoa pode verificar integridade e autenticidade de uma tessera diretamente no navegador, sem instalar nenhum software.">
    <meta property="og:image" content="https://tesseras.net/images/social.jpg">
    <meta property="og:image:width" content="1200">
    <meta property="og:image:height" content="630">
    <meta property="og:site_name" content="Tesseras">
    <!-- Twitter Card -->
    <meta name="twitter:card" content="summary_large_image">
    <meta name="twitter:title" content="Fase 4: Verificar Sem Instalar Nada">
    <meta name="twitter:description" content="Tesseras agora compila para WebAssembly — qualquer pessoa pode verificar integridade e autenticidade de uma tessera diretamente no navegador, sem instalar nenhum software.">
    <meta name="twitter:image" content="https://tesseras.net/images/social.jpg">
    <link rel="stylesheet" href="https://tesseras.net/style.css?h=21f0f32121928ee5c690">
    
        
            <link rel="alternate" type="application/atom+xml" title="Tesseras" href="https://tesseras.net/atom.xml">
        
    
    <link rel="icon" type="image/png" sizes="32x32" href="https://tesseras.net/images/favicon.png?h=be4e123a23393b1a027d">
    
</head>
<body>
    <header>
        <h1>
            <a href="https:&#x2F;&#x2F;tesseras.net/pt-br/">
                <img src="https://tesseras.net/images/logo-64.png?h=c1b8d0c4c5f93b49d40b" alt="Tesseras" width="40" height="40" class="logo">
                Tesseras
            </a>
        </h1>
        <nav>
            
                <a href="https://tesseras.net/pt-br/about/">Sobre</a>
                <a href="https://tesseras.net/pt-br/news/">Notícias</a>
                <a href="https://tesseras.net/pt-br/releases/">Lançamentos</a>
                <a href="https://tesseras.net/pt-br/faq/">FAQ</a>
                <a href="https://tesseras.net/pt-br/subscriptions/">Inscrições</a>
                <a href="https://tesseras.net/pt-br/contact/">Contato</a>
            
        </nav>
        <nav class="lang-switch">
            
                <a href="https:&#x2F;&#x2F;tesseras.net&#x2F;news&#x2F;phase4-wasm-browser-verification&#x2F;">English</a> | <strong>Português</strong>
            
        </nav>
    </header>

    <main>
        
<article>
    <h2>Fase 4: Verificar Sem Instalar Nada</h2>
    <p class="news-date">2026-02-15</p>
    <p>Confiança não deveria exigir instalação de software. Se alguém te envia uma
tessera — um pacote de memórias preservadas — você deveria poder verificar que é
genuína e não foi modificada sem baixar um app, criar uma conta, ou confiar em
um servidor. É isso que o <code>tesseras-wasm</code> entrega: arraste um arquivo tessera
para uma página web, e a verificação criptográfica acontece inteiramente no seu
navegador.</p>
<h2 id="o-que-foi-construido">O que foi construído</h2>
<p><strong>tesseras-wasm</strong> — Um crate Rust que compila para WebAssembly via wasm-pack,
expondo quatro funções stateless para JavaScript. O crate depende do
<code>tesseras-core</code> para parsing do manifesto e chama primitivas criptográficas
diretamente (blake3, ed25519-dalek) ao invés de depender do <code>tesseras-crypto</code>,
que puxa bibliotecas pós-quânticas baseadas em C que não compilam para
<code>wasm32-unknown-unknown</code>.</p>
<p><code>parse_manifest</code> recebe os bytes brutos do MANIFEST (texto UTF-8 plano, não
MessagePack), delega para <code>tesseras_core::manifest::Manifest::parse()</code>, e
retorna uma string JSON com a chave pública Ed25519 do criador, caminhos dos
arquivos de assinatura, e uma lista de arquivos com seus hashes BLAKE3
esperados, tamanhos e tipos MIME. Structs internas (<code>ManifestJson</code>,
<code>CreatorPubkey</code>, <code>SignatureFiles</code>, <code>FileEntry</code>) são serializadas com serde_json.
Os campos de chave pública ML-DSA e arquivo de assinatura estão presentes no
contrato JSON mas definidos como <code>null</code> — prontos para quando a assinatura
pós-quântica for implementada no lado nativo.</p>
<p><code>hash_blake3</code> computa um hash BLAKE3 de bytes arbitrários e retorna uma string
hexadecimal de 64 caracteres. É chamada uma vez por arquivo na tessera para
verificar integridade contra o MANIFEST.</p>
<p><code>verify_ed25519</code> recebe uma mensagem, uma assinatura de 64 bytes e uma chave
pública de 32 bytes, constrói uma <code>ed25519_dalek::VerifyingKey</code>, e retorna se a
assinatura é válida. A validação de comprimento retorna erros descritivos
("Ed25519 public key must be 32 bytes") ao invés de causar panic.</p>
<p><code>verify_ml_dsa</code> é um stub que retorna um erro explicando que verificação ML-DSA
ainda não está disponível. Isso é deliberado: o crate <code>ml-dsa</code> no crates.io está
na v0.1.0-rc.7 (pré-release), e o <code>tesseras-crypto</code> usa <code>pqcrypto-dilithium</code>
(CRYSTALS-Dilithium baseado em C) que é incompatível em nível de bytes com FIPS
204 ML-DSA. Ambos os lados precisam usar a mesma implementação em Rust puro
antes que a verificação cruzada funcione. Verificação Ed25519 é suficiente —
toda tessera é assinada com Ed25519.</p>
<p>Todas as quatro funções usam um padrão de duas camadas para testabilidade:
funções internas retornam <code>Result&lt;T, String&gt;</code> e são testadas nativamente,
enquanto wrappers finos <code>#[wasm_bindgen]</code> convertem erros para <code>JsError</code>. Isso
evita que <code>JsError::new()</code> cause panic em targets não-WASM durante os testes.</p>
<p>O binário WASM compilado tem 109 KB bruto e 44 KB com gzip — bem abaixo do
orçamento de 200 KB. O wasm-opt aplica otimização <code>-Oz</code> após o wasm-pack
compilar com <code>opt-level = "z"</code>, LTO e uma única unidade de codegen.</p>
<p><strong>@tesseras/verify</strong> — Um pacote npm TypeScript (<code>crates/tesseras-wasm/js/</code>) que
orquestra a verificação no lado do navegador. A API pública é uma única função:</p>
<pre><code data-lang="typescript">async function verifyTessera(
  archive: Uint8Array,
  onProgress?: (current: number, total: number, file: string) =&gt; void
): Promise&lt;VerificationResult&gt;
</code></pre>
<p>O tipo <code>VerificationResult</code> fornece tudo que uma UI precisa: validade geral,
hash da tessera, chaves públicas do criador, status das assinaturas
(valid/invalid/missing para Ed25519 e ML-DSA), resultados de integridade por
arquivo com hashes esperados e reais, uma lista de arquivos inesperados não
presentes no MANIFEST, e um array de erros.</p>
<p>A descompactação de arquivos (<code>unpack.ts</code>) lida com três formatos: tar
comprimido com gzip (detectado pelos magic bytes <code>\x1f\x8b</code>, descomprimido com
fflate e depois parseado como tar), ZIP (magic <code>PK\x03\x04</code>, descompactado com
<code>unzipSync</code> do fflate), e tar bruto (<code>ustar</code> no offset 257). Uma função
<code>normalizePath</code> remove o prefixo <code>tessera-&lt;hash&gt;/</code> para que os caminhos internos
correspondam às entradas do MANIFEST.</p>
<p>A verificação roda em um Web Worker (<code>worker.ts</code>) para manter a thread da UI
responsiva. O worker inicializa o módulo WASM, descompacta o arquivo, parseia o
MANIFEST, verifica a assinatura Ed25519 contra a chave pública do criador,
depois faz hash de cada arquivo com BLAKE3 e compara com os valores esperados.
Mensagens de progresso são transmitidas de volta para a thread principal após
cada arquivo. Se qualquer assinatura é inválida, a verificação para
imediatamente sem fazer hash dos arquivos — falhando rápido na verificação mais
crítica.</p>
<p>O arquivo é transferido para o worker com zero-copy
(<code>worker.postMessage({ type: "verify", archive }, [archive.buffer])</code>) para
evitar duplicar arquivos de tessera potencialmente grandes na memória.</p>
<p><strong>Pipeline de build</strong> — Três novos targets no justfile: <code>wasm-build</code> executa
wasm-pack com <code>--target web --release</code> e otimiza com wasm-opt; <code>wasm-size</code>
reporta o tamanho do binário bruto e com gzip; <code>test-wasm</code> executa a suíte de
testes nativos.</p>
<p><strong>Testes</strong> — 9 testes unitários nativos cobrem hashing BLAKE3 (entrada vazia,
valor conhecido), verificação Ed25519 (assinatura válida, assinatura inválida,
chave errada, comprimento de chave inválido), e parsing do MANIFEST (manifesto
válido, UTF-8 inválido, lixo). 3 testes de integração WASM rodam em Chrome
headless via <code>wasm-pack test --headless --chrome</code>, verificando que
<code>hash_blake3</code>, <code>verify_ed25519</code> e <code>parse_manifest</code> funcionam corretamente quando
compilados para <code>wasm32-unknown-unknown</code>.</p>
<h2 id="decisoes-de-arquitetura">Decisões de arquitetura</h2>
<ul>
<li><strong>Sem dependência do tesseras-crypto</strong>: o crate WASM chama blake3 e
ed25519-dalek diretamente. O <code>tesseras-crypto</code> depende do <code>pqcrypto-kyber</code>
(ML-KEM baseado em C via pqcrypto-traits) que requer um toolchain de
compilador C e não tem target wasm32. Dependendo apenas de crates Rust puros,
o build WASM tem zero dependências C e compila sem problemas para WebAssembly.</li>
<li><strong>ML-DSA adiado, não fingido</strong>: ao invés de silenciosamente pular a
verificação pós-quântica, o stub retorna um erro explícito. Isso garante que
se uma tessera contiver uma assinatura ML-DSA, o resultado da verificação
reportará <code>ml_dsa: "missing"</code> ao invés de fingir que foi verificada. O
orquestrador JS lida com isso graciosamente — uma tessera é válida se Ed25519
passar e ML-DSA estiver ausente (ainda não implementado em nenhum dos lados).</li>
<li><strong>Padrão de função interna</strong>: <code>JsError</code> não pode ser construído em targets
não-WASM (causa panic). Dividir cada função em
<code>foo_inner() -&gt; Result&lt;T, String&gt;</code> e <code>foo() -&gt; Result&lt;T, JsError&gt;</code> permite que
a suíte de testes nativa exercite toda a lógica sem tocar em tipos JavaScript.
Os testes de integração WASM em Chrome headless testam a superfície completa
do <code>#[wasm_bindgen]</code>.</li>
<li><strong>Isolamento em Web Worker</strong>: operações criptográficas (especialmente BLAKE3
sobre arquivos de mídia grandes) podem levar centenas de milissegundos. Rodar
em um Worker previne travamentos na UI. O protocolo de progresso com streaming
(<code>{ type: "progress", current, total, file }</code>) permite que a UI mostre uma
barra de progresso durante a verificação de tesseras com muitos arquivos.</li>
<li><strong>Transferência zero-copy</strong>: <code>archive.buffer</code> é transferido para o Worker, não
copiado. Para um arquivo tessera de 50 MB, isso evita dobrar o uso de memória
durante a verificação.</li>
<li><strong>MANIFEST em texto plano, não MessagePack</strong>: o crate WASM parseia o mesmo
formato de MANIFEST em texto plano que o CLI. Isso é por design — o MANIFEST é
a Pedra de Rosetta da tessera, legível por qualquer pessoa com um editor de
texto. A dependência <code>rmp-serde</code> no Cargo.toml não é usada e será removida.</li>
</ul>
<h2 id="o-que-vem-a-seguir">O que vem a seguir</h2>
<ul>
<li><strong>Fase 4: Resiliência e Escala</strong> — Empacotamento para sistemas operacionais
(Alpine, Arch, Debian, FreeBSD, OpenBSD), CI no SourceHut e GitHub Actions,
auditorias de segurança, explorador de tesseras no navegador em tesseras.net
usando @tesseras/verify</li>
<li><strong>Fase 5: Exploração e Cultura</strong> — Navegador público de tesseras por
era/localização/tema/idioma, curadoria institucional, integração com
genealogia, exportação para mídia física (M-DISC, microfilme, papel livre de
ácido com QR)</li>
</ul>
<p>A verificação não exige mais confiança em software. Um arquivo tessera arrastado
para um navegador é verificado com o mesmo rigor criptográfico do CLI — mesmos
hashes BLAKE3, mesmas assinaturas Ed25519, mesmo parser de MANIFEST. A diferença
é que agora qualquer pessoa pode fazer isso.</p>

</article>

    </main>

    <footer>
        <p>&copy; 2026 Tesseras Project. <a href="/atom.xml">News Feed</a> · <a href="https://git.sr.ht/~ijanc/tesseras">Source</a></p>
    </footer>
</body>
</html>