diff --git a/libs/driver/src/warm.rs b/libs/driver/src/warm.rs index 7ef1a8cb..65dfdc72 100644 --- a/libs/driver/src/warm.rs +++ b/libs/driver/src/warm.rs @@ -4,18 +4,18 @@ //! action. This module forces those builds/loads up front so `dobjd` does them //! at boot instead. -use lt_eq_u256_pod::STANDARD_LT_EQ_U256_VD_HASH; +use lt_eq_u256_pod::warm_standard_lt_eq_u256_circuit; use payload::shrink::ShrunkMainPodSetup; use pod2::backends::plonky2::basetypes::DEFAULT_VD_SET; use pod2::backends::plonky2::emptypod::EmptyPod; use pod2::backends::plonky2::mainpod::cache_get_rec_main_pod_common_hash; use pod2::middleware::Params; -use vdfpod::STANDARD_VDF_VD_HASH; +use vdfpod::warm_standard_vdf_circuit; /// Load (building on a cold cache) the proving artifacts the first action would /// otherwise build lazily, so the first `execute` doesn't pay for them: /// - the recursive MainPod circuit and its common hash, -/// - the VDF and lt_eq_u256 intro pod circuits (via their verifier-data hashes), +/// - the VDF and lt_eq_u256 intro pod circuits, /// - the empty pod: both its circuit and the proved *instance* the prover /// inserts as recursion padding. /// @@ -44,13 +44,11 @@ pub fn warm_proving_circuits() { log::info!("warming empty pod (circuit + instance)..."); let _ = EmptyPod::new_boxed(DEFAULT_VD_SET.clone()); - // Forcing each intro pod's verifier-data hash drives its circuit data to - // load/build, without constructing a pod (which would prove). log::info!("warming VDF intro pod circuit..."); - let _ = *STANDARD_VDF_VD_HASH; + warm_standard_vdf_circuit(); log::info!("warming lt_eq_u256 intro pod circuit..."); - let _ = *STANDARD_LT_EQ_U256_VD_HASH; + warm_standard_lt_eq_u256_circuit(); log::info!("proving circuits ready (warmed in {:?})", start.elapsed()); } diff --git a/libs/intro-pods/lt-eq-u256-pod/src/lib.rs b/libs/intro-pods/lt-eq-u256-pod/src/lib.rs index 66a18e91..fdbefc13 100644 --- a/libs/intro-pods/lt-eq-u256-pod/src/lib.rs +++ b/libs/intro-pods/lt-eq-u256-pod/src/lib.rs @@ -28,6 +28,7 @@ //! ``` use anyhow::Result; +use hex::FromHex; use plonky2::{ field::types::{Field, PrimeField64}, hash::{ @@ -70,23 +71,44 @@ use serde::{Deserialize, Serialize}; const LT_EQ_U256_POD_TYPE: (usize, &str) = (2002, "LtEqU256"); +const STANDARD_LT_EQ_U256_VD_HASH_HEX: &str = + "e0595e5c75467e5a27bd30fa48a45e1dcc66a327076e5ce7c02ce33dfe357311"; + +/// Verifier-data identity used by compiled predicates. Resolving it does not initialize the +/// prover circuit. pub static STANDARD_LT_EQ_U256_VD_HASH: std::sync::LazyLock = std::sync::LazyLock::new(|| { - let (_, data) = &**STANDARD_LT_EQ_U256_POD_DATA; - let hash_out = - pod2::backends::plonky2::recursion::circuit::hash_verifier_data(&data.verifier_only); - Hash(hash_out.elements.map(|e| e)) + Hash::from_hex(STANDARD_LT_EQ_U256_VD_HASH_HEX) + .expect("valid pinned lt-eq-u256 verifier-data hash") }); static STANDARD_LT_EQ_U256_POD_DATA: std::sync::LazyLock< CacheEntry<(LtEqU256PodTarget, CircuitDataSerializer)>, > = std::sync::LazyLock::new(|| { - cache::get("standard_lt_eq_u256_pod_circuit_data", &(), |_| { + let pod_data = cache::get("standard_lt_eq_u256_pod_circuit_data", &(), |_| { let (target, circuit_data) = build().expect("successful build"); (target, CircuitDataSerializer(circuit_data)) }) - .expect("cache ok") + .expect("cache ok"); + let (_, circuit_data) = &*pod_data; + let actual_hash = Hash( + pod2::backends::plonky2::recursion::circuit::hash_verifier_data( + &circuit_data.verifier_only, + ) + .elements, + ); + assert_eq!( + actual_hash, *STANDARD_LT_EQ_U256_VD_HASH, + "standard lt-eq-u256 circuit does not match its pinned verifier-data hash" + ); + pod_data }); + +/// Load or build the standard proving circuit and check its pinned verifier-data identity. +pub fn warm_standard_lt_eq_u256_circuit() { + std::sync::LazyLock::force(&STANDARD_LT_EQ_U256_POD_DATA); +} + fn build() -> Result<(LtEqU256PodTarget, CircuitData)> { let params = Params::default(); diff --git a/libs/intro-pods/vdfpod/src/lib.rs b/libs/intro-pods/vdfpod/src/lib.rs index 7ae6ddc1..0d0f0834 100644 --- a/libs/intro-pods/vdfpod/src/lib.rs +++ b/libs/intro-pods/vdfpod/src/lib.rs @@ -38,6 +38,7 @@ //! of this file). use anyhow::{Result, anyhow}; +use hex::FromHex; use plonky2::{ field::types::{Field, PrimeField64}, hash::{ @@ -88,11 +89,13 @@ const ARITY: usize = 1; const NUM_PUBLIC_INPUTS: usize = 13; // 13: count + input + output + verified_data_hash const VDF_POD_TYPE: (usize, &str) = (2001, "Vdf"); +const STANDARD_VDF_VD_HASH_HEX: &str = + "ab82223f501b5056f458f063eb2fc073f8ac01f2ea178a3a2303394fec6828a0"; + +/// Verifier-data identity used by compiled predicates. Resolving it does not initialize the +/// prover circuit. pub static STANDARD_VDF_VD_HASH: std::sync::LazyLock = std::sync::LazyLock::new(|| { - let (_, data) = &**STANDARD_VDF_POD_DATA; - let hash_out = - pod2::backends::plonky2::recursion::circuit::hash_verifier_data(&data.verifier_only); - Hash(hash_out.elements.map(|e| e)) + Hash::from_hex(STANDARD_VDF_VD_HASH_HEX).expect("valid pinned VDF verifier-data hash") }); static STANDARD_VDF_POD_DATA: std::sync::LazyLock< @@ -100,12 +103,30 @@ static STANDARD_VDF_POD_DATA: std::sync::LazyLock< > = std::sync::LazyLock::new(|| { // v2: the count arg in the public statement uses the tagged pod2 int // encoding. The version suffix evicts cache entries built before that. - cache::get("standard_vdf_pod_circuit_data_v2", &(), |_| { + let pod_data = cache::get("standard_vdf_pod_circuit_data_v2", &(), |_| { let (target, circuit_data) = build().expect("successful build"); (target, CircuitDataSerializer(circuit_data)) }) - .expect("cache ok") + .expect("cache ok"); + let (_, circuit_data) = &*pod_data; + let actual_hash = Hash( + pod2::backends::plonky2::recursion::circuit::hash_verifier_data( + &circuit_data.verifier_only, + ) + .elements, + ); + assert_eq!( + actual_hash, *STANDARD_VDF_VD_HASH, + "standard VDF circuit does not match its pinned verifier-data hash" + ); + pod_data }); + +/// Load or build the standard proving circuit and check its pinned verifier-data identity. +pub fn warm_standard_vdf_circuit() { + std::sync::LazyLock::force(&STANDARD_VDF_POD_DATA); +} + fn build() -> Result<(VdfPodTarget, CircuitData)> { let params = Params::default();