Ir al contenido

Funciones Integradas

Los circuitos proporcionan funciones integradas para aserciones, hashing, selección condicional y verificación de rango. Cada función integrada se compila a un número fijo de restricciones.

Función IntegradaRestricciones (R1CS)Propósito
assert_eq(a, b)1Forzar igualdad
assert(expr)2Forzar que expresión booleana sea verdadera
poseidon(a, b)361Hash Poseidon 2-a-1
poseidon_many(a, b, c, ...)(N−1) × 361Hash Poseidon con plegado izquierdo
mux(cond, a, b)2Selección condicional
range_check(x, bits)bits + 1El valor cabe en N bits
merkle_verify(root, leaf, path, indices)profundidad × ~363Prueba de membresía Merkle
len(arr)0Longitud de array en tiempo de compilación

Fuerza que dos expresiones sean iguales. Cuesta 1 restricción.

circuit multiply(out: Public, a: Witness, b: Witness) {
let product = a * b
assert_eq(product, out)
}

Esta es la función integrada más común — úsala para vincular valores calculados con salidas públicas.

Fuerza que una expresión booleana sea verdadera. Cuesta 2 restricciones (una para verificación booleana, una para forzar que el valor sea igual a 1).

circuit ordering(x: Witness, y: Witness) {
assert(x < y)
}

A diferencia de assert_eq, funciona con cualquier expresión que evalúe a 0 o 1.

Calcula un hash Poseidon 2-a-1. Cuesta 361 restricciones (360 para las rondas de permutación + 1 para el cable de capacidad). La salida es compatible con circomlibjs.

circuit hash_check(expected: Public, a: Witness, b: Witness) {
let h = poseidon(a, b)
assert_eq(h, expected)
}

Hashea un número arbitrario de valores mediante plegado izquierdo de poseidon. Tres argumentos cuestan 2 × 361 = 722 restricciones, cuatro argumentos cuestan 3 × 361 = 1083, y así sucesivamente.

circuit hash_many(expected: Public, a: Witness, b: Witness, c: Witness) {
// poseidon_many(a, b, c) == poseidon(poseidon(a, b), c)
let h = poseidon_many(a, b, c)
assert_eq(h, expected)
}

Selección condicional: devuelve a cuando cond es 1, b cuando cond es 0. Cuesta 2 restricciones (una verificación booleana para cond, una restricción de selección).

circuit select(out: Public, cond: Witness, a: Witness, b: Witness) {
let selected = mux(cond, a, b)
assert_eq(selected, out)
}

Tanto a como b siempre se evalúan — no hay comportamiento de cortocircuito.

Demuestra que un valor cabe dentro de un número dado de bits. En R1CS, cuesta bits + 1 restricciones (descomposición booleana). En Plonkish, cuesta 1 lookup.

circuit range_demo(x: Witness, y: Witness) {
// x cabe en 8 bits (0..255)
range_check(x, 8)
// y cabe en 16 bits (0..65535)
range_check(y, 16)
}

Verifica una prueba de membresía Merkle. Toma una raíz, una hoja, un array de hashes hermanos (la ruta) y un array de índices de dirección (0 = hijo izquierdo, 1 = hijo derecho). La prueba se desenrolla a nivel de IR — cada nivel cuesta aproximadamente 363 restricciones (un hash Poseidon + un mux).

circuit merkle_check(root: Public, leaf: Witness, path: Witness[1], indices: Witness[1]) {
merkle_verify(root, leaf, path, indices)
}

Los arrays path e indices deben tener la misma longitud, que determina la profundidad del árbol.

Devuelve la longitud en tiempo de compilación de un array. Cuesta 0 restricciones — el valor se resuelve durante la compilación.

circuit len_demo(vals: Witness[3]) {
let n = len(vals)
assert_eq(n, 3)
}