newton-core 0.4.16

newton protocol core sdk
#![cfg(all(feature = "attestation", feature = "rpc"))]

use sp1_sdk::{
    network::FulfillmentStrategy, Elf, HashableKey, ProveRequest, Prover, ProverClient, ProvingKey, SP1Stdin,
};
use std::time::Duration;

use crate::zk::{Proof, SP1_ATTESTATION_ELF};

/// Input parameters for proving an attestation is invalid.
#[derive(Debug, Clone)]
pub struct AttestationProofInput {
    /// Raw CBOR attestation document (~3KB)
    pub attestation_bytes: Vec<u8>,
    /// Hashes of pre-cached intermediate certs (on-chain, for cycle reduction)
    pub cached_cert_hashes: Vec<[u8; 32]>,
    /// AWS Nitro root CA DER bytes
    pub root_cert_der: Vec<u8>,
    /// Task ID for binding verification
    pub task_id: [u8; 32],
    /// keccak256(abi.encode(taskResponse)) for binding verification
    pub response_digest: [u8; 32],
}

/// Generate an SP1 proof that a Nitro attestation is invalid.
///
/// The circuit verifies the cert chain, PCR0, and task binding, then commits
/// `AttestationResult` as public values. If any check fails, `is_valid = false`.
///
/// Called by the challenger when it detects an invalid attestation on-chain.
pub async fn prove_attestation_invalid(input: AttestationProofInput) -> eyre::Result<Proof> {
    tracing::info!("generating SP1 attestation invalidity proof");
    crate::config::dotenv::init().unwrap();

    let mut stdin = SP1Stdin::new();
    stdin.write_vec(input.attestation_bytes);
    stdin.write(&input.cached_cert_hashes);
    stdin.write_vec(input.root_cert_der);
    stdin.write(&input.task_id);
    stdin.write(&input.response_digest);

    let client = ProverClient::builder()
        .network()
        .private_key(&crate::config::dotenv::get::<String>("NETWORK_PRIVATE_KEY"))
        .build()
        .await;

    let pk = client
        .setup(Elf::Static(SP1_ATTESTATION_ELF))
        .await
        .map_err(|e| eyre::eyre!("SP1 attestation setup failed: {e}"))?;
    let vk = pk.verifying_key().clone();

    tracing::info!(
        "requesting attestation proof, vkey={}",
        vk.bytes32().to_string().as_str()
    );

    let request_id = client
        .prove(&pk, stdin)
        .groth16()
        .strategy(FulfillmentStrategy::Reserved)
        .request()
        .await
        .map_err(|e| eyre::eyre!("SP1 attestation proof request failed: {e}"))?;

    tracing::info!("attestation proof request ID: {}", crate::hex!(request_id));

    let proof = client
        .wait_proof(request_id, Some(Duration::from_secs(600)), None)
        .await
        .map_err(|e| eyre::eyre!("SP1 attestation proof generation failed: {e}"))?;

    tracing::info!("attestation proof generated successfully");

    Ok(Proof::Sp1 {
        journal: proof.public_values.to_vec(),
        vk,
        proof,
        request_id,
    })
}