Universidade Estadual de Campinas Instituto de Computação INSTITUTO DE COMPUTAÇÃO

Roberto Cabral Rabêlo Filho

Implementação eficiente das funções de resumo criptográfico: SHA-3 e QUARK.

CAMPINAS 2015 Roberto Cabral Rabêlo Filho

Implementação eficiente das funções de resumo criptográfico: SHA-3 e QUARK.

Dissertação apresentada ao Instituto de Computação da Universidade Estadual de Campinas como parte dos requisitos para a obtenção do título de Mestre em Ciência da Computação.

Orientador: Prof. Dr. Julio César López Hernández

Este exemplar corresponde à versão final da Dissertação defendida por Roberto Cabral Rabêlo Filho e orientada pelo Prof. Dr. Julio César López Hernández.

CAMPINAS 2015 Agência(s) de fomento e nº(s) de processo(s): CNPq, 301566/2014-3; CAPES

Ficha catalográfica Universidade Estadual de Campinas Biblioteca do Instituto de Matemática, Estatística e Computação Científica Ana Regina Machado - CRB 8/5467

Rabêlo Filho, Roberto Cabral, 1990- R112i RabImplementação eficiente das funções de resumo criptográfico : SHA-3 e QUARK / Roberto Cabral Rabêlo Filho. – Campinas, SP : [s.n.], 2015.

RabOrientador: Julio César López Hernández. RabDissertação (mestrado) – Universidade Estadual de Campinas, Instituto de Computação.

Rab1. Hashing (Computação). 2. Criptografia. 3. Arquitetura de computador. I. López Hernández, Julio César,1961-. II. Universidade Estadual de Campinas. Instituto de Computação. III. Título.

Informações para Biblioteca Digital

Título em outro idioma: Efficient implementation of cryptography hash functions : SHA-3 and QUARK Palavras-chave em inglês: Hashing (Computer science) Cryptography Computer architecture Área de concentração: Ciência da Computação Titulação: Mestre em Ciência da Computação Banca examinadora: Julio César López Hernández [Orientador] Marcos Antonio Simplicio Junior Marco Aurélio Amaral Henriques Data de defesa: 16-12-2015 Programa de Pós-Graduação: Ciência da Computação

Powered by TCPDF (www.tcpdf.org) Universidade Estadual de Campinas Instituto de Computação INSTITUTO DE COMPUTAÇÃO

Roberto Cabral Rabêlo Filho

Implementação eficiente das funções de resumo criptográfico: SHA-3 e QUARK.

Banca Examinadora:

• Prof. Dr. Julio César López Hernández IC/UNICAMP

• Prof. Dr. Marcos Antonio Simplicio Junior LARC/USP

• Dr. Marco Aurélio Amaral Henriques FEEC/UNICAMP

A ata da defesa com as respectivas assinaturas dos membros da banca encontra-se no processo de vida acadêmica do aluno.

Campinas, 16 de dezembro de 2015 Agradecimentos

Agradeço primeiramente a Deus, por me dar força diariamente para continuar nessa jor- nada, me dando forças e sabedoria para trilhar o meu caminho.

Depois à minha família, que mesmo distante geograficamente, sempre me deram o apoio necessário, acreditaram em mim e me incentivaram a seguir minha jornada. Meu muito obrigado a minha mãe, Rosângela, meu pai, Roberto, e meus irmãos Ana e Robert. Eu não teria conseguido sem o apoio de vocês.

À minha noiva, Leonara, que me apoiou durante toda essa caminhada, muito obrigado por seu carinho, alegria e atenção; pela sua vibração com minhas conquistas e teu ombro amigo em cada momento difícil. Sem você, essa caminhada teria sido muito mais difícil.

Ao meu orientador, professor Julio, por me guiar durante o desenvolvimento deste tra- balho. Por compartilhar seus conhecimentos, pela paciência, dedicação e disponibilidade. Agradeço por me proporcionar essas experiências que levarei comido para sempre.

Aos membros da banca, professor Marcos Simplicio e professor Marco Aurelio, pelo tempo dedicado, pelas correções e propostas de melhorias.

Agradeço ao meu amigo Armando, por se disponibilizar, sempre que necessário, a me ajudar, com discussões pertinentes e troca de experiência e conhecimento. Também agra- deço pelo tempo disponibilizado para realizar revisões em meu trabalho.

Aos companheiros do LASCA que me auxiliaram, direta ou indiretamente, durante a minha pesquisa.

Registro meu reconhecimento à , por financiar o projeto ISRA, ao CNPq pela bolsa de Desenvolvimento Tecnológico e à CAPES pelo auxílio financeiro.

Finalmente agradeço aos demais que, de alguma forma, me ajudaram na conclusão deste trabalho: docentes, funcionários e colegas do Instituto de Computação da UNICAMP.

Muito Obrigado! Resumo

As funções de resumo criptográfico são primitivas de extrema importância, pois são ne- cessárias para a construção de inúmeros protocolos de segurança. Em 2007, o Instituto Nacional de Padrões e Tecnologias americano (NIST) iniciou um concurso público para escolher um novo padrão de funções de resumo criptográfico, conhecido por SHA-3; tal concurso teve fim em 2012, tendo como vencedor o algoritmo Keccak. A família SHA-3 tende a ser usada em larga escala nos próximos anos e é importante desenvolver implemen- tações eficientes e seguras destas funções; uma estratégia que pode ser usada é aproveitar conjuntos avançados de instruções vetoriais. Os processadores de propósito geral estão expandindo cada vez mais seus conjuntos de instruções; em 2013, a microarquitetura Haswell da Intel trouxe consigo o conjunto de instruções vetoriais AVX2, que expandiu as instruções de aritmética inteira nos registradores de 128 e 256 bits. Um dos objetivos gerais desta dissertação foi prover técnicas que viabilizem o uso eficiente dos conjuntos de instruções vetoriais na implementação do algoritmo SHA-3; este estudo culminou em um conjunto de implementações eficientes que usam registradores de 128 e 256 bits para cal- cular um, dois ou quatro valores de resumo concorrentemente, permitindo uma aceleração de 1,89 e 2,57 vezes na computação de dois e quatro valores de resumo, respectivamente. Adicionalmente, também foram estudadas funções de resumo criptográfico para disposi- tivos com recursos limitados; tais dispositivos estão ganhando cada vez mais mercado, sendo usados principalmente para a Internet das Coisas (IoT). A maioria dos algoritmos criptográficos desenvolvidos para esses dispositivos foram projetados para serem imple- mentados em hardware; do ponto de vista de implementação em software, esses algoritmos apresentam desafios para realizar uma implementação eficiente e segura. O QUARK é um algoritmo que foi projetado neste contexto; ele é uma família de funções de resumo que possui um bom desempenho em hardware, mas não possui implementações em software eficientes para processadores de 32 bits. Neste contexto, foram realizadas otimizações algorítmicas e de implementação no QUARK que permitiram acelerar sua execução na plataforma , atingindo um ganho de desempenho de aproximadamente 15 vezes quando comparado com a implementação de referência. Abstract

Cryptographic hash functions are extremely important primitives, as they are necessary for the construction of several cryptographic protocols. In 2007, the National Institute of Standards and Technology (NIST) started a competition to select the new version of the SHA algorithm family, called SHA-3; this competition ended in 2012, having Keccak as the winner. The SHA-3 family is expected to be used on a large scale in the coming years, so it is important to have fast and secure implementations of these functions; a strategy that can be used is to take advantage of the advanced instruction sets. General purpose processors are increasingly expanding their instruction sets; in 2013 the Intel’s microarchitecture, Haswell, brought the set of vector instructions AVX2 that expanded the integer arithmetic instructions in the registers of 128 and 256 bits. One of the general goals of this work was to provide techniques that facilitate the efficient use of sets of vector instructions in implementing the SHA-3 algorithm; this study culminated in a set of efficient implementations that use registers of 128 and 256 bits to calculate one, two or four hash values concurrently, allowing to compute two and four hash values 1.89 and 2.57 times faster, respectively. Additionally, cryptographic hash functions for resource-constrained devices were also studied; such devices are being used widely, mainly for the Internet of Things (IoT). Most of the cryptographic algorithms developed for these devices were designed to be implemented in hardware; from the point of view of software implementation, those algorithms present challenges to achieve a fast and secure implementation. QUARK is a family of lightweight hash functions that was designed for hardware implementation. In this work, we propose some algorithmic optimizations to obtain a fast software implementation of QUARK on the Intel Galileo platform, achieving a speedup of 15 times compared to the reference implementation. Lista de Figuras

2.1 As três propriedades de segurança de uma função de resumo, adaptado de [42]...... 16 2.2 Ataque do Homem no meio, adaptado de [51]...... 17 2.3 Construção esponja: Z = ESPONJA[f, pad, r](M, d)...... 21 2.4 Permutação P ...... 27

3.1 Conjunto de registradores vetoriais e de propósito geral da arquitetura Intel. 31

4.1 Organização do estado para implementação sequencial usando variáveis de 256 bits...... 41 4.2 Passo a passo da etapa de mapeamento θ na implementação sequencial usando as instruções de 256 bits...... 41 4.3 Passo a passo das etapas de mapeamento ρ e π na implementação sequencial usando as instruções de 256 bits...... 43 4.4 Valores a serem rotados na etapa ρ para a implementação sequencial usando as registradores de 256 bits...... 43 4.5 Passo a passo das etapas de mapeamento χ e ι na implementação sequencial usando as instruções de 256 bits...... 44 4.6 Organização do estado para as iterações subsequentes...... 46 4.7 Organização do estado entre a execução das etapas de mapeamento na implementação sequencial usando instruções de 128 bits...... 47 4.8 Organização do estado para implementação vetorizada (2M) usando ins- truções de 128 bits...... 51 4.9 Organização do estado para a iteração i + 1 na implementação vetorizada usando instruções de 128 bits...... 52 4.10 Organização do estado para implementação vetorizada (4M) usando ins- truções de 256 bits...... 54 4.11 Organização do estado para implementação vetorizada (2M) usando ins- truções de 256 bits...... 55 4.12 Teste de desempenho da família SHA-3...... 56 4.13 Teste de desempenho da família SHA-3...... 57

5.1 Inicialização das palavras t0, . . . , t12, usadas como entrada na primeira ite- ração da função u do algoritmo S-QUARK...... 62 5.2 Inicialização das palavras, t0, . . . , t12, usadas como entrada na primeira iteração da função u1 do algoritmo D-QUARK...... 66 5.3 Palavra t11 na iteração (i + 1)...... 66 Lista de Tabelas

2.1 Nível de segurança atingível pelas funções de resumo...... 19 2.2 Nível de segurança das funções SHA-1, SHA-2 e SHA-3 [40]...... 26 2.3 Parâmetros da família QUARK...... 29 2.4 Nível de segurança da família QUARK [3]...... 29

3.1 Latência, vazão (instruções executadas por ciclo quando não há dependên- cias) e portas de execução de algumas instruções AVX2...... 36 3.2 Latência, vazão e portas de execução de das instruções do conjunto BMI1 e BMI2...... 37 3.3 Principais características do microcontrolador Intel Galileo...... 38 3.4 Latência de algumas instruções da microarquitetura Quark...... 39

4.1 Valores a serem rotados na etapa de mapeamento ρ na implementação sequencial usando instruções de 128 bits...... 48 4.2 Especificações técnicas dos computadores HW-DESKTOP e HW-ULTRA. 56 4.3 Ciclos por bytes e speedup das implementações paralelas vetorizadas. . . . 57

5.1 Desempenho do código de referência usando as funções otimizadas. . . . . 67 5.2 Desempenho para nível de segurança de 112 bits...... 67 5.3 Desempenho para nível de segurança de 80 bits...... 68 Sumário

1 Introdução 12

2 Funções de Resumo Criptográfico 15 2.1 Propriedades ...... 15 2.2 Aplicações ...... 16 2.2.1 Autenticador de mensagem ...... 16 2.2.2 Assinatura digital ...... 17 2.2.3 Armazenamento de senhas ...... 18 2.3 Segurança ...... 18 2.3.1 Ataque do Aniversário ...... 18 2.3.2 Modelo do oráculo aleatório ...... 19 2.4 Construção de funções de resumo ...... 19 2.4.1 Construção Merkle-Damgård ...... 19 2.4.2 Construção Esponja ...... 20 2.5 Funções de resumo baseadas na construção esponja ...... 21 2.5.1 SHA-3 ...... 21 2.5.2 QUARK ...... 25 2.6 Resumo ...... 29

3 Micro Arquitetura Intel 30 3.1 Instruções vetoriais ...... 30 3.1.1 O conjunto de instruções AVX2 ...... 31 3.2 Instruções de manipulação de bits ...... 35 3.3 Intel Galileo ...... 37 3.4 Conjunto de instruções ...... 38 3.5 Resumo ...... 39

4 Implementação da família SHA-3 40 4.1 Implementação sequencial usando instruções de 256 bits ...... 40 4.2 Implementação sequencial usando instruções de 128 bits ...... 45 4.3 Implementação vetorizada (2M) usando instruções de 128 bits ...... 50 4.4 Implementação vetorizada (4M) usando instruções de 256 bits ...... 53 4.5 Implementação vetorizada (2M) usando instruções de 256 bits ...... 54 4.6 Testes de desempenho ...... 55 4.7 Conclusão ...... 58 5 Implementação da família QUARK 59 5.1 Otimizações algorítmicas ...... 59 5.2 S-QUARK ...... 61 5.3 D-QUARK ...... 63 5.4 Testes de desempenho ...... 66 5.5 Conclusão ...... 68

6 Conclusões e trabalhos futuros 69

Referências Bibliográficas 72

A 77 A.1 Família QUARK ...... 77 Capítulo 1

Introdução

A segurança da informação é um requisito básico para o bom funcionamento de muitas aplicações que utilizam informações sensíveis. Para prover esse requisito, as aplicações precisam usar protocolos criptográficos, que por sua vez devem ser implementados de forma eficiente e segura. Uma primitiva básica, que é crucial na construção de muitos protocolos criptográficos, chama-se função de resumo criptográfico; ela atua como uma função de compressão que mapeia uma cadeia de bits de tamanho arbitrário em uma cadeia de bits de tamanho fixo; essa flexibilidade nas aplicações lhes rendeu o apelido de canivete suíço da criptografia (Swiss army knives of cryptography) [43]. Durante a década de 80, percebeu-se a necessidade da criação de funções de resumo criptográfico eficientes e seguras; em pouco tempo, surgiram inúmeras propostas de fun- ções de resumo, sendo encontradas vulnerabilidades na maioria delas [43]. Em 1993, o Instituto Nacional de Padrões e Tecnologias americano (NIST) padronizou uma função de resumo que ficou conhecida por SHA-0 [45], a qual foi retirada pouco tempo após seu lançamento por conter problemas de segurança. Em 1995, o NIST publicou o SHA-1 [41] que possui um funcionamento interno muito similar ao SHA-0 e em 2001 foi publicado o padrão SHA-2 [44], que é bastante utilizado nos dias atuais. Esses padrões, entretanto, vêm sofrendo alguns ataques nos últimos anos; em 2005, os trabalhos [12] e [48] mostraram ataques baseados em colisões contra uma versão reduzida do SHA-1; no mesmo ano, Wang et al. [50] mostraram um ataque que quebra, teorica- mente, a resistência a colisão do SHA-1. A segunda versão da família, conhecida como SHA-2, possui uma estrutura muito similar ao SHA-1 e já possui alguns ataques à sua versão reduzida, como é mostrado em [31]. Por conta desses ataques à família SHA, em 2007 o NIST decidiu publicar uma chamada aberta para selecionar um novo algoritmo, que viria a ficar conhecido como SHA-3. Em 2012, após três rodadas de competição, o algoritmo Keccak [9] foi escolhido como vencedor [35].

SHA-3

O algoritmo SHA-3 baseia-se na construção esponja definida sobre a função de permutação Keccak-p[1600, 24] [40]; internamente, essa função trabalha sobre um estado de 1600 bits que pode ser visto como uma matriz de 25 palavras de 64 bits. A família SHA-3 é

12 CAPÍTULO 1. INTRODUÇÃO 13 composta por quatro funções de resumo criptográfico e duas funções de resumo com saída variável, Extendable Output Functions (XOF). Por ter vencido o concurso, espera-se que o algoritmo SHA-3 venha a ser usado nas aplicações criptográficas por muito anos. Assim, é importante fornecer implementações eficientes e seguras desse algoritmo nas arquiteturas modernas. Em 2013 a Intel lançou a microarquitetura Haswell, trazendo consigo o conjunto de instruções AVX2. Esse conjunto trouxe instruções que permitem acelerar a computação da permutação Keccak-p[1600, 24], como a instrução de deslocamento variável, que permite deslocar quantidades diferentes de bits em cada palavra de um registrador com apenas uma instrução. Nesta dissertação, foram aproveitados os conjuntos avançados de instruções vetoriais dos processadores atuais para implementar eficientemente a família de funções de resumo criptográfico SHA-3.

Dispositivos com recursos limitados

O forte crescimento da Internet das Coisas (IoT) tem aumentado a necessidade de im- plementação de protocolos criptográficos em dispositivos com recursos limitados. Neste cenário, as implementações devem ser rápidas, compactas, consumir pouca energia e serem resistentes a ataques de canal colateral. Nos últimos anos, apareceram alguns candidatos a funções de resumo leve, tais como o PHOTON [28], QUARK [2] e SPONGENT [13]. Em plataformas que não possuem um componente de hardware dedicado para funções de resumo criptográfico, uma abordagem comum é aproveitar o conjunto de instruções do dispositivo para implementar essas funções em software. Recentemente, funções de resumo criptográfico leves têm sido implementadas em software para microcontroladores de 8 bits; em [5] foi apresentado uma implementação em software das funções de resumo leves QUARK, PHOTON e SPONGENT para um nível de segurança de 80 e 112 bits; em [22] foram mostradas implementações em software de cifras de blocos leves. Por outro lado, para arquiteturas de 32 bits existem poucas implementações de funções de resumo leve. Um dos poucos exemplos é o trabalho realizado em [29], onde é apresentada uma implementação do PHOTON baseada em tabelas. Nesta dissertação foram propostas técnicas que permitiram implementar o algoritmo QUARK eficientemente na arquitetura Intel Galileo de 32 bits; tais técnicas permitiram um ganho substancial em desempenho e em tamanho de código.

Organização do documento

O restante do texto está dividido como segue: No Capítulo 2 são apresentadas, brevemente, as definições e propriedades das funções de resumo criptográfico, mostrando o nível de segurança atingível por essas funções e duas formas diferentes de construí-las; usando a construção Merkle-Damgård e usando a construção esponja. Adicionalmente, foram definidas duas famílias de funções de resumo criptográfico baseadas na construção esponja: a família SHA-3 e a família QUARK. No Capítulo 3 são descritas as arquiteturas usadas neste trabalho, primeiramente CAPÍTULO 1. INTRODUÇÃO 14 são apresentados alguns conjuntos de instruções vetoriais, com ênfase no conjunto de instrução AVX2, onde são destacadas as instruções mais relevantes para este trabalho e por fim é apresentada a plataforma Intel Galileo, que foi a arquitetura usada no contexto de dispositivos com recursos limitados. No Capítulo 4 são detalhadas as cinco implementações em software do algoritmo SHA-3 propostas neste trabalho. A primeira usa registradores de 256 bits para imple- mentar uma instância do algoritmo SHA-3; a segunda também calcula uma instância, mas agora usando registradores de 128 bits. Também são usados registradores de 128 bits para calcular duas mensagens, independentes e de mesmo tamanho, concorrentemente; e as outras duas implementações usam registradores de 256 bits para calcular dois e quatro valores de resumo por vez. No Capítulo 5 é apresentado como adaptar os algoritmo da família QUARK para viabilizar uma implementação eficiente em software para arquiteturas de 32 bits. Primei- ramente são apresentadas otimizações algorítmicas na função de permutação do algoritmo e em seguida é mostrado como tirar proveito do paralelismo inerente do algoritmo para implementá-lo eficientemente. Finalmente, no Capítulo 6 são apresentadas as conclusões do trabalho e possíveis caminhos a serem seguidos. Capítulo 2

Funções de Resumo Criptográfico

As funções de resumo criptográfico agem como uma função de compressão que mapeia uma cadeia de bits de tamanho arbitrário1 em uma cadeia de bits de tamanho fixo. Elas são muito usadas na criptografia moderna e seu uso é essencial em várias aplicações de segurança, tais como: esquemas de assinatura digital, verificação da integridade dos dados, geração de números pseudo aleatórios, geração de chaves, dentre outras. A cadeia de bits gerada é chamada de valor de resumo criptográfico ou digest e, para efeitos práticos, deve identificar a mensagem de forma única. Definição 2.1 Uma função de resumo h : M → R, com |M| > |R|, mapeia uma cadeia de bits m ∈ M de tamanho finito e arbitrário em uma cadeia de bits r ∈ R de tamanho fixo n. Escreve-se, r = h(m). Pode-se notar que mais de uma mensagem pode ser mapeada em um mesmo valor de resumo, visto que o domínio M de h é maior que sua imagem R. Porém, algumas aplica- ções, como as assinaturas digitais, por exemplo, requerem que seja computacionalmente inviável encontrar duas mensagens diferentes que gerem o mesmo valor de resumo; outras apenas necessitam que seja inviável encontrar uma mensagem dado o valor de resumo. As primeiras definições, análises e construções de funções de resumo criptográfico podem ser encontradas nos trabalhos de Rabin [46], Yuval [52] e Merkle [37]. Rabin propôs um modelo baseado no algoritmo de encriptação DES; Yuval usou o paradoxo de aniversário para mostrar como encontrar colisões para uma função de resumo de n bits n com 2 2 operações; e Merkle introduziu que esse tipo de função deveria ser resistente a colisões, primeira pré-imagem e segunda pré-imagem.

2.1 Propriedades

As funções de resumo criptográfico, diferente dos algoritmos de encriptação, não possuem chaves secretas. Assim, para uma função de resumo ser considerada segura nas aplicações criptográficas ela deve ser resistente à colisão, à primeira pré-imagem e à segunda pré- imagem. A seguir é apresentada uma definição informal sobre essas propriedades de segurança: 1Existe um limite físico do tamanho da mensagem, mas esse número é muito grande, por exemplo, no SHA-2 é 264−1 bits.

15 CAPÍTULO 2. FUNÇÕES DE RESUMO CRIPTOGRÁFICO 16

m =? m0 m1 =? m0 =? m1 =?

h h h

r = h(m) h(m0) = h(m1) h(m0) = h(m1) (a) Pré-imagem. (b) Segunda pré-imagem. (c) Colisões.

Figura 2.1: As três propriedades de segurança de uma função de resumo, adaptado de [42].

Resistência à primeira pré-imagem Dada uma função h : M → R e um valor de resumo r ∈ R, é computacionalmente inviável encontrar uma mensagem m ∈ M tal que h(m) = r.

Resistência à segunda pré-imagem

Dada uma função h : M → R e uma mensagem m0 ∈ M, é computacionalmente inviável encontrar uma mensagem m1 ∈ M tal que m0 6= m1 e h(m0) = h(m1).

Resistência à colisão Dada uma função h : M → R, é computacionalmente inviável encontrar duas

mensagens m0, m1 ∈ M tal que m0 6= m1 e h(m0) = h(m1).

Essas propriedades são ilustradas na Figura 2.1, suas definições formais podem ser encon- tradas em [49]. Uma função de resumo resistente a colisões também é resistente à segunda pré-imagem, pois, se a partir de uma mensagem m0 um adversário conseguir encontrar uma mensagem m1 tal que m0 6= m1 e h(m0) = h(m1), ele conseguiria encontrar um par m0 e m1 diferentes que produzem o mesmo valor de resumo [36]. Entretanto, uma função de resumo ser resistente à colisão não garante que ela seja resistente à primeira pré-imagem [49].

2.2 Aplicações

As funções de resumo são amplamente utilizadas na construção de protocolos criptográfi- cos. Nesta seção, são apresentadas algumas aplicações que utilizam as funções de resumo.

2.2.1 Autenticador de mensagem Um autenticador de mensagem é um mecanismo usado para verificar a integridade de uma mensagem. Esse mecanismo provê garantias de que uma informação recebida é exatamente a mesma que foi enviada, isto é, seu conteúdo não foi modificado durante a transmissão. As funções de resumo podem ser usadas para prover a integridade de uma mensagem da seguinte forma: primeiramente o emissor calcula o valor de resumo r de uma mensagem m CAPÍTULO 2. FUNÇÕES DE RESUMO CRIPTOGRÁFICO 17

Figura 2.2: Ataque do Homem no meio, adaptado de [51]. e envia a mensagem juntamente com o valor de resumo; o receptor aplica a mesma função de resumo sobre a mensagem m0 obtendo um valor de resumo r0; por fim, o receptor compara o valor de resumo calculado, r0, com o valor de resumo recebido, r, e caso esses valores não sejam iguais o receptor conclui que a mensagem ou o valor de resumo foram alterados em trânsito. O valor de resumo deve ser transmitido de forma segura, isto é, um adversário não pode ter acesso a tal informação, pois ele poderia modificar o valor de resumo r pelo valor de resumo r0 = h(m0), onde m0 é a mensagem modificada pelo atacante, e enviar para o receptor a mensagem m0 e o valor de resumo r0. Este cenário é conhecido por ataque do homem no meio (Man-in-the-middle) e é ilustrado na Figura 2.2, no qual o emissor transmite uma mensagem concatenada com seu valor de resumo; no meio do caminho um atacante intercepta essa informação, a mensagem, calcula um novo valor de resumo, concatena esse valor à mensagem e envia a informação para o receptor; ao receber a mensagem, o receptor não consegue detectar qualquer modificação na mesma.

2.2.2 Assinatura digital Outra aplicação importante, que é similar ao autenticador de mensagem, é a assinatura digital. Existem inúmeros métodos de assinaturas digitais que usam criptografia de chave pública; tais algoritmos, normalmente, possuem um alto custo computacional para assinar dados. Assim sendo, para gerar a assinatura digital de um documento, normalmente, calcula-se o valor de resumo do mesmo e então a assinatura é gerada a partir deste resumo. Como exemplo de uso da assinatura digital pode-se imaginar uma empresa de software que deseja distribuir uma atualização autenticada, isto é, o cliente deve conseguir iden- tificar que a atualização do sistema é autêntica e uma terceira parte maliciosa não deve conseguir se passar pela empresa e fazer o cliente instalar uma atualização que não foi dis- ponibilizada pela empresa. Para fazer isso, a empresa pode assinar a atualização com sua chave privada e distribuir a assinatura juntamente com a atualização; assim, cada cliente pode usar a chave pública da empresa para verificar a autenticidade da atualização. CAPÍTULO 2. FUNÇÕES DE RESUMO CRIPTOGRÁFICO 18

2.2.3 Armazenamento de senhas A maioria dos sistemas usados atualmente necessitam da autenticação dos usuários; uma forma de implementar a autenticação é pelo uso de senhas, associando uma senha a cada usuário de modo que para ele ter acesso a algum recurso do sistema ele deve apresentá-la. Uma forma trivial de gerenciar as senhas do sistema é colocá-las em um único arquivo; no entanto, essa técnica apresenta problemas de segurança, pois caso um atacante tenha acesso a esse arquivo ele teria acesso a todas as senhas dos usuários. Uma solução para esse problema é usar funções de resumo. Neste cenário, ao invés de guardar a senha propriamente dita, é guardado o valor de resumo e no momento da autenticação é computado o valor de resumo da senha do usuário e esse valor é comparado com o valor armazenado no arquivo de senhas; assim, mesmo que o atacante tenha acesso ao arquivo de senhas, por conta da propriedade de resistência a pré-imagem, ele não teria acesso às senhas dos usuários. Uma informação útil que o atacante poderia ter acesso nesse cenário seria saber quais usuários possuem a mesma senha, visto que a aplicação de uma função de resumo em duas mensagens iguais deve resultar em duas saídas iguais. Para dificultar tal ataque, é introduzida uma palavra aleatória de n bits, denominada salt, que é utilizada juntamente com a senha para calcular o resumo. O acréscimo do salt baixa substancialmente a possibilidade de resumos idênticos no arquivo de senhas, pois agora mesmo que dois usuários possuam a mesma senha, se o valor do salt for diferente, o valor de resumo será diferente.

2.3 Segurança

2.3.1 Ataque do Aniversário Esse ataque possui ênfase na propriedade de resistência à colisão, consistindo em achar duas mensagens diferentes que gerem o mesmo valor de resumo, isto é, encontrar duas mensagens m0, m1 ∈ M tal que m0 6= m1 e h(m0) = h(m1). Ele recebe este nome pois baseia-se no paradoxo do aniversário [52], que é propriedade estatística frequentemente usada para realizar criptoanálise. O paradoxo do aniversário consiste em determinar a probabilidade de que, dado k pessoas em uma sala, existam duas pessoas que fazem aniversário no mesmo dia. Encontrar colisões em uma função de resumo pode ser mapeado ao problema de en- contrar duas pessoas que fazem aniversário no mesmo dia [42]. Fazendo o mapeamento direto, o número de possíveis valores de saída passa de 365, quantidade de dias no ano, para 2n, onde n é o tamanho do valor de resumo. Neste cenário, deseja-se saber qual a quantidade de mensagens mi um atacante precisa testar até encontrar duas mensagens diferentes que produzam o mesmo valor de resumo. Em [42] Paar e Pelzl mostraram que o número de mensagens que precisam ser testadas para encontrar uma colisão equivale à raiz quadrada do número de possíveis valores de √ n resumo, ou seja, 2n; assim, pode-se dizer que são necessárias 2 2 operações para encontrar uma colisão em uma função de resumo com tamanho de saída n, ou que essa função possui CAPÍTULO 2. FUNÇÕES DE RESUMO CRIPTOGRÁFICO 19

n um nível de segurança de 2 bits. Segundo Katz e Lindell [36] não existe qualquer ataque genérico à segunda e à pri- meira pré-imagem que possa ser executado com menos que 2n operações; na Tabela 2.1 é apresentado um resumo do nível de segurança atingível por uma função de resumo com saída de n bits.

Tabela 2.1: Nível de segurança atingível pelas funções de resumo.

Propriedades Nível de segurança em bits

Primeira pré-imagem n Segunda pré-imagem n n Colisão 2

2.3.2 Modelo do oráculo aleatório O oráculo aleatório pode ser visto como uma caixa preta que recebe como entrada uma cadeia de bits de tamanho variado e retorna uma cadeia de bits de tamanho arbitrário. Qualquer um pode interagir com ele, seja uma entidade honesta ou um atacante, sendo que tal interação consiste de uma cadeia de bits x como entrada e uma cadeia de bits y como saída. O modelo do oráculo aleatório foi introduzido em 1993 por Mihir Bellare e Phillip Rogaway em [6] e fornece uma metodologia formal que pode ser usada no projeto e validação de esquemas criptográficos; tal metodologia consiste em provar a segurança de um esquema considerando a existência de um oráculo aleatório e, ao implementar esse esquema no mundo real, substituir o oráculo aleatório por uma função de resumo apropriada [36]. Entretanto, Canetti, Goldreich e Halevi mostraram em [17] esquemas que são seguros no modelo oráculo aleatório, mas são inseguros para qualquer instância concreta do oráculo aleatório usando funções de resumo criptográfico.

2.4 Construção de funções de resumo

Nesta seção são apresentadas duas construções amplamente usadas no projeto de funções de resumo criptográfico: a construção Merkle-Damgård e a construção esponja.

2.4.1 Construção Merkle-Damgård Uma forma comum de construir funções de resumo é projetar uma função de compressão resistente à colisão com tamanho de entrada fixo e então usar extensão de domínio para criar uma função com tamanho de entrada arbitrário [36]. De forma independente, Merkle e Damgård provaram em [39] e [20] que uma função de resumo criptográfico resistente à colisão pode ser construída a partir de uma função de compressão resistente à colisão e uma regra de preenchimento adequada. Assim, o esforço de construir uma função de CAPÍTULO 2. FUNÇÕES DE RESUMO CRIPTOGRÁFICO 20 resumo resistente a colisões pode ser reduzido a produzir uma função de compressão segura. Esse método foi muito utilizado na construção de funções de resumo, incluindo os algoritmos MD5, SHA-1 e SHA-2. Seja f : {0, 1}2n → {0, 1}n uma função de compressão com 2n bits de entrada e n bits de saída. A construção de uma função de resumo criptográfico h que recebe como entrada uma mensagem m de b bits seguindo a metodologia Merkle-Damgård é descrita a seguir:

1. Divida a mensagem m em k blocos (x1, . . . , xk) de n bits, completando o último bloco com bits zero, caso necessário.

2. Defina um bloco adicional xk+1 contendo a representação binária de b, ou seja, o tamanho da mensagem.

n 3. Seja z0 = 0 (O valor de z0 é conhecido por vetor de inicialização e pode ser trocado por qualquer constante).

4. Para 1 ≤ i ≤ k + 1, calcule zi = f(zi−1||xi).

5. O valor de resumo da mensagem m (de n bits) é calculado como h(m) = zk+1 = f(zk||xk+1).

2.4.2 Construção Esponja A construção esponja foi proposta por Bertoni, Daemen, Peeters e Van Assche no Ecrypt Hash Workshop em maio de 2007 [10]. Ela é um modo de operação baseado em uma permutação f de tamanho fixo e uma regra de preenchimento p que constrói uma função, denominada função esponja, com tamanho variado de entrada e um tamanho arbitrário de saída. A função esponja imita o comportamento de um oráculo aleatório, exceto pelo fato de que na construção esponja podem ocorrer colisões internas, uma vez que ela possui uma espaço de memória finito [10]. Do ponto de vista prático, a construção esponja pode ser usada na elaboração de muitos algoritmos simétricos, tais como: funções de resumo, geração de números pseudo- aleatórios, derivação de chaves, encriptação, autenticador de mensagens (MAC - Message Authentication Code) e encriptação autenticada [27]. Essa vasta aplicabilidade fornece ao usuário uma gama de funcionalidades a partir de uma função de permutação, facilitando assim o reuso de implementações da função de permutação. Do ponto de vista teórico, uma função esponja aleatória (que é uma instância da construção esponja com a permutação f escolhida aleatoriamente dentre um conjunto de permutações) é uma alternativa ao modelo de oráculo aleatório para expressar provas de segurança [27], uma vez que foi provado em [8] que uma função esponja aleatória é tão forte quanto um oráculo aleatório, exceto pelo efeito introduzido pela memória finita. A construção esponja [10] define uma função ESPONJA[f, pad, r] com domínio {0, 1}∗ e codomínio {0, 1}∞ usando uma permutação de tamanho fixo f, uma regra de preenchi- mento pad e uma taxa de bits r. A partir desta função, uma saída de tamanho finito pode ser obtida pelo truncamento dos primeiros l bits. Uma instância da construção esponja é chamada de função esponja. CAPÍTULO 2. FUNÇÕES DE RESUMO CRIPTOGRÁFICO 21

M m1 m2 m3 ... mk h1 h2 h3 ... hn

S P P P P P P P

Figura 2.3: Construção esponja: Z = ESPONJA[f, pad, r](M, d).

A função esponja opera sobre um estado de b = r + c bits, onde r é a taxa de bits e c é a capacidade. Primeiramente, todos os bits do estado são inicializados com zeros. A regra de preenchimento pad é aplicada sobre a mensagem de entrada e posteriormente a mensagem é dividida em k blocos de r bits; feito isso, o processamento é composto por duas fases: a fase de absorção e a fase de extração. Na fase de absorção é aplicado uma operação XOR entre um bloco de r bits da mensagem de entrada com os primeiros r bits do estado atual. Então, o estado é atualizado por meio de uma permutação f; esse processo é aplicado para cada um dos k blocos da mensagem. Na fase de extração os primeiros r bits do estado são usados como saída; se o tamanho de l for maior que o tamanho de r, o estado é processado novamente pela permutação f e os r bits retornados são concatenados com os r bits retornados previamente; esse processo é repetido até que os l bits requeridos sejam extraídos. Os últimos c bits do estado nunca são afetados diretamente pelos blocos de entrada na fase de absorção e nem extraídos na fase de extração; o parâmetro c determina a segurança atingível pela construção [8]. A construção esponja é ilustrada na Figura 2.3 e seu pseudo-código é apresentado no Algoritmo 1.

2.5 Funções de resumo baseadas na construção esponja

Nesta seção são apresentadas duas famílias de funções de resumo criptográfico baseadas na construção esponja: a família SHA-3 e a família QUARK.

2.5.1 SHA-3 A família de funções de resumo criptográfico SHA-3 baseia-se na construção esponja definida sobre a função de permutação Keccak-p[1600,24]; ela está definida no documento oficial FIPS 202 [40], o qual descreve os detalhes da família SHA-3 e padroniza quatro funções de resumo criptográfico: SHA3-224, SHA3-256, SHA3-384 e SHA3-512; e duas funções de resumo com saída variável, Extendable Output Functions (XOF), chamadas CAPÍTULO 2. FUNÇÕES DE RESUMO CRIPTOGRÁFICO 22

Entrada: Cadeia de dados M e um inteiro não negativo d. Saída: Cadeia de dados Z, tal que |Z| = d. 1: P = M k pad(r, |M|) 2: n = |P |/r 3: c = b − r 4: Seja P = P0 k ... k Pn−1 a divisão de P em blocos de tamanho r. 5: S = 0b 6: for all i tal que 0 ≤ i < n do c 7: S = f(S ⊕ (Pi k 0 )) 8: end for 9: Seja Z uma cadeia de dados vazia. 10: while d > |Z| do 11: Z = Z k Truncr(S) 12: Se d > |Z| então S = f(S) 13: end while 14: Retorno: Truncd(Z) Algoritmo 1: ESPONJA[f, pad, r](M, d)

SHAKE128 e SHAKE256. A família SHA-3 baseada no algoritmo Keccak é apresentada a seguir.

Permutações Keccak-p

Uma permutação Keccak-p que possui nr rodadas e trabalha sobre um estado S de b bits, é denotada por Keccak-p[b, nr]; a permutação é definida para quaisquer b ∈ {25, 50, 100, 200, 400, 800, 1600} e qualquer inteiro positivo nr. Uma rodada da permuta- ção Keccak-p consiste de uma sequência de cinco transformações, chamadas de etapas de mapeamento. O estado interno do algoritmo pode ser organizado em uma matriz 5 × 5 × w, onde w = b/25 pode ser visto como o tamanho das palavras do estado em bits. As 25 palavras de w bits de um estado S são denotadas por si para 0 ≤ i < 25 como pode ser visto a seguir:   s0 s1 s2 s3 s4  s s s s s   5 6 7 8 9    S = s10 s11 s12 s13 s14 ; S[x, y] = s5x+y para 0 ≤ x, y < 5. (2.1)   s15 s16 s17 s18 s19 s20 s21 s22 s23 s24 Etapas de mapeamento. As cinco etapas de mapeamento usadas durante uma rodada da função Keccak-p[b, nr] são denotadas por θ, ρ, π, χ e ι. O algoritmo para cada uma dessas etapas tem como entrada um estado S e como saída esse estado atualizado. A etapa de mapeamento ι é a única que possui uma entrada adicional, um inteiro ir chamado índice da rodada. O tamanho do estado é um parâmetro que está omitido da notação, pois b sempre é especificado quando as etapas de mapeamento são chamadas; visando simplificar a CAPÍTULO 2. FUNÇÕES DE RESUMO CRIPTOGRÁFICO 23 notação, todas as operações lógicas e de rotação usadas nas etapas de mapeamento são aplicadas sobre palavras de tamanho w. As especificações das etapas de mapeamento são apresentadas a seguir:

• Etapa de mapeamento θ. O efeito da etapa θ é aplicar uma operação XOR entre cada palavra do estado com a paridade de duas colunas do estado.

• Etapa de mapeamento ρ. Nesta etapa cada palavra do estado é rotacionada

uma quantidade fixa de ri bits. Na Equação 2.2 pode-se ver a matriz R, onde cada elemento ri representa a quantidade de bits que a palavra si será rotada.

 0 1 62 28 27 36 44 6 55 20     R =  3 10 43 25 39 ; R[x, y] = r5x+y para 0 ≤ x, y < 5. (2.2)   41 45 15 21 8  18 2 61 56 14

• Etapa de mapeamento π. O efeito da etapa de mapeamento π é embaralhar as palavras do estado. Ela promove uma difusão a longo prazo dentro das rodadas, a fim de evitar que padrões sejam explorados em determinados ataques.

• Etapa de mapeamento χ. O efeito da etapa de mapeamento χ é aplicar uma

operação XOR em cada palavra do estado si com a saída de uma função não linear aplicada a duas palavras da mesma linha de si.

• Etapa de mapeamento ι. A etapa de mapeamento ι consiste na aplicação de

uma operação XOR entre o elemento s0 com um valor contante rc(ir), onde os valores de rc são definidos em [40] e são gerados a partir de um Linear Feedback Shift Register (LFSR). O efeito desta etapa consiste em modificar alguns bits da

palavra s0 de acordo com o índice da rodada ir. As outras 24 palavras do estado nunca são afetadas diretamente pela etapa de mapeamento ι.

Dado um estado S e o índice de uma rodada ir, uma função Rnd é a transformação que resulta na aplicação das etapas de mapeamento θ, ρ, π, χ e ι, da seguinte forma:

Rnd(S, ir) = ι(χ(π(ρ(θ(S)))), ir). (2.3)

A permutação Keccak-p[b, nr] consiste de nr iterações de Rnd. Um pseudocódigo da função Rnd é apresentado no Algoritmo 2.

A família Keccak

Keccak é uma família de funções de resumo originalmente definida em [9]. A seguir, são descritas a permutação fundamental e a regra de preenchimento usadas pela família Keccak: CAPÍTULO 2. FUNÇÕES DE RESUMO CRIPTOGRÁFICO 24

Entrada: Estado S e ir o índice da rodada. Saída: Estado S atualizado S = Rnd(S). Etapa de mapeamento θ 1: C[y] = S[0, y] ⊕ S[5, y] ⊕ S[10, y] ⊕ S[15, y] ⊕ S[20, y] para 0 ≤ y < 5 2: D[x] = C[(x − 1) mod 5] ⊕ (C[(x + 1) mod 5] ≪ 1) para 0 ≤ x < 5 3: S[x, y] = S[x, y] ⊕ D[x] para 0 ≤ x, y < 5 Etapa de mapeamento ρ 4: S[x, y] = (S[x, y] ≪ R[x, y]) para 0 ≤ x, y ≤ 4 Etapa de mapeamento π 5: S0[(2y + 3x) mod 5, x] = S[x, y] para 0 ≤ x, y ≤ 4 Etapa de mapeamento χ 6: for all (x, y) tal que 0 ≤ x, y < 5 do 7: T = (S0[x, (y + 2) mod 5] ∧ (¬S0[x, (y + 1) mod 5]) 8: S[x, y] = S0[x, y] ⊕ T 9: end for Etapa de mapeamento ι 10: s0 = s0 ⊕ rc(ir) 11: Retorno: S. Algoritmo 2: Rnd(S).

• Regra de preenchimento pad10∗1. A família Keccak usa a regra de preenchi- mento multi-taxa, denotada por pad10∗1, que recebe como entrada o tamanho da mensagem m e a taxa de bits r, retornando uma cadeia binária Z = 1||0j||1, onde j = −(m + 2) mod r.

• Especificação de Keccak[c]. A família de funções esponjas Keccak com a função ∗ de permutação Keccak-p[b, nr] e a regra de preenchimento pad10 1 está definida para quaisquer par de taxa de bits r e capacidade c tal que r + c ∈ {25, 50, 100, 200, 400, 800, 1600}. Quando o tamanho do estado é restrito a b = 1600, a família Keccak é denotada Keccak[c]; nesse caso, r é determinado pela escolha do parâmetro c. Em particular,

Keccak[c] = ESPONJA[Keccak-p[1600, 24], pad10∗1, 1600 − c].

Assim, dada uma mensagem M e um tamanho de saída d, tem-se

Keccak[c](M, d) = ESPONJA[Keccak-p[1600, 24], pad10∗1, 1600 − c](M, d).

Especificações da família SHA-3

As quatro funções de resumo SHA-3 são definidas a partir da aplicação da função Keccak[c] sobre uma mensagem M concatenada com dois bits e a especificação do tamanho de saída, como pode ser visto a seguir: CAPÍTULO 2. FUNÇÕES DE RESUMO CRIPTOGRÁFICO 25

SHA3-224(M) = Keccak[448](M||01,224) SHA3-256(M) = Keccak[512](M||01,256) SHA3-384(M) = Keccak[768](M||01,384) SHA3-512(M) = Keccak[1024](M||01,512). Em cada caso, a capacidade sempre é o dobro do tamanho da saída; os dois bits adici- onados à mensagem (01) servem para dar suporte à separação de domínio, por exemplo, distinguir as mensagens processadas pela função de resumo SHA-3 e pelas funções com saída variável. As duas funções com saída variável, SHAKE128 e SHAKE256 são definidas a partir da função Keccak[c], uma mensagem M concatenada com quatro bits e pela especificação do tamanho de saída d, como é apresentado a seguir: SHAKE128(M) = Keccak[256](M||1111,d) SHAKE256(M) = Keccak[512](M||1111,d). Os primeiros dois bits servem para dar suporte a separação de domínio e os dois bits adicionais (11) são usados para prover compatibilidade ao esquema Sakura [11]. Esse esquema facilitará o desenvolvimento de uma extensão dessas funções, chamada resumos em árvore [38], onde a mensagem pode ser processada em paralelo, conseguindo assim computar mensagens longas de forma mais eficiente.

Segurança

Usualmente, as aplicações requerem que as funções de resumo sejam resistentes contra ataques baseados em colisões, pré-imagem e segunda pré-imagem. Um resumo desses parâmetros para todas as funções da família SHA pode ser encontrado na Tabela 2.2. Para o nível de segurança contra ataques à segunda pré-imagem em uma mensagem M, a função L(M) é definida como dlog2(len(M)/B)e, onde B é o tamanho do bloco da função, por exemplo, 512 bits para SHA-1, SHA-224 e SHA-256 e 1024 bits para o SHA-512. As quatro funções de resumo SHA-3 são alternativas à funções da família SHA-2, provendo um nível de segurança pelo menos igual ao da família SHA-2 contra os ataque à colisões, à primeira pré-imagem e à segunda pré-imagem. As duas funções SHA-3 com saída variável foram projetadas para serem resistentes à colisão, à primeira pré-imagem e à segunda pré-imagem, e a outros ataque que sejam resistentes por uma função aleatória de mesmo tamanho, até o nível de segurança de 128 bits para o SHAKE128 e 256 bits para o SHAKE256. Essas funções, assim como uma função aleatória, não conseguem prover um nível de segurança maior que d/2 bits contra ataques baseados em colisões e d bits contra ataques de pré-imagem e de segunda pré-imagem [40].

2.5.2 QUARK A família de funções de resumo leve, QUARK, foi apresentada pela primeira vez em 2010 por Aumasson, Henzen, Meier e Naya-Plasencia em [2]. Em 2013, uma versão estendida foi publicada em [3], onde foi feita uma pequena correção no tamanho da saída do algoritmo, de modo que o parâmetro n foi incrementado para corrigir uma falha na análise inicial. CAPÍTULO 2. FUNÇÕES DE RESUMO CRIPTOGRÁFICO 26

Tamanho Nível de segurança em bits Funções de saída Colisão Pré-imagem 2a Pré-imagem SHA-1 160 <80 160 160-L(M) SHA-224 224 112 224 min(224, 256-L(M)) SHA-512/224 224 112 224 224 SHA-256 256 128 256 256-L(M) SHA-512/256 256 128 256 256 SHA-384 384 192 384 384 SHA-512 512 256 512 512-L(M) SHA3-224 224 112 224 224 SHA3-256 256 128 256 256 SHA3-384 384 192 384 384 SHA3-512 512 256 512 512 SHAKE128 d min(d/2, 128) ≥ min(d, 128) min(d, 128) SHAKE256 d min(d/2, 256) ≥ min(d, 256) min(d, 256)

Tabela 2.2: Nível de segurança das funções SHA-1, SHA-2 e SHA-3 [40].

Como na família SHA-3, o QUARK também baseia-se na construção esponja; entre- tanto, eles possuem objetivos diferentes, uma vez que a família SHA-3 foi projetada para ser um algoritmo de propósito geral e a família QUARK foi pensada para arquiteturas com recursos limitados. A família de funções de resumo leve QUARK é apresentada a seguir.

Permutação P

A permutação do QUARK foi inspirada no algoritmo de cifra de fluxo Grain [30] e no ci- frador de bloco KATAN [21]. Internamente, a função P é composta por três Registradores de Deslocamento com Retroalimentação (FSRs), dos quais um é linear (L) e dois são não lineares (X e Y ), o diagrama que representa o comportamento interno desta permutação é mostrado na Figura 2.4. A permutação P é a função crítica em termos de desempenho do algoritmo QUARK; sua entrada é um estado de b bits e sua saída é o estado atualizado. A computação da permutação P pode ser dividida em três etapas básicas, que são:

b 1. Inicialização: Nesta etapa, o registrador X é inicializado com os primeiros 2 bits b do estado S, o vetor Y com os últimos 2 bits e o vetor L, de tamanho q = dlog 4be bits, é inicializado com todos os bits um.

S =X||Y. L =(1, 1,..., 1).

2. Atualização: Esta etapa é executada 4b vezes. Em cada iteração, os i-ésimos bits

de X, Y e L, denotados por Xi, Yi e Li, são atualizados como segue: CAPÍTULO 2. FUNÇÕES DE RESUMO CRIPTOGRÁFICO 27

Xi =f(X) ⊕ h(X,Y,L) ⊕ Yi.

Yi =g(Y ) ⊕ h(X,Y,L).

Li =p(L).

3. Saída: Ao final da etapa de atualização, a saída é do estado S é composta pelos b valores de X e Y , sendo que os primeiros 2 bits do estado são atualizados com os b valores contidos em X e os últimos 2 bits são atualizados com os valores contidos em Y .

Os valores de inicialização do LFSR L são constantes; desse modo, seus valores para cada iteração podem ser pré-computados antes da execução do algoritmo. O algoritmo usado para calcular a permutação P pode ser visto no Algoritmo 3. As definições das funções f, g e h são diferentes para cada uma das instâncias e estão definidas no Apêndice A.1.

Figura 2.4: Permutação P .

Construção Esponja

Como já mencionado, a função esponja opera sobre um estado de b = r + c bits. Dado um estado S2 (de b bits) e uma mensagem M (de tamanho arbitrário), a construção esponja

2O estado de cada instância da família QUARK é inicializado com os primeiros b bits do valor de resumo calculado pelo SHA-256 de seu nome. CAPÍTULO 2. FUNÇÕES DE RESUMO CRIPTOGRÁFICO 28 processa a mensagem em três etapas: 1. Inicialização. A mensagem é completada pela aplicação de uma regra de pre- enchimento pad, que concatena o bit “1” a mensagem M seguido por j bits zeros M = M||10j, onde j = −(|M| + 1) mod r.

2. Absorção. A mensagem é dividida em k blocos de r bits (M1,...,Mk). Então, em cada iteração o estado é atualizado pela computação de uma operação XOR entre um bloco da mensagem com os últimos r bits do estado atual. Uma vez atualizado o estado, ele é processado pela permutação P ; esse processamento é aplicado para cada um dos k blocos da mensagem.

3. Extração. Os últimos r bits do estado são usados como saída; se o tamanho da saída for maior que r, o estado é processado novamente pela permutação P e os r bits retornados são concatenados com os r bits retornados previamente; esse processo é repetido até que os bits requeridos sejam extraídos.

Entrada: Um estado S de b bits. Saída: Um estado S atualizado S = P (S).

1: X = (S0,...,S(b/2)−1) 2: Y = (Sb/2,...,Sb−1) 3: for j=0 to 7 do 4b 4: for i=0 to ( 8 ) − 1 do 0 5: h = h(X,Y,L 4b ) j∗ 8 +i 0 6: Xi = f(X) ⊕ h ⊕ Yi 0 7: Yi = g(Y ) ⊕ h 8: end for 9: end for 10: (S0,...,S b ) = X ( 2 −1 11: (S b ,...,Sb−1) = Y 2 12: Retorno: S. Algoritmo 3: Função de Permutação P

Na fase de absorção da família QUARK é aplicada uma operação XOR entre os blocos da mensagem com os últimos r bits do estado, no lugar dos primeiros r bits como definido pela construção esponja em [10]. Segundo [3], usar os últimos r bits na absorção para a família QUARK permite uma melhor difusão, pois a diferença introduzida nos últimos bits permaneceram nos registradores por mais tempo, uma vez que é usado FSRs. Na fase de extração, os bits extraídos também são os últimos r bits do estado; isso acontece porque esses são os últimos bits calculados pela permutação, extrair os primeiros bits tornaria as últimas iterações desnecessárias.

Família QUARK

A família de funções de resumo leve QUARK é composta por três diferentes instâncias - U-QUARK, D-QUARK e S-QUARK (definidas no Apêndice A.1) - com diferentes valores CAPÍTULO 2. FUNÇÕES DE RESUMO CRIPTOGRÁFICO 29

Tabela 2.3: Parâmetros da família QUARK.

Instância Taxa de bits (r) Capacidade (c) Rodadas (4b) Valor de saída (n) Grau de Paralelismo

U-QUARK 8 128 544 136 8 D-QUARK 16 160 704 176 8 S-QUARK 32 224 1024 256 16 de capacidade c, taxa de bits r, valor de saída n e as funções f, g e h. Os parâmetros para cada uma das instâncias são mostrados na Tabela 2.3.

Segurança

Como a família SHA-3, a segurança do QUARK baseia-se nas propriedades da construção esponja e em uma permutação. Um resumo do nível de segurança da famílias QUARK para ataques de colisão, pré-imagem e segunda pré-imagem é apresentado na Tabela 2.4.

Tamanho Nível de segurança em bits Funções de saída Colisão Pré-imagem 2a Pré-imagem U-QUARK 136 64 64 128 D-QUARK 176 80 80 160 S-QUARK 256 112 112 224

Tabela 2.4: Nível de segurança da família QUARK [3].

Em [3] foi aplicado um conjunto de técnicas de criptoanálise sobre todos os membros da família QUARK e a permutação P se mostrou indistinguível de uma permutação aleatória, para todas as instâncias, a partir de 25% das rodadas.

2.6 Resumo

Neste capítulo, foram apresentados os conceitos básicos das funções de resumo cripto- gráfico e suas principais aplicações; adicionalmente, foram descritas duas construções amplamente usadas no projeto destas funções: a construção Merkle-Damgård e a cons- trução esponja. Finalmente, duas famílias de funções de resumo baseadas na construção esponja foram detalhadas - a família SHA-3 e a família QUARK. Capítulo 3

Micro Arquitetura Intel

Neste Capítulo são apresentados os conjuntos avançados de instruções vetoriais presentes nos processadores da Intel relevantes para este trabalho e a primeira arquitetura da Intel direcionada para a internet das coisas, Intel Galileo.

3.1 Instruções vetoriais

No fim da década de 1990, os fabricantes de processadores concentraram seus esforços em explorar o paralelismo de dados ao invés do paralelismo de instruções, como era feito nas arquiteturas RISC. Para isso, foram incorporadas unidades funcionais capazes de pro- cessar um conjunto de dados com a execução uma única instrução; esse processamento encaixa-se no paradigma conhecido como SIMD (Single Instruction Multiple Data), in- troduzido em [24]. Na arquitetura Intel, um dos primeiros conjuntos de instruções a implementar o pa- radigma SIMD foi lançado em 1997, sendo conhecido por MMX (Multimedia eXtensi- ons) [18]. O MMX adicionou registradores de 64 bits e instruções vetoriais que habili- tavam o processamento de duas operações de 32 bits simultaneamente; nessa época as arquiteturas possuíam registradores nativos de 32 bits. Essas instruções definem a se- mântica do conteúdo do registrador, isto é, um registrador de 64 bits poderia ser operado como um vetor de oito palavras de 8 bits, um vetor de quatro palavras de 16 bits, um vetor de duas palavras de 32 bits ou como um vetor de 64 bits. O conjunto de instruções MMX possui duas limitações principais, que são: ele só trabalha com inteiros e reusa os registradores de ponto flutuante, impossibilitando assim trabalhar concorrentemente com operações de ponto flutuante e vetoriais. Para sanar esses problemas a Intel lançou em 1999 o SSE (Streaming SIMD Extensions) que adicionou oito registradores de 128 bits (denotados XMM0-XMM7) e incluiu instruções para dar suporte à computação de aritmética de ponto flutuante. No ano 2000 o tamanho dos registradores nativos aumentou de 32 bits para 64 bits e o número de registradores vetoriais da arquitetura Intel 64 (denotados XMM0-XMM15) foi duplicado. Nos anos seguintes o conjunto de instruções SSE foi evoluindo com o lançamento dos novos conjuntos SSE2, SSE3, e SSE4. O SSE2 foi lançado para dar suporte às operações de aritmética inteira. Os outros conjuntos, entretanto, foram incorporando

30 CAPÍTULO 3. MICRO ARQUITETURA INTEL 31

Figura 3.1: Conjunto de registradores vetoriais e de propósito geral da arquitetura Intel. outros tipos de instruções vetoriais; desse modo, começaram a surgir instruções para manipulação de cadeias de caracteres, permutação de palavras dentro dos registradores e códigos de correção de erros. Em 2011 foi lançado o conjunto de instruções AVX (Advanced Vector Extensions), que trouxe contribuições relevantes à arquitetura. Ele incluiu registradores de 256 bits, chamados YMM, que encontram-se sobrepostos sobre os registradores XMM; o conjunto de registradores, vetoriais e de propósito geral, suportados pela arquitetura Intel podem ser vistos na Figura 3.1. Além disso, o AVX introduziu um novo formato de codificação que permite utilizar código de montagem de três operandos, tornando a atribuição de registradores mais flexível. O mais recente conjunto de instruções vetoriais é a segunda versão do AVX, chamada AVX2. Esse conjunto será detalhado na seção seguinte. Como foi apresentado, as primeiras instruções vetoriais foram direcionadas ao proces- samento gráfico, esse cenário vem mudando nos últimos anos e agora está disponível uma vasta diversidade de instruções.

3.1.1 O conjunto de instruções AVX2 A microarquitetura Haswell foi lançada no início de 2013 e trouxe consigo uma série de inovações para acelerar a execução dos programas. Dentre as quais destacam-se: (i) a inclusão de mais duas portas de execução; (ii) um novo multiplicador inteiro; (iii) novas instruções de manipulação de bits; (iv) o aumento da largura de banda da cache de dados, que foi dobrada para permitir duas leituras e uma escrita por ciclo de relógio. No entanto, o suporte ao conjunto de instruções vetoriais AVX2 é a característica mais relevante desta microarquitetura. O AVX2 contém novas instruções que expandem a computação de aritmética inteira nos registradores de 256 bits; pois o conjunto AVX continha apenas instruções para a aritmética de ponto flutuante. Além disso, AVX2 conta com instruções de permutação e combinação, que permitem movimentar as palavras contidas nos registradores vetoriais, CAPÍTULO 3. MICRO ARQUITETURA INTEL 32 entre outras características. A seguir, são destacadas algumas instruções que fazem parte do conjunto AVX2 e que foram relevantes para este trabalho:

1. Acesso a memória:

(a) LOAD/STORE. Essas funções permitem carregar/armazenar um conjunto de da- dos de/para um endereço de memória de/para um registrador vetorial. Vale a pena mencionar que o endereço de memória deve estar alinhado para 32 bits, ou seja, o valor do endereço deve ser um múltiplo de 32, caso contrário o desempenho da aplicação é afetado. (b) BRCAST. Essa instrução replica um valor de 8, 16, 32, 64 ou 128 bits de um registrador vetorial (ou endereço de memória) em um registrador vetorial.

0x75

0x75 0x75 0x75 0x75

2. Funções lógicas:

(a) XOR/AND/OR/ANDNOT. Essas funções calculam operações lógicas entre dois re- gistradores de 256 bits A e B produzindo um novo registrador C.

A = a3 a2 a1 a0 ⊕ ⊕ ⊕ ⊕

B = b3 b2 b1 b0 = = = =

C = c3 c2 c1 c0

(b) SHL/SHR. Para cada palavra armazenada em um registrador vetorial A, essas instruções deslocam para esquerda ou direta, respectivamente, uma quantidade fixa de bits b, produzindo um novo registrador C.

A = a3 a2 a1 a0  b  b

C = c3 c2 c1 c0

(c) SHLV/SHRV. Essas instruções potencializam o processamento paralelo das ins- truções de deslocamento, pois ao invés de fazer um deslocamento fixo, a ins- trução recebe, além do registrador alvo A, um segundo registrador B contendo a quantidade de bits a serem deslocados; desta forma, cada palavra de A será deslocada de acordo com às quantidades especificadas no registrador B, pro- duzindo um novo registrador C. CAPÍTULO 3. MICRO ARQUITETURA INTEL 33

A = a3 a2 a1 a0    

B = b3 b2 b1 b0 = = = =

C = c3 c2 c1 c0

3. Permutações internas no registrador:

(a) PERM. Instruções para embaralhar a posição das palavras dentro do registrador são chamadas de permutações. No entanto, nas primeiras versões do SSE e AVX, foram também conhecidos como shuffle ou shuffling. Essas instruções visualizam um registrador A como palavras de 8, 16, 32 ou 64 bits e as em- baralham de acordo com uma máscara M, produzindo um novo registrador C.

A = a3 a2 a1 a0

M = [2] [0] [3] [1] = = = =

C = a2 a0 a3 a1

4. Combinação de registradores:

(a) UPCK. Essas instruções produzem um registrador C a partir da intercalação das palavras da parte alta/baixa de dois registradores A e B. Ela está presente tanto para registradores de 128 bits como para registradores de 256 bits.

A = a1 a0 B = b1 b0 A = a3 a2 a1 a0 B = b3 b2 b1 b0

C = b0 a0 C = b2 a2 b0 a0

(b) BLEND. Esse tipo de instrução preenche um registrador C a partir de palavras contidas em dois registradores A e B; a escolha está baseada no valor de uma máscara binária M.

A = a3 a2 a1 a0 B = b3 b2 b1 b0

M = 0 1 1 0 mask = = = =

C = a3 b2 b1 a0 CAPÍTULO 3. MICRO ARQUITETURA INTEL 34

(c) PRBLEND. Essa instrução combina partes de 128 bits de dois registradores de 256 bits A e B em um novo registrador C; a escolha está baseada no valor de uma máscara binária M.

A = a1 a0 B = b1 b0

M = [3] [0]

C = b1 a0

(d) ALIGNR. Essa instrução usando registradores de 128 bits concatena dois regis- tradores A e B e desloca b bytes, produzindo um registrador intermediário de 256 bits I, os 128 bits menos significativos de I são armazenado no registrador destino C. No conjunto AVX2 usando registradores de 256 bits o comporta- mento dela é diferente do esperado, pois esperava-se que ela concatenasse dois registradores de 256 bits, deslocasse b bytes e armazenasse os 256 bits menos significativos em um novo registrador. Entretanto, ao usar registradores de 256 bits ela se comporta como duas instruções de 128 bits operando sobre as partes menos e mais significativas dos registradores de 256 bits A e B.

A = a1 a0 B = b1 b0 A = a3 a2 a1 a0 B = b3 b2 b1 b0

0 00 I = a1 a0 b1 b0 I = a3 a2 b3 b2 I = a1 a0 b1 b0  b  b  b

C = c1 c0 C0 = c3 c2 C00 = c1 c0 =

C = c3 c2 c1 c0

5. Conversão de elementos:

(a) CAST. São pseudo-instruções que mudam apenas a semântica do conteúdo dos registradores. A maioria dessas instruções são tratadas diretamente pelos com- piladores e não geram nenhuma instrução em código de montagem. (b) EXTRACT. Essa instrução retorna um registrador de 128 bits composto pela parte alta (ou baixa) de um registrador de 256 bits. Diferente das instruções de CAST, esta é uma instrução explicita que é codificada em linguagem de montagem. (c) INSERT. Essa instrução tem a funcionalidade inversa à instrução EXTRACT, pois ela permite colocar o conteúdo de um registrador de 128 bits na parte alta (ou baixa) de um registrador de 256 bits.

Com as instruções acima apresentadas, é possível criar as seguintes operações que serão úteis no decorrer do texto: CAPÍTULO 3. MICRO ARQUITETURA INTEL 35

1. ROT. Essa operação não está presente no conjunto de instruções AVX2, mas pode ser emulada a partir de três instruções, a seguir é apresentado a definição dessa instrução onde X é um registrador de 128 ou 256 bits e b é a quantidade de bits que cada palavra de w bits do vetor será rotada:

ROT(X, b) = XOR(SHL(X, b), SHR(w − b)).

2. ROTV. Essa operação é ainda mais poderosa que a anterior, pois ao invés de fazer a rotação de um valor fixo, ela recebe, além do registrador alvo, um segundo registra- dor contendo a quantidade de bits a serem rotados por cada palavra; desta forma, cada palavra do vetor alvo será rotada de acordo com as quantidades especificadas no segundo registrador, sua definição é apresentada a seguir, onde X é o registrador alvo e B é o registrador contendo os valores a serem rotados por cada palavra de w bits:

ROTV(X,B) = XOR(SHL(X,B), SHRV(SUB(W, B),X)).

As instruções aqui apresentadas não representam todas as instruções pertencentes ao conjunto de instruções AVX2; é recomendado consultar [19] para informação adicional sobre esse conjunto. Na Tabela 3.1 são mostradas as latências, a vazão e as portas de execução das instruções AVX2 acima citadas; essas informações foram extraídas do relatório técnico produzido por Agner Fog [25]. Como pode ser visto, as instruções que transitam entre as partes altas e baixas dos registradores possuem uma latência de pelo menos 3 ciclos. Essa característica foi encon- trada não apenas nesse conjunto limitado de instruções, mas em todas as instruções do conjunto AVX2 que movem dados da parte baixa/alta para a alta/baixa.

3.2 Instruções de manipulação de bits

Os conjuntos de instruções de manipulação de bits BMI1 e BMI2 foram introduzidos na microarquitetura Haswell com o intuito de acelerar a manipulação de bits. As instruções desses conjuntos não são vetoriais e operam apenas com os registradores de propósito geral. A seguir são apresentadas as instruções presentes nesses conjuntos:

1. ANDN. Aplica uma operação lógica AND entre um registrador A e o inverso de um registrador B, salvando o resultado em um registrador C.

2. BEXTR. Extrai bits contínuos de um registrador. Essa instrução recebe como entrada a posição do primeiro bit a ser extraído i e a quantidade de bits a serem extraídos n, retornando os n primeiros bits a partir de i.

3. BLSI. Retorna o bit menos significativo ativo. Dado um registrador A como entrada a instrução BLSI retorna (−A) AND A.

4. BLSMSK. Ativa todos os bits, até o bit menos significativo, de um registrador A. Dado um registrador A como entrada a instrução BLSMSK retorna (A − 1) XOR A. CAPÍTULO 3. MICRO ARQUITETURA INTEL 36

Porta de execução Instrução vetorial Latência Vazão 0 1 2 3 4 5 6 7 LOAD 3 2 × × STORE 3 1 × × × × BRCAST 5 2 × × ADD/SUB 1 2 × × MUL 5 1 × XOR 1 3 × × × SHL/SHR 1 1 × SHLV SHRV 2 0.5 × × PERM 3 1 × BLEND 1 3 × × × PRBLEND 3 1 × ALIGNR 1 1 × UPCK 1 1 × CAST 0 - EXTRACT 3 1 × INSERT 3 1 ×

Tabela 3.1: Latência, vazão (instruções executadas por ciclo quando não há dependências) e portas de execução de algumas instruções AVX2.

5. BLSR. Copia todos os bits de um registrador A, zerando o bit menos significativo. Dado um registrador A como entrada a instrução BLSR retorna (A − 1) AND A.

6. BZHI. Zera todos os bits mais significativos a partir de um bit especificado i.

7. PDEP. Usa uma máscara para determinar em quais posições de um registrador de saída C serão armazenados os primeiros n bits menos significativos, os outros bits são preenchidos com o valor zero; seu funcionamento é ilustrado a seguir, onde cada bloco corresponde um bit de um registrador de 64 bits:

A = a63 a62 a61 a60 ...... a4 a3 a2 a1 a0

M = 0 1 0 1 0.. ..0 1 0 1 0 0 ======

C = 0 a3 0 a2 0.. ..0 a1 0 a0 0 0

8. PEXT. Armazena continuamente n bits, determinados por uma máscara M, de um registrador A em um registrador C, os outros bits são preenchidos com o valor zero; seu funcionamento é ilustrado a seguir, onde cada bloco corresponde um bit de um registrador de 64 bits: CAPÍTULO 3. MICRO ARQUITETURA INTEL 37

A = a63 a62 a61 a60 ...... a4 a3 a2 a1 a0

M = 0 1 0 1 0.. ..0 1 0 1 0 0 ======

C = 0 0 0 0 0.. ..0 0 a62 a60 a4 a2

9. RORX, SARX/SHLX/SHRX. São instruções de rotação e de deslocamento.

10. TZCNT. Retorna o número de zeros a direita.

Na Tabela 3.2 são mostradas as latências, a vazão e as portas de execução das ins- truções dos conjuntos BMI1 e BMI2 acima citadas; essas informações foram extraídas do relatório técnico produzido por Agner Fog [25].

Porta de execução Instrução vetorial Latência Vazão 0 1 2 3 4 5 6 7 SHLX SHRX SARX 1 2 × RORX 1 2 × TZCNT 3 1 × ANDN 1 2 × × BLSI 1 2 × × BSLR 1 2 × × BLSMSK 1 2 × × BEXTR 2 2 × × × × BZHI 1 2 × × PDEP 3 1 × PEXT 3 2 ×

Tabela 3.2: Latência, vazão e portas de execução de das instruções do conjunto BMI1 e BMI2.

3.3 Intel Galileo

A plataforma Intel Galileo é um microcontolador que usa o processador Intel Quark SoC X1000, que é um processador de 32 bits projetado para um baixo consumo energético, compatível com a família e que foi baseado na microarquitetura clássico. Esse processador é o primeiro da Intel direcionado para a internet das coisas (Internet of Things IoT) e para o mercado wearable [47]. O processador Intel Quark SoC X1000 tem uma arquitetura de 32 bits e possui uma cache 4-way set associative de 16KB. A cache é uma memória de acesso rápido onde é mantida uma cópia temporária de instruções, operandos e dados usados frequentemente; a política de escrita na cache usada por padrão na microarquitetura Quark é o write- through [33]. CAPÍTULO 3. MICRO ARQUITETURA INTEL 38

Modelo Intel R QuarkTM SoC X1000 Frequência 400 MHz Cores/Threads 1/1

Conjunto de instrução(ISA) 32-bit Intel R Pentium R processor-compatible ISA Cache L1 16 KB SRAM 512 KB on-die, embedded 15 mm × 15 mm BGA Packaging ACPI-compatible with CPU sleep states DRAM 256 MB DDR3; 800 MT/s

Tabela 3.3: Principais características do microcontrolador Intel Galileo.

No processador Intel Quark a execução de uma instrução é subdividida em fases, onde cada fase ocupa uma parte específica da unidade de processamento [33]. Apesar de cada instrução ser processada sequencialmente, diversas instruções estão em diferentes fases de execução do processador em um determinado momento; essa técnica de execução é chamada de pipeline. Para tornar a execução mais eficiente, o processador usa um mecanismo chamado de prefetch de instruções, que busca prever qual é a próxima instrução a ser executada observando padrões de acesso. A cache e a unidade de prefetch são fortemente ligadas, de modo que um bloco de 16 bytes de instruções da cache pode ser passado rapidamente para a unidade de prefetch. Uma vez feito o prefetch de uma instrução ela será decodificada, caso o fluxo de execução seja desviado e não passe mais por essa instrução todo esse processamento é descartado [33]. Essa arquitetura possui oito registradores de propósito geral, denotados por EAX, EBX, ECX, EDX, ESI, EDI, EBP e ESP [32]. Esse processador não suporta a tecnologia de execução de instruções fora de ordem, mas possui dois pipelines para a execução de instruções e em certas condições pode executar duas instruções consecutivas simultane- amente, usando um mecanismo de emparelhamento descrito em [26]. Na Tabela 3.3 são apresentadas as principais características do microcontrolador Intel Galileo.

3.4 Conjunto de instruções

O conjunto de instruções do processador Quark, quando comparado com o do Haswell, é bem reduzido. Entretanto, isso não significa que não existem instruções poderosas neste conjunto, como as instruções que serão apresentadas a seguir:

1. ROL/ROR. Essas instruções permitem rotacionar bits dentro de um registrador. Ela rotaciona o valor armazenado no primeiro operando um número especificado de bits para a esquerda/direita, que é definido no segundo operando, armazenando o resultado no primeiro operando. CAPÍTULO 3. MICRO ARQUITETURA INTEL 39

2. BSWAP Essa instrução permite inverter a ordem dos bytes dentro de um registrador.

Ela funciona como segue: dado um registrador de 32 bits com quatro bytes (x0, x1, x2 e x3), estando o x0 na parte menos significativa e o x3 na parte mais significativa essa instrução inverte a ordem desses bytes para (x3, x2, x1 e x0).

Essa microarquitetura também possui as instruções básicas, como instruções de carre- gamento, deslocamento, operações lógicas, etc. Na Tabela 3.4 são mostradas as latências de algumas instruções da microarquitetura Quark; essas informações foram extraídas do relatório técnico produzido por Agner Fog [25].

Instrução vetorial Latência LOAD 1 AND OR XOR 1 SHR SHL 1 ROL ROR 1-3 BSWAP 1

Tabela 3.4: Latência de algumas instruções da microarquitetura Quark.

3.5 Resumo

Neste capítulo, foram apresentados os conjuntos avançados de instruções vetoriais pre- sentes nos processadores da Intel, com ênfase nos conjuntos AVX e AVX2. No contexto de Internet das Coisas, foi apresentada a primeira arquitetura da Intel direcionada a esse contexto, o Intel Galileo. Capítulo 4

Implementação da família SHA-3

A função de permutação Keccak-p[1600,24], que foi definida na Seção 2.5.1, é a mesma para todas as instâncias da família de funções de resumo criptográfico SHA-3 e é a principal responsável pela eficiência do algoritmo. Neste Capitulo, é mostrado como aproveitar o conjunto de instruções AVX2 para implementar de forma eficiente a função de permutação

Keccak-p[1600,24]. Visando simplificar a notação, as palavras s0 a s24 representarão as palavras do estado antes de uma rodada e as palavras θ0 a θ24 representarão as palavras do estado depois do cálculo da etapa de mapeamento θ; as etapas de mapeamento ρ e π foram implementadas juntas e uma vez computadas serão representadas pelas palavras

ρ0 a ρ24; as palavras χ0 a χ24 representarão as palavras do estado depois da execução da etapa de mapeamento χ e depois da execução da etapa de mapeamento ι o estado voltará a ser representado pelas palavras s0 a s24.

4.1 Implementação sequencial usando instruções de 256 bits

Organização do estado. A permutação Keccak-p[1600,24] trabalha sobre um estado de 1600 bits, divididos em 25 palavras de 64 bits. O uso de registradores de 256 bits permite empacotar quatro palavras de 64 bits em um único registrador e operá-las simultane- amente, usando apenas uma instrução. Esta implementação busca acomodar o estado do algoritmo nos registradores vetoriais visando aumentar a eficiência com a redução do número de instruções executadas. O primeiro passo foi mapear o estado do algoritmo em variáveis de 256 bits; para comportar as 25 palavras do estado S = {s0, . . . , s24} foi preciso usar sete variáveis de 256 bits, denominadas Y = {Y0,...,Y6}. O mapeamento de cada uma das palavras do estado em suas respectivas variáveis pode ser visto na Figura 4.1, onde cada linha representa uma variável de 256 bits dividida em quatro palavras de 64 bits. A computação da função de permutação Keccak-p[1600,24] é composta pelas etapas de mapeamento θ, ρ, π, χ e ι, definidas na Seção 2.5.1; a seguir, é mostrado como implementar essas etapas usando instruções vetoriais de 256 bits.

• Etapa θ. A computação dessa etapa foi dividida em três passos, ilustrados na

40 CAPÍTULO 4. IMPLEMENTAÇÃO DA FAMÍLIA SHA-3 41

Y0 s0 s1 s2 s3

Y1 s5 s6 s7 s8

Y2 s10 s11 s12 s13

Y3 s15 s16 s17 s18

Y4 s20 s21 s22 s23

Y5 s24 s24 s24 s24

Y6 s4 s9 s14 s19

Figura 4.1: Organização do estado para implementação sequencial usando variáveis de 256 bits.

Y0 s0 s1 s2 s3 Y0 θ0 θ1 θ2 θ3

Y1 s5 s6 s7 s8 Y1 θ5 θ6 θ7 θ8

Y2 s10 s11 s12 s13 Y2 θ10 θ11 θ12 θ13 C0 c0 c1 c2 c3 D0 d0 d1 d2 d3 Y3 s15 s16 s17 s18 Y3 θ15 θ16 θ17 θ18 C1 c4 c4 - - D1 d4 d4 d4 d4 Y4 s20 s21 s22 s23 Y4 θ20 θ21 θ22 θ23

Y5 s24 s24 s24 s24 Y5 θ24 θ24 θ24 θ24

Y6 s4 s9 s14 s19 Y6 θ4 θ9 θ14 θ19

Figura 4.2: Passo a passo da etapa de mapeamento θ na implementação sequencial usando as instruções de 256 bits.

Figura 4.2. No primeiro passo são calculadas as variáveis C0 e C1, no passo seguinte calcula-se D0 e D1 e finalmente esses valores são usados para atualizar o estado.

– O primeiro passo da etapa θ é composto pela computação de c0, c1, c2, c3 e c4; tal computação é definida na primeira linha do Algoritmo 2; o uso de instruções

vetoriais permite calcular os primeiros quatro valores, armazenando-os em C0, com a aplicação de uma operação XOR entre as variáveis Y0, Y1, Y2, Y3 e Y4. Por outro lado, o cálculo do último valor não é direto, pois é preciso computar

uma operação XOR entre as palavras armazenadas na variável Y6 e aplicar uma operação XOR do resultado com a variável Y5 e não existe uma instrução vetorial que calcula um XOR entre as palavras de um registrador vetorial; a

computação do último valor, que será armazenado em C1, pode ser vista a CAPÍTULO 4. IMPLEMENTAÇÃO DA FAMÍLIA SHA-3 42

seguir, onde X0 e X1 são variáveis de 128 bits:

X0 =EXTRACT(Y6, 0) [s4, s9]

X1 =EXTRACT(Y6, 1) [s14, s19]

X0 =XOR(X0,X1)[s4 ⊕ s14, s9 ⊕ s19]

X1 =PERM(X0, 0x4E)[s9 ⊕ s19, s4 ⊕ s14]

X1 =XOR(X1,X0)

C1 =CAST(X1)

C1 =XOR(C1,Y5)[c4, c4, −, −].

– O segundo passo da etapa θ consiste no cálculo de d0, d1, d2, d3 e d4, definidos na segunda linha do Algoritmo 2. Para realizar esse processamento é necessário

rearranjar as palavras contidas nas variáveis C0 e C1 de modo a deixá-las na posição exata para a computação. As variáveis D0 e D1 são calculadas como segue: T0 =BLEND(C0,C1, 0x0C)[c0, c4, c2, c3]

T0 =PERM(T0, 0x1E)[c2, c3, c4, c0]

T0 =XOR(C0, ROT(T0, 0x01)) [d1, d2, d3, d4]

T1 =XOR(C1, ROT(C0, 0x01)) [−, d0, −, −]

D1 =PERM(T0, 0xFF)[d4, d4, d4, d4]

T1 =PERM(T1, 0x55)[d0, d0, d0, d0]

T0 =PERM(T0, 0x90)[d1, d1, d2, d3]

D0 =BLEND(T1,T0, 0xFC)[d0, d1, d2, d3]. – No terceiro e último passo da etapa θ o estado é atualizado por:

Yi =XOR(Yi,D0), para 0 ≤ i ≤ 4

Yj =XOR(Yj,D1), para 5 ≤ j ≤ 6.

• Etapas ρ e π As etapas π e ρ consistem na aplicação de uma rotação e uma permutação sobre as palavras do estado, respectivamente. A permutação dos dados foi implementada visando deixar o estado com uma organização favorável para a computação da etapa χ. A Figura 4.3 ilustra a organização do estado antes e depois do processamento das etapas ρ e π.

Na etapa de mapeamento ρ, cada palavra θi será rotacionada ri bits, os valores de ri foram definidos previamente na Matriz 2.2 do Capítulo 2. A palavra θ0 não precisará ser rotacionada, visto que r0 = 0, isso permite rearranjar as palavras de modo a comportá-las em seis registradores de 256 bits, economizando assim uma operação de rotação. A instrução de rotação, definida no Capitulo 3, recebe como entrada o registrador a ser rotacionado e um registrador contendo a quantidade de bits que serão rotacionados em cada palavra - tais valores estão armazenados nos CAPÍTULO 4. IMPLEMENTAÇÃO DA FAMÍLIA SHA-3 43

Y0 θ0 θ1 θ2 θ3 Y0 ρ0 − − −

Y1 θ5 θ6 θ7 θ8 Y1 ρ11 ρ21 ρ6 ρ16

Y2 θ10 θ11 θ12 θ13 Y2 ρ12 ρ22 ρ7 ρ17 ρ e π Y3 θ15 θ16 θ17 θ18 Y3 ρ13 ρ23 ρ8 ρ18

Y4 θ20 θ21 θ22 θ23 Y4 ρ14 ρ24 ρ9 ρ19

Y5 θ24 θ24 − − Y5 ρ4 ρ1 ρ2 ρ3

Y6 θ4 θ9 θ14 θ19 Y6 ρ10 ρ20 ρ5 ρ15

Figura 4.3: Passo a passo das etapas de mapeamento ρ e π na implementação sequencial usando as instruções de 256 bits.

R0 14 44 43 21

R1 1 62 28 27

R2 6 55 20 36

R3 25 39 3 10

R4 8 41 45 15

R5 18 2 61 56

Figura 4.4: Valores a serem rotados na etapa ρ para a implementação sequencial usando as registradores de 256 bits.

registradores R0 à R5 - como pode ser visto na Figura 4.4. Na etapa π o estado é embaralhado seguindo a linha cinco do Algoritmo 2. Essa permutação pode ser feita diretamente em uma implementação nativa de 64 bits, mas existe um custo adicional para uma implementação vetorial, pois as instruções de permutação presentes no conjunto de instruções AVX2 possuem alta latência. As instruções necessárias para calcular as etapas de mapeamento ρ e π podem ser vistas a seguir:

T0 =BLEND(Y0,Y6, 0x03)[θ4, θ1, θ2, θ3]

T1 =BLEND(Y1,Y2, 0x33)[θ10, θ6, θ12, θ8]

T2 =BLEND(Y2,Y6, 0x30)[θ10, θ11, θ14, θ13]

T3 =BLEND(Y1,Y6, 0x0C)[θ5, θ9, θ7, θ8]

T4 =BLEND(Y3,Y6, 0xC0)[θ15, θ16, θ17, θ19]

T5 =BLEND(Y5,Y3, 0xC0)[θ24, θ24, θ24, θ18]

Y5 =BLEND(T1,T5, 0xC3)[θ24, θ6, θ12, θ18]

Y6 =PERM(T0, 0x39)[θ1, θ2, θ3, θ4]

Y1 =PERM(T3, 0x1E)[θ7, θ8, θ9, θ5]

Y2 =PERM(T2, 0x4B)[θ13, θ14, θ10, θ11]

Y3 =PERM(T4, 0x93)[θ19, θ15, θ16, θ17] CAPÍTULO 4. IMPLEMENTAÇÃO DA FAMÍLIA SHA-3 44

Y6 =ROTV(Y6,R1)[ρ10, ρ20, ρ5, ρ15]

Y1 =ROTV(Y1,R2)[ρ11, ρ21, ρ6, ρ16]

Y2 =ROTV(Y2,R3)[ρ12, ρ22, ρ7, ρ17]

Y3 =ROTV(Y3,R4)[ρ13, ρ23, ρ8, ρ18]

Y4 =ROTV(Y4,R5)[ρ14, ρ24, ρ9, ρ19]

Y5 =ROTV(Y5,R0)[ρ4, ρ1, ρ2, ρ3].

• Etapas χ e ι Na etapa χ o estado é processado através de uma função não linear, definida na linha sete do Algoritmo 2, e na etapa de mapeamento ι uma operação XOR é aplicada

entre a palavra ρ0 e um elemento constante. A organização do estado antes e depois dessas etapas de mapeamento pode ser vista na Figura 4.5.

Y0 ρ0 − − − Y0 s0 s1 s2 s3

Y1 ρ11 ρ21 ρ6 ρ16 Y1 s14 s24 s9 s19

Y2 ρ12 ρ22 ρ7 ρ17 Y2 s12 s22 s7 s17 χ e ι Y3 ρ13 ρ23 ρ8 ρ18 Y3 s10 s20 s5 s15

Y4 ρ14 ρ24 ρ9 ρ19 Y4 s11 s21 s6 s16

Y5 ρ4 ρ1 ρ2 ρ3 Y5 s4 − − −

Y6 ρ10 ρ20 ρ5 ρ15 Y6 s13 s23 s8 s18

Figura 4.5: Passo a passo das etapas de mapeamento χ e ι na implementação sequencial usando as instruções de 256 bits.

Após a execução das etapas ρ e π o estado ficou organizado de modo que todas as palavras de uma mesma linha ficaram armazenadas na mesma posição do registra- dor, isto é, todas as palavras da linha i ficaram nos primeiros 64 bits do registrador, as palavras da linha i+1 ficaram nos próximos 64 bits e assim sucessivamente. Essa organização permite computar eficientemente a etapa χ para quatro linhas, a linha remanescente é computada de uma forma diferente, como será mostrado posterior- mente. A computação da etapa χ para as linhas 1, 2, 3 e 4 da matriz pode ser vista a seguir:

T1 =XOR(Y6, ANDNOT(Y1,Y2)) [χ10, χ20, χ5, χ15]

T2 =XOR(Y1, ANDNOT(Y2,Y3)) [χ11, χ21, χ6, χ16]

Y2 =XOR(Y2, ANDNOT(Y3,Y4)) [χ12, χ22, χ7, χ17]

Y1 =XOR(Y4, ANDNOT(Y6,Y1)) [χ14, χ24, χ9, χ19]

Y6 =XOR(Y3, ANDNOT(Y4,Y6)) [χ13, χ23, χ8, χ18]

Y3 =T1 Y4 = T2.

Para o cálculo da linha remanescente é necessário organizar os dados restantes em

três registradores auxiliares, as palavra χ0, χ1, χ2, χ3 e χ4 são computadas como CAPÍTULO 4. IMPLEMENTAÇÃO DA FAMÍLIA SHA-3 45

segue:

T0 =BLEND(Y5,Y0, 0x03)[χ0, χ1, χ2, χ3]

T1 =PERM(Y5, 0x39)[χ1, χ2, χ3, χ4]

T2 =BLEND(T0,T1, 0xFC)[χ0, χ2, χ3, χ4]

T2 =PERM(T2, 0x39)[χ2, χ3, χ4, χ0]

Y0 =XOR(T0, ANDNOT(T1,T2)) [χ0, χ1, χ2, χ3]

Y5 =XOR(Y5, ANDNOT(T0,T1)) [χ4, −, −, −].

A etapa ι é a mais simples de ser implementada, ela consiste em fazer um XOR

entre um elemento constante rc(ir) com a primeira palavra do estado χ0. Assim sendo, Y0 é a única variável usada nessa etapa.

Próximas iterações. Uma vez calculadas todas as etapas de mapeamento, chega ao fim uma iteração da permutação; o passo seguinte é organizar o estado para as iterações subsequentes. No lado esquerdo da Figura 4.6 pode-se ver o estado organizado após a computação das 5 etapas e no lado direito é mostrado o estado reorganizado para as próximas iterações. A variável Y0 já encontra-se organizada para a próxima iteração, o processamento para organizar as variáveis restantes é mostrado abaixo:

T0 =UNPACK_LO(Y3,Y4); [χ10, χ11, χ5, χ6]

T1 =UNPACK_HI(Y3,Y4); [χ20, χ21, χ15, χ16]

T2 =UNPACK_LO(Y2,Y6); [χ12, χ13, χ7, χ8]

T3 =UNPACK_HI(Y2,Y6); [χ22, χ23, χ17, χ18]

Y5 =PERM(Y1, 0x55); [χ24, χ24, χ24, χ24]

Y6 =PERM(Y1, 0xC9); [χ24, χ9, χ14, χ19]

Y6 =BLEND(Y6,Y6, 0x03); [χ4, χ9, χ14, χ19]

Y1 =UNPACK_HI(T0,T2); [χ5, χ6, χ7, χ8]

Y2 =UNPACK_LO(T0,T2); [χ10, χ11, χ12, χ13]

Y3 =UNPACK_HI(T1,T3); [χ15, χ16, χ17, χ18]

Y4 =UNPACK_LO(T1,T3); [χ20, χ21, χ22, χ23]. Uma vez organizado o estado após a aplicação das 5 etapas de mapeamento todo o processamento é repetido mais 23 vezes, uma vez que a permutação Keccak-p[1600,24] é composta de 24 iterações.

4.2 Implementação sequencial usando instruções de 128 bits

A Implementação sequencial usando instruções de 256 bits requer muitas instruções de permutação para organizar o estado, como foi apresentado no Capítulo 3 essas instruções CAPÍTULO 4. IMPLEMENTAÇÃO DA FAMÍLIA SHA-3 46

Y0 χ0 χ1 χ2 χ3 Y0 s0 s1 s2 s3

Y1 χ14 χ24 χ9 χ19 Y1 s5 s6 s7 s8

Y2 χ12 χ22 χ7 χ17 Y2 s10 s11 s12 s13

Y3 χ10 χ20 χ5 χ15 Y3 s15 s16 s17 s18

Y4 χ11 χ21 χ6 χ16 Y4 s20 s21 s22 s23

Y5 χ4 − − − Y5 s24 s24 s24 s24

Y6 χ13 χ23 χ8 χ18 Y6 s4 s9 s14 s19

Figura 4.6: Organização do estado para as iterações subsequentes. possuem uma alta latência por transitar dados entre as partes altas e baixas dos registra- dores. Com o intuito de diminuir essas permutações, foram utilizadas instruções de 128 bits para implementar a permutação Keccak-p[1600,24] . Organização do estado. O primeiro passo foi mapear o estado do algoritmo em variáveis de 128 bits; para comportar as 25 palavras do estado foi necessário usar 13 variáveis de 128 bits, denominadas X0,..., X12. O mapeamento de cada uma das palavras do estado em suas respectivas variáveis é apresentado na primeira coluna da Figura 4.7, onde o bloco mais a esquerda representa o nome da variável e os dois blocos seguintes, do bit menos ao mais significativo, representam as palavras do estado que serão armazenadas nessa variável. Uma vez mapeado o estado nas variáveis de 128 bits, pode-se começar a computação da função de permutação Keccak-p[1600,24]. Na Figura 4.7 são mostrados os valores contidos no estado após a execução de cada uma das etapas de mapeamento, que serão descristas a seguir.

• Etapa θ A computação da etapa θ foi dividida em três partes, descritas a seguir:

– A computação do primeiro passo da etapa θ para a as quatro primeiras colunas pode ser feita diretamente, apenas com a aplicação de um XOR entre as variá-

veis que contém os valores dessas colunas, resultando nas variáveis C0 = [c0, c1] e C1 = [c2, c3]. Entretanto, a coluna remanescente requer um custo adicional, o processamento para a computação de C2 = [c4, c4] pode ser visto a seguir:

T0 =XOR(X4,X9)[s4 ⊕ s14, s9 ⊕ s19]

T1 =PERM(T0, 0x4E)[s9 ⊕ s19, s4 ⊕ s14]

T0 =XOR(T0,T1)[s4 ⊕ s14 ⊕ s9 ⊕ s19, s4 ⊕ s14 ⊕ s9 ⊕ s19]

C2 =XOR(T0,X12)[c4, c4]. – No segundo passo da etapa de mapeamento θ os valores computados no passo

anterior são usados para calcular D0 = [d0, d1], D1 = [d2, d3] e D2 = [d4, d4], o CAPÍTULO 4. IMPLEMENTAÇÃO DA FAMÍLIA SHA-3 47

X0 s0 s1 X0 θ0 θ1 X0 ρ15 ρ0 X0 χ20 χ5

X1 s2 s3 X1 θ2 θ3 X1 ρ20 ρ5 X1 χ15 χ0

X2 s5 s6 X2 θ5 θ6 X2 ρ16 ρ1 X2 χ21 χ6

X3 s7 s8 X3 θ7 θ8 X3 ρ11 ρ12 X3 χ10 χ11

X4 s4 s9 X4 θ4 θ9 X4 ρ21 ρ6 X4 χ16 χ1

X5 s10 s11 X5 θ10 θ11 X5 ρ22 ρ7 X5 χ22 χ7 θ ρ e π χ e ι X6 s12 s13 X6 θ12 θ13 X6 ρ12 ρ13 X6 χ12 χ13

X7 s15 s16 X7 θ15 θ16 X7 ρ23 ρ8 X7 χ23 χ8

X8 s17 s18 X8 θ17 θ18 X8 ρ18 ρ3 X8 χ18 χ3

X9 s14 s19 X9 θ14 θ19 X9 ρ19 ρ4 X9 χ19 χ4

X10 s20 s21 X10 θ20 θ21 X10 ρ10 ρ14 X10 χ13 χ14

X11 s22 s23 X11 θ22 θ23 X11 ρ24 ρ9 X11 χ24 χ9

X12 s24 s24 X12 θ24 − X12 ρ17 ρ2 X12 χ17 χ2

Figura 4.7: Organização do estado entre a execução das etapas de mapeamento na imple- mentação sequencial usando instruções de 128 bits.

processamento para a computação desses valores pode ser visto a seguir:

T0 =ALIGNR(C0,C2, 8) [c4, c0]

T1 =XOR(C0, ROT(C1, 1)) [d1, d2]

C0 =XOR(C2, ROT(C0, 1)) [−, d0]

C2 =XOR(C1, ROT(T0, 1)) [d3, d4]

C0 =ALIGNR(T1,C0, 8) [d0, d1]

C1 =ALIGNR(C2,T1, 8) [d2, d3]

C2 =SHUFFLE(C2, 0xEE)[d4, d4].

– O terceiro e último passo consiste em atualizar o estado com uma operação

XOR, de modo que as variáveis Y0, Y2, Y5, Y7 e Y10 sejam atualizadas pela variável C0, as variáveis Y1, Y3, Y6, Y8 e Y11 pela variável C1 e as variáveis Y4, Y9 e Y12 pela variável C2.

• Etapas ρ e π A implementação da etapa ρ usando instruções de 128 bits precisa usar 12 operações de rotação, cada uma dessas operações precisam de uma variável com os valores a serem rotacionados; os valores contido nas 12 variáveis podem ser encontrados na Tabela 4.1. Uma vez definidos os valores a serem rotados, a etapa ρ é executada como segue: CAPÍTULO 4. IMPLEMENTAÇÃO DA FAMÍLIA SHA-3 48

X12 =BLEND(X0,X12, 0x3)[θ24, θ1]

Xi =ROTV(Xi,Ri), para 1 ≤ i ≤ 12.

A etapa π foi implementada visando deixar o estado pronto para o cálculo da etapa subsequente. As instruções necessárias para a computação da etapa π são apresen- tadas a seguir:

X0 =UNPACK_LO(X4,X0)[ρ15, ρ0]

T0 =ALIGNR(X12,X11, 8) [ρ19, ρ4]

T1 =ALIGNR(X6,X5, 8) [ρ17, ρ2]

X4 =UNPACK_HI(X3,X4)[ρ21, ρ6]

X5 =UNPACK_LO(X9,X5)[ρ22, ρ7]

X11 =ALIGNR(X11,X10, 8) [ρ24, ρ9]

X3 =BLEND(X3,X6, 0xC)[ρ11, ρ12]

X6 =UNPACK_HI(X6,X9)[ρ12, ρ13]

X10 =ALIGNR(X10,X12, 8) [ρ10, ρ14]

X9 =T0 X12 = T1.

A organização do estado após o cálculo das etapas de mapeamento ρ e π pode ser vista na terceira coluna da Figura4.7.

R1 62 28 R7 41 45

R2 36 44 R8 15 21

R3 6 55 R9 39 8

R4 27 20 R10 18 2

R5 3 10 R11 61 56

R6 43 25 R12 14 1

Tabela 4.1: Valores a serem rotados na etapa de mapeamento ρ na implementação se- quencial usando instruções de 128 bits.

• Etapa χ e ι As etapas anteriores foram computadas visando um melhor aproveitamento das instruções de 128 bits na computação da etapa χ; para isso, todas as palavras das linhas 3 e 4 foram armazenadas na parte baixa das variáveis enquanto as palavras das linhas 0 e 1 foram armazenadas na parte alta. A computação da etapa χ para as linhas 0, 1, 3 e 4 pode ser vista a seguir: CAPÍTULO 4. IMPLEMENTAÇÃO DA FAMÍLIA SHA-3 49

T0 =XOR(X0, ANDNOT(X2,X12)) [χ15, χ0]

T1 =XOR(X2, ANDNOT(X12,X8)) [χ16, χ1]

X12 =XOR(X12, ANDNOT(X8,X9)) [χ17, χ2]

X8 =XOR(X8, ANDNOT(X9,X0)) [χ18, χ3]

X9 =XOR(X9, ANDNOT(X0,X2)) [χ19, χ4]

X0 =XOR(X1, ANDNOT(X4,X5)) [χ20, χ5]

X2 =XOR(X4, ANDNOT(X5,X7)) [χ21, χ6]

X5 =XOR(X5, ANDNOT(X7,X11)) [χ22, χ7]

X7 =XOR(X7, ANDNOT(X11,X1)) [χ23, χ8]

X11 =XOR(X11, ANDNOT(X1,X4)) [χ24, χ9]

X1 =T0 X4 = T1.

Para o cálculo da linha remanescente é necessário distribuir as cinco palavras da linha dois em cinco variáveis, três delas já encontram-se organizadas desde da etapa anterior. A a computação das outras duas variáveis e da etapa χ para a linha dois pode ser calculada como segue:

T0 =UNPACK_HI(X6,X10, 8) [χ13, χ14]

T1 =UNPACK_LO(X10,X3, 0x3)[χ10, χ11]

X3 =XOR(T1, ANDNOT(X3,X6)) [χ10, χ11]

X6 =XOR(X6, ANDNOT(T0,X10)) [χ12, χ13]

X10 =XOR(T0, ANDNOT(X10,T1)) [χ13, χ14].

A computação da etapa ι é feita juntamente com a execução da etapa χ, a qual

consiste apenas de uma operação XOR entre um valor constante e a palavra χ0. Próximas iterações. Uma vez processadas as cinco etapas de mapeamento, o passo seguinte é organizar os dados do estado para as iterações subsequentes; as instruções necessárias para a organização do estado são apresentadas abaixo:

T0 =ALIGNR(X9,X10, 8) [s14, s19]

X10 =UNPACK_LO(X0,X2)[s20, s21]

X2 =UNPACK_HI(X0,X2)[s5, s6]

X0 =UNPACK_HI(X1,X4)[s0, s1]

X1 =UNPACK_LO(X1,X4)[s15, s16]

X4 =UNPACK_HI(X9,X11)[s4, s9]

X9 =UNPACK_HI(X12,X8)[s2, s3]

X8 =UNPACK_LO(X12,X8)[s17, s18] CAPÍTULO 4. IMPLEMENTAÇÃO DA FAMÍLIA SHA-3 50

X12 =PERM(X11, 0x44) [s24, s24]

X11 =UNPACK_LO(X5,X7)[s22, s23]

X5 =UNPACK_HI(X5,X7)[s7, s8]

X7 =X1 X1 = X9 X9 = T0

T0 =X3 X3 = X5 X5 = T0.

Uma vez organizado o estado, todo o processo é repetido mais 23 vezes. A principal vantagem dessa implementação sobre a que usa instruções de 256 bits é que o custo de permutar dados entre registradores de 128 bits é por volta de três vezes menor do que permutar dados entre registradores de 256 bits.

4.3 Implementação vetorizada (2M) usando instruções de 128 bits

O conjunto de instruções vetoriais permite o processamento de mais de uma palavra de 64 bits com o uso de apenas uma instrução, essa característica viabiliza a computação de mais de um estado por vez pela permutação Keccak-p[1600,24]. A computação de múltiplos valores de resumo concorrentemente por ser usada diretamente para acelerar o esquema de assinatura digital de Merkle [38], que é um esquema resistente a computadores quânticos. A primeira estratégia para processar múltiplos estados concorrentemente foi usar ins- truções de 128 bits para processar dois estados por vez. A seguir são apresentados os detalhes internos dessa implementação, primeiramente é mostrado como criar um novo estado usando variáveis de 128 bits, que contenha os dois estados a serem processados, posteriormente é descrito como aplicar as etapas de mapeamento sobre esse novo estado. Organização do estado. Com as instruções de 128 bits é possível processar duas palavras de 64 bits usando apenas uma instrução; essa característica permite tirar pro- veito da principal vantagem da implementação nativa de 64 bits sobre as implementações vetoriais, que é o custo das operações de permutação. Nesta implementação, diferente das implementações apresentadas nas Seções 4.1 e 4.2, as permutações consistem apenas em mudar endereços de memória. O primeiro passo foi mapear os dois estados a serem processados em variáveis de 128 1 1 2 2 2 2 bits; para comportar as 50 palavras dos estados S = {s0, . . . , s24} e S = {s0, . . . , s24} foi preciso usar 25 variáveis de 128 bits, denominadas X = {X0,...,X24}. O mapeamento de cada uma das palavras do estado em suas respectivas variáveis por ser visto na Figura 4.8. O mapeamento dos estados S1 e S2 em X pode ser feito eficientemente com o uso das instruções LOAD, UNPACK_LO e UNPACK_HI; a seguir é apresentado o trecho de código que mapeia as primeiras duas palavras dos estados nas variáveis X0 e X1; o processamento para as outras palavras é análogo ao apresentado: CAPÍTULO 4. IMPLEMENTAÇÃO DA FAMÍLIA SHA-3 51

1 2 X0 s0 s0

1 2 X1 s1 s1

1 2 X2 s2 s2

. .

1 2 X22 s22 s22

1 2 X23 s23 s23

1 2 X24 s24 s24

Figura 4.8: Organização do estado para implementação vetorizada (2M) usando instruções de 128 bits.

1 1 T0 =LOAD(S1, 0) [s0, s1] 2 2 T1 =LOAD(S2, 0) [s0, s1] 1 2 X0 =UNPACK_LO(T0,T1)[s0, s0] 1 2 X1 =UNPACK_HI(T0,T1)[s1, s1]. Uma vez mapeado os estados nas variáveis de 128 bits, pode-se começar o cálculo da permutação Keccak-p[1600,24]. A implementação dessa versão que usa instruções de 128 bits para processar dois estados independentes concorrentemente é muito similar ao Algoritmo 2, a diferença é que aqui todas as operações são sobre variáveis de 128 bits enquanto no Algoritmo 2 as operações são sobre palavras de 64 bits usando registradores de propósito geral.

• Etapa θ Para a computação da etapa θ primeiramente são calculados os valores de

c0 à c4 para as duas mensagens, feito isso esses valores são usados na computação de d0 à d4; por último, cada palavra do estado é atualizada com uma operação XOR entre seu valor antigo e di, onde 0 ≤ i < 5 corresponde à coluna da respectiva palavra.

• Etapas ρ, π, χ e ι Visando um melhor aproveitamento dos registradores, visto que o estado usado nessa implementação é maior que a quantidade de registradores disponíveis pela arquitetura, pode-se implementar as etapas de mapeamento ρ, π, χ e ι de forma modular, processando as etapas ρ e π para um bloco de cinco palavras que serão usadas conjuntamente na etapa χ. O trecho de código a seguir é necessário para 1 1 1 1 1 2 2 2 2 2 computar as palavras χ5, χ6, χ7, χ8, χ9, χ5, χ6, χ7, χ8 e χ9 após a aplicação das etapas de mapeamento ρ, π e χ: CAPÍTULO 4. IMPLEMENTAÇÃO DA FAMÍLIA SHA-3 52

1 2 T0 =ROT(X3, 28) [ρ5, ρ5] 1 2 T1 =ROT(X9, 20) [ρ6, ρ6] 1 2 T2 =ROT(X10, 3) [ρ7, ρ7] 1 2 T3 =ROT(X16, 45) [ρ8, ρ8] 1 2 T4 =ROT(X22, 61) [ρ9, ρ9]

1 2 X16 =XOR(T0, ANDNOT(T1,T2))) X16 = [χ5, χ5] 1 2 X3 =XOR(T1, ANDNOT(T2,T3))) X3 = [χ6, χ6] 1 2 X10 =XOR(T2, ANDNOT(T3,T4))) X10 = [χ7, χ7] 1 2 X22 =XOR(T3, ANDNOT(T4,T0))) X22 = [χ8, χ8] 1 2 X9 =XOR(T4, ANDNOT(T0,T1))) X9 = [χ9, χ9].

Pode-se perceber que após a execução das etapas ρ, π e χ as palavras calculadas

não ficaram armazenadas nas variáveis X5, X6, X7 e X8, isso acontece porque as palavras armazenadas nessas variáveis ainda não foram processadas pelas etapas ρ,

π e χ. A computação da etapa ι depende apenas da variável X0, desse modo ela pode ser computada a qualquer momento após o cálculo de valor de χ0. Nesta implementação foi escolhido não rearranjar o estado após a computação da primeira iteração da função de permutação Keccak-p[1600,24]; do estado definido na

Figura 4.8 apenas as variáveis X0, X9, X13, X17 e X21 permanecem com as mesmas palavras, a organização do restante do estado é mostrado na Figura 4.9. Por conta disso, a implementação da etapa θ na iteração i + 1 deve levar em conta a nova configuração do estado.

1 2 1 2 1 2 1 2 1 2 1 2 X1 s12 s12 X2 s24 s24 X3 s6 s6 X4 s18 s18 X5 s16 s16 X6 s3 s3

1 2 1 2 1 2 1 2 1 2 1 2 X7 s10 s10 X8 s22 s22 X10 s7 s7 X11 s19 s19 X12 s1 s1 X14 s20 s20

1 2 1 2 1 2 1 2 1 2 1 2 X15 s23 s23 X16 s5 s5 X18 s4 s4 X19 s11 s11 X20 s14 s14 X22 s9 s9

1 2 1 2 X23 s15 s15 X24 s2 s2

Figura 4.9: Organização do estado para a iteração i + 1 na implementação vetorizada usando instruções de 128 bits.

O estado volta a sua configuração original após a aplicação das etapas de mapea- mento ρ, π e χ na iteração i + 1, como é apresentado a seguir com as instruções 1 1 1 1 1 2 2 2 2 2 necessárias para calculas as palavras χ5, χ6, χ7, χ8, χ9, χ5, χ6, χ7, χ8 e χ9 após a aplicação das etapas de mapeamento ρ, π e χ: CAPÍTULO 4. IMPLEMENTAÇÃO DA FAMÍLIA SHA-3 53

1 2 T0 =ROT(X6, 28) [ρ5, ρ5] 1 2 T1 =ROT(X9, 20) [ρ6, ρ6] 1 2 T2 =ROT(X7, 3) [ρ7, ρ7] 1 2 T3 =ROT(X5, 45) [ρ8, ρ8] 1 2 T4 =ROT(X8, 61) [ρ9, ρ9] 1 2 X5 =XOR(T0, ANDNOT(T1,T2))) [χ5, χ5] 1 2 X6 =XOR(T1, ANDNOT(T2,T3))) [χ6, χ6] 1 2 X7 =XOR(T2, ANDNOT(T3,T4))) [χ7, χ7] 1 2 X8 =XOR(T3, ANDNOT(T4,T0))) [χ8, χ8] 1 2 X9 =XOR(T4, ANDNOT(T0,T1))) [χ9, χ9].

Esta implementação usa praticamente a mesma quantidade de instruções que a imple- mentação nativa de 64 bits, entretanto nesta implementação são processados dois estados por vez enquanto na nativa de 64 bits apenas um estado é processado.

4.4 Implementação vetorizada (4M) usando instruções de 256 bits

Em 4.3 foi apresentada uma implementação que aproveitava os registradores de 128 bits para processar dois estados por vez. Outra implementação possível é usar os registradores de 256 bits para processar quatro estados concorrentemente. Internamente as duas imple- mentações são muito parecidas, visto que todas as instruções usadas na implementação vetorizada (2M) possuem uma instrução equivalente que opera sobre registradores de 256 bits, por conta disso não é apresentado o passo a passo desta implementação. A principal diferença entre a implementação 2-way e a implementação 4-way está na organização do estado, uma vez que agora deve-se mapear quatro estados em um estado que usa variáveis de 256 bits; a seguir é mostrado como o estado é organizado para esta implementação. Organização do estado. O primeiro passo foi mapear os quatro estados a serem processados em variáveis de 256 bits; para comportar as 100 palavras dos estados S1 = 1 2 2 2 2 3 3 3 4 4 4 {s0, . . . , s24}, S = {s0, . . . , s24}, S = {s0, . . . , s24} e S = {s0, . . . , s24} foi preciso usar 25 variáveis de 256 bits, denominadas Y = {Y0,...,Y24}. O mapeamento de cada uma das palavras do estado em suas respectivas variáveis por ser visto na Figura 4.10. O mapeamento dos estados S1, S2, S3 e S4 em Y pode ser feito eficientemente com o uso das instruções LOAD, UNPACK_LO, UNPACK_HI e PRBLEND; a seguir é apresentado o trecho de código que mapeia as primeiras quatro palavras dos estados nas variáveis Y0, Y1, Y2 e Y3, o processamento para as outras palavras é análogo ao apresentado. CAPÍTULO 4. IMPLEMENTAÇÃO DA FAMÍLIA SHA-3 54

1 2 3 4 Y0 s0 s0 s0 s0

1 2 3 4 Y1 s1 s1 s1 s1

1 2 3 4 Y2 s2 s2 s2 s2

. . . .

1 2 3 4 Y22 s22 s22 s22 s22

1 2 3 4 Y23 s23 s23 s23 s23

1 2 3 4 Y24 s24 s24 s24 s24

Figura 4.10: Organização do estado para implementação vetorizada (4M) usando instru- ções de 256 bits.

1 1 1 1 T0 =LOAD(S1, 0) [s0, s1, s2, s3] 2 2 2 2 T1 =LOAD(S2, 0) [s0, s1, s2, s3] 3 3 3 3 T2 =LOAD(S3, 0) [s0, s1, s2, s3] 4 4 4 4 T3 =LOAD(S4, 0) [s0, s1, s2, s3] 1 2 1 2 T4 =UNPACK_LO(T0,T1)[s0, s0, s2, s2] 1 2 1 2 T0 =UNPACK_HI(T0,T1)[s1, s1, s3, s3] 3 4 3 4 T1 =UNPACK_LO(T0,T1)[s0, s0, s2, s2] 3 4 3 4 T2 =UNPACK_HI(T0,T1)[s1, s1, s3, s3] 1 2 3 4 Y0 =PRBLEND(T4,T1,XX)[s0, s0, s0, s0] 1 2 3 4 Y1 =PRBLEND(T0,T2,XX)[s1, s1, s1, s1] 1 2 3 4 Y2 =PRBLEND(T4,T1,XX)[s2, s2, s2, s2] 1 2 3 4 Y3 =PRBLEND(T0,T2,XX)[s3, s3, s3, s3]. Uma vez mapeado os estados nas variáveis de 256 bits, a função de permutação Keccak-p[1600,24] é processada analogamente a implementação apresentada na seção an- terior; o número de instruções usadas no cálculo da permutação é exatamente igual, mas nesta implementação são calculados quatro estados em vez de dois.

4.5 Implementação vetorizada (2M) usando instruções de 256 bits

Analisando a evolução cronológica dos conjuntos de instruções vetoriais da Intel percebeu- se que o conjunto de instruções AVX2 não veio exatamente como era esperado, visto o alto custo de mover dados entre a parte baixa e alta dos registradores bem como o com- portamento diferente do esperado de algumas instruções. Em contrapartida, ele trouxe uma característica muito interessante, que é computar dois pelo preço de um; isto é, dado uma implementação que faz um processamento h(x) eficientemente usando registradores de 128 bits é possível reescrevê-la usando registradores de 256 bits de modo a produzir CAPÍTULO 4. IMPLEMENTAÇÃO DA FAMÍLIA SHA-3 55

h(x1) e h(x2) pelo “mesmo preço” de calcular h(x1). Isso é possível porque a maioria das instruções de combinação, deslocamento e per- mutação que operam sobre registradores de 128 bits continuaram com o mesmo compor- tamento ao serem estendidas para registradores de 256 bits, a única diferença é que agora o processamento que era feito sobre registradores de 128 bits é feito na parte baixa e alta do registrador de 256 bits. Essa característica do conjunto de instruções AVX2 permitiu estender a implementação que usa instruções de 128 bits para computar a função de permutação Keccak-p[1600,24] para dois estados diferentes usando variáveis de 256 bits. Para comportar as 50 palavras 1 1 2 2 2 2 dos estados S = {s0, . . . , s24} e S = {s0, . . . , s24} foi necessário usar 13 variáveis de 256 bits, denominadas Y = {Y0,...,Y12}. O mapeamento de cada uma das palavras do estado em suas respectivas variáveis por ser visto na Figura 4.11.

1 1 2 2 1 1 2 2 1 1 2 2 1 1 2 2 X0 s0 s1 s0 s1 X1 s2 s3 s2 s3 X2 s5 s6 s5 s6 X3 s7 s8 s7 s8

1 1 2 2 1 1 2 2 1 1 2 2 1 1 2 2 X4 s4 s9 s4 s9 X5 s10 s11 s10 s11 X6 s12 s13 s12 s13 X7 s15 s16 s15 s16

1 1 2 2 1 1 2 2 1 1 2 2 1 1 2 2 X8 s17 s18 s17 s18 X9 s14 s19 s14 s19 X10 s20 s21 s20 s21 X11 s22 s23 s22 s23

1 1 2 2 X12 s24 s24 s24 s24

Figura 4.11: Organização do estado para implementação vetorizada (2M) usando instru- ções de 256 bits.

Uma vez mapeado os dois estados, S1 e S2 ao novo estado que utiliza variáveis de 256 bits, Y , a computação da função de permutação é feita analogamente a implemen- tação descrita na Seção 4.2, a única diferença é que as instruções agora operam sobre registradores de 256 bits.

4.6 Testes de desempenho

Nesta seção são apresentados os resultados experimentais das implementações do algo- ritmo SHA-3 usando o conjunto de instruções AVX2. Para a realização dos testes de desempenho foram utilizados os computadores HW-DESKTOP e HW-ULTRA; ambos usam um processador Haswell da Intel. Durante os experimentos as tecnologias avan- çadas dos processadores (Turbo Boost e Hyper-Threading) foram desabilitadas visando a reprodutibilidade dos experimentos. É importante mencionar que apesar de possuírem a mesma arquitetura, o computador HW-DESKTOP é um processador de propósito geral indicado para computadores de mesa, já o computador HW-ULTRA é um processador de baixo consumo energético, voltado para a computação móvel. Na Tabela 4.2 são mostra- das as especificações técnicas de cada computador. Todas as implementações que compõe este trabalho foram escritas na linguagem C e foram compiladas usando o compilador GCC 4.9 com a flag de compilação -O3. Visando reduzir o impacto do erro aleatório nos resultados, todos os experimentos foram executados 30 vezes e foi usado a mediana desses resultados. O primeiro experimento realizado foi computar o valor de resumo de mensagens longas para a família de funções de resumo SHA-3. As implementações testadas foram: (i) a im- CAPÍTULO 4. IMPLEMENTAÇÃO DA FAMÍLIA SHA-3 56

HW-DESKTOP HW-ULTRA Processador Core i7-4770 Core i5-4350U Frequência 3,4 GHz 1,4 GHz Memoria RAM 8 GB 4 GB Sistema Operacional Fedora 18 Fedora 20

Tabela 4.2: Especificações técnicas dos computadores HW-DESKTOP e HW-ULTRA. plementação nativa de 64 bits, desenvolvida por Ronny Van Keeris, que é a implementação mais rápida disponível no ECRYPT Benchmarking of Cryptographic Systems (eBACS) [7]; (ii) a implementação sequencial que usa registradores de 128 bits (apresentada na Se- ção 4.2); e (iii) a implementação sequencial que usa registradores de 256 bits, desenvolvida por Vladimir Sedach - disponível em [1] - que, diferente das outras implementações, foi escrita em linguagem de montagem. Na Figura 4.12 são apresentados os ciclos por bytes necessários para computar o valor de resumo de mensagens longas para cada uma das funções da família SHA-3. Pode- se ver que as três implementações possuem praticamente o mesmo desempenho, sendo que a diferença entre a mais rápida e a mais lenta é menor que 5%. A implementação nativa de 64 bits leva uma ligeira vantagem sobre as implementações vetoriais, pois nesta implementação a organização do estado e as permutações aplicadas não possuem custo adicional, diferente das implementações vetoriais.

Figura 4.12: Teste de desempenho da família SHA-3.

Algumas aplicações, como o esquema de assinatura digital Merkle [38], requerem a computação dos valores de resumo de várias mensagens. Neste contexto é interessante ter implementações que consigam computar o valor de resumo de mensagens do mesmo tamanho concorrentemente. Um outro experimento realizado foi comparar o desempenho da função SHA3-256 usando as implementações paralelas Vetorizada 128 bits (2M), Ve- torizada 256 bits (2M) e Vetorizada 256 bits (4M), apresentadas nas Seções 4.3, 4.5 e 4.4, respectivamente, com a implementação Nativa de 64 bits(1M). CAPÍTULO 4. IMPLEMENTAÇÃO DA FAMÍLIA SHA-3 57

Ciclos por bytes Speedup Keeris_64 bits (1M)[7] 9,01 1,00 Cabral_128 bits (2M) 6,76 1,33 Cabral_256 bits (2M) 4,76 1,89 Cabral_256 bits (4M) 3,50 2,57

Tabela 4.3: Ciclos por bytes e speedup das implementações paralelas vetorizadas.

Como pode ser visto na Tabela 4.3 o uso de instruções vetoriais permitem computar mais de uma mensagem concorrentemente de forma eficiente. A implementação vetori- zada usando instruções de 128 bits, que calcula dois valores de resumo por vez, é 1,33 vezes mais rápida que a implementação com instruções nativas de 64 bits; já a extensão dessa implementação para à vetorizada com instruções de 256 bits consegue calcular qua- tro valores de resumo com aproximadamente o mesmo processamento que calcula dois valores. O speedup obtido com a implementação que computa dois valores de resumo usando instruções de 256 bits é em torno de 1,9 quando comparado com a implementação sequencial que usa instruções de 128 bits. Os experimentos apresentados até aqui utilizam apenas um núcleo de processamento, desaproveitando os outros núcleos disponíveis nas arquiteturas usadas. Ainda pensando no cálculo de múltiplos valores de resumos concorrentemente, foi feito um experimento onde a implementação vetorizada 256 bits (4M) foi executada usando 1, 2, 4 e 8 threads nos computadores HW-DESKTOP e HW-ULTRA.

Figura 4.13: Teste de desempenho da família SHA-3.

Na Figura 4.13 é apresentado o speedup da implementação Vetorizada 256 bits (4M) em duas arquiteturas diferentes. Como pode ser visto, para o computador HW-DESKTOP a curva do speedup é crescente para até quatro threads; quando é colocado uma quanti- dade maior que essa já não se observa ganhos, isso acontece porque até quatro threads o processador consegue disparar cada uma para um núcleo de processamento diferente e executá-las independentemente. É possível observar um comportamento similar quando a CAPÍTULO 4. IMPLEMENTAÇÃO DA FAMÍLIA SHA-3 58 implementação é executada no computador HW-ULTRA, entretanto, o speedup só cresce até duas threads, pois como foi apresentado na Tabela 4.2 esse computador só possui dois núcleos de processamento.

4.7 Conclusão

Neste capítulo, foram apresentadas diferentes estratégias para utilizar o conjunto de ins- truções vetoriais presente nas arquiteturas da Intel na implementação eficiente do mais novo padrão de funções de resumo, SHA-3. Dentre as implementações apresentadas destaca-se a implementação sequencial usando instruções de 128 bits, que se mostrou mais eficiente do que a implementação sequencial usando instruções de 256 bits e que pode ser estendida para calcular duas funções de resumo concorrentemente “sem custo adicional”. Outra implementação a ser destacada é a implementação vetorizada (4M) usando instruções de 256 bits, que permite calcular quatro valores de resumo concorrentemente usando apenas um núcleo de processamento. O uso dos quatro núcleos de processamento disponíveis no computador HW-DESKTOP permitem o cálculo de até 16 valores de re- sumo por vez; essa computação de múltiplos valores de resumo concorrentemente pode ser usada para acelerar esquema de assinatura digital de Merkle [38]. Capítulo 5

Implementação da família QUARK

A função de resumo QUARK foi projetada originalmente para hardware e, como já men- cionado pelos autores em [3], não é um algoritmo otimizado para software. Para prover protocolos criptográficos seguros, que utilizam funções de resumo em plataformas que não possuem um hardware dedicado para implementá-las, a única opção é usar o conjunto de instruções dos processadores para implementar essas funções em software. Recentemente, funções criptográficas leves vêm sendo implementadas em software para microcontrola- dores de 8 bits; em [5] foram apresentadas implementações das funções de resumo leve QUARK, PHOTON e ESPONGENT para os níveis de segurança de 80 e 112 bits e em [22] foram apresentadas implementações de cifradores de blocos leves. Por outro lado, para arquiteturas de 32 bits, existem muito poucas implementações de funções de resumo leves otimizadas para software, uma implementação encontrada foi a do PHOTON para quatro níveis de segurança [29]. Neste Capítulo, é apresentado como remodelar os algoritmos S-QUARK (80 bits de segurança) e D-QUARK (112 bits de segurança) visando uma implementação eficiente em software para arquiteturas de 32 bits. Primeiramente é mostrado como reescrever as funções f, g, e h, definidas no Apêndice A.1, tornando-as mais atrativas para uma implementação em software; uma vez definidas as novas funções, é explicado como tirar proveito do paralelismo inerente dos algoritmos para implementá-las na plataforma Intel Galileo, que é a primeira arquitetura da Intel criada para a internet das coisas. Finalmente, são apresentados os testes de desempenho comparando as implementações do QUARK com implementações de outras funções de resumo leves.

5.1 Otimizações algorítmicas

A família de funções de resumo QUARK baseia-se na construção esponja usando a permu- tação P , definida na Seção 2.5.2. Para cada iteração da permutação P são necessários 13 bits do vetor X e 13 bits do vetor Y como entrada das funções f e g, respectivamente. Es- sas funções são executadas 4b vezes em cada chamada à permutação P e em cada iteração requerem 100 operações binárias, sendo 58 AND’s e 42 XOR’s; assim, é possível perceber que uma otimização dessas funções implica diretamente em um ganho de eficiência sobre a computação da permutação como um todo.

59 CAPÍTULO 5. IMPLEMENTAÇÃO DA FAMÍLIA QUARK 60

Ao analisar as funções f e g percebeu-se que é possível simplificar suas operações internas por meio de manipulações algébricas, reduzindo o número de operações binárias para 32 AND’s, 38 XOR’s e 4 NOT’s; essa redução implicou em um ganho de 26% sobre o número de operações binárias necessárias. As funções f e g otimizadas são mostradas nas Equações 5.1 e 5.2, respectivamente.

Função f otimizada: Dado um vetor X de 128 bits, a função f retorna um bit, compu- tado como:

f(X) =X0 ⊕ X16 ⊕ X26 ⊕ X39 ⊕ X52 ⊕ X61 ⊕ X69 ⊕ X84 ⊕ X94 ⊕ X97⊕

X103(X111¬(X28X39) ⊕ X97(X84 ⊕ X69(X61 ⊕ X84X111)))⊕ (5.1) X52(X16X84X111 ⊕ X39X61¬(X16X28 ⊕ X69X84X97))⊕

X16X28 ⊕ X61X69 ⊕ X103.

Função g otimizada: Dado um vetor Y de 128 bits, a função g retorna um bit, compu- tado como:

g(Y ) =Y0 ⊕ Y13 ⊕ Y30 ⊕ Y37 ⊕ Y56 ⊕ Y65 ⊕ Y69 ⊕ Y79 ⊕ Y92 ⊕ Y96⊕

Y101(Y109¬(Y28Y37) ⊕ Y96(Y79 ⊕ Y69(Y65 ⊕ Y79Y109)))⊕ (5.2) Y56(Y13Y79Y109 ⊕ Y37Y65¬(Y13Y28 ⊕ Y69Y79Y96))⊕

Y13Y28 ⊕ Y65Y69 ⊕ Y101.

As funções h de cada uma das instância da família de funções leve QUARK também podem ter suas operações binárias reduzidas. Essa redução permitiu diminuir o número de instruções binárias para cada uma das funções h em aproximadamente 25%. As funções otimizadas para U-QUARK, D-QUARK e S-QUARK são mostradas nas Equações 5.3, 5.4 e 5.5, respectivamente.

Função h do U-QUARK otimizada: Dado dois vetores X e Y de 68 bits e um vetor constante L, a função h retorna um bit, computado como:

h(X,Y,L) =X1 ⊕ Y2 ⊕ X4 ⊕ Y10 ⊕ X31 ⊕ Y43 ⊕ X56 ⊕ L0 ⊕ X25 ⊕ Y59⊕

X25(L0 ⊕ Y3X46) ⊕ X55(Y3 ∨ X46 ⊕ Y59)⊕ (5.3)

Y59(X46(Y3 ⊕ L0X25)).

Função h do D-QUARK otimizada: Dado dois vetores X e Y de 88 bits e um vetor constante L, a função h retorna um bit, computado como:

h(X,Y,L) =X1 ⊕ Y2 ⊕ X5 ⊕ Y12 ⊕ X40 ⊕ Y55 ⊕ X72 ⊕ L0 ⊕ Y24 ⊕ Y61⊕

X48 ⊕ X35 ⊕ X35(L0 ⊕ Y4X57) ⊕ Y79 ⊕ X68(Y4 ∨ X57 ⊕ Y79)⊕ (5.4)

Y79(X57(Y4 ⊕ L0X35)).

Função h do S-QUARK otimizada: Dado dois vetores X e Y de 128 bits e um vetor CAPÍTULO 5. IMPLEMENTAÇÃO DA FAMÍLIA QUARK 61

constante L, a função h retorna um bit, computado como:

h(X,Y,L) =X1 ⊕ Y3 ⊕ X7 ⊕ Y18 ⊕ X58 ⊕ Y80 ⊕ X105 ⊕ L0 ⊕ Y34 ⊕ Y71⊕

X90 ⊕ Y91 ⊕ X47 ⊕ X47(L0 ⊕ Y8X72) ⊕ Y111⊕ (5.5)

X100(Y8 ∨ X72 ⊕ Y111) ⊕ Y111(X72(Y8 ⊕ L0X47)).

A computação da permutação P usando as funções f, g e h otimizadas usa aproxi- madamente 25% menos operações binárias. Essas otimizações têm um impacto direto na implementação em software do algoritmo QUARK, permitindo um ganho de eficiên- cia e de tamanho de código de aproximadamente 20% e 10%, respectivamente, como é mostrado na Seção 5.4.

5.2 S-QUARK

Cada chamada à permutação P do algoritmo S-QUARK corresponde a 1024 chamadas às funções f, g e h; desse modo, qualquer otimização sobre essas funções afeta diretamente o desempenho da função de permutação como um todo. A primeira dificuldade encontrada na implementação para software foi o algoritmo trabalhar com operações sobre bits; como já se sabe, a manipulação de bits é uma operação muito cara em software. Assim, foi feito uma analise mais cuidadosa no algoritmo buscando padrões que permitissem trabalhar sobre um conjunto de bits, de modo a trabalhar não mais com bits separados e sim com blocos de bits (palavras). O algoritmo S-QUARK permite um paralelismo de grau 16 [3], isto é, é possível com- putar as primeiras 16 iterações sem qualquer dependência de dados. Essa característica do algoritmo permite agrupar blocos de 16 bits e trabalhar sobre eles, viabilizando assim uma implementação em software usando registradores de 16 bits. Dessa forma, fazendo um preprocessamento para organizar os bits, é factível processar 16 rodadas das funções f e g em paralelo; entretanto, mesmo com essa otimização, nem todo o poder de pro- cessamento da arquitetura alvo está sendo aproveitado, já que o microcontrolador Intel Galileo possui registradores de 32 bits e apenas 16 bits estão sendo usados. Analisando o algoritmo, percebeu-se que as funções f e g são simétricas, ou seja, elas executam as mesmas operações sobre um conjunto de dados diferente. Assim, a segunda otimização aplicada foi usar a parte alta dos registradores de 32 bits para processar a função f ao mesmo tempo que é computado a função g na parte baixa. A simetria das funções f e g permite juntá-las em uma nova função u, definida na Equação 5.6, que recebe como entrada 13 palavras de 32 bits e retorna uma palavra de 32 bits. A entrada da função u é representada por um vetor de 13 palavras de 32 bits t = [t0, t1, . . . , t12]. Função u: Dado um vetor t de 13 palavras de 32 bits, a função u retorna uma palavra de 32 bit, computada como:

u(t) =t0 ⊕ t2 ⊕ t3 ⊕ t4 ⊕ t5 ⊕ t6 ⊕ t7 ⊕ t8 ⊕ t1 ⊕ t9 ⊕ t10(t11¬(t12t4)⊕

t9(t8 ⊕ t7(t6 ⊕ t8t11))) ⊕ t5(t2t8t11 ⊕ t4t6¬(t2t12 ⊕ t7t8t9))⊕ (5.6)

t2t12 ⊕ t6t7 ⊕ t10. CAPÍTULO 5. IMPLEMENTAÇÃO DA FAMÍLIA QUARK 62

t0 = X0,...... ,X15 Y0,...... ,Y15

t1 = X94,...... ,X109 Y30,...... ,Y45

t2 = X16,...... ,X31 Y13,...... ,Y28

t3 = X26,...... ,X41 Y92,...... ,Y107

t4 = X39,...... ,X54 Y37,...... ,Y52

t5 = X52,...... ,X67 Y56,...... ,Y71

t6 = X61,...... ,X76 Y65,...... ,Y80

t7 = X69,...... ,X84 Y69,...... ,Y84

t8 = X84,...... ,X99 Y79,...... ,Y94

t9 = X97,...... ,X112 Y96,...... ,Y111

t10 = X103,...... ,X118 Y101,...... ,Y116

t11 = X111,...... ,X126 Y109,...... ,Y124

t12 = X28,...... ,X43 Y28,...... ,Y43

Figura 5.1: Inicialização das palavras t0, . . . , t12, usadas como entrada na primeira iteração da função u do algoritmo S-QUARK.

Na Figura 5.1 pode-se ver o estado inicial de cada uma das 13 palavras usadas para computar a primeira iteração da função u; nas iterações seguintes os valores dos indexes dos bits de cada palavra t serão somados por 16 modulo 128; por exemplo, a palavra t0 no estado seguinte será composta pelos valores X16 a X31 na parte alta e Y16 to Y31 na parte baixa. Por outro lado, a palavra t11 terá os valores X127 a X14 na parte alta e Y125 a Y13 na parte baixa. Esse processamento possibilita o uso dos 32 bits disponíveis pela arquitetura Galileo.

Dado dois vetores de 128 bits X e Y , são usadas oito palavras de 32 bits (x0 a x3 e y0 a y3) para guardar X e Y . A quantidade de trabalho necessário para organizar as palavras apresentadas na Figura 5.1 varia de acordo com a posição dos bits envolvidos; por exemplo, para inicializar t0 o processamento é muito simples, é preciso apenas zerar a parte baixar de x0 e aplicar um XOR com o a palavra y0 deslocada 16 bits para esquerda. Entretanto, para outras palavras essa organização pode ser mais complexa, por exemplo, a computação da palavra t5 usa bits que estão distribuídos nas palavras x1, x2, y1 e y2; o passo a passo para a computação da palavra t5 é mostrado a seguir:

aux1 = (x1 << 16) ⊕ (x2 >> 16)

aux2 = (y1 << 16) ⊕ (y2 >> 16)

t5 = ((aux1 << 4) ∧ 0xFFFF0000) ⊕ ((aux2 >> 8) ∧ 0x0000FFFF). Uma vez que as funções f e g foram otimizadas para 32 bits, o passo seguinte é otimizar a implementação da função h. O algoritmo S-QUARK permite juntar e processar concorrentemente blocos de 16 bits, mas como a arquitetura alvo possui 32 bits ela estaria sendo subutilizada, pois apenas metade do poder de processamento seria aproveito. Diferente de f, a função h não é simétrica, assim não é possível usar a mesma oti- mização aplicada nas funções f e g. Analisando as entradas de h, percebeu-se que 14 das 17 entradas possuem um grau de paralelismo 32; isso permitiu dividir a função h em CAPÍTULO 5. IMPLEMENTAÇÃO DA FAMÍLIA QUARK 63

h = h1(X,Y,L) ⊕ h2(X,Y,L). A função h1 opera sobre palavras de 32 bits, onde os pri- meiros 16 bits são usados na iteração i e os outros 16 bits são usados na iteração (i + 1).

Por outro lado, a função h2 opera sobre palavras de 16 bits e precisa ser computada em cada iteração; as funções h1 e h2 são definidas nas Equações 5.7 e 5.8, respectivamente.

Função h1: Dado dois vetores X e Y de 128 bits e um vetor constante L, o retorno da função h1 é uma palavra de 32 bits computada como:

h1(X,Y,L) =X1 ⊕ Y3 ⊕ X7 ⊕ Y18 ⊕ X58 ⊕ Y80 ⊕ L0 ⊕ Y34 ⊕ Y71⊕ (5.7) X90 ⊕ Y91 ⊕ X47 ⊕ X47(L0 ⊕ Y8X72).

Função h2: Dado dois vetores X e Y de 128 bits e um vetor constante L, o retorno da função h2 é uma palavra de 16 bits computada como:

h2(X,Y,L) =X105 ⊕ Y111 ⊕ X100(Y8 ∨ X72 ⊕ Y111)⊕ (5.8) Y111(X72(Y8 ⊕ L0X47)).

Para o cálculo de h1 e h2 é preciso pré-computar 17 valores de entrada; entretanto esses valores não precisam ficar armazenados na memória, uma vez que a maioria deles é usada apenas uma vez com uma operação XOR. Isto reduz a quantidade de variáveis necessárias de 17 para 5. Um pseudocódigo do algoritmo S-QUARK com as otimizações aqui apresentadas é mostrado no Algoritmo 4.

5.3 D-QUARK

As mesmas técnicas aplicadas à implementação do S-QUARK também podem ser apli- cadas ao D-QUARK, entretanto eles possuem graus de paralelismo diferente; enquanto o S-QUARK consegue processar 16 bits concorrentemente o D-QUARK consegue processar apenas 8 bits por vez.

Usando as mesma técnicas apresentadas na seção anterior, as palavras t0 a t12 fo- ram organizadas da seguinte forma: os bits necessários para computar a função f foram comportados nos primeiros 8 bits da parte baixa do registrador e nos seguintes 8 bits encontram-se os bits necessários para a computação da função g. Uma vez feito esse pré- processamento pode-se processar o algoritmo usando registradores de 16 bits e com um grau de paralelismo de 8. Essa versão, que usa registradores de 16 bits para processar 8 bits por vez, apresentou uma boa eficiência quando comparada com a implementação de referência1. Entretanto, essa versão não utiliza todo poder de processamento disponível na arquitetura, uma vez que usa apenas 16 bits dos 32 disponíveis. Ao analisar as funções f e g do D-QUARK percebeu-se que é possível usar a mesma otimização aplicada na função h do S-QUARK nas funções f e g; isto é possível pois das 13 entradas necessárias paras as duas funções, 12 possuem um grau de paralelismo 16.

Assim, é possível dividir as funções f e g em duas funções menores, f(X) = f1(X)⊕f2(X)

1A implementação de referência está disponível em [4] e não possui qualquer otimização CAPÍTULO 5. IMPLEMENTAÇÃO DA FAMÍLIA QUARK 64

Entrada: Estado S de 256 bits. Saída: Estado S0 atualizado.

1: x0 = (S00,...,S31), x1 = (S32,...,S63); 2: x2 = (S64,...,S95), x3 = (S96,...,S127); 3: y0 = (S128,...,S159), y1 = (S160,...,S191); 4: y2 = (S192,...,S223), y3 = (S224,...,S255); 5: for j=0 to 8 do 6: for i=0 to 4 do 7: Computa os valores de entrada de u, h1 e h2 8: aux1 = (xi ⊕ yi) ∧ 0xFFFF0000 9: aux1 = aux1 ⊕ u(t) 10: aux2 = h1(x, y, l) 11: aux3 = h2(x, y, l) 12: aux3 = aux2 ⊕ aux3 13: aux3 = (aux3 ∧ 0xFFFF0000) ⊕ (aux3 >> 16) 14: aux1 = aux1 ⊕ aux3 15: Computa os valores de entrada de u e h2 16: aux4 = (xi ⊕ yi) << 16 17: aux4 = aux4 ⊕ u(t) 18: aux3 = h2(x, y, l) 19: aux3 = aux2 ⊕ aux3 20: aux3 = (aux3 ∧ 0x0000FFFF) ⊕ (aux3 << 16) 21: aux2 = aux4 ⊕ aux3 22: xi = xi ⊕ ((aux1 ∧ 0xFFFF0000) ⊕ (aux2 >> 16)) 23: yi = yi ⊕ ((aux1 << 16) ⊕ (aux2 ∧ 0000FFFF)) 24: end for 25: end for 0 0 0 0 0 0 26: (S00,...,S31) = x0, (S32,...,S63) = x1, (S64,...,S095) = x2 0 0 0 0 0 0 27: (S96,...,S127) = x3, (S128,...,S159) = y0, (S160,...,S191) = y1 0 0 0 0 28: (S192,...,S223) = y2, (S224,...,S255) = y3 29: Retorno: S0. Algoritmo 4: Pseudo código do algoritmo S-QUARK otimizado para 32 bits. CAPÍTULO 5. IMPLEMENTAÇÃO DA FAMÍLIA QUARK 65

e g(Y ) = g1(Y ) ⊕ g2(Y ); as funções f1, f2, g1 e g2 são definidas nas Equações 5.9, 5.10, 5.11 e 5.12, respectivamente.

• Função f1: Dado um vetor X de 128 bits, a função f1 retorna um bit, computado como:

f1(X) =X0 ⊕ X11 ⊕ X18 ⊕ X27 ⊕ X36 ⊕ X42 ⊕ X47 ⊕ X58 ⊕ X64 ⊕ X67 ⊕ X71⊕

X42X47X67X71 ⊕ X11X19 ⊕ X27X36X42X47X58X67⊕

X42X47 ⊕ X11X19X27X36X42 ⊕ X58X67X71 ⊕ X27X36X42. (5.9)

• Função f2: Dado um vetor X de 128 bits, a função f2 retorna um bit, computado como:

f2(X) =X11X36X58X79 ⊕ X71X79 ⊕ X47X58X67X71X79 ⊕ X19X27X71X79. (5.10)

• Função g1: Dado um vetor X de 128 bits, a função g1 retorna um bit, computado como:

g1(Y ) =Y0 ⊕ Y9 ⊕ Y19 ⊕ Y25 ⊕ Y38 ⊕ Y44 ⊕ Y47 ⊕ Y54 ⊕ Y63 ⊕ Y67 ⊕ Y69⊕

Y44Y47Y67Y69 ⊕ Y9Y20 ⊕ Y25Y38Y44Y47Y54Y67⊕ (5.11)

Y44Y47 ⊕ Y9Y20Y25Y38Y44 ⊕ Y54Y67Y69 ⊕ Y25Y38Y44.

• Função g2: Dado um vetor X de 128 bits, a função g2 retorna um bit, computado como:

g2(Y ) =Y9Y38Y54Y78 ⊕ Y69Y78 ⊕ Y47Y54Y67Y69Y78 ⊕ Y20Y25Y69Y78. (5.12)

A divisão das funções f e g nas funções f1 e g1 preserva o paralelismo existente; assim, é possível criar uma nova função u1, a partir da junção de f1 e g1, que recebe 13 palavras de 32 bits como entrada e retorna uma palavra de 32 bits, na qual os primeiros 16 bits serão usados na iteração i e os bits restantes serão usados na iteração (i + 1). O processamento remanescente é computado pela função u2. Como a única palavra modificada para a iteração (i + 1) é t11, é possível reduzir a computação da função u2 na iteração (i + 1) a um XOR entre a palavra t11 com um valor computado na iteração i. As funções u1 e u2 estão definidas nas Equações 5.13 e 5.14, respectivamente.

Função u1: Dado um vetor t de 13 palavras de 32 bits, a função u1 retorna uma palavras de 32 bit, computada como:

u1(t) =t0 ⊕ t2 ⊕ t4 ⊕ t5 ⊕ t6 ⊕ t7 ⊕ t8 ⊕ t9 ⊕ t10 ⊕ t6(t7 ⊕ (t10t7t9)⊕ (5.13) (t5t4)¬(t12t2 ⊕ t9t8t7)) ⊕ (t12t2) ⊕ (t10t9t8).

Função u2: Dado um vetor t de 13 palavras de 32 bits, a função u2 retorna uma palavras CAPÍTULO 5. IMPLEMENTAÇÃO DA FAMÍLIA QUARK 66

t0 = X0,...... ,X15 Y0,...... ,Y15

t1 = X64,...... ,X79 Y20,...... ,Y35

t2 = X11,...... ,X26 Y9,...... ,Y24

t3 = X18 ...... ,X33 Y63,...... ,Y78

t4 = X27,...... ,X42 Y25,...... ,Y40

t5 = X36,...... ,X51 Y38,...... ,Y53

t6 = X42,...... ,X57 Y44,...... ,Y59

t7 = X47,...... ,X62 Y47,...... ,Y62

t8 = X58,...... ,X73 Y54,...... ,Y69

t9 = X67,...... ,X82 Y67,...... ,Y82

t10 = X71,...... ,X86 Y69,...... ,Y84

t11 = X79, ..., X86, 0, ..., 0 Y78, ..., Y85, 0, ..., 0

t12 = X19,...... ,X34 Y19,...... ,Y34

Figura 5.2: Inicialização das palavras, t0, . . . , t12, usadas como entrada na primeira itera- ção da função u1 do algoritmo D-QUARK.

t11 = 0,..., 0,,...,X6 0,..., 0,Y86,...,Y5

Figura 5.3: Palavra t11 na iteração (i + 1).

de 32 bit, computada como:

u2(t) =t11 ∧ t10(¬(t4t12) ⊕ (t7t9t8)) ⊕ (t8t5t2). (5.14)

Usando essa otimização é possível aproveitar, na maior parte do tempo, todo o poder de processamento da arquitetura Galileo. A configuração inicial de cada uma das 13 palavras necessárias na computação da primeira rodada das funções u1 e u2 é mostrada na Figura 5.2. Dessas palavras, apenas a palavra t11 precisa ser calculada a cada iteração para ser usada pela função u2 na iteração seguinte; na Figura 5.3 é mostrado a configuração da palavra t11 para a iteração (i + 1). A função h do algoritmo D-QUARK foi implementada com as mesmas otimizações usadas na função h do algoritmo S-QUARK, processando 16 bits em cada iteração.

5.4 Testes de desempenho

Nesta seção são apresentados os testes de desempenho das implementações aqui descri- tas2. A arquitetura usada foi o microcontrolador Intel Galileo, apresentado na Seção 3.3; todos as implementações foram escritas em linguagem C e foram compiladas usando o compilador i586-poky-linux-uclibc-gcc (GCC) 4.7.2. Na Tabela 5.1 é mostrado o impacto no desempenho das otimizações das funções f,

2As implementações dos algoritmo S-QUARK e D-QUARK aqui apresentadas estão disponíveis em https://github.com/rbCabral/QUARK_32bits CAPÍTULO 5. IMPLEMENTAÇÃO DA FAMÍLIA QUARK 67 g, e h quando aplicadas ao código de referência. Na primeira linha pode-se ver o có- digo de referência (S-QUARKref ) disponibilizado pelos autores em [4] e na linha seguinte encontra-se o mesmo código usando as funções otimizadas apresentadas na Seção 5.1, cha- mado (S-QUARKopt). O uso dessas otimizações permitiu a redução de aproximadamente 10% no tamanho do código e 20% nos ciclos por bytes.

Tabela 5.1: Desempenho do código de referência usando as funções otimizadas.

flag -O2 flag -Os Funções Tamanho do código Cycles por bytes Tamanho do código Cycles por bytes

S-QUARKref 2000 78370 1602 88778

S-QUARKopt 1808 61650 1469 70816

Na Tabela 5.2 é mostrado o tamanho do código e os ciclos por bytes de algumas funções de resumo leve com nível de segurança de 112 bits usando as flags de otimização

-O2 ou -O3 (a mais rápida) e -Os. S-QUARKopt1 é uma implementação do Algoritmo 4,

S-QUARKopt2 é uma implementação do Algoritmo 4 usando a técnica de otimização loop unrolled, PHOTON-224 é uma implementação baseada em tabelas, disponibilizada pelos autores em [29] e SPONGENT-224 é uma implementação de referência, disponibilizada pelos autores em [14]. A implementação mais rápida, quando compilada com -O3, é a PHOTON-224, mas para atingir esse desempenho é necessário um tamanho de código de 13450 bytes. Por outro lado, a implementação *S-QUARKopt1 compilada com -O3 é 2,3 vezes mais lenta que a PHOTON-224, mas com um tamanho de código 5,3 vezes menor. Usando a flag de compilação -Os, a implementação *S-QUARKopt1 se mostrou a mais compacta e eficiente. Na Tabela 5.3 é mostrado o tamanho do código e os ciclos por bytes de algumas funções de resumo leve com nível de segurança de 80 bits usando as flags de otimização -O2 ou

-O3 e -Os. D-QUARKref é a implementação de referencia, disponibilizada pelos autores em [4], D-QUARKopt é a implementação descrita na Seção 5.3, PHOTON-160 é uma implementação baseada em tabelas, disponível pelos autores em [29] e SPONGENT-160 é uma implementação de referência, disponível pelos autores em [14]. Como pode ser visto, a implementação D-QUARK é mais lenta que a implementação S-QUARK mesmo com um nível de segurança menor; isso acontece porque o D-QUARK divide a mensagem em blocos menores que o S-QUARK na fase de absorção e retorna

Tabela 5.2: Desempenho para nível de segurança de 112 bits.

flag O2 - O3 flag -Os Funções Tamanho do código Cycles por bytes Tamanho do código Cycles por bytes

S-QUARKref 2000 78370 1602 88778

S-QUARKopt1 2518 5671 2107 5832

S-QUARKopt2 7078 5138 3298 8015 PHOTON-224 13450 2366 2612 7678

SPONGENT-224 5030 1040014 3016 2311836 CAPÍTULO 5. IMPLEMENTAÇÃO DA FAMÍLIA QUARK 68 blocos menores na fase de extração, desse modo o algoritmo D-QUARK precisa computar a permutação P mais vezes que o algoritmo S-QUARK.

Tabela 5.3: Desempenho para nível de segurança de 80 bits.

flags O2 - O3 flag -Os Funções Tamanho do código Cycles por bytes Tamanho do código Cycles por bytes

D-QUARKref 1990 102997 1592 117462

D-QUARKopt 3326 9628 3114 10319 PHOTON-160 13795 1651 2698 12625

SPONGENT-160 4901 562337 3016 1255905

5.5 Conclusão

Neste capítulo foram apresentadas implementações eficientes em software dos algoritmos S-QUARK e D-QUARK. Na plataforma Intel Galileo, as implementações do S-QUARK e D-QUARK aqui descritas obtiveram uma aceleração de 15 e 10 vezes, respectivamente, quando comparadas com à implementação de referência. As técnicas aqui apresentadas também podem ser aplicadas para implementar a família QUARK em plataformas de 8 e 16 bits. Capítulo 6

Conclusões e trabalhos futuros

Este trabalho contribuiu com implementações eficientes de funções de resumo criptográ- fico. As famílias de funções de resumo estudadas foram: SHA-3, que teve sua implemen- tação direcionada à microarquitetura de propósito geral Haswell e QUARK, que teve sua implementação direcionada à arquitetura de 32 bits com recursos limitados. Na microarquitetura Haswell, foram usados os conjuntos de instruções vetoriais para implementar a família de funções de resumo SHA-3; dentre as implementações feitas, duas podem calcular um valor de resumo por vez, duas podem calcular dois valores de resumos concorrentemente e uma pode calcular quatro valores de resumo de quatro mensagens diferentes de mesmo tamanho; essas implementações usam os conjuntos de instruções AVX/AVX2 em um único núcleo de processamento. Os processadores de propósito geral atuais, normalmente, possuem mais de um nú- cleo de processamento; fazendo uso dos outros núcleos de processamento disponíveis na máquina utilizada o número de valores de resumo calculados concorrentemente aumentou para 32. Com a implementação vetorizada (2M) usando instruções de 256 bits, foi possível per- ceber uma das principais vantagens trazidas pelo conjunto de instruções AVX2, que é a possibilidade de estender uma implementação que usa registradores de 128 bits para realizar dois processamentos simultâneos usando praticamente o mesmo tempo de pro- cessamento; essa característica permitiu calcular dois valores de resumo 1,89 vezes mais rápido que calculá-los sequencialmente. A implementação da família QUARK foi feita na primeira plataforma de desenvolvi- mento da Intel direcionada à internet das coisas, Intel Galileo. Neste contexto, o principal desafio foi implementar um algoritmo que foi desencorajado até pelos próprios autores de ser implementado em software. Visando uma implementação eficiente, o algoritmo foi re- escrito para trabalhar com palavras de 16 e 32 bits em vez de trabalhar com bits dispersos, visto o alto custo de operações sobre bits em software. Uma das principais contribuições foi a reescrita das funções internas, reduzindo a quantidade de operações binárias em 25%; tal otimização teve um impacto direto na implementação eficiente do algoritmo em software, acarretando em uma redução no tempo de execução e no tamanho de código de aproximadamente 20% e 10%, respectivamente.

69 CAPÍTULO 6. CONCLUSÕES E TRABALHOS FUTUROS 70

Participação em eventos

Os resultados obtidos neste trabalho foram parcialmente financiados pela Intel (Intel Stra- tegic Research Alliance (ISRA) in Brazil - Energy-efficient Security for SOC Devices), por intermédio do CNPq com a bolsa de Desenvolvimento Tecnológico em TICs - Nível F. Assim, os avanços do projeto foram relatados por meio de relatórios técnicos e apresenta- ções presenciais que aconteciam duas vezes ao ano, sendo uma vez no Brasil e outra vez nos EUA; as apresentações feitas foram:

• Workshop em Manaus, Novembro de 2013;

• Workshop em Hillsboro, Maio de 2014;

• Workshop em Belo Horizonte, Novembro de 2014;

• Workshop em Hillsboro, Maio de 2015;

• Workshop em Florianópolis, Novembro de 2015.

Resultados intermediários das implementações do SHA-3 também foram apresenta- dos no Third International Conference on Cryptology and Information Security in Latin America (latincrypt 2014), por meio de apresentação de estudantes e no XIV Simpósio Brasileiro de Segurança da Informação e de Sistemas Computacionais (SBSeg 2014), por meio de um resumo estendido [15]. As implementações da família SHA-3 desenvolvidas neste trabalho encontram-se disponibilizadas em www.github.com/rbCabral/SHA-3. A implementação da família QUARK em dispositivos com recursos limitados resul- tou em um artigo [16] que foi apresentado em setembro de 2015 no Fourth International Workshop on Lightweight Cryptography for Security and Privacy (LightSec 2015). As implementações da família QUARK desenvolvidas neste trabalho encontram-se disponi- bilizadas em www.github.com/rbCabral/QUARK_32bits. Adicionalmente, foi publicado um minicurso na forma de capítulo de livro no SBSeg 2015 [23]. O minicurso é intitulado Implementação Eficiente e Segura de Algoritmos Criptográficos e concentra-se em descrever os aspectos que ajudam a tornar uma imple- mentação de criptografia em software eficiente e segura. Mais detalhes sobre o minicurso podem ser encontrados em http://www.ic.unicamp.br/~rbcabral/sbseg2015_mc03/.

Trabalhos futuros

Todas as implementações apresentadas neste trabalho foram escritas em linguagem C, como trabalho futuro pretende-se codificá-las em linguagem de montagem, visando uma melhora no desempenho. Neste trabalho foi apresentado uma implementação que permite calcular quatro va- lores de resumo do algoritmo SHA-3 paralelamente, tal implementação pode ser usada para acelerar o esquema de assinatura digital de Merkle [38], que é um esquema de as- sinatura digital resistente a computadores quânticos. Como trabalho futuro, pretende-se estender essa implementação para calcular 8 valores de resumo concorrentemente usando CAPÍTULO 6. CONCLUSÕES E TRABALHOS FUTUROS 71 registradores de 512 bits [34], que já estão presente nos processadores Phi, tal como aproveitar a quantidade de núcleos de processamento disponível no para acelerar mais ainda o esquema de assinatura digital de Merkle. A internet das coisas está ganhando uma atenção maior a cada dia e existe uma grande preocupação em desenvolver algoritmos criptográficos seguros que se adequem aos recursos limitados de tais dispositivos. Na maioria das vezes esses algoritmos são projetados para serem implementados em hardware, sendo muito ineficiente em software; assim, é importante pesquisar técnicas de implementar tais algoritmos eficientemente em software para arquiteturas com recursos limitados. Como trabalho futuro, espera-se aplicar as técnicas de otimizações apresentadas para implementar a família QUARK em arquiteturas de 8 e 16 bits. Referências Bibliográficas

[1] Gilles Van Assche. The Keccak Code Package. Available at https://github.com/ gvanas/KeccakCodePackage in Oct. 26 2015, October 2015.

[2] Jean-Philippe Aumasson, Luca Henzen, Willi Meier, and María Naya-Plasencia. Quark: A lightweight hash. In Stefan Mangard and François-Xavier Standaert, edi- tors, Cryptographic Hardware and Embedded Systems, CHES 2010, volume 6225 of Lecture Notes in Computer Science, pages 1–15. Springer Berlin Heidelberg, 2010.

[3] Jean-Philippe Aumasson, Luca Henzen, Willi Meier, and María Naya-Plasencia. Quark: A lightweight hash. Journal of Cryptology, 26(2):313–339, 2013.

[4] Jean-Philippe Aumasson, Luca Henzen, Willi Meier, and María Naya-Plasencia. Quark: a lightweight hash. URL: https://131002.net/quark/, May 2015.

[5] Josep Balasch, Bariş Ege, Thomas Eisenbarth, Benoit Gérard, Zheng Gong, Tim Gü- neysu, Stefan Heyse, Stéphanie Kerckhof, François Koeune, Thomas Plos, Thomas Pöppelmann, Francesco Regazzoni, François-Xavier Standaert, Gilles Van Assche, Ronny Van Keer, Loïc van Oldeneel tot Oldenzeel, and Ingo von Maurich. Compact implementation and performance evaluation of hash functions in attiny devices. In Stefan Mangard, editor, Smart Card Research and Advanced Applications, volume 7771 of Lecture Notes in Computer Science, pages 158–172. Springer Berlin Heidel- berg, 2013.

[6] Mihir Bellare and Phillip Rogaway. Random oracles are practical: A paradigm for designing efficient protocols. In Proceedings of the 1st ACM Conference on Computer and Communications Security, CCS ’93, pages 62–73, New York, NY, USA, 1993. ACM.

[7] Daniel J Bernstein and Tanja Lange. ebacs: Ecrypt benchmarking of cryptographic systems, 2009.

[8] G. Bertoni, J. Daemen, M. Peeters, and G. Van Assche. On the Indifferentiability of the Sponge Construction. In Advances in Cryptology – Eurocrypt 2008, pages 181–197, 2008. http://sponge.noekeon.org/.

[9] Guido Bertoni, Joan Daemen, Michaël Peeters, and GV Assche. The keccak reference. Submission to NIST (Round 3), 13, 2011.

72 REFERÊNCIAS BIBLIOGRÁFICAS 73

[10] Guido Bertoni, Joan Daemen, Michaël Peeters, and Gilles Van Assche. Sponge func- tions. In ECRYPT hash workshop, volume 2007, 2007.

[11] Guido Bertoni, Joan Daemen, Michaël Peeters, and Gilles Van Assche. Sakura: A Flexible Coding for Tree Hashing. In Ioana Boureanu, Philippe Owesarski, and Serge Vaudenay, editors, Applied Cryptography and Network Security, volume 8479 of Lec- ture Notes in Computer Science, pages 217–234. Springer International Publishing, 2014.

[12] Eli Biham, Rafi Chen, Antoine Joux, Patrick Carribault, Christophe Lemuet, and William Jalby. Collisions of sha-0 and reduced sha-1. In Advances in Cryptology– EUROCRYPT 2005, pages 36–57. Springer, 2005.

[13] Andrey Bogdanov, Miroslav Knežević, Gregor Leander, Deniz Toz, Kerem Varıcı, and Ingrid Verbauwhede. spongent: A lightweight hash function. In Bart Preneel and Tsuyoshi Takagi, editors, Cryptographic Hardware and Embedded Systems – CHES 2011, volume 6917 of Lecture Notes in Computer Science, pages 312–325. Springer Berlin Heidelberg, 2011.

[14] Andrey Bogdanov, Miroslav Knežević, Gregor Leander, Deniz Toz, Kerem Varıcı, and Ingrid Verbauwhede. Spongent:the design space of lightweight cryptographic hashing. URL: https://sites.google.com/site/spongenthash/home, June 2015.

[15] Roberto Cabral and Julio López. Software implementation of SHA-3 family using AVX2. In Simpósio Brasileiro em Segurança da Informação e de Sistemas Compu- tacionais, volume XIV, pages 330–333. Sociedade Brasileira de Computação, 2014.

[16] Roberto Cabral and Julio López. Fast Software Implementation of QUARK on a 32-bit architecture. In LightSec 2015, volume IV, 2015.

[17] Ran Canetti, Oded Goldreich, and Shai Halevi. The random oracle methodology, revisited. J. ACM, 51(4):557–594, July 2004.

[18] Intel Corporation. Hardware Design Site Archives. Intel R Pentium processor with MMXTM technology documentation. http://www.intel.com/design/archives/ Processors/mmx/.

[19] Intel Corporation. Intel R Advanced Vector Extensions Programming Reference, June 2011. Disponível em https://software.intel.com/sites/default/files/ m/f/7/c/36945.

[20] IvanBjerre Damgård. A design principle for hash functions. In Gilles Brassard, editor, Advances in Cryptology — CRYPTO’ 89 Proceedings, volume 435 of Lecture Notes in Computer Science, pages 416–427. Springer New York, 1990.

[21] Christophe De Cannière, Orr Dunkelman, and Miroslav Knežević. Katan and ktantan — a family of small and efficient hardware-oriented block ciphers. In Christophe Clavier and Kris Gaj, editors, Cryptographic Hardware and Embedded Systems - REFERÊNCIAS BIBLIOGRÁFICAS 74

CHES 2009, volume 5747 of Lecture Notes in Computer Science, pages 272–288. Springer Berlin Heidelberg, 2009.

[22] Thomas Eisenbarth, Zheng Gong, Tim Güneysu, Stefan Heyse, Sebastiaan Indeste- ege, Stéphanie Kerckhof, François Koeune, Tomislav Nad, Thomas Plos, Francesco Regazzoni, François-Xavier Standaert, and Loic van Oldeneel tot Oldenzeel. Com- pact implementation and performance evaluation of block ciphers in attiny devices. In Aikaterini Mitrokotsa and Serge Vaudenay, editors, Progress in Cryptology - AFRI- CACRYPT 2012, volume 7374 of Lecture Notes in Computer Science, pages 172–187. Springer Berlin Heidelberg, 2012.

[23] Armando Faz-Hernández, Roberto Cabral, Diego F. Aranha, and Julio López. Imple- mentação Eficiente e Segura de Algoritmos Criptográficos. In Simpósio Brasileiro em Segurança da Informação e de Sistemas Computacionais - Minicursos, volume XV, pages 93–140. Sociedade Brasileira de Computação, 2015.

[24] M. Flynn. Some Computer Organizations and Their Effectiveness. Computers, IEEE Transactions on, C-21(9):948–960, Sept 1972.

[25] Agner Fog. Instruction tables: Lists of instruction latencies, throughputs and micro- operation breakdowns for Intel, AMD and VIA CPUs, December 2014.

[26] Agner Fog. The microarchitecture of intel, amd and via cpus/an optimization guide for assembly programmers and compiler makers, 2014.

[27] Guido, Joan Bertoni, Michaël Daemen, Gilles Van Peeters, and Assche. Crypto- graphic sponge functions. URL: http://sponge.noekeon.org/CSF-0.1.pdf, Janu- ary 2011.

[28] Jian Guo, Thomas Peyrin, and Axel Poschmann. The photon family of lightweight hash functions. In Phillip Rogaway, editor, Advances in Cryptology – CRYPTO 2011, volume 6841 of Lecture Notes in Computer Science, pages 222–239. Springer Berlin Heidelberg, 2011.

[29] Jian Guo, Thomas Peyrin, and Axel Poschmann. The photon family of lightweight hash functions. URL: https://sites.google.com/site/photonhashfunction/, May 2015.

[30] Martin Hell, Thomas Johansson, Alexander Maximov, and Willi Meier. A stream cipher proposal: Grain-128. In IEEE International Symposium on Information The- ory (ISIT 2006). Citeseer, 2006.

[31] Sebastiaan Indesteege, Florian Mendel, Bart Preneel, and Christian Rechberger. Col- lisions and other non-random properties for step-reduced sha-256. In Selected Areas in Cryptography, pages 276–293. Springer, 2009.

[32] Intel Corporation. Intel R Quark SoC X1000 Core Developer’s Manual. Number 329679-001US. October 2013. REFERÊNCIAS BIBLIOGRÁFICAS 75

[33] Intel Corporation. Intel R Quark SoC X1000 Core Hardware Reference Manual. Number 329678-001US. October 2013.

[34] Intel Corporation. Intel R Architecture Instruction Set Extensions Programming Re- ference. Number 319433-023. August 2015.

[35] Shu jen Chang, Ray Perlner, William E Burr, Meltem Sönmez Turan, John M Kel- sey, Souradyuti Paul, and Lawrence E Bassham. Third-round report of the SHA-3 cryptographic hash algorithm competition. US Department of Commerce, National Institute of Standards and Technology, 2012.

[36] Jonathan Katz and Yehuda Lindell. Introduction to modern cryptography. CRC Press, 2014.

[37] Ralph Charles Merkle. Secrecy, authentication, and public key systems. PhD thesis, Stanford University, 1979.

[38] RalphC. Merkle. A Digital Signature Based on a Conventional Encryption Function. In Carl Pomerance, editor, Advances in Cryptology — CRYPTO ’87, volume 293 of Lecture Notes in Computer Science, pages 369–378. Springer Berlin Heidelberg, 1988.

[39] RalphC. Merkle. A certified digital signature. In Gilles Brassard, editor, Advances in Cryptology — CRYPTO’ 89 Proceedings, volume 435 of Lecture Notes in Computer Science, pages 218–238. Springer New York, 1990.

[40] National Institute of Standards and Technology. FIPS PUB 202 SHA-3 Standard: Permutation-Based Hash and Extendable-Output Functions. National Institute for Standards and Technology, Gaithersburg, MD, USA, August 2015.

[41] FIPS PUB NIST. 180-1: Secure hash standard, 1995.

[42] Christof Paar and Jan Pelzl. Understanding cryptography: a textbook for students and practitioners. Springer Science & Business Media, 2009.

[43] Bart Preneel. The first 30 years of cryptographic hash functions and the nist sha-3 competition. In Topics in Cryptology-CT-RSA 2010, pages 1–14. Springer, 2010.

[44] NIST FIPS PUB. 180-2: Secure hash standard, 2001. Federal Information Processing Standards Publication.

[45] NIST FIPS PUB. 180. Secure hash standard, National Institute of Standards and Technology, US Department of Commerce, DRAFT, 1993.

[46] Michael O Rabin. Digitalized signatures. Foundations of secure computation, 78:155– 166, 1978.

[47] Manoel Carlos Ramon. Intel Galileo and Intel Galileo Gen 2. Springer, 2014. REFERÊNCIAS BIBLIOGRÁFICAS 76

[48] Vincent Rijmen and Elisabeth Oswald. Update on sha-1. In Topics in Cryptology– CT-RSA 2005, pages 58–71. Springer, 2005.

[49] Phillip Rogaway and Thomas Shrimpton. Cryptographic hash-function basics: De- finitions, implications, and separations for preimage resistance, second-preimage re- sistance, and collision resistance. In Bimal Roy and Willi Meier, editors, Fast Soft- ware Encryption, volume 3017 of Lecture Notes in Computer Science, pages 371–388. Springer Berlin Heidelberg, 2004.

[50] Xiaoyun Wang, Yiqun Lisa Yin, and Hongbo Yu. Finding collisions in the full sha-1. In Advances in Cryptology–CRYPTO 2005, pages 17–36. Springer, 2005.

[51] Stallings William and William Stallings. Cryptography and Network Security, 6/E. Pearson Education India, 2014.

[52] G. Yuval. How to Swindle Rabin. Rapport nr. IR. Vrije Universiteit, Wiskundig Seminarium, 1978. Apêndice A

A.1 Família QUARK

Aqui é apresentada a família de funções de resumo QUARK e as funções p, f, g e h para cada membro da família. A função p, usada no LFSR L, é a mesma para todas as instâncias: dado um vetor L, p(L) = L0 ⊕ L3.

U-QUARK É a versão mais leve da família QUARK. Foi projetada para fornecer um valor de resumo de 136 bits e possui uma segurança de 64 bits. As funções f, g e h usadas nesta instância são definidas a seguir:

• Função f: Dado um vetor X de 68 bits, a função f retorna 1 bit, computado como:

f(X) =X0 ⊕ X9 ⊕ X14 ⊕ X21 ⊕ X28 ⊕ X33 ⊕ X37 ⊕ X45 ⊕ X50 ⊕ X52 ⊕ X55⊕

X9X28X45X59 ⊕ X33X37X52X55 ⊕ X9X15 ⊕ X21X28X33X37X45X52⊕

X55X59 ⊕ X33X37 ⊕ X9X15X21X28X33 ⊕ X45X52X55 ⊕ X21X28X33⊕

X37X45X52X55X59 ⊕ X15X21X55X59. (A.1) • Função g: Dado um vetor Y de 68 bits, a função g retorna 1 bit, computado como:

g(Y ) =Y0 ⊕ Y7 ⊕ Y15 ⊕ Y20 ⊕ Y30 ⊕ Y35 ⊕ Y37 ⊕ Y42 ⊕ Y49 ⊕ Y51 ⊕ Y54⊕

Y7Y30Y42Y58 ⊕ Y35Y37Y51Y54 ⊕ Y7Y16 ⊕ Y20Y30Y35Y37Y42Y51⊕ (A.2) Y54Y58 ⊕ Y35Y37 ⊕ Y7Y16Y20Y30Y35 ⊕ Y42Y51Y54 ⊕ Y20Y30Y35⊕

Y37Y42Y51Y54Y58 ⊕ Y16Y20Y54Y58.

• Função h: Dado dois vetores X e Y de 68 bits e um vetor de constantes L, a função h retorna 1 bit, computado como:

h(X,Y,L) =L0 ⊕ X1 ⊕ Y2 ⊕ X4 ⊕ Y10 ⊕ X25 ⊕ X31 ⊕ Y43 ⊕ X56 ⊕ Y59

⊕ Y3X55 ⊕ X46X55 ⊕ X55Y59 ⊕ Y3X25X46 ⊕ Y3X46X55 (A.3)

⊕ Y3X46Y59 ⊕ L0X25X46Y59 ⊕ L0X25.

77 APÊNDICE A. 78

D-QUARK O algoritmo D-QUARK é a versão intermediária da família de algoritmos leve QUARK. Ela fornece um valor de resumo de 160 bits e possui 80 bits de segurança. As funções f, g e h, são definidas como segue:

• Função f: Dado um vetor X de 88 bits, a função f retorna 1 bit, computado como:

f(X) =X0 ⊕ X11 ⊕ X18 ⊕ X27 ⊕ X36 ⊕ X42 ⊕ X47 ⊕ X58 ⊕ X64 ⊕ X67⊕

X71 ⊕ X11X36X58X79 ⊕ X42X47X67X71 ⊕ X27X36X42X47X58X67⊕

X42X47 ⊕ X11X19X27X36X42 ⊕ X58X67X71 ⊕ X27X36X42⊕

X71X79 ⊕ X47X58X67X71X79 ⊕ X19X27X71X79 ⊕ X11X19. (A.4) • Função g: Dado um vetor Y de 88 bits, a função g retorna 1 bit, computado como:

g(Y ) =Y0 ⊕ Y9 ⊕ Y19 ⊕ Y25 ⊕ Y38 ⊕ Y44 ⊕ Y47 ⊕ Y54 ⊕ Y63 ⊕ Y67 ⊕ Y69⊕

Y9Y38Y54Y78 ⊕ Y44Y47Y67Y69 ⊕ Y9Y20 ⊕ Y25Y38Y44Y47Y54Y67⊕ (A.5) Y69Y78 ⊕ Y44Y47 ⊕ Y9Y20Y25Y38Y44 ⊕ Y54Y67Y69 ⊕ Y25Y38Y44⊕

Y47Y54Y67Y69Y78 ⊕ Y20Y25Y69Y78.

• Função h: Dado dois vetores X e Y de 88 bits e um vetor de constantes L, a função h retorna 1 bit, computado como:

h(X,Y,L) =L0 ⊕ X1 ⊕ Y2 ⊕ X5 ⊕ Y12 ⊕ Y24 ⊕ X35 ⊕ X40 ⊕ X48 ⊕ Y55⊕

Y61 ⊕ X72 ⊕ Y79 ⊕ Y4X68 ⊕ X57X68 ⊕ X68Y79 ⊕ Y4X35X57⊕

Y4X57X68 ⊕ Y4X57Y79 ⊕ L0X35X57Y79 ⊕ L0X35. (A.6)

S-QUARK O algoritmo S-QUARK é a versão que fornece o maior nível de segurança na família de funções de resumo leves QUARK. Ela fornece um valor de resumo de 256 bits e possui 112 bits de segurança. Como todas as outras versões do QUARK, ele usa essencialmente três funções, sendo elas, f, g e h, que são definidas a seguir:

• Função f: Dado um vetor X de 128 bits, a função f retorna 1 bit, computado como:

f(X) =X0 ⊕ X16 ⊕ X26 ⊕ X39 ⊕ X52 ⊕ X61 ⊕ X69 ⊕ X84 ⊕ X94 ⊕ X97⊕

X103 ⊕ X16X52X84X111 ⊕ X61X69X97X103 ⊕ X39X52X61X69X84X97⊕

X61X69 ⊕ X16X28X39X52X61 ⊕ X84X97X103 ⊕ X39X52X61⊕

X103X111 ⊕ X69X84X97X103X111 ⊕ X28X39X103X111 ⊕ X16X28. (A.7) APÊNDICE A. 79

• Função g: Dado um vetor Y de 128 bits, a função g retorna 1 bit, computado como:

g(Y ) =Y0 ⊕ Y13 ⊕ Y28 ⊕ Y37 ⊕ Y56 ⊕ Y65 ⊕ Y69 ⊕ Y79 ⊕ Y92 ⊕ Y96 ⊕ Y101⊕

Y13Y56Y79Y109 ⊕ Y65Y69Y96Y101 ⊕ Y13Y30 ⊕ Y37Y56Y65Y69Y79Y96⊕

Y101Y109 ⊕ Y65Y69 ⊕ Y13Y30Y37Y56Y65 ⊕ Y79Y96Y101 ⊕ Y37Y56Y65⊕

Y69Y79Y96Y101Y109 ⊕ Y30Y37Y101Y109. (A.8) • Função h: Dado dois vetores X e Y de 128 bits e um vetor de constantes L, a função h retorna 1 bit, computado como:

h(X,Y,L) =L0 ⊕ X1 ⊕ Y3 ⊕ X7 ⊕ Y18 ⊕ Y34 ⊕ X47 ⊕ X58 ⊕ Y71 ⊕ Y80⊕

Y91 ⊕ X105 ⊕ Y111 ⊕ Y8X100 ⊕ X72X100 ⊕ X100Y111 ⊕ Y8X47X72⊕

X90 ⊕ Y8X72X100 ⊕ Y8X72Y111 ⊕ L0X47X72Y111 ⊕ L0X47. (A.9)