Convert API to const_generics
This commit is contained in:
parent
a0d2cb7d12
commit
e26981e6af
18
README.md
18
README.md
|
@ -69,8 +69,7 @@ provided them (depending on the efficiency of the decryption method).
|
|||
Generate a key pair:
|
||||
|
||||
use fuzzytags::FuzzySecretKey;
|
||||
let gamma = 24;
|
||||
let secret_key = FuzzySecretKey::generate(gamma);
|
||||
let secret_key = FuzzySecretKey::<24>::generate();
|
||||
|
||||
`key.public_key` can be given to parties who you want to be able to communicate with you over a specific anonymous
|
||||
messaging service / privacy-preserving application.
|
||||
|
@ -85,8 +84,7 @@ validate against a random public key with a maximum probability of _2^-gamma_.
|
|||
Once in possession of a public key, a party in a metadata resistant app can use it to generate tags:
|
||||
|
||||
use fuzzytags::FuzzySecretKey;
|
||||
let gamma = 24;
|
||||
let secret_key = FuzzySecretKey::generate(gamma);
|
||||
let secret_key = FuzzySecretKey::<24>::generate();
|
||||
let public_key = secret_key.public_key();
|
||||
|
||||
// Give public key to a another party...
|
||||
|
@ -102,8 +100,7 @@ First it is necessary to extract a detection key for a given false positive prob
|
|||
This extracted key can then be given to an adversarial server. The server can then test a given tag against the detection key e.g.:
|
||||
|
||||
use fuzzytags::FuzzySecretKey;
|
||||
let gamma = 24;
|
||||
let secret_key = FuzzySecretKey::generate(gamma);
|
||||
let secret_key = FuzzySecretKey::<24>::generate();
|
||||
let public_key = secret_key.public_key();
|
||||
// extract a detection key
|
||||
let detection_key = secret_key.extract(5);
|
||||
|
@ -127,8 +124,8 @@ opens up applications like **multiple broadcast** and **deniable sending**.
|
|||
|
||||
|
||||
use fuzzytags::{FuzzySecretKey, FuzzyPublicKey};
|
||||
let secret_key_1 = FuzzySecretKey::generate(24);
|
||||
let secret_key_2 = FuzzySecretKey::generate(24);
|
||||
let secret_key_1 = FuzzySecretKey::<24>::generate();
|
||||
let secret_key_2 = FuzzySecretKey::<24>::generate();
|
||||
let public_key_1 = secret_key_1.public_key(); // give this to a sender
|
||||
let public_key_2 = secret_key_2.public_key(); // give this to a sender
|
||||
// Will validate for detection keys derived from both secret_key_1 and secret_key_2 up
|
||||
|
@ -145,8 +142,7 @@ of different approaches e.g.:
|
|||
use fuzzytags::FuzzySecretKey;
|
||||
use fuzzytags::FuzzyTag;
|
||||
|
||||
let gamma = 24;
|
||||
let secret_key = FuzzySecretKey::generate(gamma);
|
||||
let secret_key = FuzzySecretKey::<24>::generate();
|
||||
let public_key = secret_key.public_key();
|
||||
|
||||
// Give public key to a another party...
|
||||
|
@ -158,7 +154,7 @@ of different approaches e.g.:
|
|||
println!("Serialized: {}", serialized_tag);
|
||||
|
||||
// We can then deserialize with:
|
||||
let deserialized_tag: Result<FuzzyTag, serde_json::Error> = serde_json::from_str(&serialized_tag);
|
||||
let deserialized_tag: Result<FuzzyTag<24>, serde_json::Error> = serde_json::from_str(&serialized_tag);
|
||||
println!("Deserialized: {}", deserialized_tag.unwrap());
|
||||
|
||||
## Benchmarks
|
||||
|
|
|
@ -19,7 +19,8 @@ fn_single_line = false
|
|||
where_single_line = false
|
||||
imports_indent = "Block"
|
||||
imports_layout = "Mixed"
|
||||
merge_imports = false
|
||||
imports_granularity = "Preserve"
|
||||
group_imports = "Preserve"
|
||||
reorder_imports = true
|
||||
reorder_modules = true
|
||||
reorder_impl_items = false
|
||||
|
@ -34,6 +35,7 @@ overflow_delimited_expr = false
|
|||
struct_field_align_threshold = 0
|
||||
enum_discrim_align_threshold = 0
|
||||
match_arm_blocks = true
|
||||
match_arm_leading_pipes = "Never"
|
||||
force_multiline_blocks = false
|
||||
fn_args_layout = "Tall"
|
||||
brace_style = "SameLineWhere"
|
||||
|
@ -52,7 +54,7 @@ use_field_init_shorthand = false
|
|||
force_explicit_abi = true
|
||||
condense_wildcard_suffixes = false
|
||||
color = "Auto"
|
||||
required_version = "1.4.21"
|
||||
required_version = "1.4.34"
|
||||
unstable_features = false
|
||||
disable_all_formatting = false
|
||||
skip_children = false
|
||||
|
|
217
src/lib.rs
217
src/lib.rs
|
@ -1,7 +1,6 @@
|
|||
#![deny(missing_docs)]
|
||||
#![feature(array_methods)]
|
||||
#![feature(external_doc)]
|
||||
#![feature(in_band_lifetimes)]
|
||||
#![feature(const_generics)]
|
||||
#![doc(include = "../README.md")]
|
||||
#![doc(include = "../ANONYMITY.md")]
|
||||
use bit_vec::BitVec;
|
||||
|
@ -25,19 +24,19 @@ use brute_force::brute_force;
|
|||
|
||||
/// A tag is a probabilistic cryptographic structure. When constructed for a given `FuzzyPublicKey`
|
||||
/// it will pass the `FuzzyDetectionKey::test` 100% of the time. For other public keys
|
||||
/// it will pass the test with probability `gamma` related to the security parameter of the system.
|
||||
/// it will pass the test with probability `GAMMA` related to the security parameter of the system.
|
||||
/// This system provides the following security properties:
|
||||
/// * Correctness: Valid tags constructed for a specific public key will always validate when tested using the detection key
|
||||
/// * Fuzziness: Invalid tags will produce false positives with probability _p_ related to the security property (_γ_)
|
||||
/// * Security: An adversarial server with access to the detection key is unable to distinguish false positives from true positives. (Detection Ambiguity)
|
||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||
pub struct FuzzyTag {
|
||||
pub struct FuzzyTag<const GAMMA: u8> {
|
||||
u: RistrettoPoint,
|
||||
y: Scalar,
|
||||
ciphertexts: BitVec,
|
||||
}
|
||||
|
||||
impl Serialize for FuzzyTag {
|
||||
impl<const GAMMA: u8> Serialize for FuzzyTag<{ GAMMA }> {
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
S: Serializer,
|
||||
|
@ -52,21 +51,21 @@ impl Serialize for FuzzyTag {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'de> Deserialize<'de> for FuzzyTag {
|
||||
impl<'de, const GAMMA: u8> Deserialize<'de> for FuzzyTag<{ GAMMA }> {
|
||||
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||
where
|
||||
D: Deserializer<'de>,
|
||||
{
|
||||
struct FuzzyTagVisitor;
|
||||
struct FuzzyTagVisitor<const GAMMA: u8>;
|
||||
|
||||
impl<'de> Visitor<'de> for FuzzyTagVisitor {
|
||||
type Value = FuzzyTag;
|
||||
impl<'de, const GAMMA: u8> Visitor<'de> for FuzzyTagVisitor<{ GAMMA }> {
|
||||
type Value = FuzzyTag<{ GAMMA }>;
|
||||
|
||||
fn expecting(&self, formatter: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
|
||||
formatter.write_str("64 bytes + gamma+bits of data")
|
||||
formatter.write_str("64 bytes + GAMMA+bits of data")
|
||||
}
|
||||
|
||||
fn visit_seq<A>(self, mut seq: A) -> Result<FuzzyTag, A::Error>
|
||||
fn visit_seq<A>(self, mut seq: A) -> Result<FuzzyTag<{ GAMMA }>, A::Error>
|
||||
where
|
||||
A: serde::de::SeqAccess<'de>,
|
||||
{
|
||||
|
@ -80,24 +79,23 @@ impl<'de> Deserialize<'de> for FuzzyTag {
|
|||
_ => break,
|
||||
}
|
||||
}
|
||||
FuzzyTag::decompress(&bytes).ok_or(serde::de::Error::custom("invalid fuzzytag"))
|
||||
FuzzyTag::<GAMMA>::decompress(&bytes).ok_or(serde::de::Error::custom("invalid fuzzytag"))
|
||||
}
|
||||
}
|
||||
|
||||
// support up to gamma = 64
|
||||
deserializer.deserialize_tuple(72, FuzzyTagVisitor)
|
||||
// support up to GAMMA = 64
|
||||
deserializer.deserialize_tuple(72, FuzzyTagVisitor::<GAMMA>)
|
||||
}
|
||||
}
|
||||
|
||||
impl FuzzyTag {
|
||||
impl<const GAMMA: u8> FuzzyTag<{ GAMMA }> {
|
||||
/// An optimal sized copy of the tag
|
||||
/// Compressed u || y || ciphertext
|
||||
/// Ciphertext is right-padded with zeros to the nearest byte
|
||||
/// You probably want to use one of the many serde `serialize` apis instead (see README)
|
||||
/// ```
|
||||
/// use fuzzytags::FuzzySecretKey;
|
||||
/// let gamma = 24;
|
||||
/// let secret_key = FuzzySecretKey::generate(gamma);
|
||||
/// let secret_key = FuzzySecretKey::<24>::generate();
|
||||
/// let public_key = secret_key.public_key();
|
||||
/// // extract a detection key
|
||||
/// let detection_key = secret_key.extract(5);
|
||||
|
@ -119,8 +117,7 @@ impl FuzzyTag {
|
|||
/// You probably want to use one of the many serde `deserialize` apis instead (see README)
|
||||
/// ```
|
||||
/// use fuzzytags::{FuzzySecretKey, FuzzyTag};
|
||||
/// let gamma = 24;
|
||||
/// let secret_key = FuzzySecretKey::generate(gamma);
|
||||
/// let secret_key = FuzzySecretKey::<24>::generate();
|
||||
/// let public_key = secret_key.public_key();
|
||||
/// // extract a detection key
|
||||
/// let detection_key = secret_key.extract(5);
|
||||
|
@ -132,16 +129,26 @@ impl FuzzyTag {
|
|||
/// let decompressed_tag = FuzzyTag::decompress(&compressed_tag).unwrap();
|
||||
/// assert_eq!(tag, decompressed_tag);
|
||||
/// ```
|
||||
pub fn decompress(bytes: &[u8]) -> Option<FuzzyTag> {
|
||||
pub fn decompress(bytes: &[u8]) -> Option<FuzzyTag<{ GAMMA }>> {
|
||||
if bytes.len() > 64 {
|
||||
let (u_bytes, rest) = bytes.split_at(32);
|
||||
let (y_bytes, ciphertext) = rest.split_at(32);
|
||||
return match CompressedRistretto::from_slice(u_bytes).decompress() {
|
||||
Some(u) => Some(FuzzyTag {
|
||||
u,
|
||||
y: Scalar::from_bits(<[u8; 32]>::try_from(y_bytes).unwrap()),
|
||||
ciphertexts: BitVec::from_bytes(ciphertext),
|
||||
}),
|
||||
|
||||
// if the ciphertext is too short, then this is an invalid tag
|
||||
let min_bytes = GAMMA / 8;
|
||||
if ciphertext.len() < min_bytes as usize {
|
||||
return None;
|
||||
}
|
||||
|
||||
// This shouldn't actually fail, but for the safety...
|
||||
let y_bytes_fixed = match <[u8; 32]>::try_from(y_bytes) {
|
||||
Ok(fixed_size) => fixed_size,
|
||||
_ => return None,
|
||||
};
|
||||
let mut ciphertexts = BitVec::from_bytes(ciphertext);
|
||||
ciphertexts.truncate(GAMMA as usize);
|
||||
return match (CompressedRistretto::from_slice(u_bytes).decompress(), Scalar::from_canonical_bytes(y_bytes_fixed)) {
|
||||
(Some(u), Some(y)) => Some(FuzzyTag { u, y, ciphertexts }),
|
||||
_ => None,
|
||||
};
|
||||
}
|
||||
|
@ -149,7 +156,7 @@ impl FuzzyTag {
|
|||
}
|
||||
}
|
||||
|
||||
impl Display for FuzzyTag {
|
||||
impl<const GAMMA: u8> Display for FuzzyTag<{ GAMMA }> {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
||||
write!(
|
||||
f,
|
||||
|
@ -164,35 +171,35 @@ impl Display for FuzzyTag {
|
|||
/// The complete secret key. Can't directly be used for testing. Instead you will need to generate
|
||||
/// a FuzzyDetectionKey using extract
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
pub struct FuzzySecretKey {
|
||||
pub struct FuzzySecretKey<const GAMMA: u8> {
|
||||
/// the detection key - this can be given to adversarial servers to help probabilistically
|
||||
/// filter messages (with a false-positive rate derived from γ and a 0% false negative rate)
|
||||
secret_key: Vec<Scalar>,
|
||||
/// the public key - this can be given to people who you want to contact you
|
||||
public_key: FuzzyPublicKey,
|
||||
public_key: FuzzyPublicKey<{ GAMMA }>,
|
||||
}
|
||||
|
||||
impl FuzzySecretKey {
|
||||
/// Generate a new Key Pair given a security parameter `gamma`. Tags generated for a given
|
||||
impl<const GAMMA: u8> FuzzySecretKey<{ GAMMA }> {
|
||||
/// Generate a new Key Pair given a security parameter `GAMMA`. Tags generated for a given
|
||||
/// `FuzzyPublicKey::flag` will pass the `FuzzyDetectionKey::test` for other public
|
||||
/// keys with probability $ 2 ^ -8 $
|
||||
/// Example:
|
||||
/// ```
|
||||
/// use fuzzytags::{FuzzySecretKey};
|
||||
/// let secret_key = FuzzySecretKey::generate(5);
|
||||
/// let secret_key = FuzzySecretKey::<24>::generate();
|
||||
/// ```
|
||||
pub fn generate(gamma: usize) -> FuzzySecretKey {
|
||||
pub fn generate() -> FuzzySecretKey<{ GAMMA }> {
|
||||
let mut rng = OsRng::default();
|
||||
let g = RISTRETTO_BASEPOINT_POINT;
|
||||
let mut secret_key = vec![];
|
||||
let mut p_keys = vec![];
|
||||
for _i in 0..gamma {
|
||||
for _i in 0..GAMMA {
|
||||
let sk_i = Scalar::random(&mut rng);
|
||||
let pk_i = g.mul(sk_i);
|
||||
secret_key.push(sk_i);
|
||||
p_keys.push(pk_i);
|
||||
}
|
||||
FuzzySecretKey {
|
||||
FuzzySecretKey::<GAMMA> {
|
||||
secret_key,
|
||||
public_key: FuzzyPublicKey { 0: p_keys },
|
||||
}
|
||||
|
@ -202,28 +209,29 @@ impl FuzzySecretKey {
|
|||
/// Example:
|
||||
/// ```
|
||||
/// use fuzzytags::{FuzzySecretKey};
|
||||
/// let secret_key = FuzzySecretKey::generate(24);
|
||||
/// let secret_key = FuzzySecretKey::<24>::generate();
|
||||
/// let detection_key = secret_key.extract(2);
|
||||
/// ```
|
||||
pub fn extract(&self, n: usize) -> FuzzyDetectionKey {
|
||||
pub fn extract(&self, n: usize) -> FuzzyDetectionKey<{ GAMMA }> {
|
||||
let parts = self.secret_key.iter().take(n).cloned().collect();
|
||||
FuzzyDetectionKey { 0: parts }
|
||||
FuzzyDetectionKey::<GAMMA> { 0: parts }
|
||||
}
|
||||
|
||||
/// derive the public key for this key
|
||||
/// Example:
|
||||
/// ```
|
||||
/// use fuzzytags::FuzzySecretKey;
|
||||
/// let secret_key = FuzzySecretKey::generate(24);
|
||||
/// let secret_key = FuzzySecretKey::<24>::generate();
|
||||
/// let public_key = secret_key.public_key();
|
||||
/// ```
|
||||
pub fn public_key(&self) -> FuzzyPublicKey {
|
||||
pub fn public_key(&self) -> FuzzyPublicKey<{ GAMMA }> {
|
||||
self.public_key.clone()
|
||||
}
|
||||
|
||||
/// a hash function that takes 3 ristretto points as a parameter and outputs 0 or 1.
|
||||
fn h(u: RistrettoPoint, h: RistrettoPoint, w: RistrettoPoint) -> u8 {
|
||||
let mut hash = sha3::Sha3_256::new();
|
||||
hash.update(&[GAMMA]);
|
||||
hash.update(u.compress().as_bytes());
|
||||
hash.update(h.compress().as_bytes());
|
||||
hash.update(w.compress().as_bytes());
|
||||
|
@ -233,7 +241,11 @@ impl FuzzySecretKey {
|
|||
/// a hash function which takes a ristretto point and a vector of ciphertexts and outputs a
|
||||
/// ristretto scalar.
|
||||
fn g(u: RistrettoPoint, points: &BitVec) -> Scalar {
|
||||
let mut input = points.to_bytes().as_slice().to_vec();
|
||||
let mut input = vec![];
|
||||
input.push(GAMMA);
|
||||
input.extend_from_slice(points.to_bytes().as_slice());
|
||||
// enforce separation between ciphertext and u
|
||||
input.extend_from_slice("|| u: ".as_bytes());
|
||||
input.extend_from_slice(u.compress().as_bytes());
|
||||
Scalar::hash_from_bytes::<Sha3_512>(input.as_slice())
|
||||
}
|
||||
|
@ -242,9 +254,9 @@ impl FuzzySecretKey {
|
|||
/// A collection of "secret" data that can be used to determine if a `FuzzyTag` was intended for
|
||||
/// the derived public key with probability p
|
||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
pub struct FuzzyDetectionKey(Vec<Scalar>);
|
||||
pub struct FuzzyDetectionKey<const GAMMA: u8>(Vec<Scalar>);
|
||||
|
||||
impl FuzzyDetectionKey {
|
||||
impl<const GAMMA: u8> FuzzyDetectionKey<{ GAMMA }> {
|
||||
/// a convenient id for a detection key for internal accounting purposes
|
||||
/// do not expose this to applications
|
||||
pub fn id(&self) -> String {
|
||||
|
@ -256,18 +268,17 @@ impl FuzzyDetectionKey {
|
|||
}
|
||||
}
|
||||
|
||||
impl Display for FuzzyDetectionKey {
|
||||
impl<const GAMMA: u8> Display for FuzzyDetectionKey<{ GAMMA }> {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
||||
write!(f, "{}", self.id())
|
||||
}
|
||||
}
|
||||
|
||||
impl FuzzyDetectionKey {
|
||||
impl<const GAMMA: u8> FuzzyDetectionKey<{ GAMMA }> {
|
||||
/// calculate the ideal false positive rate of this detection key
|
||||
/// ```
|
||||
/// use fuzzytags::FuzzySecretKey;
|
||||
/// let gamma = 24;
|
||||
/// let secret_key = FuzzySecretKey::generate(gamma);
|
||||
/// let secret_key = FuzzySecretKey::<24>::generate();
|
||||
/// let public_key = secret_key.public_key();
|
||||
/// // extract a detection key
|
||||
/// let detection_key = secret_key.extract(5);
|
||||
|
@ -281,8 +292,7 @@ impl FuzzyDetectionKey {
|
|||
/// Example:
|
||||
/// ```
|
||||
/// use fuzzytags::FuzzySecretKey;
|
||||
/// let gamma = 24;
|
||||
/// let secret_key = FuzzySecretKey::generate(gamma);
|
||||
/// let secret_key = FuzzySecretKey::<24>::generate();
|
||||
/// let public_key = secret_key.public_key();
|
||||
/// // extract a detection key
|
||||
/// let detection_key = secret_key.extract(5);
|
||||
|
@ -298,7 +308,7 @@ impl FuzzyDetectionKey {
|
|||
/// // the message attached to this tag is definitely *not* for the party associated with the detection key.
|
||||
/// }
|
||||
/// ```
|
||||
pub fn test_tag(&self, tag: &FuzzyTag) -> bool {
|
||||
pub fn test_tag(&self, tag: &FuzzyTag<{ GAMMA }>) -> bool {
|
||||
// A few checks to make sure the tag is well formed.
|
||||
// All zeros in u or y can lead to a tag that validates against *all* public keys
|
||||
// That doesn't seem like a great idea, so we return false to be safe.
|
||||
|
@ -307,7 +317,7 @@ impl FuzzyDetectionKey {
|
|||
return false;
|
||||
}
|
||||
|
||||
let m = FuzzySecretKey::g(tag.u, &tag.ciphertexts);
|
||||
let m = FuzzySecretKey::<GAMMA>::g(tag.u, &tag.ciphertexts);
|
||||
let g = RISTRETTO_BASEPOINT_POINT;
|
||||
|
||||
// Re-derive w = g^z from the public tag.
|
||||
|
@ -324,7 +334,7 @@ impl FuzzyDetectionKey {
|
|||
let mut result = true;
|
||||
for (i, x_i) in self.0.iter().enumerate() {
|
||||
// re-derive the key from the tag
|
||||
let k_i = FuzzySecretKey::h(tag.u, tag.u.mul(x_i), w);
|
||||
let k_i = FuzzySecretKey::<GAMMA>::h(tag.u, tag.u.mul(x_i), w);
|
||||
|
||||
// calculate the "original" plaintext
|
||||
let c_i = match tag.ciphertexts.get(i) {
|
||||
|
@ -346,9 +356,9 @@ impl FuzzyDetectionKey {
|
|||
|
||||
/// A public identity that others can create tags for.
|
||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
pub struct FuzzyPublicKey(Vec<RistrettoPoint>);
|
||||
pub struct FuzzyPublicKey<const GAMMA: u8>(Vec<RistrettoPoint>);
|
||||
|
||||
impl FuzzyPublicKey {
|
||||
impl<const GAMMA: u8> FuzzyPublicKey<{ GAMMA }> {
|
||||
/// a convenient id for a public key for internal accounting purposes
|
||||
/// do not expose this to applications
|
||||
pub fn id(&self) -> String {
|
||||
|
@ -363,11 +373,11 @@ impl FuzzyPublicKey {
|
|||
/// Example:
|
||||
/// ```
|
||||
/// use fuzzytags::{FuzzySecretKey};
|
||||
/// let secret_key = FuzzySecretKey::generate(24);
|
||||
/// let secret_key = FuzzySecretKey::<24>::generate();
|
||||
/// let public_key = secret_key.public_key(); // give this to a sender
|
||||
/// let tag = public_key.generate_tag();
|
||||
/// ```
|
||||
pub fn generate_tag(&self) -> FuzzyTag {
|
||||
pub fn generate_tag(&self) -> FuzzyTag<{ GAMMA }> {
|
||||
let mut rng = OsRng::default();
|
||||
let g = RISTRETTO_BASEPOINT_POINT;
|
||||
|
||||
|
@ -380,7 +390,7 @@ impl FuzzyPublicKey {
|
|||
// construct the ciphertext portion of the tag
|
||||
let mut ciphertexts = BitVec::new();
|
||||
for (_i, h_i) in self.0.iter().enumerate() {
|
||||
let k_i = FuzzySecretKey::h(u, h_i.mul(r), w);
|
||||
let k_i = FuzzySecretKey::<GAMMA>::h(u, h_i.mul(r), w);
|
||||
// encrypt a plaintext of all 1's
|
||||
let c_i = k_i ^ 0x01;
|
||||
ciphertexts.push(c_i == 0x01);
|
||||
|
@ -401,7 +411,7 @@ impl FuzzyPublicKey {
|
|||
// used to derive the key.
|
||||
|
||||
// finally calculate a `y` = 1/r * (z-m) which will be used to re-derive `w`
|
||||
let m = FuzzySecretKey::g(u, &ciphertexts);
|
||||
let m = FuzzySecretKey::<GAMMA>::g(u, &ciphertexts);
|
||||
let y = r.invert().mul(z.sub(m));
|
||||
|
||||
return FuzzyTag { u, y, ciphertexts };
|
||||
|
@ -414,8 +424,8 @@ impl FuzzyPublicKey {
|
|||
/// Example:
|
||||
/// ```
|
||||
/// use fuzzytags::{FuzzySecretKey, FuzzyPublicKey};
|
||||
/// let secret_key_1 = FuzzySecretKey::generate(24);
|
||||
/// let secret_key_2 = FuzzySecretKey::generate(24);
|
||||
/// let secret_key_1 = FuzzySecretKey::<24>::generate();
|
||||
/// let secret_key_2 = FuzzySecretKey::<24>::generate();
|
||||
/// let public_key_1 = secret_key_1.public_key(); // give this to a sender
|
||||
/// let public_key_2 = secret_key_2.public_key(); // give this to a sender
|
||||
/// // Will validate for detection keys derived from both secret_key_1 and secret_key_2 up
|
||||
|
@ -423,7 +433,7 @@ impl FuzzyPublicKey {
|
|||
/// // Sender can now do...tag will validate on detection keys of length 8 or lower.
|
||||
/// let tag = FuzzyPublicKey::generate_entangled_tag(vec![public_key_1,public_key_2], 8);
|
||||
/// ```
|
||||
pub fn generate_entangled_tag(public_keys: Vec<FuzzyPublicKey>, length: usize) -> FuzzyTag {
|
||||
pub fn generate_entangled_tag(public_keys: Vec<FuzzyPublicKey<{ GAMMA }>>, length: usize) -> FuzzyTag<{ GAMMA }> {
|
||||
let mut rng = OsRng::default();
|
||||
let g = RISTRETTO_BASEPOINT_POINT;
|
||||
// generate some random points...
|
||||
|
@ -445,10 +455,10 @@ impl FuzzyPublicKey {
|
|||
let w = g.mul(z);
|
||||
let mut key = vec![];
|
||||
for (i, precompute) in public_key_precomputes[0].iter().enumerate() {
|
||||
let k_i = FuzzySecretKey::h(u, *precompute, w);
|
||||
let k_i = FuzzySecretKey::<GAMMA>::h(u, *precompute, w);
|
||||
if i < length {
|
||||
for precompute in public_key_precomputes.iter().skip(1) {
|
||||
let n_k_i = FuzzySecretKey::h(u, precompute[i], w);
|
||||
let n_k_i = FuzzySecretKey::<GAMMA>::h(u, precompute[i], w);
|
||||
if k_i != n_k_i {
|
||||
return None;
|
||||
}
|
||||
|
@ -466,7 +476,7 @@ impl FuzzyPublicKey {
|
|||
}
|
||||
|
||||
// This is the same as generate_tag, kept separate to avoid over-decomposition
|
||||
let m = FuzzySecretKey::g(u, &ciphertexts);
|
||||
let m = FuzzySecretKey::<GAMMA>::g(u, &ciphertexts);
|
||||
let y = r.invert().mul(z.sub(m));
|
||||
return Some(FuzzyTag { u, y, ciphertexts });
|
||||
};
|
||||
|
@ -483,56 +493,52 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn test_compression() {
|
||||
let gamma = 24;
|
||||
let secret_key = FuzzySecretKey::generate(gamma);
|
||||
let secret_key = FuzzySecretKey::<24>::generate();
|
||||
let public_key = secret_key.public_key();
|
||||
|
||||
// Give public key to a another party...
|
||||
// and then they can do...
|
||||
let tag = public_key.generate_tag();
|
||||
let compressed_tag = tag.compress();
|
||||
let decompressed_tag = FuzzyTag::decompress(&compressed_tag).unwrap();
|
||||
let decompressed_tag = FuzzyTag::<24>::decompress(&compressed_tag).unwrap();
|
||||
assert_eq!(tag, decompressed_tag);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_serialization() {
|
||||
// We support up to gamma=64 when deserializing..
|
||||
for gamma in [5, 10, 15, 24, 45, 64].iter() {
|
||||
// generate some new keys...
|
||||
let secret_key = FuzzySecretKey::generate(*gamma);
|
||||
let tag = secret_key.public_key.generate_tag();
|
||||
// generate some new keys...
|
||||
let secret_key = FuzzySecretKey::<15>::generate();
|
||||
let tag = secret_key.public_key.generate_tag();
|
||||
let detection_key = secret_key.extract(10);
|
||||
let serialized_tag = serde_json::to_string(&tag).unwrap();
|
||||
let deserialized_tag: FuzzyTag<15> = serde_json::from_str(&serialized_tag).unwrap();
|
||||
assert_eq!(tag.compress(), deserialized_tag.compress());
|
||||
assert_eq!(true, detection_key.test_tag(&deserialized_tag));
|
||||
|
||||
let detection_key = secret_key.extract(10);
|
||||
// println!("{}", serde_json::to_string(&detection_key).unwrap());
|
||||
// generate some new keys...
|
||||
let secret_key = FuzzySecretKey::<24>::generate();
|
||||
let tag = secret_key.public_key.generate_tag();
|
||||
let detection_key = secret_key.extract(10);
|
||||
let serialized_tag = serde_json::to_string(&tag).unwrap();
|
||||
let deserialized_tag: FuzzyTag<24> = serde_json::from_str(&serialized_tag).unwrap();
|
||||
assert_eq!(tag.compress(), deserialized_tag.compress());
|
||||
assert_eq!(true, detection_key.test_tag(&deserialized_tag));
|
||||
|
||||
//println!("Original: {}", tag);
|
||||
let serialized_tag = serde_json::to_string(&tag).unwrap();
|
||||
//println!("Serialized: {}", serialized_tag);
|
||||
|
||||
let deserialized_tag: FuzzyTag = serde_json::from_str(&serialized_tag).unwrap();
|
||||
// println!("Deserialized: {}", deserialized_tag);
|
||||
|
||||
// Test some equality and testing properties
|
||||
assert_eq!(tag.compress(), deserialized_tag.compress());
|
||||
assert_eq!(true, detection_key.test_tag(&deserialized_tag));
|
||||
|
||||
// Test some bincode...
|
||||
let bincode_tag = bincode::serialize(&tag);
|
||||
// println!("Serialized: {:?}", bincode_tag);
|
||||
let deserialized_tag: FuzzyTag = bincode::deserialize(&bincode_tag.unwrap()).unwrap();
|
||||
//println!("Deserialized: {}", deserialized_tag);
|
||||
assert_eq!(tag.compress(), deserialized_tag.compress());
|
||||
assert_eq!(true, detection_key.test_tag(&deserialized_tag));
|
||||
}
|
||||
// Test some bincode...
|
||||
let bincode_tag = bincode::serialize(&tag);
|
||||
// println!("Serialized: {:?}", bincode_tag);
|
||||
let deserialized_tag: FuzzyTag<24> = bincode::deserialize(&bincode_tag.unwrap()).unwrap();
|
||||
//println!("Deserialized: {}", deserialized_tag);
|
||||
//assert_eq!(tag.compress(), deserialized_tag.compress());
|
||||
assert_eq!(true, detection_key.test_tag(&deserialized_tag));
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(feature = "entangled")]
|
||||
fn test_multiple() {
|
||||
use crate::FuzzyPublicKey;
|
||||
let secret_keys: Vec<FuzzySecretKey> = (0..2).map(|_x| FuzzySecretKey::generate(24)).collect();
|
||||
let public_keys: Vec<FuzzyPublicKey> = secret_keys.iter().map(|x| x.public_key()).collect();
|
||||
let secret_keys: Vec<FuzzySecretKey<24>> = (0..2).map(|_x| FuzzySecretKey::<24>::generate()).collect();
|
||||
let public_keys: Vec<FuzzyPublicKey<24>> = secret_keys.iter().map(|x| x.public_key()).collect();
|
||||
// it takes ~15 minutes on a standard desktop to find a length=24 match for 2 parties, so for testing let's keep things light
|
||||
let entangled_tag = FuzzyPublicKey::generate_entangled_tag(public_keys, 16);
|
||||
println!("{}", entangled_tag);
|
||||
|
@ -546,7 +552,7 @@ mod tests {
|
|||
#[test]
|
||||
fn correctness() {
|
||||
let number_of_messages = 100;
|
||||
let secret_key = FuzzySecretKey::generate(16);
|
||||
let secret_key = FuzzySecretKey::<16>::generate();
|
||||
for i in 0..number_of_messages {
|
||||
let tag = secret_key.public_key().generate_tag();
|
||||
println!("{}: {}", i, tag);
|
||||
|
@ -554,20 +560,20 @@ mod tests {
|
|||
}
|
||||
}
|
||||
|
||||
fn gen_zero_tag_zero(max_gamma: usize) -> FuzzyTag {
|
||||
fn gen_zero_tag_zero() -> FuzzyTag<24> {
|
||||
let tag = FuzzyTag {
|
||||
u: RistrettoPoint::default(),
|
||||
y: Scalar::default(),
|
||||
ciphertexts: BitVec::from_elem(max_gamma, false),
|
||||
ciphertexts: BitVec::from_elem(24, false),
|
||||
};
|
||||
tag
|
||||
}
|
||||
|
||||
fn gen_zero_tag_one(max_gamma: usize) -> FuzzyTag {
|
||||
fn gen_zero_tag_one() -> FuzzyTag<24> {
|
||||
let mut tag = FuzzyTag {
|
||||
u: RistrettoPoint::default(),
|
||||
y: Scalar::default(),
|
||||
ciphertexts: BitVec::from_elem(max_gamma, false),
|
||||
ciphertexts: BitVec::from_elem(24, false),
|
||||
};
|
||||
tag.ciphertexts.set_all();
|
||||
tag
|
||||
|
@ -579,21 +585,20 @@ mod tests {
|
|||
// broadcast, which overall seems like a bad idea...
|
||||
// Test to make sure that doesn't happen.
|
||||
fn test_zero_tag() {
|
||||
let secret_key = FuzzySecretKey::generate(24);
|
||||
let tag = gen_zero_tag_zero(16);
|
||||
let secret_key = FuzzySecretKey::<24>::generate();
|
||||
let tag = gen_zero_tag_zero();
|
||||
assert_eq!(false, secret_key.extract(6).test_tag(&tag));
|
||||
let tag = gen_zero_tag_one(16);
|
||||
let tag = gen_zero_tag_one();
|
||||
assert_eq!(false, secret_key.extract(6).test_tag(&tag));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn false_positives() {
|
||||
let gamma = 8;
|
||||
let number_of_messages = 1000;
|
||||
let secret_key = FuzzySecretKey::generate(gamma);
|
||||
let secret_key = FuzzySecretKey::<24>::generate();
|
||||
let mut false_positives = 0;
|
||||
for _i in 0..number_of_messages {
|
||||
let secret_key2 = FuzzySecretKey::generate(gamma);
|
||||
let secret_key2 = FuzzySecretKey::<24>::generate();
|
||||
let tag = secret_key2.public_key().generate_tag();
|
||||
assert!(secret_key2.extract(3).test_tag(&tag));
|
||||
if secret_key.extract(3).test_tag(&tag) == true {
|
||||
|
|
Loading…
Reference in New Issue