use std::collections::BTreeMap;
use serde::{Deserialize, Serialize};
use slop_algebra::AbstractField;
use slop_alloc::{CpuBackend, GLOBAL_CPU_BACKEND};
use slop_basefold::BasefoldProof;
use slop_challenger::{GrindingChallenger, IopCtx};
use slop_commit::Rounds;
use slop_jagged::{JaggedPcsProof, JaggedSumcheckEvalProof};
use slop_matrix::dense::RowMajorMatrixView;
use slop_multilinear::{Mle, MleEval, MultilinearPcsVerifier, Point};
use slop_sumcheck::PartialSumcheckProof;
use slop_symmetric::PseudoCompressionFunction;
use slop_tensor::Tensor;
use sp1_primitives::{utils::reverse_bits_len, SP1ExtensionField, SP1Field, SP1GlobalContext};
use crate::{
LogUpEvaluations, LogUpGkrOutput, LogupGkrProof, MachineVerifyingKey, SP1PcsProof,
SP1PcsProofInner, SP1VerifyingKey, ShardContext, DIGEST_SIZE,
};
pub const PROOF_MAX_NUM_PVS: usize = 187;
#[derive(Clone, Serialize, Deserialize)]
#[serde(bound(
serialize = "GC: IopCtx, GC::Challenger: Serialize",
deserialize = "GC: IopCtx, GC::Challenger: Deserialize<'de>"
))]
pub struct TestingData<GC: IopCtx> {
pub gkr_points: Vec<Point<GC::EF>>,
pub challenger_state: GC::Challenger,
}
#[derive(Clone, Serialize, Deserialize)]
#[serde(bound(
serialize = "GC: IopCtx, GC::Challenger: Serialize, Proof: Serialize",
deserialize = "GC: IopCtx, GC::Challenger: Deserialize<'de>, Proof: Deserialize<'de>"
))]
pub struct ShardProof<GC: IopCtx, Proof> {
pub public_values: Vec<GC::F>,
pub main_commitment: GC::Digest,
pub logup_gkr_proof: LogupGkrProof<<GC::Challenger as GrindingChallenger>::Witness, GC::EF>,
pub zerocheck_proof: PartialSumcheckProof<GC::EF>,
pub opened_values: ShardOpenedValues<GC::F, GC::EF>,
pub evaluation_proof: JaggedPcsProof<GC, Proof>,
}
pub type ShardContextProof<GC, SC> =
ShardProof<GC, <<SC as ShardContext<GC>>::Config as MultilinearPcsVerifier<GC>>::Proof>;
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ShardOpenedValues<F, EF> {
pub chips: BTreeMap<String, ChipOpenedValues<F, EF>>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(bound(serialize = "F: Serialize, EF: Serialize"))]
#[serde(bound(deserialize = "F: Deserialize<'de>, EF: Deserialize<'de>"))]
pub struct ChipOpenedValues<F, EF> {
pub preprocessed: AirOpenedValues<EF>,
pub main: AirOpenedValues<EF>,
pub degree: Point<F>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(bound(serialize = "T: Serialize"))]
#[serde(bound(deserialize = "T: Deserialize<'de>"))]
pub struct AirOpenedValues<T> {
pub local: Vec<T>,
}
impl<T> AirOpenedValues<T> {
#[must_use]
pub fn view(&self) -> RowMajorMatrixView<'_, T>
where
T: Clone + Send + Sync,
{
RowMajorMatrixView::new_row(&self.local)
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct MerkleProof<GC: IopCtx> {
pub index: usize,
pub path: Vec<GC::Digest>,
}
#[derive(Debug)]
pub struct VcsError;
pub fn verify_merkle_proof<GC: IopCtx>(
proof: &MerkleProof<GC>,
value: GC::Digest,
commitment: GC::Digest,
) -> Result<(), VcsError> {
let MerkleProof { index, path } = proof;
let mut value = value;
let mut index = reverse_bits_len(*index, path.len());
for sibling in path {
let new_pair = if index.is_multiple_of(2) { [value, *sibling] } else { [*sibling, value] };
let (_, compressor) = GC::default_hasher_and_compressor();
value = compressor.compress(new_pair);
index >>= 1;
}
if value != commitment {
Err(VcsError)
} else {
Ok(())
}
}
#[derive(Serialize, Deserialize, Clone)]
#[serde(bound(
serialize = "GC: IopCtx, GC::Challenger: Serialize, Proof: Serialize",
deserialize = "GC: IopCtx, GC::Challenger: Deserialize<'de>, Proof: Deserialize<'de>"
))]
pub struct SP1RecursionProof<GC: IopCtx, Proof> {
pub vk: MachineVerifyingKey<GC>,
pub proof: ShardProof<GC, Proof>,
pub vk_merkle_proof: MerkleProof<SP1GlobalContext>,
}
impl<GC: IopCtx, Proof> std::fmt::Debug for SP1RecursionProof<GC, Proof> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let mut debug_struct = f.debug_struct("SP1ReduceProof");
debug_struct.finish()
}
}
#[derive(Serialize, Deserialize, Clone)]
#[serde(bound(
serialize = "GC: IopCtx, GC::Challenger: Serialize, Proof: Serialize",
deserialize = "GC: IopCtx, GC::Challenger: Deserialize<'de>, Proof: Deserialize<'de>"
))]
pub struct SP1WrapProof<GC: IopCtx, Proof> {
pub vk: MachineVerifyingKey<GC>,
pub proof: ShardProof<GC, Proof>,
}
#[must_use]
pub fn create_dummy_recursion_proof(
vk: &SP1VerifyingKey,
) -> SP1RecursionProof<SP1GlobalContext, SP1PcsProofInner> {
let dummy_query_proof = Vec::new();
let basefold_proof = BasefoldProof::<SP1GlobalContext> {
univariate_messages: vec![],
fri_commitments: vec![],
final_poly: SP1ExtensionField::zero(),
pow_witness: SP1Field::zero(),
batch_grinding_witness: SP1Field::zero(),
component_polynomials_query_openings_and_proofs: vec![],
query_phase_openings_and_proofs: dummy_query_proof,
};
let batch_evaluations: Rounds<MleEval<SP1ExtensionField, CpuBackend>> = Rounds::default();
let stacked_proof = SP1PcsProof { basefold_proof, batch_evaluations };
let jagged_eval_proof =
JaggedSumcheckEvalProof { partial_sumcheck_proof: PartialSumcheckProof::dummy() };
let evaluation_proof = JaggedPcsProof {
pcs_proof: stacked_proof,
jagged_eval_proof,
sumcheck_proof: PartialSumcheckProof::dummy(),
merkle_tree_commitments: Rounds::default(),
row_counts_and_column_counts: Rounds::default(),
expected_eval: SP1ExtensionField::zero(),
max_log_row_count: 1,
log_m: 1,
};
let empty_tensor: Tensor<SP1ExtensionField, CpuBackend> =
Tensor::zeros_in([1], GLOBAL_CPU_BACKEND);
let logup_gkr_proof = LogupGkrProof {
circuit_output: LogUpGkrOutput {
numerator: Mle::new(empty_tensor.clone()),
denominator: Mle::new(empty_tensor),
},
round_proofs: vec![],
logup_evaluations: LogUpEvaluations {
point: Point::from_usize(0, 1),
chip_openings: BTreeMap::new(),
},
witness: SP1Field::zero(),
};
let dummy_shard_proof = ShardProof {
public_values: Vec::new(),
main_commitment: [SP1Field::zero(); DIGEST_SIZE],
logup_gkr_proof,
zerocheck_proof: PartialSumcheckProof::dummy(),
opened_values: ShardOpenedValues { chips: BTreeMap::new() },
evaluation_proof,
};
SP1RecursionProof {
vk: vk.vk.clone(),
proof: dummy_shard_proof,
vk_merkle_proof: MerkleProof { index: 0, path: vec![] },
}
}