#![cfg(test)]
use crate::{
auditor::audit_verify,
client::{key_history_verify, lookup_verify},
directory::{get_key_history_hashes, Directory, PublishCorruption},
ecvrf::{HardCodedAkdVRF, VRFKeyStorage},
errors::AkdError,
proof_structs::VerifyResult,
storage::{
manager::StorageManager,
memory::AsyncInMemoryDatabase,
types::{AkdLabel, AkdValue, DbRecord},
Database,
},
HistoryParams, HistoryVerificationParams,
};
use winter_crypto::{Digest, Hasher};
use winter_math::fields::f128::BaseElement;
type Blake3 = winter_crypto::hashers::Blake3_256<BaseElement>;
type Sha3 = winter_crypto::hashers::Sha3_256<BaseElement>;
#[tokio::test]
async fn test_empty_tree_root_hash() -> Result<(), AkdError> {
let db = AsyncInMemoryDatabase::new();
let storage = StorageManager::new_no_cache(&db);
let vrf = HardCodedAkdVRF {};
let akd = Directory::<_, _, Blake3>::new(&storage, &vrf, false).await?;
let current_azks = akd.retrieve_current_azks().await?;
let hash = akd.get_root_hash(¤t_azks).await?;
assert_eq!(
"f48ded419214732a2c610c1e280543744bab3c17aec33e444997fa2d8f79792a",
hex::encode(hash.as_bytes())
);
Ok(())
}
#[tokio::test]
async fn test_simple_publish() -> Result<(), AkdError> {
let db = AsyncInMemoryDatabase::new();
let storage = StorageManager::new_no_cache(&db);
let vrf = HardCodedAkdVRF {};
let akd = Directory::<_, _, Blake3>::new(&storage, &vrf, false).await?;
akd.publish(vec![(
AkdLabel::from_utf8_str("hello"),
AkdValue::from_utf8_str("world"),
)])
.await?;
Ok(())
}
#[tokio::test]
async fn test_simple_lookup() -> Result<(), AkdError> {
let db = AsyncInMemoryDatabase::new();
let storage = StorageManager::new_no_cache(&db);
let vrf = HardCodedAkdVRF {};
let akd = Directory::<_, _, Blake3>::new(&storage, &vrf, false).await?;
akd.publish(vec![
(
AkdLabel::from_utf8_str("hello"),
AkdValue::from_utf8_str("world"),
),
(
AkdLabel::from_utf8_str("hello2"),
AkdValue::from_utf8_str("world2"),
),
])
.await?;
let lookup_proof = akd.lookup(AkdLabel::from_utf8_str("hello")).await?;
let current_azks = akd.retrieve_current_azks().await?;
let root_hash = akd.get_root_hash(¤t_azks).await?;
let vrf_pk = akd.get_public_key().await?;
lookup_verify(
&vrf_pk,
root_hash,
AkdLabel::from_utf8_str("hello"),
lookup_proof,
)?;
Ok(())
}
#[tokio::test]
async fn test_small_key_history() -> Result<(), AkdError> {
let db = AsyncInMemoryDatabase::new();
let storage = StorageManager::new_no_cache(&db);
let vrf = HardCodedAkdVRF {};
let akd = Directory::<_, _, Blake3>::new(&storage, &vrf, false).await?;
akd.publish(vec![(
AkdLabel::from_utf8_str("hello"),
AkdValue::from_utf8_str("world"),
)])
.await?;
akd.publish(vec![(
AkdLabel::from_utf8_str("hello"),
AkdValue::from_utf8_str("world2"),
)])
.await?;
let key_history_proof = akd
.key_history(&AkdLabel::from_utf8_str("hello"), HistoryParams::default())
.await?;
let current_azks = akd.retrieve_current_azks().await?;
let current_epoch = current_azks.get_latest_epoch();
let root_hash = akd.get_root_hash(¤t_azks).await?;
let vrf_pk = akd.get_public_key().await?;
let result = key_history_verify::<Blake3>(
&vrf_pk,
root_hash,
current_epoch,
AkdLabel::from_utf8_str("hello"),
key_history_proof,
HistoryVerificationParams::default(),
)?;
assert_eq!(
result,
vec![
VerifyResult {
epoch: 2,
version: 2,
value: AkdValue::from_utf8_str("world2"),
},
VerifyResult {
epoch: 1,
version: 1,
value: AkdValue::from_utf8_str("world"),
},
]
);
Ok(())
}
#[tokio::test]
async fn test_simple_key_history() -> Result<(), AkdError> {
let db = AsyncInMemoryDatabase::new();
let storage = StorageManager::new_no_cache(&db);
let vrf = HardCodedAkdVRF {};
let akd = Directory::<_, _, Blake3>::new(&storage, &vrf, false).await?;
akd.publish(vec![
(
AkdLabel::from_utf8_str("hello"),
AkdValue::from_utf8_str("world"),
),
(
AkdLabel::from_utf8_str("hello2"),
AkdValue::from_utf8_str("world2"),
),
])
.await?;
akd.publish(vec![
(
AkdLabel::from_utf8_str("hello"),
AkdValue::from_utf8_str("world_2"),
),
(
AkdLabel::from_utf8_str("hello2"),
AkdValue::from_utf8_str("world2_2"),
),
])
.await?;
akd.publish(vec![
(
AkdLabel::from_utf8_str("hello"),
AkdValue::from_utf8_str("world3"),
),
(
AkdLabel::from_utf8_str("hello2"),
AkdValue::from_utf8_str("world4"),
),
])
.await?;
akd.publish(vec![
(
AkdLabel::from_utf8_str("hello3"),
AkdValue::from_utf8_str("world"),
),
(
AkdLabel::from_utf8_str("hello4"),
AkdValue::from_utf8_str("world2"),
),
])
.await?;
akd.publish(vec![(
AkdLabel::from_utf8_str("hello"),
AkdValue::from_utf8_str("world_updated"),
)])
.await?;
akd.publish(vec![
(
AkdLabel::from_utf8_str("hello3"),
AkdValue::from_utf8_str("world6"),
),
(
AkdLabel::from_utf8_str("hello4"),
AkdValue::from_utf8_str("world12"),
),
])
.await?;
let key_history_proof = akd
.key_history(&AkdLabel::from_utf8_str("hello"), HistoryParams::default())
.await?;
if key_history_proof.update_proofs.len() != 4 {
return Err(AkdError::TestErr(format!(
"Key history proof should have 4 update_proofs but has {:?}",
key_history_proof.update_proofs.len()
)));
}
let current_azks = akd.retrieve_current_azks().await?;
let current_epoch = current_azks.get_latest_epoch();
let root_hash = akd.get_root_hash(¤t_azks).await?;
let vrf_pk = akd.get_public_key().await?;
key_history_verify::<Blake3>(
&vrf_pk,
root_hash,
current_epoch,
AkdLabel::from_utf8_str("hello"),
key_history_proof,
HistoryVerificationParams::default(),
)?;
let key_history_proof = akd
.key_history(&AkdLabel::from_utf8_str("hello2"), HistoryParams::default())
.await?;
if key_history_proof.update_proofs.len() != 3 {
return Err(AkdError::TestErr(format!(
"Key history proof should have 3 update_proofs but has {:?}",
key_history_proof.update_proofs.len()
)));
}
key_history_verify::<Blake3>(
&vrf_pk,
root_hash,
current_epoch,
AkdLabel::from_utf8_str("hello2"),
key_history_proof,
HistoryVerificationParams::default(),
)?;
let key_history_proof = akd
.key_history(&AkdLabel::from_utf8_str("hello3"), HistoryParams::default())
.await?;
if key_history_proof.update_proofs.len() != 2 {
return Err(AkdError::TestErr(format!(
"Key history proof should have 2 update_proofs but has {:?}",
key_history_proof.update_proofs.len()
)));
}
key_history_verify::<Blake3>(
&vrf_pk,
root_hash,
current_epoch,
AkdLabel::from_utf8_str("hello3"),
key_history_proof,
HistoryVerificationParams::default(),
)?;
let key_history_proof = akd
.key_history(&AkdLabel::from_utf8_str("hello4"), HistoryParams::default())
.await?;
if key_history_proof.update_proofs.len() != 2 {
return Err(AkdError::TestErr(format!(
"Key history proof should have 2 update_proofs but has {:?}",
key_history_proof.update_proofs.len()
)));
}
key_history_verify::<Blake3>(
&vrf_pk,
root_hash,
current_epoch,
AkdLabel::from_utf8_str("hello4"),
key_history_proof.clone(),
HistoryVerificationParams::default(),
)?;
let mut borked_proof = key_history_proof;
borked_proof.update_proofs = borked_proof.update_proofs.into_iter().rev().collect();
let result = key_history_verify::<Blake3>(
&vrf_pk,
root_hash,
current_epoch,
AkdLabel::from_utf8_str("hello4"),
borked_proof,
HistoryVerificationParams::default(),
);
assert!(matches!(result, Err(_)), "{:?}", result);
Ok(())
}
#[tokio::test]
async fn test_limited_key_history() -> Result<(), AkdError> {
let db = AsyncInMemoryDatabase::new();
let storage_manager = StorageManager::new_no_cache(&db);
let vrf = HardCodedAkdVRF {};
let akd = Directory::<_, _, Blake3>::new(&storage_manager, &vrf, false).await?;
akd.publish(vec![
(
AkdLabel::from_utf8_str("hello"),
AkdValue::from_utf8_str("world"),
),
(
AkdLabel::from_utf8_str("hello2"),
AkdValue::from_utf8_str("world2"),
),
])
.await?;
akd.publish(vec![
(
AkdLabel::from_utf8_str("hello"),
AkdValue::from_utf8_str("world_2"),
),
(
AkdLabel::from_utf8_str("hello2"),
AkdValue::from_utf8_str("world2_2"),
),
])
.await?;
akd.publish(vec![
(
AkdLabel::from_utf8_str("hello"),
AkdValue::from_utf8_str("world3"),
),
(
AkdLabel::from_utf8_str("hello2"),
AkdValue::from_utf8_str("world4"),
),
])
.await?;
akd.publish(vec![
(
AkdLabel::from_utf8_str("hello3"),
AkdValue::from_utf8_str("world"),
),
(
AkdLabel::from_utf8_str("hello4"),
AkdValue::from_utf8_str("world2"),
),
])
.await?;
akd.publish(vec![(
AkdLabel::from_utf8_str("hello"),
AkdValue::from_utf8_str("world_updated"),
)])
.await?;
akd.publish(vec![
(
AkdLabel::from_utf8_str("hello3"),
AkdValue::from_utf8_str("world6"),
),
(
AkdLabel::from_utf8_str("hello4"),
AkdValue::from_utf8_str("world12"),
),
])
.await?;
akd.publish(vec![
(
AkdLabel::from_utf8_str("hello3"),
AkdValue::from_utf8_str("world7"),
),
(
AkdLabel::from_utf8_str("hello4"),
AkdValue::from_utf8_str("world13"),
),
])
.await?;
let vrf_pk = akd.get_public_key().await?;
let current_azks = akd.retrieve_current_azks().await?;
let current_epoch = current_azks.get_latest_epoch();
let root_hash = akd.get_root_hash(¤t_azks).await?;
let history_proof = akd
.key_history(
&AkdLabel::from_utf8_str("hello"),
HistoryParams::MostRecent(1),
)
.await?;
assert_eq!(1, history_proof.update_proofs.len());
assert_eq!(5, history_proof.update_proofs[0].epoch);
key_history_verify::<Blake3>(
&vrf_pk,
root_hash,
current_epoch,
AkdLabel::from_utf8_str("hello"),
history_proof,
HistoryVerificationParams::default(),
)?;
let history_proof = akd
.key_history(
&AkdLabel::from_utf8_str("hello"),
HistoryParams::MostRecent(3),
)
.await?;
assert_eq!(3, history_proof.update_proofs.len());
assert_eq!(5, history_proof.update_proofs[0].epoch);
assert_eq!(3, history_proof.update_proofs[1].epoch);
assert_eq!(2, history_proof.update_proofs[2].epoch);
key_history_verify::<Blake3>(
&vrf_pk,
root_hash,
current_epoch,
AkdLabel::from_utf8_str("hello"),
history_proof,
HistoryVerificationParams::default(),
)?;
let history_proof = akd
.key_history(
&AkdLabel::from_utf8_str("hello"),
HistoryParams::SinceEpoch(3),
)
.await?;
assert_eq!(2, history_proof.update_proofs.len());
assert_eq!(5, history_proof.update_proofs[0].epoch);
assert_eq!(3, history_proof.update_proofs[1].epoch);
key_history_verify::<Blake3>(
&vrf_pk,
root_hash,
current_epoch,
AkdLabel::from_utf8_str("hello"),
history_proof,
HistoryVerificationParams::default(),
)?;
Ok(())
}
#[tokio::test]
async fn test_malicious_key_history() -> Result<(), AkdError> {
let db = AsyncInMemoryDatabase::new();
let storage = StorageManager::new_no_cache(&db);
let vrf = HardCodedAkdVRF {};
let akd = Directory::<_, _, Blake3>::new(&storage, &vrf, false).await?;
akd.publish(vec![(
AkdLabel::from_utf8_str("hello"),
AkdValue::from_utf8_str("world"),
)])
.await?;
let corruption_2 = PublishCorruption::UnmarkedStaleVersion(AkdLabel::from_utf8_str("hello"));
akd.publish_malicious_update(
vec![(
AkdLabel::from_utf8_str("hello"),
AkdValue::from_utf8_str("world2"),
)],
corruption_2,
)
.await?;
let key_history_proof = akd
.key_history(&AkdLabel::from_utf8_str("hello"), HistoryParams::default())
.await?;
let current_azks = akd.retrieve_current_azks().await?;
let current_epoch = current_azks.get_latest_epoch();
let root_hash = akd.get_root_hash(¤t_azks).await?;
let vrf_pk = akd.get_public_key().await?;
key_history_verify::<Blake3>(
&vrf_pk,
root_hash,
current_epoch,
AkdLabel::from_utf8_str("hello"),
key_history_proof,
HistoryVerificationParams::default(),
).expect_err("The key history proof should fail here since the previous value was not marked stale at all");
let corruption_3 = PublishCorruption::MarkVersionStale(AkdLabel::from_utf8_str("hello"), 1);
akd.publish_malicious_update(
vec![(
AkdLabel::from_utf8_str("hello2"),
AkdValue::from_utf8_str("world"),
)],
corruption_3,
)
.await?;
let key_history_proof = akd
.key_history(&AkdLabel::from_utf8_str("hello"), HistoryParams::default())
.await?;
let current_azks = akd.retrieve_current_azks().await?;
let current_epoch = current_azks.get_latest_epoch();
let root_hash = akd.get_root_hash(¤t_azks).await?;
let vrf_pk = akd.get_public_key().await?;
key_history_verify::<Blake3>(
&vrf_pk,
root_hash,
current_epoch,
AkdLabel::from_utf8_str("hello"),
key_history_proof,
HistoryVerificationParams::default(),
).expect_err("The key history proof should fail here since the previous value was marked stale one epoch too late.");
Ok(())
}
#[tokio::test]
async fn test_simple_audit() -> Result<(), AkdError> {
let db = AsyncInMemoryDatabase::new();
let storage = StorageManager::new_no_cache(&db);
let vrf = HardCodedAkdVRF {};
let akd = Directory::<_, _, Blake3>::new(&storage, &vrf, false).await?;
akd.publish(vec![
(
AkdLabel::from_utf8_str("hello"),
AkdValue::from_utf8_str("world"),
),
(
AkdLabel::from_utf8_str("hello2"),
AkdValue::from_utf8_str("world2"),
),
])
.await?;
let root_hash_1 = akd
.get_root_hash(&akd.retrieve_current_azks().await?)
.await?;
akd.publish(vec![
(
AkdLabel::from_utf8_str("hello"),
AkdValue::from_utf8_str("world_2"),
),
(
AkdLabel::from_utf8_str("hello2"),
AkdValue::from_utf8_str("world2_2"),
),
])
.await?;
let root_hash_2 = akd
.get_root_hash(&akd.retrieve_current_azks().await?)
.await?;
akd.publish(vec![
(
AkdLabel::from_utf8_str("hello"),
AkdValue::from_utf8_str("world3"),
),
(
AkdLabel::from_utf8_str("hello2"),
AkdValue::from_utf8_str("world4"),
),
])
.await?;
let root_hash_3 = akd
.get_root_hash(&akd.retrieve_current_azks().await?)
.await?;
akd.publish(vec![
(
AkdLabel::from_utf8_str("hello3"),
AkdValue::from_utf8_str("world"),
),
(
AkdLabel::from_utf8_str("hello4"),
AkdValue::from_utf8_str("world2"),
),
])
.await?;
let root_hash_4 = akd
.get_root_hash(&akd.retrieve_current_azks().await?)
.await?;
akd.publish(vec![(
AkdLabel::from_utf8_str("hello"),
AkdValue::from_utf8_str("world_updated"),
)])
.await?;
let root_hash_5 = akd
.get_root_hash(&akd.retrieve_current_azks().await?)
.await?;
akd.publish(vec![
(
AkdLabel::from_utf8_str("hello3"),
AkdValue::from_utf8_str("world6"),
),
(
AkdLabel::from_utf8_str("hello4"),
AkdValue::from_utf8_str("world12"),
),
])
.await?;
let root_hash_6 = akd
.get_root_hash(&akd.retrieve_current_azks().await?)
.await?;
let audit_proof_1 = akd.audit(1, 2).await?;
audit_verify::<Blake3>(vec![root_hash_1, root_hash_2], audit_proof_1).await?;
let audit_proof_2 = akd.audit(1, 3).await?;
audit_verify::<Blake3>(vec![root_hash_1, root_hash_2, root_hash_3], audit_proof_2).await?;
let audit_proof_3 = akd.audit(1, 4).await?;
audit_verify::<Blake3>(
vec![root_hash_1, root_hash_2, root_hash_3, root_hash_4],
audit_proof_3,
)
.await?;
let audit_proof_4 = akd.audit(1, 5).await?;
audit_verify::<Blake3>(
vec![
root_hash_1,
root_hash_2,
root_hash_3,
root_hash_4,
root_hash_5,
],
audit_proof_4,
)
.await?;
let audit_proof_5 = akd.audit(2, 3).await?;
audit_verify::<Blake3>(vec![root_hash_2, root_hash_3], audit_proof_5).await?;
let audit_proof_6 = akd.audit(2, 4).await?;
audit_verify::<Blake3>(vec![root_hash_2, root_hash_3, root_hash_4], audit_proof_6).await?;
let audit_proof_7 = akd.audit(4, 6).await?;
audit_verify::<Blake3>(vec![root_hash_4, root_hash_5, root_hash_6], audit_proof_7).await?;
let invalid_audit = akd.audit(3, 3).await;
assert!(matches!(invalid_audit, Err(_)));
let invalid_audit = akd.audit(3, 2).await;
assert!(matches!(invalid_audit, Err(_)));
let invalid_audit = akd.audit(6, 7).await;
assert!(matches!(invalid_audit, Err(_)));
Ok(())
}
#[tokio::test]
async fn test_read_during_publish() -> Result<(), AkdError> {
let db = AsyncInMemoryDatabase::new();
let storage = StorageManager::new_no_cache(&db);
let vrf = HardCodedAkdVRF {};
let akd = Directory::<_, _, Blake3>::new(&storage, &vrf, false).await?;
akd.publish(vec![
(
AkdLabel::from_utf8_str("hello"),
AkdValue::from_utf8_str("world"),
),
(
AkdLabel::from_utf8_str("hello2"),
AkdValue::from_utf8_str("world2"),
),
])
.await?;
let root_hash_1 = akd
.get_root_hash(&akd.retrieve_current_azks().await?)
.await?;
akd.publish(vec![
(
AkdLabel::from_utf8_str("hello"),
AkdValue::from_utf8_str("world_2"),
),
(
AkdLabel::from_utf8_str("hello2"),
AkdValue::from_utf8_str("world2_2"),
),
])
.await?;
let root_hash_2 = akd
.get_root_hash(&akd.retrieve_current_azks().await?)
.await?;
let checkpoint_azks = akd.retrieve_current_azks().await.unwrap();
akd.publish(vec![
(
AkdLabel::from_utf8_str("hello"),
AkdValue::from_utf8_str("world_3"),
),
(
AkdLabel::from_utf8_str("hello2"),
AkdValue::from_utf8_str("world2_3"),
),
])
.await?;
db.set(DbRecord::Azks(checkpoint_azks))
.await
.expect("Error resetting directory to previous epoch");
let history_proof = akd
.key_history(&AkdLabel::from_utf8_str("hello"), HistoryParams::default())
.await?;
let (root_hashes, _) = get_key_history_hashes(&akd, &history_proof).await?;
assert_eq!(2, root_hashes.len());
let vrf_pk = akd.get_public_key().await?;
let current_azks = akd.retrieve_current_azks().await?;
let current_epoch = current_azks.get_latest_epoch();
let root_hash = akd.get_root_hash(¤t_azks).await?;
key_history_verify::<Blake3>(
&vrf_pk,
root_hash,
current_epoch,
AkdLabel::from_utf8_str("hello"),
history_proof,
HistoryVerificationParams::default(),
)?;
let lookup_proof = akd.lookup(AkdLabel::from_utf8_str("hello")).await?;
assert_eq!(
AkdValue::from_utf8_str("world_2"),
lookup_proof.plaintext_value
);
lookup_verify::<Blake3>(
&vrf_pk,
root_hash,
AkdLabel::from_utf8_str("hello"),
lookup_proof,
)?;
let audit_proof = akd.audit(1, 2).await?;
audit_verify::<Blake3>(vec![root_hash_1, root_hash_2], audit_proof).await?;
let invalid_audit = akd.audit(2, 3).await;
assert!(matches!(invalid_audit, Err(_)));
Ok(())
}
#[tokio::test]
async fn test_directory_read_only_mode() -> Result<(), AkdError> {
let db = AsyncInMemoryDatabase::new();
let storage = StorageManager::new_no_cache(&db);
let vrf = HardCodedAkdVRF {};
let akd = Directory::<_, _, Blake3>::new(&storage, &vrf, true).await;
assert!(matches!(akd, Err(_)));
let akd = Directory::<_, _, Blake3>::new(&storage, &vrf, false).await;
assert!(matches!(akd, Ok(_)));
let akd = Directory::<_, _, Blake3>::new(&storage, &vrf, true).await?;
assert!(matches!(akd.publish(vec![]).await, Err(_)));
Ok(())
}
#[tokio::test]
async fn test_directory_polling_azks_change() -> Result<(), AkdError> {
let db = AsyncInMemoryDatabase::new();
let storage = StorageManager::new(&db, None, None, None);
let vrf = HardCodedAkdVRF {};
let writer = Directory::<_, _, Blake3>::new(&storage, &vrf, false).await?;
writer
.publish(vec![
(
AkdLabel::from_utf8_str("hello"),
AkdValue::from_utf8_str("world"),
),
(
AkdLabel::from_utf8_str("hello2"),
AkdValue::from_utf8_str("world2"),
),
])
.await?;
let reader = Directory::<_, _, Blake3>::new(&storage, &vrf, true).await?;
let (tx, mut rx) = tokio::sync::mpsc::channel(10);
let reader_clone = reader.clone();
let _join_handle = tokio::task::spawn(async move {
reader_clone
.poll_for_azks_changes(tokio::time::Duration::from_millis(100), Some(tx))
.await
});
async_poll_helper_proof(&reader, AkdValue::from_utf8_str("world")).await?;
writer
.publish(vec![
(
AkdLabel::from_utf8_str("hello"),
AkdValue::from_utf8_str("world_2"),
),
(
AkdLabel::from_utf8_str("hello2"),
AkdValue::from_utf8_str("world2_2"),
),
])
.await?;
let notification = tokio::time::timeout(tokio::time::Duration::from_secs(10), rx.recv()).await;
assert!(matches!(notification, Ok(Some(()))));
async_poll_helper_proof(&reader, AkdValue::from_utf8_str("world_2")).await?;
Ok(())
}
#[tokio::test]
async fn test_tombstoned_key_history() -> Result<(), AkdError> {
let db = AsyncInMemoryDatabase::new();
let storage = StorageManager::new_no_cache(&db);
let vrf = HardCodedAkdVRF {};
let akd = Directory::<_, _, Blake3>::new(&storage, &vrf, false).await?;
akd.publish(vec![(
AkdLabel::from_utf8_str("hello"),
AkdValue::from_utf8_str("world"),
)])
.await?;
akd.publish(vec![(
AkdLabel::from_utf8_str("hello"),
AkdValue::from_utf8_str("world2"),
)])
.await?;
akd.publish(vec![(
AkdLabel::from_utf8_str("hello"),
AkdValue::from_utf8_str("world3"),
)])
.await?;
akd.publish(vec![(
AkdLabel::from_utf8_str("hello"),
AkdValue::from_utf8_str("world4"),
)])
.await?;
akd.publish(vec![(
AkdLabel::from_utf8_str("hello"),
AkdValue::from_utf8_str("world5"),
)])
.await?;
let vrf_pk = akd.get_public_key().await?;
let tombstones = [
crate::storage::types::ValueStateKey("hello".as_bytes().to_vec(), 1u64),
crate::storage::types::ValueStateKey("hello".as_bytes().to_vec(), 2u64),
];
storage.tombstone_value_states(&tombstones).await?;
let history_proof = akd
.key_history(&AkdLabel::from_utf8_str("hello"), HistoryParams::default())
.await?;
assert_eq!(5, history_proof.update_proofs.len());
let current_azks = akd.retrieve_current_azks().await?;
let current_epoch = current_azks.get_latest_epoch();
let root_hash = akd.get_root_hash(¤t_azks).await?;
let tombstones = key_history_verify::<Blake3>(
&vrf_pk,
root_hash,
current_epoch,
AkdLabel::from_utf8_str("hello"),
history_proof.clone(),
HistoryVerificationParams::default(),
);
assert!(matches!(tombstones, Err(_)));
let results = key_history_verify::<Blake3>(
&vrf_pk,
root_hash,
current_epoch,
AkdLabel::from_utf8_str("hello"),
history_proof,
HistoryVerificationParams::AllowMissingValues,
)?;
assert_eq!(false, results[0].value.0 == crate::TOMBSTONE);
assert_eq!(false, results[1].value.0 == crate::TOMBSTONE);
assert_eq!(false, results[2].value.0 == crate::TOMBSTONE);
assert_eq!(true, results[3].value.0 == crate::TOMBSTONE);
assert_eq!(true, results[4].value.0 == crate::TOMBSTONE);
Ok(())
}
#[tokio::test]
async fn test_simple_lookup_for_small_tree_blake() -> Result<(), AkdError> {
let db = AsyncInMemoryDatabase::new();
let storage = StorageManager::new_no_cache(&db);
let vrf = HardCodedAkdVRF {};
let akd = Directory::<_, _, Blake3>::new(&storage, &vrf, false).await?;
let mut updates = vec![];
for i in 0..1 {
updates.push((
AkdLabel(format!("hello1{}", i).as_bytes().to_vec()),
AkdValue(format!("hello1{}", i).as_bytes().to_vec()),
));
}
akd.publish(updates).await?;
let target_label = AkdLabel(format!("hello1{}", 0).as_bytes().to_vec());
let lookup_proof = akd.lookup(target_label.clone()).await?;
let current_azks = akd.retrieve_current_azks().await?;
let root_hash = akd.get_root_hash(¤t_azks).await?;
let vrf_pk = vrf.get_vrf_public_key().await?;
let akd_result = crate::client::lookup_verify::<Blake3>(
&vrf_pk,
root_hash,
target_label.clone(),
lookup_proof,
)?;
assert_eq!(
akd_result,
VerifyResult {
epoch: 1,
version: 1,
value: AkdValue::from_utf8_str("hello10"),
},
);
Ok(())
}
#[tokio::test]
async fn test_simple_lookup_for_small_tree_sha256() -> Result<(), AkdError> {
let db = AsyncInMemoryDatabase::new();
let storage = StorageManager::new_no_cache(&db);
let vrf = HardCodedAkdVRF {};
let akd = Directory::<_, _, Sha3>::new(&storage, &vrf, false).await?;
let mut updates = vec![];
for i in 0..1 {
updates.push((
AkdLabel(format!("hello{}", i).as_bytes().to_vec()),
AkdValue(format!("hello{}", i).as_bytes().to_vec()),
));
}
akd.publish(updates).await?;
let target_label = AkdLabel(format!("hello{}", 0).as_bytes().to_vec());
let lookup_proof = akd.lookup(target_label.clone()).await?;
let current_azks = akd.retrieve_current_azks().await?;
let root_hash = akd.get_root_hash(¤t_azks).await?;
let vrf_pk = vrf.get_vrf_public_key().await?;
let akd_result =
crate::client::lookup_verify(&vrf_pk, root_hash, target_label.clone(), lookup_proof)?;
assert_eq!(
akd_result,
VerifyResult {
epoch: 1,
version: 1,
value: AkdValue::from_utf8_str("hello0"),
},
);
Ok(())
}
async fn async_poll_helper_proof<T: Database + Sync + Send, V: VRFKeyStorage, H: Hasher>(
reader: &Directory<T, V, H>,
value: AkdValue,
) -> Result<(), AkdError> {
let lookup_proof = reader.lookup(AkdLabel::from_utf8_str("hello")).await?;
assert_eq!(value, lookup_proof.plaintext_value);
let current_azks = reader.retrieve_current_azks().await?;
let root_hash = reader.get_root_hash(¤t_azks).await?;
let pk = reader.get_public_key().await?;
lookup_verify(
&pk,
root_hash,
AkdLabel::from_utf8_str("hello"),
lookup_proof,
)?;
Ok(())
}