negative_report.rs 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195
  1. use crate::{
  2. bridge_verification_info::BridgeVerificationInfo, get_date, BridgeDistributor, COUNTRY_CODES,
  3. };
  4. use curve25519_dalek::scalar::Scalar;
  5. use lox_library::{bridge_table::BridgeLine, cred::Lox};
  6. use serde::{Deserialize, Serialize};
  7. use sha1::{Digest, Sha1};
  8. use sha3::Sha3_256;
  9. #[derive(Debug)]
  10. pub enum NegativeReportError {
  11. DateInFuture,
  12. FailedToDeserialize, // couldn't deserialize to SerializableNegativeReport
  13. InvalidCountryCode,
  14. MissingCountryCode,
  15. }
  16. /// A report that the user was unable to connect to the bridge
  17. #[derive(Eq, PartialEq, Ord, PartialOrd)]
  18. pub struct NegativeReport {
  19. /// hashed fingerprint (SHA-1 hash of 20-byte bridge ID)
  20. pub fingerprint: [u8; 20],
  21. /// some way to prove knowledge of bridge
  22. bridge_pok: ProofOfBridgeKnowledge,
  23. /// user's country code
  24. pub country: String,
  25. /// today's Julian date
  26. pub date: u32,
  27. /// the bridge distributor, e.g., Lox, Https, or Moat
  28. pub distributor: BridgeDistributor,
  29. }
  30. impl NegativeReport {
  31. pub fn new(
  32. bridge_id: [u8; 20],
  33. bridge_pok: ProofOfBridgeKnowledge,
  34. country: String,
  35. distributor: BridgeDistributor,
  36. ) -> Self {
  37. let mut hasher = Sha1::new();
  38. hasher.update(bridge_id);
  39. let fingerprint: [u8; 20] = hasher.finalize().into();
  40. let date = get_date();
  41. Self {
  42. fingerprint,
  43. bridge_pok,
  44. country,
  45. date,
  46. distributor,
  47. }
  48. }
  49. pub fn from_bridgeline(
  50. bridgeline: BridgeLine,
  51. country: String,
  52. distributor: BridgeDistributor,
  53. ) -> Self {
  54. let bridge_pok =
  55. ProofOfBridgeKnowledge::HashOfBridgeLine(HashOfBridgeLine::new(&bridgeline));
  56. NegativeReport::new(bridgeline.fingerprint, bridge_pok, country, distributor)
  57. }
  58. pub fn from_lox_bucket(bridge_id: [u8; 20], bucket: Scalar, country: String) -> Self {
  59. let mut hasher = Sha3_256::new();
  60. hasher.update(bucket.to_bytes());
  61. let bucket_hash: [u8; 32] = hasher.finalize().into();
  62. let bridge_pok = ProofOfBridgeKnowledge::HashOfBucket(HashOfBucket { hash: bucket_hash });
  63. NegativeReport::new(bridge_id, bridge_pok, country, BridgeDistributor::Lox)
  64. }
  65. pub fn from_lox_credential(bridge_id: [u8; 20], cred: Lox, country: String) -> Self {
  66. NegativeReport::from_lox_bucket(bridge_id, cred.bucket, country)
  67. }
  68. /// Convert report to a serializable version
  69. pub fn to_serializable_report(self) -> SerializableNegativeReport {
  70. SerializableNegativeReport {
  71. fingerprint: self.fingerprint,
  72. bridge_pok: self.bridge_pok,
  73. country: self.country,
  74. date: self.date,
  75. distributor: self.distributor,
  76. }
  77. }
  78. /// Serializes the report, eliding the underlying process
  79. pub fn to_json(self) -> String {
  80. serde_json::to_string(&self.to_serializable_report()).unwrap()
  81. }
  82. /// Deserializes the report, eliding the underlying process
  83. pub fn from_json(str: String) -> Result<Self, NegativeReportError> {
  84. match serde_json::from_str::<SerializableNegativeReport>(&str) {
  85. Ok(v) => v.to_report(),
  86. Err(_) => Err(NegativeReportError::FailedToDeserialize),
  87. }
  88. }
  89. /// Verify the report
  90. pub fn verify(self, bridge_info: &BridgeVerificationInfo) -> bool {
  91. match self.bridge_pok {
  92. ProofOfBridgeKnowledge::HashOfBridgeLine(pok) => {
  93. let hash = HashOfBridgeLine::new(&bridge_info.bridge_line);
  94. hash == pok
  95. }
  96. ProofOfBridgeKnowledge::HashOfBucket(pok) => {
  97. for b in &bridge_info.buckets {
  98. let hash = HashOfBucket::new(&b);
  99. if hash == pok {
  100. return true;
  101. }
  102. }
  103. false
  104. }
  105. }
  106. }
  107. }
  108. /// (De)serializable negative report object which must be consumed by the
  109. /// checking function before it can be used
  110. #[derive(Eq, PartialEq, Ord, PartialOrd, Serialize, Deserialize)]
  111. pub struct SerializableNegativeReport {
  112. pub fingerprint: [u8; 20],
  113. bridge_pok: ProofOfBridgeKnowledge,
  114. pub country: String,
  115. pub date: u32,
  116. pub distributor: BridgeDistributor,
  117. }
  118. impl SerializableNegativeReport {
  119. pub fn to_report(self) -> Result<NegativeReport, NegativeReportError> {
  120. if self.country == "" {
  121. return Err(NegativeReportError::MissingCountryCode);
  122. }
  123. if !COUNTRY_CODES.contains(self.country.as_str()) {
  124. return Err(NegativeReportError::InvalidCountryCode);
  125. }
  126. if self.date > get_date().into() {
  127. return Err(NegativeReportError::DateInFuture);
  128. }
  129. Ok(NegativeReport {
  130. fingerprint: self.fingerprint,
  131. bridge_pok: self.bridge_pok,
  132. country: self.country.to_string(),
  133. date: self.date.try_into().unwrap(),
  134. distributor: self.distributor,
  135. })
  136. }
  137. }
  138. /// Proof that the user knows (and should be able to access) a given bridge
  139. #[derive(Eq, PartialEq, Ord, PartialOrd, Serialize, Deserialize)]
  140. pub enum ProofOfBridgeKnowledge {
  141. /// Hash of bridge line as proof of knowledge of bridge line
  142. HashOfBridgeLine(HashOfBridgeLine),
  143. /// Hash of bucket ID for Lox user
  144. HashOfBucket(HashOfBucket),
  145. }
  146. /// Hash of bridge line to prove knowledge of that bridge
  147. #[derive(Eq, PartialEq, Ord, PartialOrd, Serialize, Deserialize)]
  148. pub struct HashOfBridgeLine {
  149. hash: [u8; 32],
  150. }
  151. impl HashOfBridgeLine {
  152. pub fn new(bl: &BridgeLine) -> Self {
  153. let mut hasher = Sha3_256::new();
  154. hasher.update(bincode::serialize(&bl).unwrap());
  155. let hash: [u8; 32] = hasher.finalize().into();
  156. Self { hash }
  157. }
  158. }
  159. /// Hash of bucket ID to prove knowledge of bridges in that bucket
  160. #[derive(Eq, PartialEq, Ord, PartialOrd, Serialize, Deserialize)]
  161. pub struct HashOfBucket {
  162. hash: [u8; 32],
  163. }
  164. impl HashOfBucket {
  165. pub fn new(bucket: &Scalar) -> Self {
  166. let mut hasher = Sha3_256::new();
  167. hasher.update(bucket.to_bytes());
  168. let hash: [u8; 32] = hasher.finalize().into();
  169. Self { hash }
  170. }
  171. }