use alloc::{vec, vec::Vec};
pub use miden_core::proof::StarkProof;
use miden_core::{Felt, utils::RowMajorMatrix};
pub use crate::transcript::eval::trace::{EcNode, Truthy, UintNode};
use crate::{
ec::{
EcStores,
add::trace::generate_trace as ec_add_trace,
msm::{
require,
trace::{EcExprPtr, EcMsmRequires, generate_trace as msm_trace},
},
point_store_groups::trace::generate_trace as ec_store_trace,
trace::EcGroupPtr,
},
hash::{
chunk::trace::ChunkRequires,
chunk_node_sponge::trace::generate_trace as chunk_node_sponge_trace,
keccak::{
digest::KeccakDigest,
node::trace::KeccakNodeRequires,
round::{RoundRequires, generate_trace as round_trace},
sponge::trace::SpongeRequires,
},
},
math::{U256, from_limbs32, to_limbs32},
primitives::byte_pair_lut::{BytePairLutRequires, generate_trace as bpl_trace},
transcript::{
eval::trace::{TranscriptEvalRequires, generate_trace as eval_trace},
nodes::UintOpId,
poseidon2::{
P2Digest,
trace::{Poseidon2Requires, generate_trace as p2_trace},
},
},
uint::{
UintStores, add::trace::generate_trace as uint_add_trace,
store_mul::trace::generate_trace as uint_trace, trace::UintPtr,
},
};
mod fixed;
mod prove;
pub(crate) use fixed::{fixed_ecgroup_msgs, fixed_uintval_msgs};
pub mod statements;
pub mod strategies;
pub use miden_precompiles_air::{ChipletAir, ChipletMultiAir, NUM_CHIPLETS};
#[derive(Debug)]
pub struct Session {
p2: Poseidon2Requires,
chunk: ChunkRequires,
round: RoundRequires,
bpl: BytePairLutRequires,
sponge: SpongeRequires,
node: KeccakNodeRequires,
eval: TranscriptEvalRequires,
uint: UintStores,
ec: EcStores,
msm: EcMsmRequires,
}
impl Session {
pub fn new() -> Self {
let mut session = Self {
p2: Poseidon2Requires::new(),
chunk: ChunkRequires::new(),
round: RoundRequires::new(),
bpl: BytePairLutRequires::new(),
sponge: SpongeRequires::new(),
node: KeccakNodeRequires::new(),
eval: TranscriptEvalRequires::new(),
uint: UintStores::new(),
ec: EcStores::new(),
msm: EcMsmRequires::new(),
};
session.install_fixed_uints();
session.ec.store.require_fixed_groups();
session
}
fn install_fixed_uints(&mut self) {
for (addr, bound_addr, limbs) in fixed::fixed_uints() {
let value = from_limbs32(&limbs);
let ptr = if addr == bound_addr {
self.uint.store.pin_modulus(addr, value)
} else {
let bound = self.uint.store.pinned(bound_addr);
self.uint.store.intern_fixed_pinned(addr, value, bound)
};
self.uint.store.require_uintval(ptr);
}
}
pub fn keccak(&mut self, input: &[u8]) -> (KeccakDigest, Truthy) {
let out = self.node.require(
input,
&mut self.sponge,
&mut self.chunk,
&mut self.round,
&mut self.bpl,
&mut self.p2,
);
let handle = self.eval.issue_keccak(out.h_keccak, out.node_row);
(out.keccak_digest, handle)
}
pub fn pin_uint(&mut self, ptr: u32, value: U256, bound_ptr: u32) -> Truthy {
let handle = if ptr == bound_ptr {
self.uint.store.pin_modulus(ptr, value)
} else {
let bound = self.uint.store.pinned(bound_ptr);
self.uint.store.intern_pinned(ptr, value, bound)
};
let bound = self.uint.store.pinned(bound_ptr);
self.eval
.pin_uint(handle, bound, to_limbs32(value), &mut self.uint.store, &mut self.p2)
}
pub fn uint_leaf(&mut self, value: U256, bound_ptr: u32) -> UintNode {
let bound = self.uint.store.pinned(bound_ptr);
let ptr = self.uint.store.intern(value, bound);
self.eval
.uint_leaf(ptr, bound, to_limbs32(value), &mut self.uint.store, &mut self.p2)
}
pub fn uint_add(&mut self, a: &UintNode, b: &UintNode) -> UintNode {
self.uint_op(UintOpId::Add, a, b)
}
pub fn uint_sub(&mut self, a: &UintNode, b: &UintNode) -> UintNode {
self.uint_op(UintOpId::Sub, a, b)
}
pub fn uint_mul(&mut self, a: &UintNode, b: &UintNode) -> UintNode {
self.uint_op(UintOpId::Mul, a, b)
}
pub fn uint_is(&mut self, a: &UintNode, b: &UintNode) -> Truthy {
self.eval.record_is(a, b, &mut self.p2)
}
pub fn ec_create(&mut self, group_ptr: u32, x: &UintNode, y: &UintNode) -> EcNode {
let group = EcGroupPtr::from_addr(group_ptr);
let (_, _, bound) = self.ec.store.group_params(group);
assert_eq!(x.bound_ptr, y.bound_ptr, "coordinates must share a modulus");
assert_eq!(
x.bound_ptr, bound,
"coordinates must be stored under the group's base-field modulus",
);
self.eval
.ec_create(group_ptr, x, y, self.ec.require(self.uint.require()), &mut self.p2)
}
pub fn constrain_scalar_bound(&mut self, point: &EcNode, sbound_ptr: u32) {
let group = self.ec.store.point_params(point.point).0;
self.ec.store.set_scalar_bound(group, UintPtr::from_addr(sbound_ptr));
}
pub fn ec_pai(&mut self, group_ptr: u32) -> EcNode {
let group = EcGroupPtr::from_addr(group_ptr);
let _ = self.ec.store.group_params(group);
self.eval.ec_pai(group_ptr, self.ec.require(self.uint.require()), &mut self.p2)
}
pub fn ec_add(&mut self, p: &EcNode, q: &EcNode) -> EcNode {
self.eval.ec_add(p, q, self.ec.require(self.uint.require()), &mut self.p2)
}
pub fn ec_is(&mut self, p: &EcNode, q: &EcNode) -> Truthy {
self.eval.ec_is(p, q, &mut self.p2)
}
pub(crate) fn uint_value(&self, node: &UintNode) -> U256 {
self.uint.store.uint(node.ptr).value
}
pub(crate) fn is_recorded_truth(&self, claim: Truthy) -> bool {
self.eval.is_recorded_truth(claim)
}
pub fn ec_sub(&mut self, p: &EcNode, q: &EcNode) -> EcNode {
self.eval.ec_sub(p, q, self.ec.require(self.uint.require()), &mut self.p2)
}
pub fn msm_intro(&mut self, point: &EcNode) -> EcExprPtr {
require::intro(&mut self.msm, &mut self.ec, &mut self.uint, point.point)
}
pub fn msm_intro_endo(&mut self, point: &EcNode) -> EcExprPtr {
require::intro_endo(&mut self.msm, &mut self.ec, &mut self.uint, point.point)
}
pub fn msm_intro_zero(&mut self, point: &EcNode) -> EcExprPtr {
require::intro_zero(&mut self.msm, &mut self.ec, &mut self.uint, point.point)
}
pub fn is_pai(&self, point: &EcNode) -> bool {
self.ec.store.point_params(point.point).1.is_none()
}
pub fn msm_combine(&mut self, a: EcExprPtr, b: EcExprPtr) -> EcExprPtr {
require::combine(&mut self.msm, &mut self.ec, &mut self.uint, a, b)
}
pub fn msm_combine_terms_preserving(&mut self, a: EcExprPtr, b: EcExprPtr) -> EcExprPtr {
require::combine_terms_preserving(&mut self.msm, &mut self.ec, &mut self.uint, a, b)
}
pub fn msm_neg(&mut self, a: EcExprPtr) -> EcExprPtr {
require::neg(&mut self.msm, &mut self.ec, &mut self.uint, a)
}
pub fn ec_msm(&mut self, expr: EcExprPtr, terms: &[(EcNode, UintNode)]) -> EcNode {
self.eval.record_ec_msm(expr, terms, &mut self.msm, &mut self.p2)
}
pub fn msm_expr_count(&self) -> usize {
self.msm.expr_count()
}
pub fn msm_value_coords(&self, expr: EcExprPtr) -> (U256, U256) {
let val = self.msm.value(expr);
let (_, coords) = self.ec.store.point_params(val);
let (x, y) = coords.expect("MSM value is the point at infinity");
(self.uint.store.uint(x).value, self.uint.store.uint(y).value)
}
fn uint_op(&mut self, op: UintOpId, a: &UintNode, b: &UintNode) -> UintNode {
self.eval.uint_op(op, a, b, self.uint.require(), &mut self.p2)
}
pub fn zero(&mut self) -> Truthy {
self.eval.zero()
}
pub fn assert_and(&mut self, a: Truthy, b: Truthy) -> Truthy {
self.eval.record_and(a, b, &mut self.p2)
}
pub fn assert_and_fold(&mut self, handles: impl IntoIterator<Item = Truthy>) -> Truthy {
let mut acc = self.zero();
for h in handles {
acc = self.assert_and(acc, h);
}
acc
}
pub fn finish(mut self, root: Truthy) -> SessionTraces {
macro_rules! trace_span {
($name:literal, $expr:expr) => {{
let _span = tracing::info_span!($name).entered();
$expr
}};
}
let public_root = root.hash();
self.eval.assert_no_stray_values();
for (row, consumers) in self.eval.additional_keccak_uses() {
self.node.add_consumers(row, consumers);
}
let eval = trace_span!("eval", eval_trace(self.eval, root));
let chunk_node_sponge = trace_span!(
"chunk_node_sponge",
chunk_node_sponge_trace(self.chunk, self.node, self.sponge)
);
let p2 = trace_span!("poseidon2", p2_trace(self.p2));
let round = trace_span!("keccak_round", round_trace(self.round, &mut self.bpl));
let add = trace_span!("uint_add", uint_add_trace(self.uint.add, &mut self.uint.store));
let msm = trace_span!("ec_msm", msm_trace(self.msm, &mut self.uint.store, &mut self.bpl));
let uint = trace_span!(
"uint_store_mul",
uint_trace(self.uint.store, self.uint.mul, &mut self.bpl)
);
let ec_add =
trace_span!("ec_add", ec_add_trace(self.ec.add, &mut self.ec.store, &mut self.bpl));
let ec = trace_span!("ec_store", ec_store_trace(self.ec.store));
let bpl = trace_span!("byte_pair_lut", bpl_trace(self.bpl));
SessionTraces {
chunk_node_sponge,
p2,
round,
bpl,
eval,
uint,
add,
ec,
ec_add,
msm,
public_root,
}
}
}
impl Default for Session {
fn default() -> Self {
Self::new()
}
}
#[derive(Debug)]
pub struct SessionTraces {
chunk_node_sponge: RowMajorMatrix<Felt>,
p2: RowMajorMatrix<Felt>,
round: RowMajorMatrix<Felt>,
bpl: RowMajorMatrix<Felt>,
eval: RowMajorMatrix<Felt>,
uint: RowMajorMatrix<Felt>,
add: RowMajorMatrix<Felt>,
ec: RowMajorMatrix<Felt>,
ec_add: RowMajorMatrix<Felt>,
msm: RowMajorMatrix<Felt>,
public_root: P2Digest,
}
impl SessionTraces {
pub fn mains(&self) -> [&RowMajorMatrix<Felt>; NUM_CHIPLETS] {
[
&self.chunk_node_sponge,
&self.p2,
&self.round,
&self.bpl,
&self.eval,
&self.uint,
&self.add,
&self.ec,
&self.ec_add,
&self.msm,
]
}
pub fn into_mains(self) -> Vec<RowMajorMatrix<Felt>> {
vec![
self.chunk_node_sponge,
self.p2,
self.round,
self.bpl,
self.eval,
self.uint,
self.add,
self.ec,
self.ec_add,
self.msm,
]
}
pub fn air_inputs(&self) -> Vec<Felt> {
self.public_root.as_array().to_vec()
}
pub fn public_root(&self) -> P2Digest {
self.public_root
}
}