No Pod IDs (#394)
- middleware:
- Add `Statement::Intro`
- Add `SignedBy` native predicate and operation. The signature is auxiliary data to the operation
- Rename `PodSigner` to `Signer` with a new API (just for signing `RawValue`)
- Removed `NewEntry` operation. Use `ContainsFromEntries` instead
- Remove `KEY_SIGNER` and `KEY_TYPE` which are no longer used
- Merge `RecursivePod` and `Pod` traits
- Change the `Pod::deserialize_data` method to use `Self` instead of `Box<dyn Pod>`
- Extend `Pod` trait with these methods:
- `is_main`: when the pod is Main, in a (recursive) verification its vk will be checked to exist in the vd_set but not if it's intro pod
- `is_mock`: skip some verifications in the recursive mock MainPod verification
- `verifier_data_hash`
- `pod_id` renamed to `statements_hash`
- AnchoredKeys are now a pair of dictionary root and key
- Entry statements are now defined as Contains with literal arguments
- Operations that take Entries now use Contains statements with literal arguments
- frontend:
- Rename `SignedPod` to `SignedDict` (which now contains the dict, public key and signature, and can still `verify(self)`ed)
- The `SignedDict` keeps the method `get_statement` for convenience but now it returns a `Contains` statement that proves the existence of the key in the dict
- The `MainPodBuilder` automatically inserts a `Contains` statement when an operation is added that uses an entry as argument that was not yet "opened".
- Removed the `literal` methods from the `MainPodBuilder` that were loading literals to anchored keys: that was no longer needed after we introduced literal arguments
- backend
- Only verify inclusion of the verifying key into the vd_set if the pod is MainPod. A pod is not MainPod if the first statement is Intro.
- Reject intro pods that have non-intro statements
- Empty pod now returns an intro statement
- Don't insert a type statement automatically in MainPod and MockMainPod. We get rid of the type entry.
- Implement `SignedBy` operation, which uses the muxed table to store signature verifications
- Rename `PodId` to `statements_hash` or `sts_hash` for short. Now this is only used as a hash of the statements for the circuits public inputs.
- Refactor normalization of `self` statements:
- Before: replace values that contain `SELF` by the given pod_id
- After: place the verifying key hash into the Intro predicates
This commit is contained in:
parent
122f9c3cac
commit
0e2f7b756e
39 changed files with 2127 additions and 3064 deletions
|
|
@ -3,7 +3,6 @@ use plonky2::{
|
|||
hash::hash_types::HashOutTarget,
|
||||
iop::witness::{PartialWitness, WitnessWrite},
|
||||
plonk::{
|
||||
circuit_builder::CircuitBuilder,
|
||||
circuit_data::{self, CircuitConfig},
|
||||
proof::ProofWithPublicInputs,
|
||||
},
|
||||
|
|
@ -12,16 +11,16 @@ use serde::{Deserialize, Serialize};
|
|||
|
||||
use crate::{
|
||||
backends::plonky2::{
|
||||
basetypes::{Proof, C, D},
|
||||
basetypes::{CircuitBuilder, Proof, C, D},
|
||||
cache_get_standard_rec_main_pod_common_circuit_data,
|
||||
circuits::{
|
||||
common::{Flattenable, StatementTarget},
|
||||
mainpod::{calculate_id_circuit, PI_OFFSET_ID},
|
||||
mainpod::{calculate_statements_hash_circuit, PI_OFFSET_STATEMENTS_HASH},
|
||||
},
|
||||
deserialize_proof, deserialize_verifier_only,
|
||||
error::{Error, Result},
|
||||
hash_common_data,
|
||||
mainpod::{self, calculate_id},
|
||||
mainpod::{self, calculate_statements_hash},
|
||||
recursion::pad_circuit,
|
||||
serialization::{
|
||||
CircuitDataSerializer, VerifierCircuitDataSerializer, VerifierOnlyCircuitDataSerializer,
|
||||
|
|
@ -30,52 +29,57 @@ use crate::{
|
|||
},
|
||||
cache::{self, CacheEntry},
|
||||
middleware::{
|
||||
self, AnchoredKey, Hash, Params, Pod, PodId, PodType, RecursivePod, Statement, ToFields,
|
||||
VDSet, Value, VerifierOnlyCircuitData, F, HASH_SIZE, KEY_TYPE, SELF,
|
||||
self, Hash, IntroPredicateRef, Params, Pod, PodType, Statement, ToFields, VDSet,
|
||||
VerifierOnlyCircuitData, EMPTY_HASH, F, HASH_SIZE,
|
||||
},
|
||||
timed,
|
||||
};
|
||||
|
||||
struct EmptyPodVerifyCircuit {
|
||||
params: Params,
|
||||
}
|
||||
|
||||
fn type_statement() -> Statement {
|
||||
Statement::equal(
|
||||
AnchoredKey::from((SELF, KEY_TYPE)),
|
||||
Value::from(PodType::Empty),
|
||||
fn empty_statement() -> Statement {
|
||||
Statement::Intro(
|
||||
IntroPredicateRef {
|
||||
name: "empty".to_string(),
|
||||
args_len: 0,
|
||||
verifier_data_hash: EMPTY_HASH,
|
||||
},
|
||||
vec![],
|
||||
)
|
||||
}
|
||||
|
||||
impl EmptyPodVerifyCircuit {
|
||||
fn eval(&self, builder: &mut CircuitBuilder<F, D>) -> Result<EmptyPodVerifyTarget> {
|
||||
let type_statement = StatementTarget::from_flattened(
|
||||
&self.params,
|
||||
&builder.constants(&type_statement().to_fields(&self.params)),
|
||||
);
|
||||
let id = calculate_id_circuit(&self.params, builder, &[type_statement]);
|
||||
let vds_root = builder.add_virtual_hash();
|
||||
builder.register_public_inputs(&id.elements);
|
||||
builder.register_public_inputs(&vds_root.elements);
|
||||
Ok(EmptyPodVerifyTarget { vds_root })
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Serialize, Deserialize)]
|
||||
pub struct EmptyPodVerifyTarget {
|
||||
vds_root: HashOutTarget,
|
||||
}
|
||||
|
||||
impl EmptyPodVerifyTarget {
|
||||
pub fn new_virtual(builder: &mut CircuitBuilder) -> Self {
|
||||
Self {
|
||||
vds_root: builder.add_virtual_hash(),
|
||||
}
|
||||
}
|
||||
pub fn set_targets(&self, pw: &mut PartialWitness<F>, vds_root: Hash) -> Result<()> {
|
||||
Ok(pw.set_target_arr(&self.vds_root.elements, &vds_root.0)?)
|
||||
}
|
||||
}
|
||||
|
||||
fn verify_empty_pod_circuit(
|
||||
params: &Params,
|
||||
builder: &mut CircuitBuilder,
|
||||
empty_pod: &EmptyPodVerifyTarget,
|
||||
) {
|
||||
let empty_statement = StatementTarget::from_flattened(
|
||||
params,
|
||||
&builder.constants(&empty_statement().to_fields(params)),
|
||||
);
|
||||
let sts_hash = calculate_statements_hash_circuit(params, builder, &[empty_statement]);
|
||||
builder.register_public_inputs(&sts_hash.elements);
|
||||
builder.register_public_inputs(&empty_pod.vds_root.elements);
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
|
||||
pub struct EmptyPod {
|
||||
params: Params,
|
||||
id: PodId,
|
||||
sts_hash: Hash,
|
||||
verifier_only: VerifierOnlyCircuitDataSerializer,
|
||||
common_hash: String,
|
||||
vd_set: VDSet,
|
||||
|
|
@ -110,17 +114,15 @@ fn build() -> Result<(EmptyPodVerifyTarget, CircuitData)> {
|
|||
#[cfg(feature = "zk")]
|
||||
let config = CircuitConfig::standard_recursion_zk_config();
|
||||
|
||||
let mut builder = CircuitBuilder::<F, D>::new(config);
|
||||
let empty_pod_verify_target = EmptyPodVerifyCircuit {
|
||||
params: params.clone(),
|
||||
}
|
||||
.eval(&mut builder)?;
|
||||
let mut builder = CircuitBuilder::new(config);
|
||||
let empty_pod = EmptyPodVerifyTarget::new_virtual(&mut builder);
|
||||
verify_empty_pod_circuit(¶ms, &mut builder, &empty_pod);
|
||||
let common_circuit_data = &*cache_get_standard_rec_main_pod_common_circuit_data();
|
||||
pad_circuit(&mut builder, common_circuit_data);
|
||||
|
||||
let data = timed!("EmptyPod build", builder.build::<C>());
|
||||
assert_eq!(common_circuit_data.0, data.common);
|
||||
Ok((empty_pod_verify_target, data))
|
||||
Ok((empty_pod, data))
|
||||
}
|
||||
|
||||
impl EmptyPod {
|
||||
|
|
@ -130,19 +132,22 @@ impl EmptyPod {
|
|||
let mut pw = PartialWitness::<F>::new();
|
||||
empty_pod_verify_target.set_targets(&mut pw, vd_set.root())?;
|
||||
let proof = timed!("EmptyPod prove", data.prove(pw)?);
|
||||
let id = &proof.public_inputs[PI_OFFSET_ID..PI_OFFSET_ID + HASH_SIZE];
|
||||
let id = PodId(Hash([id[0], id[1], id[2], id[3]]));
|
||||
let sts_hash = {
|
||||
let v = &proof.public_inputs
|
||||
[PI_OFFSET_STATEMENTS_HASH..PI_OFFSET_STATEMENTS_HASH + HASH_SIZE];
|
||||
Hash([v[0], v[1], v[2], v[3]])
|
||||
};
|
||||
let common_hash = hash_common_data(&data.common).expect("hash ok");
|
||||
Ok(EmptyPod {
|
||||
params: params.clone(),
|
||||
verifier_only: VerifierOnlyCircuitDataSerializer(data.verifier_only.clone()),
|
||||
common_hash,
|
||||
id,
|
||||
sts_hash,
|
||||
vd_set,
|
||||
proof: proof.proof,
|
||||
})
|
||||
}
|
||||
pub fn new_boxed(params: &Params, vd_set: VDSet) -> Box<dyn RecursivePod> {
|
||||
pub fn new_boxed(params: &Params, vd_set: VDSet) -> Box<dyn Pod> {
|
||||
let default_params = Params::default();
|
||||
assert_eq!(default_params.id_params(), params.id_params());
|
||||
|
||||
|
|
@ -173,12 +178,12 @@ impl Pod for EmptyPod {
|
|||
.into_iter()
|
||||
.map(mainpod::Statement::from)
|
||||
.collect_vec();
|
||||
let id = PodId(calculate_id(&statements, &self.params));
|
||||
if id != self.id {
|
||||
return Err(Error::id_not_equal(self.id, id));
|
||||
let sts_hash = calculate_statements_hash(&statements, &self.params);
|
||||
if sts_hash != self.sts_hash {
|
||||
return Err(Error::statements_hash_not_equal(self.sts_hash, sts_hash));
|
||||
}
|
||||
|
||||
let public_inputs = id
|
||||
let public_inputs = sts_hash
|
||||
.to_fields(&self.params)
|
||||
.iter()
|
||||
.chain(self.vd_set.root().0.iter())
|
||||
|
|
@ -194,28 +199,17 @@ impl Pod for EmptyPod {
|
|||
.map_err(|e| Error::plonky2_proof_fail("EmptyPod", e))
|
||||
}
|
||||
|
||||
fn id(&self) -> PodId {
|
||||
self.id
|
||||
fn statements_hash(&self) -> Hash {
|
||||
self.sts_hash
|
||||
}
|
||||
fn pod_type(&self) -> (usize, &'static str) {
|
||||
(PodType::Empty as usize, "Empty")
|
||||
}
|
||||
|
||||
fn pub_self_statements(&self) -> Vec<middleware::Statement> {
|
||||
vec![type_statement()]
|
||||
vec![empty_statement()]
|
||||
}
|
||||
|
||||
fn serialize_data(&self) -> serde_json::Value {
|
||||
serde_json::to_value(Data {
|
||||
proof: serialize_proof(&self.proof),
|
||||
verifier_only: serialize_verifier_only(&self.verifier_only),
|
||||
common_hash: self.common_hash.clone(),
|
||||
})
|
||||
.expect("serialization to json")
|
||||
}
|
||||
}
|
||||
|
||||
impl RecursivePod for EmptyPod {
|
||||
fn verifier_data(&self) -> VerifierOnlyCircuitData {
|
||||
self.verifier_only.0.clone()
|
||||
}
|
||||
|
|
@ -228,24 +222,33 @@ impl RecursivePod for EmptyPod {
|
|||
fn vd_set(&self) -> &VDSet {
|
||||
&self.vd_set
|
||||
}
|
||||
|
||||
fn serialize_data(&self) -> serde_json::Value {
|
||||
serde_json::to_value(Data {
|
||||
proof: serialize_proof(&self.proof),
|
||||
verifier_only: serialize_verifier_only(&self.verifier_only),
|
||||
common_hash: self.common_hash.clone(),
|
||||
})
|
||||
.expect("serialization to json")
|
||||
}
|
||||
fn deserialize_data(
|
||||
params: Params,
|
||||
data: serde_json::Value,
|
||||
vd_set: VDSet,
|
||||
id: PodId,
|
||||
) -> Result<Box<dyn RecursivePod>> {
|
||||
sts_hash: Hash,
|
||||
) -> Result<Self> {
|
||||
let data: Data = serde_json::from_value(data)?;
|
||||
let common_circuit_data = cache_get_standard_rec_main_pod_common_circuit_data();
|
||||
let proof = deserialize_proof(&common_circuit_data, &data.proof)?;
|
||||
let verifier_only = deserialize_verifier_only(&data.verifier_only)?;
|
||||
Ok(Box::new(Self {
|
||||
Ok(Self {
|
||||
params,
|
||||
id,
|
||||
sts_hash,
|
||||
verifier_only: VerifierOnlyCircuitDataSerializer(verifier_only),
|
||||
common_hash: data.common_hash,
|
||||
vd_set,
|
||||
proof,
|
||||
}))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue