Hashing Poseidon
Poseidon es una función hash amigable con la aritmética diseñada para circuitos de conocimiento cero. La implementación de Achronyme usa parámetros BN254 compatibles con circomlibjs, por lo que los hashes calculados en Achronyme coinciden con los del ecosistema iden3/circom.
Hash Básico
Sección titulada «Hash Básico»Calcula un hash Poseidon 2-a-1:
let h: Field = poseidon(1, 2)print(h)// 7853200120776062878684798364095072458815029376092732009249414926327459813530Ambos argumentos pueden ser enteros o elementos de campo. El resultado siempre es un elemento de campo.
Vectores de Prueba Conocidos
Sección titulada «Vectores de Prueba Conocidos»Estos valores coinciden con la salida de circomlibjs:
// poseidon(0, 0)let h0 = poseidon(0, 0)print(h0)// 14744269619966411208579211824598458697587494354926760081771325075741142829156
// poseidon(1, 2)let h1 = poseidon(1, 2)print(h1)// 7853200120776062878684798364095072458815029376092732009249414926327459813530Puedes usar estos vectores para verificar compatibilidad con otras implementaciones de Poseidon.
Cadenas Hash
Sección titulada «Cadenas Hash»Encadena múltiples valores alimentando el hash anterior como entrada:
let h01 = poseidon(1, 2)let h012 = poseidon(h01, 3)let h0123 = poseidon(h012, 4)print(h0123)O usa poseidon_many() para el mismo resultado con menos código:
let h = poseidon_many(1, 2, 3, 4)print(h)// Igual que poseidon(poseidon(poseidon(1, 2), 3), 4)poseidon_many requiere al menos 2 argumentos. Pliega a la izquierda el hash: los dos primeros valores se hashean juntos, luego cada valor subsiguiente se hashea con el resultado acumulado.
El Orden de las Entradas Importa
Sección titulada «El Orden de las Entradas Importa»Poseidon no es conmutativo — intercambiar las entradas produce un hash diferente:
let h1 = poseidon(1, 2)let h2 = poseidon(2, 1)assert(h1 != h2) // valores diferentesEsta propiedad es esencial para árboles Merkle, donde los hijos izquierdo y derecho deben distinguirse.
Uso con Elementos de Campo
Sección titulada «Uso con Elementos de Campo»Para valores mayores que i60 o para aritmética exacta del campo BN254, usa literales de campo 0p:
let a = 0p21888242871839275222246405745257275088548364400416034343698204186575808495616let b = 0p1let h = poseidon(a, b)print(h)En Modo Circuito
Sección titulada «En Modo Circuito»Poseidon funciona tanto en modo VM como en modo circuito. En circuitos, cada hash emite 361 restricciones R1CS (360 rondas de permutación + 1 inicialización de capacidad):
circuit poseidon_check(expected: Public, a: Witness, b: Witness) { let h = poseidon(a, b) assert_eq(h, expected)}Compilar y ejecutar:
ach circuit hash.ach --inputs "expected=7853200120776062878684798364095072458815029376092732009249414926327459813530,a=1,b=2"Costos de Restricciones
Sección titulada «Costos de Restricciones»| Expresión | Restricciones |
|---|---|
poseidon(a, b) | 361 |
poseidon_many(a, b, c) | 722 (2 × 361) |
poseidon_many(a, b, c, d) | 1,083 (3 × 361) |
Construir Raíces Merkle
Sección titulada «Construir Raíces Merkle»Calcula una raíz Merkle hasheando hojas por pares, luego hasheando los resultados:
// Árbol de 4 hojaslet leaf0 = 0p100let leaf1 = 0p200let leaf2 = 0p300let leaf3 = 0p400
// Nivel 0: hashear pareslet n0 = poseidon(leaf0, leaf1)let n1 = poseidon(leaf2, leaf3)
// Nivel 1: raízlet root = poseidon(n0, n1)print(root)Para árboles más grandes, usa bucles:
// Árbol de 8 hojaslet leaves = [ 0p100, 0p200, 0p300, 0p400, 0p500, 0p600, 0p700, 0p800]
// Nivel 0let l0_0 = poseidon(leaves[0], leaves[1])let l0_1 = poseidon(leaves[2], leaves[3])let l0_2 = poseidon(leaves[4], leaves[5])let l0_3 = poseidon(leaves[6], leaves[7])
// Nivel 1let l1_0 = poseidon(l0_0, l0_1)let l1_1 = poseidon(l0_2, l0_3)
// Raízlet root = poseidon(l1_0, l1_1)print(root)En Bloques Prove
Sección titulada «En Bloques Prove»Poseidon funciona dentro de prove {} para generación de pruebas en línea:
let a: Field = 0p1let b: Field = 0p2let h: Field = 0p7853200120776062878684798364095072458815029376092732009249414926327459813530
let p = prove(h: Public) { assert_eq(poseidon(a, b), h)}
print(verify_proof(p)) // trueEl probador demuestra conocimiento de a y b sin revelarlos. El verificador solo ve h.
Compatibilidad con circomlibjs
Sección titulada «Compatibilidad con circomlibjs»Achronyme usa las mismas constantes de Poseidon que circomlibjs v0.1.7:
- Curva: campo escalar BN254
- Ancho de estado: t = 3
- Rondas completas: R_f = 8
- Rondas parciales: R_p = 57
- S-box: x^5
Los hashes calculados con poseidon() en Achronyme producen salidas idénticas a circomlibjs.poseidon([a, b]). Esto asegura interoperabilidad con circuitos circom, pruebas snarkjs y verificadores Poseidon on-chain.