Refactor frontend/middleware types (#194)
* unify fe/be NativeOp and NativePred * remove Origin in favour of PodId * Combine string and hash in Key * use middleware::AnchoredKey in frontend * merge frontend/middleware types * refactor custom predicates * clean up a bit * fix middleware custom tests * clean up * clean up 2 * add acronyms in typos list
This commit is contained in:
parent
9e860ef262
commit
c232c8dae5
33 changed files with 1985 additions and 2800 deletions
|
|
@ -2,37 +2,10 @@
|
|||
//! `backend_plonky2` feature is enabled.
|
||||
//! See src/middleware/basetypes.rs for more details.
|
||||
|
||||
use std::{
|
||||
cmp::{Ord, Ordering},
|
||||
fmt,
|
||||
};
|
||||
use plonky2::plonk::{config::PoseidonGoldilocksConfig, proof::Proof as Plonky2Proof};
|
||||
|
||||
use anyhow::{anyhow, Error, Result};
|
||||
use hex::{FromHex, FromHexError};
|
||||
use plonky2::{
|
||||
field::{
|
||||
goldilocks_field::GoldilocksField,
|
||||
types::{Field, PrimeField64},
|
||||
},
|
||||
hash::poseidon::PoseidonHash,
|
||||
plonk::{
|
||||
config::{Hasher, PoseidonGoldilocksConfig},
|
||||
proof::Proof as Plonky2Proof,
|
||||
},
|
||||
};
|
||||
use schemars::JsonSchema;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use crate::middleware::F;
|
||||
|
||||
use crate::middleware::{
|
||||
serialization::{
|
||||
deserialize_hash_tuple, deserialize_value_tuple, serialize_hash_tuple,
|
||||
serialize_value_tuple,
|
||||
},
|
||||
Params, ToFields,
|
||||
};
|
||||
|
||||
/// F is the native field we use everywhere. Currently it's Goldilocks from plonky2
|
||||
pub type F = GoldilocksField;
|
||||
/// C is the Plonky2 config used in POD2 to work with Plonky2 recursion.
|
||||
pub type C = PoseidonGoldilocksConfig;
|
||||
/// D defines the extension degree of the field used in the Plonky2 proofs (quadratic extension).
|
||||
|
|
@ -40,228 +13,3 @@ pub const D: usize = 2;
|
|||
|
||||
/// proof system proof
|
||||
pub type Proof = Plonky2Proof<F, PoseidonGoldilocksConfig, D>;
|
||||
|
||||
pub const HASH_SIZE: usize = 4;
|
||||
pub const VALUE_SIZE: usize = 4;
|
||||
|
||||
pub const EMPTY_VALUE: Value = Value([F::ZERO, F::ZERO, F::ZERO, F::ZERO]);
|
||||
pub const SELF_ID_HASH: Hash = Hash([F::ONE, F::ZERO, F::ZERO, F::ZERO]);
|
||||
pub const EMPTY_HASH: Hash = Hash([F::ZERO, F::ZERO, F::ZERO, F::ZERO]);
|
||||
|
||||
#[derive(Clone, Copy, Debug, Default, Hash, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
|
||||
#[schemars(rename = "MiddlewareValue")]
|
||||
pub struct Value(
|
||||
#[serde(
|
||||
serialize_with = "serialize_value_tuple",
|
||||
deserialize_with = "deserialize_value_tuple"
|
||||
)]
|
||||
// We know that Serde will serialize and deserialize this as a string, so we can
|
||||
// use the JsonSchema to validate the format.
|
||||
#[schemars(with = "String", regex(pattern = r"^[0-9a-fA-F]{64}$"))]
|
||||
pub [F; VALUE_SIZE],
|
||||
);
|
||||
|
||||
impl ToFields for Value {
|
||||
fn to_fields(&self, _params: &Params) -> Vec<F> {
|
||||
self.0.to_vec()
|
||||
}
|
||||
}
|
||||
|
||||
impl Value {
|
||||
pub fn to_bytes(self) -> Vec<u8> {
|
||||
self.0
|
||||
.iter()
|
||||
.flat_map(|e| e.to_canonical_u64().to_le_bytes())
|
||||
.collect()
|
||||
}
|
||||
}
|
||||
|
||||
impl Ord for Value {
|
||||
fn cmp(&self, other: &Self) -> Ordering {
|
||||
for (lhs, rhs) in self.0.iter().zip(other.0.iter()).rev() {
|
||||
let (lhs, rhs) = (lhs.to_canonical_u64(), rhs.to_canonical_u64());
|
||||
match lhs.cmp(&rhs) {
|
||||
Ordering::Less => return Ordering::Less,
|
||||
Ordering::Greater => return Ordering::Greater,
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
Ordering::Equal
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialOrd for Value {
|
||||
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
|
||||
Some(self.cmp(other))
|
||||
}
|
||||
}
|
||||
|
||||
impl From<i64> for Value {
|
||||
fn from(v: i64) -> Self {
|
||||
let lo = F::from_canonical_u64((v as u64) & 0xffffffff);
|
||||
let hi = F::from_canonical_u64((v as u64) >> 32);
|
||||
Value([lo, hi, F::ZERO, F::ZERO])
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Hash> for Value {
|
||||
fn from(h: Hash) -> Self {
|
||||
Value(h.0)
|
||||
}
|
||||
}
|
||||
|
||||
impl TryInto<i64> for Value {
|
||||
type Error = Error;
|
||||
fn try_into(self) -> std::result::Result<i64, Self::Error> {
|
||||
let value = self.0;
|
||||
if value[2..] != [F::ZERO, F::ZERO]
|
||||
|| value[..2]
|
||||
.iter()
|
||||
.all(|x| x.to_canonical_u64() > u32::MAX as u64)
|
||||
{
|
||||
Err(anyhow!("Value not an element of the i64 embedding."))
|
||||
} else {
|
||||
Ok((value[0].to_canonical_u64() | (value[1].to_canonical_u64() << 32)) as i64)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for Value {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
if self.0[2].is_zero() && self.0[3].is_zero() {
|
||||
// Assume this is an integer
|
||||
let (l0, l1) = (self.0[0].to_canonical_u64(), self.0[1].to_canonical_u64());
|
||||
assert!(l0 < (1 << 32));
|
||||
assert!(l1 < (1 << 32));
|
||||
write!(f, "{}", l0 + l1 * (1 << 32))
|
||||
} else {
|
||||
// Assume this is a hash
|
||||
Hash(self.0).fmt(f)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, Default, Hash, Eq, PartialEq, Serialize, Deserialize, JsonSchema)]
|
||||
pub struct Hash(
|
||||
#[serde(
|
||||
serialize_with = "serialize_hash_tuple",
|
||||
deserialize_with = "deserialize_hash_tuple"
|
||||
)]
|
||||
#[schemars(with = "String", regex(pattern = r"^[0-9a-fA-F]{64}$"))]
|
||||
pub [F; HASH_SIZE],
|
||||
);
|
||||
|
||||
pub fn hash_value(input: &Value) -> Hash {
|
||||
hash_fields(&input.0)
|
||||
}
|
||||
|
||||
pub fn hash_fields(input: &[F]) -> Hash {
|
||||
Hash(PoseidonHash::hash_no_pad(input).elements)
|
||||
}
|
||||
|
||||
impl From<Value> for Hash {
|
||||
fn from(v: Value) -> Self {
|
||||
Hash(v.0)
|
||||
}
|
||||
}
|
||||
impl Hash {
|
||||
pub fn value(self) -> Value {
|
||||
Value(self.0)
|
||||
}
|
||||
}
|
||||
|
||||
impl ToFields for Hash {
|
||||
fn to_fields(&self, _params: &Params) -> Vec<F> {
|
||||
self.0.to_vec()
|
||||
}
|
||||
}
|
||||
|
||||
impl Ord for Hash {
|
||||
fn cmp(&self, other: &Self) -> Ordering {
|
||||
Value(self.0).cmp(&Value(other.0))
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialOrd for Hash {
|
||||
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
|
||||
Some(self.cmp(other))
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for Hash {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
let v0 = self.0[0].to_canonical_u64();
|
||||
for i in 0..HASH_SIZE {
|
||||
write!(f, "{:02x}", (v0 >> (i * 8)) & 0xff)?;
|
||||
}
|
||||
write!(f, "…")
|
||||
}
|
||||
}
|
||||
|
||||
impl FromHex for Hash {
|
||||
type Error = FromHexError;
|
||||
|
||||
// TODO make it dependant on backend::Value len
|
||||
fn from_hex<T: AsRef<[u8]>>(hex: T) -> Result<Self, Self::Error> {
|
||||
// In little endian
|
||||
let bytes = <[u8; 32]>::from_hex(hex)?;
|
||||
let mut buf: [u8; 8] = [0; 8];
|
||||
let mut inner = [F::ZERO; HASH_SIZE];
|
||||
for i in 0..HASH_SIZE {
|
||||
buf.copy_from_slice(&bytes[8 * i..8 * (i + 1)]);
|
||||
inner[i] = F::from_canonical_u64(u64::from_le_bytes(buf));
|
||||
}
|
||||
Ok(Self(inner))
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&str> for Hash {
|
||||
fn from(s: &str) -> Self {
|
||||
hash_str(s)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn hash_str(s: &str) -> Hash {
|
||||
let mut input = s.as_bytes().to_vec();
|
||||
input.push(1); // padding
|
||||
|
||||
// Merge 7 bytes into 1 field, because the field is slightly below 64 bits
|
||||
let input: Vec<F> = input
|
||||
.chunks(7)
|
||||
.map(|bytes| {
|
||||
let mut v: u64 = 0;
|
||||
for b in bytes.iter().rev() {
|
||||
v <<= 8;
|
||||
v += *b as u64;
|
||||
}
|
||||
F::from_canonical_u64(v)
|
||||
})
|
||||
.collect();
|
||||
hash_fields(&input)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_i64_value_roundtrip() {
|
||||
let test_cases = [
|
||||
0i64,
|
||||
1,
|
||||
-1,
|
||||
i64::MAX,
|
||||
i64::MIN,
|
||||
42,
|
||||
-42,
|
||||
1 << 32,
|
||||
-(1 << 32),
|
||||
];
|
||||
|
||||
for &original in test_cases.iter() {
|
||||
let value = Value::from(original);
|
||||
let roundtrip: i64 = value.try_into().unwrap();
|
||||
assert_eq!(original, roundtrip, "Failed roundtrip for {}", original);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ use crate::{
|
|||
primitives::merkletree::MerkleClaimAndProofTarget,
|
||||
},
|
||||
middleware::{
|
||||
NativeOperation, NativePredicate, Params, Predicate, StatementArg, ToFields, Value,
|
||||
NativeOperation, NativePredicate, Params, Predicate, RawValue, StatementArg, ToFields,
|
||||
EMPTY_VALUE, F, HASH_SIZE, OPERATION_ARG_F_LEN, OPERATION_AUX_F_LEN, STATEMENT_ARG_F_LEN,
|
||||
VALUE_SIZE,
|
||||
},
|
||||
|
|
@ -294,7 +294,7 @@ pub trait CircuitBuilderPod<F: RichField + Extendable<D>, const D: usize> {
|
|||
fn add_virtual_operation(&mut self, params: &Params) -> OperationTarget;
|
||||
fn select_value(&mut self, b: BoolTarget, x: ValueTarget, y: ValueTarget) -> ValueTarget;
|
||||
fn select_bool(&mut self, b: BoolTarget, x: BoolTarget, y: BoolTarget) -> BoolTarget;
|
||||
fn constant_value(&mut self, v: Value) -> ValueTarget;
|
||||
fn constant_value(&mut self, v: RawValue) -> ValueTarget;
|
||||
fn is_equal_slice(&mut self, xs: &[Target], ys: &[Target]) -> BoolTarget;
|
||||
|
||||
// Convenience methods for checking values.
|
||||
|
|
@ -365,7 +365,7 @@ impl CircuitBuilderPod<F, D> for CircuitBuilder<F, D> {
|
|||
BoolTarget::new_unsafe(self.select(b, x.target, y.target))
|
||||
}
|
||||
|
||||
fn constant_value(&mut self, v: Value) -> ValueTarget {
|
||||
fn constant_value(&mut self, v: RawValue) -> ValueTarget {
|
||||
ValueTarget {
|
||||
elements: std::array::from_fn(|i| {
|
||||
self.constant(F::from_noncanonical_u64(v.0[i].to_noncanonical_u64()))
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ use plonky2::{
|
|||
|
||||
use crate::{
|
||||
backends::plonky2::{
|
||||
basetypes::{Value, D, EMPTY_HASH, F, VALUE_SIZE},
|
||||
basetypes::D,
|
||||
circuits::{
|
||||
common::{
|
||||
CircuitBuilderPod, Flattenable, MerkleClaimTarget, OperationTarget,
|
||||
|
|
@ -24,8 +24,8 @@ use crate::{
|
|||
signedpod::SignedPod,
|
||||
},
|
||||
middleware::{
|
||||
hash_str, AnchoredKey, NativeOperation, NativePredicate, Params, PodType, Statement,
|
||||
StatementArg, ToFields, KEY_TYPE, SELF,
|
||||
AnchoredKey, NativeOperation, NativePredicate, Params, PodType, Statement, StatementArg,
|
||||
ToFields, Value, F, KEY_TYPE, SELF, VALUE_SIZE,
|
||||
},
|
||||
};
|
||||
|
||||
|
|
@ -304,7 +304,7 @@ impl OperationVerifyGadget {
|
|||
let st_code_ok = st.has_native_type(builder, &self.params, NativePredicate::ValueOf);
|
||||
|
||||
let expected_arg_prefix = builder.constants(
|
||||
&StatementArg::Key(AnchoredKey(SELF, EMPTY_HASH)).to_fields(&self.params)[..VALUE_SIZE],
|
||||
&StatementArg::Key(AnchoredKey::from((SELF, ""))).to_fields(&self.params)[..VALUE_SIZE],
|
||||
);
|
||||
let arg_prefix_ok =
|
||||
builder.is_equal_slice(&st.args[0].elements[..VALUE_SIZE], &expected_arg_prefix);
|
||||
|
|
@ -422,11 +422,13 @@ impl MainPodVerifyGadget {
|
|||
let type_statement = &pub_statements[0];
|
||||
// TODO: Store this hash in a global static with lazy init so that we don't have to
|
||||
// compute it every time.
|
||||
let key_type = hash_str(KEY_TYPE);
|
||||
let expected_type_statement = StatementTarget::from_flattened(
|
||||
&builder.constants(
|
||||
&Statement::ValueOf(AnchoredKey(SELF, key_type), Value::from(PodType::MockMain))
|
||||
.to_fields(params),
|
||||
&Statement::ValueOf(
|
||||
AnchoredKey::from((SELF, KEY_TYPE)),
|
||||
Value::from(PodType::MockMain),
|
||||
)
|
||||
.to_fields(params),
|
||||
),
|
||||
);
|
||||
builder.connect_flattenable(type_statement, &expected_type_statement);
|
||||
|
|
@ -541,7 +543,7 @@ mod tests {
|
|||
mainpod::{OperationArg, OperationAux},
|
||||
},
|
||||
},
|
||||
middleware::{OperationType, PodId},
|
||||
middleware::{OperationType, PodId, RawValue},
|
||||
};
|
||||
|
||||
fn operation_verify(
|
||||
|
|
@ -573,7 +575,7 @@ mod tests {
|
|||
.map(|pf| pf.into())
|
||||
.collect();
|
||||
|
||||
let operation_verify = OperationVerifyGadget {
|
||||
OperationVerifyGadget {
|
||||
params: params.clone(),
|
||||
}
|
||||
.eval(
|
||||
|
|
@ -634,10 +636,10 @@ mod tests {
|
|||
|
||||
// NewEntry
|
||||
let st1: mainpod::Statement =
|
||||
Statement::ValueOf(AnchoredKey(SELF, "hello".into()), 55.into()).into();
|
||||
Statement::ValueOf(AnchoredKey::from((SELF, "hello")), Value::from(55)).into();
|
||||
let st2: mainpod::Statement = Statement::ValueOf(
|
||||
AnchoredKey(PodId(Value::from(75).into()), "hello".into()),
|
||||
55.into(),
|
||||
AnchoredKey::from((PodId(RawValue::from(75).into()), "hello")),
|
||||
Value::from(55),
|
||||
)
|
||||
.into();
|
||||
let prev_statements = vec![st2];
|
||||
|
|
@ -665,13 +667,13 @@ mod tests {
|
|||
|
||||
// Eq
|
||||
let st2: mainpod::Statement = Statement::ValueOf(
|
||||
AnchoredKey(PodId(Value::from(75).into()), "world".into()),
|
||||
55.into(),
|
||||
AnchoredKey::from((PodId(RawValue::from(75).into()), "world")),
|
||||
Value::from(55),
|
||||
)
|
||||
.into();
|
||||
let st: mainpod::Statement = Statement::Equal(
|
||||
AnchoredKey(SELF, "hello".into()),
|
||||
AnchoredKey(PodId(Value::from(75).into()), "world".into()),
|
||||
AnchoredKey::from((SELF, "hello")),
|
||||
AnchoredKey::from((PodId(RawValue::from(75).into()), "world")),
|
||||
)
|
||||
.into();
|
||||
let op = mainpod::Operation(
|
||||
|
|
@ -684,13 +686,13 @@ mod tests {
|
|||
|
||||
// Lt
|
||||
let st2: mainpod::Statement = Statement::ValueOf(
|
||||
AnchoredKey(PodId(Value::from(88).into()), "hello".into()),
|
||||
56.into(),
|
||||
AnchoredKey::from((PodId(RawValue::from(88).into()), "hello")),
|
||||
Value::from(56),
|
||||
)
|
||||
.into();
|
||||
let st: mainpod::Statement = Statement::Lt(
|
||||
AnchoredKey(SELF, "hello".into()),
|
||||
AnchoredKey(PodId(Value::from(88).into()), "hello".into()),
|
||||
AnchoredKey::from((SELF, "hello")),
|
||||
AnchoredKey::from((PodId(RawValue::from(88).into()), "hello")),
|
||||
)
|
||||
.into();
|
||||
let op = mainpod::Operation(
|
||||
|
|
@ -711,16 +713,16 @@ mod tests {
|
|||
.collect();
|
||||
let mt = MerkleTree::new(params.max_depth_mt_gadget, &kvs)?;
|
||||
|
||||
let root = mt.root().into();
|
||||
let root_ak = AnchoredKey(PodId(Value::from(88).into()), "merkle root".into());
|
||||
let root = Value::from(mt.root());
|
||||
let root_ak = AnchoredKey::from((PodId(RawValue::from(88).into()), "merkle root"));
|
||||
|
||||
let key = 5.into();
|
||||
let key_ak = AnchoredKey(PodId(Value::from(88).into()), "key".into());
|
||||
let key_ak = AnchoredKey::from((PodId(RawValue::from(88).into()), "key"));
|
||||
|
||||
let no_key_pf = mt.prove_nonexistence(&key)?;
|
||||
|
||||
let root_st: mainpod::Statement = Statement::ValueOf(root_ak, root).into();
|
||||
let key_st: mainpod::Statement = Statement::ValueOf(key_ak, key).into();
|
||||
let root_st: mainpod::Statement = Statement::ValueOf(root_ak.clone(), root.clone()).into();
|
||||
let key_st: mainpod::Statement = Statement::ValueOf(key_ak.clone(), key.into()).into();
|
||||
let st: mainpod::Statement = Statement::NotContains(root_ak, key_ak).into();
|
||||
let op = mainpod::Operation(
|
||||
OperationType::Native(NativeOperation::NotContainsFromEntries),
|
||||
|
|
@ -729,7 +731,11 @@ mod tests {
|
|||
);
|
||||
|
||||
let merkle_proofs = vec![mainpod::MerkleClaimAndProof::try_from_middleware(
|
||||
¶ms, &root, &key, None, &no_key_pf,
|
||||
¶ms,
|
||||
&root.raw(),
|
||||
&key,
|
||||
None,
|
||||
&no_key_pf,
|
||||
)?];
|
||||
let prev_statements = vec![root_st, key_st];
|
||||
operation_verify(st, op, prev_statements, merkle_proofs.clone())?;
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ use plonky2::{
|
|||
|
||||
use crate::{
|
||||
backends::plonky2::{
|
||||
basetypes::{Value, D, EMPTY_VALUE, F},
|
||||
basetypes::D,
|
||||
circuits::common::{CircuitBuilderPod, StatementArgTarget, StatementTarget, ValueTarget},
|
||||
primitives::{
|
||||
merkletree::{MerkleProof, MerkleProofExistenceGadget, MerkleProofExistenceTarget},
|
||||
|
|
@ -22,7 +22,8 @@ use crate::{
|
|||
signedpod::SignedPod,
|
||||
},
|
||||
middleware::{
|
||||
hash_str, NativePredicate, Params, PodType, Predicate, ToFields, KEY_SIGNER, KEY_TYPE, SELF,
|
||||
hash_str, Key, NativePredicate, Params, PodType, Predicate, RawValue, ToFields, Value,
|
||||
EMPTY_VALUE, F, KEY_SIGNER, KEY_TYPE, SELF,
|
||||
},
|
||||
};
|
||||
|
||||
|
|
@ -48,7 +49,7 @@ impl SignedPodVerifyGadget {
|
|||
let type_mt_proof = &mt_proofs[0];
|
||||
let key_type = builder.constant_value(hash_str(KEY_TYPE).into());
|
||||
builder.connect_values(type_mt_proof.key, key_type);
|
||||
let value_type = builder.constant_value(Value::from(PodType::Signed));
|
||||
let value_type = builder.constant_value(Value::from(PodType::Signed).raw());
|
||||
builder.connect_values(type_mt_proof.value, value_type);
|
||||
|
||||
// 3.a. Verify signature
|
||||
|
|
@ -56,7 +57,7 @@ impl SignedPodVerifyGadget {
|
|||
|
||||
// 3.b. Verify signer (ie. signature.pk == merkletree.signer_leaf)
|
||||
let signer_mt_proof = &mt_proofs[1];
|
||||
let key_signer = builder.constant_value(hash_str(KEY_SIGNER).into());
|
||||
let key_signer = builder.constant_value(Key::from(KEY_SIGNER).raw());
|
||||
builder.connect_values(signer_mt_proof.key, key_signer);
|
||||
builder.connect_values(signer_mt_proof.value, signature.pk);
|
||||
|
||||
|
|
@ -122,21 +123,28 @@ impl SignedPodVerifyTarget {
|
|||
// - empty leaves (if needed)
|
||||
|
||||
// add proof verification of KEY_TYPE & KEY_SIGNER leaves
|
||||
let key_type_key = Value::from(hash_str(KEY_TYPE));
|
||||
let key_signer_key = Value::from(hash_str(KEY_SIGNER));
|
||||
let key_signer_value = [key_type_key, key_signer_key]
|
||||
let key_type_key = Key::from(KEY_TYPE);
|
||||
let key_signer_key = Key::from(KEY_SIGNER);
|
||||
let key_signer_value = [&key_type_key, &key_signer_key]
|
||||
.iter()
|
||||
.enumerate()
|
||||
.map(|(i, k)| {
|
||||
let (v, proof) = pod.dict.prove(k)?;
|
||||
self.mt_proofs[i].set_targets(pw, true, pod.dict.commitment(), proof, *k, v)?;
|
||||
self.mt_proofs[i].set_targets(
|
||||
pw,
|
||||
true,
|
||||
pod.dict.commitment(),
|
||||
proof,
|
||||
k.raw(),
|
||||
v.raw(),
|
||||
)?;
|
||||
Ok(v)
|
||||
})
|
||||
.collect::<Result<Vec<Value>>>()?[1];
|
||||
.collect::<Result<Vec<&Value>>>()?[1];
|
||||
|
||||
// add the verification of the rest of leaves
|
||||
let mut curr = 2; // since we already added key_type and key_signer
|
||||
for (k, v) in pod.dict.iter().sorted_by_key(|kv| kv.0) {
|
||||
for (k, v) in pod.dict.kvs().iter().sorted_by_key(|kv| kv.0.hash()) {
|
||||
if *k == key_type_key || *k == key_signer_key {
|
||||
// skip the key_type & key_signer leaves, since they have
|
||||
// already been checked
|
||||
|
|
@ -144,9 +152,16 @@ impl SignedPodVerifyTarget {
|
|||
}
|
||||
|
||||
let (obtained_v, proof) = pod.dict.prove(k)?;
|
||||
assert_eq!(obtained_v, *v); // sanity check
|
||||
assert_eq!(obtained_v, v); // sanity check
|
||||
|
||||
self.mt_proofs[curr].set_targets(pw, true, pod.dict.commitment(), proof, *k, *v)?;
|
||||
self.mt_proofs[curr].set_targets(
|
||||
pw,
|
||||
true,
|
||||
pod.dict.commitment(),
|
||||
proof,
|
||||
k.raw(),
|
||||
v.raw(),
|
||||
)?;
|
||||
curr += 1;
|
||||
}
|
||||
// sanity check
|
||||
|
|
@ -170,9 +185,9 @@ impl SignedPodVerifyTarget {
|
|||
}
|
||||
|
||||
// get the signer pk
|
||||
let pk = PublicKey(key_signer_value);
|
||||
let pk = PublicKey(key_signer_value.raw());
|
||||
// the msg signed is the pod.id
|
||||
let msg = Value::from(pod.id.0);
|
||||
let msg = RawValue::from(pod.id.0);
|
||||
|
||||
// set signature targets values
|
||||
self.signature
|
||||
|
|
|
|||
|
|
@ -11,13 +11,13 @@ use plonky2::{
|
|||
|
||||
use crate::{
|
||||
backends::plonky2::{
|
||||
basetypes::{C, D, F},
|
||||
basetypes::{C, D},
|
||||
circuits::mainpod::{MainPodVerifyCircuit, MainPodVerifyInput},
|
||||
mock::mainpod::{hash_statements, MockMainPod, Statement},
|
||||
signedpod::SignedPod,
|
||||
},
|
||||
middleware::{
|
||||
self, AnchoredKey, MainPodInputs, Params, Pod, PodId, PodProver, StatementArg, SELF,
|
||||
self, AnchoredKey, MainPodInputs, Params, Pod, PodId, PodProver, StatementArg, F, SELF,
|
||||
},
|
||||
};
|
||||
// TODO: Move the shared components between MockMainPod and MainPod to a common place.
|
||||
|
|
@ -136,10 +136,10 @@ impl Pod for MainPod {
|
|||
.1
|
||||
.iter()
|
||||
.map(|sa| match &sa {
|
||||
StatementArg::Key(AnchoredKey(pod_id, h)) if *pod_id == SELF => {
|
||||
StatementArg::Key(AnchoredKey(self.id(), *h))
|
||||
StatementArg::Key(AnchoredKey { pod_id, key }) if *pod_id == SELF => {
|
||||
StatementArg::Key(AnchoredKey::new(self.id(), key.clone()))
|
||||
}
|
||||
_ => *sa,
|
||||
_ => sa.clone(),
|
||||
})
|
||||
.collect(),
|
||||
)
|
||||
|
|
@ -168,61 +168,12 @@ pub mod tests {
|
|||
backends::plonky2::{
|
||||
mock::mainpod::MockProver, primitives::signature::SecretKey, signedpod::Signer,
|
||||
},
|
||||
examples::zu_kyc_sign_pod_builders,
|
||||
examples::{zu_kyc_pod_builder, zu_kyc_sign_pod_builders},
|
||||
frontend, middleware,
|
||||
middleware::Value,
|
||||
middleware::RawValue,
|
||||
op,
|
||||
};
|
||||
|
||||
// TODO: Use the method from examples once everything works
|
||||
pub fn zu_kyc_pod_builder(
|
||||
params: &Params,
|
||||
gov_id: &frontend::SignedPod,
|
||||
pay_stub: &frontend::SignedPod,
|
||||
sanction_list: &frontend::SignedPod,
|
||||
) -> Result<frontend::MainPodBuilder> {
|
||||
let sanction_set = match sanction_list.kvs.get("sanctionList") {
|
||||
Some(frontend::Value::Set(s)) => Ok(s),
|
||||
_ => Err(anyhow!("Missing sanction list!")),
|
||||
}?;
|
||||
let now_minus_18y: i64 = 1169909388;
|
||||
let now_minus_1y: i64 = 1706367566;
|
||||
|
||||
let gov_id_kvs = gov_id.kvs();
|
||||
let id_number_value = gov_id_kvs.get(&"idNumber".into()).unwrap();
|
||||
|
||||
let mut kyc = frontend::MainPodBuilder::new(params);
|
||||
kyc.add_signed_pod(gov_id);
|
||||
kyc.add_signed_pod(pay_stub);
|
||||
kyc.add_signed_pod(sanction_list);
|
||||
kyc.pub_op(op!(
|
||||
set_not_contains,
|
||||
(sanction_list, "sanctionList"),
|
||||
(gov_id, "idNumber"),
|
||||
sanction_set
|
||||
.middleware_set()
|
||||
.prove_nonexistence(id_number_value)?
|
||||
))?;
|
||||
kyc.pub_op(op!(lt, (gov_id, "dateOfBirth"), now_minus_18y))?;
|
||||
kyc.pub_op(op!(
|
||||
eq,
|
||||
(gov_id, "socialSecurityNumber"),
|
||||
(pay_stub, "socialSecurityNumber")
|
||||
))?;
|
||||
let start_date_st = kyc.pub_op(frontend::Operation(
|
||||
frontend::OperationType::Native(frontend::NativeOperation::NewEntry),
|
||||
vec![frontend::OperationArg::Entry(
|
||||
"startDate".to_string(),
|
||||
now_minus_1y.into(),
|
||||
)],
|
||||
middleware::OperationAux::None,
|
||||
))?;
|
||||
kyc.pub_op(op!(eq, (pay_stub, "startDate"), start_date_st))?;
|
||||
kyc.pub_op(op!(eq, (pay_stub, "startDate"), now_minus_1y))?;
|
||||
|
||||
Ok(kyc)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_main_zu_kyc() -> Result<()> {
|
||||
let params = middleware::Params {
|
||||
|
|
@ -232,15 +183,13 @@ pub mod tests {
|
|||
..Default::default()
|
||||
};
|
||||
|
||||
let sanctions_values = vec!["A343434340".into()];
|
||||
let sanction_set = frontend::Value::Set(frontend::containers::Set::new(sanctions_values)?);
|
||||
let (gov_id_builder, pay_stub_builder, sanction_list_builder) =
|
||||
zu_kyc_sign_pod_builders(¶ms, &sanction_set);
|
||||
let mut signer = Signer(SecretKey(Value::from(1)));
|
||||
zu_kyc_sign_pod_builders(¶ms);
|
||||
let mut signer = Signer(SecretKey(RawValue::from(1)));
|
||||
let gov_id_pod = gov_id_builder.sign(&mut signer)?;
|
||||
let mut signer = Signer(SecretKey(Value::from(2)));
|
||||
let mut signer = Signer(SecretKey(RawValue::from(2)));
|
||||
let pay_stub_pod = pay_stub_builder.sign(&mut signer)?;
|
||||
let mut signer = Signer(SecretKey(Value::from(3)));
|
||||
let mut signer = Signer(SecretKey(RawValue::from(3)));
|
||||
let sanction_list_pod = sanction_list_builder.sign(&mut signer)?;
|
||||
let kyc_builder =
|
||||
zu_kyc_pod_builder(¶ms, &gov_id_pod, &pay_stub_pod, &sanction_list_pod)?;
|
||||
|
|
@ -267,7 +216,7 @@ pub mod tests {
|
|||
gov_id_builder.insert("idNumber", "4242424242");
|
||||
gov_id_builder.insert("dateOfBirth", 1169909384);
|
||||
gov_id_builder.insert("socialSecurityNumber", "G2121210");
|
||||
let mut signer = Signer(SecretKey(Value::from(42)));
|
||||
let mut signer = Signer(SecretKey(RawValue::from(42)));
|
||||
let gov_id = gov_id_builder.sign(&mut signer).unwrap();
|
||||
let now_minus_18y: i64 = 1169909388;
|
||||
let mut kyc_builder = frontend::MainPodBuilder::new(¶ms);
|
||||
|
|
|
|||
|
|
@ -1,10 +1,10 @@
|
|||
use std::{any::Any, fmt};
|
||||
|
||||
use anyhow::{anyhow, Result};
|
||||
use base64::prelude::*;
|
||||
// use base64::prelude::*;
|
||||
use plonky2::{hash::poseidon::PoseidonHash, plonk::config::Hasher};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
// use serde::{Deserialize, Serialize};
|
||||
use crate::{
|
||||
backends::plonky2::primitives::merkletree,
|
||||
middleware::{
|
||||
|
|
@ -27,7 +27,7 @@ impl PodProver for MockProver {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct MockMainPod {
|
||||
params: Params,
|
||||
id: PodId,
|
||||
|
|
@ -199,7 +199,7 @@ impl MockMainPod {
|
|||
// Public statements
|
||||
assert!(inputs.public_statements.len() < params.max_public_statements);
|
||||
let mut type_st = middleware::Statement::ValueOf(
|
||||
AnchoredKey(SELF, hash_str(KEY_TYPE)),
|
||||
AnchoredKey::from((SELF, KEY_TYPE)),
|
||||
middleware::Value::from(PodType::MockMain),
|
||||
)
|
||||
.into();
|
||||
|
|
@ -235,9 +235,9 @@ impl MockMainPod {
|
|||
pf,
|
||||
) => Some(MerkleClaimAndProof::try_from_middleware(
|
||||
params,
|
||||
root,
|
||||
key,
|
||||
Some(value),
|
||||
&root.raw(),
|
||||
&key.raw(),
|
||||
Some(&value.raw()),
|
||||
pf,
|
||||
)),
|
||||
middleware::Operation::NotContainsFromEntries(
|
||||
|
|
@ -245,7 +245,11 @@ impl MockMainPod {
|
|||
middleware::Statement::ValueOf(_, key),
|
||||
pf,
|
||||
) => Some(MerkleClaimAndProof::try_from_middleware(
|
||||
params, root, key, None, pf,
|
||||
params,
|
||||
&root.raw(),
|
||||
&key.raw(),
|
||||
None,
|
||||
pf,
|
||||
)),
|
||||
_ => None,
|
||||
})
|
||||
|
|
@ -417,14 +421,14 @@ impl MockMainPod {
|
|||
fill_pad(args, OperationArg::None, params.max_operation_args)
|
||||
}
|
||||
|
||||
pub fn deserialize(serialized: String) -> Result<Self> {
|
||||
let proof = String::from_utf8(BASE64_STANDARD.decode(&serialized)?)
|
||||
.map_err(|e| anyhow::anyhow!("Invalid base64 encoding: {}", e))?;
|
||||
let pod: MockMainPod = serde_json::from_str(&proof)
|
||||
.map_err(|e| anyhow::anyhow!("Failed to parse proof: {}", e))?;
|
||||
// pub fn deserialize(serialized: String) -> Result<Self> {
|
||||
// let proof = String::from_utf8(BASE64_STANDARD.decode(&serialized)?)
|
||||
// .map_err(|e| anyhow::anyhow!("Invalid base64 encoding: {}", e))?;
|
||||
// let pod: MockMainPod = serde_json::from_str(&proof)
|
||||
// .map_err(|e| anyhow::anyhow!("Failed to parse proof: {}", e))?;
|
||||
|
||||
Ok(pod)
|
||||
}
|
||||
// Ok(pod)
|
||||
// }
|
||||
}
|
||||
|
||||
pub fn hash_statements(statements: &[Statement], _params: &Params) -> middleware::Hash {
|
||||
|
|
@ -449,8 +453,8 @@ impl Pod for MockMainPod {
|
|||
let has_type_statement = self.public_statements.iter().any(|s| {
|
||||
s.0 == Predicate::Native(NativePredicate::ValueOf)
|
||||
&& !s.1.is_empty()
|
||||
&& if let StatementArg::Key(AnchoredKey(pod_id, key_hash)) = s.1[0] {
|
||||
pod_id == SELF && key_hash == hash_str(KEY_TYPE)
|
||||
&& if let StatementArg::Key(AnchoredKey { pod_id, ref key }) = s.1[0] {
|
||||
pod_id == SELF && key.hash() == hash_str(KEY_TYPE)
|
||||
} else {
|
||||
false
|
||||
}
|
||||
|
|
@ -477,7 +481,7 @@ impl Pod for MockMainPod {
|
|||
.filter(|(_, s)| s.0 == Predicate::Native(NativePredicate::ValueOf))
|
||||
.flat_map(|(i, s)| {
|
||||
if let StatementArg::Key(ak) = &s.1[0] {
|
||||
vec![(i, ak.1, ak.0)]
|
||||
vec![(i, ak.pod_id, ak.key.hash())]
|
||||
} else {
|
||||
vec![]
|
||||
}
|
||||
|
|
@ -536,10 +540,10 @@ impl Pod for MockMainPod {
|
|||
.1
|
||||
.iter()
|
||||
.map(|sa| match &sa {
|
||||
StatementArg::Key(AnchoredKey(pod_id, h)) if *pod_id == SELF => {
|
||||
StatementArg::Key(AnchoredKey(self.id(), *h))
|
||||
StatementArg::Key(AnchoredKey { pod_id, key }) if *pod_id == SELF => {
|
||||
StatementArg::Key(AnchoredKey::new(self.id(), key.clone()))
|
||||
}
|
||||
_ => *sa,
|
||||
_ => sa.clone(),
|
||||
})
|
||||
.collect(),
|
||||
)
|
||||
|
|
@ -557,7 +561,8 @@ impl Pod for MockMainPod {
|
|||
}
|
||||
|
||||
fn serialized_proof(&self) -> String {
|
||||
BASE64_STANDARD.encode(serde_json::to_string(self).unwrap())
|
||||
todo!()
|
||||
// BASE64_STANDARD.encode(serde_json::to_string(self).unwrap())
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -570,19 +575,14 @@ pub mod tests {
|
|||
great_boy_pod_full_flow, tickets_pod_full_flow, zu_kyc_pod_builder,
|
||||
zu_kyc_sign_pod_builders,
|
||||
},
|
||||
middleware,
|
||||
middleware::{self},
|
||||
};
|
||||
|
||||
#[test]
|
||||
fn test_mock_main_zu_kyc() -> Result<()> {
|
||||
let params = middleware::Params::default();
|
||||
let sanctions_values = ["A343434340"].map(|s| crate::frontend::Value::from(s));
|
||||
let sanction_set = crate::frontend::Value::Set(crate::frontend::containers::Set::new(
|
||||
sanctions_values.to_vec(),
|
||||
)?);
|
||||
|
||||
let (gov_id_builder, pay_stub_builder, sanction_list_builder) =
|
||||
zu_kyc_sign_pod_builders(¶ms, &sanction_set);
|
||||
zu_kyc_sign_pod_builders(¶ms);
|
||||
let mut signer = MockSigner {
|
||||
pk: "ZooGov".into(),
|
||||
};
|
||||
|
|
|
|||
|
|
@ -2,17 +2,19 @@ use std::{fmt, iter};
|
|||
|
||||
use anyhow::{anyhow, Result};
|
||||
use plonky2::field::types::Field;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
// use serde::{Deserialize, Serialize};
|
||||
use crate::{
|
||||
backends::plonky2::{
|
||||
mock::mainpod::Statement,
|
||||
primitives::merkletree::{self},
|
||||
},
|
||||
middleware::{self, Hash, OperationType, Params, ToFields, Value, EMPTY_HASH, EMPTY_VALUE, F},
|
||||
middleware::{
|
||||
self, Hash, OperationType, Params, RawValue, ToFields, EMPTY_HASH, EMPTY_VALUE, F,
|
||||
},
|
||||
};
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub enum OperationArg {
|
||||
None,
|
||||
Index(usize),
|
||||
|
|
@ -34,7 +36,7 @@ impl OperationArg {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub enum OperationAux {
|
||||
None,
|
||||
MerkleProofIndex(usize),
|
||||
|
|
@ -50,17 +52,17 @@ impl ToFields for OperationAux {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub struct MerkleClaimAndProof {
|
||||
pub enabled: bool,
|
||||
pub root: Hash,
|
||||
pub key: Value,
|
||||
pub value: Value,
|
||||
pub key: RawValue,
|
||||
pub value: RawValue,
|
||||
pub existence: bool,
|
||||
pub siblings: Vec<Hash>,
|
||||
pub case_ii_selector: bool,
|
||||
pub other_key: Value,
|
||||
pub other_value: Value,
|
||||
pub other_key: RawValue,
|
||||
pub other_value: RawValue,
|
||||
}
|
||||
|
||||
impl MerkleClaimAndProof {
|
||||
|
|
@ -68,7 +70,7 @@ impl MerkleClaimAndProof {
|
|||
Self {
|
||||
enabled: false,
|
||||
root: EMPTY_HASH,
|
||||
key: Value::from(1),
|
||||
key: RawValue::from(1),
|
||||
value: EMPTY_VALUE,
|
||||
existence: false,
|
||||
siblings: iter::repeat(EMPTY_HASH).take(max_depth).collect(),
|
||||
|
|
@ -79,9 +81,9 @@ impl MerkleClaimAndProof {
|
|||
}
|
||||
pub fn try_from_middleware(
|
||||
params: &Params,
|
||||
root: &Value,
|
||||
key: &Value,
|
||||
value: Option<&Value>,
|
||||
root: &RawValue,
|
||||
key: &RawValue,
|
||||
value: Option<&RawValue>,
|
||||
mid_mp: &merkletree::MerkleProof,
|
||||
) -> Result<Self> {
|
||||
if mid_mp.siblings.len() > params.max_depth_mt_gadget {
|
||||
|
|
@ -152,7 +154,7 @@ impl fmt::Display for MerkleClaimAndProof {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub struct Operation(pub OperationType, pub Vec<OperationArg>, pub OperationAux);
|
||||
|
||||
impl Operation {
|
||||
|
|
@ -209,7 +211,7 @@ impl fmt::Display for Operation {
|
|||
}
|
||||
match self.2 {
|
||||
OperationAux::None => (),
|
||||
OperationAux::MerkleProofIndex(i) => write!(f, "merkle_proof_{:02}", i)?,
|
||||
OperationAux::MerkleProofIndex(i) => write!(f, " merkle_proof_{:02}", i)?,
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,13 +1,13 @@
|
|||
use std::fmt;
|
||||
|
||||
use anyhow::{anyhow, Result};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
// use serde::{Deserialize, Serialize};
|
||||
use crate::middleware::{
|
||||
self, AnchoredKey, NativePredicate, Params, Predicate, StatementArg, ToFields,
|
||||
self, NativePredicate, Params, Predicate, StatementArg, ToFields, WildcardValue,
|
||||
};
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub struct Statement(pub Predicate, pub Vec<StatementArg>);
|
||||
|
||||
impl Statement {
|
||||
|
|
@ -81,15 +81,15 @@ impl TryFrom<Statement> for middleware::Statement {
|
|||
_ => Err(anyhow!("Ill-formed statement expression {:?}", s))?,
|
||||
},
|
||||
Predicate::Custom(cpr) => {
|
||||
let aks: Vec<AnchoredKey> = proper_args
|
||||
let vs: Vec<WildcardValue> = proper_args
|
||||
.into_iter()
|
||||
.filter_map(|arg| match arg {
|
||||
SA::None => None,
|
||||
SA::Key(ak) => Some(ak),
|
||||
SA::Literal(_) => unreachable!(),
|
||||
SA::WildcardLiteral(v) => Some(v),
|
||||
_ => unreachable!(),
|
||||
})
|
||||
.collect();
|
||||
S::Custom(cpr, aks)
|
||||
S::Custom(cpr, vs)
|
||||
}
|
||||
Predicate::BatchSelf(_) => {
|
||||
unreachable!()
|
||||
|
|
|
|||
|
|
@ -7,8 +7,8 @@ use crate::{
|
|||
backends::plonky2::primitives::merkletree::MerkleTree,
|
||||
constants::MAX_DEPTH,
|
||||
middleware::{
|
||||
containers::Dictionary, hash_str, AnchoredKey, Hash, Params, Pod, PodId, PodSigner,
|
||||
PodType, Statement, Value, KEY_SIGNER, KEY_TYPE,
|
||||
containers::Dictionary, hash_str, AnchoredKey, Hash, Key, Params, Pod, PodId, PodSigner,
|
||||
PodType, RawValue, Statement, Value, KEY_SIGNER, KEY_TYPE,
|
||||
},
|
||||
};
|
||||
|
||||
|
|
@ -17,26 +17,22 @@ pub struct MockSigner {
|
|||
}
|
||||
|
||||
impl MockSigner {
|
||||
pub fn pubkey(&self) -> Value {
|
||||
Value(hash_str(&self.pk).0)
|
||||
pub fn pubkey(&self) -> Hash {
|
||||
hash_str(&self.pk)
|
||||
}
|
||||
}
|
||||
|
||||
impl PodSigner for MockSigner {
|
||||
fn sign(&mut self, _params: &Params, kvs: &HashMap<Hash, Value>) -> Result<Box<dyn Pod>> {
|
||||
fn sign(&mut self, _params: &Params, kvs: &HashMap<Key, Value>) -> Result<Box<dyn Pod>> {
|
||||
let mut kvs = kvs.clone();
|
||||
let pubkey = self.pubkey();
|
||||
kvs.insert(hash_str(KEY_SIGNER), pubkey);
|
||||
kvs.insert(hash_str(KEY_TYPE), Value::from(PodType::MockSigned));
|
||||
kvs.insert(Key::from(KEY_SIGNER), Value::from(pubkey));
|
||||
kvs.insert(Key::from(KEY_TYPE), Value::from(PodType::MockSigned));
|
||||
|
||||
let dict = Dictionary::new(&kvs)?;
|
||||
let dict = Dictionary::new(kvs.clone())?;
|
||||
let id = PodId(dict.commitment());
|
||||
let signature = format!("{}_signed_by_{}", id, pubkey);
|
||||
Ok(Box::new(MockSignedPod {
|
||||
dict,
|
||||
id,
|
||||
signature,
|
||||
}))
|
||||
Ok(Box::new(MockSignedPod { id, signature, kvs }))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -44,18 +40,18 @@ impl PodSigner for MockSigner {
|
|||
pub struct MockSignedPod {
|
||||
id: PodId,
|
||||
signature: String,
|
||||
dict: Dictionary,
|
||||
kvs: HashMap<Key, Value>,
|
||||
}
|
||||
|
||||
impl MockSignedPod {
|
||||
pub fn deserialize(id: PodId, signature: String, dict: Dictionary) -> Self {
|
||||
Self {
|
||||
id,
|
||||
signature,
|
||||
dict,
|
||||
}
|
||||
}
|
||||
}
|
||||
// impl MockSignedPod {
|
||||
// pub fn deserialize(id: PodId, signature: String, dict: Dictionary) -> Self {
|
||||
// Self {
|
||||
// id,
|
||||
// signature,
|
||||
// dict,
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
impl Pod for MockSignedPod {
|
||||
fn verify(&self) -> Result<()> {
|
||||
|
|
@ -63,10 +59,10 @@ impl Pod for MockSignedPod {
|
|||
let mt = MerkleTree::new(
|
||||
MAX_DEPTH,
|
||||
&self
|
||||
.dict
|
||||
.kvs
|
||||
.iter()
|
||||
.map(|(&k, &v)| (k, v))
|
||||
.collect::<HashMap<Value, Value>>(),
|
||||
.map(|(k, v)| (k.raw(), v.raw()))
|
||||
.collect::<HashMap<RawValue, RawValue>>(),
|
||||
)?;
|
||||
let id = PodId(mt.root());
|
||||
if id != self.id {
|
||||
|
|
@ -78,8 +74,11 @@ impl Pod for MockSignedPod {
|
|||
}
|
||||
|
||||
// 2. Verify type
|
||||
let value_at_type = self.dict.get(&hash_str(KEY_TYPE).into())?;
|
||||
if Value::from(PodType::MockSigned) != value_at_type {
|
||||
let value_at_type = self
|
||||
.kvs
|
||||
.get(&Key::from(KEY_TYPE))
|
||||
.ok_or(anyhow!("key not found"))?;
|
||||
if &Value::from(PodType::MockSigned) != value_at_type {
|
||||
return Err(anyhow!(
|
||||
"type does not match, expected MockSigned ({}), found {}",
|
||||
PodType::MockSigned,
|
||||
|
|
@ -88,7 +87,10 @@ impl Pod for MockSignedPod {
|
|||
}
|
||||
|
||||
// 3. Verify signature
|
||||
let pk_hash = self.dict.get(&hash_str(KEY_SIGNER).into())?;
|
||||
let pk_hash = self
|
||||
.kvs
|
||||
.get(&Key::from(KEY_SIGNER))
|
||||
.ok_or(anyhow!("key not found"))?;
|
||||
let signature = format!("{}_signed_by_{}", id, pk_hash);
|
||||
if signature != self.signature {
|
||||
return Err(anyhow!(
|
||||
|
|
@ -108,15 +110,15 @@ impl Pod for MockSignedPod {
|
|||
fn pub_statements(&self) -> Vec<Statement> {
|
||||
let id = self.id();
|
||||
// By convention we put the KEY_TYPE first and KEY_SIGNER second
|
||||
let mut kvs: HashMap<_, _> = self.dict.iter().collect();
|
||||
let key_type = Value::from(hash_str(KEY_TYPE));
|
||||
let mut kvs = self.kvs.clone();
|
||||
let key_type = Key::from(KEY_TYPE);
|
||||
let value_type = kvs.remove(&key_type).expect("KEY_TYPE");
|
||||
let key_signer = Value::from(hash_str(KEY_SIGNER));
|
||||
let key_signer = Key::from(KEY_SIGNER);
|
||||
let value_signer = kvs.remove(&key_signer).expect("KEY_SIGNER");
|
||||
[(&key_type, value_type), (&key_signer, value_signer)]
|
||||
[(key_type, value_type), (key_signer, value_signer)]
|
||||
.into_iter()
|
||||
.chain(kvs.into_iter().sorted_by_key(|kv| kv.0))
|
||||
.map(|(k, v)| Statement::ValueOf(AnchoredKey(id, Hash(k.0)), *v))
|
||||
.chain(kvs.into_iter().sorted_by_key(|kv| kv.0.hash()))
|
||||
.map(|(k, v)| Statement::ValueOf(AnchoredKey::from((id, k)), v))
|
||||
.collect()
|
||||
}
|
||||
|
||||
|
|
@ -140,9 +142,8 @@ pub mod tests {
|
|||
|
||||
use super::*;
|
||||
use crate::{
|
||||
constants::MAX_DEPTH,
|
||||
frontend,
|
||||
middleware::{self, EMPTY_HASH, F},
|
||||
middleware::{self, EMPTY_VALUE, F},
|
||||
};
|
||||
|
||||
#[test]
|
||||
|
|
@ -170,27 +171,25 @@ pub mod tests {
|
|||
assert!(bad_pod.verify().is_err());
|
||||
|
||||
let mut bad_pod = pod.clone();
|
||||
let bad_kv = (hash_str(KEY_SIGNER).into(), Value(PodId(EMPTY_HASH).0 .0));
|
||||
let bad_kvs_mt = &bad_pod
|
||||
.kvs()
|
||||
let bad_kv = (Key::from(KEY_SIGNER), Value::from(EMPTY_VALUE));
|
||||
let bad_kvs = bad_pod
|
||||
.kvs
|
||||
.clone()
|
||||
.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;
|
||||
.collect::<HashMap<Key, Value>>();
|
||||
bad_pod.kvs = bad_kvs;
|
||||
assert!(bad_pod.verify().is_err());
|
||||
|
||||
let mut bad_pod = pod.clone();
|
||||
let bad_kv = (hash_str(KEY_TYPE).into(), Value::from(0));
|
||||
let bad_kvs_mt = &bad_pod
|
||||
.kvs()
|
||||
let bad_kv = (Key::from(KEY_TYPE), Value::from(0));
|
||||
let bad_kvs = bad_pod
|
||||
.kvs
|
||||
.clone()
|
||||
.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;
|
||||
.collect::<HashMap<Key, Value>>();
|
||||
bad_pod.kvs = bad_kvs;
|
||||
assert!(bad_pod.verify().is_err());
|
||||
|
||||
Ok(())
|
||||
|
|
|
|||
|
|
@ -4,10 +4,10 @@ use std::{collections::HashMap, fmt, iter::IntoIterator};
|
|||
|
||||
use anyhow::{anyhow, Result};
|
||||
use plonky2::field::types::Field;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
// use serde::{Deserialize, Serialize};
|
||||
pub use super::merkletree_circuit::*;
|
||||
use crate::backends::plonky2::basetypes::{hash_fields, Hash, Value, EMPTY_HASH, F};
|
||||
use crate::middleware::{hash_fields, Hash, RawValue, EMPTY_HASH, F};
|
||||
|
||||
/// Implements the MerkleTree specified at
|
||||
/// https://0xparc.github.io/pod2/merkletree.html
|
||||
|
|
@ -19,7 +19,7 @@ pub struct MerkleTree {
|
|||
|
||||
impl MerkleTree {
|
||||
/// builds a new `MerkleTree` where the leaves contain the given key-values
|
||||
pub fn new(max_depth: usize, kvs: &HashMap<Value, Value>) -> Result<Self> {
|
||||
pub fn new(max_depth: usize, kvs: &HashMap<RawValue, RawValue>) -> Result<Self> {
|
||||
// Construct leaves.
|
||||
let mut leaves: Vec<_> = kvs
|
||||
.iter()
|
||||
|
|
@ -50,7 +50,7 @@ impl MerkleTree {
|
|||
}
|
||||
|
||||
/// returns the value at the given key
|
||||
pub fn get(&self, key: &Value) -> Result<Value> {
|
||||
pub fn get(&self, key: &RawValue) -> Result<RawValue> {
|
||||
let path = keypath(self.max_depth, *key)?;
|
||||
let key_resolution = self.root.down(0, self.max_depth, path, None)?;
|
||||
match key_resolution {
|
||||
|
|
@ -60,7 +60,7 @@ impl MerkleTree {
|
|||
}
|
||||
|
||||
/// returns a boolean indicating whether the key exists in the tree
|
||||
pub fn contains(&self, key: &Value) -> Result<bool> {
|
||||
pub fn contains(&self, key: &RawValue) -> Result<bool> {
|
||||
let path = keypath(self.max_depth, *key)?;
|
||||
match self.root.down(0, self.max_depth, path, None) {
|
||||
Ok(Some((k, _))) => {
|
||||
|
|
@ -77,7 +77,7 @@ impl MerkleTree {
|
|||
/// returns a proof of existence, which proves that the given key exists in
|
||||
/// the tree. It returns the `value` of the leaf at the given `key`, and the
|
||||
/// `MerkleProof`.
|
||||
pub fn prove(&self, key: &Value) -> Result<(Value, MerkleProof)> {
|
||||
pub fn prove(&self, key: &RawValue) -> Result<(RawValue, MerkleProof)> {
|
||||
let path = keypath(self.max_depth, *key)?;
|
||||
|
||||
let mut siblings: Vec<Hash> = Vec::new();
|
||||
|
|
@ -102,7 +102,7 @@ impl MerkleTree {
|
|||
/// `key` does not exist in the tree. The return value specifies
|
||||
/// the key-value pair in the leaf reached as a result of
|
||||
/// resolving `key` as well as a `MerkleProof`.
|
||||
pub fn prove_nonexistence(&self, key: &Value) -> Result<MerkleProof> {
|
||||
pub fn prove_nonexistence(&self, key: &RawValue) -> Result<MerkleProof> {
|
||||
let path = keypath(self.max_depth, *key)?;
|
||||
|
||||
let mut siblings: Vec<Hash> = Vec::new();
|
||||
|
|
@ -134,8 +134,8 @@ impl MerkleTree {
|
|||
max_depth: usize,
|
||||
root: Hash,
|
||||
proof: &MerkleProof,
|
||||
key: &Value,
|
||||
value: &Value,
|
||||
key: &RawValue,
|
||||
value: &RawValue,
|
||||
) -> Result<()> {
|
||||
let h = proof.compute_root_from_leaf(max_depth, key, Some(*value))?;
|
||||
|
||||
|
|
@ -152,13 +152,13 @@ impl MerkleTree {
|
|||
max_depth: usize,
|
||||
root: Hash,
|
||||
proof: &MerkleProof,
|
||||
key: &Value,
|
||||
key: &RawValue,
|
||||
) -> Result<()> {
|
||||
match proof.other_leaf {
|
||||
Some((k, _v)) if &k == key => Err(anyhow!("Invalid non-existence proof.")),
|
||||
_ => {
|
||||
let k = proof.other_leaf.map(|(k, _)| k).unwrap_or(*key);
|
||||
let v: Option<Value> = proof.other_leaf.map(|(_, v)| v);
|
||||
let v: Option<RawValue> = proof.other_leaf.map(|(_, v)| v);
|
||||
let h = proof.compute_root_from_leaf(max_depth, &k, v)?;
|
||||
|
||||
if h != root {
|
||||
|
|
@ -180,14 +180,14 @@ impl MerkleTree {
|
|||
|
||||
/// Hash function for key-value pairs. Different branch pair hashes to
|
||||
/// mitigate fake proofs.
|
||||
pub fn kv_hash(key: &Value, value: Option<Value>) -> Hash {
|
||||
pub fn kv_hash(key: &RawValue, value: Option<RawValue>) -> Hash {
|
||||
value
|
||||
.map(|v| hash_fields(&[key.0.to_vec(), v.0.to_vec(), vec![F::ONE]].concat()))
|
||||
.unwrap_or(EMPTY_HASH)
|
||||
}
|
||||
|
||||
impl<'a> IntoIterator for &'a MerkleTree {
|
||||
type Item = (&'a Value, &'a Value);
|
||||
type Item = (&'a RawValue, &'a RawValue);
|
||||
type IntoIter = Iter<'a>;
|
||||
|
||||
fn into_iter(self) -> Self::IntoIter {
|
||||
|
|
@ -208,7 +208,7 @@ impl fmt::Display for MerkleTree {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub struct MerkleProof {
|
||||
// note: currently we don't use the `_existence` field, we would use if we merge the methods
|
||||
// `verify` and `verify_nonexistence` into a single one
|
||||
|
|
@ -216,7 +216,7 @@ pub struct MerkleProof {
|
|||
pub(crate) existence: bool,
|
||||
pub(crate) siblings: Vec<Hash>,
|
||||
// other_leaf is used for non-existence proofs
|
||||
pub(crate) other_leaf: Option<(Value, Value)>,
|
||||
pub(crate) other_leaf: Option<(RawValue, RawValue)>,
|
||||
}
|
||||
|
||||
impl fmt::Display for MerkleProof {
|
||||
|
|
@ -238,8 +238,8 @@ impl MerkleProof {
|
|||
fn compute_root_from_leaf(
|
||||
&self,
|
||||
max_depth: usize,
|
||||
key: &Value,
|
||||
value: Option<Value>,
|
||||
key: &RawValue,
|
||||
value: Option<RawValue>,
|
||||
) -> Result<Hash> {
|
||||
if self.siblings.len() >= max_depth {
|
||||
return Err(anyhow!("max depth reached"));
|
||||
|
|
@ -335,7 +335,7 @@ impl Node {
|
|||
max_depth: usize,
|
||||
path: Vec<bool>,
|
||||
mut siblings: Option<&mut Vec<Hash>>,
|
||||
) -> Result<Option<(Value, Value)>> {
|
||||
) -> Result<Option<(RawValue, RawValue)>> {
|
||||
if lvl >= max_depth {
|
||||
return Err(anyhow!("max depth reached"));
|
||||
}
|
||||
|
|
@ -494,11 +494,11 @@ impl Intermediate {
|
|||
struct Leaf {
|
||||
hash: Option<Hash>,
|
||||
path: Vec<bool>,
|
||||
key: Value,
|
||||
value: Value,
|
||||
key: RawValue,
|
||||
value: RawValue,
|
||||
}
|
||||
impl Leaf {
|
||||
fn new(max_depth: usize, key: Value, value: Value) -> Result<Self> {
|
||||
fn new(max_depth: usize, key: RawValue, value: RawValue) -> Result<Self> {
|
||||
Ok(Self {
|
||||
hash: None,
|
||||
path: keypath(max_depth, key)?,
|
||||
|
|
@ -523,7 +523,7 @@ impl Leaf {
|
|||
// max-depth? ie, what happens when two keys share the same path for more bits
|
||||
// than the max_depth?
|
||||
/// returns the path of the given key
|
||||
pub(crate) fn keypath(max_depth: usize, k: Value) -> Result<Vec<bool>> {
|
||||
pub(crate) fn keypath(max_depth: usize, k: RawValue) -> Result<Vec<bool>> {
|
||||
let bytes = k.to_bytes();
|
||||
if max_depth > 8 * bytes.len() {
|
||||
// note that our current keys are of Value type, which are 4 Goldilocks
|
||||
|
|
@ -545,7 +545,7 @@ pub struct Iter<'a> {
|
|||
}
|
||||
|
||||
impl<'a> Iterator for Iter<'a> {
|
||||
type Item = (&'a Value, &'a Value);
|
||||
type Item = (&'a RawValue, &'a RawValue);
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
let node = self.state.pop();
|
||||
|
|
@ -586,10 +586,10 @@ pub mod tests {
|
|||
if i == 1 {
|
||||
continue;
|
||||
}
|
||||
kvs.insert(Value::from(i), Value::from(1000 + i));
|
||||
kvs.insert(RawValue::from(i), RawValue::from(1000 + i));
|
||||
}
|
||||
let key = Value::from(13);
|
||||
let value = Value::from(1013);
|
||||
let key = RawValue::from(13);
|
||||
let value = RawValue::from(1013);
|
||||
kvs.insert(key, value);
|
||||
|
||||
let tree = MerkleTree::new(32, &kvs)?;
|
||||
|
|
@ -598,25 +598,25 @@ pub mod tests {
|
|||
println!("{}", tree);
|
||||
|
||||
// Inclusion checks
|
||||
let (v, proof) = tree.prove(&Value::from(13))?;
|
||||
assert_eq!(v, Value::from(1013));
|
||||
let (v, proof) = tree.prove(&RawValue::from(13))?;
|
||||
assert_eq!(v, RawValue::from(1013));
|
||||
println!("{}", proof);
|
||||
|
||||
MerkleTree::verify(32, tree.root(), &proof, &key, &value)?;
|
||||
|
||||
// Exclusion checks
|
||||
let key = Value::from(12);
|
||||
let key = RawValue::from(12);
|
||||
let proof = tree.prove_nonexistence(&key)?;
|
||||
assert_eq!(
|
||||
proof.other_leaf.unwrap(),
|
||||
(Value::from(4), Value::from(1004))
|
||||
(RawValue::from(4), RawValue::from(1004))
|
||||
);
|
||||
println!("{}", proof);
|
||||
|
||||
MerkleTree::verify_nonexistence(32, tree.root(), &proof, &key)?;
|
||||
|
||||
let key = Value::from(1);
|
||||
let proof = tree.prove_nonexistence(&Value::from(1))?;
|
||||
let key = RawValue::from(1);
|
||||
let proof = tree.prove_nonexistence(&RawValue::from(1))?;
|
||||
assert_eq!(proof.other_leaf, None);
|
||||
println!("{}", proof);
|
||||
|
||||
|
|
|
|||
|
|
@ -24,10 +24,13 @@ use plonky2::{
|
|||
plonk::circuit_builder::CircuitBuilder,
|
||||
};
|
||||
|
||||
use crate::backends::plonky2::{
|
||||
basetypes::{Hash, Value, D, EMPTY_HASH, EMPTY_VALUE, F, HASH_SIZE},
|
||||
circuits::common::{CircuitBuilderPod, ValueTarget},
|
||||
primitives::merkletree::MerkleProof,
|
||||
use crate::{
|
||||
backends::plonky2::{
|
||||
basetypes::D,
|
||||
circuits::common::{CircuitBuilderPod, ValueTarget},
|
||||
primitives::merkletree::MerkleProof,
|
||||
},
|
||||
middleware::{Hash, RawValue, EMPTY_HASH, EMPTY_VALUE, F, HASH_SIZE},
|
||||
};
|
||||
|
||||
/// `MerkleProofGadget` allows to verify both proofs of existence and proofs
|
||||
|
|
@ -163,8 +166,8 @@ impl MerkleClaimAndProofTarget {
|
|||
existence: bool,
|
||||
root: Hash,
|
||||
proof: MerkleProof,
|
||||
key: Value,
|
||||
value: Value,
|
||||
key: RawValue,
|
||||
value: RawValue,
|
||||
) -> Result<()> {
|
||||
pw.set_bool_target(self.enabled, enabled)?;
|
||||
pw.set_hash_target(self.root, HashOut::from_vec(root.0.to_vec()))?;
|
||||
|
|
@ -268,8 +271,8 @@ impl MerkleProofExistenceTarget {
|
|||
enabled: bool,
|
||||
root: Hash,
|
||||
proof: MerkleProof,
|
||||
key: Value,
|
||||
value: Value,
|
||||
key: RawValue,
|
||||
value: RawValue,
|
||||
) -> Result<()> {
|
||||
assert!(proof.existence); // sanity check
|
||||
|
||||
|
|
@ -405,9 +408,9 @@ pub mod tests {
|
|||
use plonky2::plonk::{circuit_builder::CircuitBuilder, circuit_data::CircuitConfig};
|
||||
|
||||
use super::*;
|
||||
use crate::backends::plonky2::{
|
||||
basetypes::{hash_value, C},
|
||||
primitives::merkletree::*,
|
||||
use crate::{
|
||||
backends::plonky2::{basetypes::C, primitives::merkletree::*},
|
||||
middleware::{hash_value, RawValue},
|
||||
};
|
||||
|
||||
#[test]
|
||||
|
|
@ -424,7 +427,7 @@ pub mod tests {
|
|||
let mut builder = CircuitBuilder::<F, D>::new(config);
|
||||
let mut pw = PartialWitness::<F>::new();
|
||||
|
||||
let key = Value::from(hash_value(&Value::from(i)));
|
||||
let key = RawValue::from(hash_value(&RawValue::from(i)));
|
||||
let expected_path = keypath(max_depth, key)?;
|
||||
|
||||
// small circuit logic to check
|
||||
|
|
@ -455,8 +458,8 @@ pub mod tests {
|
|||
#[test]
|
||||
fn test_kv_hash() -> Result<()> {
|
||||
for i in 0..10 {
|
||||
let key = Value::from(hash_value(&Value::from(i)));
|
||||
let value = Value::from(1000 + i);
|
||||
let key = RawValue::from(hash_value(&RawValue::from(i)));
|
||||
let value = RawValue::from(1000 + i);
|
||||
let h = kv_hash(&key, Some(value));
|
||||
|
||||
// circuit
|
||||
|
|
@ -502,20 +505,23 @@ pub mod tests {
|
|||
|
||||
// test logic to be reused both by the existence & nonexistence tests
|
||||
fn test_merkleproof_verify_opt(max_depth: usize, existence: bool) -> Result<()> {
|
||||
let mut kvs: HashMap<Value, Value> = HashMap::new();
|
||||
let mut kvs: HashMap<RawValue, RawValue> = HashMap::new();
|
||||
for i in 0..10 {
|
||||
kvs.insert(Value::from(hash_value(&Value::from(i))), Value::from(i));
|
||||
kvs.insert(
|
||||
RawValue::from(hash_value(&RawValue::from(i))),
|
||||
RawValue::from(i),
|
||||
);
|
||||
}
|
||||
|
||||
let tree = MerkleTree::new(max_depth, &kvs)?;
|
||||
|
||||
let (key, value, proof) = if existence {
|
||||
let key = Value::from(hash_value(&Value::from(5)));
|
||||
let key = RawValue::from(hash_value(&RawValue::from(5)));
|
||||
let (value, proof) = tree.prove(&key)?;
|
||||
assert_eq!(value, Value::from(5));
|
||||
assert_eq!(value, RawValue::from(5));
|
||||
(key, value, proof)
|
||||
} else {
|
||||
let key = Value::from(hash_value(&Value::from(200)));
|
||||
let key = RawValue::from(hash_value(&RawValue::from(200)));
|
||||
(key, EMPTY_VALUE, tree.prove_nonexistence(&key)?)
|
||||
};
|
||||
assert_eq!(proof.existence, existence);
|
||||
|
|
@ -559,16 +565,19 @@ pub mod tests {
|
|||
}
|
||||
|
||||
fn test_merkleproof_only_existence_verify_opt(max_depth: usize) -> Result<()> {
|
||||
let mut kvs: HashMap<Value, Value> = HashMap::new();
|
||||
let mut kvs: HashMap<RawValue, RawValue> = HashMap::new();
|
||||
for i in 0..10 {
|
||||
kvs.insert(Value::from(hash_value(&Value::from(i))), Value::from(i));
|
||||
kvs.insert(
|
||||
RawValue::from(hash_value(&RawValue::from(i))),
|
||||
RawValue::from(i),
|
||||
);
|
||||
}
|
||||
|
||||
let tree = MerkleTree::new(max_depth, &kvs)?;
|
||||
|
||||
let key = Value::from(hash_value(&Value::from(5)));
|
||||
let key = RawValue::from(hash_value(&RawValue::from(5)));
|
||||
let (value, proof) = tree.prove(&key)?;
|
||||
assert_eq!(value, Value::from(5));
|
||||
assert_eq!(value, RawValue::from(5));
|
||||
assert_eq!(proof.existence, true);
|
||||
|
||||
MerkleTree::verify(max_depth, tree.root(), &proof, &key, &value)?;
|
||||
|
|
@ -604,24 +613,28 @@ pub mod tests {
|
|||
// 5 13
|
||||
|
||||
let mut kvs = HashMap::new();
|
||||
kvs.insert(Value::from(0), Value::from(1000));
|
||||
kvs.insert(Value::from(2), Value::from(1002));
|
||||
kvs.insert(Value::from(5), Value::from(1005));
|
||||
kvs.insert(Value::from(13), Value::from(1013));
|
||||
kvs.insert(RawValue::from(0), RawValue::from(1000));
|
||||
kvs.insert(RawValue::from(2), RawValue::from(1002));
|
||||
kvs.insert(RawValue::from(5), RawValue::from(1005));
|
||||
kvs.insert(RawValue::from(13), RawValue::from(1013));
|
||||
|
||||
let max_depth = 5;
|
||||
let tree = MerkleTree::new(max_depth, &kvs)?;
|
||||
// existence
|
||||
test_merkletree_edgecase_opt(max_depth, &tree, Value::from(5))?;
|
||||
test_merkletree_edgecase_opt(max_depth, &tree, RawValue::from(5))?;
|
||||
// non-existence case i) expected leaf does not exist
|
||||
test_merkletree_edgecase_opt(max_depth, &tree, Value::from(1))?;
|
||||
test_merkletree_edgecase_opt(max_depth, &tree, RawValue::from(1))?;
|
||||
// non-existence case ii) expected leaf does exist but it has a different 'key'
|
||||
test_merkletree_edgecase_opt(max_depth, &tree, Value::from(21))?;
|
||||
test_merkletree_edgecase_opt(max_depth, &tree, RawValue::from(21))?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn test_merkletree_edgecase_opt(max_depth: usize, tree: &MerkleTree, key: Value) -> Result<()> {
|
||||
fn test_merkletree_edgecase_opt(
|
||||
max_depth: usize,
|
||||
tree: &MerkleTree,
|
||||
key: RawValue,
|
||||
) -> Result<()> {
|
||||
let contains = tree.contains(&key)?;
|
||||
// generate merkleproof
|
||||
let (value, proof) = if contains {
|
||||
|
|
@ -666,19 +679,19 @@ pub mod tests {
|
|||
|
||||
#[test]
|
||||
fn test_wrong_witness() -> Result<()> {
|
||||
let mut kvs: HashMap<Value, Value> = HashMap::new();
|
||||
let mut kvs: HashMap<RawValue, RawValue> = HashMap::new();
|
||||
for i in 0..10 {
|
||||
kvs.insert(Value::from(i), Value::from(i));
|
||||
kvs.insert(RawValue::from(i), RawValue::from(i));
|
||||
}
|
||||
let max_depth = 16;
|
||||
let tree = MerkleTree::new(max_depth, &kvs)?;
|
||||
|
||||
let key = Value::from(3);
|
||||
let key = RawValue::from(3);
|
||||
let (value, proof) = tree.prove(&key)?;
|
||||
|
||||
// build another tree with an extra key-value, so that it has a
|
||||
// different root
|
||||
kvs.insert(Value::from(100), Value::from(100));
|
||||
kvs.insert(RawValue::from(100), RawValue::from(100));
|
||||
let tree2 = MerkleTree::new(max_depth, &kvs)?;
|
||||
|
||||
MerkleTree::verify(max_depth, tree.root(), &proof, &key, &value)?;
|
||||
|
|
|
|||
|
|
@ -21,7 +21,10 @@ use plonky2::{
|
|||
};
|
||||
|
||||
pub use super::signature_circuit::*;
|
||||
use crate::backends::plonky2::basetypes::{Proof, Value, C, D, F, VALUE_SIZE};
|
||||
use crate::{
|
||||
backends::plonky2::basetypes::{Proof, C, D},
|
||||
middleware::{RawValue, F, VALUE_SIZE},
|
||||
};
|
||||
|
||||
lazy_static! {
|
||||
/// Signature prover parameters
|
||||
|
|
@ -45,10 +48,10 @@ pub struct ProverParams {
|
|||
pub struct VerifierParams(pub(crate) VerifierCircuitData<F, C, D>);
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct SecretKey(pub(crate) Value);
|
||||
pub struct SecretKey(pub(crate) RawValue);
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct PublicKey(pub(crate) Value);
|
||||
pub struct PublicKey(pub(crate) RawValue);
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct Signature(pub(crate) Proof);
|
||||
|
|
@ -57,16 +60,16 @@ pub struct Signature(pub(crate) Proof);
|
|||
impl SecretKey {
|
||||
pub fn new_rand() -> Self {
|
||||
// note: the `F::rand()` internally uses `rand::rngs::OsRng`
|
||||
Self(Value(std::array::from_fn(|_| F::rand())))
|
||||
Self(RawValue(std::array::from_fn(|_| F::rand())))
|
||||
}
|
||||
|
||||
pub fn public_key(&self) -> PublicKey {
|
||||
PublicKey(Value(PoseidonHash::hash_no_pad(&self.0 .0).elements))
|
||||
PublicKey(RawValue(PoseidonHash::hash_no_pad(&self.0 .0).elements))
|
||||
}
|
||||
|
||||
pub fn sign(&self, msg: Value) -> Result<Signature> {
|
||||
pub fn sign(&self, msg: RawValue) -> Result<Signature> {
|
||||
let pk = self.public_key();
|
||||
let s = Value(PoseidonHash::hash_no_pad(&[pk.0 .0, msg.0].concat()).elements);
|
||||
let s = RawValue(PoseidonHash::hash_no_pad(&[pk.0 .0, msg.0].concat()).elements);
|
||||
|
||||
let mut pw = PartialWitness::<F>::new();
|
||||
PP.circuit.set_targets(&mut pw, self.clone(), pk, msg, s)?;
|
||||
|
|
@ -108,9 +111,9 @@ impl Signature {
|
|||
Ok((builder, circuit))
|
||||
}
|
||||
|
||||
pub fn verify(&self, pk: &PublicKey, msg: Value) -> Result<()> {
|
||||
pub fn verify(&self, pk: &PublicKey, msg: RawValue) -> Result<()> {
|
||||
// prepare public inputs as [pk, msg, s]
|
||||
let s = Value(PoseidonHash::hash_no_pad(&[pk.0 .0, msg.0].concat()).elements);
|
||||
let s = RawValue(PoseidonHash::hash_no_pad(&[pk.0 .0, msg.0].concat()).elements);
|
||||
let public_inputs: Vec<F> = [pk.0 .0, msg.0, s.0].concat();
|
||||
|
||||
// verify plonky2 proof
|
||||
|
|
@ -122,16 +125,16 @@ impl Signature {
|
|||
}
|
||||
|
||||
fn dummy_public_inputs() -> Result<Vec<F>> {
|
||||
let sk = SecretKey(Value::from(0));
|
||||
let sk = SecretKey(RawValue::from(0));
|
||||
let pk = sk.public_key();
|
||||
let msg = Value::from(0);
|
||||
let s = Value(PoseidonHash::hash_no_pad(&[pk.0 .0, msg.0].concat()).elements);
|
||||
let msg = RawValue::from(0);
|
||||
let s = RawValue(PoseidonHash::hash_no_pad(&[pk.0 .0, msg.0].concat()).elements);
|
||||
Ok([pk.0 .0, msg.0, s.0].concat())
|
||||
}
|
||||
|
||||
fn dummy_signature() -> Result<Signature> {
|
||||
let sk = SecretKey(Value::from(0));
|
||||
let msg = Value::from(0);
|
||||
let sk = SecretKey(RawValue::from(0));
|
||||
let msg = RawValue::from(0);
|
||||
sk.sign(msg)
|
||||
}
|
||||
|
||||
|
|
@ -186,8 +189,8 @@ impl SignatureInternalCircuit {
|
|||
pw: &mut PartialWitness<F>,
|
||||
sk: SecretKey,
|
||||
pk: PublicKey,
|
||||
msg: Value,
|
||||
s: Value,
|
||||
msg: RawValue,
|
||||
s: RawValue,
|
||||
) -> Result<()> {
|
||||
pw.set_target_arr(&self.sk_targ, sk.0 .0.as_ref())?;
|
||||
pw.set_hash_target(self.pk_targ, HashOut::<F>::from_vec(pk.0 .0.to_vec()))?;
|
||||
|
|
@ -201,23 +204,23 @@ impl SignatureInternalCircuit {
|
|||
#[cfg(test)]
|
||||
pub mod tests {
|
||||
use super::*;
|
||||
use crate::backends::plonky2::basetypes::Hash;
|
||||
use crate::middleware::hash_str;
|
||||
|
||||
#[test]
|
||||
fn test_signature() -> Result<()> {
|
||||
let sk = SecretKey::new_rand();
|
||||
let pk = sk.public_key();
|
||||
|
||||
let msg = Value::from(42);
|
||||
let msg = RawValue::from(42);
|
||||
let sig = sk.sign(msg)?;
|
||||
sig.verify(&pk, msg)?;
|
||||
|
||||
// expect the signature verification to fail when using a different msg
|
||||
let v = sig.verify(&pk, Value::from(24));
|
||||
let v = sig.verify(&pk, RawValue::from(24));
|
||||
assert!(v.is_err(), "should fail to verify");
|
||||
|
||||
// perform a 2nd signature over another msg and verify it
|
||||
let msg_2 = Value::from(Hash::from("message"));
|
||||
let msg_2 = RawValue::from(hash_str("message"));
|
||||
let sig2 = sk.sign(msg_2)?;
|
||||
sig2.verify(&pk, msg_2)?;
|
||||
|
||||
|
|
@ -226,9 +229,9 @@ pub mod tests {
|
|||
|
||||
#[test]
|
||||
fn test_dummy_signature() -> Result<()> {
|
||||
let sk = SecretKey(Value::from(0));
|
||||
let sk = SecretKey(RawValue::from(0));
|
||||
let pk = sk.public_key();
|
||||
let msg = Value::from(0);
|
||||
let msg = RawValue::from(0);
|
||||
DUMMY_SIGNATURE.clone().verify(&pk, msg)?;
|
||||
|
||||
Ok(())
|
||||
|
|
|
|||
|
|
@ -22,12 +22,15 @@ use plonky2::{
|
|||
},
|
||||
};
|
||||
|
||||
use crate::backends::plonky2::{
|
||||
basetypes::{Hash, Proof, Value, C, D, EMPTY_HASH, EMPTY_VALUE, F, VALUE_SIZE},
|
||||
circuits::common::{CircuitBuilderPod, ValueTarget},
|
||||
primitives::signature::{
|
||||
PublicKey, SecretKey, Signature, DUMMY_PUBLIC_INPUTS, DUMMY_SIGNATURE,
|
||||
use crate::{
|
||||
backends::plonky2::{
|
||||
basetypes::{Proof, C, D},
|
||||
circuits::common::{CircuitBuilderPod, ValueTarget},
|
||||
primitives::signature::{
|
||||
PublicKey, SecretKey, Signature, DUMMY_PUBLIC_INPUTS, DUMMY_SIGNATURE,
|
||||
},
|
||||
},
|
||||
middleware::{Hash, RawValue, EMPTY_HASH, EMPTY_VALUE, F, VALUE_SIZE},
|
||||
};
|
||||
|
||||
lazy_static! {
|
||||
|
|
@ -81,12 +84,12 @@ impl SignatureVerifyGadget {
|
|||
let dummy_pi = DUMMY_PUBLIC_INPUTS.clone();
|
||||
|
||||
let pk_targ_dummy =
|
||||
builder.constant_value(Value(dummy_pi[..VALUE_SIZE].try_into().unwrap()));
|
||||
let msg_targ_dummy = builder.constant_value(Value(
|
||||
builder.constant_value(RawValue(dummy_pi[..VALUE_SIZE].try_into().unwrap()));
|
||||
let msg_targ_dummy = builder.constant_value(RawValue(
|
||||
dummy_pi[VALUE_SIZE..VALUE_SIZE * 2].try_into().unwrap(),
|
||||
));
|
||||
let s_targ_dummy =
|
||||
builder.constant_value(Value(dummy_pi[VALUE_SIZE * 2..].try_into().unwrap()));
|
||||
builder.constant_value(RawValue(dummy_pi[VALUE_SIZE * 2..].try_into().unwrap()));
|
||||
|
||||
// connect the {pk, msg, s} with the proof_targ.public_inputs conditionally
|
||||
let pk_targ_connect = builder.select_value(enabled, pk_targ, pk_targ_dummy);
|
||||
|
|
@ -129,7 +132,7 @@ impl SignatureVerifyTarget {
|
|||
pw: &mut PartialWitness<F>,
|
||||
enabled: bool,
|
||||
pk: PublicKey,
|
||||
msg: Value,
|
||||
msg: RawValue,
|
||||
signature: Signature,
|
||||
) -> Result<()> {
|
||||
pw.set_bool_target(self.enabled, enabled)?;
|
||||
|
|
@ -137,7 +140,7 @@ impl SignatureVerifyTarget {
|
|||
pw.set_target_arr(&self.msg.elements, &msg.0)?;
|
||||
|
||||
// note that this hash is checked again in-circuit at the `SignatureInternalCircuit`
|
||||
let s = Value(PoseidonHash::hash_no_pad(&[pk.0 .0, msg.0].concat()).elements);
|
||||
let s = RawValue(PoseidonHash::hash_no_pad(&[pk.0 .0, msg.0].concat()).elements);
|
||||
let public_inputs: Vec<F> = [pk.0 .0, msg.0, s.0].concat();
|
||||
|
||||
if enabled {
|
||||
|
|
@ -170,14 +173,14 @@ impl SignatureVerifyTarget {
|
|||
#[cfg(test)]
|
||||
pub mod tests {
|
||||
use super::*;
|
||||
use crate::backends::plonky2::{basetypes::Hash, primitives::signature::SecretKey};
|
||||
use crate::{backends::plonky2::primitives::signature::SecretKey, middleware::Hash};
|
||||
|
||||
#[test]
|
||||
fn test_signature_gadget() -> Result<()> {
|
||||
// generate a valid signature
|
||||
let sk = SecretKey::new_rand();
|
||||
let pk = sk.public_key();
|
||||
let msg = Value::from(42);
|
||||
let msg = RawValue::from(42);
|
||||
let sig = sk.sign(msg)?;
|
||||
sig.verify(&pk, msg)?;
|
||||
|
||||
|
|
@ -208,15 +211,15 @@ pub mod tests {
|
|||
// generate a valid signature
|
||||
let sk = SecretKey::new_rand();
|
||||
let pk = sk.public_key();
|
||||
let msg = Value::from(42);
|
||||
let msg = RawValue::from(42);
|
||||
let sig = sk.sign(msg)?;
|
||||
// verification should pass
|
||||
sig.verify(&pk, msg)?;
|
||||
|
||||
// replace the message, so that verifications should fail
|
||||
let msg = Value::from(24);
|
||||
let msg = RawValue::from(24);
|
||||
// expect signature native verification to fail
|
||||
let v = sig.verify(&pk, Value::from(24));
|
||||
let v = sig.verify(&pk, RawValue::from(24));
|
||||
assert!(v.is_err(), "should fail to verify");
|
||||
|
||||
// circuit
|
||||
|
|
|
|||
|
|
@ -10,22 +10,22 @@ use crate::{
|
|||
},
|
||||
constants::MAX_DEPTH,
|
||||
middleware::{
|
||||
containers::Dictionary, hash_str, AnchoredKey, Hash, Params, Pod, PodId, PodSigner,
|
||||
PodType, Statement, Value, KEY_SIGNER, KEY_TYPE,
|
||||
containers::Dictionary, AnchoredKey, Hash, Key, Params, Pod, PodId, PodSigner, PodType,
|
||||
RawValue, Statement, Value, KEY_SIGNER, KEY_TYPE,
|
||||
},
|
||||
};
|
||||
|
||||
pub struct Signer(pub SecretKey);
|
||||
|
||||
impl PodSigner for Signer {
|
||||
fn sign(&mut self, _params: &Params, kvs: &HashMap<Hash, Value>) -> Result<Box<dyn Pod>> {
|
||||
fn sign(&mut self, _params: &Params, kvs: &HashMap<Key, Value>) -> Result<Box<dyn Pod>> {
|
||||
let mut kvs = kvs.clone();
|
||||
let pubkey = self.0.public_key();
|
||||
kvs.insert(hash_str(KEY_SIGNER), pubkey.0);
|
||||
kvs.insert(hash_str(KEY_TYPE), Value::from(PodType::Signed));
|
||||
kvs.insert(Key::from(KEY_SIGNER), Value::from(pubkey.0));
|
||||
kvs.insert(Key::from(KEY_TYPE), Value::from(PodType::Signed));
|
||||
|
||||
let dict = Dictionary::new(&kvs)?;
|
||||
let id = Value::from(dict.commitment()); // PodId as Value
|
||||
let dict = Dictionary::new(kvs)?;
|
||||
let id = RawValue::from(dict.commitment()); // PodId as Value
|
||||
|
||||
let signature: Signature = self.0.sign(id)?;
|
||||
Ok(Box::new(SignedPod {
|
||||
|
|
@ -46,8 +46,8 @@ pub struct SignedPod {
|
|||
impl Pod for SignedPod {
|
||||
fn verify(&self) -> Result<()> {
|
||||
// 1. Verify type
|
||||
let value_at_type = self.dict.get(&hash_str(KEY_TYPE).into())?;
|
||||
if Value::from(PodType::Signed) != value_at_type {
|
||||
let value_at_type = self.dict.get(&Key::from(KEY_TYPE))?;
|
||||
if Value::from(PodType::Signed) != *value_at_type {
|
||||
return Err(anyhow!(
|
||||
"type does not match, expected Signed ({}), found {}",
|
||||
PodType::Signed,
|
||||
|
|
@ -60,9 +60,10 @@ impl Pod for SignedPod {
|
|||
MAX_DEPTH,
|
||||
&self
|
||||
.dict
|
||||
.kvs()
|
||||
.iter()
|
||||
.map(|(&k, &v)| (k, v))
|
||||
.collect::<HashMap<Value, Value>>(),
|
||||
.map(|(k, v)| (k.raw(), v.raw()))
|
||||
.collect::<HashMap<RawValue, RawValue>>(),
|
||||
)?;
|
||||
let id = PodId(mt.root());
|
||||
if id != self.id {
|
||||
|
|
@ -74,9 +75,9 @@ impl Pod for SignedPod {
|
|||
}
|
||||
|
||||
// 3. Verify signature
|
||||
let pk_value = self.dict.get(&hash_str(KEY_SIGNER).into())?;
|
||||
let pk = PublicKey(pk_value);
|
||||
self.signature.verify(&pk, Value::from(id.0))?;
|
||||
let pk_value = self.dict.get(&Key::from(KEY_SIGNER))?;
|
||||
let pk = PublicKey(pk_value.raw());
|
||||
self.signature.verify(&pk, RawValue::from(id.0))?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
|
@ -88,15 +89,15 @@ impl Pod for SignedPod {
|
|||
fn pub_statements(&self) -> Vec<Statement> {
|
||||
let id = self.id();
|
||||
// By convention we put the KEY_TYPE first and KEY_SIGNER second
|
||||
let mut kvs: HashMap<_, _> = self.dict.iter().collect();
|
||||
let key_type = Value::from(hash_str(KEY_TYPE));
|
||||
let mut kvs: HashMap<Key, Value> = self.dict.kvs().clone();
|
||||
let key_type = Key::from(KEY_TYPE);
|
||||
let value_type = kvs.remove(&key_type).expect("KEY_TYPE");
|
||||
let key_signer = Value::from(hash_str(KEY_SIGNER));
|
||||
let key_signer = Key::from(KEY_SIGNER);
|
||||
let value_signer = kvs.remove(&key_signer).expect("KEY_SIGNER");
|
||||
[(&key_type, value_type), (&key_signer, value_signer)]
|
||||
[(key_type, value_type), (key_signer, value_signer)]
|
||||
.into_iter()
|
||||
.chain(kvs.into_iter().sorted_by_key(|kv| kv.0))
|
||||
.map(|(k, v)| Statement::ValueOf(AnchoredKey(id, Hash(k.0)), *v))
|
||||
.chain(kvs.into_iter().sorted_by_key(|kv| kv.0.hash()))
|
||||
.map(|(k, v)| Statement::ValueOf(AnchoredKey::from((id, k)), v))
|
||||
.collect()
|
||||
}
|
||||
|
||||
|
|
@ -123,9 +124,8 @@ pub mod tests {
|
|||
|
||||
use super::*;
|
||||
use crate::{
|
||||
constants::MAX_DEPTH,
|
||||
frontend,
|
||||
middleware::{self, EMPTY_HASH, F},
|
||||
middleware::{self, EMPTY_VALUE, F},
|
||||
};
|
||||
|
||||
#[test]
|
||||
|
|
@ -147,7 +147,7 @@ pub mod tests {
|
|||
println!("kvs: {:?}", pod.kvs());
|
||||
|
||||
let mut bad_pod = pod.clone();
|
||||
bad_pod.signature = signer.0.sign(Value::from(42_i64))?;
|
||||
bad_pod.signature = signer.0.sign(RawValue::from(42_i64))?;
|
||||
assert!(bad_pod.verify().is_err());
|
||||
|
||||
let mut bad_pod = pod.clone();
|
||||
|
|
@ -155,27 +155,27 @@ pub mod tests {
|
|||
assert!(bad_pod.verify().is_err());
|
||||
|
||||
let mut bad_pod = pod.clone();
|
||||
let bad_kv = (hash_str(KEY_SIGNER).into(), Value(PodId(EMPTY_HASH).0 .0));
|
||||
let bad_kvs_mt = &bad_pod
|
||||
let bad_kv = (Key::from(KEY_SIGNER), Value::from(EMPTY_VALUE));
|
||||
let bad_kvs = bad_pod
|
||||
.dict
|
||||
.kvs()
|
||||
.clone()
|
||||
.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;
|
||||
.collect::<HashMap<Key, Value>>();
|
||||
bad_pod.dict = Dictionary::new(bad_kvs).unwrap();
|
||||
assert!(bad_pod.verify().is_err());
|
||||
|
||||
let mut bad_pod = pod.clone();
|
||||
let bad_kv = (hash_str(KEY_TYPE).into(), Value::from(0));
|
||||
let bad_kvs_mt = &bad_pod
|
||||
let bad_kv = (Key::from(KEY_TYPE), Value::from(0));
|
||||
let bad_kvs = bad_pod
|
||||
.dict
|
||||
.kvs()
|
||||
.clone()
|
||||
.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;
|
||||
.collect::<HashMap<Key, Value>>();
|
||||
bad_pod.dict = Dictionary::new(bad_kvs).unwrap();
|
||||
assert!(bad_pod.verify().is_err());
|
||||
|
||||
Ok(())
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue