Skip to main content

ChipGadget

Trait ChipGadget 

Source
pub trait ChipGadget: Hint {
    // Required method
    fn build(
        &self,
        builder: &CircuitBuilder,
        dimensions: &[usize],
        inputs: &[Wire],
    ) -> Vec<Wire>;
}
Expand description

A gadget the builder emits either as inline gates or as a call to a chip.

The gadget is written once, in build, and where it lands is the building circuit’s to decide: CircuitBuilder::build_gadget emits the gates unless CircuitBuilder::register_chip has made the gadget a chip, in which case it emits a hint and a call constraining it.

The Hint half is what the chip path needs of a gadget beyond its gates. Its NAME and dimensions name which gadget a registered chip serves; shape gives the arity of the gates and of the chip’s interface alike; and execute computes the outputs a call passes alongside its inputs.

So a Hint::execute and a build of the same gadget must agree on every input the circuit can reach them with. Where they disagree, the chip instance recomputes a word the call did not name, and only WitnessM4::verify reports it.

use binius_core::word::Word;
use binius_frontend::{ChipGadget, CircuitBuilder, Hint, Wire};

/// The bitwise conjunction of two words.
struct And;

impl Hint for And {
    const NAME: &'static str = "doc.and";

    fn shape(&self, _dimensions: &[usize]) -> (usize, usize) {
        (2, 1)
    }

    fn execute(&self, _dimensions: &[usize], inputs: &[Word], outputs: &mut [Word]) {
        outputs[0] = Word(inputs[0].as_u64() & inputs[1].as_u64());
    }
}

impl ChipGadget for And {
    fn build(&self, builder: &CircuitBuilder, _dims: &[usize], inputs: &[Wire]) -> Vec<Wire> {
        vec![builder.band(inputs[0], inputs[1])]
    }
}

// Without a chip the gadget is its gates, and the circuit builds as any other.
let builder = CircuitBuilder::new();
let (a, b) = (builder.add_inout(), builder.add_inout());
builder.build_gadget(And, &[], &[a, b]);
builder.build();

// Registering the gadget is the whole of the opt-in: the same call is now a chip call.
let builder = CircuitBuilder::new();
builder.register_chip(And, &[]);
let (a, b) = (builder.add_inout(), builder.add_inout());
builder.build_gadget(And, &[], &[a, b]);
builder.build_m4().validate().unwrap();

Required Methods§

Source

fn build( &self, builder: &CircuitBuilder, dimensions: &[usize], inputs: &[Wire], ) -> Vec<Wire>

Emits the gadget’s gates, returning the outputs its shape declares.

Each returned wire must be gate-created: a chip promotes them with CircuitBuilder::mark_inout, which takes no other kind. Returning an input or a constant unchanged is what that rules out.

Dyn Compatibility§

This trait is not dyn compatible.

In older versions of Rust, dyn compatibility was called "object safety".

Implementors§