use chia_protocol::Bytes32;
use chia_sha2::Sha256;
use hex_literal::hex;
pub const DIGSTORE_OWNER_HINT_DOMAIN: &[u8] = b"dig:datastore:owner:v1";
pub const DATASTORE_LAUNCHER_HINT: Bytes32 = Bytes32::new(hex!(
"aa7e5b234e1d55967bf0a316395a2eab6cb3370332c0f251f0e44a5afb84fc68"
));
pub const DID_PROFILE_LAUNCHER_HINT: Bytes32 = Bytes32::new(hex!(
"9c1d6b6d5d530dd613f4d7d2ced6b704ae8423377e4d567518493159c1d21d01"
));
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum StoreKind {
File,
DidProfile,
}
#[must_use]
pub fn launcher_hint_for(kind: StoreKind) -> Bytes32 {
match kind {
StoreKind::File => DATASTORE_LAUNCHER_HINT,
StoreKind::DidProfile => DID_PROFILE_LAUNCHER_HINT,
}
}
#[must_use]
pub fn from_launcher_hint(memo: Bytes32) -> Option<StoreKind> {
if memo == DATASTORE_LAUNCHER_HINT {
Some(StoreKind::File)
} else if memo == DID_PROFILE_LAUNCHER_HINT {
Some(StoreKind::DidProfile)
} else {
None
}
}
#[must_use]
pub fn digstore_owner_hint(owner_puzzle_hash: Bytes32) -> Bytes32 {
let mut hasher = Sha256::new();
hasher.update(DIGSTORE_OWNER_HINT_DOMAIN);
hasher.update(owner_puzzle_hash);
Bytes32::new(hasher.finalize())
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn launcher_hint_is_sha256_of_datastore() {
let mut hasher = Sha256::new();
hasher.update(b"datastore");
assert_eq!(DATASTORE_LAUNCHER_HINT, Bytes32::new(hasher.finalize()));
}
#[test]
fn owner_hint_matches_domain_prefixed_sha256() {
let owner_ph = Bytes32::new([0x11; 32]);
let mut hasher = Sha256::new();
hasher.update(b"dig:datastore:owner:v1");
hasher.update(owner_ph);
let expected = Bytes32::new(hasher.finalize());
assert_eq!(digstore_owner_hint(owner_ph), expected);
}
#[test]
fn owner_hint_is_deterministic_and_owner_specific() {
let a = Bytes32::new([0x11; 32]);
let b = Bytes32::new([0x22; 32]);
assert_eq!(digstore_owner_hint(a), digstore_owner_hint(a));
assert_ne!(digstore_owner_hint(a), digstore_owner_hint(b));
}
#[test]
fn domain_tag_is_the_pinned_bytes() {
assert_eq!(DIGSTORE_OWNER_HINT_DOMAIN, b"dig:datastore:owner:v1");
}
#[test]
fn did_profile_hint_is_sha256_of_domain() {
let mut hasher = Sha256::new();
hasher.update(b"dig:datastore:profile:v1");
assert_eq!(DID_PROFILE_LAUNCHER_HINT, Bytes32::new(hasher.finalize()));
}
#[test]
fn file_and_did_profile_hints_are_distinct() {
assert_ne!(DATASTORE_LAUNCHER_HINT, DID_PROFILE_LAUNCHER_HINT);
}
#[test]
fn launcher_hint_for_maps_each_kind() {
assert_eq!(launcher_hint_for(StoreKind::File), DATASTORE_LAUNCHER_HINT);
assert_eq!(
launcher_hint_for(StoreKind::DidProfile),
DID_PROFILE_LAUNCHER_HINT
);
}
#[test]
fn from_launcher_hint_round_trips_and_rejects_unknown() {
for kind in [StoreKind::File, StoreKind::DidProfile] {
assert_eq!(from_launcher_hint(launcher_hint_for(kind)), Some(kind));
}
assert_eq!(from_launcher_hint(Bytes32::new([0x00; 32])), None);
}
#[test]
fn legacy_launcher_hint_classifies_as_file() {
let legacy_memo = DATASTORE_LAUNCHER_HINT;
assert_eq!(from_launcher_hint(legacy_memo), Some(StoreKind::File));
}
}