Optimizar operaciones de listas en Python

Tenemos una lista (Lista A) que contiene 2 millones de ID de los clientes que reciben un determinado servicio, por otro lado tenemos una lista (Lista B) que contiene 850,000 ID de clientes que han realizado el pago de su servicio del mes de Abril. Se necesita saber cuales son los ID de clientes que aún no han pagado su servicio.

Solución

La solución parece resultar simple, debemos de saber que IDs de la Lista A no están en la Lista B. Si bien el algoritmo parece tener todo el sentido del mundo, es importante emplear las funciones y herramientas correctas en la codificación.

Vamos a resolver este problema con 3 alternativas distintas (métodos getDifferent1, getDifferent2 y getDifferent3). El contenido de las listas se generarán de manera aleatoria y de manera secuencial. Finalmente el script mostrará en pantalla los tiempos de ejecución de las 3 alternativas.

Ejecución

Puedes descargar el código del siguiente repositorio.

La cantidad de elementos que deben tener las listas A y B son enviadas como argumentos en la invocación del script. Puedes intentar cambiar estos valores si lo deseas. El tercer argumento es para indicarle al programa que genere los elementos de ambas listas de forma aleatoria o secuencial.

Resultado

El resultado obtenido de la ejecución del script es el siguiente:

Ejercicio 1: No generando aleatoriamente los elementos de las listas A y B.

 

Ejercicio 2: Generando aleatoriamente los elementos de las listas A y B.

Generando password seguros Bcrypt/Blowfish en GO



Los históricamente conocidos algoritmos de hash MD5, SHA1 dejan de ser una alternativa segura a la hora de almacenar y proteger contraseñas, debido a que sus algoritmos matemáticos convierten una cantidad de datos a un valor string de longitud fija, dejando la posibilidad de originarse una colisión ó 2 hash iguales para distintos datos.

Por qué usar Bcrypt?

Es un hash pensado para ser utilizado para guardar contraseñas. Utiliza el algoritmo Blowfish de una sola via.

Razones el por que usar Bcrypt:

1. Es lento,  y lento es bueno porque  fustra los ataques de fuerza bruta. (pueden leer de aquí.)

2. La salida de bcrypt es un alfabeto base-64.

En esta entrada,  les comparto como generar un hash Bcrypt/Blowfish con el lenguaje de programación de Google, el ya conocido Go (Golang).

Para ello, primero necesitamos instalar Golang:

$ sudo yum install golang

Seteamos la variable de entorno:

$ mkdir $HOME/go
$ export GOPATH=$HOME/go
$ export PATH=$PATH:$GOPATH/bin

Instalamos mercurial, para poder descargar el package bcrypt del repositorio de Google.

$ sudo yum install mercurial

Si se presenta un problema para instalar Mercurial, puedes hacer lo siguiente:

$ sudo yum install python-setuptools python-devel gcc -y
$ sudo easy_install Mercurial

Luego descargamos el package del repositorio de Google para generar bcrypt.

$ go get code.google.com/p/go.crypto/bcrypt

Luego creamos nuestro script en go (bcrypt_generate.go)

package main
import (
	"flag"
	"fmt"
	"os"
	"code.google.com/p/go.crypto/bcrypt"
)
 
func main() {
	password := flag.String("password", "", "the password to hash or validate")
	hash := flag.String("hash", "", "the hash to validate the password against")
	cost := flag.Int("cost", 13, "the cost of the bcrypt function to execute")
 
	flag.Parse()
 
	if *hash != "" {
		// do validation
		err := bcrypt.CompareHashAndPassword([]byte(*hash), []byte(*password))
		if err != nil {
			fmt.Print("Error: Password and hash do not match.")
			os.Exit(1)
		}
		fmt.Print("OK")
		os.Exit(0)
	} else {
		// do encryption
		generated_hash, err := bcrypt.GenerateFromPassword([]byte(*password), *cost)
		if err != nil {
			fmt.Print("Error: Couldn't generate hash.")
			os.Exit(1)
		}
 
		fmt.Printf("%s\n", generated_hash)
		os.Exit(0)
	}
}

Compilamos nuestro script.

$ go build clicrypt.go

Probamos nuestro script, intentando hashear un valor, atraves del parametro password.

$ ./bcrypt_generate -password="@gchacaltanab"

Me retorna el siguiente hash:

$ $2a$13$oWvgAl9CYjiQE8rjzX6h4.Lf/NS2pIAb9KnfG2s9vszFy6dXmP6Ry

Y finalmente para comparar hash, se utiliza de la siguiente forma.

$./bcrypt_generate -password="@gchacaltanab" -hash='$2a$13$oWvgAl9CYjiQE8rjzX6h4.Lf/NS2pIAb9KnfG2s9vszFy6dXmP6Ry'

Fuente imagen: eduonix.com