Aritmética BigInt
BigInt proporciona aritmética de enteros sin signo de 256 y 512 bits en la VM. A diferencia de los elementos de campo (que usan aritmética modular sobre BN254), los BigInts usan aritmética no modular con errores explícitos de desbordamiento. Esto los hace ideales para operaciones donde necesitas semántica de enteros exacta a anchos criptográficos.
Crear BigInts
Sección titulada «Crear BigInts»Hay tres formas de crear valores BigInt:
Sintaxis literal
Sección titulada «Sintaxis literal»Usa el prefijo 0i seguido del ancho (256 o 512) y la base (x para hex, d para decimal, b para binario):
let a = 0i256xFF // 256 bits, hexlet b = 0i256d255 // 256 bits, decimallet c = 0i256b11111111 // 256 bits, binariolet d = 0i512x1234ABCD // 512 bits, hexLas tres representaciones de 255 son iguales:
assert(0i256xFF == 0i256d255)assert(0i256d255 == 0i256b11111111)Funciones constructoras
Sección titulada «Funciones constructoras»bigint256() y bigint512() construyen desde enteros o cadenas:
let a = bigint256(42) // desde enterolet b = bigint256("0xFF") // desde cadena hexadecimallet c = bigint256("12345") // desde cadena decimallet d = bigint512(0) // 512 bits ceroVerificación de tipo
Sección titulada «Verificación de tipo»Usa typeof() para inspeccionar valores BigInt:
let x = 0i256d42print(typeof(x)) // "BigInt256"
let y = 0i512d42print(typeof(y)) // "BigInt512"Aritmética
Sección titulada «Aritmética»Los operadores estándar funcionan entre BigInts del mismo ancho:
let a = 0i256d100let b = 0i256d200
print(a + b) // BigInt256(0x12c) (300)print(b - a) // BigInt256(0x64) (100)print(a * b) // BigInt256(0x4e20) (20000)print(b / a) // BigInt256(0x2) (2)print(b % a) // BigInt256(0x0) (0)La exponenciación usa ^ con un exponente entero:
let base = 0i256d2let result = base ^ 128print(result) // 2^128 como entero de 256 bitsDesbordamiento y Subdesbordamiento
Sección titulada «Desbordamiento y Subdesbordamiento»A diferencia de los elementos de campo, la aritmética BigInt no se envuelve. Las operaciones que exceden el rango producen errores en tiempo de ejecución:
// Esto generará error: desbordamiento BigIntlet max = bit_not(bigint256(0)) // todos los bits activados = 2^256 - 1let boom = max + bigint256(1) // ERROR: BigIntOverflow// Esto generará error: subdesbordamiento BigIntlet zero = bigint256(0)let boom = zero - bigint256(1) // ERROR: BigIntUnderflowEsto hace los errores visibles inmediatamente en lugar de producir resultados silenciosamente incorrectos.
Seguridad de Tipos
Sección titulada «Seguridad de Tipos»BigInt aplica límites estrictos de tipo. No puedes mezclar BigInt con Int, Field, ni con un BigInt de diferente ancho:
// Todos estos son errores en tiempo de ejecución:// bigint256(1) + 1 -- BigInt + Int// bigint256(1) + 0p1 -- BigInt + Field// bigint256(1) + bigint512(1) -- incompatibilidad de anchoEsto previene aritmética accidental entre tipos incompatibles.
Operaciones a Nivel de Bits
Sección titulada «Operaciones a Nivel de Bits»BigInt soporta manipulación completa a nivel de bits a través de funciones nativas:
let a = 0i256xFFlet b = 0i256x0F
print(bit_and(a, b)) // 0x0Fprint(bit_or(a, b)) // 0xFFprint(bit_xor(a, b)) // 0xF0print(bit_not(b)) // todos los bits invertidosDesplazamientos
Sección titulada «Desplazamientos»let one = bigint256(1)
// Desplazar a la izquierda: multiplicar por potencias de 2let shifted = bit_shl(one, 128) // 2^128
// Desplazar a la derecha: dividir por potencias de 2let back = bit_shr(shifted, 128) // de vuelta a 1assert(back == one)Los desplazamientos a la izquierda generan error si algún bit activado es desplazado fuera (protección contra desbordamiento). Los desplazamientos a la derecha descartan los bits desplazados.
Descomposición de Bits
Sección titulada «Descomposición de Bits»Convierte entre BigInts y bits individuales con to_bits() y from_bits():
let val = bigint256(42)let bits = to_bits(val)
// bits es una lista de 256 enteros (0 o 1), LSB primeroprint(len(bits)) // 256print(bits[0]) // 0 (bit menos significativo)print(bits[1]) // 1print(bits[2]) // 0print(bits[3]) // 1print(bits[4]) // 0print(bits[5]) // 1// 42 = 0b101010, LSB primero = [0, 1, 0, 1, 0, 1, 0, 0, ...]
// Reconstruir desde bitslet reconstructed = from_bits(bits, 256)assert(reconstructed == val)El segundo argumento de from_bits() es el ancho objetivo (256 o 512).
Ejemplo: Conteo de Bits
Sección titulada «Ejemplo: Conteo de Bits»Contar el número de bits activados en un BigInt:
fn popcount(x) { let bits = to_bits(x) mut count = 0 for b in bits { count = count + b } return count}
assert(popcount(bigint256(0)) == 0)assert(popcount(bigint256(1)) == 1)assert(popcount(bigint256(255)) == 8)assert(popcount(bigint256("0xFFFF")) == 16)
print("popcount(0xFF) =", popcount(bigint256(255))) // 8Ejemplo: Intercambio XOR
Sección titulada «Ejemplo: Intercambio XOR»Intercambiar dos valores usando XOR sin variable temporal:
mut a = 0i256d42mut b = 0i256d99
a = bit_xor(a, b)b = bit_xor(b, a)a = bit_xor(a, b)
assert(a == 0i256d99)assert(b == 0i256d42)print("Después del intercambio XOR: a =", a, "b =", b)Ejemplo: Verificación de Potencia de Dos
Sección titulada «Ejemplo: Verificación de Potencia de Dos»Verificar si un BigInt es potencia de dos usando el truco de bits n & (n - 1) == 0:
fn is_power_of_two(n) { if n == bigint256(0) { return false } let prev = n - bigint256(1) return bit_and(n, prev) == bigint256(0)}
assert(is_power_of_two(bigint256(1)) == true)assert(is_power_of_two(bigint256(256)) == true)assert(is_power_of_two(bit_shl(bigint256(1), 128)) == true)assert(is_power_of_two(bigint256(3)) == false)assert(is_power_of_two(bigint256(100)) == false)
print("2^128 es potencia de 2:", is_power_of_two(bit_shl(bigint256(1), 128)))BigInt vs Field
Sección titulada «BigInt vs Field»| BigInt | Field | |
|---|---|---|
| Aritmética | No modular (errores de desbordamiento) | Modular (se envuelve en primo BN254) |
| Anchos | 256 bits, 512 bits | 254 bits (campo escalar BN254) |
| Soporte de circuitos | Solo VM | VM y circuitos |
| Caso de uso | Aritmética entera exacta a anchos criptográficos | Valores de circuito ZK, hashing Poseidon |
| División | División entera (trunca) | Inverso modular |
| Negación | Error (sin signo) | Inverso aditivo en campo |
Elige BigInt cuando necesites semántica de enteros exacta. Elige Field cuando necesites aritmética modular o compatibilidad con circuitos.