TesserasRede P2P para preservar memórias humanas através dos milêniosZola2026-02-16T10:00:00+00:00https://tesseras.net/pt-br/atom.xmlEmpacotando o Tesseras para Debian2026-02-16T10:00:00+00:002026-02-16T10:00:00+00:00
Unknown
https://tesseras.net/pt-br/news/packaging-debian/<p>O Tesseras agora inclui um pacote <code>.deb</code> para Debian e Ubuntu. Este post explica
como compilar e instalar o pacote a partir do código-fonte usando <code>cargo-deb</code>.</p>
<h2 id="pre-requisitos">Pré-requisitos</h2>
<p>Você precisa de uma toolchain Rust funcional e das bibliotecas de sistema
necessárias:</p>
<pre><code data-lang="sh">sudo apt install build-essential pkg-config libsqlite3-dev
rustup toolchain install stable
cargo install cargo-deb
</code></pre>
<h2 id="compilando">Compilando</h2>
<p>Clone o repositório e execute a recipe <code>just deb</code>:</p>
<pre><code data-lang="sh">git clone https://git.sr.ht/~ijanc/tesseras
cd tesseras
just deb
</code></pre>
<p>Essa recipe faz três coisas:</p>
<ol>
<li><strong>Compila</strong> <code>tesd</code> (o daemon) e <code>tes</code> (o CLI) em modo release com
<code>cargo build --release</code></li>
<li><strong>Gera completions de shell</strong> para bash, zsh e fish a partir do binário <code>tes</code></li>
<li><strong>Empacota</strong> tudo em um arquivo <code>.deb</code> com
<code>cargo deb -p tesseras-daemon --no-build</code></li>
</ol>
<p>O resultado é um arquivo <code>.deb</code> em <code>target/debian/</code>.</p>
<h2 id="instalando">Instalando</h2>
<pre><code data-lang="sh">sudo dpkg -i target/debian/tesseras-daemon_*.deb
</code></pre>
<p>Se houver dependências faltando, corrija com:</p>
<pre><code data-lang="sh">sudo apt install -f
</code></pre>
<h2 id="configuracao-pos-instalacao">Configuração pós-instalação</h2>
<p>O script <code>postinst</code> cria automaticamente um usuário de sistema <code>tesseras</code> e o
diretório de dados <code>/var/lib/tesseras</code>. Para usar o CLI sem sudo, adicione seu
usuário ao grupo:</p>
<pre><code data-lang="sh">sudo usermod -aG tesseras $USER
</code></pre>
<p>Faça logout e login novamente, depois inicie o daemon:</p>
<pre><code data-lang="sh">sudo systemctl enable --now tesd
</code></pre>
<h2 id="o-que-o-pacote-inclui">O que o pacote inclui</h2>
<table><thead><tr><th>Caminho</th><th>Descrição</th></tr></thead><tbody>
<tr><td><code>/usr/bin/tesd</code></td><td>Daemon do nó completo</td></tr>
<tr><td><code>/usr/bin/tes</code></td><td>Cliente CLI</td></tr>
<tr><td><code>/etc/tesseras/config.toml</code></td><td>Configuração padrão (marcado como conffile)</td></tr>
<tr><td><code>/lib/systemd/system/tesd.service</code></td><td>Unit systemd com hardening de segurança</td></tr>
<tr><td>Completions de shell</td><td>bash, zsh e fish</td></tr>
</tbody></table>
<h2 id="como-o-cargo-deb-funciona">Como o cargo-deb funciona</h2>
<p>Os metadados de empacotamento ficam em <code>crates/tesseras-daemon/Cargo.toml</code> na
seção <code>[package.metadata.deb]</code>. Essa seção define:</p>
<ul>
<li><strong>depends</strong> — dependências em tempo de execução: <code>libc6</code> e <code>libsqlite3-0</code></li>
<li><strong>assets</strong> — arquivos incluídos no pacote (binários, config, unit systemd,
completions de shell)</li>
<li><strong>conf-files</strong> — arquivos tratados como configuração (preservados na
atualização)</li>
<li><strong>maintainer-scripts</strong> — scripts <code>postinst</code> e <code>postrm</code> em
<code>packaging/debian/scripts/</code></li>
<li><strong>systemd-units</strong> — integração automática com systemd</li>
</ul>
<p>O script <code>postinst</code> cria o usuário de sistema <code>tesseras</code> e o diretório de dados
na instalação. O script <code>postrm</code> remove o usuário, grupo e diretório de dados
apenas no <code>purge</code> (não na remoção simples).</p>
<h2 id="hardening-do-systemd">Hardening do systemd</h2>
<p>A unit <code>tesd.service</code> inclui diretivas de hardening de segurança:</p>
<pre><code data-lang="ini">NoNewPrivileges=true
ProtectSystem=strict
ProtectHome=true
ReadWritePaths=/var/lib/tesseras
PrivateTmp=true
PrivateDevices=true
ProtectKernelTunables=true
ProtectControlGroups=true
RestrictSUIDSGID=true
MemoryDenyWriteExecute=true
</code></pre>
<p>O daemon roda como o usuário não-privilegiado <code>tesseras</code> e só pode escrever em
<code>/var/lib/tesseras</code>.</p>
<h2 id="deploy-para-um-servidor-remoto">Deploy para um servidor remoto</h2>
<p>O justfile inclui uma recipe <code>deploy</code> para enviar o <code>.deb</code> a um host remoto:</p>
<pre><code data-lang="sh">just deploy bootstrap1.tesseras.net
</code></pre>
<p>Isso compila o <code>.deb</code>, copia via <code>scp</code>, instala com <code>dpkg -i</code> e reinicia o
serviço <code>tesd</code>.</p>
<h2 id="atualizando">Atualizando</h2>
<p>Depois de baixar novas mudanças, basta rodar <code>just deb</code> novamente e reinstalar:</p>
<pre><code data-lang="sh">git pull
just deb
sudo dpkg -i target/debian/tesseras-daemon_*.deb
</code></pre>
Empacotando o Tesseras para Arch Linux2026-02-16T09:00:00+00:002026-02-16T09:00:00+00:00
Unknown
https://tesseras.net/pt-br/news/packaging-archlinux/<p>O Tesseras agora inclui um PKGBUILD para Arch Linux. Este post explica como
compilar e instalar o pacote a partir do código-fonte.</p>
<h2 id="pre-requisitos">Pré-requisitos</h2>
<p>Você precisa de uma toolchain Rust funcional e do grupo base-devel:</p>
<pre><code data-lang="sh">sudo pacman -S --needed base-devel sqlite
rustup toolchain install stable
</code></pre>
<h2 id="compilando">Compilando</h2>
<p>Clone o repositório e execute a recipe <code>just arch</code>:</p>
<pre><code data-lang="sh">git clone https://git.sr.ht/~ijanc/tesseras
cd tesseras
just arch
</code></pre>
<p>Isso executa <code>makepkg -sf</code> dentro de <code>packaging/archlinux/</code>, que:</p>
<ol>
<li><strong>prepare</strong> — baixa as dependências Cargo com <code>cargo fetch --locked</code></li>
<li><strong>build</strong> — compila <code>tesd</code> e <code>tes</code> (o CLI) em modo release</li>
<li><strong>package</strong> — instala binários, serviço systemd, configs sysusers/tmpfiles,
completions de shell (bash, zsh, fish) e um arquivo de configuração padrão</li>
</ol>
<p>O resultado é um arquivo <code>.pkg.tar.zst</code> em <code>packaging/archlinux/</code>.</p>
<h2 id="instalando">Instalando</h2>
<pre><code data-lang="sh">sudo pacman -U packaging/archlinux/tesseras-*.pkg.tar.zst
</code></pre>
<h2 id="configuracao-pos-instalacao">Configuração pós-instalação</h2>
<p>O pacote cria automaticamente um usuário e grupo de sistema <code>tesseras</code> via
systemd-sysusers. Para usar o CLI sem sudo, adicione seu usuário ao grupo:</p>
<pre><code data-lang="sh">sudo usermod -aG tesseras $USER
</code></pre>
<p>Faça logout e login novamente, depois inicie o daemon:</p>
<pre><code data-lang="sh">sudo systemctl enable --now tesd
</code></pre>
<h2 id="o-que-o-pacote-inclui">O que o pacote inclui</h2>
<table><thead><tr><th>Caminho</th><th>Descrição</th></tr></thead><tbody>
<tr><td><code>/usr/bin/tesd</code></td><td>Daemon do nó completo</td></tr>
<tr><td><code>/usr/bin/tes</code></td><td>Cliente CLI</td></tr>
<tr><td><code>/etc/tesseras/config.toml</code></td><td>Configuração padrão (marcado como backup)</td></tr>
<tr><td><code>/usr/lib/systemd/system/tesd.service</code></td><td>Unit systemd com hardening de segurança</td></tr>
<tr><td><code>/usr/lib/sysusers.d/tesseras.conf</code></td><td>Definição do usuário de sistema</td></tr>
<tr><td><code>/usr/lib/tmpfiles.d/tesseras.conf</code></td><td>Diretório de dados <code>/var/lib/tesseras</code></td></tr>
<tr><td>Completions de shell</td><td>bash, zsh e fish</td></tr>
</tbody></table>
<h2 id="detalhes-do-pkgbuild">Detalhes do PKGBUILD</h2>
<p>O PKGBUILD compila diretamente a partir do checkout git local em vez de baixar
um tarball. A variável de ambiente <code>TESSERAS_ROOT</code> aponta o makepkg para a raiz
do workspace. O diretório target do Cargo é configurado para <code>$srcdir/target</code>
para manter os artefatos de build dentro do sandbox do makepkg.</p>
<p>O pacote depende apenas de <code>sqlite</code> em tempo de execução e <code>cargo</code> em tempo de
build.</p>
<h2 id="atualizando">Atualizando</h2>
<p>Depois de baixar novas mudanças, basta rodar <code>just arch</code> novamente e reinstalar:</p>
<pre><code data-lang="sh">git pull
just arch
sudo pacman -U packaging/archlinux/tesseras-*.pkg.tar.zst
</code></pre>
Fase 4: Deduplicacao de Armazenamento2026-02-15T23:00:00+00:002026-02-15T23:00:00+00:00
Unknown
https://tesseras.net/pt-br/news/phase4-storage-deduplication/<p>Quando multiplas tesseras compartilham a mesma foto, o mesmo clipe de audio ou
os mesmos dados de fragmento, a camada de armazenamento antiga mantinha copias
separadas de cada. Em um no armazenando milhares de tesseras para a rede, essa
duplicacao se acumula rapidamente. A Fase 4 continua com deduplicacao de
armazenamento: um armazenamento enderecavel por conteudo (CAS) que garante que
cada dado unico seja armazenado exatamente uma vez em disco, independentemente
de quantas tesseras o referenciam.</p>
<p>O design e simples e comprovado: hash do conteudo com BLAKE3, usar o hash como
nome do arquivo e manter uma contagem de referencias no SQLite. Quando duas
tesseras incluem a mesma foto de 5 MB, um arquivo existe em disco com
refcount 2. Quando uma tessera e deletada, o refcount cai para 1 e o arquivo
permanece. Quando a ultima referencia e liberada, uma varredura periodica limpa
o orfao.</p>
<h2 id="o-que-foi-construido">O que foi construido</h2>
<p><strong>Migracao do esquema CAS</strong> (<code>tesseras-storage/migrations/004_dedup.sql</code>) — Tres
novas tabelas:</p>
<ul>
<li><code>cas_objects</code> — rastreia cada objeto no armazenamento: hash BLAKE3 (chave
primaria), tamanho em bytes, contagem de referencias e timestamp de criacao</li>
<li><code>blob_refs</code> — mapeia identificadores logicos de blobs (hash da tessera + hash
da memoria + nome do arquivo) para hashes CAS, substituindo a convencao antiga
de caminhos no sistema de arquivos</li>
<li><code>fragment_refs</code> — mapeia identificadores logicos de fragmentos (hash da
tessera + indice do fragmento) para hashes CAS, substituindo o antigo layout
do diretorio <code>fragments/</code></li>
</ul>
<p>Indices nas colunas de hash garantem lookups O(1) durante leituras e contagem de
referencias.</p>
<p><strong>CasStore</strong> (<code>tesseras-storage/src/cas.rs</code>) — O motor central de armazenamento
enderecavel por conteudo. Arquivos sao armazenados sob um diretorio de prefixo
de dois niveis: <code><raiz>/<prefixo-hex-2-chars>/<hash-completo>.blob</code>. O
armazenamento fornece cinco operacoes:</p>
<ul>
<li><code>put(hash, data)</code> — escreve dados em disco se ainda nao presente, incrementa o
refcount. Retorna se ocorreu um hit de deduplicacao.</li>
<li><code>get(hash)</code> — le dados do disco pelo hash</li>
<li><code>release(hash)</code> — decrementa o refcount. Se chegar a zero, o arquivo em disco
e deletado imediatamente.</li>
<li><code>contains(hash)</code> — verifica existencia sem ler</li>
<li><code>ref_count(hash)</code> — retorna a contagem de referencias atual</li>
</ul>
<p>Todas as operacoes sao atomicas dentro de uma unica transacao SQLite. O refcount
e a fonte de verdade — se o refcount diz que o objeto existe, o arquivo deve
estar em disco.</p>
<p><strong>FsBlobStore com CAS</strong> (<code>tesseras-storage/src/blob.rs</code>) — Reescrito para
delegar todo armazenamento ao CAS. Quando um blob e escrito, seu hash BLAKE3 e
computado e passado para <code>cas.put()</code>. Uma linha em <code>blob_refs</code> mapeia o caminho
logico (tessera + memoria + arquivo) para o hash CAS. Leituras buscam o hash CAS
via <code>blob_refs</code> e leem de <code>cas.get()</code>. Deletar uma tessera libera todas as suas
referencias de blob em uma unica transacao.</p>
<p><strong>FsFragmentStore com CAS</strong> (<code>tesseras-storage/src/fragment.rs</code>) — Mesmo padrao
para fragmentos codificados com erasure coding. O checksum BLAKE3 de cada
fragmento ja e computado durante a codificacao Reed-Solomon, entao e usado
diretamente como chave CAS. A verificacao de fragmentos agora checa o hash CAS
ao inves de recomputar do zero — se o CAS diz que os dados estao intactos,
estao.</p>
<p><strong>Coletor de lixo sweep</strong> (<code>cas.rs:sweep()</code>) — Uma passagem periodica de GC que
trata tres casos limite que o caminho normal de refcount nao consegue:</p>
<ol>
<li><strong>Arquivos orfaos</strong> — arquivos em disco sem linha correspondente em
<code>cas_objects</code>. Pode acontecer apos um crash durante escrita. Arquivos com
menos de 1 hora sao pulados (periodo de graca para escritas em andamento);
orfaos mais antigos sao deletados.</li>
<li><strong>Refcounts vazados</strong> — linhas em <code>cas_objects</code> com refcount zero que nao
foram limpas (ex: se o processo morreu entre decrementar e deletar). Essas
linhas sao removidas.</li>
<li><strong>Idempotente</strong> — executar sweep duas vezes produz o mesmo resultado.</li>
</ol>
<p>O sweep e conectado ao loop de reparo existente em <code>tesseras-replication</code>, entao
roda automaticamente a cada 24 horas junto com as verificacoes de saude dos
fragmentos.</p>
<p><strong>Migracao do layout antigo</strong> (<code>tesseras-storage/src/migration.rs</code>) — Uma
estrategia de migracao copy-first que move dados do layout antigo baseado em
diretorios (<code>blobs/<tessera>/<memoria>/<arquivo></code> e
<code>fragments/<tessera>/<indice>.shard</code>) para o CAS. A migracao:</p>
<ol>
<li>Verifica a versao de armazenamento em <code>storage_meta</code> (versao 1 = layout
antigo, versao 2 = CAS)</li>
<li>Percorre os diretorios antigos <code>blobs/</code> e <code>fragments/</code></li>
<li>Computa hashes BLAKE3 e insere no CAS via <code>put()</code> — duplicatas sao
automaticamente deduplicadas</li>
<li>Cria entradas correspondentes em <code>blob_refs</code> / <code>fragment_refs</code></li>
<li>Remove diretorios antigos somente apos todos os dados estarem seguros no CAS</li>
<li>Atualiza a versao de armazenamento para 2</li>
</ol>
<p>A migracao roda na inicializacao do daemon, e idempotente (segura para
re-executar) e reporta estatisticas: arquivos migrados, duplicatas encontradas,
bytes economizados.</p>
<p><strong>Metricas Prometheus</strong> (<code>tesseras-storage/src/metrics.rs</code>) — Dez novas metricas
para observabilidade:</p>
<table><thead><tr><th>Metrica</th><th>Descricao</th></tr></thead><tbody>
<tr><td><code>cas_objects_total</code></td><td>Total de objetos unicos no CAS</td></tr>
<tr><td><code>cas_bytes_total</code></td><td>Total de bytes armazenados</td></tr>
<tr><td><code>cas_dedup_hits_total</code></td><td>Numero de escritas que encontraram um objeto existente</td></tr>
<tr><td><code>cas_bytes_saved_total</code></td><td>Bytes economizados por deduplicacao</td></tr>
<tr><td><code>cas_gc_refcount_deletions_total</code></td><td>Objetos deletados quando refcount chegou a zero</td></tr>
<tr><td><code>cas_gc_sweep_orphans_cleaned_total</code></td><td>Arquivos orfaos removidos pelo sweep</td></tr>
<tr><td><code>cas_gc_sweep_leaked_refs_cleaned_total</code></td><td>Linhas de refcount vazadas limpas</td></tr>
<tr><td><code>cas_gc_sweep_skipped_young_total</code></td><td>Orfaos jovens pulados (periodo de graca)</td></tr>
<tr><td><code>cas_gc_sweep_duration_seconds</code></td><td>Tempo gasto no sweep GC</td></tr>
</tbody></table>
<p><strong>Testes baseados em propriedades</strong> — Dois testes proptest verificam invariantes
do CAS sob entradas aleatorias:</p>
<ul>
<li><code>refcount_matches_actual_refs</code> — apos N operacoes aleatorias de put/release, o
refcount sempre corresponde ao numero real de referencias pendentes</li>
<li><code>cas_path_is_deterministic</code> — o mesmo hash sempre produz o mesmo caminho no
sistema de arquivos</li>
</ul>
<p><strong>Atualizacao de testes de integracao</strong> — Todos os testes de integracao em
<code>tesseras-core</code>, <code>tesseras-replication</code>, <code>tesseras-embedded</code> e <code>tesseras-cli</code>
atualizados para os novos construtores com CAS. Testes de deteccao de
adulteracao atualizados para funcionar com o layout de diretorio CAS.</p>
<p>347 testes passam em todo o workspace. Clippy limpo com <code>-D warnings</code>.</p>
<h2 id="decisoes-de-arquitetura">Decisoes de arquitetura</h2>
<ul>
<li><strong>BLAKE3 como chave CAS</strong>: o hash de conteudo que ja computamos para
verificacao de integridade serve tambem como chave de deduplicacao. Nenhuma
etapa adicional de hashing — o hash computado durante <code>create</code> ou <code>replicate</code>
e reutilizado como endereco CAS.</li>
<li><strong>Refcount SQLite ao inves de reflinks do sistema de arquivos</strong>: consideramos
usar copy-on-write no nivel do sistema de arquivos (reflinks em btrfs/XFS),
mas isso amarraria o Tesseras a sistemas de arquivos especificos. Refcounting
em SQLite funciona em qualquer sistema de arquivos, incluindo FAT32 em
pendrives baratos e ext4 em Raspberry Pis.</li>
<li><strong>Diretorios de prefixo hexadecimal de dois niveis</strong>: armazenar todos os
objetos CAS em um diretorio plano desaceleraria sistemas de arquivos com
milhoes de entradas. A divisao <code><prefixo 2 chars>/</code> limita qualquer diretorio
individual a ~65k entradas antes de um segundo nivel ser necessario. Isso
segue a abordagem usada pelo object store do Git.</li>
<li><strong>Periodo de graca para arquivos orfaos</strong>: o sweep GC pula arquivos com menos
de 1 hora para evitar deletar objetos sendo escritos por uma operacao
concorrente. Esta e uma escolha pragmatica — troca uma pequena janela de
potenciais orfaos por seguranca contra crashes sem exigir fsync ou commit de
duas fases.</li>
<li><strong>Migracao copy-first</strong>: a migracao copia dados para o CAS antes de remover
diretorios antigos. Se o processo for interrompido, os dados antigos
permanecem intactos e a migracao pode ser re-executada. Isso e mais lento que
mover arquivos mas garante zero perda de dados.</li>
<li><strong>Sweep no loop de reparo</strong>: ao inves de adicionar um timer separado de GC, o
sweep CAS aproveita o loop de reparo existente de 24 horas. Isso mantem o
daemon simples — um unico ciclo de manutencao em segundo plano cuida tanto da
saude dos fragmentos quanto da limpeza de armazenamento.</li>
</ul>
<h2 id="o-que-vem-a-seguir">O que vem a seguir</h2>
<ul>
<li><strong>Fase 4 continuacao</strong> — auditorias de seguranca, empacotamento para OS
(Alpine, Arch, Debian, OpenBSD, FreeBSD)</li>
<li><strong>Fase 5: Exploracao e Cultura</strong> — navegador publico de tesseras por
era/localizacao/tema/idioma, curadoria institucional, integracao genealogica
(FamilySearch, Ancestry), exportacao para midia fisica (M-DISC, microfilme,
papel livre de acido com QR), contexto assistido por IA</li>
</ul>
<p>A deduplicacao de armazenamento completa a historia de eficiencia de
armazenamento do Tesseras. Um no que armazena fragmentos para milhares de
usuarios — comum para nos institucionais e nos completos sempre ligados — agora
paga o custo de disco apenas por dados unicos. Combinado com codificacao de
apagamento Reed-Solomon (que ja minimiza redundancia no nivel da rede), o
sistema alcanca armazenamento eficiente tanto nas camadas local quanto
distribuida.</p>
Fase 4: Onboarding de Nos Institucionais2026-02-15T22:00:00+00:002026-02-15T22:00:00+00:00
Unknown
https://tesseras.net/pt-br/news/phase4-institutional-onboarding/<p>Uma rede P2P composta apenas por individuos e fragil. Discos rigidos morrem,
celulares sao perdidos, pessoas perdem interesse. A sobrevivencia a longo prazo
das memorias da humanidade depende de instituicoes — bibliotecas, arquivos,
museus, universidades — que medem seus tempos de vida em seculos. A Fase 4
continua com o onboarding de nos institucionais: organizacoes verificadas agora
podem prometer armazenamento, manter indices de busca e participar da rede com
uma identidade distinta.</p>
<p>O design segue um principio de confiar mas verificar: instituicoes se
identificam via registros DNS TXT (o mesmo mecanismo usado por SPF, DKIM e DMARC
para email), prometem um orcamento de armazenamento e recebem isencoes de
reciprocidade para que possam armazenar fragmentos para outros sem esperar nada
em troca. Em contrapartida, a rede trata seus fragmentos como replicas de maior
qualidade e limita a dependencia excessiva de qualquer instituicao individual
atraves de restricoes de diversidade.</p>
<h2 id="o-que-foi-construido">O que foi construido</h2>
<p><strong>Bits de capacidade</strong> (<code>tesseras-core/src/network.rs</code>) — Dois novos flags
adicionados ao bitfield <code>Capabilities</code>: <code>INSTITUTIONAL</code> (bit 7) e <code>SEARCH_INDEX</code>
(bit 8). Um novo construtor <code>institutional_default()</code> retorna o conjunto
completo de capacidades da Fase 2 mais esses dois bits e <code>RELAY</code>. Nos normais
anunciam <code>phase2_default()</code> que nao inclui flags institucionais. Testes de
roundtrip de serializacao verificam que os novos bits sobrevivem a codificacao
MessagePack.</p>
<p><strong>Tipos de busca</strong> (<code>tesseras-core/src/search.rs</code>) — Tres novos tipos de dominio
para o subsistema de busca:</p>
<ul>
<li><code>SearchFilters</code> — parametros de consulta: <code>memory_type</code>, <code>visibility</code>,
<code>language</code>, <code>date_range</code>, <code>geo</code> (bounding box), <code>page</code>, <code>page_size</code></li>
<li><code>SearchHit</code> — um resultado individual: hash do conteudo mais um
<code>MetadataExcerpt</code> (titulo, descricao, tipo de memoria, data de criacao,
visibilidade, idioma, tags)</li>
<li><code>GeoFilter</code> — bounding box com <code>min_lat</code>, <code>max_lat</code>, <code>min_lon</code>, <code>max_lon</code> para
consultas espaciais</li>
</ul>
<p>Todos os tipos derivam <code>Serialize</code>/<code>Deserialize</code> para transporte e
<code>Clone</code>/<code>Debug</code> para diagnostico.</p>
<p><strong>Configuracao institucional do daemon</strong> (<code>tesd/src/config.rs</code>) — Uma nova secao
<code>[institutional]</code> no TOML com <code>domain</code> (o dominio DNS a verificar),
<code>pledge_bytes</code> (compromisso de armazenamento em bytes) e <code>search_enabled</code>
(toggle para o indice FTS5). O metodo <code>to_dht_config()</code> agora define
<code>Capabilities::institutional_default()</code> quando a configuracao institucional esta
presente, para que nos institucionais anunciem os bits de capacidade corretos em
respostas Pong.</p>
<p><strong>Verificacao DNS TXT</strong> (<code>tesd/src/institutional.rs</code>) — Resolucao DNS assincrona
usando <code>hickory-resolver</code> para verificar identidade institucional. O daemon
consulta registros TXT em <code>_tesseras.<dominio></code> e analisa campos chave-valor:
<code>v</code> (versao), <code>node</code> (node ID em hexadecimal) e <code>pledge</code> (compromisso de
armazenamento em bytes). A verificacao checa:</p>
<ol>
<li>Um registro TXT existe em <code>_tesseras.<dominio></code></li>
<li>O campo <code>node</code> corresponde ao node ID do proprio daemon</li>
<li>O campo <code>pledge</code> esta presente e e valido</li>
</ol>
<p>Na inicializacao, o daemon tenta a verificacao DNS. Se bem-sucedida, o no roda
com capacidades institucionais. Se falhar, o no registra um aviso e faz
downgrade para um no completo normal — sem crash, sem intervencao manual.</p>
<p><strong>Comando CLI de setup</strong> (<code>tesseras-cli/src/institutional.rs</code>) — Um novo
subcomando <code>institutional setup</code> que guia operadores pelo onboarding:</p>
<ol>
<li>Le a identidade do no a partir do diretorio de dados</li>
<li>Solicita nome de dominio e tamanho do pledge</li>
<li>Gera o registro DNS TXT exato a adicionar:
<code>v=tesseras1 node=<hex> pledge=<bytes></code></li>
<li>Escreve a secao institucional no arquivo de configuracao do daemon</li>
<li>Imprime os proximos passos: adicionar o registro TXT, reiniciar o daemon</li>
</ol>
<p><strong>Indice de busca SQLite</strong> (<code>tesseras-storage</code>) — Uma migracao
(<code>003_institutional.sql</code>) que cria tres estruturas:</p>
<ul>
<li><code>search_content</code> — uma tabela virtual FTS5 para busca full-text sobre
metadados de tesseras (titulo, descricao, criador, tags, idioma)</li>
<li><code>geo_index</code> — uma tabela virtual R-tree para consultas espaciais de bounding
box sobre latitude/longitude</li>
<li><code>geo_map</code> — uma tabela de mapeamento ligando IDs de linhas do R-tree a hashes
de conteudo</li>
</ul>
<p>O adaptador <code>SqliteSearchIndex</code> implementa o port trait <code>SearchIndex</code> com
<code>index_tessera()</code> (inserir/atualizar) e <code>search()</code> (consultar com filtros).
Consultas FTS5 suportam busca em linguagem natural; consultas geo usam
<code>INTERSECT</code> do R-tree para lookups de bounding box. Resultados sao ranqueados
por score de relevancia do FTS5.</p>
<p>A migracao tambem adiciona uma coluna <code>is_institutional</code> a tabela <code>reciprocity</code>,
tratada de forma idempotente via checagens <code>pragma_table_info</code> (o
<code>ALTER TABLE ADD COLUMN</code> do SQLite nao tem <code>IF NOT EXISTS</code>).</p>
<p><strong>Bypass de reciprocidade</strong> (<code>tesseras-replication/src/service.rs</code>) — Nos
institucionais sao isentos de checagens de reciprocidade. Quando
<code>receive_fragment()</code> e chamado, se o node ID do remetente esta marcado como
institucional no ledger de reciprocidade, a checagem de saldo e ignorada
completamente. Isso significa que instituicoes podem armazenar fragmentos para
toda a rede sem precisar "ganhar" creditos primeiro — sua identidade verificada
por DNS e compromisso de armazenamento servem como credencial.</p>
<p><strong>Restricao de diversidade por tipo de no</strong>
(<code>tesseras-replication/src/distributor.rs</code>) — Uma nova funcao
<code>apply_institutional_diversity()</code> limita quantas replicas de uma unica tessera
podem ir para nos institucionais. O limite e <code>ceil(fator_replicacao / 3.5)</code> —
com o padrao <code>r=7</code>, no maximo 2 de 7 replicas vao para instituicoes. Isso impede
que a rede se torne dependente de um pequeno numero de grandes instituicoes: se
os servidores de uma universidade cairem, pelo menos 5 replicas permanecem em
nos independentes.</p>
<p><strong>Extensoes de mensagens DHT</strong> (<code>tesseras-dht/src/message.rs</code>) — Duas novas
variantes de mensagem:</p>
<table><thead><tr><th>Mensagem</th><th>Proposito</th></tr></thead><tbody>
<tr><td><code>Search</code></td><td>Cliente envia string de consulta, filtros e numero da pagina</td></tr>
<tr><td><code>SearchResult</code></td><td>No institucional responde com resultados e contagem total</td></tr>
</tbody></table>
<p>A funcao <code>encode()</code> foi trocada de serializacao MessagePack posicional para
nomeada (<code>rmp_serde::to_vec_named</code>) para lidar corretamente com campos opcionais
de <code>SearchFilters</code> — a codificacao posicional quebra quando
<code>skip_serializing_if</code> omite campos.</p>
<p><strong>Metricas Prometheus</strong> (<code>tesd/src/metrics.rs</code>) — Oito metricas especificas
institucionais:</p>
<ul>
<li><code>tesseras_institutional_pledge_bytes</code> — compromisso de armazenamento
configurado</li>
<li><code>tesseras_institutional_stored_bytes</code> — bytes realmente armazenados</li>
<li><code>tesseras_institutional_pledge_utilization_ratio</code> — razao armazenado/prometido</li>
<li><code>tesseras_institutional_peers_served</code> — peers unicos que receberam fragmentos</li>
<li><code>tesseras_institutional_search_index_total</code> — tesseras no indice de busca</li>
<li><code>tesseras_institutional_search_queries_total</code> — consultas de busca recebidas</li>
<li><code>tesseras_institutional_dns_verification_status</code> — 1 se verificado por DNS, 0
caso contrario</li>
<li><code>tesseras_institutional_dns_verification_last</code> — timestamp Unix da ultima
verificacao</li>
</ul>
<p><strong>Testes de integracao</strong> — Dois testes em
<code>tesseras-replication/tests/integration.rs</code>:</p>
<ul>
<li><code>institutional_peer_bypasses_reciprocity</code> — verifica que um peer institucional
com deficit massivo (-999.999 de saldo) ainda pode armazenar fragmentos,
enquanto um peer nao institucional com o mesmo deficit e rejeitado</li>
<li><code>institutional_node_accepts_fragment_despite_deficit</code> — teste async completo
usando <code>ReplicationService</code> com DHT, fragment store, reciprocity ledger e blob
store mockados: envia um fragmento de um remetente institucional e verifica
que e aceito</li>
</ul>
<p>322 testes passam em todo o workspace. Clippy limpo com <code>-D warnings</code>.</p>
<h2 id="decisoes-de-arquitetura">Decisoes de arquitetura</h2>
<ul>
<li><strong>DNS TXT ao inves de PKI ou blockchain</strong>: DNS e universalmente implantado,
universalmente compreendido e ja usado para verificacao de dominio (SPF, DKIM,
Let's Encrypt). Instituicoes ja gerenciam DNS. Nenhuma autoridade
certificadora, nenhum token, nenhuma transacao on-chain — apenas um registro
TXT. Se uma instituicao perder controle de seu dominio, a verificacao
naturalmente falha na proxima checagem.</li>
<li><strong>Degradacao graciosa em falha DNS</strong>: se a verificacao DNS falha na
inicializacao, o daemon faz downgrade para um no completo normal ao inves de
recusar iniciar. Isso previne incidentes operacionais — uma misconfiguracao
DNS nao deveria tirar um no do ar.</li>
<li><strong>Limite de diversidade em <code>ceil(r / 3.5)</code></strong>: com <code>r=7</code>, no maximo 2 replicas
vao para instituicoes. Isso e conservador — garante que a rede nunca dependa
de instituicoes para quorum majoritario, enquanto ainda se beneficia de sua
capacidade de armazenamento e uptime.</li>
<li><strong>Codificacao MessagePack nomeada</strong>: trocar de codificacao posicional para
nomeada adiciona ~15% de overhead por mensagem mas elimina uma classe de bugs
de serializacao quando campos opcionais estao presentes. O DHT nao e limitado
por largura de banda no nivel de mensagem, entao o tradeoff vale a pena.</li>
<li><strong>Isencao de reciprocidade ao inves de concessao de creditos</strong>: ao inves de
dar as instituicoes um saldo inicial grande de creditos (que e arbitrario e
precisa de ajuste), isentamos completamente. Sua identidade verificada por DNS
e compromisso publico de armazenamento substituem o mecanismo de reciprocidade
bilateral.</li>
<li><strong>FTS5 + R-tree no SQLite</strong>: busca full-text e indexacao espacial sao
embutidas no SQLite como extensoes carregaveis. Nenhum motor de busca externo
(Elasticsearch, Meilisearch) necessario. Isso mantem o deploy como um unico
binario com um unico arquivo de banco de dados — critico para operadores
institucionais que podem nao ter uma equipe de DevOps.</li>
</ul>
<h2 id="o-que-vem-a-seguir">O que vem a seguir</h2>
<ul>
<li><strong>Fase 4 continuacao</strong> — deduplicacao de armazenamento (armazenamento
enderecavel por conteudo com BLAKE3), auditorias de seguranca, empacotamento
para OS (Alpine, Arch, Debian, OpenBSD, FreeBSD)</li>
<li><strong>Fase 5: Exploracao e Cultura</strong> — navegador publico de tesseras por
era/localizacao/tema/idioma, curadoria institucional, integracao genealogica
(FamilySearch, Ancestry), exportacao para midia fisica (M-DISC, microfilme,
papel livre de acido com QR), contexto assistido por IA</li>
</ul>
<p>O onboarding institucional fecha uma lacuna critica no modelo de preservacao do
Tesseras. Nos individuais fornecem resiliencia de base — milhares de
dispositivos ao redor do globo, cada um armazenando alguns fragmentos. Nos
institucionais fornecem ancoragem — organizacoes com infraestrutura
profissional, armazenamento redundante e horizontes operacionais de multiplas
decadas. Juntos, formam uma rede onde memorias podem sobreviver tanto a
dispositivos individuais quanto a instituicoes individuais.</p>
Fase 4: Tuning de Performance2026-02-15T20:00:00+00:002026-02-15T20:00:00+00:00
Unknown
https://tesseras.net/pt-br/news/phase4-performance-tuning/<p>Uma rede P2P que atravessa NATs mas engasga com seu proprio I/O nao serve de
muito. A Fase 4 continua com tuning de performance: centralizacao da
configuracao do banco de dados, cache de blobs de fragmentos em memoria,
gerenciamento de ciclo de vida de conexoes QUIC e eliminacao de leituras
desnecessarias de disco no hot path de atestacao.</p>
<p>O principio orientador foi o mesmo do resto do Tesseras: fazer a coisa mais
simples que realmente funciona. Sem alocadores customizados, sem estruturas de
dados lock-free, sem complexidade prematura. Um <code>StorageConfig</code> centralizado, um
cache LRU, um reaper de conexoes e uma correcao pontual para evitar reler blobs
que ja tinham checksum calculado.</p>
<h2 id="o-que-foi-construido">O que foi construido</h2>
<p><strong>Configuracao SQLite centralizada</strong> (<code>tesseras-storage/src/database.rs</code>) — Um
novo struct <code>StorageConfig</code> e funcoes <code>open_database()</code> / <code>open_in_memory()</code> que
aplicam todos os pragmas SQLite em um unico lugar: journal mode WAL, foreign
keys, modo synchronous (NORMAL por padrao, FULL para hardware instavel como
RPi + cartao SD), busy timeout, tamanho do cache de paginas e intervalo de
autocheckpoint WAL. Anteriormente, cada ponto de chamada abria uma conexao e
aplicava pragmas ad hoc. Agora o daemon, CLI e testes passam todos pelo mesmo
caminho. 7 testes cobrindo foreign keys, busy timeout, journal mode, migracoes,
modos synchronous e criacao de arquivos WAL em disco.</p>
<p><strong>Cache LRU de fragmentos</strong> (<code>tesseras-storage/src/cache.rs</code>) — Um
<code>CachedFragmentStore</code> que envolve qualquer <code>FragmentStore</code> com um cache LRU
ciente de bytes. Blobs de fragmentos sao cacheados na leitura e invalidados na
escrita ou exclusao. Quando o cache excede seu limite de bytes configurado, as
entradas menos recentemente usadas sao removidas. O cache e transparente: ele
proprio implementa <code>FragmentStore</code>, entao o resto da pilha nao sabe que esta la.
Metricas Prometheus opcionais rastreiam hits, misses e uso atual de bytes. 3
testes: hit no cache evita leitura interna, store invalida cache, remocao quando
excede bytes maximos.</p>
<p><strong>Metricas Prometheus de storage</strong> (<code>tesseras-storage/src/metrics.rs</code>) — Um
struct <code>StorageMetrics</code> com tres contadores/gauges: <code>fragment_cache_hits</code>,
<code>fragment_cache_misses</code> e <code>fragment_cache_bytes</code>. Registrado no registry
Prometheus e conectado ao cache de fragmentos via <code>with_metrics()</code>.</p>
<p><strong>Correcao do hot path de atestacao</strong> (<code>tesseras-replication/src/service.rs</code>) —
O fluxo de atestacao anteriormente lia cada blob de fragmento do disco e
recalculava seu checksum BLAKE3. Como <code>list_fragments()</code> ja retorna <code>FragmentId</code>
com um checksum armazenado, a correcao e trivial: usar <code>frag.checksum</code> ao inves
de <code>blake3::hash(&data)</code>. Isso elimina uma leitura de disco por fragmento
durante atestacao — para uma tessera com 100 fragmentos, sao 100 leituras a
menos. Um teste com <code>expect_read_fragment().never()</code> verifica que nenhuma
leitura de blob acontece durante atestacao.</p>
<p><strong>Ciclo de vida do pool de conexoes QUIC</strong>
(<code>tesseras-net/src/quinn_transport.rs</code>) — Um struct <code>PoolConfig</code> controlando
maximo de conexoes, timeout de inatividade e intervalo do reaper.
<code>PooledConnection</code> envolve cada <code>quinn::Connection</code> com um timestamp
<code>last_used</code>. Quando o pool atinge capacidade maxima, a conexao inativa mais
antiga e removida antes de abrir uma nova. Uma tarefa reaper em background
(Tokio spawn) periodicamente fecha conexoes que ficaram inativas alem do
timeout. 4 novas metricas de pool: <code>tesseras_conn_pool_size</code>, <code>pool_hits_total</code>,
<code>pool_misses_total</code>, <code>pool_evictions_total</code>.</p>
<p><strong>Integracao no daemon</strong> (<code>tesd/src/config.rs</code>, <code>main.rs</code>) — Uma nova secao
<code>[performance]</code> na configuracao TOML com campos para tamanho de cache SQLite,
modo synchronous, busy timeout, tamanho de cache de fragmentos, maximo de
conexoes, timeout de inatividade e intervalo do reaper. O <code>main()</code> do daemon
agora chama <code>open_database()</code> com o <code>StorageConfig</code> configurado, envolve
<code>FsFragmentStore</code> com <code>CachedFragmentStore</code> e vincula QUIC com o <code>PoolConfig</code>
configurado. A dependencia direta de <code>rusqlite</code> foi removida do crate do daemon.</p>
<p><strong>Migracao do CLI</strong> (<code>tesseras-cli/src/commands/init.rs</code>, <code>create.rs</code>) — Ambos
os comandos <code>init</code> e <code>create</code> agora usam <code>tesseras_storage::open_database()</code> com
o <code>StorageConfig</code> padrao ao inves de abrir conexoes <code>rusqlite</code> diretamente. A
dependencia de <code>rusqlite</code> foi removida do crate do CLI.</p>
<h2 id="decisoes-de-arquitetura">Decisoes de arquitetura</h2>
<ul>
<li><strong>Padrao decorator para cache</strong>: <code>CachedFragmentStore</code> envolve
<code>Box<dyn FragmentStore></code> e implementa <code>FragmentStore</code> ele proprio. Isso
significa que cache e opt-in, composavel e invisivel para consumidores. O
daemon habilita; testes podem pular.</li>
<li><strong>Remocao ciente de bytes</strong>: o cache LRU rastreia bytes totais, nao contagem
de entradas. Blobs de fragmentos variam muito em tamanho (um fragmento de
texto de 4KB vs um shard de foto de 2MB), entao contar entradas daria uma
visao enganosa do uso de memoria.</li>
<li><strong>Sem crate de pool de conexoes</strong>: ao inves de trazer uma biblioteca generica
de pool, o pool de conexoes e um wrapper fino sobre
<code>DashMap<SocketAddr, PooledConnection></code> com um reaper Tokio. Conexoes QUIC sao
multiplexadas, entao o "pool" e realmente sobre gerenciamento de ciclo de vida
(limpeza de inativos, maximo de conexoes) e nao sobre emprestar/devolver.</li>
<li><strong>Checksums armazenados ao inves de releituras</strong>: a correcao de atestacao e
intencionalmente minima — uma linha alterada, uma leitura de disco removida
por fragmento. Os checksums ja estavam armazenados no SQLite por
<code>store_fragment()</code>, apenas nao estavam sendo usados.</li>
<li><strong>Configuracao centralizada de pragmas</strong>: um unico struct <code>StorageConfig</code>
substitui chamadas <code>PRAGMA</code> espalhadas. O flag <code>sqlite_synchronous_full</code>
existe especificamente para implantacoes em Raspberry Pi onde o kernel pode
crashar e perder transacoes WAL nao checkpointadas.</li>
</ul>
<h2 id="o-que-vem-a-seguir">O que vem a seguir</h2>
<ul>
<li><strong>Fase 4 continuacao</strong> — Shamir's Secret Sharing para herdeiros, tesseras
seladas (criptografia time-lock), auditorias de seguranca, onboarding de nos
institucionais, deduplicacao de storage, empacotamento para OS</li>
<li><strong>Fase 5: Exploracao e Cultura</strong> — navegador publico de tesseras por
era/localizacao/tema/idioma, curadoria institucional, integracao genealogica,
exportacao para midia fisica (M-DISC, microfilme, papel livre de acido com QR)</li>
</ul>
<p>Com tuning de performance implementado, Tesseras lida com o caso comum de forma
eficiente: leituras de fragmentos acertam o cache LRU, atestacao pula I/O de
disco, conexoes QUIC inativas sao removidas automaticamente e o SQLite e
configurado consistentemente em toda a pilha. Os proximos passos focam em
funcionalidades criptograficas (Shamir, time-lock) e hardening para implantacao
em producao.</p>
Fase 4: Verificar Sem Instalar Nada2026-02-15T20:00:00+00:002026-02-15T20:00:00+00:00
Unknown
https://tesseras.net/pt-br/news/phase4-wasm-browser-verification/<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<T, String></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) => void
): Promise<VerificationResult>
</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-<hash>/</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() -> Result<T, String></code> e <code>foo() -> Result<T, JsError></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>
Fase 4: Furando NATs2026-02-15T18:00:00+00:002026-02-15T18:00:00+00:00
Unknown
https://tesseras.net/pt-br/news/phase4-nat-traversal/<p>A maioria dos dispositivos das pessoas ficam atras de um NAT — um tradutor de
enderecos de rede que permite acessar a internet mas impede conexoes de entrada.
Para uma rede P2P, isso e um problema existencial: se dois nos atras de NATs nao
conseguem se comunicar, a rede se fragmenta. A Fase 4 continua com uma pilha
completa de travessia de NAT: descoberta via STUN, hole punching coordenado e
fallback por relay.</p>
<p>A abordagem segue o mesmo padrao da maioria dos sistemas P2P consolidados
(WebRTC, BitTorrent, IPFS): tente a opcao mais barata primeiro, escale apenas
quando necessario. Conectividade direta nao custa nada. Hole punching custa
alguns pacotes coordenados. Relay custa largura de banda sustentada de um
terceiro. Tesseras tenta nessa ordem.</p>
<h2 id="o-que-foi-construido">O que foi construido</h2>
<p><strong>Classificacao NatType</strong> (<code>tesseras-core/src/network.rs</code>) — Um novo enum
<code>NatType</code> (Public, Cone, Symmetric, Unknown) adicionado a camada de dominio
core. Esse tipo e compartilhado por toda a pilha: o cliente STUN o escreve, o
DHT o divulga em mensagens Pong, e o coordenador de punch o le para decidir se
hole punching vale a pena tentar (Cone-para-Cone funciona ~80% das vezes;
Symmetric-para-Symmetric quase nunca funciona).</p>
<p><strong>Cliente STUN</strong> (<code>tesseras-net/src/stun.rs</code>) — Uma implementacao STUN minima
(RFC 5389 Binding Request/Response) que descobre o endereco externo de um no. O
codec codifica requisicoes de 20 bytes com um ID de transacao aleatorio e
decodifica respostas XOR-MAPPED-ADDRESS. A funcao <code>discover_nat()</code> consulta
multiplos servidores STUN em paralelo (Google, Cloudflare por padrao), compara
os enderecos mapeados e classifica o tipo de NAT:</p>
<ul>
<li>Mesmo IP e porta de todos os servidores → <strong>Public</strong> (sem NAT)</li>
<li>Mesmo endereco mapeado de todos os servidores → <strong>Cone</strong> (hole punching
funciona)</li>
<li>Enderecos mapeados diferentes → <strong>Symmetric</strong> (hole punching nao confiavel)</li>
<li>Sem respostas → <strong>Unknown</strong></li>
</ul>
<p>Retentativas com backoff exponencial e timeouts configuraveis. 12 testes
cobrindo roundtrips de codec, todos os caminhos de classificacao e consultas
async em loopback.</p>
<p><strong>Coordenacao de punch assinada</strong> (<code>tesseras-net/src/punch.rs</code>) — Assinatura e
verificacao Ed25519 para mensagens <code>PunchIntro</code>, <code>RelayRequest</code> e
<code>RelayMigrate</code>. Cada introducao e assinada pelo iniciador com uma janela de
timestamp de 30 segundos, prevenindo ataques de reflexao (onde um atacante
reproduz uma introducao antiga para redirecionar trafego). O formato do payload
e <code>target || external_addr || timestamp</code> — alterar qualquer campo invalida a
assinatura. 6 testes unitarios mais 3 testes baseados em propriedades com
proptest (IDs de no, portas e tokens de sessao arbitrarios).</p>
<p><strong>Gerenciador de sessoes de relay</strong> (<code>tesseras-net/src/relay.rs</code>) — Gerencia
sessoes de relay UDP transparente entre nos com NAT. Cada sessao tem um token
aleatorio de 16 bytes; os nos prefixam seus pacotes com o token, o relay remove
e encaminha. Funcionalidades:</p>
<ul>
<li>Encaminhamento bidirecional (A→R→B e B→R→A)</li>
<li>Limite de taxa: 256 KB/s para nos reciprocos, 64 KB/s para nao reciprocos</li>
<li>Duracao maxima de 10 minutos para sessoes bootstrap (nao reciprocas)</li>
<li>Migracao de endereco: quando o IP de um no muda (Wi-Fi para celular), um
<code>RelayMigrate</code> assinado atualiza a sessao sem derruba-la</li>
<li>Limpeza por inatividade com timeout configuravel</li>
<li>8 testes unitarios mais 2 testes baseados em propriedades</li>
</ul>
<p><strong>Extensoes de mensagens DHT</strong> (<code>tesseras-dht/src/message.rs</code>) — Sete novas
variantes de mensagem adicionadas ao protocolo DHT:</p>
<table><thead><tr><th>Mensagem</th><th>Proposito</th></tr></thead><tbody>
<tr><td><code>PunchIntro</code></td><td>"Quero conectar ao no X, aqui esta meu endereco externo assinado"</td></tr>
<tr><td><code>PunchRequest</code></td><td>O introdutor encaminha a requisicao ao destino</td></tr>
<tr><td><code>PunchReady</code></td><td>O destino confirma prontidao, envia seu endereco externo</td></tr>
<tr><td><code>RelayRequest</code></td><td>"Crie uma sessao de relay para o no X"</td></tr>
<tr><td><code>RelayOffer</code></td><td>O relay responde com seu endereco e token de sessao</td></tr>
<tr><td><code>RelayClose</code></td><td>Encerrar uma sessao de relay</td></tr>
<tr><td><code>RelayMigrate</code></td><td>Atualizar sessao apos mudanca de rede</td></tr>
</tbody></table>
<p>A mensagem <code>Pong</code> foi estendida com metadados NAT: <code>nat_type</code>,
<code>relay_slots_available</code> e <code>relay_bandwidth_used_kbps</code>. Todos os novos campos
usam <code>#[serde(default)]</code> para compatibilidade retroativa — nos antigos ignoram o
que nao reconhecem, nos novos usam defaults. 9 novos testes de roundtrip de
serializacao.</p>
<p><strong>Trait NatHandler e dispatch</strong> (<code>tesseras-dht/src/engine.rs</code>) — Uma nova trait
async <code>NatHandler</code> (5 metodos) injetada no engine DHT, seguindo o mesmo padrao
de injecao de dependencia do <code>ReplicationHandler</code> existente. O loop de dispatch
de mensagens do engine agora roteia todas as mensagens punch/relay para o
handler. Isso mantem o engine DHT agnóstico ao protocolo enquanto permite que a
logica de travessia de NAT viva em <code>tesseras-net</code>.</p>
<p><strong>Tipos de reconexao mobile</strong> (<code>tesseras-embedded/src/reconnect.rs</code>) — Uma
maquina de estados de reconexao em tres fases para dispositivos moveis:</p>
<ol>
<li><strong>QuicMigration</strong> (0-2s) — tenta migracao de conexao QUIC para todos os peers
ativos</li>
<li><strong>ReStun</strong> (2-5s) — redescobre endereco externo via STUN</li>
<li><strong>ReEstablish</strong> (5-10s) — reconecta peers que a migracao nao conseguiu salvar</li>
</ol>
<p>Peers sao reconectados em ordem de prioridade: nos bootstrap primeiro, depois
nos que guardam nossos fragmentos, depois nos cujos fragmentos guardamos, depois
vizinhos DHT gerais. Uma nova variante de evento <code>NetworkChanged</code> foi adicionada
ao stream de eventos FFI para que o app Flutter possa mostrar progresso de
reconexao.</p>
<p><strong>Configuracao NAT do daemon</strong> (<code>tesd/src/config.rs</code>) — Uma nova secao <code>[nat]</code>
na configuracao TOML com lista de servidores STUN, toggle de relay, maximo de
sessoes relay, limites de largura de banda (reciproco vs bootstrap) e timeout de
inatividade. Todos os campos tem defaults sensiveis; relay e desabilitado por
padrao.</p>
<p><strong>Metricas Prometheus</strong> (<code>tesseras-net/src/metrics.rs</code>) — 16 metricas em quatro
subsistemas:</p>
<ul>
<li><strong>STUN</strong>: requisicoes, falhas, histograma de latencia</li>
<li><strong>Punch</strong>: tentativas/sucessos/falhas (por par de tipo NAT), histograma de
latencia</li>
<li><strong>Relay</strong>: sessoes ativas, sessoes totais, bytes encaminhados, timeouts por
inatividade, hits de rate limit</li>
<li><strong>Reconexao</strong>: mudancas de rede, tentativas/sucessos por fase, histograma de
duracao</li>
</ul>
<p>6 testes verificando registro, incremento, cardinalidade de labels e deteccao de
registro duplo.</p>
<p><strong>Testes de integracao</strong> — Dois testes end-to-end usando <code>MemTransport</code> (rede
simulada em memoria):</p>
<ul>
<li><code>punch_integration.rs</code> — Fluxo completo de hole-punch com 3 nos: A envia
<code>PunchIntro</code> assinado ao introdutor I, I verifica e encaminha <code>PunchRequest</code> a
B, B verifica a assinatura original e envia <code>PunchReady</code> de volta, A e B
trocam mensagens diretamente. Tambem testa que uma assinatura invalida e
corretamente rejeitada.</li>
<li><code>relay_integration.rs</code> — Fluxo completo de relay com 3 nos: A solicita relay
de R, R cria sessao e envia <code>RelayOffer</code> a ambos os peers, A e B trocam
pacotes prefixados com token atraves de R, A migra para um novo endereco no
meio da sessao, A fecha a sessao, e o teste verifica que a sessao e encerrada
e encaminhamento posterior falha.</li>
</ul>
<p><strong>Testes de propriedade</strong> — 7 testes baseados em proptest cobrindo: roundtrips
de assinatura para todos os tres tipos de mensagem assinada (IDs de no, portas e
tokens arbitrarios), determinismo de classificacao NAT (mesmas entradas sempre
produzem mesma saida), validade de binding request STUN, unicidade de tokens de
sessao, e rejeicao de pacotes curtos pelo relay.</p>
<p><strong>Alvos Justfile</strong> — <code>just test-nat</code> executa todos os testes de travessia NAT em
<code>tesseras-net</code> e <code>tesseras-dht</code>. <code>just test-chaos</code> e um placeholder para futuros
testes de caos com Docker Compose e <code>tc netem</code>.</p>
<h2 id="decisoes-de-arquitetura">Decisoes de arquitetura</h2>
<ul>
<li><strong>STUN ao inves de TURN</strong>: implementamos STUN (descoberta) e relay customizado
ao inves de TURN completo. TURN requer alocacao autenticada e foi projetado
para relay de midia; nosso relay e mais simples — encaminhamento UDP com
prefixo de token e limites de taxa. Isso mantem o protocolo minimo e evita
depender de servidores TURN externos.</li>
<li><strong>Assinaturas em introducoes</strong>: cada <code>PunchIntro</code> e assinado pelo iniciador.
Sem isso, um atacante poderia enviar introducoes forjadas para redirecionar as
tentativas de hole-punch de um no para um endereco controlado pelo atacante
(ataque de reflexao). A janela de timestamp de 30 segundos limita replay.</li>
<li><strong>Tiers reciprocos de largura de banda</strong>: nos relay dao 4x mais largura de
banda (256 vs 64 KB/s) para peers com boas pontuacoes de reciprocidade. Isso
incentiva nos a armazenar fragmentos para outros — se voce contribui, recebe
melhor servico de relay quando precisa.</li>
<li><strong>Extensao Pong retrocompativel</strong>: novos campos NAT em <code>Pong</code> usam
<code>#[serde(default)]</code> e <code>Option<T></code>. Nos antigos que nao entendem esses campos
simplesmente os pulam durante deserializacao. Nenhum bump de versao de
protocolo necessario.</li>
<li><strong>NatHandler como trait async</strong>: a logica de travessia NAT e injetada no
engine DHT via trait, assim como <code>ReplicationHandler</code>. Isso mantem o engine
DHT focado em roteamento e gerenciamento de peers, e permite que a
implementacao NAT seja trocada ou desabilitada sem tocar no codigo core do
DHT.</li>
</ul>
<h2 id="o-que-vem-a-seguir">O que vem a seguir</h2>
<ul>
<li><strong>Fase 4 continuacao</strong> — tuning de performance (pooling de conexoes, cache de
fragmentos, SQLite WAL), auditorias de seguranca, onboarding de nos
institucionais, empacotamento para OS</li>
<li><strong>Fase 5: Exploracao e Cultura</strong> — navegador publico de tesseras por
era/localizacao/tema/idioma, curadoria institucional, integracao genealogica,
exportacao para midia fisica (M-DISC, microfilme, papel livre de acido com QR)</li>
</ul>
<p>Com travessia de NAT, Tesseras pode conectar nos independentemente de sua
topologia de rede. Nos publicos conversam diretamente. Nos com NAT Cone furam
com ajuda de um introdutor. Nos com NAT Symmetric ou firewalled usam relay
atraves de peers voluntarios. A rede se adapta ao mundo real, onde a maioria dos
dispositivos esta atras de um NAT e as condicoes de rede mudam constantemente.</p>
CLI Encontra a Rede: Comandos Publish, Fetch e Status2026-02-15T00:00:00+00:002026-02-15T00:00:00+00:00
Unknown
https://tesseras.net/pt-br/news/cli-daemon-rpc/<p>Até agora o CLI operava isoladamente: criar uma tessera, verificar, exportar,
listar o que você tem. Tudo ficava na sua máquina. Com esta atualização, o <code>tes</code>
ganha três comandos que fazem a ponte entre o armazenamento local e a rede P2P —
<code>publish</code>, <code>fetch</code> e <code>status</code> — comunicando-se com um <code>tesd</code> em execução através
de um socket Unix.</p>
<h2 id="o-que-foi-construido">O que foi construído</h2>
<p><strong>Crate <code>tesseras-rpc</code></strong> — Um novo crate compartilhado entre CLI e daemon.
Define o protocolo RPC usando serialização MessagePack com enquadramento
prefixado por tamanho (cabeçalho big-endian de 4 bytes, máximo de 64 MiB). Três
tipos de requisição (<code>Publish</code>, <code>Fetch</code>, <code>Status</code>) e suas respostas
correspondentes. Um <code>DaemonClient</code> síncrono gerencia a conexão do socket Unix
com timeouts configuráveis. O protocolo é deliberadamente simples — uma
requisição, uma resposta, conexão fechada — para manter a implementação
auditável.</p>
<p><strong><code>tes publish <hash></code></strong> — Publica uma tessera na rede. Aceita hashes completos
ou prefixos curtos (ex.: <code>tes publish a1b2</code>), que são resolvidos no banco de
dados local. O daemon lê todos os arquivos da tessera do armazenamento, empacota
em um único buffer MessagePack e entrega ao motor de replicação. Tesseras
pequenas (< 4 MB) são replicadas como um único fragmento; maiores passam por
codificação de apagamento Reed-Solomon. A saída mostra o hash curto e a contagem
de fragmentos:</p>
<pre><code>Published tessera 9f2c4a1b (24 fragments created)
Distribution in progress — use `tes status 9f2c4a1b` to track.
</code></pre>
<p><strong><code>tes fetch <hash></code></strong> — Busca uma tessera da rede usando o hash de conteúdo
completo. O daemon coleta fragmentos disponíveis localmente, reconstrói os dados
originais via decodificação de apagamento se necessário, desempacota os arquivos
e armazena no CAS (content-addressable store). Retorna o número de memórias e o
tamanho total buscado.</p>
<p><strong><code>tes status <hash></code></strong> — Exibe a saúde de replicação de uma tessera. A saída
mapeia diretamente o modelo interno de saúde do motor de replicação:</p>
<table><thead><tr><th>Estado</th><th>Significado</th></tr></thead><tbody>
<tr><td>Local</td><td>Ainda não publicada — existe apenas na sua máquina</td></tr>
<tr><td>Publishing</td><td>Fragmentos sendo distribuídos, redundância crítica</td></tr>
<tr><td>Replicated</td><td>Distribuída, mas abaixo da redundância alvo</td></tr>
<tr><td>Healthy</td><td>Redundância completa alcançada</td></tr>
</tbody></table>
<p><strong>Listener RPC no daemon</strong> — O daemon agora escuta em um socket Unix (padrão:
<code>$XDG_RUNTIME_DIR/tesseras/daemon.sock</code>) com permissões de diretório adequadas
(0700), limpeza de sockets obsoletos e shutdown gracioso. Cada conexão é tratada
em uma task Tokio — o listener converte o stream assíncrono para I/O síncrono
para a camada de enquadramento, despacha para o handler RPC e escreve a resposta
de volta.</p>
<p><strong>Pack/unpack no <code>tesseras-core</code></strong> — Um módulo pequeno que serializa uma lista
de entradas de arquivo (caminho + dados) em um único buffer MessagePack e
vice-versa. Esta é a ponte entre a estrutura de diretórios da tessera e os blobs
opacos do motor de replicação.</p>
<h2 id="decisoes-de-arquitetura">Decisões de arquitetura</h2>
<ul>
<li><strong>Socket Unix ao invés de TCP</strong>: a comunicação RPC entre CLI e daemon acontece
na mesma máquina. Sockets Unix são mais rápidos, não precisam de alocação de
porta, e as permissões do sistema de arquivos fornecem controle de acesso sem
TLS.</li>
<li><strong>MessagePack ao invés de JSON</strong>: o mesmo formato wire usado em todo o
Tesseras. Compacto, sem schema, e já é uma dependência do workspace. Uma
ida-e-volta típica de publish request/response ocupa menos de 200 bytes.</li>
<li><strong>Cliente síncrono, daemon assíncrono</strong>: o <code>DaemonClient</code> usa I/O bloqueante
porque o CLI não precisa de concorrência — envia uma requisição e espera. O
listener do daemon é assíncrono (Tokio) para tratar múltiplas conexões. A
camada de enquadramento funciona com qualquer impl <code>Read</code>/<code>Write</code>, conectando
ambos os mundos.</li>
<li><strong>Resolução de prefixo no lado do cliente</strong>: <code>publish</code> e <code>status</code> resolvem
prefixos curtos localmente antes de enviar o hash completo ao daemon. Isso
mantém o daemon stateless — ele não precisa acessar o banco de dados do CLI.</li>
<li><strong>Alinhamento do diretório de dados padrão</strong>: o padrão do CLI mudou de
<code>~/.tesseras</code> para <code>~/.local/share/tesseras</code> (via <code>dirs::data_dir()</code>) para
coincidir com o daemon. Um aviso de migração é exibido quando dados no caminho
antigo são detectados.</li>
</ul>
<h2 id="proximos-passos">Próximos passos</h2>
<ul>
<li><strong>Contagem de peers no DHT</strong>: o comando <code>status</code> atualmente reporta 0 peers —
conectar a contagem real do DHT é o próximo passo</li>
<li><strong><code>tes show</code></strong>: exibir o conteúdo de uma tessera (memórias, metadados) sem
exportar</li>
<li><strong>Fetch com streaming</strong>: para tesseras grandes, transmitir fragmentos conforme
chegam ao invés de esperar por todos</li>
</ul>
Fase 4: Recuperação de Chaves por Herdeiros com Shamir's Secret Sharing2026-02-15T00:00:00+00:002026-02-15T00:00:00+00:00
Unknown
https://tesseras.net/pt-br/news/phase4-shamir-heir-recovery/<p>O que acontece com suas memórias quando você morre? Até agora, Tesseras
conseguia preservar conteúdo ao longo de milênios — mas as chaves privadas e
seladas morriam com o dono. A Fase 4 continua com uma solução: Shamir's Secret
Sharing, um esquema criptográfico que permite dividir sua identidade em
fragmentos e distribuí-los para as pessoas em quem você mais confia.</p>
<p>A matemática é elegante: você escolhe um limiar T e um total N. Qualquer T
fragmentos reconstroem o segredo completo; T-1 fragmentos não revelam
absolutamente nada. Isso não é "quase nada" — é informação-teoricamente seguro.
Um atacante com um fragmento a menos que o limiar tem exatamente zero bits de
informação sobre o segredo, independentemente do poder computacional que tenha.</p>
<h2 id="o-que-foi-construido">O que foi construído</h2>
<p><strong>Aritmética de corpo finito GF(256)</strong> (<code>tesseras-crypto/src/shamir/gf256.rs</code>) —
Shamir's Secret Sharing requer aritmética em um corpo finito. Implementamos
GF(256) usando o mesmo polinômio irredutível do AES (x^8 + x^4 + x^3 + x + 1),
com tabelas de lookup para logaritmo e exponenciação computadas em tempo de
compilação. Todas as operações são em tempo constante via consulta a tabelas —
sem ramificações baseadas em dados secretos. O módulo inclui o método de Horner
para avaliação de polinômios e interpolação de Lagrange em x=0 para recuperação
do segredo. 233 linhas, exaustivamente testado: todos os 256 elementos para
propriedades de identidade/inverso, comutatividade e associatividade.</p>
<p><strong>ShamirSplitter</strong> (<code>tesseras-crypto/src/shamir/mod.rs</code>) — A API principal de
split/reconstruct. <code>split()</code> recebe uma fatia de bytes do segredo, uma
configuração (limiar T, total N) e a chave pública Ed25519 do dono. Para cada
byte do segredo, constrói um polinômio aleatório de grau T-1 sobre GF(256) com o
byte do segredo como termo constante, e então o avalia em N pontos distintos.
<code>reconstruct()</code> recebe T ou mais fragmentos e recupera o segredo via
interpolação de Lagrange. Ambas as operações incluem validação extensiva:
limites do limiar, consistência de sessão, correspondência de impressão digital
do dono e verificação de checksum BLAKE3.</p>
<p><strong>Formato HeirShare</strong> — Cada fragmento é um artefato autocontido e serializável
com:</p>
<ul>
<li>Versão do formato (v1) para compatibilidade futura</li>
<li>Índice do fragmento (1..N) e metadados de limiar/total</li>
<li>ID de sessão (8 bytes aleatórios) — impede mistura de fragmentos de sessões
diferentes</li>
<li>Impressão digital do dono (primeiros 8 bytes do hash BLAKE3 da chave pública
Ed25519)</li>
<li>Dados do fragmento (os y-values de Shamir, mesmo comprimento do segredo)</li>
<li>Checksum BLAKE3 sobre todos os campos anteriores</li>
</ul>
<p>Os fragmentos são serializados em dois formatos: <strong>MessagePack</strong> (binário
compacto, para uso programático) e <strong>texto base64</strong> (legível por humanos, para
impressão e armazenamento físico). O formato texto inclui um cabeçalho com
metadados e delimitadores:</p>
<pre><code>--- TESSERAS HEIR SHARE ---
Format: v1
Owner: a1b2c3d4e5f6a7b8 (fingerprint)
Share: 1 of 3 (threshold: 2)
Session: 9f8e7d6c5b4a3210
Created: 2026-02-15
<dados MessagePack codificados em base64>
--- END HEIR SHARE ---
</code></pre>
<p>Este formato é projetado para ser impresso em papel, armazenado em um cofre
bancário ou gravado em metal. O cabeçalho é informacional — apenas o payload
base64 é analisado durante a reconstrução.</p>
<p><strong>Integração com CLI</strong> (<code>tesseras-cli/src/commands/heir.rs</code>) — Três novos
subcomandos:</p>
<ul>
<li><code>tes heir create</code> — divide sua identidade Ed25519 em fragmentos de herdeiros.
Solicita confirmação (sua identidade completa está em jogo), gera arquivos
<code>.bin</code> e <code>.txt</code> para cada fragmento e escreve <code>heir_meta.json</code> no diretório de
identidade.</li>
<li><code>tes heir reconstruct</code> — carrega arquivos de fragmentos (detecta
automaticamente formato binário vs texto), valida consistência, reconstrói o
segredo, deriva o par de chaves Ed25519 e opcionalmente o instala em
<code>~/.tesseras/identity/</code> (com backup automático da identidade existente).</li>
<li><code>tes heir info</code> — exibe metadados do fragmento e verifica o checksum sem expor
nenhum material secreto.</li>
</ul>
<p><strong>Formato do blob secreto</strong> — As chaves de identidade são serializadas em um
blob versionado antes da divisão: um byte de versão (0x01), um byte de flags
(0x00 para somente Ed25519), seguido da chave secreta Ed25519 de 32 bytes. Isso
deixa espaço para expansão futura quando as chaves privadas X25519 e ML-KEM-768
forem integradas ao sistema de fragmentos de herdeiros.</p>
<p><strong>Testes</strong> — 20 testes unitários para ShamirSplitter (roundtrip, todas as
combinações de fragmentos, fragmentos insuficientes, dono errado, sessão errada,
limite threshold-1, segredos grandes até o tamanho de chave ML-KEM-768). 7
testes unitários para aritmética GF(256) (propriedades de campo exaustivas). 3
testes baseados em propriedades com proptest (segredos arbitrários até 5000
bytes, configurações T-de-N arbitrárias, verificação de segurança
informação-teórica). Testes de roundtrip de serialização para ambos os formatos
MessagePack e texto base64. 2 testes de integração cobrindo o ciclo de vida
completo de herdeiros: gerar identidade, dividir em fragmentos, serializar,
desserializar, reconstruir, verificar par de chaves e assinar/verificar com
chaves reconstruídas.</p>
<h2 id="decisoes-de-arquitetura">Decisões de arquitetura</h2>
<ul>
<li><strong>GF(256) ao invés de GF(primo)</strong>: usamos GF(256) ao invés de um corpo primo
porque ele mapeia naturalmente para bytes — cada elemento é um único byte,
cada fragmento tem o mesmo comprimento do segredo. Sem aritmética de inteiros
grandes, sem redução modular, sem padding. Esta é a mesma abordagem usada pela
maioria das implementações reais de Shamir, incluindo SSSS e Hashicorp Vault.</li>
<li><strong>Tabelas de lookup em tempo de compilação</strong>: as tabelas LOG e EXP para
GF(256) são computadas em tempo de compilação usando <code>const fn</code>. Isso
significa zero custo de inicialização em tempo de execução e operações em
tempo constante via consulta a tabelas ao invés de loops.</li>
<li><strong>ID de sessão previne mistura entre sessões</strong>: cada chamada a <code>split()</code> gera
um novo ID de sessão aleatório. Se um herdeiro acidentalmente usar fragmentos
de duas sessões diferentes de divisão (por exemplo, antes e depois de uma
rotação de chaves), a reconstrução falha de forma limpa com um erro de
validação ao invés de produzir dados corrompidos.</li>
<li><strong>Checksums BLAKE3 detectam corrupção</strong>: cada fragmento inclui um checksum
BLAKE3 sobre seu conteúdo. Isso captura degradação de bits, erros de
transmissão e truncamento acidental antes de qualquer tentativa de
reconstrução. Um fragmento impresso em papel e escaneado via OCR vai falhar no
checksum se um único caractere estiver errado.</li>
<li><strong>Impressão digital do dono para identificação</strong>: os fragmentos incluem os
primeiros 8 bytes de BLAKE3(chave pública Ed25519) como impressão digital.
Isso permite aos herdeiros verificar a qual identidade um fragmento pertence
sem revelar a chave pública completa. Durante a reconstrução, a impressão
digital é verificada contra a chave recuperada.</li>
<li><strong>Formato duplo para resiliência</strong>: ambos os formatos binário (MessagePack) e
texto (base64) são gerados porque mídias físicas têm modos de falha diferentes
de armazenamento digital. Um pendrive pode falhar; papel sobrevive. Um QR code
pode ficar ilegível; texto base64 pode ser digitado manualmente.</li>
<li><strong>Versionamento do blob</strong>: o segredo é envolvido em um blob versionado
(versão + flags + material de chave) para que versões futuras possam incluir
chaves adicionais (X25519, ML-KEM-768) sem quebrar compatibilidade com
fragmentos existentes.</li>
</ul>
<h2 id="o-que-vem-a-seguir">O que vem a seguir</h2>
<ul>
<li><strong>Fase 4 continuada: Resiliência e Escala</strong> — NAT traversal avançado
(STUN/TURN), ajuste de performance (pool de conexões, cache de fragmentos,
SQLite WAL), auditorias de segurança, integração de nós institucionais,
empacotamento para sistemas operacionais</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>Com Shamir's Secret Sharing, Tesseras fecha a última lacuna crítica na
preservação a longo prazo. Suas memórias sobrevivem a falhas de infraestrutura
através de erasure coding. Sua privacidade sobrevive a computadores quânticos
através de criptografia híbrida. E agora, sua identidade sobrevive a você —
passada adiante para as pessoas que você escolheu, exigindo a cooperação delas
para desbloquear o que você deixou para trás.</p>
Fase 4: Criptografia e Tesseras Seladas2026-02-14T16:00:00+00:002026-02-14T16:00:00+00:00
Unknown
https://tesseras.net/pt-br/news/phase4-encryption-sealed/<p>Algumas memórias não são para todos. Um diário privado, uma carta para ser
aberta em 2050, um segredo de família selado até que os netos tenham idade
suficiente. Até agora, toda tessera na rede era aberta. A Fase 4 muda isso:
Tesseras agora criptografa conteúdo privado e selado com um esquema
criptográfico híbrido projetado para resistir tanto a ataques clássicos quanto
quânticos.</p>
<p>O princípio continua o mesmo — criptografar o mínimo possível. Memórias públicas
precisam de disponibilidade, não de sigilo. Mas quando alguém cria uma tessera
privada ou selada, o conteúdo agora é trancado por criptografia AES-256-GCM com
chaves protegidas por um mecanismo híbrido de encapsulamento de chaves
combinando X25519 e ML-KEM-768. Ambos os algoritmos precisam ser quebrados para
acessar o conteúdo.</p>
<h2 id="o-que-foi-construido">O que foi construído</h2>
<p><strong>Encriptador AES-256-GCM</strong> (<code>tesseras-crypto/src/encryption.rs</code>) — Criptografia
simétrica de conteúdo com nonces aleatórios de 12 bytes e dados autenticados
associados (AAD). O AAD vincula o texto cifrado ao seu contexto: para tesseras
privadas, o hash do conteúdo é incluído; para tesseras seladas, tanto o hash do
conteúdo quanto o timestamp <code>open_after</code> são vinculados no AAD. Isso significa
que mover texto cifrado entre tesseras com datas de abertura diferentes causa
falha na decriptação — você não consegue enganar o sistema para abrir uma
memória selada antecipadamente trocando o texto cifrado para uma tessera com uma
data de selo anterior.</p>
<p><strong>Mecanismo Híbrido de Encapsulamento de Chaves</strong> (<code>tesseras-crypto/src/kem.rs</code>)
— Troca de chaves usando X25519 (Diffie-Hellman clássico em curva elíptica)
combinado com ML-KEM-768 (o KEM pós-quântico baseado em reticulados padronizado
pelo NIST, anteriormente Kyber). Ambos os segredos compartilhados são combinados
via <code>blake3::derive_key</code> com uma string de contexto fixa ("tesseras hybrid kem
v1") para produzir uma única chave de criptografia de conteúdo de 256 bits. Isso
segue a mesma filosofia "dual desde o início" das assinaturas duplas do projeto
(Ed25519 + ML-DSA): se qualquer algoritmo for quebrado no futuro, o outro ainda
protege o conteúdo.</p>
<p><strong>Envelope de Chave Selada</strong> (<code>tesseras-crypto/src/sealed.rs</code>) — Encapsula uma
chave de criptografia de conteúdo usando o KEM híbrido, para que apenas o dono
da tessera possa recuperá-la. O KEM produz uma chave de transporte, que é XORed
com a chave de conteúdo para produzir uma chave encapsulada armazenada junto ao
texto cifrado do KEM. Ao desselar, o dono decapsula o texto cifrado do KEM para
recuperar a chave de transporte, depois faz XOR novamente para recuperar a chave
de conteúdo.</p>
<p><strong>Publicação de Chave</strong> (<code>tesseras-crypto/src/sealed.rs</code>) — Um artefato assinado
independente para publicar a chave de conteúdo de uma tessera selada após a data
<code>open_after</code> ter passado. O dono assina a chave de conteúdo, o hash da tessera e
o timestamp de publicação com suas chaves duais (Ed25519, com placeholder
ML-DSA). O manifesto permanece imutável — a publicação da chave é um documento
separado. Outros nós verificam a assinatura contra a chave pública do dono antes
de usar a chave publicada para decriptar o conteúdo.</p>
<p><strong>EncryptionContext</strong> (<code>tesseras-core/src/enums.rs</code>) — Um tipo de domínio que
representa o contexto AAD para criptografia. Ele vive em tesseras-core e não em
tesseras-crypto porque é um conceito de domínio (não um detalhe de implementação
criptográfica). O método <code>to_aad_bytes()</code> produz serialização determinística: um
byte de tag (0x00 para Private, 0x01 para Sealed), seguido do hash de conteúdo
e, para Sealed, o timestamp <code>open_after</code> como i64 little-endian.</p>
<p><strong>Validação de domínio</strong> (<code>tesseras-core/src/service.rs</code>) —
<code>TesseraService::create()</code> agora rejeita tesseras Sealed e Private que não
fornecem chaves de criptografia. Esta é uma validação no nível de domínio: a
camada de serviço garante que você não pode criar uma memória selada sem a
maquinaria criptográfica para protegê-la. A mensagem de erro é clara: "missing
encryption keys for visibility sealed until 2050-01-01."</p>
<p><strong>Atualizações de tipos do core</strong> — <code>TesseraIdentity</code> agora inclui um campo
opcional <code>encryption_public: Option<HybridEncryptionPublic></code> contendo tanto as
chaves públicas X25519 quanto ML-KEM-768. <code>KeyAlgorithm</code> ganhou as variantes
<code>X25519</code> e <code>MlKem768</code>. O layout do sistema de arquivos de identidade agora
suporta <code>node.x25519.key</code>/<code>.pub</code> e <code>node.mlkem768.key</code>/<code>.pub</code>.</p>
<p><strong>Testes</strong> — 8 testes unitários para AES-256-GCM (roundtrip, chave errada, texto
cifrado adulterado, AAD errado, falha de decriptação cross-context, nonces
únicos, mais 2 testes baseados em propriedades para payloads arbitrários e
unicidade de nonces). 5 testes unitários para HybridKem (roundtrip, par de
chaves errado, X25519 adulterado, determinismo do KDF, mais 1 teste baseado em
propriedades). 4 testes unitários para SealedKeyEnvelope e KeyPublication. 2
testes de integração cobrindo o ciclo de vida completo de tesseras seladas e
privadas: gerar chaves, criar chave de conteúdo, criptografar, selar, desselar,
decriptar, publicar chave e verificar — o ciclo completo.</p>
<h2 id="decisoes-de-arquitetura">Decisões de arquitetura</h2>
<ul>
<li><strong>KEM híbrido desde o início</strong>: X25519 + ML-KEM-768 segue a mesma filosofia
das assinaturas duplas. Não sabemos quais suposições criptográficas se
manterão ao longo dos milênios, então combinamos algoritmos clássicos e
pós-quânticos. O custo é ~1,2 KB de material de chave adicional por identidade
— trivial comparado às fotos e vídeos em uma tessera.</li>
<li><strong>BLAKE3 para KDF</strong>: ao invés de adicionar <code>hkdf</code> + <code>sha2</code> como novas
dependências, usamos <code>blake3::derive_key</code> com uma string de contexto fixa. O
modo de derivação de chaves do BLAKE3 é especificamente projetado para este
caso de uso, e o projeto já depende do BLAKE3 para hashing de conteúdo.</li>
<li><strong>Manifestos imutáveis</strong>: quando a data <code>open_after</code> de uma tessera selada
passa, a chave de conteúdo é publicada como um artefato assinado separado
(<code>KeyPublication</code>), não modificando o manifesto. Isso preserva a natureza
append-only e endereçada por conteúdo das tesseras. O manifesto foi assinado
no momento da criação e nunca muda.</li>
<li><strong>Vinculação AAD previne troca de texto cifrado</strong>: o <code>EncryptionContext</code>
vincula tanto o hash de conteúdo quanto (para tesseras seladas) o timestamp
<code>open_after</code> nos dados autenticados do AES-GCM. Um atacante que copie conteúdo
criptografado de uma tessera "selada até 2050" para uma tessera "selada até
2025" vai descobrir que a decriptação falha — o AAD não corresponde mais.</li>
<li><strong>Encapsulamento de chave por XOR</strong>: o envelope de chave selada usa um XOR
simples da chave de conteúdo com a chave de transporte derivada do KEM, ao
invés de uma camada adicional de AES-GCM. Como a chave de transporte é um
valor aleatório fresco do KEM e é usada exatamente uma vez, o XOR é
informação-teoricamente seguro para este caso de uso específico e evita
complexidade desnecessária.</li>
<li><strong>Validação de domínio, não validação de storage</strong>: a verificação de "chaves
de criptografia ausentes" vive em <code>TesseraService::create()</code>, não na camada de
storage. Isso segue o padrão de arquitetura hexagonal: regras de domínio são
aplicadas na fronteira de serviço, não espalhadas pelos adaptadores.</li>
</ul>
<h2 id="o-que-vem-a-seguir">O que vem a seguir</h2>
<ul>
<li><strong>Fase 4 continuada: Resiliência e Escala</strong> — Shamir's Secret Sharing para
distribuição de chaves de herdeiros, NAT traversal avançado (STUN/TURN),
ajuste de performance, auditorias de segurança, empacotamento para sistemas
operacionais</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>Tesseras seladas fazem do Tesseras uma verdadeira cápsula do tempo. Um pai agora
pode gravar uma mensagem para o neto que ainda não nasceu, selá-la até 2060 e
saber que o envelope criptográfico vai resistir — mesmo que os computadores
quânticos do futuro tentem abri-lo antes da hora.</p>
Fase 3: Memórias nas Suas Mãos2026-02-14T14:00:00+00:002026-02-14T14:00:00+00:00
Unknown
https://tesseras.net/pt-br/news/phase3-api-and-apps/<p>As pessoas agora podem segurar suas memórias nas próprias mãos. A Fase 3 entrega
o que as fases anteriores construíram: um app mobile onde alguém baixa o
Tesseras, cria uma identidade, tira uma foto, e aquela memória entra na rede de
preservação. Sem contas na nuvem, sem assinaturas, sem nenhuma empresa entre
você e suas memórias.</p>
<h2 id="o-que-foi-construido">O que foi construído</h2>
<p><strong>tesseras-embedded</strong> — Um nó P2P completo que roda dentro de um app mobile. A
struct <code>EmbeddedNode</code> é dona de um runtime Tokio, banco SQLite, transporte QUIC,
engine Kademlia DHT, serviço de replicação e serviço de tessera — a mesma stack
do daemon desktop, compilada como biblioteca compartilhada. Um padrão singleton
global (<code>Mutex<Option<EmbeddedNode>></code>) garante um único nó por ciclo de vida do
app. Ao iniciar, ele abre o banco de dados, executa migrações, carrega ou gera
uma identidade Ed25519 com proof-of-work para o node ID, faz bind QUIC numa
porta efêmera, conecta DHT e replicação, e inicia o loop de reparo. Ao parar,
envia um sinal de shutdown e drena graciosamente.</p>
<p>Onze funções FFI são expostas para Dart via flutter_rust_bridge: ciclo de vida
(<code>node_start</code>, <code>node_stop</code>, <code>node_is_running</code>), identidade (<code>create_identity</code>,
<code>get_identity</code>), memórias (<code>create_memory</code>, <code>get_timeline</code>, <code>get_memory</code>) e
status da rede (<code>get_network_stats</code>, <code>get_replication_status</code>). Todos os tipos
que cruzam a fronteira FFI são structs planas com apenas <code>String</code>,
<code>Option<String></code>, <code>Vec<String></code> e primitivos — sem trait objects, sem generics,
sem lifetimes.</p>
<p>Quatro módulos adaptadores fazem a ponte entre as ports do core e as
implementações concretas: <code>Blake3HasherAdapter</code>,
<code>Ed25519SignerAdapter</code>/<code>Ed25519VerifierAdapter</code> para criptografia,
<code>DhtPortAdapter</code> para operações DHT, e <code>ReplicationHandlerAdapter</code> para RPCs de
fragmentos e atestação recebidos.</p>
<p>A feature flag <code>bundled-sqlite</code> compila o SQLite a partir do código-fonte,
necessário para Android e iOS onde a biblioteca do sistema pode não estar
disponível. A configuração do Cargokit passa essa flag automaticamente em builds
de debug e release.</p>
<p><strong>App Flutter</strong> — Uma aplicação Material Design 3 com gerenciamento de estado
Riverpod, direcionada para Android, iOS, Linux, macOS e Windows a partir de uma
única base de código.</p>
<p>O <em>fluxo de onboarding</em> são três telas: uma tela de boas-vindas explicando o
projeto em uma frase ("Preserve suas memórias através dos milênios. Sem nuvem.
Sem empresa."), uma tela de criação de identidade que dispara a geração do par
de chaves Ed25519 em Rust, e uma tela de confirmação mostrando o nome do usuário
e a identidade criptográfica.</p>
<p>A <em>tela de timeline</em> exibe memórias em ordem cronológica reversa com previews de
imagem, texto de contexto e chips para tipo de memória e visibilidade.
Pull-to-refresh recarrega a partir do nó Rust. Um floating action button abre a
<em>tela de criação de memória</em>, que suporta seleção de foto da galeria ou câmera
via <code>image_picker</code>, texto de contexto opcional, dropdowns de tipo de memória e
visibilidade, e tags separadas por vírgula. Criar uma memória chama o FFI Rust
sincronamente, depois retorna à timeline.</p>
<p>A <em>tela de rede</em> mostra dois cards: status do nó (contagem de peers, tamanho da
DHT, estado de bootstrap, uptime) e saúde da replicação (total de fragmentos,
fragmentos saudáveis, fragmentos em reparo, fator de replicação). A <em>tela de
configurações</em> exibe a identidade do usuário — nome, node ID truncado, chave
pública truncada e data de criação.</p>
<p>Três providers Riverpod gerenciam o estado: <code>nodeProvider</code> inicia o nó embarcado
ao abrir o app usando o diretório de documentos e para ao fazer dispose;
<code>identityProvider</code> carrega o perfil existente ou cria um novo;
<code>timelineProvider</code> busca a lista de memórias com paginação.</p>
<p><strong>Testes</strong> — 9 testes unitários Rust em tesseras-embedded cobrindo ciclo de vida
do nó (start/stop sem panic), persistência de identidade entre reinícios, ciclos
de reinício sem corrupção do SQLite, streaming de eventos de rede, recuperação
de estatísticas, criação de memória e recuperação da timeline, e busca de
memória individual por hash. 2 testes Flutter: um teste de integração
verificando inicialização do Rust e startup do app, e um smoke test de widget.</p>
<h2 id="decisoes-de-arquitetura">Decisões de arquitetura</h2>
<ul>
<li><strong>Nó embarcado, não cliente-servidor</strong>: o celular roda a stack P2P completa,
não um thin client conversando com um daemon remoto. Isso significa que
memórias são preservadas mesmo sem internet. Usuários com um Raspberry Pi ou
VPS podem opcionalmente conectar o app ao seu daemon via GraphQL para maior
disponibilidade, mas não é obrigatório.</li>
<li><strong>FFI síncrono</strong>: todas as funções flutter_rust_bridge são marcadas como
<code>#[frb(sync)]</code> e bloqueiam no runtime Tokio interno. Isso simplifica o lado
Dart (sem complexidade de bridge assíncrono) enquanto o lado Rust lida com
concorrência internamente. A UI thread do Flutter permanece responsiva porque
o Riverpod envolve as chamadas em providers assíncronos.</li>
<li><strong>Singleton global</strong>: um global <code>Mutex<Option<EmbeddedNode>></code> garante que o
ciclo de vida do nó seja previsível — um start, um stop, sem race conditions.
Plataformas mobile matam processos agressivamente, então simplicidade no
gerenciamento de ciclo de vida é uma feature.</li>
<li><strong>Tipos FFI planos</strong>: nenhuma abstração Rust vaza pela fronteira FFI. Todo
tipo é uma struct plana com strings e números. Isso torna os bindings Dart
auto-gerados confiáveis e fáceis de debugar.</li>
<li><strong>Onboarding de três telas</strong>: a criação de identidade é o único passo
obrigatório. Sem email, sem senha, sem registro em servidor. O app gera uma
identidade criptográfica localmente e está pronto para uso.</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> — NAT traversal avançado (STUN/TURN),
Shamir's Secret Sharing para herdeiros, tesseras seladas com criptografia
temporal, ajuste de performance, auditorias de segurança, empacotamento para
Alpine/Arch/Debian/FreeBSD/OpenBSD</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 infraestrutura está completa. A rede existe, a replicação funciona, e agora
qualquer pessoa com um celular pode participar. O que resta é fortalecer o que
temos e abrir para o mundo.</p>
Reed-Solomon: Como o Tesseras Sobrevive à Perda de Dados2026-02-14T14:00:00+00:002026-02-14T14:00:00+00:00
Unknown
https://tesseras.net/pt-br/news/reed-solomon/<p>Seu disco rígido vai morrer. Seu provedor de nuvem vai pivotar. O array RAID no
seu armário vai sobreviver ao controlador, mas não ao dono. Se uma memória está
armazenada em exatamente um lugar, ela tem exatamente uma forma de se perder
para sempre.</p>
<p>Tesseras é uma rede que mantém memórias humanas vivas através de ajuda mútua. O
mecanismo central de sobrevivência é a <strong>codificação de apagamento
Reed-Solomon</strong> — uma técnica emprestada da comunicação espacial profunda que nos
permite reconstruir dados mesmo quando pedaços desaparecem.</p>
<h2 id="o-que-e-reed-solomon">O que é Reed-Solomon?</h2>
<p>Reed-Solomon é uma família de códigos corretores de erros inventada por Irving
Reed e Gustave Solomon em 1960. O caso de uso original era corrigir erros em
dados transmitidos por canais ruidosos — pense na Voyager enviando fotos de
Júpiter, ou num CD tocando apesar de arranhões.</p>
<p>A ideia-chave: se você adicionar redundância cuidadosamente calculada aos seus
dados <em>antes</em> que algo dê errado, você pode recuperar o original mesmo depois de
perder alguns pedaços.</p>
<p>Eis a intuição. Suponha que você tenha um polinômio de grau 2 — uma parábola.
Você precisa de 3 pontos para defini-lo de forma única. Mas se você avaliá-lo em
5 pontos, pode perder quaisquer 2 desses 5 e ainda reconstruir o polinômio a
partir dos 3 restantes. Reed-Solomon generaliza essa ideia para trabalhar sobre
corpos finitos (corpos de Galois), onde o "polinômio" são seus dados e os
"pontos de avaliação" são seus fragmentos.</p>
<p>Em termos concretos:</p>
<ol>
<li><strong>Divida</strong> seus dados em <em>k</em> shards de dados</li>
<li><strong>Calcule</strong> <em>m</em> shards de paridade a partir dos shards de dados</li>
<li><strong>Distribua</strong> todos os <em>k + m</em> shards em diferentes locais</li>
<li><strong>Reconstrua</strong> os dados originais a partir de quaisquer <em>k</em> dos <em>k + m</em>
shards</li>
</ol>
<p>Você pode perder até <em>m</em> shards — quaisquer <em>m</em>, de dados ou paridade, em
qualquer combinação — e ainda recuperar tudo.</p>
<h2 id="por-que-nao-simplesmente-fazer-copias">Por que não simplesmente fazer cópias?</h2>
<p>A abordagem ingênua para redundância é a replicação: faça 3 cópias, armazene-as
em 3 lugares. Isso dá tolerância a 2 falhas ao custo de 3x o seu armazenamento.</p>
<p>Reed-Solomon é dramaticamente mais eficiente:</p>
<table><thead><tr><th>Estratégia</th><th style="text-align: right">Overhead de armazenamento</th><th style="text-align: right">Falhas toleradas</th></tr></thead><tbody>
<tr><td>Replicação 3x</td><td style="text-align: right">200%</td><td style="text-align: right">2 de 3</td></tr>
<tr><td>Reed-Solomon (16,8)</td><td style="text-align: right">50%</td><td style="text-align: right">8 de 24</td></tr>
<tr><td>Reed-Solomon (48,24)</td><td style="text-align: right">50%</td><td style="text-align: right">24 de 72</td></tr>
</tbody></table>
<p>Com 16 shards de dados e 8 de paridade, você usa 50% de armazenamento extra mas
pode sobreviver à perda de um terço de todos os fragmentos. Para alcançar a
mesma tolerância a falhas só com replicação, você precisaria de 3x o
armazenamento.</p>
<p>Para uma rede que visa preservar memórias ao longo de décadas e séculos, essa
eficiência não é um luxo — é a diferença entre um sistema viável e um que se
afoga no próprio overhead.</p>
<h2 id="como-o-tesseras-usa-reed-solomon">Como o Tesseras usa Reed-Solomon</h2>
<p>Nem todos os dados merecem o mesmo tratamento. Uma memória de texto de 500 bytes
e um vídeo de 100 MB têm necessidades de redundância muito diferentes. O
Tesseras usa uma estratégia de fragmentação em três camadas:</p>
<p><strong>Small (< 4 MB)</strong> — Replicação do arquivo inteiro para 7 pares. Para tesseras
pequenas, o overhead da codificação de apagamento (tempo de codificação,
gerenciamento de fragmentos, lógica de reconstrução) supera seus benefícios.
Cópias simples são mais rápidas e mais simples.</p>
<p><strong>Medium (4–256 MB)</strong> — 16 shards de dados + 8 de paridade = 24 fragmentos no
total. Cada fragmento tem aproximadamente 1/16 do tamanho original. Quaisquer 16
dos 24 fragmentos reconstroem o original. Distribuídos entre 7 pares.</p>
<p><strong>Large (≥ 256 MB)</strong> — 48 shards de dados + 24 de paridade = 72 fragmentos no
total. Maior contagem de shards significa fragmentos individuais menores (mais
fáceis de transferir e armazenar) e maior tolerância absoluta a falhas. Também
distribuídos entre 7 pares.</p>
<p>A implementação usa o crate <code>reed-solomon-erasure</code> operando sobre GF(2⁸) — o
mesmo corpo de Galois usado em códigos QR e CDs. Cada fragmento carrega um
checksum BLAKE3 para que a corrupção seja detectada imediatamente, não propagada
silenciosamente.</p>
<pre><code>Tessera (álbum de fotos de 120 MB)
↓ codificar
16 shards de dados (7,5 MB cada) + 8 shards de paridade (7,5 MB cada)
↓ distribuir
24 fragmentos entre 7 pares (diversidade de sub-rede)
↓ quaisquer 16 fragmentos
Tessera original recuperada
</code></pre>
<h2 id="os-desafios">Os desafios</h2>
<p>Reed-Solomon resolve o problema matemático da redundância. Os desafios de
engenharia estão em tudo ao redor.</p>
<h3 id="rastreamento-de-fragmentos">Rastreamento de fragmentos</h3>
<p>Cada fragmento precisa ser localizável. O Tesseras usa uma DHT Kademlia para
descoberta de pares e mapeamento de fragmentos para pares. Quando um nó fica
offline, seus fragmentos precisam ser recriados e distribuídos para novos pares.
Isso significa rastrear quais fragmentos existem, onde estão e se ainda estão
intactos — numa rede sem autoridade central.</p>
<h3 id="corrupcao-silenciosa">Corrupção silenciosa</h3>
<p>Um fragmento que retorna dados errados é pior que um ausente — pelo menos um
fragmento ausente é honestamente ausente. O Tesseras aborda isso com
verificações de saúde baseadas em atestação: o loop de reparo periodicamente
pede aos detentores de fragmentos que provem posse retornando checksums BLAKE3.
Se um checksum não bater, o fragmento é tratado como perdido.</p>
<h3 id="falhas-correlacionadas">Falhas correlacionadas</h3>
<p>Se todos os 24 fragmentos de uma tessera caírem em máquinas no mesmo datacenter,
uma única queda de energia os elimina todos. A matemática do Reed-Solomon assume
falhas independentes. O Tesseras impõe <strong>diversidade de sub-rede</strong> durante a
distribuição: no máximo 2 fragmentos por sub-rede /24 IPv4 (ou prefixo /48
IPv6). Isso espalha fragmentos por diferentes infraestruturas físicas.</p>
<h3 id="velocidade-de-reparo-vs-carga-na-rede">Velocidade de reparo vs. carga na rede</h3>
<p>Quando um par fica offline, o relógio começa a contar. Fragmentos perdidos
precisam ser recriados antes que mais falhas se acumulem. Mas reparo agressivo
inunda a rede. O Tesseras equilibra isso com um loop de reparo configurável
(padrão: a cada 24 horas com 2 horas de jitter) e limites de transferências
simultâneas (padrão: 4 transferências simultâneas). O jitter previne tempestades
de reparo onde cada nó verifica seus fragmentos no mesmo momento.</p>
<h3 id="gerenciamento-de-chaves-a-longo-prazo">Gerenciamento de chaves a longo prazo</h3>
<p>Reed-Solomon protege contra perda de dados, não contra perda de acesso. Se uma
tessera é criptografada (visibilidade privada ou selada), você precisa da chave
de descriptografia para tornar os dados recuperados úteis. O Tesseras separa
essas preocupações: codificação de apagamento cuida da disponibilidade, enquanto
o Compartilhamento de Segredo de Shamir (uma fase futura) cuidará da
distribuição de chaves entre herdeiros. A filosofia de design do projeto —
criptografar o mínimo possível — mantém o problema de gerenciamento de chaves
pequeno.</p>
<h3 id="limitacoes-do-corpo-de-galois">Limitações do corpo de Galois</h3>
<p>O corpo GF(2⁸) limita o número total de shards a 255 (dados + paridade
combinados). Para o Tesseras, isso não é uma restrição prática — mesmo a camada
Large usa apenas 72 shards. Mas significa que arquivos extremamente grandes com
milhares de fragmentos exigiriam um corpo diferente ou um esquema de codificação
em camadas.</p>
<h3 id="compatibilidade-evolutiva-do-codec">Compatibilidade evolutiva do codec</h3>
<p>Uma tessera codificada hoje precisa ser decodificável em 50 anos. Reed-Solomon
sobre GF(2⁸) é um dos algoritmos mais amplamente implementados na computação —
está em todo leitor de CD, em todo scanner de código QR, em toda sonda espacial.
Essa ubiquidade é em si uma estratégia de sobrevivência. O algoritmo não será
esquecido porque metade da infraestrutura do mundo depende dele.</p>
<h2 id="o-quadro-geral">O quadro geral</h2>
<p>Reed-Solomon é uma peça de um quebra-cabeça maior. Ele trabalha em conjunto com:</p>
<ul>
<li><strong>DHT Kademlia</strong> para encontrar pares e rotear fragmentos</li>
<li><strong>Checksums BLAKE3</strong> para verificação de integridade</li>
<li><strong>Reciprocidade bilateral</strong> para troca justa de armazenamento (sem blockchain)</li>
<li><strong>Diversidade de sub-rede</strong> para independência de falhas</li>
<li><strong>Reparo automático</strong> para manter a redundância ao longo do tempo</li>
</ul>
<p>Nenhuma técnica isolada faz memórias sobreviverem. Reed-Solomon garante que
dados <em>podem</em> ser recuperados. A DHT garante que fragmentos <em>podem ser
encontrados</em>. A reciprocidade garante que pares <em>querem ajudar</em>. O reparo
garante que nada disso se degrade com o tempo.</p>
<p>Uma tessera é uma aposta de que a soma desses mecanismos, rodando em muitas
máquinas independentes operadas por muitas pessoas independentes, é mais durável
que qualquer instituição isolada. Reed-Solomon é a fundação matemática dessa
aposta.</p>
Fase 2: Memórias Sobrevivem2026-02-14T12:00:00+00:002026-02-14T12:00:00+00:00
Unknown
https://tesseras.net/pt-br/news/phase2-replication/<p>Uma tessera não está mais presa a uma única máquina. A Fase 2 entrega a camada
de replicação: os dados são divididos em fragmentos com codificação de
apagamento, distribuídos entre múltiplos pares e reparados automaticamente
quando nós ficam offline. Um livro-razão de reciprocidade bilateral garante
troca justa de armazenamento — sem blockchain, sem tokens.</p>
<h2 id="o-que-foi-construido">O que foi construído</h2>
<p><strong>tesseras-core</strong> (atualizado) — Novos tipos de domínio de replicação:
<code>FragmentPlan</code> (seleciona a camada de fragmentação baseada no tamanho da
tessera), <code>FragmentId</code> (hash da tessera + índice + contagem de shards +
checksum), <code>FragmentEnvelope</code> (fragmento com seus metadados para transporte na
rede), <code>FragmentationTier</code> (Small/Medium/Large), <code>Attestation</code> (prova de que um
nó possui um fragmento em um dado momento) e <code>ReplicateAck</code> (confirmação de
recebimento de fragmento). Três novas traits de porta definem os limites
hexagonais: <code>DhtPort</code> (encontrar pares, replicar fragmentos, solicitar
atestações, ping), <code>FragmentStore</code> (armazenar/ler/deletar/listar/verificar
fragmentos) e <code>ReciprocityLedger</code> (registrar trocas de armazenamento, consultar
saldos, encontrar melhores pares). O tamanho máximo de uma tessera é 1 GB.</p>
<p><strong>tesseras-crypto</strong> (atualizado) — O <code>ReedSolomonCoder</code> existente agora alimenta
a codificação de fragmentos. Os dados são divididos em shards, shards de
paridade são computados, e qualquer combinação de shards de dados pode
reconstruir o original — desde que o número de shards ausentes não exceda a
contagem de paridade.</p>
<p><strong>tesseras-storage</strong> (atualizado) — Dois novos adaptadores:</p>
<ul>
<li><code>FsFragmentStore</code> — armazena dados de fragmentos como arquivos em disco
(<code>{raiz}/{hash_tessera}/{indice:03}.shard</code>) com um índice de metadados SQLite
rastreando hash da tessera, índice do shard, contagem de shards, checksum e
tamanho em bytes. A verificação recalcula o hash BLAKE3 e compara com o
checksum armazenado.</li>
<li><code>SqliteReciprocityLedger</code> — contabilidade bilateral de armazenamento em
SQLite. Cada par tem uma linha rastreando bytes armazenados para eles e bytes
que eles armazenam para nós. A coluna <code>balance</code> é uma coluna gerada
(<code>bytes_they_store_for_us - bytes_stored_for_them</code>). UPSERT garante incremento
atômico dos contadores.</li>
</ul>
<p>Nova migração (<code>002_replication.sql</code>) adiciona tabelas para fragmentos, planos
de fragmentação, detentores, mapeamentos detentor-fragmento e saldos de
reciprocidade.</p>
<p><strong>tesseras-dht</strong> (atualizado) — Quatro novas variantes de mensagem: <code>Replicate</code>
(enviar um envelope de fragmento), <code>ReplicateAck</code> (confirmar recebimento),
<code>AttestRequest</code> (pedir a um nó que prove que possui os fragmentos de uma
tessera) e <code>AttestResponse</code> (retornar atestação com checksums e timestamp). O
engine trata essas mensagens em seu loop de despacho.</p>
<p><strong>tesseras-replication</strong> — O novo crate, com cinco módulos:</p>
<ul>
<li>
<p><em>Codificação de fragmentos</em> (<code>fragment.rs</code>): <code>encode_tessera()</code> seleciona a
camada de fragmentação baseada no tamanho e então chama a codificação
Reed-Solomon para as camadas Medium e Large. Três camadas:</p>
<ul>
<li><strong>Small</strong> (< 4 MB): replicação do arquivo inteiro para r=7 pares, sem
codificação de apagamento</li>
<li><strong>Medium</strong> (4–256 MB): 16 shards de dados + 8 de paridade, distribuídos
entre r=7 pares</li>
<li><strong>Large</strong> (≥ 256 MB): 48 shards de dados + 24 de paridade, distribuídos
entre r=7 pares</li>
</ul>
</li>
<li>
<p><em>Distribuição</em> (<code>distributor.rs</code>): filtragem de diversidade de sub-rede limita
pares por sub-rede /24 IPv4 (ou prefixo /48 IPv6) para evitar falhas
correlacionadas. Se todos os seus fragmentos caírem no mesmo rack, uma única
queda de energia os elimina.</p>
</li>
<li>
<p><em>Serviço</em> (<code>service.rs</code>): <code>ReplicationService</code> é o orquestrador.
<code>replicate_tessera()</code> codifica os dados, encontra os pares mais próximos via
DHT, aplica diversidade de sub-rede e distribui fragmentos em round-robin.
<code>receive_fragment()</code> valida o checksum BLAKE3, verifica o saldo de
reciprocidade (rejeita se o déficit do remetente exceder o limite
configurado), armazena o fragmento e atualiza o livro-razão.
<code>handle_attestation_request()</code> lista os fragmentos locais e calcula seus
checksums como prova de posse.</p>
</li>
<li>
<p><em>Reparo</em> (<code>repair.rs</code>): <code>check_tessera_health()</code> solicita atestações dos
detentores conhecidos, recorre ao ping para nós não responsivos, verifica a
integridade local dos fragmentos e retorna uma de três ações: <code>Healthy</code>,
<code>NeedsReplication { deficit }</code> ou <code>CorruptLocal { fragment_index }</code>. O loop de
reparo roda a cada 24 horas (com 2 horas de jitter) via <code>tokio::select!</code> com
integração de desligamento.</p>
</li>
<li>
<p><em>Configuração</em> (<code>config.rs</code>): <code>ReplicationConfig</code> com padrões para intervalo
de reparo (24h), jitter (2h), transferências simultâneas (4), espaço livre
mínimo (1 GB), tolerância de déficit (256 MB) e limite de armazenamento por
par (1 GB).</p>
</li>
</ul>
<p><strong>tesd</strong> (atualizado) — O daemon agora abre um banco de dados SQLite
(<code>db/tesseras.db</code>), executa migrações, cria instâncias de <code>FsFragmentStore</code>,
<code>SqliteReciprocityLedger</code> e <code>FsBlobStore</code>, envolve o engine DHT em um
<code>DhtPortAdapter</code>, constrói um <code>ReplicationService</code> e lança o loop de reparo como
tarefa em segundo plano com desligamento gracioso.</p>
<p><strong>Testes</strong> — 193 testes em todo o workspace:</p>
<ul>
<li>15 testes unitários em tesseras-replication (camadas de codificação de
fragmentos, validação de checksum, diversidade de sub-rede, verificações de
saúde do reparo, fluxos de recebimento/replicação do serviço)</li>
<li>3 testes de integração com armazenamento real (ciclo completo
codificar→distribuir→receber para tessera média, replicação de arquivo inteiro
para tessera pequena, rejeição de fragmento adulterado)</li>
<li>Testes usam SQLite em memória + diretório temporário para fragmentos com mocks
mockall para DHT e BlobStore</li>
<li>Zero avisos do clippy, formatação limpa</li>
</ul>
<h2 id="decisoes-de-arquitetura">Decisões de arquitetura</h2>
<ul>
<li><strong>Fragmentação em três camadas</strong>: arquivos pequenos não precisam de
codificação de apagamento — o overhead não compensa. Arquivos médios e grandes
recebem progressivamente mais shards de paridade. Isso evita desperdiçar
armazenamento em tesseras pequenas enquanto oferece redundância forte para as
grandes.</li>
<li><strong>Distribuição por push do dono</strong>: o dono da tessera codifica os fragmentos e
os envia aos pares, em vez dos pares puxarem. Isso simplifica o protocolo (sem
fase de negociação) e garante que os fragmentos são distribuídos
imediatamente.</li>
<li><strong>Reciprocidade bilateral sem consenso</strong>: cada nó rastreia seu próprio saldo
com cada par localmente. Sem livro-razão global, sem token, sem blockchain. Se
o par A armazena 500 MB para o par B, o par B deveria armazenar
aproximadamente 500 MB para o par A. Free riders perdem redundância
gradualmente — seus fragmentos são despriorizados para reparo, mas nunca
deletados.</li>
<li><strong>Diversidade de sub-rede</strong>: os fragmentos são espalhados por diferentes
sub-redes para sobreviver a falhas correlacionadas. Uma queda de datacenter
não deveria eliminar todas as cópias de uma tessera.</li>
<li><strong>Verificações de saúde por atestação primeiro</strong>: o loop de reparo pede aos
detentores que provem posse (atestação com checksums) antes de declarar uma
tessera degradada. Apenas quando a atestação falha é que ele recorre a um
simples ping. Isso detecta corrupção silenciosa de dados, não apenas partida
de nós.</li>
</ul>
<h2 id="o-que-vem-a-seguir">O que vem a seguir</h2>
<ul>
<li><strong>Fase 3: API e Apps</strong> — App Flutter mobile/desktop via flutter_rust_bridge,
API GraphQL (async-graphql), nó WASM no navegador</li>
<li><strong>Fase 4: Resiliência e Escala</strong> — Assinaturas pós-quânticas ML-DSA, travessia
avançada de NAT, Compartilhamento de Segredo de Shamir para herdeiros,
empacotamento para Alpine/Arch/Debian/FreeBSD/OpenBSD, CI no SourceHut</li>
<li><strong>Fase 5: Exploração e Cultura</strong> — navegador público de tesseras, curadoria
institucional, integração genealógica, exportação para mídia física</li>
</ul>
<p>Os nós conseguem se encontrar e manter vivas as memórias uns dos outros. Em
seguida, damos às pessoas uma forma de segurar suas memórias nas mãos.</p>
Fase 1: Nós Se Encontram2026-02-14T11:00:00+00:002026-02-14T11:00:00+00:00
Unknown
https://tesseras.net/pt-br/news/phase1-basic-network/<p>Tesseras não é mais uma ferramenta apenas local. A Fase 1 entrega a camada de
rede: nós se descobrem através de uma DHT Kademlia, comunicam-se sobre QUIC e
publicam ponteiros de tesseras que qualquer par na rede pode encontrar. Uma
tessera criada no nó A agora pode ser encontrada a partir do nó C.</p>
<h2 id="o-que-foi-construido">O que foi construído</h2>
<p><strong>tesseras-core</strong> (atualizado) — Novos tipos de domínio de rede:
<code>TesseraPointer</code> (referência leve aos detentores de uma tessera e localização
dos fragmentos), <code>NodeIdentity</code> (ID do nó + chave pública + nonce de prova de
trabalho), <code>NodeInfo</code> (identidade + endereço + capacidades) e <code>Capabilities</code>
(bitflags do que um nó suporta: DHT, armazenamento, relay, replicação).</p>
<p><strong>tesseras-net</strong> — A camada de transporte, construída sobre QUIC via quinn. A
trait <code>Transport</code> define a porta: <code>send</code>, <code>recv</code>, <code>disconnect</code>, <code>local_addr</code>.
Dois adaptadores a implementam:</p>
<ul>
<li><code>QuinnTransport</code> — QUIC real com TLS auto-assinado, negociação ALPN
(<code>tesseras/1</code>), pool de conexões via DashMap e um loop de aceitação em
background que trata streams recebidas.</li>
<li><code>MemTransport</code> + <code>SimNetwork</code> — canais em memória para testes determinísticos
sem I/O de rede. Cada teste de integração no crate DHT roda contra este
adaptador.</li>
</ul>
<p>O protocolo de fio usa MessagePack com prefixo de comprimento: um cabeçalho de 4
bytes big-endian seguido de um payload rmp-serde. <code>WireMessage</code> carrega um byte
de versão, ID de requisição e um corpo que pode ser requisição, resposta ou erro
de protocolo. Tamanho máximo de mensagem é 64 KiB.</p>
<p><strong>tesseras-dht</strong> — Uma implementação completa de Kademlia:</p>
<ul>
<li><em>Tabela de roteamento</em>: 160 k-buckets com k=20. Evicção do menos recentemente
visto, mover-para-trás ao atualizar, verificação por ping antes de substituir
a entrada mais antiga de um bucket cheio.</li>
<li><em>Distância XOR</em>: métrica XOR de 160 bits com indexação de bucket pelo bit mais
significativo diferente.</li>
<li><em>Prova de trabalho</em>: nós iteram um nonce até que
<code>BLAKE3(pubkey || nonce)[..20]</code> tenha 8 bits zero iniciais (~256 tentativas de
hash em média). Barato o suficiente para qualquer dispositivo, caro o
suficiente para tornar ataques Sybil impraticáveis em escala.</li>
<li><em>Mensagens de protocolo</em>: Ping/Pong, FindNode/FindNodeResponse,
FindValue/FindValueResult, Store — todos serializados com MessagePack via
serde.</li>
<li><em>Armazenamento de ponteiros</em>: armazenamento em memória limitado com TTL
configurável (24 horas padrão) e máximo de entradas (10.000 padrão). Quando
cheio, remove ponteiros mais distantes do ID do nó local, seguindo o modelo de
responsabilidade baseado em distância do Kademlia.</li>
<li><em>DhtEngine</em>: o orquestrador principal. Trata RPCs recebidos, executa buscas
iterativas (paralelismo alpha=3), bootstrap, publicação e busca. O método
<code>run()</code> dirige um loop <code>tokio::select!</code> com timers de manutenção: refresh da
tabela de roteamento a cada 60 segundos, expiração de ponteiros a cada 5
minutos.</li>
</ul>
<p><strong>tesd</strong> — Um binário de nó completo. Analisa argumentos de CLI (endereço de
bind, pares de bootstrap, diretório de dados), gera uma identidade de nó válida
por PoW, abre um endpoint QUIC, faz bootstrap na rede e roda o motor DHT.
Desligamento gracioso com Ctrl+C via tratamento de sinais do tokio.</p>
<p><strong>Infraestrutura</strong> — Configuração OpenTofu para dois nós bootstrap no Hetzner
Cloud (instâncias cx22 em Falkenstein, Alemanha e Helsinki, Finlândia). Script
de provisionamento cloud-init cria um usuário dedicado <code>tesseras</code>, escreve um
arquivo de configuração e configura um serviço systemd. Regras de firewall abrem
UDP 4433 (QUIC) e restringem métricas a acesso interno.</p>
<p><strong>Testes</strong> — 139 testes em todo o workspace:</p>
<ul>
<li>47 testes unitários em tesseras-dht (tabela de roteamento, distância, PoW,
armazenamento de ponteiros, serialização de mensagens, RPCs do engine)</li>
<li>5 testes de integração multi-nó (bootstrap de 3 nós, convergência de lookup
com 10 nós, publicar-e-encontrar, detecção de partida de nó, rejeição de PoW)</li>
<li>14 testes em tesseras-net (roundtrips de codec, send/recv de transporte,
backpressure, disconnect)</li>
<li>Testes de fumaça com Docker Compose usando 3 nós containerizados comunicando
sobre QUIC real</li>
<li>Zero avisos do clippy, formatação limpa</li>
</ul>
<h2 id="decisoes-de-arquitetura">Decisões de arquitetura</h2>
<ul>
<li><strong>Transport como porta</strong>: a trait <code>Transport</code> é a única interface entre o
motor DHT e a rede. Trocar QUIC por qualquer outro protocolo significa
implementar quatro métodos. Todos os testes de DHT usam o adaptador em
memória, tornando-os rápidos e determinísticos.</li>
<li><strong>Um stream por RPC</strong>: cada par requisição-resposta DHT usa um stream
bidirecional QUIC novo. Sem complexidade de multiplexação, sem bloqueio
head-of-line entre operações independentes. O QUIC trata a multiplexação no
nível da conexão.</li>
<li><strong>MessagePack em vez de Protobuf</strong>: codificação binária compacta sem geração
de código ou arquivos de esquema. Integração com serde significa que adicionar
um campo a uma mensagem é uma mudança de uma linha. Trade-off: sem garantias
de evolução de esquema embutidas, mas neste estágio velocidade importa mais.</li>
<li><strong>PoW em vez de stake ou reputação</strong>: uma identidade de nó custa ~256 hashes
BLAKE3. Isso roda em menos de um segundo em qualquer hardware, incluindo um
Raspberry Pi, mas gerar milhares de identidades para um ataque Sybil se torna
caro. Sem tokens, sem blockchain, sem dependências externas.</li>
<li><strong>Busca iterativa com atualização da tabela de roteamento</strong>: nós descobertos
são adicionados à tabela de roteamento conforme encontrados durante buscas
iterativas, seguindo o comportamento padrão do Kademlia. Isso garante que a
tabela de roteamento melhore organicamente conforme os nós interagem.</li>
</ul>
<h2 id="o-que-vem-a-seguir">O que vem a seguir</h2>
<ul>
<li><strong>Fase 2: Replicação</strong> — Codificação de apagamento Reed-Solomon pela rede,
distribuição de fragmentos, loops de reparo automáticos, livro-razão de
reciprocidade bilateral (sem blockchain, sem tokens)</li>
<li><strong>Fase 3: API e Apps</strong> — App Flutter mobile/desktop via flutter_rust_bridge,
API GraphQL (async-graphql), nó WASM no navegador</li>
<li><strong>Fase 4: Resiliência e Escala</strong> — Assinaturas pós-quânticas ML-DSA, travessia
avançada de NAT, Compartilhamento de Segredo de Shamir para herdeiros,
empacotamento para Alpine/Arch/Debian/FreeBSD/OpenBSD, CI no SourceHut</li>
<li><strong>Fase 5: Exploração e Cultura</strong> — navegador público de tesseras, curadoria
institucional, integração genealógica, exportação para mídia física</li>
</ul>
<p>Os nós conseguem se encontrar. Em seguida, aprendem a manter vivas as memórias
uns dos outros.</p>
Fase 0: Fundação Construída2026-02-14T10:00:00+00:002026-02-14T10:00:00+00:00
Unknown
https://tesseras.net/pt-br/news/phase0-foundation/<p>O primeiro marco do projeto Tesseras está completo. A Fase 0 estabelece a
fundação sobre a qual cada componente futuro será construído: tipos de domínio,
criptografia, armazenamento e uma interface de linha de comando funcional.</p>
<h2 id="o-que-foi-construido">O que foi construído</h2>
<p><strong>tesseras-core</strong> — A camada de domínio define o formato tessera: <code>ContentHash</code>
(BLAKE3, 32 bytes), <code>NodeId</code> (Kademlia, 20 bytes), tipos de memória (Moment,
Reflection, Daily, Relation, Object), modos de visibilidade (Private, Circle,
Public, PublicAfterDeath, Sealed) e um formato de manifesto em texto plano que
pode ser interpretado por qualquer linguagem de programação pelos próximos mil
anos. A camada de serviço (<code>TesseraService</code>) gerencia operações de criação,
verificação, exportação e listagem através de port traits, seguindo arquitetura
hexagonal.</p>
<p><strong>tesseras-crypto</strong> — Geração de chaves Ed25519, assinatura e verificação. Um
framework de assinatura dual (Ed25519 + placeholder ML-DSA) pronto para migração
pós-quântica. Hashing de conteúdo com BLAKE3. Codificação de apagamento
Reed-Solomon atrás de uma feature flag para futura replicação.</p>
<p><strong>tesseras-storage</strong> — Índice SQLite via rusqlite com migrações em SQL puro.
Blob store no sistema de arquivos com layout endereçável por conteúdo
(<code>blobs/<tessera_hash>/<memory_hash>/<filename></code>). Persistência de chaves de
identidade em disco.</p>
<p><strong>tesseras-cli</strong> — Um binário <code>tesseras</code> funcional com cinco comandos:</p>
<ul>
<li><code>init</code> — gera identidade Ed25519, cria banco de dados SQLite</li>
<li><code>create <dir></code> — varre um diretório por arquivos de mídia, cria uma tessera
assinada</li>
<li><code>verify <hash></code> — verifica assinatura e integridade dos arquivos</li>
<li><code>export <hash> <dest></code> — escreve um diretório tessera autocontido</li>
<li><code>list</code> — mostra uma tabela das tesseras armazenadas</li>
</ul>
<p><strong>Testes</strong> — 67+ testes em todo o workspace: testes unitários em cada módulo,
testes baseados em propriedades (proptest) para roundtrips hex e serialização de
manifesto, testes de integração cobrindo o ciclo completo de
criação-verificação-exportação incluindo detecção de arquivos adulterados e
assinaturas inválidas. Zero avisos do clippy.</p>
<h2 id="decisoes-de-arquitetura">Decisões de arquitetura</h2>
<ul>
<li><strong>Arquitetura hexagonal</strong>: operações criptográficas são injetadas via trait
objects (<code>Box<dyn Hasher></code>, <code>Box<dyn ManifestSigner></code>,
<code>Box<dyn ManifestVerifier></code>), mantendo o crate core livre de dependências
criptográficas concretas.</li>
<li><strong>Feature flags</strong>: a feature <code>service</code> no tesseras-core controla a camada de
aplicação assíncrona. As features <code>classical</code> e <code>erasure</code> no tesseras-crypto
controlam quais algoritmos são compilados.</li>
<li><strong>Manifesto em texto plano</strong>: interpretável sem qualquer biblioteca de formato
binário, com prefixos de hash explícitos <code>blake3:</code> e layout legível por
humanos.</li>
</ul>
<h2 id="o-que-vem-a-seguir">O que vem a seguir</h2>
<p>A Fase 0 é a fundação local. O caminho adiante:</p>
<ul>
<li><strong>Fase 1: Rede</strong> — Transporte QUIC (quinn), DHT Kademlia para descoberta de
pares, travessia de NAT</li>
<li><strong>Fase 2: Replicação</strong> — Codificação de apagamento Reed-Solomon pela rede,
loops de reparo, reciprocidade bilateral (sem blockchain, sem tokens)</li>
<li><strong>Fase 3: Clientes</strong> — App Flutter mobile/desktop via flutter_rust_bridge, API
GraphQL, nó WASM no navegador</li>
<li><strong>Fase 4: Endurecimento</strong> — Assinaturas pós-quânticas ML-DSA, empacotamento
para Alpine/Arch/Debian/FreeBSD/OpenBSD, CI no SourceHut</li>
</ul>
<p>O formato tessera é estável. Tudo construído a partir daqui se conecta e estende
o que existe hoje.</p>
Olá, Mundo2026-02-13T00:00:00+00:002026-02-13T00:00:00+00:00
Unknown
https://tesseras.net/pt-br/news/hello-world/<p>Hoje anunciamos o projeto Tesseras: uma rede peer-to-peer para preservar
memórias humanas através dos milênios.</p>
<p>Tesseras é construído sobre uma ideia simples — suas fotos, gravações e escritos
merecem sobreviver a qualquer empresa, plataforma ou formato de arquivo. Cada
pessoa cria uma tessera, uma cápsula do tempo autocontida que a rede mantém viva
através de ajuda mútua e redundância.</p>
<p>O projeto está em seu estágio mais inicial. Estamos construindo a fundação:
ferramentas para criar, verificar e exportar tesseras offline. A camada de rede,
replicação e aplicativos virão em seguida.</p>
<p>Se essa missão ressoa com você,
<a href="/pt-br/subscriptions/">entre na lista de discussão</a> ou navegue pelo
<a rel="external" href="https://git.sr.ht/~ijanc/tesseras">código-fonte</a>.</p>