diff --git a/book/src/using-extensions/pairing.md b/book/src/using-extensions/pairing.md index 5ee6176ba0..76e25861da 100644 --- a/book/src/using-extensions/pairing.md +++ b/book/src/using-extensions/pairing.md @@ -14,7 +14,7 @@ A full guest program example is available here: [pairing_check.rs](https://githu We'll be working with an example using the BLS12-381 elliptic curve. This is in addition to the setup that needs to be done in the [Writing a Program](../writing-apps/write-program.md) section. -In the guest program, we will import the `PairingCheck` and `IntMod` traits, along with a few other values that we will require: +In the guest program, we will import the `PairingCheck` and `IntMod` traits, along with the BLS12-381 curve structs (**IMPORTANT:** this requires the `bls12_381` feature enabled in Cargo.toml for the `openvm-pairing-guest` dependency), and a few other values that we will need: ```rust title="guest program" use openvm_pairing_guest::{ @@ -29,6 +29,7 @@ use openvm::io::read; Additionally, we'll need to initialize our moduli and `Fp2` struct via the following macros. For a more in-depth description of these macros, please see the [Customizable Extensions](./customizable-extensions.md) section. ```rust +// These correspond to the BLS12-381 coordinate and scalar moduli, respectively openvm_algebra_moduli_setup::moduli_init! { "0x1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffaaab", "0x73eda753299d7d483339d80809a1d80553bda402fffe5bfeffffffff00000001" @@ -46,11 +47,13 @@ setup_0(); setup_all_complex_extensions(); ``` +There are two moduli defined internally in the Bls12_381 feature. The `moduli_init!` macro thus requires both of them to be initialized. However, we do not need the scalar field of BLS12-381 (which is at index 1), and thus we only initialize the modulus from index 0, thus we only use `setup_0()` (as opposed to `setup_all_moduli()`, which will save us some columns when generating the trace). + ## Input values The inputs to the pairing check are `AffinePoint`s in $\mathbb{F}_p$ and $\mathbb{F}_{p^2}$. They can be constructed via the `AffinePoint::new` function, with the inner `Fp` and `Fp2` values constructed via various `from_...` functions. -We can create a new struct that will hold this point outside of our guest program and import it into our guest program: +We can create a new struct outside of our guest program that will hold these `AffinePoint`s and import it into our guest program: ```rust #[derive(Clone, serde::Serialize, serde::Deserialize)] @@ -68,11 +71,9 @@ Our guest program imports the struct and can read it in via: let io: PairingCheckInput = read(); ``` -> Please note that the coefficients of the input points must equal to 0: $ad + bc = 0$, with $a,b$ as the $p0,q0$ points and $c,d$ as the $p1,q1$ points. A point is given by $a*g$, where $a$ is a scalar and $g$ is the generator in either $\mathbb{F}_p$ or $\mathbb{F}_{p^2}$. To get the above $ad + bc = 0$ equation, we can negate (`.neg()`) a single `AffinePoint` to ensure that the equation holds. - ## Pairing check -Most users that use the pairing extension will want to assert that a pairing is valid (the final exponentiation equals one). This with the `PairingCheck` trait imported from the previous section, we have access to the `pairing_check` function on the `Bls12_381` struct. After reading in the input struct, we can use its values in the `pairing_check`: +Most users that use the pairing extension will want to assert that a pairing is valid (the final exponentiation equals one). With the `PairingCheck` trait imported from the previous section, we have access to the `pairing_check` function on the `Bls12_381` struct. After reading in the input struct, we can use its values in the `pairing_check`: ```rust let res = Bls12_381::pairing_check( @@ -86,20 +87,9 @@ assert!(res.is_ok()) We also have access to each of the specific functions that the pairing check utilizes for either the BN254 or BLS12-381 elliptic curves. -### Line function evaluations - -Line functions can be separately evaluated: - -```rust -// Line functions in 023 form; b0, c0, b1, c1 are Fp2 -let l0 = EvaluatedLine:: { b: b0, c: c0 } -let l1 = EvaluatedLine:: { b: b1, c: c1 }; -let r = Bls12_381::mul_023_by_023(l0, l1); -``` - ### Multi-Miller loop -The multi-Miller loop can also be ran separately via: +The multi-Miller loop requires the MultiMillerLoop trait can also be ran separately via: ```rust let f = Bls12_381::multi_miller_loop( @@ -108,12 +98,17 @@ let f = Bls12_381::multi_miller_loop( ); ``` -### Final exponentiation hint +### Final exponentiation -Final exponentiation is computed on the host and hinted to OpenVM via the `final_exp_hint` function: +Final exponentiation can be run separately by importing the `FinalExp` trait. ```rust -let (c, s) = Bls12_381::final_exp_hint(&f); +use openvm_pairing_guest::pairing::FinalExp; +let (c, s) = Bls12_381::assert_final_exp_is_one( + &f, + &[p0, p1], + &[q0, q1], +); ``` -Where $c$ is the residue witness and $s$ is the scaling factor (BLS12-381) or cubic non-residue power (BN254), and the input $f$ is the result of the multi-Miller loop. +Where $c$ is the residue witness and $s$ is the scaling factor (BLS12-381) or cubic non-residue power (BN254), and the input $f$ is the result of the multi-Miller loop. The `p0`, `p1`, `q0`, `q1` points are the same as those used in the multi_miller_loop function.