@zk-kit/utils
Utility functions for zero-knowledge applications including field arithmetic, conversions, and helper functions.
Overview
This package provides essential utilities for working with zero-knowledge proofs:
- Field arithmetic: Operations in finite fields
- Conversions: Between different number formats
- Validators: Check values and formats
- Helpers: Common ZK operations
Installation
npm install @zk-kit/utils
Quick Start
Field Arithmetic
import { F1Field } from "@zk-kit/utils"
// Baby JubJub prime field
const BABYJUBJUB_PRIME = BigInt("21888242871839275222246405745257275088548364400416034343698204186575808495617")
const field = new F1Field(BABYJUBJUB_PRIME)
// Field operations
const a = BigInt(100)
const b = BigInt(200)
const sum = field.add(a, b)
const product = field.mul(a, b)
const inverse = field.inv(a)
const power = field.pow(a, BigInt(3))
console.log(sum) // 300n
console.log(product) // 20000n
Number Conversions
import {
bigintToUint8Array,
uint8ArrayToBigInt,
bigintToHex,
hexToBigint
} from "@zk-kit/utils"
// BigInt to Uint8Array
const num = BigInt(12345)
const bytes = bigintToUint8Array(num)
console.log(bytes) // Uint8Array
// Uint8Array to BigInt
const recovered = uint8ArrayToBigInt(bytes)
console.log(recovered) // 12345n
// BigInt to hex
const hex = bigintToHex(num)
console.log(hex) // "0x3039"
// Hex to BigInt
const fromHex = hexToBigint("0x3039")
console.log(fromHex) // 12345n
API Reference
F1Field Class
Finite field arithmetic operations.
Constructor
new F1Field(order: bigint): F1Field
Creates a finite field with the given order (prime).
Parameters:
order: The prime modulus of the field
Example:
import { F1Field } from "@zk-kit/utils"
const PRIME = BigInt("21888242871839275222246405745257275088548364400416034343698204186575808495617")
const field = new F1Field(PRIME)
Properties
order
field.order: bigint
Returns the order (prime) of the field.
zero
field.zero: bigint
Returns the additive identity (0).
one
field.one: bigint
Returns the multiplicative identity (1).
Methods
add
field.add(a: bigint, b: bigint): bigint
Adds two field elements.
Parameters:
a: First elementb: Second element
Returns:
bigint: (a + b) mod order
Example:
const sum = field.add(BigInt(5), BigInt(10))
console.log(sum) // 15n
sub
field.sub(a: bigint, b: bigint): bigint
Subtracts two field elements.
Returns:
bigint: (a - b) mod order
Example:
const diff = field.sub(BigInt(10), BigInt(5))
console.log(diff) // 5n
mul
field.mul(a: bigint, b: bigint): bigint
Multiplies two field elements.
Returns:
bigint: (a * b) mod order
Example:
const product = field.mul(BigInt(5), BigInt(10))
console.log(product) // 50n
div
field.div(a: bigint, b: bigint): bigint
Divides two field elements (a * b⁻¹).
Returns:
bigint: (a / b) mod order
Example:
const quotient = field.div(BigInt(10), BigInt(5))
console.log(quotient) // 2n
neg
field.neg(a: bigint): bigint
Negates a field element.
Returns:
bigint: -a mod order
Example:
const negated = field.neg(BigInt(5))
console.log(field.add(BigInt(5), negated)) // 0n
inv
field.inv(a: bigint): bigint
Computes the multiplicative inverse.
Returns:
bigint: a⁻¹ mod order
Example:
const a = BigInt(5)
const inverse = field.inv(a)
console.log(field.mul(a, inverse)) // 1n
pow
field.pow(base: bigint, exponent: bigint): bigint
Raises a field element to a power.
Returns:
bigint: base^exponent mod order
Example:
const result = field.pow(BigInt(2), BigInt(10))
console.log(result) // 1024n
sqrt
field.sqrt(a: bigint): bigint | null
Computes the square root if it exists.
Returns:
bigint | null: Square root or null if none exists
Example:
const a = BigInt(4)
const sqrt = field.sqrt(a)
console.log(sqrt) // 2n or field.sub(order, 2n)
isZero
field.isZero(a: bigint): boolean
Checks if a value is zero in the field.
Returns:
boolean:trueif a equals 0
Example:
console.log(field.isZero(BigInt(0))) // true
console.log(field.isZero(field.order)) // true (wraps to 0)
equals
field.equals(a: bigint, b: bigint): boolean
Checks if two field elements are equal.
Returns:
boolean:trueif a equals b (mod order)
Example:
const a = BigInt(5)
const b = field.add(BigInt(5), field.order)
console.log(field.equals(a, b)) // true (equivalent in field)
normalize
field.normalize(a: bigint): bigint
Normalizes a value to the range [0, order).
Returns:
bigint: a mod order
Example:
const normalized = field.normalize(BigInt(-5))
console.log(normalized) // order - 5n
Conversion Functions
bigintToUint8Array
bigintToUint8Array(
value: bigint,
length?: number
): Uint8Array
Converts a BigInt to a Uint8Array.
Parameters:
value: The BigInt to convertlength: Optional fixed length (pads with zeros)
Returns:
Uint8Array: Byte representation
Example:
import { bigintToUint8Array } from "@zk-kit/utils"
const bytes = bigintToUint8Array(BigInt(255))
console.log(bytes) // Uint8Array[255]
const fixed = bigintToUint8Array(BigInt(255), 32)
console.log(fixed.length) // 32
uint8ArrayToBigInt
uint8ArrayToBigInt(bytes: Uint8Array): bigint
Converts a Uint8Array to a BigInt.
Parameters:
bytes: The byte array to convert
Returns:
bigint: The resulting number
Example:
import { uint8ArrayToBigInt } from "@zk-kit/utils"
const bytes = new Uint8Array([0, 255])
const num = uint8ArrayToBigInt(bytes)
console.log(num) // 255n
bigintToHex
bigintToHex(value: bigint, length?: number): string
Converts a BigInt to a hexadecimal string.
Parameters:
value: The BigInt to convertlength: Optional fixed length (pads with zeros)
Returns:
string: Hex string with "0x" prefix
Example:
import { bigintToHex } from "@zk-kit/utils"
const hex = bigintToHex(BigInt(255))
console.log(hex) // "0xff"
const fixed = bigintToHex(BigInt(255), 8)
console.log(fixed) // "0x000000ff"
hexToBigint
hexToBigint(hex: string): bigint
Converts a hexadecimal string to a BigInt.
Parameters:
hex: Hex string (with or without "0x" prefix)
Returns:
bigint: The resulting number
Example:
import { hexToBigint } from "@zk-kit/utils"
const num = hexToBigint("0xff")
console.log(num) // 255n
const num2 = hexToBigint("ff")
console.log(num2) // 255n
bufferToBigInt
bufferToBigInt(buffer: Buffer): bigint
Converts a Buffer to a BigInt.
Parameters:
buffer: The buffer to convert
Returns:
bigint: The resulting number
Example:
import { bufferToBigInt } from "@zk-kit/utils"
const buffer = Buffer.from([0, 255])
const num = bufferToBigInt(buffer)
console.log(num) // 255n
bigintToBuffer
bigintToBuffer(value: bigint, length?: number): Buffer
Converts a BigInt to a Buffer.
Parameters:
value: The BigInt to convertlength: Optional fixed length
Returns:
Buffer: Buffer representation
Example:
import { bigintToBuffer } from "@zk-kit/utils"
const buffer = bigintToBuffer(BigInt(255))
console.log(buffer) // <Buffer ff>
Validation Functions
requireBigInt
requireBigInt(value: any, name?: string): bigint
Validates and returns a BigInt, throws on invalid input.
Parameters:
value: Value to validatename: Optional parameter name for error message
Returns:
bigint: The validated BigInt
Throws:
- TypeError if not a BigInt
Example:
import { requireBigInt } from "@zk-kit/utils"
const valid = requireBigInt(BigInt(123), "myValue")
console.log(valid) // 123n
// Throws: TypeError: myValue must be a BigInt
// requireBigInt("123", "myValue")
requireArray
requireArray(value: any, name?: string): any[]
Validates that a value is an array.
Parameters:
value: Value to validatename: Optional parameter name
Returns:
any[]: The validated array
Throws:
- TypeError if not an array
Example:
import { requireArray } from "@zk-kit/utils"
const valid = requireArray([1, 2, 3], "myArray")
console.log(valid) // [1, 2, 3]
// Throws: TypeError
// requireArray("not array", "myArray")
Advanced Usage
Custom Field Operations
import { F1Field } from "@zk-kit/utils"
// Create field for BN254 curve
const BN254_PRIME = BigInt("21888242871839275222246405745257275088548364400416034343698204186575808495617")
const field = new F1Field(BN254_PRIME)
function lagrangeInterpolation(
points: Array<[bigint, bigint]>
): bigint[] {
const n = points.length
const result: bigint[] = []
for (let i = 0; i < n; i++) {
let numerator = field.one
let denominator = field.one
for (let j = 0; j < n; j++) {
if (i !== j) {
numerator = field.mul(numerator, points[j][0])
denominator = field.mul(
denominator,
field.sub(points[j][0], points[i][0])
)
}
}
const coefficient = field.div(numerator, denominator)
result.push(field.mul(coefficient, points[i][1]))
}
return result
}
Batch Conversions
import { bigintToUint8Array, uint8ArrayToBigInt } from "@zk-kit/utils"
function serializeArray(values: bigint[]): Uint8Array {
// Convert array of BigInts to single Uint8Array
const chunks = values.map(v => bigintToUint8Array(v, 32))
const result = new Uint8Array(chunks.length * 32)
chunks.forEach((chunk, i) => {
result.set(chunk, i * 32)
})
return result
}
function deserializeArray(data: Uint8Array): bigint[] {
// Convert Uint8Array back to array of BigInts
const result: bigint[] = []
for (let i = 0; i < data.length; i += 32) {
const chunk = data.slice(i, i + 32)
result.push(uint8ArrayToBigInt(chunk))
}
return result
}
Constants
Common Field Primes
import { F1Field } from "@zk-kit/utils"
// Baby JubJub / BN254
export const BN254_PRIME = BigInt("21888242871839275222246405745257275088548364400416034343698204186575808495617")
// Subgroup order
export const BABYJUBJUB_ORDER = BigInt("2736030358979909402780800718157159386076813972158567259200215660948447373041")
const field = new F1Field(BN254_PRIME)
Performance Tips
- Reuse field instances: Create once, use many times
- Batch operations: Group multiple operations together
- Pre-compute constants: Calculate once, store result
- Use native BigInt: Faster than string conversion
Dependencies
None - this is a standalone package.
TypeScript Support
Full TypeScript support with type definitions included.
import type { F1Field } from "@zk-kit/utils"
Related Documentation
- Baby JubJub - Uses field arithmetic
- EdDSA-Poseidon - Uses conversions
- Core Concepts - ZK fundamentals
Common Use Cases
- ✅ Field arithmetic in finite fields
- ✅ Number format conversions
- ✅ Data serialization/deserialization
- ✅ Cryptographic operations
- ✅ Circuit input preparation
- ✅ Value validation
Source
- GitHub: zk-kit/packages/utils
- NPM: @zk-kit/utils
- License: MIT