1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
//! A Rust implementation of Selection-Sensitive Attribute-Based Key
//! Derivation, providing a novel scheme where cryptographic keys are derived
//! from a collection of attributes, with sensitivity to selection within the
//! collection.
//!
//! An **attribute** is a piece of data that contributes to key derivation. A
//! collection of attributes is first hardened using memory-hard key
//! derivation, then organised into a keyspace from which attribute-based keys
//! can be selected.
//!
//! A **keyspace** consists of:
//! - A collection of hardened attribute values derived through parallel
//! [Argon2id](argon2::Argon2) key derivation with per-attribute salts.
//! - A proof-of-work constraint parameter for
//! [annihilative pair](annihilation::AnnihlKey::new_pair) generation.
//!
//! Key derivation requires selecting a subset of attribute indices, which
//! partitions the collection into two sets: selected and remaining attributes.
//! These are concatenated to form keying material for an
//! **annihilative pair**, where selected attributes become key material and
//! remaining attributes become antikey material. The derivation process mines
//! a pair satisfying the configured proof-of-work constraint, computes the
//! pair's [annihilation key](annihilation::AnnihlKey::to_annihilation), then
//! uses this key as a seed for [ChaCha8 CSPRNG](rand_chacha::ChaCha8Rng)
//! expansion to produce the final derived key.
//!
//! Derived keys depend on both which attributes are selected and which are
//! not. Different selections produce cryptographically independent keys,
//! even when there is overlap in selection. The memory-hard nature of Argon2id
//! makes brute-force attacks on individual attributes computationally
//! expensive, and the derived key's dependence on all attributes prevents an
//! attacker with knowledge of attribute selection from optimising by
//! discarding remaining attributes.
//!
//! The requirement to select at least one attribute, but not all attributes,
//! ensures that both partition sets are non-empty and the annihilative pair
//! can be constructed.
//!
//! # Example
//! ```
//! use attrkey::{Attributes, Params};
//! use sha2::Sha256;
//!
//! fn main() {
//! let arr = vec![
//! b"Pigs on the Wing I".to_vec(),
//! b"Dogs".to_vec(),
//! b"Pigs (Three Different Ones)".to_vec(),
//! b"Sheep".to_vec(),
//! b"Pigs on the Wing II".to_vec(),
//! ];
//!
//! // Create a collection of attributes with default parameters
//! let attributes = Attributes::<Sha256>::new(arr, Params::default())
//! .expect("valid set of attributes should produce collection");
//!
//! // Harden attributes into a keyspace
//! let salt = b"Animals";
//! let keyspace = attributes
//! .harden(salt)
//! .expect("Argon2id should be able to harden all attributes");
//!
//! // Derive keys from two selections within the same keyspace
//! let selection_1 = vec![0, 2, 4];
//! let selection_2 = vec![1, 3];
//!
//! let dk_1 = keyspace
//! .derive_key(&selection_1, Some(32))
//! .expect("valid selection");
//!
//! let mut dk_2 = [0u8; 32];
//! keyspace
//! .derive_key_into(&selection_2, &mut dk_2)
//! .expect("valid selection");
//!
//! // Different selections produce different keys
//! assert_ne!(dk_1, dk_2);
//! }
//! ```
pub use crateArrkeyError;
pub use crateParams;
pub use Attributes;
pub use Keyspace;