WEB3DEV

Cover image for Comprovação de Consenso na Ethereum: DIDs, JWTs, e Contratos Inteligentes
Panegali
Panegali

Posted on

Comprovação de Consenso na Ethereum: DIDs, JWTs, e Contratos Inteligentes

https://veramo.io/

A equipe Veramo tem trabalhado arduamente na construção das bases para a identidade descentralizada na Ethereum. Por meio de seu contrato ethr-did-registry, os usuários agora podem gerenciar sua identidade on-chain e até mesmo fazer reivindicações off-chain que podem ser facilmente verificadas por outra conta Ethereum. Isso significa que agora podemos provar com eficiência o consenso entre qualquer conta Ethereum de forma privada, sem a necessidade de um terceiro confiável!

Esse modelo centrado no usuário é uma mudança significativa para a realização de uma camada de identidade descentralizada viável, na qual os usuários controlam seus próprios dados digitais. Para obter mais contexto e um resumo sobre por que a identidade descentralizada é tão importante, você pode consultar minha pequena série (em inglês):

Tendo coberto os conceitos, este artigo é sobre a implementação técnica de DIDs na cadeia Ethereum (rede de testes Goerli) usando Tokens Web JSON e Contratos Inteligentes. Além dos conceitos específicos de identidade descentralizada, presume-se que você tenha alguma familiaridade básica com Express.js, Ethers.js e Metamask. Se você quiser uma atualização de como esses 3 são integrados, especialmente em relação à execução do Ethers.js no navegador, consulte:

Conectar a Metamask com Ethers.js

O repositório do Github para este guia pode ser encontrado aqui:


Principais Conceitos e Notas de Desenvolvimento

Antes de mergulhar no código, existem alguns objetos de dados principais com os quais trabalharemos:

  • DID: Um identificador descentralizado globalmente exclusivo com recursos projetados para blockchains. Consiste em um método DID que define como os DIDs funcionam dentro de uma blockchain específica, bem como um identificador específico do método que é exclusivo dentro do namespace do método.
  • Documento DID: um objeto JSON-LD que descreve as chaves públicas e os terminais de serviço necessários para inicializar interações criptograficamente verificáveis ​​com o assunto em questão. Para mais informações sobre DIDs e Documentos DID - DID: Linha de partida da Identidade Descentralizada.
  • Registro de Dados Verificáveis: Um sistema que facilita a criação, verificação, atualização e/ou desativação de DIDs e Documentos DID. Neste caso, estamos usando o contrato inteligente ethr-did-registry.
  • Par de chaves: Um par de chaves públicas e privadas que representa uma conta Ethereum que permite a resolução pública de um endereço, bem como o controle privado sobre as ações da conta. Para mais informações: Livro da Ethereum.
  • Token Web JSON (JWT): define uma maneira compacta e independente de transmitir informações com segurança entre as partes como um objeto JSON. Consulte o site do JWT.
  • Reivindicação privada (específica do JWT): uma reivindicação personalizável que foi pré-acordada entre o produtor e o consumidor da reivindicação JWT. Usaremos isso como um exemplo de dados que podem ser incluídos em uma carga JWT. Você pode consultar a especificação JWT RFC7519 aqui.

Este é um ótimo recurso se você quiser se aprofundar nesses conceitos:

Para propriedades mais específicas do DID, você pode consultar diretamente as especificações do DID.

Notas de Desenvolvimento

Este guia é composto por 3 estágios logicamente separados na emição/verificação de um Ethereum DID-JWT:

  • Emissão de um JWT com uma reivindicação privada assinada pelo Emissor.
  • Adição de JWT ao Documento DID do Sujeito pelo Sujeito [OPCIONAL: Somente para reivindicações persistentes on-chain, para considerar os requisitos de privacidade].
  • Validação do Documento DID do Assunto e da carga útil do JWT pelo Público.

Cada um dos estágios acima é separado em sua própria página específica (emissor/assunto/aplicativo de auditoria), que exige que você interaja com o JWT por meio de contas de função separadas na Metamask.

A intenção por trás da operação manual de cada estágio é fornecer uma visão mais detalhada das seções do fluxo de ponta a ponta. Observe que, embora os diagramas de sequência indiquem salvar o JWT em um “Dispositivo do sujeito” (ou seja, carteira de identidade), optei por armazená-lo temporariamente no token de sessão para simplificar.


Assinatura e Emissão de JWTs

Primeiro precisamos preparar as reivindicações que estarão no JWT. Isso consiste na reivindicação privada, bem como nas partes da reivindicação:

  • “iss”: a declaração “iss” (emissor) identifica o principal que emitiu o JWT. Essa conta exigirá algum ETH de teste para assinar o JWT.
  • “sub”: a declaração “sub” (sujeito) identifica o principal que é o assunto do JWT. Esta conta exigirá algum ETH de teste para atualizar o documento DID on-chain.
  • “aud”: a declaração “aud” (público) identifica os destinatários aos quais o JWT se destina.

Todos os endereços Ethereum terão que ser formatados em seu método DID equivalente. Como estamos utilizando o método did:ethr:, nosso DID equivalente ficará no seguinte formato: did:ethr:<chainId>:<ethAddress>. Observe que o chainId está sendo puxado com base na rede Metamask conectada. A biblioteca ethr-did fornece um invólucro útil em torno da conta conectada que nos permite interagir convenientemente com os DIDs.

Você pode substituir facilmente os padrões desses 3 campos por meio da interface do usuário ou alterando as variáveis ​​relevantes no código (subjectAddress, audienceAddress, privateClaim). Em particular, precisaremos acessar as chaves privadas do sujeito para assinar transações on-chain na seção opcional a seguir. Ao construir a mensagem JWT, você deve ver o objeto impresso no console do navegador:

Com a mensagem configurada, podemos prosseguir e assinar a mensagem JWT com a conta Metamask conectada ao emissor.

Isso acionará uma solicitação da Metamask para você confirmar a transação. Observe que você pode ter que alterar a taxa de gás sugerida na Metamask para que a transação seja minerada.

Se você abriu a guia de dados da transação, deve ter notado que estamos criando um signatário delegado com base na carteira Issuer Metamask. Isso é necessário porque “os provedores web3 não são capazes de assinar dados diretamente de uma maneira compatível com o JWT ES256K ou os algoritmos ES256K-R (não registrados)” (Começando o Ethr-Did). Ao criar um signatário delegado, um novo objeto assertionMethod e verificationMethod que vincula o emissor delegado será adicionado ao documento DID do emissor. Isso é o que permite que o JWT seja verificado posteriormente.

Observe que a biblioteca ethr-didtambém substituirá o issem nossa payload (carga útil) pelo DID do signatário delegado (guia atualizado de assinatura com o DID do emissor aqui). Uma vez confirmado pela rede de testes Goerli, você deve ver o endereço do delegado, bem como o JWT sendo exibido na interface do usuário:

O JWT assinado é uma concatenação Base64 da entrada de assinatura (cabeçalho e carga útil), bem como da assinatura resultante, cada uma separada por um . (ponto). De forma crítica, dado que o JWT é independente, isso significa que as entradas do JWT podem ser decodificadas com base apenas na propriedade do JWT. Como tal, qualquer JWT que contenha informações pessoalmente identificáveis ​​ou confidenciais nunca deve ser mantido on-chain, pois estará permanentemente visível para todos. Nesse caso, é recomendável que o JWT seja armazenado no dispositivo do sujeito (ou seja, carteira de identidade) de onde pode ser recuperado com eficiência com base no consentimento do usuário. Os JWTs devem ser reemitidos quando necessário (ou seja, perda do dispositivo/DID).

Dito isso, a próxima seção explora a viabilidade de armazenar atributos públicos on-chain por meio de registros. Observe que um Documento DID é construído no ponto da solicitação de resolução usando apenas funções de leitura, bem como eventos de contrato. Um desses eventos é DIDAttributeChanged,o que usaremos para adicionar atributos não Ethereum ao documento DID.

Código da seção:

Adicionando JWT ao Documento DID do Sujeito [OPCIONAL]

Vale a pena repetir que esta seção diverge do padrão de design recomendado (consulte a seção acima), mas é incluída para fins de exploração de reivindicações persistidas publicamente. O JWT pode ser verificado sem a necessidade de armazenamento on-chain, pois o documento DID do emissor já contém o link para o signatário delegado que pode ser verificado em relação ao JWT decodificado (verificationMethod[i].blockchainAccountId). Com as considerações de privacidade em vigor, alguns casos de uso possíveis para esse fluxo girarão em torno de dados de domínio público permanente e público, como certificações e conquistas verificadas.

Navegue até o Subject App e altere a conta Metamask conectada para a do Subject. Você pode verificar a conta conectada clicando no botão a seguir:

Com a conta Subject conectada e financiada com algum ETH de teste, podemos então adicionar o JWT ao Documento Subject DID selecionando o botão "Add JWT" que solicitará que você assine a transação na Metamask. Um recibo de transação é retornado assim que o JWT é adicionado:

Você também pode visualizar a transação confirmada e o evento resultante DIDAttributeChangedvia Etherscan:

Além disso, ao resolver o Documento DID do Subject após a alteração do atributo, também podemos ver que o JWT foi adicionado ao verificationMethod:

Observe que o JWT é armazenado como DataHexString, que pode ser facilmente convertido de volta ao formato UTF8 original, conforme detalhado na próxima seção.

Código da seção:

Validando o JWT

Embora o JWT possa ser facilmente verificado chamando verifyJWT() da biblioteca ethr-did, este guia também implementa um fluxo de validação usando o fluxo alternativo acima. Além das diferenças em termos de qual documento DID está sendo extraído, a validação em relação ao documento DID em questão também visa fornecer uma visão altamente simplificada de como o JWT é verificado:

  • Decodifica o JWT.
  • Obtém a chave pública de verificação e o controlador do JWT decodificado (em verificationMethod).
  • Verifica a finalidade da verificação do JWT.
  • Resolve o Documento DID do controlador (e Emissor, se necessário).
  • Verifica o documento DID do emissor assertionMethodem relação ao JWT decodificado.
  • Verifica o vencimento e validade do JWT aud.

Validação contra documento DID Subject

Resolvendo primeiro o Subject DID Document, podemos acessar o objeto verificationMethodque contém o publicKeyHexlocal onde o JWT está armazenado. Ao comparar o equivalente UTF8 do publicKeyHexcom o JWT, podemos confirmar que o Subject recebeu o JWT e decidiu adicioná-lo ao seu documento DID.

Como uma etapa de validação adicional, também podemos comparar a carga JWT decodificada (que contém “iss”, “sub”, “aud”) com os endereços relevantes. Observe que também conseguimos extrair a declaração privada da chave pública hex usando ethers.utils.

Validar via biblioteca de conveniência Ethr-DID

Como a biblioteca ethr-did verifica o JWT em relação ao documento DID iss que foi atualizado no primeiro estágio (ou seja, issuerDelegateKp.signJWT()), esse fluxo pode ser alcançado pelo validador apenas com o JWT sozinho. Em outras palavras, o JWT pode ser armazenado de forma privada off-chain e fornecido apenas quando um Subject solicita validação pelo Público listado no JWT.

Para este fluxo, verifique se você está conectado à carteira pública na Metamask ou pode configurar o endereço da audiência através do formulário:

ethr-did irá comparar o DID público configurado com a carga útil JWT “aud” como parte das checagens de verificação. Para acionar as verificações, você pode clicar no botão “Validate JWT”:

A verificação também retornará o resultado, bem como a carga útil totalmente decodificada, que é exibida na interface do usuário. O resultado completo pode ser visualizado no console:

Examinando o resultado, você pode ver que o issna carga útil foi realmente substituído pelo id do signatário delegado. Observe que, como o método verifyJWT() verifica o issincluído, uma chamada bem-sucedida aqui significa que foi verificado que o JWT foi emitido pelo signatário delegado e não pelo emissor. Para vincular o signatário delegado ao Emissor, precisaríamos assinar o JWT com um objeto DID do Emissor atualizado, que é abordado aqui.

Embora o valor verifiedseja tudo o que é necessário para validar o JWT, a biblioteca ethr-did também retorna detalhes adicionais sobre o JWT e o signatário para sua conveniência.

Código da seção:

Obrigado por ficar até o fim. Adoraria ouvir seus pensamentos/comentários, então deixe um comentário. Estou ativo no twitter @ AwKaiShin se você quiser receber informações mais digeríveis sobre assuntos relacionados à criptografia ou visite meu site pessoal se quiser meus serviços.


Artigo original escrito por Aw Kai Shin. Traduzido por Marcelo Panegali.

Top comments (0)