pub mod add;
pub mod groups;
pub mod msm;
pub mod require;
pub mod trace;
use alloc::vec::Vec;
use add::EcOnCurveCertMsg;
use miden_core::{
Felt,
field::{Algebra, PrimeCharacteristicRing, QuadFelt},
utils::RowMajorMatrix,
};
use miden_lifted_air::{AirBuilder, BaseAir, LiftedAir, LiftedAirBuilder};
pub use require::{EcRequire, EcStores};
use crate::{
logup::{
Challenges, CyclicConstraintLookupBuilder, Deg, LookupAir, LookupBatch, LookupBuilder,
LookupColumn, LookupGroup, LookupMessage, NUM_PUBLIC_VALUES, NUM_RANDOMNESS,
NUM_SIGMA_VALUES, frac_col,
},
relations::{BusId, MAX_MESSAGE_WIDTH, NUM_BUS_IDS},
uint::mul::UintMulMsg,
utils::{current_main, next_main},
};
#[derive(Debug, Clone)]
pub struct EcGroupMsg<E> {
pub group_ptr: E,
pub a_ptr: E,
pub b_ptr: E,
pub bound_ptr: E,
pub scalar_bound_ptr: E,
}
impl<E, EF> LookupMessage<E, EF> for EcGroupMsg<E>
where
E: Algebra<E>,
EF: Algebra<E>,
{
fn encode(&self, challenges: &Challenges<EF>) -> EF {
challenges.encode(
BusId::EcGroup as usize,
[
self.group_ptr.clone(),
self.a_ptr.clone(),
self.b_ptr.clone(),
self.bound_ptr.clone(),
self.scalar_bound_ptr.clone(),
],
)
}
}
#[derive(Debug, Clone)]
pub struct EcPointMsg<E> {
pub point_ptr: E,
pub group_ptr: E,
pub x_ptr: E,
pub y_ptr: E,
pub is_pai: E,
}
impl<E, EF> LookupMessage<E, EF> for EcPointMsg<E>
where
E: Algebra<E>,
EF: Algebra<E>,
{
fn encode(&self, challenges: &Challenges<EF>) -> EF {
challenges.encode(
BusId::EcPoint as usize,
[
self.point_ptr.clone(),
self.group_ptr.clone(),
self.x_ptr.clone(),
self.y_ptr.clone(),
self.is_pai.clone(),
],
)
}
}
pub const COL_PTR: usize = 0;
pub const COL_GROUP_PTR: usize = 1;
pub const COL_A_PTR: usize = 2;
pub const COL_B_PTR: usize = 3;
pub const COL_BOUND_PTR: usize = 4;
pub const COL_SBOUND_PTR: usize = 5;
pub const COL_X_PTR: usize = 6;
pub const COL_Y_PTR: usize = 7;
pub const COL_U_PTR: usize = 8;
pub const COL_W_PTR: usize = 9;
pub const COL_IS_PAI: usize = 10;
pub const COL_ECPOINT_MULT: usize = 11;
pub const COL_ACT: usize = 12;
pub const COL_IS_CERT: usize = 13;
pub const NUM_MAIN_COLS: usize = 14;
const NUM_LOGUP_COLS: usize = 5;
const AUX_WIDTH: usize = 5;
const COLUMN_SHAPE: [usize; NUM_LOGUP_COLS] = [1, 2, 1, 1, 1];
#[derive(Debug, Default, Clone, Copy)]
pub struct EcPointStoreAir;
impl BaseAir<Felt> for EcPointStoreAir {
fn width(&self) -> usize {
NUM_MAIN_COLS
}
fn num_public_values(&self) -> usize {
NUM_PUBLIC_VALUES
}
}
impl LiftedAir<Felt, QuadFelt> for EcPointStoreAir {
fn num_randomness(&self) -> usize {
NUM_RANDOMNESS
}
fn aux_width(&self) -> usize {
AUX_WIDTH
}
fn num_aux_values(&self) -> usize {
NUM_SIGMA_VALUES
}
fn build_aux_trace(
&self,
main: &RowMajorMatrix<Felt>,
_air_inputs: &[Felt],
_aux_inputs: &[Felt],
challenges: &[QuadFelt],
) -> (RowMajorMatrix<QuadFelt>, Vec<QuadFelt>) {
trace::build_points_aux(main, challenges)
}
fn eval<AB: LiftedAirBuilder<F = Felt>>(&self, builder: &mut AB) {
let local: [AB::Var; NUM_MAIN_COLS] = current_main(builder.main(), 0);
let next: [AB::Var; NUM_MAIN_COLS] = next_main(builder.main(), 0);
let is_pai: AB::Expr = local[COL_IS_PAI].into();
let is_cert: AB::Expr = local[COL_IS_CERT].into();
let act: AB::Expr = local[COL_ACT].into();
let act_next: AB::Expr = next[COL_ACT].into();
let ptr: AB::Expr = local[COL_PTR].into();
let ptr_next: AB::Expr = next[COL_PTR].into();
builder.assert_zero(is_pai.clone() * (AB::Expr::ONE - is_pai.clone()));
builder.assert_zero(is_cert.clone() * (AB::Expr::ONE - is_cert.clone()));
builder.assert_zero(act.clone() * (AB::Expr::ONE - act.clone()));
builder.assert_zero(is_pai.clone() * is_cert.clone());
for col in [COL_X_PTR, COL_Y_PTR, COL_U_PTR, COL_W_PTR] {
let cell: AB::Expr = local[col].into();
builder.assert_zero(is_pai.clone() * cell);
}
for col in [COL_U_PTR, COL_W_PTR] {
let cell: AB::Expr = local[col].into();
builder.assert_zero(is_cert.clone() * cell);
}
let point_mult: AB::Expr = local[COL_ECPOINT_MULT].into();
builder.assert_zero((AB::Expr::ONE - act.clone()) * point_mult);
builder
.when_transition()
.assert_zero((AB::Expr::ONE - act.clone()) * act_next.clone());
builder
.when_transition()
.assert_zero(act_next * (ptr_next - ptr.clone() - AB::Expr::ONE));
builder.when_first_row().assert_zero(ptr - act);
let mut lb =
CyclicConstraintLookupBuilder::new(builder, self, self.preprocessed_width() > 0);
<Self as LookupAir<_>>::eval(self, &mut lb);
}
}
impl<LB> LookupAir<LB> for EcPointStoreAir
where
LB: LookupBuilder<F = Felt>,
{
fn num_columns(&self) -> usize {
NUM_LOGUP_COLS
}
fn column_shape(&self) -> &[usize] {
&COLUMN_SHAPE
}
fn max_message_width(&self) -> usize {
MAX_MESSAGE_WIDTH
}
fn num_bus_ids(&self) -> usize {
NUM_BUS_IDS
}
fn eval(&self, builder: &mut LB) {
let local: [LB::Var; NUM_MAIN_COLS] = current_main(builder.main(), 0);
let ptr: LB::Expr = local[COL_PTR].into();
let group_ptr: LB::Expr = local[COL_GROUP_PTR].into();
let a_ptr: LB::Expr = local[COL_A_PTR].into();
let b_ptr: LB::Expr = local[COL_B_PTR].into();
let bound_ptr: LB::Expr = local[COL_BOUND_PTR].into();
let sbound_ptr: LB::Expr = local[COL_SBOUND_PTR].into();
let x_ptr: LB::Expr = local[COL_X_PTR].into();
let y_ptr: LB::Expr = local[COL_Y_PTR].into();
let u_ptr: LB::Expr = local[COL_U_PTR].into();
let w_ptr: LB::Expr = local[COL_W_PTR].into();
let is_pai: LB::Expr = local[COL_IS_PAI].into();
let is_cert: LB::Expr = local[COL_IS_CERT].into();
let act: LB::Expr = local[COL_ACT].into();
let neg_mult: LB::Expr = LB::Expr::ZERO - local[COL_ECPOINT_MULT].into();
let member_flag: LB::Expr =
act.clone() * (LB::Expr::ONE - is_pai.clone()) * (LB::Expr::ONE - is_cert.clone());
let cert_flag: LB::Expr = act.clone() * is_cert;
let one: LB::Expr = LB::Expr::ONE;
let zero: LB::Expr = LB::Expr::ZERO;
let provide_deg = Deg { v: 1, u: 1 };
let consume_deg = Deg { v: 1, u: 1 };
let member_deg = Deg { v: 3, u: 1 };
let cert_deg = Deg { v: 2, u: 1 };
let single_deg = Deg { v: 1, u: 2 };
let paired_deg = Deg { v: 3, u: 2 };
frac_col!(
builder,
"ec-points",
single_deg,
(
"provide-ecpoint",
neg_mult,
EcPointMsg {
point_ptr: ptr.clone(),
group_ptr: group_ptr.clone(),
x_ptr: x_ptr.clone(),
y_ptr: y_ptr.clone(),
is_pai: is_pai.clone(),
},
provide_deg
),
);
frac_col!(
builder,
"ec-points",
paired_deg,
(
"consume-ecgroup",
act,
EcGroupMsg {
group_ptr: group_ptr.clone(),
a_ptr: a_ptr.clone(),
b_ptr: b_ptr.clone(),
bound_ptr: bound_ptr.clone(),
scalar_bound_ptr: sbound_ptr.clone(),
},
consume_deg
),
(
"consume-ecgroupadd-cert",
cert_flag,
EcOnCurveCertMsg {
group_ptr: group_ptr.clone(),
r_ptr: ptr.clone()
},
cert_deg
),
);
frac_col!(
builder,
"ec-points",
single_deg,
(
"consume-mac-u",
member_flag.clone(),
UintMulMsg {
kappa_a: one.clone(),
kappa_c: one.clone(),
a_ptr: x_ptr.clone(),
b_ptr: x_ptr.clone(),
c_ptr: a_ptr.clone(),
r_ptr: u_ptr.clone(),
bound_ptr: bound_ptr.clone(),
is_sub: LB::Expr::ZERO,
},
member_deg
),
);
frac_col!(
builder,
"ec-points",
single_deg,
(
"consume-mac-w",
member_flag.clone(),
UintMulMsg {
kappa_a: one.clone(),
kappa_c: one.clone(),
a_ptr: x_ptr.clone(),
b_ptr: u_ptr.clone(),
c_ptr: b_ptr.clone(),
r_ptr: w_ptr.clone(),
bound_ptr: bound_ptr.clone(),
is_sub: LB::Expr::ZERO,
},
member_deg
),
);
frac_col!(
builder,
"ec-points",
single_deg,
(
"consume-mac-y",
member_flag,
UintMulMsg {
kappa_a: one,
kappa_c: zero,
a_ptr: y_ptr.clone(),
b_ptr: y_ptr.clone(),
c_ptr: bound_ptr.clone(),
r_ptr: w_ptr.clone(),
bound_ptr: bound_ptr.clone(),
is_sub: LB::Expr::ZERO,
},
member_deg
),
);
}
}