halo2-ecc 0.5.1

In-circuit elliptic curve library for halo2.
Documentation
use crate::ff::{Field as _, PrimeField as _};
use crate::fields::fp::FpChip;
use crate::fields::FieldChip;
use crate::halo2_proofs::halo2curves::bn256::{Fq, Fr};

use halo2_base::utils::biguint_to_fe;
use halo2_base::utils::testing::base_test;
use halo2_base::utils::{fe_to_biguint, modulus};
use halo2_base::Context;
use rand::rngs::OsRng;

pub mod assert_eq;

const K: usize = 10;

fn fp_chip_test(
    k: usize,
    lookup_bits: usize,
    limb_bits: usize,
    num_limbs: usize,
    f: impl Fn(&mut Context<Fr>, &FpChip<Fr, Fq>),
) {
    base_test().k(k as u32).lookup_bits(lookup_bits).run(|ctx, range| {
        let chip = FpChip::<Fr, Fq>::new(range, limb_bits, num_limbs);
        f(ctx, &chip);
    });
}

#[test]
fn test_fp() {
    let limb_bits = 88;
    let num_limbs = 3;
    fp_chip_test(K, K - 1, limb_bits, num_limbs, |ctx, chip| {
        let _a = Fq::random(OsRng);
        let _b = Fq::random(OsRng);

        let [a, b] = [_a, _b].map(|x| chip.load_private(ctx, x));
        let c = chip.mul(ctx, a, b);

        assert_eq!(c.0.truncation.to_bigint(limb_bits), c.0.value);
        assert_eq!(c.native().value(), &biguint_to_fe(&(c.value() % modulus::<Fr>())));
        assert_eq!(c.0.value, fe_to_biguint(&(_a * _b)).into());
    });
}

#[test]
fn test_range_check() {
    fp_chip_test(K, K - 1, 88, 3, |ctx, chip| {
        let mut range_test = |x, bits| {
            let x = chip.load_private(ctx, x);
            chip.range_check(ctx, x, bits);
        };
        let a = -Fq::one();
        range_test(a, Fq::NUM_BITS as usize);
        range_test(Fq::one(), 1);
        range_test(Fq::from(u64::MAX), 64);
        range_test(Fq::zero(), 1);
        range_test(Fq::zero(), 0);
    });
}

#[cfg(feature = "dev-graph")]
#[test]
fn plot_fp() {
    use halo2_base::gates::circuit::builder::BaseCircuitBuilder;
    use halo2_base::halo2_proofs;
    use plotters::prelude::*;

    let root = BitMapBackend::new("layout.png", (1024, 1024)).into_drawing_area();
    root.fill(&WHITE).unwrap();
    let root = root.titled("Fp Layout", ("sans-serif", 60)).unwrap();

    let k = K;
    let a = Fq::zero();
    let b = Fq::zero();

    let mut builder = BaseCircuitBuilder::new(false).use_k(k).use_lookup_bits(k - 1);
    let range = builder.range_chip();
    let chip = FpChip::<Fr, Fq>::new(&range, 88, 3);
    let ctx = builder.main(0);
    let [a, b] = [a, b].map(|x| chip.load_private(ctx, x));
    let c = chip.mul(ctx, a, b);

    let cp = builder.calculate_params(Some(10));
    log::info!("cp: {:?}", cp);
    halo2_proofs::dev::CircuitLayout::default().render(k as u32, &builder, &root).unwrap();
}