Mais um blog inútil.

Useless

Outubro 20, 2011

Novas arvorezinhas (1.0 e 2.0) em Perl

Arquivado em: arvorezinha, coding, serious-business, useless — falco @ 15:05

A arvorezinha em Perl que existe, não desenha a arvorezinha toda, com código escrito por quem faz o código da arvorezinha. Na minha opinião isso não respeitava o standard. Como tal achei que devia fazer uma arvorezinha como deve ser em Perl:

A versão 1.0:


print "*"x$_,"\n" for(1 .. 5);

Para este não ser um post demasiado parvo. Resolvi fazer uma arvorezinha em versão 2.0. em Perl. Inspirei-me no código do falso, mas não consegui resolver o bug do tronco (também não tentei muito):

use 5.010;
use strict;
use warnings;

# I'm not playing Perl Golf!

our $RAMO = "*";
our $ESPACO = qq/ /;
our $TRONCO = "#";



run();



sub run {
    my $altura = $ARGV[0] || 0;
    
    desenha_ramos($altura);
    desenha_tronco($altura);
}



sub desenha_ramos {
    my ($altura) = @_;

    for(1 .. $altura) {
        my $linha = desenha_elemento(1, ($altura - $_), $ESPACO);
        $linha .= $RAMO for( 1 .. (($_ * 2) - 1) );
        say $linha;
    }
}



sub desenha_tronco {
    my ($altura) = @_;

    my $largura = ($altura * 2) - 1;
    $altura = ($altura / 2);

    for(1 .. $altura) {
        if($altura % 2) {
            my $sombra = desenha_elemento(0, (($largura / 4) - 1), $ESPACO);
            my $tronco = desenha_elemento(0, (($largura / 2) - 1), $TRONCO);

            say $sombra.$tronco;
        }
        else {
            my $sombra = desenha_elemento(0, ($largura / 4), $ESPACO);
            my $tronco = desenha_elemento(1, (($largura / 2) - 1), $TRONCO);

            say $sombra.$tronco;
        }
    }
}



sub desenha_elemento {
    my ($min, $max, $tipo_elemento) = @_;

    my $elemento = $tipo_elemento;
    $elemento = sprintf("%s%s", $elemento, $tipo_elemento) for($min .. $max);

    return $elemento;
}

Julho 4, 2011

BrainFucker

Arquivado em: arvorezinha, coding, osx, useless — falso @ 22:54

Ora viva!!!

Há uns tempos atrás vi nas internets um projecto verdadeiramente inutil, do calibre das coisas que vão aparecendo por aqui, chamado Brainfuck Developer, que é um IDE para programar e debugar Brainfuck.
Senti-me um pouco cabisbaixo ao ver que alguém tinha tentado chegar aos meus calcanhares em nível de inutilidade, portanto decidi por mãos à obra para me redimir. E então à boa maneira dos projectos open sores, decidi ripar a ideia, e comecei a desenvolver o BrainFucker, um IDE de Brainfuck para OSX!
Claro que isto não foi assim feito do pé-pra-mão, até porque não sabia nada de Objective-C nem de Cocoa, mas com o tempo, e pachorra aos fins de semana e tal, finalmente está disponível a versão 0.1.

Suporta correr programas de Brainfuck que só usem OUTPUT (.), o INPUT (,) ainda não está implementado, mas provavelmente vai ser uma DialogBox a pedir o valor.
Possibilidade de correr programas STEP-BY-STEP para ver as alterações dos valores e posição do apontador de memoria.

Espero que isto sirva para alguém aprender Brainfuck, ou mesmo para aprender como não programar em Objective-C.
O codigo está disponivel no github. E um build experimental está disponível: BrainFucker.zip - Apenas testado em OSX 10.4 e 10.5 POWERPC (só para quem ama). Agradeço a alguém que reporte se também funciona em Intels.

Cumprimentos, e um bem haja!

Dezembro 14, 2010

Árvorezinha 2.0

Arquivado em: arvorezinha, assembly, coding, drama, useless — falso @ 01:07

Ora viva amigos!

Há uns tempos no trabalho um colega meu começou a fazer pouco das minhas árvorezinhas, a dizer que só eram meia árvore, e que eu devia era de fazer uma árvore completa. Eu fiquei SENTIDO com tal AFRONTA, e fiquei a MATUTAR sobre isso, até que decidi por mãos à obra, e criar a Árvorezinha 2.0.

Primeiro decidi faze-la em C porque é a linguagem STANDARD!

[sourcecode language="c"]
#include <stdio.h>
#include <stdlib.h>

int main(int argc, char *argv[])
{
        int altura;
        int i,x;
        int lul;

        if (argc < 2)
        {
                return(0);
        }
        altura = atoi(argv[1]);

        /* Ciclo da altura da Arvore */
        for(i = 1; i <= altura; i++)
        {

                /*
                        Numero de Espaços
                        Começa em 0 porque existem linhas com 0 espaços
                        Algoritmo: altura - linha
                */
                for(x = 0 ; x < (altura-i); x++)
                {
                        putchar(' ');
                }

                /*
                        Numero de Asteriscos
                        Começa em 1 porque não existem linhas sem *
                        Algoritmo: (2 * linha) - 1
                */
                for (x = 1; x <= (2*i)-1; x++)
                {
                        putchar('*');
                }

                putchar('\n');
        }

        /* Largura ultima linha */
        lul = (altura * 2) - 1;

        /*
                Ciclo da altura do tronco
                Algoritmo: altura / 2
        */
        for(i = 1; i <= (altura/2); i++)
        {
                /*
                        Por causa do ASCII nao permitir meio char
                        tive de fazer duas implementacoes diferentes,
                        uma para quando o  valor da altura do tronco
                        e' par, e outra para quando e' impar.
                */
                if (altura % 2)
                {
                        /* Impar */

                        /*
                                Numero de Espaços
                                Algoritmo: (lul / 4) - 1
                        */
                        for(x = 0; x <= (lul/4)-1; x++)
                        {
                                putchar(' ');
                        }


                        /*
                                Numero de # (tronco)
                                Algoritmo: lul / 2
                        */
                        for(x = 0; x <= (lul/2); x++)
                        {
                                putchar('#');
                        }

                        putchar('\n');
                }
                else
                {
                        /* Par */

                        /*
                                Numero de Espaços
                                Algoritmo: lul / 4
                        */
                        for(x = 0; x <= (lul/4); x++)
                        {
                                putchar(' ');
                        }


                        /*
                                Numero de # (tronco)
                                Algoritmo: (lul / 2) - 1
                        */
                        for(x = 0; x <= (lul/2)-1; x++)
                        {
                                putchar('#');
                        }

                        putchar('\n');
                }
        }

}

[/sourcecode]

A pedido de muitas famílias, foi me imposta a tarefa de fazer um RFC da nova árvorezinha, mas não tenho muito jeito para escrever algoritmos em pseudo-código. Então tal obra heróica fica para o caro leitor, façam me um baseado no código em C e enviem-me!

Segundo as próprias leis já pré-estabelecidas da Árvorezinha, tem de existir uma implementação em Assembly! Então não podia cá faltar a minha versão em x86 Assembly.

[sourcecode language="plain"]

;
; Arvorezinha 2.0
; x86 Assembly
; Copyright (C) 2010 Pedro de Oliveira
; //blol.org
;
; this assembly can never fail
;
        BITS            32
        GLOBAL          main

; Vou usar duas funcoes da libc para o codigo nao crescer gigantescamente
; com rotinas que nao interessam nada para aqui.
        EXTERN          atoi
        EXTERN          printf

; Definicao das Variaveis
SECTION         .data

        argc    dd      0
        argv    dd      0

        erro    db      "ERRO! Executar: %s <altura da arvore>",10,0

        card    db      '#'
        newl    db      0xa
        aste    db      '*'
        espa    db      ' '

        altura  dd      0
        i       dd      1
        x       dd      0
        lul     dd      0

; He cometh!
SECTION         .text

main:
        pop     eax                     ; Ignorar...

        pop     eax                     ; Saca o argc da Stack
        mov     dword [argc], eax       ; Guarda o valor na variavel argc

        pop     ebx                     ; Saca a posicao de memoria do
                                        ; argv[0] da Stack
        mov     eax, dword [ebx]        ; Mete a posicao em EAX
        mov     [argv], eax             ; Guarda-a em argv

        add     ebx,0x4                 ; Salta 4 bytes para a frente
                                        ; para o argv[1] ficar em EBX

        mov     eax, [argc]             ; Mete o argc em EAX
        cmp     eax, 0x2                ; Verifica se e' diferente de 2
        jne     jafoste                 ; Se for sai com erro

        push    dword [ebx]             ; Mete o valor de argv[1] na Stack
        call    atoi                    ; Corre o atoi com esse valor
        mov     [altura], eax           ; O resultado fica em EAX, guarda
                                        ; na variavel altura

ciclo_linhas:
        ; INICIO - CICLO DAS LINHAS DA ARVORE
        mov     eax, [i]                ; i em EAX
        mov     ebx, [altura]           ; altura em EBX

        cmp     ebx, eax                ; Compara
        jb      prepara_tronco          ; i > altura ? proximo passo
        mov     dword [x], 0            ; Mete x a 0

ciclo_espacos:
        ; INICIO - CICLO DE ESPAÇOS ANTES DOS ASTERISCOS
        mov     eax, [x]                ; x em EAX

        ; pretende-se (altura - i) em EBX
        mov     ebx, [altura]           ; altura em EBX
        mov     ecx, [i]                ; i em ECX
        sub     ebx, ecx                ; EBX - ECX

        cmp     ebx, eax                ; Compara
        jbe     prepara_asteriscos      ; x >= (altura - i) ? proximo passo

        push    espa                    ; Espaço
        call    print                   ; write()

        call    incrementa_x
        jmp     ciclo_espacos           ; Volta para o inicio do ciclo
        ; FIM - CICLO DE ESPAÇOS ANTES DOS ASTERISCOS

prepara_asteriscos:
        mov     dword [x], 1            ; Mete x a 1

ciclo_asteriscos:
        ; INICIO - CICLO DE ASTERISCOS (ARVORE)
        mov     ebx, [x]                ; x em EBX

        ; pretende-se (2 * i) - 1 em EAX
        mov     eax, 2                  ; 2 em EAX
        mov     ecx, [i]                ; i em ECX
        mul     ecx                     ; Multiplica EAX por ECX
        dec     eax                     ; Subtrai 1 a EAX

        cmp     eax, ebx                ; Compara
        jb      fim_ciclo_linhas        ; x > (2*i)-1 ? proximo passo

        push    aste                    ; Asterisco
        call    print                   ; write()

        call    incrementa_x
        jmp     ciclo_asteriscos        ; Volta para o inicio do ciclo
        ; FIM - CICLO DE ASTERISCOS (ARVORE)

fim_ciclo_linhas:
        push    newl                    ; Newline
        call    print                   ; write()

        call    incrementa_i
        jmp     ciclo_linhas            ; Volta para o inicio
        ; FIM - CICLO DAS LINHAS DA ARVORE

prepara_tronco:
        ; pretende-se (altura * 2) - 1 em EAX
        mov     eax, [altura]           ; altura em EAX
        mov     ecx, 2                  ; 2 em ECX
        mul     ecx                     ; Multiplica EAX por ECX
        dec     eax                     ; Subtrai 1 a EAX
        mov     dword [lul], eax        ; Guarda a largura da ultima linha
                                        ; em lul


        mov     dword [i], 1            ; Mete o i a 1

ciclo_linhas_tronco:
        ; BEGIN - CICLO DAS LINHAS DO TRONCO
        mov     ecx, [i]                ; i em ECX

        ; pretende-se (altura / 2)
        mov     eax, [altura]           ; altura em EAX
        shr     eax, 1                  ; divide por 2

        cmp     ecx, eax                ; Compara ECX com EAX
        jg      sair                    ; i > (altura / 2) ? Adeus!

        mov     eax, [altura]           ; altura em EAX
        test    eax, 1
        je      pc_tronco_par_espacos   ; e' par?

; --------------------------- IMPAR -------------------------------
pc_tronco_impar_espacos:
        mov     dword [x], 0            ; Mete-se x a 0

c_tronco_impar_espacos:
        ; INICIO - CICLO DOS ESPAÇOS ANTES DO TRONCO (IMPAR)
        mov     ecx, [x]                ; x em EAX

        ; pretende-se (lul / 4) - 1 em EAX
        mov     eax, [lul]              ; lul em EAX
        shr     eax, 2                  ; Divide por 4
        dec     eax                     ; Subtrai 1

        cmp     eax, ecx                ; Compara
        jb      pc_tronco_impar_cardinal; x > (lul/4)-1 ? Next!

        push    espa                    ; Espaço
        call    print                   ; write()

        call    incrementa_x
        jmp     c_tronco_impar_espacos  ; Volta para o inicio
        ; FIM - CICLO DOS ESPAÇOS ANTES DO TRONCO (IMPAR)

pc_tronco_impar_cardinal:
        mov     dword [x], 0            ; Mete x a 0

c_tronco_impar_cardinal:
        ; INICIO - CICLO DOS CARDINAIS DO TRONCO (IMPAR)
        mov     ecx, [x]                ; x em ECX

        ; pretende-se (lul / 2) em EAX
        mov     eax, [lul]              ; lul em EAX
        shr     eax, 1                  ; Divide por 2

        cmp     eax, ecx                ; Compara
        jb      fim_ciclo_linhas_tronco ; x > (lul/2) ? Next!

        push    card                    ; Cardinal
        call    print                   ; write()

        call    incrementa_x

        jmp     c_tronco_impar_cardinal ; Volta para o inico
        ; FIM - CICLO DOS CARDINAIS DO TRONCO (IMPAR)

; --------------------- FIM IMPAR --------------------------------


; ----------------------------- PAR ------------------------------
pc_tronco_par_espacos:
        mov     dword [x], 0            ; Mete x a 0

c_tronco_par_espacos:
        ; INICIO - CICLO DOS ESPAÇOS ANTES DO TRONCO (PAR)
        mov     ecx, [x]                ; x em ECX

        ; pretende-se (lul / 4) em EAX
        mov     eax, [lul]              ; lul em EAX
        shr     eax, 2                  ; divide por 4

        cmp     eax, ecx                ; Compara
        jb      pc_tronco_par_cardinal  ; x > (lul / 4) ? Next!

        push    espa                    ; Espaço
        call    print                   ; write()

        call    incrementa_x
        jmp     c_tronco_par_espacos    ; Volto para o inico do ciclo
        ; FIM - CICLO DOS ESPAÇOS ANTES DO TRONCO (PAR)

pc_tronco_par_cardinal:
        mov     dword [x], 0            ; Mete x a 0

c_tronco_par_cardinal:
        ; INICIO - CICLO DOS CARDINAIS DO TRONCO (PAR)
        mov     ecx, [x]                ; x em ECX

        ; pretende-se (lul / 2) - 1 em EAX
        mov     eax, [lul]              ; lul em EAX
        shr     eax, 1                  ; Divide por 2
        dec     eax                     ; Subtrai 1

        cmp     eax, ecx                ; Compara
        jb      fim_ciclo_linhas_tronco ; x > (lul / 2) - 1 ? uhuhuh

        push    card                    ; Cardinal
        call    print                   ; write()

        call    incrementa_x

        jmp     c_tronco_par_cardinal   ; Volta para o inicio do ciclo
        ; FIM - CICLO DOS CARDINAIS DO TRONCO (PAR)
; ----------------------- FIM PAR ----------------------------------

fim_ciclo_linhas_tronco:
        push    newl
        call    print

        call    incrementa_i
        jmp     ciclo_linhas_tronco     ; Volta para o inico do ciclo
        ; FIM - CICLO DAS LINHAS DO TRONCO

jafoste:
        mov     eax, [argv]             ; Mete o apontador de argv em EAX
        push    dword eax               ; Mete o endereço de argv na Stack
        push    dword erro              ; Mete o endereço da String na Stack
        call    printf                  ; Escreve no ecra!


sair:
        mov     ebx,0x0                 ; valor de saida
        mov     eax,0x1                 ; sys_exit
        int     0x80

print:
        mov     ecx,[esp+4]             ; Mete o argumento em ECX
        mov     edx,1                   ; Length
        mov     ebx,1                   ; stdout
        mov     eax,4                   ; sys_write
        int     0x80
        ret

incrementa_x:
        mov     eax, [x]
        inc     eax
        mov     dword [x], eax
        ret

incrementa_i:
        mov     eax, [i]
        inc     eax
        mov     dword [i], eax
        ret
[/sourcecode]

E aqui vai a prova dos nove:

[sourcecode language="plain"]
falso@lemonparty:~/src/zbr$ make
rm -f arvore2 arvore.o
nasm -f elf arvore.asm -o arvore.o
gcc -g -o arvore2 arvore.o
falso@lemonparty:~/src/zbr$ ./arvore2 4
   *
  ***
 *****
*******
  ###
  ###
falso@lemonparty:~/src/zbr$ ./arvore2 5
    *
   ***
  *****
 *******
*********
  #####
  #####
falso@lemonparty:~/src/zbr$
[/sourcecode]

Espero lançar futuramente um género de Unit Tests, para testar as varias implementações da Arvorezinha 2.0 que possam surgir, para ver se cumprem o standard ou não.

Espero que tenham gostado do post, até à proxima, fiquem bem e joguem muito! Chuuuuuuack!

Novembro 4, 2010

Arvorezinha --- C++ Templates 2

Arquivado em: arvorezinha, coding, useless — dcoder @ 03:00

Viva. Há demasiado tempo que não são adicionadas novas entradas à nossa já lendária colecção de arvorezinhas em várias linguagens e dialectos de todo o mundo.

Assim sendo, hoje trago-vos uma arvorezinha feita com templates de C++. Sim, eu sei. Já temos uma. Mas isto não me impede de utilizar outras capacidades de C++ para cumprir o mesmo objectivo. Ora vejam lá:

#include <iostream>

using namespace std;

template<int i>
struct SemiArvorezinha : public SemiArvorezinha<i-1>
{
	SemiArvorezinha(){cout << "*";}
};

template<> struct SemiArvorezinha<0> {};

template<int i>
struct Arvorezinha : public Arvorezinha<i-1>, SemiArvorezinha<i>
{
	Arvorezinha(){ cout << endl; }
};

template<> struct Arvorezinha<0>{};

int main(int argc, char **argv)
{
	Arvorezinha<5> A;
	return 0;
}

Em vez de funções com templates, temos nesta encarnação classes e multiple inheritance. Bem haja a todos.

Outubro 28, 2010

Scam nos leilões do ClubeFashion

Arquivado em: drama, fail, serious-business, useless — falso @ 09:32

Ora viva amigos!

Hoje não venho aqui blogar de nada relativo a Informáticas, mas sim a um scam lindo que achei nas Internets portuguesas.

Então estava eu ontem muito bem no meu covil, a fazer a lida das coisas inúteis do dia-a-dia, quando a minha FC se vira para mim e diz-me que o site ClubeFashion (que já é conhecido por dar altas baldas de 1 e 2 meses para entregar as coisas que se compra la) agora tem leilões, e que haviam la pessoas a ganhar coisas mirabolantes por preços bues baratos.

Eu achei que isso cheirava a esturro, porque em Portugal, ninguém da nada a ninguém. Então decidi investigar melhor a coisa.

Então funciona desta maneira, para se licitar em algo, tem de se fazer um carregamento de “Bids” do site. 10 Bids = 5€, 20 Bids = 10€, etc.
Então basicamente sempre que se faz uma licitação, mesmo que não se ganhe, ou se alguém der um valor superior eles ganham logo 0.50€. Até aqui está MAIS ou MENOS bem, até que se entra na pagina de um leilão a decorrer actualmente…

Agora aqui é que parte a loiça toda. Pelos vistos (já tinha visto ontem à noite) os leilões arrancam sempre com o valor inicial de 1€. E depois temos a seguinte informação:

\* A sua licitação subirá o valor em 0.01€.
\* Abaixo de 2 MINUTOS, qualquer licitação reinicia o contador.

Então isto funciona mais ou menos assim, eles têm uma coisa para leiloar, mas com o dinheiro que vão ganhar com as licitações, vai chegar para pagar o que quer que estejam a leiloar, e ainda um lucro de mais de 100%. E claro que se o leilão estiver a acabar, sem terem sido feitas licitações suficientes, eles têm um script que faz automaticamente licitações com fake accounts, para o tempo nunca terminar até fazerem o dinheiro suficiente.

Vamos ver então um exemplo, a “Viagem Lufthansa para a Europa”, dizem que o PVP Loja é 358€ e quem ganhou o leilão, ganhou por 79.90€.
Então o leilão começa a 1€. 79.90€-1€ da 78.90, que dá 7890 licitações, então vamos ver, 7890 * 0.50€ = 3945€, então eles com este leilão da viagem que custava 358€ ganharam 3587€, está um belo negocio hein?

Bem, eu achei isto tanta roubalheira, que necessitei de vir blogar sobre isto, espero que gostem! E leiam tudo bem antes de serem enganados por estes sites malandros. Até à proxima, fiquem bem e joguem muito.

Outubro 17, 2010

FCT

Arquivado em: useless — amg @ 16:22

No outro dia ia pela escolinha e vi o fALSO. Fui falar com ele e ele pensava que eu era todo trve. Só que eu não sou

Setembro 5, 2010

Arduino, AT*'s, AVR Studio/AVRdude, ISP, JTAG, debugWIRE e afins

Arquivado em: coding, useless — thread @ 03:02

Boa noite amiguinhos!

A pedido de algumas familias, volto para monologar um pouco sobre algumas inutilidades que me ocuparam o fim de semana. Penso que também poderá ser util para o patrão deste blog!

Aqui há algum tempo falei com nosso amiguinho fALSO sobre o facto de ele utilizar o AVR Studio para brincar com o seu arduino. Na altura a conversa ficou um bocado por ali, não falamos muito sobre o caso, mas hoje vou blolar sobre isso com um mini-how-to inútil.

Resumindo o conteúdo, irei apresentar algumas alternativas para a programação do arduino, passando por avr studio e avrdude, utilizando alguns programadores/debuggers.

Ora bem, primeiro que tudo, os únicos arduinos que andam aqui por casa perdidos são os “duemilanove”… existem varias versões do arduino, embora a mais conhecida/usada penso que seja a “mega”.

Duas grandes diferenças entre a “mega” e a “duemilanove” são a expansibilidade (dado que a versão “mega” traz um atmega1280 e a “duemilanove” traz um atmega168…). Resumindo: “mega” is better.

Embora este how-to se baseie na versão “duemilanove”, irei referir os procedimentos para a versão “mega” quando estes diferirem do que for dito, a fim de quem tenha esta versão possa seguir os passos.

Existem para já duas grandes diferenças no que toca a debugging entre o ATmega1280 e o ATmega168:

- o ATmega1280 na versão “mega” suporta JTAG para debugging/programming, que no caso do chip instalado no arduino mega, o JTAG vem desabilitado por defeito para que existam mais ADC’s (Analog/Digital Converters) disponíveis. Ou seja, com JTAG habilitado, teremos menos quatro analog inputs no arduino.

- o ATmega168 na versão “duemilanove” suporta debugWIRE para debugging, que vem desabilitado por defeito, a fim de o ISP programming interface (SPI) esteja habilitado dado que as duas tecnologias partilham o pin RESET(debugWIRE)/RESET(SPI) (que é o pin nr 1 do chip). Ou seja, se um estiver habilitado, o outro não está. Isto pode ser especialmente perigoso, mas mais à frente vou dar mais uma palavrinha sobre isto, mas para já vamos prosseguir com outras coisas ainda menos úteis que isto. O facto do ATmega168 ter debugWIRE em vez de JTAG é unica e exclusivamente devido a ter menos pins disponiveis. Isto acontece com todos os chips da ATmel. Todos aqueles que tenham poucos pinos, utilizam debugWIRE uma vez que esta interface apenas utiliza um pin bidirecional, ao contrario de JTAG que no minimo necessita de 4.

Arduino, Bus Pirate & avrdude

Para habilitarmos JTAG ou debugWIRE nos respectivos arduinos, passa pela alteração do estado dos Fuses. Os fuses são basicamente flag registers que controlam o comportamento do chip. No caso dos chips da atmel existem 3 familias de fuses nos ATmega: lfuse, hfuse e efuse (Low, High e Extended Fuse Bytes)… portanto poderemos ter até 24 configurações on/off nesta familia de chips.

Cada ATmegaXxx têm o sua propria configuração de fuses. Digo isto pois o mapa de bits da configuração dos fuses pode n coincidir de modelo para modelo dentro da familia ATmega. Cada chip tem o seu datasheet que deverá ser consultado antes de se efectuar qualquer configuração nos fuses. Alerto que pode ser fácil brickar um chip através das configurações dos fuses e, sem as ferramentas certas, pode ser dificil voltar ao estado anterior.

Uma das formas mais economicas de ler/programar os fuses nestes chips, é usando o Bus Pirate e o avrdude.

Actualmente o avrdude suporta o bus pirate, mas ontem tive alguns problemas com o driver (da versão avrdude 5.10) pois não é compativel com a nova versão de firmware 5.7 (latest até à data do bus pirate), portanto tive que fazer um pequeno patch:

—BOF—
--- ./buspirate.c 2010-01-19 10:39:11.000000000 +0000
+++ ../avrdude-5.10-new/buspirate.c 2010-09-04 03:01:06.000000000 +0100
@@ -257,7 +257,7 @@
static int buspirate_is_prompt(char *str)
{
/\* Prompt ends with ‘>’ all other input probably ends with ‘\n’ */
- return (str[strlen(str) - 1] == ‘>’);
+ return (str[strlen(str) - 2] == ‘>’);
}

static int buspirate_expect(struct programmer_t *pgm, char *send,
@@ -533,7 +533,7 @@

static void buspirate_enable(struct programmer_t *pgm)
{
- unsigned char *reset_str = “#\n”;
+ unsigned char *reset_str = “#\ny”;
char *rcvd;
int fw_v1 = 0, fw_v2 = 0;
int rc, print_banner = 0;
@@ -600,7 +600,7 @@
serial_recv_timeout = 100;
buspirate_reset_from_binmode(pgm);
} else
- buspirate_expect(pgm, “#\n”, “RESET”, 1);
+ buspirate_expect(pgm, “#\ny”, “RESET”, 1);
}

static int buspirate_initialize(struct programmer_t *pgm, AVRPART * p)
—EOF—

Atenção que este patch torna o avrdude incompativel com as versões de firmware < 5.x pois não tive paciencia para manter a retrocompatibilidade… mas penso q era mais uma inutilidade inútil para ocupar tempo.

As sources do avrdude podem ser downloaded here: http://download.savannah.gnu.org/releases/avrdude/avrdude-doc-5.10.tar.gz

Depois de se instalar o avrdude com a patch anterior, está na hora de ligar cabinhos:

Buspirate & arduino duemilanove. SPI connection
Buspirate & arduino duemilanove. SPI connection

Ora bem, o que aqui foi feito foi o seguinte:

1 - Interligou-se o bus pirate à interface SPI do arduino “duemilanove”, cujo pinout do arduino é:

MISO (1) +Vcc (2)
SCK (3) MOSI (4)
RESET (5) GND (6)

2 - E as cores dos cabos (e não dos aligators, pois diferem) do Bus Pirate que correspondem ao SPI são:

MOSI - Cinzento
MISO - Preto
SCK (CLK) - Rosa/Violeta
RESET (CS) - Branco
+5V (+Vcc) - Laranja
GND - Castanho

3 - Colocar uma resistencia de 10k entre o RESET e Vcc

4 - Embora o Bus Pirate possa alimentar o arduino, o avrdude não vai permitir que a PSU fique enabled, uma vez que é feito um reset sempre que se faz uma operação. Uma opção é mais uma vez alterar o driver do avrdude para o buspirate não fazer reset, no entanto, é mais facil alimentar externamente o arduino com uma PSU externa. Portanto deverão ligar o pin 2 (+) e 6 (-) a algo que forneça +5VDC.

5 - Ligar o bus pirate por usb à maquina onde se encontra o avrdude e efectuar o seguinte comando (verificar a path para o ficheiro de configuração do avrdude):

ATmega1280 (arduino “mega”):

# avrdude -C./avrdude.conf -pm1280 -cbuspirate -P/dev/ttyUSB0 -b115200 -v

ATmega168 (arduino “duemilanove”):

# avrdude -C./avrdude.conf -pm168 -cbuspirate -P/dev/ttyUSB0 -b115200 -v

Isto vai largar alguma tralha que neste momento não interessa ao menino jesus… o mais importante aparece mais para o fim:

(O dump seguinte refere-se ao ATmega168 [duemilanove])

Reading | ################################################## | 100% 0.10s

avrdude: Device signature = 0x1e9406
avrdude: safemode: lfuse reads as FF
avrdude: safemode: hfuse reads as DD
avrdude: safemode: efuse reads as 0

avrdude: safemode: lfuse reads as FF
avrdude: safemode: hfuse reads as DD
avrdude: safemode: efuse reads as 0
avrdude: safemode: Fuses OK

A partir daqui já temos alguma informação que nos interessa. De acordo com a datasheet do ATmega168, poderiamos activar o debugWIRE activando o 6º bit do hfuse. Neste caso, mudariamos o valor de 0xDD para 0xFD e ficariamos com uma meio de debugar o chip no avr studio. No entanto, isto também iria causar que o SPI fosse desabilitado, e não teriamos forma de programar o chip por SPI nem de alterar o hfuse por este meio. Teriamos de reabilitar o SPI por outros meios. Resumindo, o ATmega168 não é um bom chip se a nossa intenção for efectuar debugs, a menos que se tenham uma serie de ferramentas que facilitem o processo (alguns programadores da atmel) mas isso já não seria uma solução barata.

Se, por outro lado, fizermos um fetch do state dos fuses no ATmega1280 (“mega”) teriamos o seguiunte valor do hfuse:

avrdude: safemode: hfuse reads as 9A

Segundo a datasheet do ATmega1280, se activarmos o 7º bit do hfuse, activaremos o JTAG sem desabilitar o SPI, o que nos permite ter DUAS interfaces de programação (JTAG e SPI) e uma de debugging (JTAG) em simultaneo. No entanto, iremos perder quatro ADC’s, significando que o arduino ficará com menos 4 analog inputs -> ADC4, ADC5, ADC6 e ADC7 que correspondem respectivamente aos JTAG pins -> TCK, TDO, TMS e TDI.

Ora para isto ser concluido, temos de alterar o valor de 0x9A (10011010b) para 0xDA (11011010b). Para isso teremos de executar o seguinte:

# avrdude -C./avrdude.conf -pm1280 -cbuspirate -P/dev/ttyUSB0 -b115200 -v -U hfuse:w:0xda:m

Após isto, temos novas ferramentas para desenvolver, programar e debugar o arduino. Para aproveitar-mos o JTAG, necessitamos de um JTAG programmer para, pelo menos, a familia ATmega*. Existem um mini-avr jtag programmers no ebay baratuxos, que custam à volta de 18 dollares com free shipping, vindos dos confins do mundo. Demoram uns 15 dias a chegar, mas n se paga alfandega dado que o valor é inferior a 22 (ou 25) euros.

Estes mini-avr jtag programmers têm um pequeno senão! Não funcionam bem (pelo menos cmg não funcionam de todo) em win7 64-bits. O problema reside no chip que faz a conversão usbserie, que é um PL3203. Os drivers para estes chips em 64-bits não são flor que se cheire. Se contactarem o seller do ebay, ele vai-vos enviar um driver que diz que funciona, mas eu nunca o usei pq não está assinado. A minha solução passou por alterar o chip. Retirei o PL3203 e coloquei um FT232RL que, na minha opinião, são muito superiores a nível de suporte e efeciencia e o pinout é *quase* igual ao PL3203 (existe um ground no PL3203 que não está connected no FT232RL, mas esse ground não é usado no mini-avr jtag programmer, portanto o FT232RL torna-se assim um substituto directo neste caso). Se estiverem dispostos a fazer o mesmo, poderão adquirir o chip na farnell ou no ebay (FT232RL vem com package SSOP28 (atenção as letras RL)) e para o substituir deverão verificar se têm o material seguinte:

1 - Uma infrared soldering station OU uma hot air gun (se usarem uma hot air gun, podem abdicar do masking com folha de aluminio, no entanto se colocarem, só fará bem e não mal pois ajudará um pouco na dissipação do calor ao longo da folha).
2 - Flux em pasta
3 - Kapton tape E folha de aluminio (se possivel, que se possa colar tipo fita cola. podem comprar aqueles rolos de junção e isolamento de escapes de esquentadores que se vende no AKI).
4 - Um pincel e uma pinça

Aqui vão algumas photos do procedimento (algumas não estão muito focadas pq sou um troglodita a tirar fotos… depois parecem-me estar bem no ecrã minusculo da camara, mas depois qd passo pro PC tão uma merda valente):

infrared_station
infrared_station

kapton tape masking
kapton tape masking

Masking de aluminio para refletir infareds em zonas que não deverão ser expostas a esta radiação
Masking de aluminio para refletir infrared em zonas que não deverão ser expostas a esta radiação

Colocação de flux nas leads do chip
Colocação de flux nas leads do chip

Soldar / Dessoldar com infrared
Soldar / Dessoldar com infrared

Remoção do chip PL3203
Remoção do chip PL3203

mini-avr jtag programmer com novo chip FT232RL
mini-avr jtag programmer com novo chip FT232RL

Resumindo os passos efectuados:

1 - Mask de kapton tape em volta do chip. A kapton tape é uma “fita cola” que suporta cerca de 400ºC. A maioria não a usa quando utiliza folha de aluminio, mas eu uso como uma camada extra just in case.
2 - Mask de folha de aluminio em torno do chip. Isto irá simultaneamente refletir parte da radiação infrared e agir como um (ligeiro) dissipador, fazendo com que o q está na periferia do chip não seja tão aquecido como o chip.
3 - Aplicação de flux nas leads do chip. É um desoxidante poderoso quando activado a altas temperaturas. Irá impedir que os contactos não oxidem e irá facilitar o processo de soldadura.
4 - Colocar o pre-heater a 90ºC (mais não, devido aos plasticos que se encontram na board poderão deformar) e aplicar de radiação infrared. Programar a station para 270 ou 280ºC.
5 - Após remover o chip com uma pinça, deixar arrefecer e limpar toda a area onde se encontrava o chip com Isopropanol (IPA).
6 - Colocar um pouco de flux nos contactos do novo chip FT232RL, alinhar com os contactos da board e aplicar novamente infrared a 270/280ºC durante 6 ou 7 segundos.
7 - Verificar se o chip está fixo, deixar arrefecer e limpar novamente a area das leads com IPA.

Alternativamente, pode-se usar uma hot air gun para desoldar/soldar os chips, mas é um processo mais demorado e mais perigoso para os chips.

ATENÇÃO: A radiação infrared da estação é muito prejudicial para os olhos (e mãos se as la meterem). Utilizar SEMPRE oculos de protecção infrared, para alem do filtro que vem com a estação. O efeito é mais ou menos o mesmo que estarem a olhar para o sol.

Se tudo for feito sem espinhas, o resultado esperado será este:

O pinout deste mini-programmer é exactamente o mesmo do programador JTAGICE da ATmel. Basta verem o manual e interligar os pinos analogicos do arduino (referidos em cima com a correspondencia JTAG) aos pinos do mini-programador (Um site útil com pinouts de alguns fabricantes: http://www.jtagtest.com/pinouts/) . No AVR Studio deverão selecionar o programador JTAGICE. Mais à frente neste post encontrarão algumas ilustrações de como usar um programador no AVR studio (não será o mini-programador, pois quero poupar espaço e demonstrar outras coisas, mas os procedimentos são os mesmos).

AVRISP / AVR JTAG ICE e AVRstudio

Agora vamo-nos focar no AVRISP / AVR JTAG ICE programmer e as maravilhas (ou inutilidades) que esta peça de hardware faz juntamente com o AVRstudio.

Este programador é mais caro que o mini-avr jtag programmer, mas também suporta muitos mais familias de chips da Atmel (não só da familia mega) e tem dois modos de operação -> ISP ou JTAG (que é podem ser activados por um switch no programador -> para a direita activa ISP, para a esquerda activa JTAG). Existem alguns programadores da Atmel, cada um com a sua função. Poderão ser todos consultados no site da atmel. Este é um dos que suporta grande parte dos chips excepto a familias XMEGA e AT32* (e mais algumas). Caso pretendam um programador com suporte as familias xmega e a AT32*, deverão optar por uma versão do mkII.

Como já foi visto anteriormente, tanto o arduino “mega” como o “duemilanove” tem uma interface ISP, que são os 6 pins que se podem encontrar no caso do “mega” +/- a meio da board, e no caso do “duemilanove” na extremidade da board.

Agora vamos ligar este programmer ao arduino, utilizando um adaptador ISP de 10pin para 6pin (para atmel pinout):

Interligação do avrisp com o arduino
Interligação do avrisp com o arduino

Podemos utilizar uma bateria de 9V ligada directamente ao arduino, mas APENAS se esta for ligada no socket de alimentação. Pois à entrada deste socket, existe um regulador que irá fornecer os +5VDC ao atmega. Se ligarem directamente uma bateria de 9V no pinout do ISP, arriscam-se a chamuscar a coisa.

Verificar se o switch do programador está na posição da direita, e caso afirmativo, estamos prontos para brincar com o AVRstudio.

Tudo aquilo que fizemos com o avrdude, pode ser feito com uma interface bem mais simpatica no AVRStudio. Verificar e alterar fuses, efectuar backups de flash, eeprom, fuse states, enfim, uma serie de inutilidades. Seguem alguns screenshots:

Conectar ao programador em ISP mode:

Fuses:

Backups:

E pronto, não vou fazer um how-to também do avrstudio, pois não é esse o intuito do post, mas sim mostrar como se pode usar o AVRstudio para programar o arduino, a fim de expandir os meios (ou ferramentas, ou como lhe queiram chamar) de desenvolvimento.

Falta-me acrescentar que caso não tenham nenhum programador da atmel (ou equivalente) nem o mini-avr programmer, podem sempre usar o buspirate e o avrdude para programar os chips. Podem desenvolver tudo no AVRStudio e compilar, depois para flashar utilizam o avrdude com o seguinte comando (neste caso para programar a flash. No caso da eeprom deverão substituir a -U flash por -U eeprom, pro caso dos fuses -U hfuse ou lfuse ou efuse. Consultar o manual do avrdude para uma lista detalhada da flag -U):

# avrdude -C./avrdude.conf -pm168 -cbuspirate -P/dev/ttyUSB0 -b115200 -v -U flash:w:/path/para/o/file.hex:i

ou para o ATmega1280:

# avrdude -C./avrdude.conf -pm1280 -cbuspirate -P/dev/ttyUSB0 -b115200 -v -U flash:w:/path/para/o/file.hex:i

Bom, penso que já falei de inutilidades suficientes por hoje, espero que dentro desta tralha toda, isto motive o fALSO a mexer mais no seu arduino :D

Setembro 2, 2010

Cena de Urso da Tipp-Ex

Arquivado em: fail, lulz, useless — armorfist @ 23:01

Boas amiguinhos!

Já não blogo há algum tempo, portanto aqui vai um post sobre uma coisa completamente inútil:

Um amigo meu mostrou-me nas internets uma cena fofi, que podem ver aqui:
http://www.youtube.com/profile?user=tippexperience&feature=iv&annotation_id=annotation_820885

Basicamente tens alto player etc e depois metes palavras (verbos) na caixinha de texto e mostra-te um video se existir. O problema é que eu sou preguiçoso e não me apetecia tar a pensar em palavras. Então decidi fazer alto scripte em php. Fui às internets, saquei uma lista de 600 e tais verbos mais usados em inglês e fiz o seguinte:

<?php
/*
Output:

No match:
<?xml version="1.0" encoding="utf-8" ?><datas><status>NO MATCH</status><url>gaC_66xPvBc</url><id>1</id><duration>0.001227855682373</duration></datas>
Match:
<?xml version="1.0" encoding="utf-8" ?><datas><status>MATCH</status><url>Ks_2nKOKVGg</url><cost>0</cost><id>38</id><duration>0.00061297416687012</duration></datas>
*/

//No execution timeout
set_time_limit(0); 

// Open Verb list
$handle = @fopen("verb_list.txt", "r");

if ($handle) 
    while (!feof($handle)) 
    {
		// Get word
        $word = fgets($handle, 4096);
		
		//Filter Word
		$word = trim(str_replace(array("\r\n", "\n", "\r"),'',$word));
		
		// Create a stream
		$opts = array(
		  'http' =>array(
			'header'  => "Content-type: application/x-www-form-urlencoded\r\n", 
			'method' =>"POST",
			'content' => http_build_query(array('words' => $word, 'language' => 'en')),
			'timeout' => 5, 
		  )
		);

		$context = stream_context_create($opts);

		// Open the file using the HTTP headers set above
		$file = file_get_contents('http://217.174.206.135/tippex/scripts/matchfinder.php', false, $context);

		// Make an Object out of the XML
		$xmlobj = simplexml_load_string($file);

		// Is it a MATCH?
		if ($xmlobj->status == 'MATCH')
			echo "<a href='http://www.youtube.com/watch?v=".$xmlobj->url."'>".$word."</a> - http://www.youtube.com/watch?v=".$xmlobj->url."<br/>";
		
		// No flood
		sleep(1);
    }
	
// Close file
fclose($handle);
?>

Os comentários estão em inglês porque estou habituado a faze-los em inglês. Basicamente deu-me a seguinte lista:

Lista Completa

Muitos vídeos estão repetidos, o que poderia ter sido evitado pois eles dão o ID do video no XML, mas só me lembrei disso depois e não me apetece fazer a filtragem agora. Talvez amanhã.

Espero que gostem!

Beijinhos abraços e muitos palhaços.

Setembro 1, 2010

Bus Pirate - Firmware update

Arquivado em: drama, fail, useless — thread @ 23:04

Bom noite amiguinhos!! (disseram-me que “amiguinhos” ficava muito gay, então decidi editar).

Estive quase para blogar sobre a aventura que foi conseguir recuperar a password neste blog inútil… mas fica para outra vez.

Ora estava eu hoje com vontade de arranjar problemas e decidi fazer um firmware update ao meu Bus Pirate. Dei uma vista de olhos na diagonal no site mas como não estava com muita paciencia para ler, decidi logo zergar à campeão e fiz logo o download do maior numero que sufixava o nome dos ficheiros de firmware disponiveis para download no repositório.

Mal aquilo acabou de sacar a coisa, liguei-me via serie ao Bus Pirate, activei o bootloader mode, e em seguida fiz logo cócó:

Pronto… depois de rapidamente perceber que tinha brickado o Bus Pirate, também percebi que esta coisa ia tentar rescrever o bootloader que por sua vez estava activo.. e não ia poder ser re-escrito!

Agora sim, tinha um desafio e uma vontade enorme de fazer serão à volta disto para o unbrickar.
E decidi também blogar sobre isto caso alguem faça o mesmo cócó que eu fiz… pode ser que seja uma coisa pouco útil dentro desta vasta inutiilidade que estão para ver!

Comecei pelo que pensei ser o caminho mais simples… dado que o Bus Pirate tem uma interface ICSP, decidi tentar aceder directamente à pic com o auxilio dum pic debugger/programmer.

Portanto peguei então no lixo seguinte:

Montei o estaminé seguinte:

Alimentado pela besta seguinte:

Ora resumindo pseudo-tecnicamente a coisa, fiz o seguinte:
Interliguei o pickit3 ao interface ICSP do bus pirate com os cabinhos e alimentado por uma fonte de alimentação… (que podia ser 2 pilhas ou usar o próprio pickit3.. mas achei que assim ficava mais giro e tenho de dar uso as inutilidades cá de casa!) E as relações de cor/função na foto são:

amarelo -> MCLR | vermelho -> 3.3V | preto -> ground | azul -> PGD | verde -> PGC

Após esta cangalhada estar bem ligada, deve acender um led vermelhinho e outro verde no bus pirate. Se não acender e se eventualmente cheirar a queimado significa que têm de encomendar umas coisinhas na farnell ou assim.
Dado isto, está na altura de aproveitar o que o opensource tem de bom, e descarregar uma versão qualquer das sources do bus pirate para a sua amada pic. Decidi descarregar primeiro as sources da versão 4.3 e abri no mplab. (Nota… se realmente estiverem a salvar um bus pirate e queiram poupar tempo e trabalho… passem já para a parte final do post onde tem uns procedimentos de 1 a 15, que indica como flashar um bootloader e firmware com hex files, poupando assim a trabalhera de compilar as coisas todas.)

Algo importante a referir aqui, é que caso estejam a fazer este procedimento, devem instalar o mplab juntamente com outro pacote da microchip -> O mplab c30 (pode ser a versão LITE) que contem o toolkit para compilar e linkar os projects para pic24’s (que vêm no bus pirate v3).

Caso tudo esteja correcto, indo a Project -> Build all deverão obter o resultado seguinte:

Agora só se tem que selecionar o programador que vai ser usado para escrever o firmware.. que neste caso é um pickit3: Programmer -> Select Programmer -> 4 Pickit3.

E selecionar o pic em questão… que no caso do meu bus pirate v3 é o PIC24FJ64GA002 (mais alguem que esteja a fazer isto, deverá conferir a sopa de letras na pic do seu bus pirate e selecionar a correspondente): Configure -> Select Device -> Device:

Com isto, penso que é seguro dizer que se pode ir a Programmer -> Program, que deverá dar o seguinte resultado:

Agora só têm que desligar a fonte de alimentação, desligar o pickit3, retirar os cabinhos todos do interface ICSP, ligar por usb ao pc, e abrir um terminal na COMx correspondente e ver se o gajo respira:

E parece que sim! De novo à vida inútil, pronto para ir para a prateleira mais uns meses apanhar pó…

Agora já só falta colocar um bootloader nisto, que como podem ver está com a v255.255 que quer dizer isso mesmo que estão a pensar.

Para poupar espaço no blog, vou apenas referir os procedimentos sem estar a largar mais screenshots.

1 - ligar novamente o bus pirate ao pickit3 com os passinhos todos anteriores.
2 - abrir o mplab
3 - ir a File -> Import -> selecionar o .hex file que contem o bootloader desejado. No meu caso: BPv3-Bootloader-v4.4.hex
4 - Selecionar o programador em Programmer -> Select Programmer e selecionar o device em Configure -> Select Device
5 - ir a Programmer -> Program
6 - se não houver erros, desligar o bus pirate do pickit3 e da alimentação (verificar que o bus pirate está mesmo desligado)
7 - short entre PDC e PGD (basicamente, ligar o cabo azul ao verde)
8 - Ligar o bus pirate por usb
9 - tentar pingar o bootloader com: pirate-loader.exe –dev=COM3 –hello
10 - Se não houver erros até aqui, estamos prontos para colocar novamente um firmware, neste caso será o último, o 5.7
11 - Abrir o ds30 Loader GUI.exe (esta util bem como o pirate-loader encontram-se no pacote de update de firmware/bootloader que se pode descarregar do repositorio de code do bus pirate).
12 - Selecionar o BPv3-Firmware-v5.7.hex e pressionar “Download” (claro está que se quiserem uma versão custom da coisa, têm que sacar a source, compilar, etc.. basicamente seguir os passos descritos anteriormente neste post).
13 - Se não houver erros, desligar o bus pirate do usb
14 - retirar o short entre o PDC e PGD (melhor ainda -> desligar todos os cabos… já não vão ser necessários)
15 - Ligar o bus pirate por usb novamente e aceder à consola pela respectiva COMx

Deverão ter o seguinte aspecto:

E pronto…

Agora que já vos gastei 5 ou 10 minutos do vosso tempo, já posso ir jogar Starcraft II.

Agosto 13, 2010

Desenvolvimentos no SHA-3

Arquivado em: serious-business, useless — dcoder @ 00:06

Ora viva,

Como os leitores deste blog devem certamente lembrar-se, decorre neste momento uma competição para seleccionar uma função de hashing adequada para servir como um novo standard, denominado SHA-3.

As funções restantes neste momento são: BLAKE, Blue Midnight Wish, CubeHash, ECHO, Fugue, Grøstl, Hamsi, JH, Keccak, Luffa, Shabal, SHAvite-3, SIMD e Skein. No próximo dia 24, serão anunciados os 5 finalistas da competição.

Quais destas funções serão escolhidas é impossível de saber ao certo. Das funções listadas, não foram encontrados ataques que reduzissem dramaticamente a segurança de qualquer uma delas. Existem algumas decisões no design destas funções que podem afectar a segurança, no entanto.

A função CubeHash torna mais fácil obter preimages de 512 bits do que o esperado; ao invés de O(2^512) operações, são apenas necessárias O(2^384). A relevância deste problema é bastante discutível — mesmo com computadores quânticos e transformando todos os átomos em qubits, seria difícil encontrar 2^192 no universo inteiro. No entanto, este nível de segurança vai contra as regras da competição, que especificavam um nível de segurança mínimo de 2^512. Isto põe a passagem desta função para o próximo passo em risco.

Outro ponto a considerar é o desempenho das funções. O NIST especificou que qualquer função escolhida terá de ser mais ou igualmente rápida que o SHA-2. Isto deixa-nos com as seguintes funções: BLAKE, Blue Midnight Wish, Shabal, Skein, CubeHash, Keccak, SIMD, Luffa (parcialmente). Algumas destas (i.e., ECHO e SHAvite-3) são extremamente acelerada se existirem instruções específicas de AES no sistema (AES-NI).

Dito isto, é uma decisão difícil escolher as 5 funções finalistas. Um palpite pode ser: BLAKE, Shabal, Skein, Blue Midnight Wish, Keccak. Existe um problema com este palpite, dado que as primeiras 4 funções são todas bastante semelhantes e pode ser vantajoso ter mais variedade, mas vou ignorar esse pequeno detalhe.