use crate::halo2_proofs::arithmetic::Field;
use halo2_base::{
gates::{GateInstructions, RangeInstructions},
utils::{BigPrimeField, ScalarField},
AssignedValue, Context,
};
use num_bigint::BigUint;
use serde::{Deserialize, Serialize};
use std::fmt::Debug;
pub mod fp;
pub mod fp12;
pub mod fp2;
pub mod vector;
#[cfg(test)]
mod tests;
pub trait FieldChip<F: BigPrimeField>: Clone + Send + Sync {
const PRIME_FIELD_NUM_BITS: u32;
type UnsafeFieldPoint: Clone
+ Debug
+ Send
+ Sync
+ From<Self::FieldPoint>
+ for<'a> From<&'a Self::UnsafeFieldPoint>
+ for<'a> From<&'a Self::FieldPoint>; type FieldPoint: Clone
+ Debug
+ Send
+ Sync
+ From<Self::ReducedFieldPoint>
+ for<'a> From<&'a Self::FieldPoint>;
type ReducedFieldPoint: Clone + Debug + Send + Sync;
type FieldType: Field;
type RangeChip: RangeInstructions<F>;
fn native_modulus(&self) -> &BigUint;
fn gate(&self) -> &<Self::RangeChip as RangeInstructions<F>>::Gate {
self.range().gate()
}
fn range(&self) -> &Self::RangeChip;
fn limb_bits(&self) -> usize;
fn get_assigned_value(&self, x: &Self::UnsafeFieldPoint) -> Self::FieldType;
fn load_private(&self, ctx: &mut Context<F>, fe: Self::FieldType) -> Self::FieldPoint;
fn load_private_reduced(
&self,
ctx: &mut Context<F>,
fe: Self::FieldType,
) -> Self::ReducedFieldPoint {
let fe = self.load_private(ctx, fe);
self.enforce_less_than(ctx, fe)
}
fn load_constant(&self, ctx: &mut Context<F>, fe: Self::FieldType) -> Self::FieldPoint;
fn add_no_carry(
&self,
ctx: &mut Context<F>,
a: impl Into<Self::UnsafeFieldPoint>,
b: impl Into<Self::UnsafeFieldPoint>,
) -> Self::UnsafeFieldPoint;
fn add_constant_no_carry(
&self,
ctx: &mut Context<F>,
a: impl Into<Self::UnsafeFieldPoint>,
c: Self::FieldType,
) -> Self::UnsafeFieldPoint;
fn sub_no_carry(
&self,
ctx: &mut Context<F>,
a: impl Into<Self::UnsafeFieldPoint>,
b: impl Into<Self::UnsafeFieldPoint>,
) -> Self::UnsafeFieldPoint;
fn negate(&self, ctx: &mut Context<F>, a: Self::FieldPoint) -> Self::FieldPoint;
fn scalar_mul_no_carry(
&self,
ctx: &mut Context<F>,
a: impl Into<Self::UnsafeFieldPoint>,
c: i64,
) -> Self::UnsafeFieldPoint;
fn scalar_mul_and_add_no_carry(
&self,
ctx: &mut Context<F>,
a: impl Into<Self::UnsafeFieldPoint>,
b: impl Into<Self::UnsafeFieldPoint>,
c: i64,
) -> Self::UnsafeFieldPoint;
fn mul_no_carry(
&self,
ctx: &mut Context<F>,
a: impl Into<Self::UnsafeFieldPoint>,
b: impl Into<Self::UnsafeFieldPoint>,
) -> Self::UnsafeFieldPoint;
fn check_carry_mod_to_zero(&self, ctx: &mut Context<F>, a: Self::UnsafeFieldPoint);
fn carry_mod(&self, ctx: &mut Context<F>, a: Self::UnsafeFieldPoint) -> Self::FieldPoint;
fn range_check(&self, ctx: &mut Context<F>, a: impl Into<Self::FieldPoint>, max_bits: usize);
fn enforce_less_than(
&self,
ctx: &mut Context<F>,
a: Self::FieldPoint,
) -> Self::ReducedFieldPoint;
fn is_soft_zero(
&self,
ctx: &mut Context<F>,
a: impl Into<Self::FieldPoint>,
) -> AssignedValue<F>;
fn is_soft_nonzero(
&self,
ctx: &mut Context<F>,
a: impl Into<Self::FieldPoint>,
) -> AssignedValue<F>;
fn is_zero(&self, ctx: &mut Context<F>, a: impl Into<Self::FieldPoint>) -> AssignedValue<F>;
fn is_equal_unenforced(
&self,
ctx: &mut Context<F>,
a: Self::ReducedFieldPoint,
b: Self::ReducedFieldPoint,
) -> AssignedValue<F>;
fn assert_equal(
&self,
ctx: &mut Context<F>,
a: impl Into<Self::FieldPoint>,
b: impl Into<Self::FieldPoint>,
);
fn is_equal(
&self,
ctx: &mut Context<F>,
a: impl Into<Self::FieldPoint>,
b: impl Into<Self::FieldPoint>,
) -> AssignedValue<F> {
let a = self.enforce_less_than(ctx, a.into());
let b = self.enforce_less_than(ctx, b.into());
self.is_equal_unenforced(ctx, a, b)
}
fn mul(
&self,
ctx: &mut Context<F>,
a: impl Into<Self::UnsafeFieldPoint>,
b: impl Into<Self::UnsafeFieldPoint>,
) -> Self::FieldPoint {
let no_carry = self.mul_no_carry(ctx, a, b);
self.carry_mod(ctx, no_carry)
}
fn divide(
&self,
ctx: &mut Context<F>,
a: impl Into<Self::FieldPoint>,
b: impl Into<Self::FieldPoint>,
) -> Self::FieldPoint {
let b = b.into();
let b_is_zero = self.is_zero(ctx, b.clone());
self.gate().assert_is_const(ctx, &b_is_zero, &F::ZERO);
self.divide_unsafe(ctx, a.into(), b)
}
fn divide_unsafe(
&self,
ctx: &mut Context<F>,
a: impl Into<Self::UnsafeFieldPoint>,
b: impl Into<Self::UnsafeFieldPoint>,
) -> Self::FieldPoint {
let a = a.into();
let b = b.into();
let a_val = self.get_assigned_value(&a);
let b_val = self.get_assigned_value(&b);
let b_inv: Self::FieldType = Option::from(b_val.invert()).unwrap_or_default();
let quot_val = a_val * b_inv;
let quot = self.load_private(ctx, quot_val);
let quot_b = self.mul_no_carry(ctx, quot.clone(), b);
let quot_constraint = self.sub_no_carry(ctx, quot_b, a);
self.check_carry_mod_to_zero(ctx, quot_constraint);
quot
}
fn neg_divide(
&self,
ctx: &mut Context<F>,
a: impl Into<Self::FieldPoint>,
b: impl Into<Self::FieldPoint>,
) -> Self::FieldPoint {
let b = b.into();
let b_is_zero = self.is_zero(ctx, b.clone());
self.gate().assert_is_const(ctx, &b_is_zero, &F::ZERO);
self.neg_divide_unsafe(ctx, a.into(), b)
}
fn neg_divide_unsafe(
&self,
ctx: &mut Context<F>,
a: impl Into<Self::UnsafeFieldPoint>,
b: impl Into<Self::UnsafeFieldPoint>,
) -> Self::FieldPoint {
let a = a.into();
let b = b.into();
let a_val = self.get_assigned_value(&a);
let b_val = self.get_assigned_value(&b);
let b_inv: Self::FieldType = Option::from(b_val.invert()).unwrap_or_default();
let quot_val = -a_val * b_inv;
let quot = self.load_private(ctx, quot_val);
let quot_b = self.mul_no_carry(ctx, quot.clone(), b);
let quot_constraint = self.add_no_carry(ctx, quot_b, a);
self.check_carry_mod_to_zero(ctx, quot_constraint);
quot
}
}
pub trait Selectable<F: ScalarField, Pt> {
fn select(&self, ctx: &mut Context<F>, a: Pt, b: Pt, sel: AssignedValue<F>) -> Pt;
fn select_by_indicator(
&self,
ctx: &mut Context<F>,
a: &impl AsRef<[Pt]>,
coeffs: &[AssignedValue<F>],
) -> Pt;
}
pub trait PrimeFieldChip<F: BigPrimeField>: FieldChip<F>
where
Self::FieldType: BigPrimeField,
{
fn num_limbs(&self) -> usize;
fn limb_mask(&self) -> &BigUint;
fn limb_bases(&self) -> &[F];
}
pub trait FieldExtConstructor<Fp: crate::ff::PrimeField, const DEGREE: usize> {
fn new(c: [Fp; DEGREE]) -> Self;
fn coeffs(&self) -> Vec<Fp>;
}
#[derive(Clone, Copy, Debug, Serialize, Deserialize)]
pub enum FpStrategy {
Simple,
}