feat: move code here (#11)

This commit is contained in:
Eduard S. 2025-01-31 16:20:57 +01:00 committed by GitHub
parent 5bb98e2645
commit ef3dd308e8
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
22 changed files with 889 additions and 10 deletions

3
.gitignore vendored
View file

@ -1 +1,2 @@
book
/target
Cargo.lock

15
Cargo.toml Normal file
View file

@ -0,0 +1,15 @@
[package]
name = "pod2"
version = "0.1.0"
edition = "2021"
[lib]
name = "pod2"
path = "src/lib.rs"
[dependencies]
plonky2 = { git = "https://github.com/mir-protocol/plonky2" }
hex = "0.4.3"
itertools = "0.14.0"
strum = "0.26"
strum_macros = "0.26"

View file

@ -1,10 +1,3 @@
# pod2-docs
> Hackmds for sharing ideas, once there is consensus around it, move it into this repo to consolidate it. Also we can use PRs to discuss asynchronously specific ideas of the spec.
# POD2
## Usage
A rendered version of the site can be found at: https://0xparc.github.io/pod2-docs/
To run it locally:
- Needs [mdbook](https://github.com/rust-lang/mdBook), to install: `cargo install mdbook`
- Needs [mdbook-katex](https://github.com/lzanini/mdbook-katex), to install: `cargo install mdbook-katex`
- Run locally: `mdbook serve`
TODO

1
book/.gitignore vendored Normal file
View file

@ -0,0 +1 @@
book

10
book/README.md Normal file
View file

@ -0,0 +1,10 @@
# pod2-docs
> Hackmds for sharing ideas, once there is consensus around it, move it into this repo to consolidate it. Also we can use PRs to discuss asynchronously specific ideas of the spec.
## Usage
A rendered version of the site can be found at: https://0xparc.github.io/pod2-docs/
To run it locally:
- Needs [mdbook](https://github.com/rust-lang/mdBook), to install: `cargo install mdbook`
- Needs [mdbook-katex](https://github.com/lzanini/mdbook-katex), to install: `cargo install mdbook-katex`
- Run locally: `mdbook serve`

296
src/backend.rs Normal file
View file

@ -0,0 +1,296 @@
use plonky2::field::types::{Field, PrimeField64};
use std::collections::HashMap;
use std::fmt;
use std::io::{self, Write};
use std::iter;
use strum_macros::FromRepr;
use crate::{Hash, Params, PodId, F, NULL};
#[derive(Clone, Copy, Debug, FromRepr, PartialEq, Eq)]
pub enum NativeStatement {
None = 0,
ValueOf = 1,
Equal = 2,
NotEqual,
Gt,
Lt,
Contains,
NotContains,
SumOf,
ProductOf,
MaxOf,
}
#[derive(Clone, Copy, Debug, Default, Hash, PartialEq, Eq)]
pub struct Value(pub [F; 4]);
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, Debug, PartialEq, Eq, Hash)]
pub struct AnchoredKey(pub PodId, pub Hash);
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum StatementArg {
None,
Literal(Value),
Ref(AnchoredKey),
}
impl StatementArg {
pub fn is_none(&self) -> bool {
matches!(self, Self::None)
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct Statement(pub NativeStatement, pub Vec<StatementArg>);
impl Statement {
pub fn is_none(&self) -> bool {
matches!(self.0, NativeStatement::None)
}
}
#[derive(Clone, Debug)]
pub struct SignedPod {
pub params: Params,
pub id: PodId,
pub kvs: HashMap<Hash, Value>,
}
impl SignedPod {
pub fn is_null(&self) -> bool {
self.id.0 == NULL
}
}
#[derive(Clone, Debug)]
pub struct MainPod {
pub params: Params,
pub id: PodId,
pub input_signed_pods: Vec<SignedPod>,
pub statements: Vec<Statement>,
}
fn fill_pad<T: Clone>(v: &mut Vec<T>, pad_value: T, len: usize) {
if v.len() > len {
panic!("length exceeded");
}
while v.len() < len {
v.push(pad_value.clone());
}
}
impl MainPod {
pub fn new(
params: Params,
mut input_signed_pods: Vec<SignedPod>,
input_main_pods: Vec<MainPod>,
mut statements: Vec<Statement>,
) -> Self {
Self::pad_statements(&params, &mut statements, params.max_statements);
Self::pad_input_signed_pods(&params, &mut input_signed_pods);
Self {
params,
id: PodId::default(), // TODO
input_signed_pods,
statements,
}
}
fn statement_none(params: &Params) -> Statement {
let mut args = Vec::with_capacity(params.max_statement_args);
Self::pad_statement_args(&params, &mut args);
Statement(NativeStatement::None, args)
}
fn pad_statements(params: &Params, statements: &mut Vec<Statement>, len: usize) {
for st in statements.iter_mut() {
fill_pad(&mut st.1, StatementArg::None, params.max_statement_args)
}
fill_pad(statements, Self::statement_none(params), len)
}
fn pad_statement_args(params: &Params, args: &mut Vec<StatementArg>) {
fill_pad(args, StatementArg::None, params.max_statement_args)
}
fn pad_input_signed_pods(params: &Params, pods: &mut Vec<SignedPod>) {
let pod_none = SignedPod {
params: params.clone(),
id: PodId::default(),
kvs: HashMap::new(),
};
fill_pad(pods, pod_none, params.max_input_signed_pods)
}
pub fn input_signed_pods_statements(&self) -> Vec<Vec<Statement>> {
let mut pods_statements = Vec::new();
let st_none = Self::statement_none(&self.params);
for pod in &self.input_signed_pods {
let mut pod_statements: Vec<Statement> = Vec::new();
for kv in &pod.kvs {
let args = vec![
StatementArg::Ref(AnchoredKey(pod.id, *kv.0)),
StatementArg::Literal(*kv.1),
];
pod_statements.push(Statement(NativeStatement::ValueOf, args));
}
Self::pad_statements(
&self.params,
&mut pod_statements,
self.params.max_signed_pod_values,
);
pods_statements.push(pod_statements);
}
let statements_none: Vec<Statement> = iter::repeat(st_none.clone())
.take(self.params.max_signed_pod_values)
.collect();
fill_pad(
&mut pods_statements,
statements_none,
self.params.max_input_signed_pods,
);
pods_statements
}
pub fn prv_statements(&self) -> Vec<Statement> {
self.statements
.iter()
.take(self.params.max_priv_statements())
.cloned()
.collect()
}
pub fn pub_statements(&self) -> Vec<Statement> {
self.statements
.iter()
.skip(self.params.max_priv_statements())
.cloned()
.collect()
}
}
pub struct Printer {
pub skip_none: bool,
}
impl Printer {
pub fn fmt_arg(&self, w: &mut dyn Write, arg: &StatementArg) -> io::Result<()> {
match arg {
StatementArg::None => write!(w, "none"),
StatementArg::Literal(v) => write!(w, "{}", v),
StatementArg::Ref(r) => write!(w, "{}.{}", r.0, r.1),
}
}
pub fn fmt_signed_pod(&self, w: &mut dyn Write, pod: &SignedPod) -> io::Result<()> {
writeln!(w, "SignedPod ({}):", pod.id)?;
// for (k, v) in pod.kvs.iter().sorted_by_key(|kv| kv.0) {
// TODO: print in a stable order
for (k, v) in pod.kvs.iter() {
println!(" - {}: {}", k, v);
}
Ok(())
}
pub fn fmt_statement(&self, w: &mut dyn Write, st: &Statement) -> io::Result<()> {
write!(w, "{:?} ", st.0)?;
for (i, arg) in st.1.iter().enumerate() {
if !(self.skip_none && arg.is_none()) {
if i != 0 {
write!(w, " ")?;
}
self.fmt_arg(w, arg)?;
}
}
Ok(())
}
pub fn fmt_statement_index(
&self,
w: &mut dyn Write,
st: &Statement,
index: usize,
) -> io::Result<()> {
if !(self.skip_none && st.is_none()) {
write!(w, " {:03}. ", index)?;
self.fmt_statement(w, &st)?;
write!(w, "\n")?;
}
Ok(())
}
pub fn fmt_main_pod(&self, w: &mut dyn Write, pod: &MainPod) -> io::Result<()> {
writeln!(w, "MainPod ({}):", pod.id)?;
// TODO
// writeln!(w, " input_main_pods:")?;
// for in_pod in &pod.input_main_pods {
// writeln!(w, " - {}", in_pod.id)?;
// }
let mut st_index = 0;
for (i, (pod, statements)) in pod
.input_signed_pods
.iter()
.zip(pod.input_signed_pods_statements())
.enumerate()
{
if !(self.skip_none && pod.is_null()) {
writeln!(w, " in sig_pod {:02} (id:{}) statements:", i, pod.id)?;
for st in statements {
self.fmt_statement_index(w, &st, st_index)?;
st_index += 1;
}
} else {
st_index += pod.params.max_signed_pod_values;
}
}
writeln!(w, " prv statements:")?;
for st in pod.prv_statements() {
self.fmt_statement_index(w, &st, st_index)?;
st_index += 1;
}
writeln!(w, " pub statements:")?;
for st in pod.pub_statements() {
self.fmt_statement_index(w, &st, st_index)?;
st_index += 1;
}
Ok(())
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::frontend;
#[test]
fn test_back_0() {
let params = Params::default();
let (front_gov_id, front_pay_stub, front_kyc) = frontend::tests::data_zu_kyc(params);
let gov_id = front_gov_id.compile();
let pay_stub = front_pay_stub.compile();
let kyc = front_kyc.compile();
// println!("{:#?}", kyc);
let printer = Printer { skip_none: true };
let mut w = io::stdout();
printer.fmt_signed_pod(&mut w, &gov_id).unwrap();
printer.fmt_signed_pod(&mut w, &pay_stub).unwrap();
printer.fmt_main_pod(&mut w, &kyc).unwrap();
}
}

456
src/frontend.rs Normal file
View file

@ -0,0 +1,456 @@
use itertools::Itertools;
use plonky2::field::types::Field;
use std::collections::HashMap;
use std::convert::From;
use std::fmt;
use std::io::{self, Write};
use crate::backend;
use crate::{hash_str, Params, PodId, F, SELF};
#[derive(Clone, Debug, Default, Hash, PartialEq, Eq)]
pub enum PodType {
#[default]
Signed = 1,
Main,
}
// An Origin, which represents a reference to an ancestor POD.
#[derive(Clone, Debug, PartialEq, Eq, Hash, Default)]
pub struct Origin(pub PodType, pub PodId);
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct MerkleTree {
pub root: u8, // TODO
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum Value {
String(String),
Int(i64),
MerkleTree(MerkleTree),
}
impl From<&str> for Value {
fn from(s: &str) -> Self {
Value::String(s.to_string())
}
}
impl From<i64> for Value {
fn from(v: i64) -> Self {
Value::Int(v)
}
}
impl From<&Value> for backend::Value {
fn from(v: &Value) -> Self {
match v {
Value::String(s) => backend::Value(hash_str(s).0),
Value::Int(v) => {
backend::Value([F::from_canonical_u64(*v as u64), F::ZERO, F::ZERO, F::ZERO])
}
// TODO
Value::MerkleTree(mt) => backend::Value([
F::from_canonical_u64(mt.root as u64),
F::ZERO,
F::ZERO,
F::ZERO,
]),
}
}
}
impl fmt::Display for Value {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Value::String(s) => write!(f, "\"{}\"", s),
Value::Int(v) => write!(f, "{}", v),
Value::MerkleTree(mt) => write!(f, "mt:{}", mt.root),
}
}
}
#[derive(Clone, Debug)]
pub struct SignedPod {
pub params: Params,
pub id: PodId,
pub kvs: HashMap<String, Value>,
}
impl SignedPod {
pub fn origin(&self) -> Origin {
Origin(PodType::Signed, self.id)
}
pub fn compile(&self) -> backend::SignedPod {
backend::SignedPod {
params: self.params,
id: self.id,
kvs: self
.kvs
.iter()
.map(|(k, v)| (hash_str(k), backend::Value::from(v)))
.collect(),
}
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum NativeStatement {
Equal = 2,
NotEqual,
Gt,
Lt,
Contains,
NotContains,
SumOf,
ProductOf,
MaxOf,
}
impl From<NativeStatement> for backend::NativeStatement {
fn from(v: NativeStatement) -> Self {
Self::from_repr(v as usize).unwrap()
}
}
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub struct AnchoredKey(pub Origin, pub String);
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum StatementArg {
Literal(Value),
Ref(AnchoredKey),
}
impl fmt::Display for StatementArg {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::Literal(v) => write!(f, "{}", v),
Self::Ref(r) => write!(f, "{}.{}", r.0 .1, r.1),
}
}
}
impl From<Value> for StatementArg {
fn from(v: Value) -> Self {
StatementArg::Literal(v)
}
}
impl From<&str> for StatementArg {
fn from(s: &str) -> Self {
StatementArg::Literal(Value::from(s))
}
}
impl From<i64> for StatementArg {
fn from(v: i64) -> Self {
StatementArg::Literal(Value::from(v))
}
}
impl From<(Origin, &str)> for StatementArg {
fn from((origin, key): (Origin, &str)) -> Self {
StatementArg::Ref(AnchoredKey(origin, key.to_string()))
}
}
impl From<(&SignedPod, &str)> for StatementArg {
fn from((pod, key): (&SignedPod, &str)) -> Self {
StatementArg::Ref(AnchoredKey(pod.origin(), key.to_string()))
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct Statement(pub NativeStatement, pub Vec<StatementArg>);
impl fmt::Display for Statement {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{:?} ", self.0)?;
for (i, arg) in self.1.iter().enumerate() {
if i != 0 {
write!(f, " ")?;
}
write!(f, "{}", arg)?;
}
Ok(())
}
}
#[derive(Clone, Debug)]
pub struct MainPodBuilder {
pub params: Params,
pub statements: Vec<Statement>,
pub operations: Vec<Operation>,
}
impl MainPodBuilder {
pub fn push_statement(&mut self, st: Statement, op: Operation) {
self.statements.push(st);
self.operations.push(op);
}
pub fn build(self) -> MainPod {
MainPod {
params: self.params,
id: PodId::default(), // TODO
input_signed_pods: vec![], // TODO
input_main_pods: vec![], // TODO
statements: self
.statements
.into_iter()
.zip(self.operations.into_iter())
.collect(),
}
}
}
#[derive(Clone, Debug)]
pub struct MainPod {
pub params: Params,
pub id: PodId,
pub input_signed_pods: Vec<SignedPod>,
pub input_main_pods: Vec<MainPod>,
pub statements: Vec<(Statement, Operation)>,
}
impl MainPod {
pub fn origin(&self) -> Origin {
Origin(PodType::Main, self.id)
}
pub fn compile(&self) -> backend::MainPod {
MainPodCompiler::new(self).compile()
}
pub fn max_priv_statements(&self) -> usize {
self.params.max_statements - self.params.max_public_statements
}
}
struct MainPodCompiler<'a> {
// Input
pod: &'a MainPod,
// Output
statements: Vec<backend::Statement>,
// Internal state
const_cnt: usize,
}
impl<'a> MainPodCompiler<'a> {
fn new(pod: &'a MainPod) -> Self {
Self {
pod,
statements: Vec::new(),
const_cnt: 0,
}
}
fn compile_st(&mut self, st: &Statement) {
let mut args = Vec::new();
let Statement(front_typ, front_args) = st;
for front_arg in front_args {
let key = match front_arg {
StatementArg::Literal(v) => {
let key = format!("_c{}", self.const_cnt);
let key_hash = hash_str(&key);
self.const_cnt += 1;
let value_of_args = vec![
backend::StatementArg::Ref(backend::AnchoredKey(SELF, key_hash)),
backend::StatementArg::Literal(backend::Value::from(v)),
];
self.statements.push(backend::Statement(
backend::NativeStatement::ValueOf,
value_of_args,
));
backend::AnchoredKey(SELF, key_hash)
}
StatementArg::Ref(k) => backend::AnchoredKey(k.0 .1, hash_str(&k.1)),
};
args.push(backend::StatementArg::Ref(key));
if args.len() > self.pod.params.max_statement_args {
panic!("too many statement args");
}
}
self.statements.push(backend::Statement(
backend::NativeStatement::from(*front_typ),
args,
));
}
pub fn compile(mut self) -> backend::MainPod {
let MainPod {
statements,
params,
input_signed_pods,
..
} = self.pod;
for st in statements {
self.compile_st(&st.0);
if self.statements.len() > params.max_statements {
panic!("too many statements");
}
}
let input_signed_pods = input_signed_pods.iter().map(|p| p.compile()).collect();
backend::MainPod::new(params.clone(), input_signed_pods, vec![], self.statements)
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum NativeOperation {
TransitiveEqualityFromStatements = 1,
GtToNonequality = 2,
LtToNonequality = 3,
Auto = 1024,
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum OperationArg {
Statement(Statement),
Key(AnchoredKey),
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct Operation(pub NativeOperation, pub Vec<OperationArg>);
pub struct Printer {}
impl Printer {
pub fn fmt_op_arg(&self, w: &mut dyn Write, arg: &OperationArg) -> io::Result<()> {
match arg {
OperationArg::Statement(s) => write!(w, "{}", s),
OperationArg::Key(r) => write!(w, "{}.{}", r.0 .1, r.1),
}
}
pub fn fmt_op(&self, w: &mut dyn Write, op: &Operation) -> io::Result<()> {
write!(w, "{:?} ", op.0)?;
for (i, arg) in op.1.iter().enumerate() {
if i != 0 {
write!(w, " ")?;
}
self.fmt_op_arg(w, arg)?;
}
Ok(())
}
pub fn fmt_signed_pod(&self, w: &mut dyn Write, pod: &SignedPod) -> io::Result<()> {
writeln!(w, "SignedPod (id:{}):", pod.id)?;
for (k, v) in pod.kvs.iter().sorted_by_key(|kv| kv.0) {
println!(" - {}: {}", k, v);
}
Ok(())
}
pub fn fmt_main_pod(&self, w: &mut dyn Write, pod: &MainPod) -> io::Result<()> {
writeln!(w, "MainPod (id:{}):", pod.id)?;
writeln!(w, " input_signed_pods:")?;
for in_pod in &pod.input_signed_pods {
writeln!(w, " - {}", in_pod.id)?;
}
writeln!(w, " input_main_pods:")?;
for in_pod in &pod.input_main_pods {
writeln!(w, " - {}", in_pod.id)?;
}
writeln!(w, " statements:")?;
for st in &pod.statements {
let (st, op) = st;
write!(w, " - {} <- ", st)?;
self.fmt_op(w, op)?;
write!(w, "\n")?;
}
Ok(())
}
}
#[cfg(test)]
pub mod tests {
use super::*;
use crate::Hash;
use hex::FromHex;
use std::io;
fn pod_id(hex: &str) -> PodId {
PodId(Hash::from_hex(hex).unwrap())
}
fn auto() -> Operation {
Operation(NativeOperation::Auto, vec![])
}
macro_rules! args {
($($arg:expr),+) => {vec![$(StatementArg::from($arg)),*]}
}
macro_rules! st {
(eq, $($arg:expr),+) => { Statement(NativeStatement::Equal, args!($($arg),*)) };
(ne, $($arg:expr),+) => { Statement(NativeStatement::NotEqual, args!($($arg),*)) };
(gt, $($arg:expr),+) => { Statement(NativeStatement::Gt, args!($($arg),*)) };
(lt, $($arg:expr),+) => { Statement(NativeStatement::Lt, args!($($arg),*)) };
(contains, $($arg:expr),+) => { Statement(NativeStatement::Contains, args!($($arg),*)) };
(not_contains, $($arg:expr),+) => { Statement(NativeStatement::NotContains, args!($($arg),*)) };
(sum_of, $($arg:expr),+) => { Statement(NativeStatement::SumOf, args!($($arg),*)) };
(product_of, $($arg:expr),+) => { Statement(NativeStatement::product_of, args!($($arg),*)) };
(max_of, $($arg:expr),+) => { Statement(NativeStatement::max_of, args!($($arg),*)) };
}
pub fn data_zu_kyc(params: Params) -> (SignedPod, SignedPod, MainPod) {
let mut kvs = HashMap::new();
kvs.insert("idNumber".into(), "4242424242".into());
kvs.insert("dateOfBirth".into(), 1169909384.into());
kvs.insert("socialSecurityNumber".into(), "G2121210".into());
let gov_id = SignedPod {
params: params.clone(),
id: pod_id("1100000000000000000000000000000000000000000000000000000000000000"),
kvs,
};
let mut kvs = HashMap::new();
kvs.insert("socialSecurityNumber".into(), "G2121210".into());
kvs.insert("startDate".into(), 1706367566.into());
let pay_stub = SignedPod {
params: params.clone(),
id: pod_id("2200000000000000000000000000000000000000000000000000000000000000"),
kvs,
};
let sanction_list = Value::MerkleTree(MerkleTree { root: 1 });
let now_minus_18y: i64 = 1169909388;
let now_minus_1y: i64 = 1706367566;
let mut statements: Vec<(Statement, Operation)> = Vec::new();
statements.push((
st!(not_contains, sanction_list, (&gov_id, "idNumber")),
auto(),
));
statements.push((st!(lt, (&gov_id, "dateOfBirth"), now_minus_18y), auto()));
statements.push((
st!(
eq,
(&gov_id, "socialSecurityNumber"),
(&pay_stub, "socialSecurityNumber")
),
auto(),
));
statements.push((st!(eq, (&pay_stub, "startDate"), now_minus_1y), auto()));
let kyc = MainPod {
params: params.clone(),
id: pod_id("3300000000000000000000000000000000000000000000000000000000000000"),
input_signed_pods: vec![gov_id.clone(), pay_stub.clone()],
input_main_pods: vec![],
statements,
};
(gov_id, pay_stub, kyc)
}
#[test]
fn test_front_0() {
let (gov_id, pay_stub, kyc) = data_zu_kyc(Params::default());
let printer = Printer {};
let mut w = io::stdout();
printer.fmt_signed_pod(&mut w, &gov_id).unwrap();
printer.fmt_signed_pod(&mut w, &pay_stub).unwrap();
printer.fmt_main_pod(&mut w, &kyc).unwrap();
}
}

104
src/lib.rs Normal file
View file

@ -0,0 +1,104 @@
use hex::{FromHex, FromHexError};
use plonky2::field::goldilocks_field::GoldilocksField;
use plonky2::field::types::{Field, PrimeField64};
use plonky2::hash::poseidon::PoseidonHash;
use plonky2::plonk::config::Hasher;
use std::fmt;
pub mod backend;
pub mod frontend;
pub type F = GoldilocksField;
#[derive(Clone, Copy, Debug, Default, Hash, PartialEq, Eq)]
pub struct Hash(pub [F; 4]);
pub const NULL: Hash = Hash([F::ZERO, F::ZERO, F::ZERO, F::ZERO]);
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..4 {
write!(f, "{:02x}", (v0 >> (i * 8)) & 0xff)?;
}
write!(f, "")
}
}
impl FromHex for Hash {
type Error = FromHexError;
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; 4];
for i in 0..4 {
buf.copy_from_slice(&bytes[8 * i..8 * (i + 1)]);
inner[i] = F::from_canonical_u64(u64::from_le_bytes(buf));
}
Ok(Self(inner))
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Default)]
pub struct PodId(pub Hash);
pub const SELF: PodId = PodId(Hash([F::ONE, F::ZERO, F::ZERO, F::ZERO]));
impl fmt::Display for PodId {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
if *self == SELF {
write!(f, "self")
} else if self.0 == NULL {
write!(f, "null")
} else {
write!(f, "{}", self.0)
}
}
}
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(PoseidonHash::hash_no_pad(&input).elements)
}
#[derive(Clone, Debug, Copy)]
pub struct Params {
pub max_input_signed_pods: usize,
pub max_input_main_pods: usize,
pub max_statements: usize,
pub max_signed_pod_values: usize,
pub max_public_statements: usize,
pub max_statement_args: usize,
}
impl Params {
pub fn max_priv_statements(&self) -> usize {
self.max_statements - self.max_public_statements
}
}
impl Default for Params {
fn default() -> Self {
Self {
max_input_signed_pods: 3,
max_input_main_pods: 3,
max_statements: 20,
max_signed_pod_values: 8,
max_public_statements: 10,
max_statement_args: 5,
}
}
}

3
src/main.rs Normal file
View file

@ -0,0 +1,3 @@
fn main() {
println!("Hello, world!");
}