use tasm_lib::verifier::stark_verify::StarkVerify;
use trident::runtime::ProgramInput;
use triton_vm::prelude::*;
pub const SCHEMA_VERSION: u64 = 1;
pub const MAX_CLAIM_WORDS: usize = 1 << 17;
pub const MAX_PROOF_WORDS: usize = 1 << 20;
pub const CLAIM_ADDRESS: u64 = 1 << 25;
pub const PROOF_ADDRESS: u64 = 1 << 24;
pub const CONTROL_ADDRESS: u64 = 1 << 26;
pub fn claim_commitment(claim: &Claim) -> Digest {
Tip5::hash(claim)
}
pub fn encode(expected: &Claim, proof: &Proof) -> Result<ProgramInput, String> {
if expected.input.len().saturating_add(expected.output.len()) > MAX_CLAIM_WORDS {
return Err("recursive claim exceeds version1 size limit".into());
}
if proof.0.len() >= MAX_PROOF_WORDS {
return Err("recursive proof exceeds version1 size limit".into());
}
let claim_words = expected.encode();
let proof_words = proof.encode();
if claim_words.is_empty() || claim_words.len() > MAX_CLAIM_WORDS {
return Err("recursive claim exceeds version1 size limit".into());
}
if proof_words.is_empty() || proof_words.len() > MAX_PROOF_WORDS {
return Err("recursive proof exceeds version1 size limit".into());
}
let claim_roundtrip =
Claim::decode(&claim_words).map_err(|_| "noncanonical recursive claim")?;
let proof_roundtrip =
Proof::decode(&proof_words).map_err(|_| "noncanonical recursive proof")?;
if claim_roundtrip.encode() != claim_words || proof_roundtrip.encode() != proof_words {
return Err("recursive witness encoding is not canonical".into());
}
let stark = Stark::default();
crate::convert::verify_native_proof(expected, proof)
.map_err(|_| "proof does not verify for the expected claim")?;
let mut nd = NonDeterminism::default();
StarkVerify::new_with_dynamic_layout(stark).update_nondeterminism(&mut nd, proof, expected);
let mut secret = vec![SCHEMA_VERSION, claim_words.len() as u64];
secret.extend(claim_words.into_iter().map(|v| v.value()));
secret.push(proof_words.len() as u64);
secret.extend(proof_words.into_iter().map(|v| v.value()));
Ok(ProgramInput {
public: claim_commitment(expected)
.values()
.into_iter()
.map(|v| v.value())
.collect(),
secret,
digests: nd
.digests
.into_iter()
.map(|d| d.values().map(|v| v.value()))
.collect(),
})
}
pub fn encode_proof_data(
expected: &Claim,
artifact: &trident::runtime::ProofData,
) -> Result<ProgramInput, String> {
if artifact.format != "stark-triton-v7" {
return Err("recursive verifier requires stark-triton-v7 proof format".into());
}
let expected_metadata = crate::convert::to_trident_claim(expected);
if artifact.claim.program_hash != expected_metadata.program_hash
|| artifact.claim.public_input != expected_metadata.public_input
|| artifact.claim.public_output != expected_metadata.public_output
{
return Err("proof artifact claim differs from caller expected claim".into());
}
let byte_limit = (MAX_PROOF_WORDS as u64) * 8 + 8;
if artifact.proof_bytes.len() as u64 > byte_limit {
return Err("recursive proof artifact exceeds version1 size limit".into());
}
let proof = crate::convert::bytes_to_proof(&artifact.proof_bytes)
.map_err(|_| "invalid canonical recursive proof artifact")?;
encode(expected, &proof)
}