pub trait Relation: Clone {
type Instance: Clone;
type Witness: Clone;
type Error: From<Error>;
// Required methods
fn format_instance(
instance: &Self::Instance,
) -> Result<Vec<Fq>, Self::Error>;
fn circuit(
&self,
std_lib: &ZkStdLib,
layouter: &mut impl Layouter<Fq>,
instance: Value<Self::Instance>,
witness: Value<Self::Witness>,
) -> Result<(), Self::Error>;
fn write_relation<W: Write>(&self, writer: &mut W) -> Result<()>;
fn read_relation<R: Read>(reader: &mut R) -> Result<Self>;
// Provided methods
fn format_committed_instances(_witness: &Self::Witness) -> Vec<Fq> { ... }
fn used_chips(&self) -> ZkStdLibArch { ... }
}Expand description
Helper trait, used to abstract the circuit developer from Halo2’s boilerplate.
Relation has a default implementation for loading only the tables
needed for the requested chips. The developer needs to implement the
function Relation::circuit, which essentially contains the
statement of the proof we are creating.
§Important note
The API provided here guarantees that the number of public inputs used during verification matches the number of public inputs (as raw scalars) declared in Relation::circuit through the PublicInputInstructions interface. Proof verification will fail if this requirement is not met.
§Example
type F = midnight_curves::Fq;
#[derive(Clone, Default)]
struct ShaPreImageCircuit;
impl Relation for ShaPreImageCircuit {
// When defining a circuit, one must clearly state the instance and the witness
// of the underlying NP-relation.
type Instance = [u8; 32];
type Witness = [u8; 24]; // 192 = 24 * 8
type Error = Error;
// We must specify how the instance is converted into raw field elements to
// be process by the prover/verifier. The order here must be consistent with
// the order in which public inputs are constrained/assigned in [circuit].
fn format_instance(instance: &Self::Instance) -> Result<Vec<F>, Error> {
Ok(instance.iter().flat_map(AssignedByte::<F>::as_public_input).collect())
}
// Define the logic of the NP-relation being proved.
fn circuit(
&self,
std_lib: &ZkStdLib,
layouter: &mut impl Layouter<F>,
_instance: Value<Self::Instance>,
witness: Value<Self::Witness>,
) -> Result<(), Error> {
let assigned_input = std_lib.assign_many(layouter, &witness.transpose_array())?;
let output = std_lib.sha2_256(layouter, &assigned_input)?;
output.iter().try_for_each(|b| std_lib.constrain_as_public_input(layouter, b))
}
fn used_chips(&self) -> ZkStdLibArch {
ZkStdLibArch {
sha2_256: true,
..ZkStdLibArch::default()
}
}
fn write_relation<W: std::io::Write>(&self, _writer: &mut W) -> std::io::Result<()> {
Ok(())
}
fn read_relation<R: std::io::Read>(_reader: &mut R) -> std::io::Result<Self> {
Ok(ShaPreImageCircuit)
}
}
const K: u32 = 13;
let mut srs = filecoin_srs(K);
let relation = ShaPreImageCircuit;
let vk = midnight_zk_stdlib::setup_vk(&srs, &relation);
let pk = midnight_zk_stdlib::setup_pk(&relation, &vk);
let mut rng = ChaCha8Rng::from_entropy();
let witness: [u8; 24] = core::array::from_fn(|_| rng.gen());
let instance = sha2::Sha256::digest(witness).into();
let proof = midnight_zk_stdlib::prove::<ShaPreImageCircuit, blake2b_simd::State>(
&srs, &pk, &relation, &instance, witness, OsRng,
)
.expect("Proof generation should not fail");
assert!(
midnight_zk_stdlib::verify::<ShaPreImageCircuit, blake2b_simd::State>(
&srs.verifier_params(),
&vk,
&instance,
None,
&proof
)
.is_ok()
)Required Associated Types§
Sourcetype Error: From<Error>
type Error: From<Error>
The error type returned by Self::circuit and Self::format_instance.
Required Methods§
Sourcefn format_instance(instance: &Self::Instance) -> Result<Vec<Fq>, Self::Error>
fn format_instance(instance: &Self::Instance) -> Result<Vec<Fq>, Self::Error>
Produces a vector of field elements in PLONK format representing the given Self::Instance.
Sourcefn circuit(
&self,
std_lib: &ZkStdLib,
layouter: &mut impl Layouter<Fq>,
instance: Value<Self::Instance>,
witness: Value<Self::Witness>,
) -> Result<(), Self::Error>
fn circuit( &self, std_lib: &ZkStdLib, layouter: &mut impl Layouter<Fq>, instance: Value<Self::Instance>, witness: Value<Self::Witness>, ) -> Result<(), Self::Error>
Defines the circuit’s logic.
Sourcefn write_relation<W: Write>(&self, writer: &mut W) -> Result<()>
fn write_relation<W: Write>(&self, writer: &mut W) -> Result<()>
Writes a relation to a buffer.
Sourcefn read_relation<R: Read>(reader: &mut R) -> Result<Self>
fn read_relation<R: Read>(reader: &mut R) -> Result<Self>
Reads a relation from a buffer.
Provided Methods§
Sourcefn format_committed_instances(_witness: &Self::Witness) -> Vec<Fq>
fn format_committed_instances(_witness: &Self::Witness) -> Vec<Fq>
Produces a vector of field elements in PLONK format representing the data inside the committed instance.
Sourcefn used_chips(&self) -> ZkStdLibArch
fn used_chips(&self) -> ZkStdLibArch
Specifies what chips are enabled in the standard library. A chip needs to be enabled if it is used in Self::circuit, but it can also be enabled even if it is not used (possibly to share the same architecture with other circuits).
The blanket implementation enables none of them.
Dyn Compatibility§
This trait is not dyn compatible.
In older versions of Rust, dyn compatibility was called "object safety", so this trait is not object safe.