use axiom_codec::{
constants::{MAX_SUBQUERY_INPUTS, MAX_SUBQUERY_OUTPUTS},
types::{field_elements::AnySubqueryResult, native::SubqueryType},
};
use axiom_eth::{
halo2_base::{gates::GateInstructions, utils::ScalarField, AssignedValue},
rlc::{chip::RlcChip, circuit::builder::RlcContextPair},
};
#[derive(Clone, Debug)]
pub struct GroupedSubqueryResults<T> {
pub subquery_type: SubqueryType,
pub results: Vec<AnySubqueryResult<Vec<T>, Vec<T>>>,
}
impl<F: ScalarField> GroupedSubqueryResults<AssignedValue<F>> {
pub fn into_rlc(
self,
(ctx_gate, ctx_rlc): RlcContextPair<F>,
gate: &impl GateInstructions<F>,
rlc: &RlcChip<F>,
) -> Vec<[AssignedValue<F>; 1]> {
if self.results.is_empty() {
return vec![];
}
let subquery_type = ctx_gate.load_constant(F::from(self.subquery_type as u64));
let subquery_len = self.results[0].subquery.len();
assert!(subquery_len <= MAX_SUBQUERY_INPUTS);
let val_len = self.results[0].value.len();
assert!(val_len <= MAX_SUBQUERY_OUTPUTS);
let val_multiplier = (val_len < MAX_SUBQUERY_OUTPUTS)
.then(|| rlc.rlc_pow_fixed(ctx_gate, gate, MAX_SUBQUERY_OUTPUTS - val_len));
let subquery_multiplier = rlc.rlc_pow_fixed(
ctx_gate,
gate,
MAX_SUBQUERY_INPUTS + MAX_SUBQUERY_OUTPUTS - subquery_len,
);
self.results
.into_iter()
.map(|result| {
let subquery = result.subquery;
let value = result.value;
assert_eq!(subquery.len(), subquery_len);
assert_eq!(value.len(), val_len);
let mut val_rlc = rlc.compute_rlc_fixed_len(ctx_rlc, value.clone()).rlc_val;
if let Some(multiplier) = val_multiplier {
val_rlc = gate.mul(ctx_gate, val_rlc, multiplier);
}
let key = [vec![subquery_type], subquery].concat();
let key_rlc = rlc.compute_rlc_fixed_len(ctx_rlc, key).rlc_val;
[gate.mul_add(ctx_gate, key_rlc, subquery_multiplier, val_rlc)]
})
.collect()
}
}