Xorcism

Xorcism

Difícil

Instruções

Escreve um adaptador de streaming que contém uma referência a uma chave e que faz XOR bit a bit dessa chave com dados arbitrários.

O XOR é uma operação binária fundamental: para cada bit dos valores de entrada, define o bit correspondente da saída como 1 se os bits de entrada forem diferentes. Se ambos os valores de entrada forem 1 ou ambos forem 0, o bit correspondente da saída é 0.

Quando se faz XOR de um documento com uma chave, a chave é repetida tantas vezes quantas as necessárias, produzindo um documento de saída com o mesmo comprimento que o documento de entrada.

O XOR de um documento com uma chave foi usado em criptografia ainda no início do século XX. Embora este método seja completamente obsoleto para esconder dados, pode ser surpreendentemente útil para gerar dados ruidosos com aparência aleatória, sem precisar da complicação da aleatoriedade verdadeira. Ainda é usado ocasionalmente na criptografia moderna em certas cifras: a própria cifra é apenas um mecanismo para gerar uma chave muito aleatória e infinitamente longa, que é combinada com o documento através de XOR.

Uma propriedade interessante da encriptação com XOR é que é simétrica: fazer XOR de um número com ele próprio produz 0, e fazer XOR de um número com 0 devolve o número de entrada inalterado. Por isso, para desencriptar um documento que foi encriptado com XOR, volta a encriptá-lo com XOR usando a mesma chave.

Sem alocação

Não é prático escrever um teste que garanta que a tua struct contém uma referência à chave em vez de a copiar. Do mesmo modo, não é prático provar com um teste que nem munge nem munge_in_place, nem nenhuma das suas funções auxiliares, alocam memória na heap. No entanto, deves tentar escrever a tua solução dessa forma.

Implementação

Vais precisar de escrever uma struct Xorcism que contém uma referência a uma chave. Essa struct tem de disponibilizar dois métodos: munge_in_place e munge. O primeiro ajusta um buffer de bytes no próprio local. O segundo é um adaptador de iterador: aceita um iterador de dados arbitrário e devolve um novo iterador de dados.

As assinaturas stub deste exercício estão, em grande parte, corretas em termos de sintaxe, mas não compilam: grande parte do objetivo deste exercício é que te familiarizes com o uso de lifetimes e generics, por isso vais ter de as preencher sozinho. Outro objetivo deste exercício é que descubras uma fatorização adequada que te permita implementar ambos os métodos com o mínimo de esforço duplicado. Não tenhas medo de introduzir funções auxiliares adicionais!

Traits úteis

Estes traits serão úteis:

Testes bónus

Este exercício contém testes bónus, por trás da feature flag io. Para os ativar, corre

cargo test --features io

Para estes testes, vais precisar de implementar um método reader com a assinatura

fn reader(self, impl Read) -> impl Read

e um método writer com a assinatura

fn writer(self, impl Write) -> impl Write

Cada uma destas funções converte a struct Xorcism num adaptador de fluxo na direção adequada. Usam estes traits:

Tempo de vida do valor devolvido por munge

Devido à utilização da funcionalidade impl Trait, a gestão dos tempos de vida pode ser um pouco complicada quando implementas o método munge. Podes achar mais fácil escrever a tua própria struct com uma implementação de Iterator e devolver esse tipo concreto, pelo menos para começar. Em última análise, é boa ideia tentares implementar a solução diretamente com os combinadores de Iterator.


Fonte

Peter Goodspeed-Niklaus
Editar via GitHub A ligação abre numa nova janela ou separador
Rust Exercism

Estás pronto para começar Xorcism?

Inscreve-te no Exercism para aprenderes e dominares Rust com 99 exercícios, e mentoria humana real, tudo grátis.