Featurize middleware types that are actually defined by the backend (#94)
At the middleware we were defining some types that actually are dependant on the backend no matter how we define them in the middleware. For example, we were hardcoding the `Hash` and `Value` types and their related behaviour (eg. `.to_fields()`) to be based on the length of 4 field elements, but that's not a choice of the middleware, and in fact this is determined by the backend itself. On the same time, those types and related methods do not belong to the backend, since conceptually they are part of the middleware reasoning. The intention of this PR is not to prematurely abstract the library, but to avoid inconsistencies where a type or parameter is defined in the middleware to have certain carachteristic and later in the backend it gets used differently. The idea is that those types and parameters (eg. lengths) have a single source of truth in the code; and in the case of the "base types" (hash, value, etc) this is determined by the backend being used under the hood, not by a choice of the middleware parameters. The idea with this approach, is that the frontend & middleware should not need to import the proving library used by the backend (eg. plonky2, plonky3, etc). As mentioned earlier, the `Hash` and `Value` types are types belonging at the middleware, and is the middleware who reasons about them, but depending on the backend being used, the `Hash` and `Value` types will have different sizes. So it's the backend being used who actually defines their nature under the hood. For example with a plonky2 backend, these types will have a length of 4 field elements, whereas with a plonky3 backend they will have a length of 8 field eleements. Note that his approach does not introduce new traits or abstract code, just makes use of rust features to define 'base types' that are being used in the middleware.
This commit is contained in:
parent
af46ab7a8d
commit
423605f867
18 changed files with 359 additions and 278 deletions
|
|
@ -1,159 +0,0 @@
|
|||
use anyhow::Result;
|
||||
use std::any::Any;
|
||||
use std::collections::HashMap;
|
||||
|
||||
use crate::constants::MAX_DEPTH;
|
||||
use crate::middleware::{
|
||||
containers::Dictionary, hash_str, AnchoredKey, Hash, Params, Pod, PodId, PodSigner, PodType,
|
||||
Statement, Value, KEY_SIGNER, KEY_TYPE,
|
||||
};
|
||||
use crate::primitives::merkletree::MerkleTree;
|
||||
|
||||
pub struct MockSigner {
|
||||
pub pk: String,
|
||||
}
|
||||
|
||||
impl PodSigner for MockSigner {
|
||||
fn sign(&mut self, _params: &Params, kvs: &HashMap<Hash, Value>) -> Result<Box<dyn Pod>> {
|
||||
let mut kvs = kvs.clone();
|
||||
let pk_hash = hash_str(&self.pk);
|
||||
kvs.insert(hash_str(&KEY_SIGNER), Value(pk_hash.0));
|
||||
kvs.insert(hash_str(&KEY_TYPE), Value::from(PodType::MockSigned));
|
||||
|
||||
let dict = Dictionary::new(&kvs)?;
|
||||
let id = PodId(dict.commitment());
|
||||
let signature = format!("{}_signed_by_{}", id, pk_hash);
|
||||
Ok(Box::new(MockSignedPod {
|
||||
dict,
|
||||
id,
|
||||
signature,
|
||||
}))
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct MockSignedPod {
|
||||
id: PodId,
|
||||
signature: String,
|
||||
dict: Dictionary,
|
||||
}
|
||||
|
||||
impl Pod for MockSignedPod {
|
||||
fn verify(&self) -> bool {
|
||||
// Verify type
|
||||
let value_at_type = match self.dict.get(&hash_str(&KEY_TYPE).into()) {
|
||||
Ok(v) => v,
|
||||
Err(_) => return false,
|
||||
};
|
||||
if Value::from(PodType::MockSigned) != value_at_type {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Verify id
|
||||
let mt = match MerkleTree::new(
|
||||
MAX_DEPTH,
|
||||
&self
|
||||
.dict
|
||||
.iter()
|
||||
.map(|(&k, &v)| (k, v))
|
||||
.collect::<HashMap<Value, Value>>(),
|
||||
) {
|
||||
Ok(mt) => mt,
|
||||
Err(_) => return false,
|
||||
};
|
||||
let id = PodId(mt.root());
|
||||
if id != self.id {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Verify signature
|
||||
let pk_hash = match self.dict.get(&hash_str(&KEY_SIGNER).into()) {
|
||||
Ok(v) => v,
|
||||
Err(_) => return false,
|
||||
};
|
||||
let signature = format!("{}_signed_by_{}", id, pk_hash);
|
||||
if signature != self.signature {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
fn id(&self) -> PodId {
|
||||
self.id
|
||||
}
|
||||
|
||||
fn pub_statements(&self) -> Vec<Statement> {
|
||||
let id = self.id();
|
||||
self.dict
|
||||
.iter()
|
||||
.map(|(k, v)| Statement::ValueOf(AnchoredKey(id, Hash(k.0)), *v))
|
||||
.collect()
|
||||
}
|
||||
|
||||
fn into_any(self: Box<Self>) -> Box<dyn Any> {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
pub mod tests {
|
||||
use plonky2::field::types::Field;
|
||||
use std::iter;
|
||||
|
||||
use super::*;
|
||||
use crate::constants::MAX_DEPTH;
|
||||
use crate::frontend;
|
||||
use crate::middleware::{self, F, NULL};
|
||||
|
||||
#[test]
|
||||
fn test_mock_signed_0() -> Result<()> {
|
||||
let params = middleware::Params::default();
|
||||
let mut pod = frontend::SignedPodBuilder::new(¶ms);
|
||||
pod.insert("idNumber", "4242424242");
|
||||
pod.insert("dateOfBirth", 1169909384);
|
||||
pod.insert("socialSecurityNumber", "G2121210");
|
||||
|
||||
let mut signer = MockSigner { pk: "Molly".into() };
|
||||
let pod = pod.sign(&mut signer).unwrap();
|
||||
let pod = pod.pod.into_any().downcast::<MockSignedPod>().unwrap();
|
||||
|
||||
assert_eq!(pod.verify(), true);
|
||||
println!("id: {}", pod.id());
|
||||
println!("kvs: {:?}", pod.kvs());
|
||||
|
||||
let mut bad_pod = pod.clone();
|
||||
bad_pod.signature = "".into();
|
||||
assert_eq!(bad_pod.verify(), false);
|
||||
|
||||
let mut bad_pod = pod.clone();
|
||||
bad_pod.id.0 .0[0] = F::ZERO;
|
||||
assert_eq!(bad_pod.verify(), false);
|
||||
|
||||
let mut bad_pod = pod.clone();
|
||||
let bad_kv = (hash_str(KEY_SIGNER).into(), Value(PodId(NULL).0 .0));
|
||||
let bad_kvs_mt = &bad_pod
|
||||
.kvs()
|
||||
.into_iter()
|
||||
.map(|(AnchoredKey(_, k), v)| (Value(k.0), v))
|
||||
.chain(iter::once(bad_kv))
|
||||
.collect::<HashMap<Value, Value>>();
|
||||
let bad_mt = MerkleTree::new(MAX_DEPTH, &bad_kvs_mt)?;
|
||||
bad_pod.dict.mt = bad_mt;
|
||||
assert_eq!(bad_pod.verify(), false);
|
||||
|
||||
let mut bad_pod = pod.clone();
|
||||
let bad_kv = (hash_str(KEY_TYPE).into(), Value::from(0));
|
||||
let bad_kvs_mt = &bad_pod
|
||||
.kvs()
|
||||
.into_iter()
|
||||
.map(|(AnchoredKey(_, k), v)| (Value(k.0), v))
|
||||
.chain(iter::once(bad_kv))
|
||||
.collect::<HashMap<Value, Value>>();
|
||||
let bad_mt = MerkleTree::new(MAX_DEPTH, &bad_kvs_mt)?;
|
||||
bad_pod.dict.mt = bad_mt;
|
||||
assert_eq!(bad_pod.verify(), false);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue