Procházet zdrojové kódy

Clean up enum definitions/shared behavior, add struct creation functions

Vecna před 1 rokem
rodič
revize
326d7e5560
1 změnil soubory, kde provedl 97 přidání a 33 odebrání
  1. 97 33
      src/lib.rs

+ 97 - 33
src/lib.rs

@@ -1,6 +1,7 @@
 use curve25519_dalek::scalar::Scalar;
 use ed25519_dalek::{Signature, Signer, SigningKey, Verifier, VerifyingKey};
 use lox_library::bridge_table::{BridgeLine, MAX_BRIDGES_PER_BUCKET};
+use lox_library::cred::Lox;
 use serde::{Deserialize, Serialize};
 use sha1::{Digest, Sha1};
 use sha3::Sha3_256;
@@ -51,38 +52,86 @@ pub fn get_bucket(beta_hash: &[u8; 32]) -> [BridgeLine; MAX_BRIDGES_PER_BUCKET]
 #[derive(Serialize, Deserialize)]
 pub enum ProofOfBridgeKnowledge {
     /// Hash of bridge line as proof of knowledge of bridge line
-    HashOfBridgeLine { hash: [u8; 32] },
+    HashOfBridgeLine(HashOfBridgeLine),
     /// Hash of bucket ID for Lox user
-    HashOfBucket { hash: [u8; 32] },
+    HashOfBucket(HashOfBucket),
 }
 
 impl ProofOfBridgeKnowledge {
-    fn verify(&self, fingerprint: [u8; 20]) -> bool {
-        match *self {
-            ProofOfBridgeKnowledge::HashOfBridgeLine { ref hash } => {
-                let bl = get_bridge_line(&fingerprint);
-                let mut hasher = Sha3_256::new();
-                hasher.update(bincode::serialize(&bl).unwrap());
-                let bl_hash: [u8; 32] = hasher.finalize().into();
-                hash == &bl_hash
+    pub fn verify(&self, bridge_fingerprint: [u8; 20]) -> bool {
+        // TODO: It seems like there ought to be a cleaner way to do this?
+        match self {
+            ProofOfBridgeKnowledge::HashOfBridgeLine(bl_hash) => bl_hash.verify(bridge_fingerprint),
+            ProofOfBridgeKnowledge::HashOfBucket(bucket_hash) => {
+                bucket_hash.verify(bridge_fingerprint)
             }
-            ProofOfBridgeKnowledge::HashOfBucket { ref hash } => {
-                let bucket = get_bucket(&hash);
-                for bl in bucket {
-                    let mut hasher = Sha1::new();
-                    hasher.update(bl.uid_fingerprint.to_le_bytes());
-                    if fingerprint == <[u8; 20]>::from(hasher.finalize()) {
-                        return true;
-                    }
-                }
-                false
+        }
+    }
+}
+
+/// Hash of bridge line to prove knowledge of that bridge
+#[derive(PartialEq, Serialize, Deserialize)]
+pub struct HashOfBridgeLine {
+    hash: [u8; 32],
+}
+
+impl HashOfBridgeLine {
+    pub fn new(bl: BridgeLine) -> Self {
+        let mut hasher = Sha3_256::new();
+        hasher.update(bincode::serialize(&bl).unwrap());
+        let hash: [u8; 32] = hasher.finalize().into();
+        Self { hash }
+    }
+
+    pub fn verify(&self, bridge_fingerprint: [u8; 20]) -> bool {
+        let bl = get_bridge_line(&bridge_fingerprint);
+        self == &HashOfBridgeLine::new(bl)
+    }
+}
+
+/// Hash of bucket ID to prove knowledge of bridges in that bucket
+#[derive(PartialEq, Serialize, Deserialize)]
+pub struct HashOfBucket {
+    hash: [u8; 32],
+}
+
+impl HashOfBucket {
+    pub fn new(bucket: Scalar) -> Self {
+        let mut hasher = Sha3_256::new();
+        hasher.update(bucket.to_bytes());
+        let hash: [u8; 32] = hasher.finalize().into();
+        Self { hash }
+    }
+
+    pub fn verify(&self, bridge_fingerprint: [u8; 20]) -> bool {
+        let bucket = get_bucket(&self.hash);
+        for bl in bucket {
+            let mut hasher = Sha1::new();
+            hasher.update(bl.uid_fingerprint.to_le_bytes());
+            if bridge_fingerprint == <[u8; 20]>::from(hasher.finalize()) {
+                return true;
             }
         }
+        false
     }
 }
 
-pub trait Report {
-    fn verify(&self) -> bool;
+/// Reports from users about whether or not their bridges are blocked
+#[derive(Serialize, Deserialize)]
+pub enum Report {
+    /// Negative report indicating user was unable to connect
+    NegativeUserReport(NegativeUserReport),
+    /// Positive report indicating user was able to connect
+    PositiveUserReport(PositiveUserReport),
+}
+
+impl Report {
+    fn verify(&self) -> bool {
+        match self {
+            Report::NegativeUserReport(report) => report.verify(),
+            Report::PositiveUserReport(report) => report.verify(),
+        }
+    }
 }
 
 /// A report that the user was unable to connect to the bridge
@@ -91,7 +140,7 @@ pub struct NegativeUserReport {
     /// hashed fingerprint (SHA-1 hash of 20-byte bridge ID)
     pub fingerprint: [u8; 20],
     /// some way to prove knowledge of bridge
-    pub bridge_pok: ProofOfBridgeKnowledge,
+    bridge_pok: ProofOfBridgeKnowledge,
     /// user's country code, may be an empty string
     pub country: String,
     /// today's Julian date
@@ -99,14 +148,10 @@ pub struct NegativeUserReport {
 }
 
 impl NegativeUserReport {
-    pub fn new(bridge_id: [u8; 20], bucket: Scalar, country: String) -> Self {
+    pub fn new(bridge_id: [u8; 20], bridge_pok: ProofOfBridgeKnowledge, country: String) -> Self {
         let mut hasher = Sha1::new();
         hasher.update(bridge_id);
         let fingerprint: [u8; 20] = hasher.finalize().into();
-        let mut hasher = Sha3_256::new();
-        hasher.update(bucket.to_bytes());
-        let bucket_hash: [u8; 32] = hasher.finalize().into();
-        let bridge_pok = ProofOfBridgeKnowledge::HashOfBridgeLine { hash: bucket_hash };
         let today = today();
         Self {
             fingerprint,
@@ -115,9 +160,30 @@ impl NegativeUserReport {
             today,
         }
     }
-}
 
-impl Report for NegativeUserReport {
+    pub fn from_bridgeline(
+        &self,
+        bridge_id: [u8; 20],
+        bridgeline: BridgeLine,
+        country: String,
+    ) -> Self {
+        let bridge_pok =
+            ProofOfBridgeKnowledge::HashOfBridgeLine(HashOfBridgeLine::new(bridgeline));
+        NegativeUserReport::new(bridge_id, bridge_pok, country)
+    }
+
+    pub fn from_bucket(&self, bridge_id: [u8; 20], bucket: Scalar, country: String) -> Self {
+        let mut hasher = Sha3_256::new();
+        hasher.update(bucket.to_bytes());
+        let bucket_hash: [u8; 32] = hasher.finalize().into();
+        let bridge_pok = ProofOfBridgeKnowledge::HashOfBucket(HashOfBucket { hash: bucket_hash });
+        NegativeUserReport::new(bridge_id, bridge_pok, country)
+    }
+
+    pub fn from_lox_credential(&self, bridge_id: [u8; 20], cred: Lox, country: String) -> Self {
+        self.from_bucket(bridge_id, cred.bucket, country)
+    }
+
     fn verify(&self) -> bool {
         // possibly include check that self.today is recent as well
         self.today <= today() && self.bridge_pok.verify(self.fingerprint)
@@ -130,7 +196,7 @@ pub struct PositiveUserReport {
     /// hashed fingerprint (SHA-1 hash of 20-byte bridge ID)
     pub fingerprint: [u8; 20],
     /// token from the bridge indicating it was reached
-    pub bridge_token: Option<BridgeToken>,
+    bridge_token: Option<BridgeToken>,
     // TODO: proof of level, something involving credential show
     /// user's country code, may be an empty string
     pub country: String,
@@ -151,9 +217,7 @@ impl PositiveUserReport {
             today,
         }
     }
-}
 
-impl Report for PositiveUserReport {
     fn verify(&self) -> bool {
         // possibly include check that self.today is recent as well
         self.today <= today()