diff --git a/.gitignore b/.gitignore index 6a4b33d..044eef8 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,6 @@ /target /Cargo.lock +/cargo/*/Cargo.toml +/cargo/*/Cargo.lock /*.profraw -.idea \ No newline at end of file +.idea diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..9b73fbe --- /dev/null +++ b/Makefile @@ -0,0 +1,36 @@ +DEV_DEPENDENCIES_LINE = $(shell cat Cargo.toml | grep -n "\[dev-dependencies\]" | cut -d : -f 1) +DELIMITING_LINE = $(shell echo $$(( $(DEV_DEPENDENCIES_LINE) - 2 ))) +TOTAL_LINES = $(shell cat Cargo.toml | wc -l) +TAIL_LINES = $(shell echo $$(( $(TOTAL_LINES) - $(DELIMITING_LINE) ))) + +python: + @head -n $(DELIMITING_LINE) Cargo.toml > cargo/$@/Cargo.toml + @echo "pyo3 = { version = \"0.18.0\", features = [\"abi3\", \"extension-module\"] }" >> cargo/$@/Cargo.toml + @tail -n $(TAIL_LINES) Cargo.toml >> cargo/$@/Cargo.toml + @echo >> cargo/$@/Cargo.toml + @cat cargo/$@/Cargo.toml.tail >> cargo/$@/Cargo.toml + @cd cargo/$@ && cargo build --release --target-dir ../../target/$@ + @mv target/$@/release/libcesride.dylib target/$@/release/cesride.so + +python-shell: + @cd target/python/release/ && python3 + +rust: + @cargo build --release + +libs: rust python + +clean: + cargo clean + +fix: + cargo fix + cargo fmt + +preflight: + cargo fmt --check + cargo clippy -- -D warnings + cargo build --release + cargo test --release + cargo audit + cargo tarpaulin diff --git a/README.md b/README.md index 2bd7d45..425103e 100644 --- a/README.md +++ b/README.md @@ -5,22 +5,54 @@ Cryptographic primitives for use with Composable Event Streaming Representation (CESR). -#### Running tests on an M1 +## Important Reference Material +- WebOfTrust/[ietf-cesr](https://github.com/WebOfTrust/ietf-cesr) repository - IETF draft specification for CESR +- Design Assumptions, Use Cases, and ToDo list - [HackMD link](https://hackmd.io/W2Z39cuSSTmD2TovVLvAPg?view) +- Introductory articles: + - [#1 CESR Proof Signatures](https://medium.com/happy-blockchains/cesr-proof-signatures-are-the-segwit-of-authentic-data-in-keri-e891c83e070a) + - [#2 CESR Overview](https://medium.com/happy-blockchains/cesr-one-of-sam-smiths-inventions-is-as-controversial-as-genius-d757f36b88f8) + +## Development + +Install dependencies: +```shell +cargo install cargo-audit +cargo install cargo-tarpaulin +``` + +Change some code and then fix it automatically: +```shell +make fix +``` +Commit your changes locally, and run these automated tests: ```shell -cargo +nightly test --target=aarch64-apple-darwin --package cesride --lib core::matter::matter_codex_tests::test_matter_new -- --exact --nocapture +make clean preflight ``` +If you've modified the python code, either add some python tests (you'll need to do that yourself, +none have been added) or run this code after running `make libs`: +```shell +make python python-shell + +# in python shell +from cesride import Matter +m = Matter(qb64="BGlOiUdp5sMmfotHfCWQKEzWR91C72AH0lT84c0um-Qj") +qb2 = m.qb2() +print(qb2) +m2 = Matter(qb2=bytes(qb2)) +m2.qb64() +``` +and expect to see the initial `qb64` input as the output. + +You are now ready to open a pull request! + ## Community -## Bi-weekly Meeting + +### Bi-weekly Meeting - [Zoom Link](https://us06web.zoom.us/j/88102305873?pwd=Wm01TEJKUWc0aE51a0QzZ2hNbTV2Zz09) -- [HackMD Link](https://hackmd.io/UQaEI0w8Thy_xRF7oYX03Q?view) Bi-Weekly Meeting Agenda and Minutes -- Slack https://join.slack.com/t/keriworld/shared_invite/zt-14326yxue-p7P~GEmAZ65luGSZvbgFAQ - - `#cesr` channel. +- [Agenda and Minutes Link](https://hackmd.io/UQaEI0w8Thy_xRF7oYX03Q?view) -# Important Reference Material -- WebOfTrust/[ietf-cesr](https://github.com/WebOfTrust/ietf-cesr) repository - IETF draft specification for CESR -- Design Assumptions, Use Cases, and ToDo list - [HackMD link](https://hackmd.io/W2Z39cuSSTmD2TovVLvAPg?view) -- Introductory articles: - - [#1 CESR Proof Signatures](https://medium.com/happy-blockchains/cesr-proof-signatures-are-the-segwit-of-authentic-data-in-keri-e891c83e070a) - - [#2 CESR Overview](https://medium.com/happy-blockchains/cesr-one-of-sam-smiths-inventions-is-as-controversial-as-genius-d757f36b88f8) \ No newline at end of file +### Slack +- [Slack Invite](https://join.slack.com/t/keriworld/shared_invite/zt-14326yxue-p7P~GEmAZ65luGSZvbgFAQ) + - `#cesr` channel. diff --git a/cargo/python/.cargo/config.toml b/cargo/python/.cargo/config.toml new file mode 100644 index 0000000..d47f983 --- /dev/null +++ b/cargo/python/.cargo/config.toml @@ -0,0 +1,11 @@ +[target.x86_64-apple-darwin] +rustflags = [ + "-C", "link-arg=-undefined", + "-C", "link-arg=dynamic_lookup", +] + +[target.aarch64-apple-darwin] +rustflags = [ + "-C", "link-arg=-undefined", + "-C", "link-arg=dynamic_lookup", +] diff --git a/cargo/python/Cargo.toml.tail b/cargo/python/Cargo.toml.tail new file mode 100644 index 0000000..e8b6050 --- /dev/null +++ b/cargo/python/Cargo.toml.tail @@ -0,0 +1,11 @@ +[lib] +path = "../../src/lib_python.rs" +test = false +doctest = false +bench = true +doc = true +crate-type = ["cdylib"] + +[features] +default = ["python"] +python = [] diff --git a/src/core/counter/mod.rs b/src/core/counter/mod.rs index cd943ec..f57638b 100644 --- a/src/core/counter/mod.rs +++ b/src/core/counter/mod.rs @@ -1,4 +1,4 @@ -pub(crate) mod tables; +pub mod tables; use crate::core::util; use crate::error::{err, Error, Result}; diff --git a/src/core/diger.rs b/src/core/diger.rs index 4fdc1ff..954ae9f 100644 --- a/src/core/diger.rs +++ b/src/core/diger.rs @@ -5,7 +5,7 @@ use crate::error::{err, Error, Result}; type Blake2b256 = blake2::Blake2b; -trait Diger { +pub trait Diger { fn new_with_code_and_raw(code: &str, raw: &[u8]) -> Result where Self: Sized; diff --git a/src/core/matter/mod.rs b/src/core/matter/mod.rs index bf160f7..0f3d3a8 100644 --- a/src/core/matter/mod.rs +++ b/src/core/matter/mod.rs @@ -1,10 +1,13 @@ -pub(crate) mod tables; - use base64::{engine::general_purpose as b64_engine, Engine}; +#[cfg(feature = "python")] +use pyo3::prelude::pyclass; use crate::core::util; use crate::error::{err, Error, Result}; +pub mod tables; + +#[cfg_attr(feature = "python", pyclass)] #[derive(Debug, Clone)] pub struct Matter { pub(crate) raw: Vec, @@ -131,8 +134,6 @@ impl Matter { self.binfil() } - pub fn transferable() {} - fn infil(&self) -> Result { let code = &self.code; let size = self.size; diff --git a/src/core/mod.rs b/src/core/mod.rs index 0c02d6e..be33f99 100644 --- a/src/core/mod.rs +++ b/src/core/mod.rs @@ -1,6 +1,6 @@ -mod cigar; -mod counter; -mod diger; -mod matter; -mod util; -mod verfer; +pub mod cigar; +pub mod counter; +pub mod diger; +pub mod matter; +pub mod util; +pub mod verfer; diff --git a/src/lib.rs b/src/lib.rs index de0eea5..0578eee 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -3,3 +3,10 @@ mod core; mod error; + +pub use crate::core::cigar::Cigar; +pub use crate::core::counter::{tables as counter, Counter}; +pub use crate::core::diger::Diger; +pub use crate::core::matter::{tables as matter, Matter}; +pub use crate::core::util; +pub use crate::core::verfer::Verfer; diff --git a/src/lib_python.rs b/src/lib_python.rs new file mode 100644 index 0000000..b6d88cf --- /dev/null +++ b/src/lib_python.rs @@ -0,0 +1,16 @@ +// TODO: remove before 1.0.0 +#![allow(dead_code)] + +use pyo3::prelude::*; + +mod core; +mod error; +mod python; + +use crate::core::matter::Matter; + +#[pymodule] +fn cesride(_py: Python, m: &PyModule) -> PyResult<()> { + m.add_class::()?; + Ok(()) +} diff --git a/src/python/matter.rs b/src/python/matter.rs new file mode 100644 index 0000000..85edcd9 --- /dev/null +++ b/src/python/matter.rs @@ -0,0 +1,76 @@ +use pyo3::{ + prelude::*, + exceptions::{PyException, PyValueError}, +}; + +use crate::core::matter::Matter; + +#[pymethods] +impl Matter { + #[new] + fn py_new( + code: Option<&str>, + raw: Option<&[u8]>, + raw_size: Option, + qb64: Option<&str>, + qb64b: Option<&[u8]>, + qb2: Option<&[u8]>, + ) -> PyResult { + let result = if let Some(code) = code { + let (raw, raw_size) = if raw.is_none() || raw_size.is_none() { + return Err(PyValueError::new_err("code present, raw and raw_size missing")); + } else { + (raw.unwrap(), raw_size.unwrap()) + }; + + Self::new_with_code_and_raw(code, raw, raw_size) + } else if let Some(qb64) = qb64 { + Self::new_with_qb64(qb64) + } else if let Some(qb64b) = qb64b { + Self::new_with_qb64b(qb64b) + } else if let Some(qb2) = qb2 { + Self::new_with_qb2(qb2) + } else { + return Err(PyValueError::new_err("must specify some parameters")); + }; + + match result { + Ok(matter) => Ok(matter), + Err(e) => Err(PyException::new_err(e.to_string())), + } + } + + #[pyo3(name = "code")] + fn py_code(&self) -> String { + self.code() + } + + #[pyo3(name = "raw")] + fn py_raw(&self) -> Vec { + self.raw() + } + + #[pyo3(name = "qb64")] + fn py_qb64(&self) -> PyResult { + match self.qb64() { + Ok(s) => Ok(s), + Err(e) => Err(PyException::new_err(e.to_string())), + } + } + + #[pyo3(name = "qb64b")] + fn py_qb64b(&self) -> PyResult> { + match self.qb64b() { + Ok(b) => Ok(b), + Err(e) => Err(PyException::new_err(e.to_string())), + } + } + + #[pyo3(name = "qb2")] + fn py_qb2(&self) -> PyResult> { + match self.qb2() { + Ok(b) => Ok(b), + Err(e) => Err(PyException::new_err(e.to_string())), + } + } +} diff --git a/src/python/mod.rs b/src/python/mod.rs new file mode 100644 index 0000000..a812ffc --- /dev/null +++ b/src/python/mod.rs @@ -0,0 +1 @@ +mod matter;