Tesseras - Notícias Rede P2P para preservar memórias humanas através dos milênios Zola 2026-02-16T10:00:00+00:00 https://tesseras.net/pt-br/news/atom.xml Empacotando o Tesseras para Debian 2026-02-16T10:00:00+00:00 2026-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 Linux 2026-02-16T09:00:00+00:00 2026-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 Armazenamento 2026-02-15T23:00:00+00:00 2026-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>&lt;raiz&gt;/&lt;prefixo-hex-2-chars&gt;/&lt;hash-completo&gt;.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/&lt;tessera&gt;/&lt;memoria&gt;/&lt;arquivo&gt;</code> e <code>fragments/&lt;tessera&gt;/&lt;indice&gt;.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>&lt;prefixo 2 chars&gt;/</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 Institucionais 2026-02-15T22:00:00+00:00 2026-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.&lt;dominio&gt;</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.&lt;dominio&gt;</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=&lt;hex&gt; pledge=&lt;bytes&gt;</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 Performance 2026-02-15T20:00:00+00:00 2026-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(&amp;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&lt;dyn FragmentStore&gt;</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&lt;SocketAddr, PooledConnection&gt;</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 Nada 2026-02-15T20:00:00+00:00 2026-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&lt;T, String&gt;</code> e são testadas nativamente, enquanto wrappers finos <code>#[wasm_bindgen]</code> convertem erros para <code>JsError</code>. Isso evita que <code>JsError::new()</code> cause panic em targets não-WASM durante os testes.</p> <p>O binário WASM compilado tem 109 KB bruto e 44 KB com gzip — bem abaixo do orçamento de 200 KB. O wasm-opt aplica otimização <code>-Oz</code> após o wasm-pack compilar com <code>opt-level = "z"</code>, LTO e uma única unidade de codegen.</p> <p><strong>@tesseras/verify</strong> — Um pacote npm TypeScript (<code>crates/tesseras-wasm/js/</code>) que orquestra a verificação no lado do navegador. A API pública é uma única função:</p> <pre><code data-lang="typescript">async function verifyTessera( archive: Uint8Array, onProgress?: (current: number, total: number, file: string) =&gt; void ): Promise&lt;VerificationResult&gt; </code></pre> <p>O tipo <code>VerificationResult</code> fornece tudo que uma UI precisa: validade geral, hash da tessera, chaves públicas do criador, status das assinaturas (valid/invalid/missing para Ed25519 e ML-DSA), resultados de integridade por arquivo com hashes esperados e reais, uma lista de arquivos inesperados não presentes no MANIFEST, e um array de erros.</p> <p>A descompactação de arquivos (<code>unpack.ts</code>) lida com três formatos: tar comprimido com gzip (detectado pelos magic bytes <code>\x1f\x8b</code>, descomprimido com fflate e depois parseado como tar), ZIP (magic <code>PK\x03\x04</code>, descompactado com <code>unzipSync</code> do fflate), e tar bruto (<code>ustar</code> no offset 257). Uma função <code>normalizePath</code> remove o prefixo <code>tessera-&lt;hash&gt;/</code> para que os caminhos internos correspondam às entradas do MANIFEST.</p> <p>A verificação roda em um Web Worker (<code>worker.ts</code>) para manter a thread da UI responsiva. O worker inicializa o módulo WASM, descompacta o arquivo, parseia o MANIFEST, verifica a assinatura Ed25519 contra a chave pública do criador, depois faz hash de cada arquivo com BLAKE3 e compara com os valores esperados. Mensagens de progresso são transmitidas de volta para a thread principal após cada arquivo. Se qualquer assinatura é inválida, a verificação para imediatamente sem fazer hash dos arquivos — falhando rápido na verificação mais crítica.</p> <p>O arquivo é transferido para o worker com zero-copy (<code>worker.postMessage({ type: "verify", archive }, [archive.buffer])</code>) para evitar duplicar arquivos de tessera potencialmente grandes na memória.</p> <p><strong>Pipeline de build</strong> — Três novos targets no justfile: <code>wasm-build</code> executa wasm-pack com <code>--target web --release</code> e otimiza com wasm-opt; <code>wasm-size</code> reporta o tamanho do binário bruto e com gzip; <code>test-wasm</code> executa a suíte de testes nativos.</p> <p><strong>Testes</strong> — 9 testes unitários nativos cobrem hashing BLAKE3 (entrada vazia, valor conhecido), verificação Ed25519 (assinatura válida, assinatura inválida, chave errada, comprimento de chave inválido), e parsing do MANIFEST (manifesto válido, UTF-8 inválido, lixo). 3 testes de integração WASM rodam em Chrome headless via <code>wasm-pack test --headless --chrome</code>, verificando que <code>hash_blake3</code>, <code>verify_ed25519</code> e <code>parse_manifest</code> funcionam corretamente quando compilados para <code>wasm32-unknown-unknown</code>.</p> <h2 id="decisoes-de-arquitetura">Decisões de arquitetura</h2> <ul> <li><strong>Sem dependência do tesseras-crypto</strong>: o crate WASM chama blake3 e ed25519-dalek diretamente. O <code>tesseras-crypto</code> depende do <code>pqcrypto-kyber</code> (ML-KEM baseado em C via pqcrypto-traits) que requer um toolchain de compilador C e não tem target wasm32. Dependendo apenas de crates Rust puros, o build WASM tem zero dependências C e compila sem problemas para WebAssembly.</li> <li><strong>ML-DSA adiado, não fingido</strong>: ao invés de silenciosamente pular a verificação pós-quântica, o stub retorna um erro explícito. Isso garante que se uma tessera contiver uma assinatura ML-DSA, o resultado da verificação reportará <code>ml_dsa: "missing"</code> ao invés de fingir que foi verificada. O orquestrador JS lida com isso graciosamente — uma tessera é válida se Ed25519 passar e ML-DSA estiver ausente (ainda não implementado em nenhum dos lados).</li> <li><strong>Padrão de função interna</strong>: <code>JsError</code> não pode ser construído em targets não-WASM (causa panic). Dividir cada função em <code>foo_inner() -&gt; Result&lt;T, String&gt;</code> e <code>foo() -&gt; Result&lt;T, JsError&gt;</code> permite que a suíte de testes nativa exercite toda a lógica sem tocar em tipos JavaScript. Os testes de integração WASM em Chrome headless testam a superfície completa do <code>#[wasm_bindgen]</code>.</li> <li><strong>Isolamento em Web Worker</strong>: operações criptográficas (especialmente BLAKE3 sobre arquivos de mídia grandes) podem levar centenas de milissegundos. Rodar em um Worker previne travamentos na UI. O protocolo de progresso com streaming (<code>{ type: "progress", current, total, file }</code>) permite que a UI mostre uma barra de progresso durante a verificação de tesseras com muitos arquivos.</li> <li><strong>Transferência zero-copy</strong>: <code>archive.buffer</code> é transferido para o Worker, não copiado. Para um arquivo tessera de 50 MB, isso evita dobrar o uso de memória durante a verificação.</li> <li><strong>MANIFEST em texto plano, não MessagePack</strong>: o crate WASM parseia o mesmo formato de MANIFEST em texto plano que o CLI. Isso é por design — o MANIFEST é a Pedra de Rosetta da tessera, legível por qualquer pessoa com um editor de texto. A dependência <code>rmp-serde</code> no Cargo.toml não é usada e será removida.</li> </ul> <h2 id="o-que-vem-a-seguir">O que vem a seguir</h2> <ul> <li><strong>Fase 4: Resiliência e Escala</strong> — Empacotamento para sistemas operacionais (Alpine, Arch, Debian, FreeBSD, OpenBSD), CI no SourceHut e GitHub Actions, auditorias de segurança, explorador de tesseras no navegador em tesseras.net usando @tesseras/verify</li> <li><strong>Fase 5: Exploração e Cultura</strong> — Navegador público de tesseras por era/localização/tema/idioma, curadoria institucional, integração com genealogia, exportação para mídia física (M-DISC, microfilme, papel livre de ácido com QR)</li> </ul> <p>A verificação não exige mais confiança em software. Um arquivo tessera arrastado para um navegador é verificado com o mesmo rigor criptográfico do CLI — mesmos hashes BLAKE3, mesmas assinaturas Ed25519, mesmo parser de MANIFEST. A diferença é que agora qualquer pessoa pode fazer isso.</p> Fase 4: Furando NATs 2026-02-15T18:00:00+00:00 2026-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&lt;T&gt;</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 Status 2026-02-15T00:00:00+00:00 2026-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 &lt;hash&gt;</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 (&lt; 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 &lt;hash&gt;</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 &lt;hash&gt;</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 Sharing 2026-02-15T00:00:00+00:00 2026-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 &lt;dados MessagePack codificados em base64&gt; --- 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 Seladas 2026-02-14T16:00:00+00:00 2026-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&lt;HybridEncryptionPublic&gt;</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ãos 2026-02-14T14:00:00+00:00 2026-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&lt;Option&lt;EmbeddedNode&gt;&gt;</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&lt;String&gt;</code>, <code>Vec&lt;String&gt;</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&lt;Option&lt;EmbeddedNode&gt;&gt;</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 Dados 2026-02-14T14:00:00+00:00 2026-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 (&lt; 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 Sobrevivem 2026-02-14T12:00:00+00:00 2026-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> (&lt; 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 Encontram 2026-02-14T11:00:00+00:00 2026-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ída 2026-02-14T10:00:00+00:00 2026-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/&lt;tessera_hash&gt;/&lt;memory_hash&gt;/&lt;filename&gt;</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 &lt;dir&gt;</code> — varre um diretório por arquivos de mídia, cria uma tessera assinada</li> <li><code>verify &lt;hash&gt;</code> — verifica assinatura e integridade dos arquivos</li> <li><code>export &lt;hash&gt; &lt;dest&gt;</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&lt;dyn Hasher&gt;</code>, <code>Box&lt;dyn ManifestSigner&gt;</code>, <code>Box&lt;dyn ManifestVerifier&gt;</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á, Mundo 2026-02-13T00:00:00+00:00 2026-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>