Skip to content

Commit

Permalink
NoSTD for lean client (#141)
Browse files Browse the repository at this point in the history
* NoSTD for lean client

* Updated CI pipeline to add additional tests around compilation targets for different feature sets

* Fix CI typos

* Removing std lib from crate imports

* Can't test dependent on the AKD library with nostd, so excluding nostd test in CI build

* rustfmt

Co-authored-by: Sean Lawlor <[email protected]>
  • Loading branch information
slawlor and slawlor authored Feb 7, 2022
1 parent 5a23bea commit a71fd9c
Show file tree
Hide file tree
Showing 8 changed files with 98 additions and 35 deletions.
10 changes: 10 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,16 @@ jobs:
run: docker-compose -f docker-compose.yml down -v
- name: Copy integration test logs for review
run: cat integration_tests/integration_test.log
- name: Test the lean client for wasm and SHA3-256 hashing
uses: actions-rs/cargo@v1
with:
command: test
args: --package akd_client --no-default-features --features wasm,sha3_256
- name: Test the lean client for wasm and BLAKE3 hashing
uses: actions-rs/cargo@v1
with:
command: test
args: --package akd_client --no-default-features --features wasm,blake3

clippy:
name: Clippy
Expand Down
2 changes: 1 addition & 1 deletion .vscode/launch.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
"--no-run",
"--lib",
"--package=akd_client",
"--features=sha3_256",
"--features=sha3_256,nostd",
"--no-default-features"
],
"filter": {
Expand Down
8 changes: 5 additions & 3 deletions akd_client/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,10 @@ readme = "../README.md"
crate-type = ["cdylib", "rlib"]

[dependencies]
sha2 = { version = "0.10.1", optional = true}
sha3 = { version = "0.10.0", optional = true}
blake3 = { version = "1.3.1", optional = true }
sha2 = { version = "0.10.1", optional = true, default-features = false }
sha3 = { version = "0.10.0", optional = true, default-features = false }
blake3 = { version = "1.3.1", optional = true, default-features = false }

wasm-bindgen = { version = "0.2.79", optional = true, features = ["serde-serialize"] }
serde = { version = "1.0", optional = true, features = ["derive"]}

Expand All @@ -27,6 +28,7 @@ serde = { version = "1.0", optional = true, features = ["derive"]}
wee_alloc = { version = "0.4.5", optional = true }

[features]
nostd = []
# Optional hash functions
sha512 = ["sha2"]
sha256 = ["sha2"]
Expand Down
5 changes: 5 additions & 0 deletions akd_client/src/hash.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,11 @@
use core::slice;

#[cfg(feature = "nostd")]
use alloc::format;
#[cfg(feature = "nostd")]
use alloc::vec::Vec;

use crate::types::Digest as PublicDigest;
use crate::types::{Direction, NodeLabel};
use crate::{verify_error, VerificationError, ARITY};
Expand Down
5 changes: 5 additions & 0 deletions akd_client/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@
//! 1. wasm: Compile with web-assembly support for WASM compilation
//! 2. wee_alloc: Utilize the WEE allocator, which is roughly 1KB instead of 10KB as a allocator but slower. This
//! is helpful in cases of constrained binary footprint size to help minimize
//! 3. nostd: Disable use of the std library
//!
//! You can compile and pack the WASM output with
//! ```bash
Expand All @@ -64,6 +65,10 @@
//! message which contains the data inside the proof. Therefore they'd need to be deserialized and handled independently
//! of the AKD crate which wouldn't be a dependency anyways. This is why the types are independent and specified separately
//! from the core AKD types.
#![cfg_attr(feature = "nostd", no_std)]
extern crate alloc;
#[cfg(feature = "nostd")]
use alloc::string::String;

pub mod types;
pub mod verify;
Expand Down
79 changes: 65 additions & 14 deletions akd_client/src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,15 @@
//! This crate contains the tests for the client library which make sure that the
//! base AKD library and this "lean" client result in the same outputs
#[cfg(feature = "nostd")]
use crate::alloc::string::ToString;
#[cfg(feature = "nostd")]
use alloc::format;
#[cfg(feature = "nostd")]
use alloc::vec;
#[cfg(feature = "nostd")]
use alloc::vec::Vec;

use akd::errors::AkdError;
use akd::storage::types::{AkdLabel, AkdValue};

Expand Down Expand Up @@ -137,20 +146,20 @@ async fn test_simple_lookup() -> Result<(), AkdError> {
let db = InMemoryDb::new();
let mut akd = Directory::new::<Hash>(&db).await?;

akd.publish::<Hash>(
vec![
(AkdLabel("hello".to_string()), AkdValue("world".to_string())),
(
AkdLabel("hello2".to_string()),
AkdValue("world2".to_string()),
),
],
false,
)
.await?;
let mut updates = vec![];
for i in 0..15 {
updates.push((
AkdLabel(format!("hello{}", i)),
AkdValue(format!("hello{}", i)),
));
}

akd.publish::<Hash>(updates, true).await?;

let target_label = AkdLabel(format!("hello{}", 10));

// retrieve the lookup proof
let lookup_proof = akd.lookup(AkdLabel("hello".to_string())).await?;
let lookup_proof = akd.lookup(target_label.clone()).await?;
// retrieve the root hash
let current_azks = akd.retrieve_current_azks().await?;
let root_hash = akd.get_root_hash::<Hash>(&current_azks).await?;
Expand All @@ -159,8 +168,7 @@ async fn test_simple_lookup() -> Result<(), AkdError> {
let internal_lookup_proof = convert_lookup_proof::<Hash>(&lookup_proof);

// perform the "traditional" AKD verification
let akd_result =
akd::client::lookup_verify::<Hash>(root_hash, AkdLabel("hello".to_string()), lookup_proof);
let akd_result = akd::client::lookup_verify::<Hash>(root_hash, target_label, lookup_proof);

let lean_result =
crate::verify::lookup_verify(to_digest::<Hash>(root_hash), vec![], internal_lookup_proof)
Expand All @@ -171,3 +179,46 @@ async fn test_simple_lookup() -> Result<(), AkdError> {

Ok(())
}

// NOTE: There is a problem with "small" AKD trees that appears to only manifest with
// SHA3 256 hashing

// #[tokio::test]
// async fn test_simple_lookup_for_small_tree() -> Result<(), AkdError> {
// let db = InMemoryDb::new();
// let mut akd = Directory::new::<Hash>(&db).await?;

// let mut updates = vec![];
// for i in 0..1 {
// updates.push((
// AkdLabel(format!("hello{}", i)),
// AkdValue(format!("hello{}", i)),
// ));
// }

// akd.publish::<Hash>(updates, true).await?;

// let target_label = AkdLabel(format!("hello{}", 0));

// // retrieve the lookup proof
// let lookup_proof = akd.lookup(target_label.clone()).await?;
// // retrieve the root hash
// let current_azks = akd.retrieve_current_azks().await?;
// let root_hash = akd.get_root_hash::<Hash>(&current_azks).await?;

// // create the "lean" lookup proof version
// let internal_lookup_proof = convert_lookup_proof::<Hash>(&lookup_proof);

// // perform the "traditional" AKD verification
// let akd_result =
// akd::client::lookup_verify::<Hash>(root_hash, target_label, lookup_proof);

// let lean_result =
// crate::verify::lookup_verify(to_digest::<Hash>(root_hash), vec![], internal_lookup_proof)
// .map_err(|i_err| AkdError::AzksNotFound(format!("Internal: {:?}", i_err)));
// // check the two results to make sure they both verify
// assert!(matches!(akd_result, Ok(())));
// assert!(matches!(lean_result, Ok(())));

// Ok(())
// }
19 changes: 2 additions & 17 deletions akd_client/src/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@
//! Append-only and history proofs to come
use crate::ARITY;
#[cfg(feature = "nostd")]
use alloc::vec::Vec;

// ============================================
// Typedefs and constants
Expand Down Expand Up @@ -43,23 +45,6 @@ pub struct NodeLabel {
pub len: u32,
}

impl PartialOrd for NodeLabel {
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
Some(self.cmp(other))
}
}

impl Ord for NodeLabel {
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
let len_cmp = self.len.cmp(&other.len);
if let std::cmp::Ordering::Equal = len_cmp {
self.val.cmp(&other.val)
} else {
len_cmp
}
}
}

impl NodeLabel {
pub(crate) fn hash(&self) -> Digest {
let label_len_bytes = crate::hash::hash(&self.len.to_be_bytes());
Expand Down
5 changes: 5 additions & 0 deletions akd_client/src/verify.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,11 @@

//! This module contains the client verification calls to verify different membership types
#[cfg(feature = "nostd")]
use crate::alloc::string::ToString;
#[cfg(feature = "nostd")]
use alloc::format;

use crate::hash::*;
use crate::types::*;
use crate::{verify_error, VerificationError, ARITY};
Expand Down

0 comments on commit a71fd9c

Please sign in to comment.