Esquema de assinatura

Ed25519 explicado matematicamente

A assinatura que acompanha cada avaliação da McGesund — da curva à chave, até à equação que o navegador do leitor recalcula.

Atualizado: 2026-09-07

1. Do que se trata aqui

Uma avaliação na McGesund não é um campo de texto numa base de dados em que seja preciso acreditar. Ao ser enviada, é assinada digitalmente, e qualquer visitante pode mais tarde recalcular essa assinatura no seu próprio navegador.

Para esta assinatura utilizamos Ed25519. Ao contrário de FALCON e ML-DSA, que podem ser acrescentados ao lado como carimbos adicionais, o Ed25519 não é uma opção: todas as avaliações assinadas o incluem, independentemente do plano e da via de submissão.

Uma nota prévia importante:

Ed25519 não é cifragem. O texto da avaliação destina-se justamente a ser lido. A assinatura não prova sigilo, mas sim origem e integridade.


2. O que é exatamente assinado

O que se assina não é o texto corrido, mas um objeto de dados compacto que fixa de forma inequívoca o texto e tudo o resto:

{
  "v":   1,
  "typ": "rev-comment",
  "f":   "<ID da empresa>",
  "c":   "<ID da avaliação>",
  "h":   "<SHA-256 do texto da avaliação>",
  "rh":  "<SHA-256 de todo o registo de submissão>",
  "rv":  1,
  "qh":  "<SHA-256 do envelope QR, apenas em avaliações por QR>",
  "kid": "<ID da chave>",
  "iat": 1757203200
}

Este objeto é codificado em CBOR. Essa sequência de bytes — e não a sua representação legível acima — é a nossa mensagem mm. Assinatura e mensagem seguem juntas num envelope:

Envelope=MCG1:    base64url(CBOR[3,  m,  σ])\text{Envelope} = \texttt{MCG1:} \;\|\; \mathrm{base64url}\bigl(\mathrm{CBOR}[\,3,\; m,\; \sigma\,]\bigr)

O 33 é a versão do formato. Não há mais nada lá dentro — em particular, nenhuma assinatura pós-quântica: essa, quando existe, fica junto ao registo de dados e não dentro do envelope.


3. O que a assinatura deve garantir

Um leitor que chega ao perfil de uma empresa tem duas perguntas à sua frente:

  1. Esta avaliação vem realmente do sistema da McGesund?
  2. Foi alterada posteriormente?

Para isso existe um par de chaves:

  • uma chave privada — permanece no serviço de assinatura
  • uma chave pública — pode estar em poder de qualquer pessoa e é endereçada pelo ID da chave (kid) no payload

Assina-se com a chave privada. Verifica-se com a pública — e isso acontece no navegador do leitor, não no nosso servidor. É esse o ponto: uma verificação que nós próprios executássemos e cujo resultado comunicássemos não seria uma verificação, seria uma afirmação.


4. Porquê uma curva elíptica?

Toda a assinatura precisa de um cálculo que seja fácil num sentido e praticamente impossível no outro. No Ed25519 esse cálculo é a multiplicação escalar numa curva elíptica:

a    A=aB.a \;\longmapsto\; A = a\cdot B.

Calcular o ponto público AA a partir do número secreto aa custa microssegundos. Deduzir aa a partir de AA é o problema do logaritmo discreto — e para ele não se conhece nenhum método que, com esta dimensão, termine em prazos humanos.

O ganho prático face a esquemas mais antigos como o RSA está no tamanho:

chave públicaassinatura
RSA-3072384 B384 B
Ed2551932 B64 B

Com um nível de segurança comparável. Mesmo com milhões de avaliações, 64 bytes por avaliação não são uma grandeza que obrigue a pensar duas vezes.


5. A curva edwards25519

Calcula-se módulo um número primo:

p=225519.p = 2^{255}-19.

Daí o nome. A curva é uma curva de Edwards torcida:

x2+y2  =  1+dx2y2,d=121665121666modp.-x^2+y^2 \;=\; 1 + d\,x^2y^2, \qquad d = -\frac{121665}{121666} \bmod p.

Um «ponto» é um par de números (x,y)(x,y) de {0,,p1}\{0,\dots,p-1\} que satisfaz esta equação. Não há nenhuma curva para ver — o desenho da secção seguinte é um auxílio visual sobre os números reais, não uma imagem do espaço de cálculo verdadeiro.

Há ainda duas grandezas a acrescentar:

  • um ponto base BB fixado por convenção,
  • a ordem \ell do subgrupo gerado por BB:
=2252+27742317777372353535851937790883648493.\ell = 2^{252} + 27742317777372353535851937790883648493.

\ell é primo. Isso significa: somando BB repetidamente a si próprio, percorrem-se exatamente \ell pontos diferentes e regressa-se depois ao início. Por isso, todos os cálculos com escalares correm módulo \ell e todos os cálculos com coordenadas módulo pp. Confundir estes dois números é o erro clássico de principiante.


6. Somar pontos

Dois pontos são combinados num terceiro segundo uma fórmula fixa:

x3=x1y2+y1x21+dx1x2y1y2,y3=y1y2x1x21dx1x2y1y2.x_3=\frac{x_1y_2+y_1x_2}{1+d\,x_1x_2y_1y_2}, \qquad y_3=\frac{y_1y_2-x_1x_2}{1-d\,x_1x_2y_1y_2}.

O elemento neutro é (0,1)(0,1) — o ponto onde o cálculo começa.

Esta fórmula tem uma propriedade que não se vê à primeira vista e que é mais importante para a segurança do que qualquer constante: é completa. Funciona para todas as entradas, sem casos especiais para «os dois pontos são iguais» ou «o resultado é o elemento neutro». Nas curvas de Weierstrass mais antigas esses casos especiais existem, e cada um deles é um ramo no programa — um ramo cujo tempo de execução é mensurável. Quem mede quanto tempo demora uma assinatura fica a saber, nesses esquemas, algo sobre a chave secreta.

Fórmulas completas significam: sempre o mesmo percurso de cálculo, sempre o mesmo tempo, nada para medir.


7. Multiplicação escalar — a via de sentido único

nBn\cdot B significa: somar BB exatamente nn vezes a si próprio. Com um nn de 253 bits isso seria uma quantidade de trabalho absurda — por isso duplica-se:

B2B4B8BB \to 2B \to 4B \to 8B \to \dots

e a partir destes resultados intermédios compõe-se o nn pretendido. Cerca de 253 duplicações bastam para qualquer nn. Este é o caminho para a frente.

Para trás não existe este atalho. Determinar o número aa a partir do ponto AA significa resolver o problema do logaritmo discreto.

(0,1) — elemento neutroB2B3B4B5B6B
Uma curva de Edwards com os primeiros múltiplos do ponto base, calculados com a verdadeira lei de adição. Sobre os números reais, ainda percorrem a curva numa ordem visível — seria possível refazer o caminho para trás. Módulo p desaparece precisamente essa ordem, e é nisso que assenta a segurança.

No esquema real calcula-se módulo pp. Aí não há «esquerda», não há «direita» e não há proximidade: de 17B17\,B e 18B18\,B resultam dois pares de números sem qualquer parentesco reconhecível.


8. O par de chaves do serviço de assinatura

No início estão 32 bytes aleatórios, a seed. Tudo o resto é derivado a partir daí:

h=SHA-512(seed),h=h0..31  a    h32..63prefixo.h = \mathrm{SHA\text{-}512}(\text{seed}), \qquad h = \underbrace{h_{0..31}}_{\to\;a}\;\|\;\underbrace{h_{32..63}}_{\text{prefixo}}.

Da primeira metade nasce o escalar secreto aa, mas não sem alterações. Três bits são fixados ou apagados — o chamado clamping:

  • os três bits inferiores são postos a zero: aa passa assim a ser múltiplo de 8. A razão é o cofator 8 da curva — o grupo completo de pontos é oito vezes maior do que o subgrupo de ordem \ell. Um aa divisível por 8 cai garantidamente no subgrupo certo e nada revela através de pontos de ordem pequena.
  • o bit mais alto é apagado e o segundo mais alto é fixado: aa tem assim sempre o mesmo comprimento em bits. Um aa mais curto exigiria menos duplicações — e, de novo, o tempo de execução deixaria algo a descoberto.

A chave pública é então simplesmente

A=aB,A = a\cdot B,

guardada como 32 bytes: a coordenada yy e, no bit mais alto, o sinal de xx. O xx é reconstruído pelo próprio verificador a partir da equação da curva — as duas soluções diferem apenas no sinal, e esse único bit diz qual delas se pretende.

A segunda metade do valor de hash, o prefixo, não é necessária para a chave. Entra em cena na secção seguinte.


9. Porque é que o acaso, aqui, não é acaso nenhum

Toda a assinatura deste tipo precisa de um valor irrepetível rr, muitas vezes chamado nonce. Nunca se pode repetir: quem tiver duas assinaturas com o mesmo rr consegue extrair a chave secreta com álgebra elementar.

Foi exatamente aí que falharam sistemas reais. O caso mais conhecido é a verificação de assinaturas de uma consola de jogos cujo fabricante, em 2010, usava sempre o mesmo nonce — a chave privada tornou-se assim reconstruível publicamente.

O Ed25519 resolve isto não usando acaso nenhum:

r=SHA-512(prefixo    m)mod.r = \mathrm{SHA\text{-}512}(\text{prefixo}\;\|\;m) \bmod \ell.

O nonce depende do prefixo secreto e da mensagem. Daí decorrem duas coisas:

  • Duas avaliações diferentes produzem, com probabilidade esmagadora, valores de rr diferentes — o caso de repetição não ocorre.
  • A mesma avaliação produz sempre a mesma assinatura. Um processo de assinatura torna-se assim reproduzível, e um gerador de números aleatórios deficiente no servidor não pode estragar nada, porque nenhum é necessário.

Para um portal de avaliações com muitas assinaturas por dia, isto não é uma vantagem académica. É a diferença entre «uma falha na fonte de aleatoriedade seria fatal» e «não há fonte de aleatoriedade que possa falhar».


10. Assinar

Três linhas, nada mais:

r=H(prefixo    m)mod,R=rB,r = H(\text{prefixo}\;\|\;m) \bmod \ell, \qquad R = r\cdot B,
k=H(R    A    m)mod,k = H(R \;\|\; A \;\|\; m) \bmod \ell,
S=(r+ka)mod.S = (r + k\,a) \bmod \ell.

A assinatura é o par

σ=(R,S),\sigma = (R,\,S),

32 bytes para o ponto RR, 32 bytes para o número SS — 64 bytes no total.

Vale a pena reparar na segunda linha: em kk entram RR, a chave pública AA e a mensagem. O facto de AA ser incluída no hash não é acessório — impede ataques em que uma assinatura é reinterpretada como pertencendo a outra chave.


11. Verificar

O navegador do leitor conhece: a avaliação mm, a assinatura (R,S)(R,S) e a chave pública AA. Recalcula kk e verifica uma única equação:

SB  =  R+kA\boxed{S\cdot B \;=\; R + k\cdot A}

Se ela se confirmar, a assinatura é válida. A RFC 8032 permite ainda a versão multiplicada pelo cofator, 8SB=8R+8kA8S\cdot B = 8R + 8k\cdot A, que trata alguns casos-limite de forma mais generosa.

Não se consulta nenhum servidor, não é preciso que nenhum serviço esteja disponível. A chave pública basta.


12. Porque é que a equação fecha

Basta substituir:

SB=(r+ka)B=rB+k(aB)=R+kA.S\cdot B = (r + k\,a)\cdot B = r\cdot B + k\,(a\cdot B) = R + k\cdot A.

Todo o truque está na transformação do meio: a multiplicação escalar é compatível com a adição. Quem conhece aa consegue calcular um SS que satisfaz a equação. Quem não conhece aa teria de encontrar, para um kk escolhido por si, um SS adequado — e isso significa resolver o logaritmo discreto.


13. Um pequeno exemplo integralmente calculado

Com os números reais não há nada para verificar à mão — valores de 253 bits não se controlam de cabeça. Por isso, o mesmo esquema num grupo minúsculo, em que cada passo se acompanha com uma calculadora.

Passo 1: O grupo

Calculamos com os restos módulo 2323 e tomamos g=2g = 2. Tem-se

211=2048=8923+11(mod23),2^{11} = 2048 = 89\cdot 23 + 1 \equiv 1 \pmod{23},

ou seja, gg gera um subgrupo de ordem =11\ell = 11. As potências são:

nn1234567891011
gng^n248169181336121

gg assume o papel do ponto base BB e a multiplicação o da adição de pontos. Os escalares contam-se módulo 1111, os valores módulo 2323.

Passo 2: O par de chaves

Seja secreto a=6a = 6. Então

A=ga=26=6418(mod23).A = g^a = 2^6 = 64 \equiv 18 \pmod{23}.

A=18A = 18 pode ser do conhecimento de todos.

Passo 3: Nonce e compromisso

Do prefixo e da avaliação resulte r=4r = 4. Daí:

R=gr=24=16.R = g^r = 2^4 = 16.

Passo 4: O desafio

O hash sobre RR, AA e a avaliação forneça

k=5.k = 5.

Passo 5: A assinatura

S=(r+ka)mod11=(4+56)mod11=34mod11=1.S = (r + k\,a) \bmod 11 = (4 + 5\cdot 6) \bmod 11 = 34 \bmod 11 = 1.

A assinatura é o par (R,S)=(16,1)(R,S) = (16,\,1).

Passo 6: O navegador verifica

Calcula os dois lados. À esquerda:

gS=21=2.g^S = 2^1 = 2.

À direita, com 1853(mod23)18^5 \equiv 3 \pmod{23}:

RAk=163=482(mod23).R\cdot A^{k} = 16\cdot 3 = 48 \equiv 2 \pmod{23}.

Os dois lados dão 22:

Assinatura vaˊlida\boxed{\text{Assinatura válida}}

Passo 7: Alguém altera o texto da avaliação

O texto entra no hash, logo o desafio muda — digamos, para k=7k' = 7. A assinatura mantém-se em (16,1)(16,1), mas o lado direito não. Com 1876(mod23)18^7 \equiv 6 \pmod{23}:

RAk=166=964(mod23)    2=gSR\cdot A^{k'} = 16\cdot 6 = 96 \equiv 4 \pmod{23} \;\neq\; 2 = g^S
Assinatura invaˊlida\boxed{\text{Assinatura inválida}}

Podemos apagar uma avaliação. Alterá-la sem que isso se note, não.

Nota de honestidade sobre o exemplo

O cálculo foi feito aqui no grupo multiplicativo módulo 2323, não numa curva: gSg^S representa SBS\cdot B, e o produto RAkR\cdot A^k representa a adição de pontos R+kAR + k\cdot A. A estrutura é a mesma, e é disso que se trata. O que difere são as ordens de grandeza: =11\ell = 11 contra 2252\ell \approx 2^{252}, e aí a chave não se descobre experimentando as onze possibilidades.


14. O que acontece se alguém alterar a avaliação

Suponhamos que alguém com acesso à base de dados — incluindo alguém da nossa equipa — altera o texto da avaliação ou um dos corações. Então o registo muda e, com ele, pelo menos um dos dois valores de hash h e rh no payload. Com isso muda mm, com isso o desafio kk, com isso o lado direito da equação de verificação. A assinatura antiga deixa de encaixar.

A frase decisiva é esta: podemos apagar uma avaliação, mas não podemos alterá-la sem que se note. Na McGesund, a mesma verificação corre ainda todas as noites do lado do servidor sobre o acervo — uma avaliação que não a passe deixa de contar para a média da empresa.


15. Porque é que um atacante fracassa

Ele conhece a chave pública AA, o ponto base BB, a curva e todas as assinaturas emitidas até hoje. O que lhe falta é aa.

O melhor ataque clássico conhecido ao problema do logaritmo discreto num grupo de ordem \ell precisa de cerca de \sqrt{\ell} passos. Com 2252\ell \approx 2^{252}, isso corresponde a cerca de

21262^{126}

operações. Para comparar: mesmo uma máquina capaz de mil milhões de milhares de milhões (101810^{18}) de passos por segundo precisaria de um múltiplo da idade do universo.

Falsificar sem a chave significaria encontrar, para um kk escolhido pelo próprio, um SS adequado — a mesma tarefa noutro disfarce.


16. Porquê Ed25519 e não ECDSA

Ambos assentam no mesmo problema. A diferença está em tudo o que acontece à volta:

ECDSA (curvas NIST)Ed25519
Nonceé preciso acaso frescodeterminístico a partir do prefixo e da mensagem
Fórmulascasos especiais, ramos dependentes dos dadoscompletas, um único percurso de cálculo
Parâmetros da curvaorigem das constantes nunca explicada por completoescolhidos a partir de critérios verificáveis
Tamanho da assinatura64–72 B, codificação variávelfixo em 64 B
No navegadordisponível há muito temponativo desde 2023/2024, caso contrário como biblioteca JS

Para nós, o nonce foi o argumento decisivo. Um portal de avaliações assina com frequência e de forma automatizada; um esquema em que um único valor aleatório fraco entrega a chave é, para isso, a escolha errada.


17. O que o Ed25519 não faz

O Ed25519 assenta no logaritmo discreto — e é exatamente esse problema que um computador quântico suficientemente grande resolve de forma eficiente com o algoritmo de Shor. Se e quando existirão tais máquinas é uma questão em aberto. Para uma avaliação que ainda deve ser verificável daqui a dez anos, é mesmo assim uma pergunta a que é preciso responder hoje.

Por isso, ao lado da assinatura Ed25519 pode surgir um carimbo resistente a computadores quânticos:

Nenhum dos dois substitui o Ed25519, colocam-se ao seu lado. Se um dos esquemas cair, o outro continua a sustentar.


18. O processo em imagem

SERVIÇO DE ASSINATURA (MCGESUND)NAVEGADOR DO VISITANTEescalar privado a + prefixo (a partir da seed)Payload m = {Empresa, Avaliação, h, rh, iat}r = H(prefixo ‖ m) mod ℓR = r · Bk = H(R ‖ A ‖ m) mod ℓS = (r + k · a) mod ℓAssinatura σ = (R, S) + kidAvaliação + σ + chave pública Arecalcular k a partir de R, A e mS · B = R + k · A ?válidainválida
Do payload até ao visto no navegador. Acima da linha de separação tudo acontece uma única vez, no momento do envio; abaixo dela, de novo em cada leitor — no seu aparelho, apenas com a chave pública.

19. O que a McGesund faz concretamente com isto

O envelope. Cada avaliação assinada leva um envelope MCG1: com versão de formato, payload e assinatura Ed25519. O kid no payload indica de que chave se trata; a chave pública correspondente é fornecida pelo servidor a pedido — é pública, não há nada a proteger nela.

A verificação no navegador. O Chrome e o Firefox suportam Ed25519 nativamente desde 2023/2024 através da interface WebCrypto. O Safari não — aí a chamada lança um erro em vez de verificar. Por isso, o nosso código de verificação recorre a uma implementação puramente em JavaScript, carregada apenas onde é necessária. A verificação da assinatura conclui-se assim em qualquer navegador, e no aparelho do leitor.

A âncora temporal. A impressão digital da chave de assinatura é ancorada num bloco da Bitcoin através do OpenTimestamps. Com isso, não se demonstra apenas que a assinatura é autêntica, mas também que a chave já existia num determinado momento — sem que ninguém tenha de acreditar no nosso carimbo temporal.

A ligação ao conteúdo. O payload transporta rh, o hash sobre todo o registo de submissão: texto, corações, estado de geolocalização, dados sobre o motivo e proveniência. A assinatura Ed25519 liga assim não só o texto, mas tudo o que é exibido junto à avaliação.


20. Uma frase para levar

O Ed25519 transforma um nuˊmero secreto numa equac¸a˜oque todos podem verificar e ningueˊm pode inventar.\boxed{ \begin{array}{c} \text{O Ed25519 transforma um número secreto numa equação}\\ \text{que todos podem verificar e ninguém pode inventar.} \end{array}}

Quem possui o escalar secreto assina em microssegundos. Quem não o possui teria de resolver um logaritmo discreto num grupo com cerca de 22522^{252} elementos.

Para o leitor de uma avaliação, isso significa simplesmente: não tem de acreditar em nós. Pode verificar por si.