remove NonePod and use dummy signed pods (#272)

* remove NonePod and use dummy signed pods

* apply suggestion by @arnaucube
This commit is contained in:
Eduard S. 2025-06-13 10:14:15 +02:00 committed by GitHub
parent 03485d6fd3
commit 3b4edab1f5
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 54 additions and 49 deletions

View file

@ -1464,12 +1464,9 @@ impl InnerCircuit for MainPodVerifyTarget {
} }
// Padding // Padding
if input.signed_pods.len() != self.params.max_input_signed_pods { if input.signed_pods.len() != self.params.max_input_signed_pods {
// TODO: Instead of using an input for padding, use a canonical minimal SignedPod, let dummy = SignedPod::dummy();
// without it a MainPod configured to support input signed pods must have at least one
// input signed pod :(
let pad_pod = &input.signed_pods[0];
for i in input.signed_pods.len()..self.params.max_input_signed_pods { for i in input.signed_pods.len()..self.params.max_input_signed_pods {
self.signed_pods[i].set_targets(pw, pad_pod)?; self.signed_pods[i].set_targets(pw, &dummy)?;
} }
} }

View file

@ -1,4 +1,7 @@
use std::{collections::HashMap, sync::Mutex}; use std::{
collections::HashMap,
sync::{LazyLock, Mutex},
};
use itertools::Itertools; use itertools::Itertools;
use plonky2::{ use plonky2::{
@ -23,7 +26,7 @@ use crate::{
error::{Error, Result}, error::{Error, Result},
mainpod::{self, calculate_id}, mainpod::{self, calculate_id},
recursion::pad_circuit, recursion::pad_circuit,
serialize_proof, LazyLock, DEFAULT_PARAMS, STANDARD_REC_MAIN_POD_CIRCUIT_DATA, serialize_proof, DEFAULT_PARAMS, STANDARD_REC_MAIN_POD_CIRCUIT_DATA,
}, },
middleware::{ middleware::{
self, AnchoredKey, DynError, Hash, Params, Pod, PodId, PodType, RecursivePod, Statement, self, AnchoredKey, DynError, Hash, Params, Pod, PodId, PodType, RecursivePod, Statement,

View file

@ -18,7 +18,7 @@ use crate::{
deserialize_proof, deserialize_proof,
emptypod::EmptyPod, emptypod::EmptyPod,
error::{Error, Result}, error::{Error, Result},
mock::emptypod::MockEmptyPod, mock::{emptypod::MockEmptyPod, signedpod::MockSignedPod},
primitives::merkletree::MerkleClaimAndProof, primitives::merkletree::MerkleClaimAndProof,
recursion::{RecursiveCircuit, RecursiveParams}, recursion::{RecursiveCircuit, RecursiveParams},
serialize_proof, serialize_proof,
@ -27,8 +27,8 @@ use crate::{
}, },
middleware::{ middleware::{
self, resolve_wildcard_values, AnchoredKey, CustomPredicateBatch, DynError, Hash, self, resolve_wildcard_values, AnchoredKey, CustomPredicateBatch, DynError, Hash,
MainPodInputs, NativeOperation, NonePod, OperationType, Params, Pod, PodId, PodProver, MainPodInputs, NativeOperation, OperationType, Params, Pod, PodId, PodProver, PodType,
PodType, RecursivePod, StatementArg, ToFields, VDSet, F, KEY_TYPE, SELF, RecursivePod, StatementArg, ToFields, VDSet, F, KEY_TYPE, SELF,
}, },
}; };
@ -257,13 +257,16 @@ pub(crate) fn layout_statements(
statements.push(middleware::Statement::None.into()); statements.push(middleware::Statement::None.into());
// Input signed pods region // Input signed pods region
// TODO: Replace this with a dumb signed pod let dummy_signed_pod_box: Box<dyn Pod> =
// https://github.com/0xPARC/pod2/issues/246 if mock || inputs.signed_pods.len() == params.max_input_signed_pods {
let none_sig_pod_box: Box<dyn Pod> = Box::new(NonePod {}); Box::new(MockSignedPod::dummy())
let none_sig_pod = none_sig_pod_box.as_ref(); } else {
Box::new(SignedPod::dummy())
};
let dummy_signed_pod = dummy_signed_pod_box.as_ref();
assert!(inputs.signed_pods.len() <= params.max_input_signed_pods); assert!(inputs.signed_pods.len() <= params.max_input_signed_pods);
for i in 0..params.max_input_signed_pods { for i in 0..params.max_input_signed_pods {
let pod = inputs.signed_pods.get(i).unwrap_or(&none_sig_pod); let pod = inputs.signed_pods.get(i).unwrap_or(&dummy_signed_pod);
let sts = pod.pub_statements(); let sts = pod.pub_statements();
assert!(sts.len() <= params.max_signed_pod_values); assert!(sts.len() <= params.max_signed_pod_values);
for j in 0..params.max_signed_pod_values { for j in 0..params.max_signed_pod_values {

View file

@ -120,6 +120,15 @@ impl MockSignedPod {
kvs: data.kvs, kvs: data.kvs,
})) }))
} }
/// Generate a valid MockSignedPod with a public deterministic public key and no other
/// key-values than the default ones. This is used for padding.
pub fn dummy() -> MockSignedPod {
MockSigner {
pk: "dummy".to_string(),
}
._sign(&Params::default(), &HashMap::new())
.expect("valid")
}
} }
impl Pod for MockSignedPod { impl Pod for MockSignedPod {

View file

@ -1,7 +1,7 @@
use std::collections::HashMap; use std::{collections::HashMap, sync::LazyLock};
use itertools::Itertools; use itertools::Itertools;
use num_bigint::RandBigInt; use num_bigint::{BigUint, RandBigInt};
use rand::rngs::OsRng; use rand::rngs::OsRng;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
@ -28,7 +28,12 @@ use crate::{
pub struct Signer(pub SecretKey); pub struct Signer(pub SecretKey);
impl Signer { impl Signer {
fn _sign(&mut self, params: &Params, kvs: &HashMap<Key, Value>) -> Result<SignedPod> { fn sign_with_nonce(
&mut self,
params: &Params,
nonce: BigUint,
kvs: &HashMap<Key, Value>,
) -> Result<SignedPod> {
let mut kvs = kvs.clone(); let mut kvs = kvs.clone();
let pubkey = self.0.public_key(); let pubkey = self.0.public_key();
kvs.insert(Key::from(KEY_SIGNER), Value::from(pubkey)); kvs.insert(Key::from(KEY_SIGNER), Value::from(pubkey));
@ -37,7 +42,6 @@ impl Signer {
let dict = Dictionary::new(params.max_depth_mt_containers, kvs)?; let dict = Dictionary::new(params.max_depth_mt_containers, kvs)?;
let id = RawValue::from(dict.commitment()); // PodId as Value let id = RawValue::from(dict.commitment()); // PodId as Value
let nonce = OsRng.gen_biguint_below(&GROUP_ORDER);
let signature: Signature = self.0.sign(id, &nonce); let signature: Signature = self.0.sign(id, &nonce);
Ok(SignedPod { Ok(SignedPod {
id: PodId(Hash::from(id)), id: PodId(Hash::from(id)),
@ -46,6 +50,10 @@ impl Signer {
dict, dict,
}) })
} }
fn _sign(&mut self, params: &Params, kvs: &HashMap<Key, Value>) -> Result<SignedPod> {
let nonce = OsRng.gen_biguint_below(&GROUP_ORDER);
self.sign_with_nonce(params, nonce, kvs)
}
pub fn public_key(&self) -> Point { pub fn public_key(&self) -> Point {
self.0.public_key() self.0.public_key()
@ -77,6 +85,15 @@ struct Data {
kvs: Dictionary, kvs: Dictionary,
} }
static DUMMY_POD: LazyLock<SignedPod> = LazyLock::new(dummy);
fn dummy() -> SignedPod {
let nonce = BigUint::from(2u32);
Signer(SecretKey(BigUint::from(1u32)))
.sign_with_nonce(&Params::default(), nonce, &HashMap::new())
.expect("valid")
}
impl SignedPod { impl SignedPod {
fn _verify(&self) -> Result<()> { fn _verify(&self) -> Result<()> {
// 1. Verify type // 1. Verify type
@ -142,6 +159,12 @@ impl SignedPod {
dict: data.kvs, dict: data.kvs,
})) }))
} }
/// Generate a valid SignedPod with a public deterministic secret key and nonce and no other
/// key-values than the default ones. This is used for padding.
pub fn dummy() -> SignedPod {
DUMMY_POD.clone()
}
} }
impl Pod for SignedPod { impl Pod for SignedPod {

View file

@ -599,7 +599,6 @@ impl ToFields for PodId {
#[derive(Clone, Copy, Debug, PartialEq, Eq, FromRepr, Serialize, Deserialize, JsonSchema)] #[derive(Clone, Copy, Debug, PartialEq, Eq, FromRepr, Serialize, Deserialize, JsonSchema)]
pub enum PodType { pub enum PodType {
None = 0,
MockSigned = 1, MockSigned = 1,
MockMain = 2, MockMain = 2,
MockEmpty = 3, MockEmpty = 3,
@ -611,7 +610,6 @@ pub enum PodType {
impl fmt::Display for PodType { impl fmt::Display for PodType {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self { match self {
PodType::None => write!(f, "None"),
PodType::MockSigned => write!(f, "MockSigned"), PodType::MockSigned => write!(f, "MockSigned"),
PodType::MockMain => write!(f, "MockMain"), PodType::MockMain => write!(f, "MockMain"),
PodType::MockEmpty => write!(f, "MockEmpty"), PodType::MockEmpty => write!(f, "MockEmpty"),
@ -837,34 +835,6 @@ pub trait PodSigner {
) -> Result<Box<dyn Pod>, Box<DynError>>; ) -> Result<Box<dyn Pod>, Box<DynError>>;
} }
// TODO: Delete once we have a fully working EmptyPod and a dumb SignedPod
// https://github.com/0xPARC/pod2/issues/246
/// This is a filler type that fulfills the Pod trait and always verifies. It's empty. This
/// can be used to simulate padding in a circuit.
#[derive(Debug, Clone)]
pub struct NonePod {}
impl Pod for NonePod {
fn params(&self) -> &Params {
panic!("NonePod doesn't have params");
}
fn verify(&self) -> Result<(), Box<DynError>> {
Ok(())
}
fn id(&self) -> PodId {
PodId(EMPTY_HASH)
}
fn pod_type(&self) -> (usize, &'static str) {
(PodType::None as usize, "None")
}
fn pub_self_statements(&self) -> Vec<Statement> {
Vec::new()
}
fn serialize_data(&self) -> serde_json::Value {
serde_json::Value::Null
}
}
#[derive(Debug)] #[derive(Debug)]
pub struct MainPodInputs<'a> { pub struct MainPodInputs<'a> {
pub signed_pods: &'a [&'a dyn Pod], pub signed_pods: &'a [&'a dyn Pod],