Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/noir-lang/noir/llms.txt

Use this file to discover all available pages before exploring further.

Black box functions are operations in Noir that are delegated to the proving backend rather than compiled into plain arithmetic constraints. The backend may implement them using optimised native gadgets, which can be far cheaper than an equivalent hand-written Noir circuit. If a backend does not have a native implementation, it must supply a fallback. The ACVM specification defines the exact interface that backends must support. You can browse the canonical list in the ACIR source.

Why black box functions exist

ZK-SNARK backends represent programs as arithmetic circuits over a finite field. Some computations — such as SHA-256 — involve operations (bit rotations, XOR, modular arithmetic over a different field) that are expensive when expressed as field arithmetic. A backend with a purpose-built gadget for SHA-256 can express the same computation in far fewer constraints. Black box functions give Noir a way to call these gadgets without hard-coding knowledge of any particular backend. The tradeoff is that if a backend does not implement a specific black box function, it must fall back to a generic (and possibly slow) implementation.

Complete function list

Encrypts a byte array with AES-128 in CBC mode. PKCS#7 padding is applied automatically.Stdlib entry point: std::aes128::aes128_encrypt
pub fn aes128_encrypt<let N: u32>(
    input: [u8; N],
    iv: [u8; 16],
    key: [u8; 16],
) -> [u8; N + 16 - N % 16]
See Cryptographic primitives — AES128 for a usage example.
A single SHA-256 compression round. Not a full SHA-256 digest — use the sha256 library for a complete implementation.Stdlib entry point: std::hash::sha256_compression
pub fn sha256_compression(input: [u32; 16], state: [u32; 8]) -> [u32; 8]
Hashes an arbitrary byte array with Blake2s, returning a 32-byte digest.Stdlib entry point: std::hash::blake2s
pub fn blake2s<let N: u32>(input: [u8; N]) -> [u8; 32]
Hashes an arbitrary byte array with Blake3, returning a 32-byte digest. Input is limited to 1024 bytes under Barretenberg.Stdlib entry point: std::hash::blake3
pub fn blake3<let N: u32>(input: [u8; N]) -> [u8; 32]
Computes a Pedersen hash (returning a Field) or Pedersen commitment (returning an EmbeddedCurvePoint) over an array of field elements.Stdlib entry points: std::hash::pedersen_hash, std::hash::pedersen_commitment
pub fn pedersen_hash<let N: u32>(input: [Field; N]) -> Field
pub fn pedersen_commitment<let N: u32>(input: [Field; N]) -> EmbeddedCurvePoint
Verifies an ECDSA signature over secp256k1 or secp256r1. Both functions share the same signature shape.Stdlib entry points: std::ecdsa_secp256k1::verify_signature, std::ecdsa_secp256r1::verify_signature
pub fn verify_signature(
    public_key_x: [u8; 32],
    public_key_y: [u8; 32],
    signature: [u8; 64],
    message_hash: [u8; 32],
) -> bool
Multi-scalar multiplication and point addition on the embedded curve (Grumpkin for BN254 / Barretenberg).Stdlib entry points: std::embedded_curve_ops::multi_scalar_mul, std::embedded_curve_ops::embedded_curve_add, std::embedded_curve_ops::fixed_base_scalar_mul
pub fn multi_scalar_mul<let N: u32>(
    points: [EmbeddedCurvePoint; N],
    scalars: [EmbeddedCurveScalar; N],
) -> EmbeddedCurvePoint

pub fn embedded_curve_add(
    point1: EmbeddedCurvePoint,
    point2: EmbeddedCurvePoint,
) -> EmbeddedCurvePoint
Constrains the bitwise AND of two integers. Exposed through the & operator in Noir source rather than as a direct function call.
let result = a & b; // invokes the AND black box function
Constrains the bitwise XOR of two integers. Exposed through the ^ operator.
let result = a ^ b; // invokes the XOR black box function
Constrains that a value fits within a given bit width. Exposed through Noir’s range constraint syntax.
let x: u8 = value as u8; // range-checks that value fits in 8 bits
You can also call std::as_witness and use explicit range assertions in some contexts.
Applies a single Keccak-f[1600] permutation to a 25-word (64-bit) state. Use this primitive to build Keccak-256 or SHA-3.Stdlib entry point: std::hash::keccakf1600
pub fn keccakf1600(input: [u64; 25]) -> [u64; 25]
Verifies a proof of a Noir program inside another Noir program. This is how recursive aggregation is performed.Stdlib entry point: std::verify_proof (via #[foreign(recursive_aggregation)])
#[foreign(recursive_aggregation)]
pub fn verify_proof(
    verification_key: [Field],
    proof: [Field],
    public_inputs: [Field],
    key_hash: Field,
) {}
See Recursion for a full walkthrough.

Language-level black box operations

Three black box functions are not callable as library functions — they are instead invoked by Noir language operators:
Language constructBlack box function
a & b (bitwise AND)AND
a ^ b (bitwise XOR)XOR
Integer casts / range assertionsRANGE

Fallback implementations

Backends are required to support all black box functions defined in the ACVM spec. If a backend does not have a native gadget for a particular function, it must supply a fallback implementation expressed in terms of basic constraints. Fallback implementations are correct but may produce significantly larger circuits. When targeting Barretenberg, all functions listed above have native gadget support and will not fall back.
If you are building a new backend and need to understand the expected semantics for each black box function, refer to the ACIR black box function definitions and the blackbox_solver crate.

Build docs developers (and LLMs) love