Include nonce in negative reports

This commit is contained in:
Vecna 2024-04-12 02:38:35 -04:00
parent e1588aac0e
commit c82e604e3d
5 changed files with 148 additions and 47 deletions

View File

@ -21,6 +21,7 @@ hyper-util = { version = "0.1", features = ["full"] }
julianday = "1.2.0" julianday = "1.2.0"
lazy_static = "1" lazy_static = "1"
lox-library = { git = "https://gitlab.torproject.org/vecna/lox.git", version = "0.1.0" } lox-library = { git = "https://gitlab.torproject.org/vecna/lox.git", version = "0.1.0" }
rand = { version = "0.8" }
#select = "0.6.0" #select = "0.6.0"
serde = "1.0.197" serde = "1.0.197"
serde_json = "1.0" serde_json = "1.0"
@ -34,4 +35,3 @@ tokio-cron = "0.1.2"
[dev-dependencies] [dev-dependencies]
base64 = "0.21.7" base64 = "0.21.7"
rand = "0.8.5"

View File

@ -29,6 +29,9 @@ lazy_static! {
pub static ref COUNTRY_CODES: HashSet<&'static str> = HashSet::from(["??","ad","ae","af","ag","ai","al","am","ao","ap","aq","ar","as","at","au","aw","ax","az","ba","bb","bd","be","bf","bg","bh","bi","bj","bl","bm","bn","bo","bq","br","bs","bt","bv","bw","by","bz","ca","cc","cd","cf","cg","ch","ci","ck","cl","cm","cn","co","cr","cs","cu","cv","cw","cx","cy","cz","de","dj","dk","dm","do","dz","ec","ee","eg","eh","er","es","et","eu","fi","fj","fk","fm","fo","fr","ga","gb","gd","ge","gf","gg","gh","gi","gl","gm","gn","gp","gq","gr","gs","gt","gu","gw","gy","hk","hm","hn","hr","ht","hu","id","ie","il","im","in","io","iq","ir","is","it","je","jm","jo","jp","ke","kg","kh","ki","km","kn","kp","kr","kw","ky","kz","la","lb","lc","li","lk","lr","ls","lt","lu","lv","ly","ma","mc","md","me","mf","mg","mh","mk","ml","mm","mn","mo","mp","mq","mr","ms","mt","mu","mv","mw","mx","my","mz","na","nc","ne","nf","ng","ni","nl","no","np","nr","nu","nz","om","pa","pe","pf","pg","ph","pk","pl","pm","pn","pr","ps","pt","pw","py","qa","re","ro","rs","ru","rw","sa","sb","sc","sd","se","sg","sh","si","sj","sk","sl","sm","sn","so","sr","ss","st","sv","sx","sy","sz","tc","td","tf","tg","th","tj","tk","tl","tm","tn","to","tr","tt","tv","tw","tz","ua","ug","um","us","uy","uz","va","vc","ve","vg","vi","vn","vu","wf","ws","ye","yt","za","zm","zw"]); pub static ref COUNTRY_CODES: HashSet<&'static str> = HashSet::from(["??","ad","ae","af","ag","ai","al","am","ao","ap","aq","ar","as","at","au","aw","ax","az","ba","bb","bd","be","bf","bg","bh","bi","bj","bl","bm","bn","bo","bq","br","bs","bt","bv","bw","by","bz","ca","cc","cd","cf","cg","ch","ci","ck","cl","cm","cn","co","cr","cs","cu","cv","cw","cx","cy","cz","de","dj","dk","dm","do","dz","ec","ee","eg","eh","er","es","et","eu","fi","fj","fk","fm","fo","fr","ga","gb","gd","ge","gf","gg","gh","gi","gl","gm","gn","gp","gq","gr","gs","gt","gu","gw","gy","hk","hm","hn","hr","ht","hu","id","ie","il","im","in","io","iq","ir","is","it","je","jm","jo","jp","ke","kg","kh","ki","km","kn","kp","kr","kw","ky","kz","la","lb","lc","li","lk","lr","ls","lt","lu","lv","ly","ma","mc","md","me","mf","mg","mh","mk","ml","mm","mn","mo","mp","mq","mr","ms","mt","mu","mv","mw","mx","my","mz","na","nc","ne","nf","ng","ni","nl","no","np","nr","nu","nz","om","pa","pe","pf","pg","ph","pk","pl","pm","pn","pr","ps","pt","pw","py","qa","re","ro","rs","ru","rw","sa","sb","sc","sd","se","sg","sh","si","sj","sk","sl","sm","sn","so","sr","ss","st","sv","sx","sy","sz","tc","td","tf","tg","th","tj","tk","tl","tm","tn","to","tr","tt","tv","tw","tz","ua","ug","um","us","uy","uz","va","vc","ve","vg","vi","vn","vu","wf","ws","ye","yt","za","zm","zw"]);
} }
/// We will accept reports up to this many days old.
pub const MAX_BACKDATE: u32 = 3;
/// Get Julian date /// Get Julian date
pub fn get_date() -> u32 { pub fn get_date() -> u32 {
time::OffsetDateTime::now_utc() time::OffsetDateTime::now_utc()
@ -315,14 +318,12 @@ pub async fn update_extra_infos(
// Process negative reports // Process negative reports
/// Negative reports can be deduplicated, so we store to-be-processed /// We store to-be-processed negative reports as a vector. Add this NR
/// negative reports as a map of [report] to [count of report]. Add this /// to that vector (or create a new vector if necessary)
/// NR to that map (or create a new map if necessary).
pub fn save_negative_report_to_process(db: &Db, nr: NegativeReport) { pub fn save_negative_report_to_process(db: &Db, nr: NegativeReport) {
// We serialize the negative reports as strings to use them as map keys.
let mut reports = match db.get("nrs-to-process").unwrap() { let mut reports = match db.get("nrs-to-process").unwrap() {
Some(v) => bincode::deserialize(&v).unwrap(), Some(v) => bincode::deserialize(&v).unwrap(),
None => BTreeMap::<String, BTreeMap<String, u32>>::new(), None => BTreeMap::<String, Vec<SerializableNegativeReport>>::new(),
}; };
// Store to-be-processed reports with key [fingerprint]_[country]_[date] // Store to-be-processed reports with key [fingerprint]_[country]_[date]
let map_key = format!( let map_key = format!(
@ -331,19 +332,15 @@ pub fn save_negative_report_to_process(db: &Db, nr: NegativeReport) {
&nr.country, &nr.country,
&nr.date, &nr.date,
); );
let serialized_nr = nr.to_json();
if reports.contains_key(&map_key) { if reports.contains_key(&map_key) {
let nr_map = reports.get_mut(&map_key).unwrap(); reports
if nr_map.contains_key(&serialized_nr) { .get_mut(&map_key)
let prev_count = nr_map.get(&serialized_nr).unwrap(); .unwrap()
nr_map.insert(serialized_nr, prev_count + 1); .push(nr.to_serializable_report());
} else {
nr_map.insert(serialized_nr, 1);
}
} else { } else {
let mut nr_map = BTreeMap::<String, u32>::new(); let mut nrs = Vec::<SerializableNegativeReport>::new();
nr_map.insert(serialized_nr, 1); nrs.push(nr.to_serializable_report());
reports.insert(map_key, nr_map); reports.insert(map_key, nrs);
} }
// Commit changes to database // Commit changes to database
db.insert("nrs-to-process", bincode::serialize(&reports).unwrap()) db.insert("nrs-to-process", bincode::serialize(&reports).unwrap())
@ -356,15 +353,14 @@ pub fn save_negative_report_to_process(db: &Db, nr: NegativeReport) {
/// distributor. /// distributor.
pub async fn verify_negative_reports( pub async fn verify_negative_reports(
distributors: &BTreeMap<BridgeDistributor, String>, distributors: &BTreeMap<BridgeDistributor, String>,
reports: &BTreeMap<String, u32>, reports: &Vec<SerializableNegativeReport>,
) -> u32 { ) -> u32 {
// Don't make a network call if we don't have any reports anyway // Don't make a network call if we don't have any reports anyway
if reports.is_empty() { if reports.is_empty() {
return 0; return 0;
} }
// Get one report, assume the rest have the same distributor // Get one report, assume the rest have the same distributor
let first_report: SerializableNegativeReport = let first_report = &reports[0];
serde_json::from_str(reports.first_key_value().unwrap().0).unwrap();
let distributor = first_report.distributor; let distributor = first_report.distributor;
let client = Client::new(); let client = Client::new();
let uri: String = (distributors.get(&distributor).unwrap().to_owned() + "/verifynegative") let uri: String = (distributors.get(&distributor).unwrap().to_owned() + "/verifynegative")
@ -385,17 +381,16 @@ pub async fn verify_negative_reports(
pub async fn update_negative_reports(db: &Db, distributors: &BTreeMap<BridgeDistributor, String>) { pub async fn update_negative_reports(db: &Db, distributors: &BTreeMap<BridgeDistributor, String>) {
let mut all_negative_reports = match db.get("nrs-to-process").unwrap() { let mut all_negative_reports = match db.get("nrs-to-process").unwrap() {
Some(v) => bincode::deserialize(&v).unwrap(), Some(v) => bincode::deserialize(&v).unwrap(),
None => BTreeMap::<String, BTreeMap<String, u32>>::new(), None => BTreeMap::<String, Vec<SerializableNegativeReport>>::new(),
}; };
// Key is [fingerprint]_[country]_[date] // Key is [fingerprint]_[country]_[date]
for bridge_country_date in all_negative_reports.keys() { for bridge_country_date in all_negative_reports.keys() {
let reports = all_negative_reports.get(bridge_country_date).unwrap(); let reports = all_negative_reports.get(bridge_country_date).unwrap();
if !reports.is_empty() { if !reports.is_empty() {
let first_report: SerializableNegativeReport = let first_report = &reports[0];
serde_json::from_str(reports.first_key_value().unwrap().0).unwrap();
let fingerprint = first_report.fingerprint; let fingerprint = first_report.fingerprint;
let date = first_report.date; let date = first_report.date;
let country = first_report.country; let country = first_report.country.clone();
let count_valid = verify_negative_reports(&distributors, reports).await; let count_valid = verify_negative_reports(&distributors, reports).await;
// Get bridge info or make new one // Get bridge info or make new one
@ -421,7 +416,6 @@ pub async fn update_negative_reports(db: &Db, distributors: &BTreeMap<BridgeDist
.info_by_country .info_by_country
.insert(country, bridge_country_info); .insert(country, bridge_country_info);
} }
// Commit changes to database // Commit changes to database
db.insert(fingerprint, bincode::serialize(&bridge_info).unwrap()) db.insert(fingerprint, bincode::serialize(&bridge_info).unwrap())
.unwrap(); .unwrap();

View File

@ -1,10 +1,11 @@
use crate::{ use crate::{
bridge_verification_info::BridgeVerificationInfo, get_date, BridgeDistributor, COUNTRY_CODES, bridge_verification_info::BridgeVerificationInfo, get_date, BridgeDistributor, COUNTRY_CODES,
MAX_BACKDATE,
}; };
use curve25519_dalek::scalar::Scalar; use curve25519_dalek::scalar::Scalar;
use lox_library::{bridge_table::BridgeLine, cred::Lox}; use lox_library::{bridge_table::BridgeLine, cred::Lox};
use rand::RngCore;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use sha1::{Digest, Sha1}; use sha1::{Digest, Sha1};
use sha3::Sha3_256; use sha3::Sha3_256;
@ -12,6 +13,7 @@ use sha3::Sha3_256;
#[derive(Debug, Serialize)] #[derive(Debug, Serialize)]
pub enum NegativeReportError { pub enum NegativeReportError {
DateInFuture, DateInFuture,
DateInPast, // report is more than MAX_BACKDATE days old
FailedToDeserialize, // couldn't deserialize to SerializableNegativeReport FailedToDeserialize, // couldn't deserialize to SerializableNegativeReport
InvalidCountryCode, InvalidCountryCode,
MissingCountryCode, MissingCountryCode,
@ -32,6 +34,9 @@ pub struct NegativeReport {
/// today's Julian date /// today's Julian date
pub date: u32, pub date: u32,
/// a random nonce used in the bridge_pok
pub nonce: [u8; 32],
/// the bridge distributor, e.g., Lox, Https, or Moat /// the bridge distributor, e.g., Lox, Https, or Moat
pub distributor: BridgeDistributor, pub distributor: BridgeDistributor,
} }
@ -42,6 +47,7 @@ impl NegativeReport {
bridge_pok: ProofOfBridgeKnowledge, bridge_pok: ProofOfBridgeKnowledge,
country: String, country: String,
date: u32, date: u32,
nonce: [u8; 32],
distributor: BridgeDistributor, distributor: BridgeDistributor,
) -> Self { ) -> Self {
let mut hasher = Sha1::new(); let mut hasher = Sha1::new();
@ -52,6 +58,7 @@ impl NegativeReport {
bridge_pok, bridge_pok,
country, country,
date, date,
nonce,
distributor, distributor,
} }
} }
@ -62,24 +69,42 @@ impl NegativeReport {
distributor: BridgeDistributor, distributor: BridgeDistributor,
) -> Self { ) -> Self {
let date = get_date(); let date = get_date();
let bridge_pok = let mut rng = rand::thread_rng();
ProofOfBridgeKnowledge::HashOfBridgeLine(HashOfBridgeLine::new(&bridgeline, date)); let mut nonce = [0; 32];
NegativeReport::new( rng.fill_bytes(&mut nonce);
let bridge_pok = ProofOfBridgeKnowledge::HashOfBridgeLine(HashOfBridgeLine::new(
&bridgeline,
date,
nonce,
));
Self::new(
bridgeline.fingerprint, bridgeline.fingerprint,
bridge_pok, bridge_pok,
country, country,
date, date,
nonce,
distributor, distributor,
) )
} }
pub fn from_lox_bucket(bridge_id: [u8; 20], bucket: Scalar, country: String) -> Self { pub fn from_lox_bucket(bridge_id: [u8; 20], bucket: Scalar, country: String) -> Self {
let date = get_date(); let date = get_date();
let bridge_pok = ProofOfBridgeKnowledge::HashOfBucket(HashOfBucket::new(&bucket, date)); let mut rng = rand::thread_rng();
NegativeReport::new(bridge_id, bridge_pok, country, date, BridgeDistributor::Lox) let mut nonce = [0; 32];
rng.fill_bytes(&mut nonce);
let bridge_pok =
ProofOfBridgeKnowledge::HashOfBucket(HashOfBucket::new(&bucket, date, nonce));
Self::new(
bridge_id,
bridge_pok,
country,
date,
nonce,
BridgeDistributor::Lox,
)
} }
pub fn from_lox_credential(bridge_id: [u8; 20], cred: Lox, country: String) -> Self { pub fn from_lox_credential(bridge_id: [u8; 20], cred: &Lox, country: String) -> Self {
NegativeReport::from_lox_bucket(bridge_id, cred.bucket, country) NegativeReport::from_lox_bucket(bridge_id, cred.bucket, country)
} }
@ -90,6 +115,7 @@ impl NegativeReport {
bridge_pok: self.bridge_pok, bridge_pok: self.bridge_pok,
country: self.country, country: self.country,
date: self.date, date: self.date,
nonce: self.nonce,
distributor: self.distributor, distributor: self.distributor,
} }
} }
@ -119,12 +145,12 @@ impl NegativeReport {
pub fn verify(self, bridge_info: &BridgeVerificationInfo) -> bool { pub fn verify(self, bridge_info: &BridgeVerificationInfo) -> bool {
match self.bridge_pok { match self.bridge_pok {
ProofOfBridgeKnowledge::HashOfBridgeLine(pok) => { ProofOfBridgeKnowledge::HashOfBridgeLine(pok) => {
let hash = HashOfBridgeLine::new(&bridge_info.bridge_line, self.date); let hash = HashOfBridgeLine::new(&bridge_info.bridge_line, self.date, self.nonce);
hash == pok hash == pok
} }
ProofOfBridgeKnowledge::HashOfBucket(pok) => { ProofOfBridgeKnowledge::HashOfBucket(pok) => {
for b in &bridge_info.buckets { for b in &bridge_info.buckets {
let hash = HashOfBucket::new(&b, self.date); let hash = HashOfBucket::new(&b, self.date, self.nonce);
if hash == pok { if hash == pok {
return true; return true;
} }
@ -143,6 +169,7 @@ pub struct SerializableNegativeReport {
bridge_pok: ProofOfBridgeKnowledge, bridge_pok: ProofOfBridgeKnowledge,
pub country: String, pub country: String,
pub date: u32, pub date: u32,
pub nonce: [u8; 32],
pub distributor: BridgeDistributor, pub distributor: BridgeDistributor,
} }
@ -154,14 +181,19 @@ impl SerializableNegativeReport {
if !COUNTRY_CODES.contains(self.country.as_str()) { if !COUNTRY_CODES.contains(self.country.as_str()) {
return Err(NegativeReportError::InvalidCountryCode); return Err(NegativeReportError::InvalidCountryCode);
} }
if self.date > get_date().into() { let date = get_date();
if self.date > date {
return Err(NegativeReportError::DateInFuture); return Err(NegativeReportError::DateInFuture);
} }
if self.date < date - MAX_BACKDATE {
return Err(NegativeReportError::DateInPast);
}
Ok(NegativeReport { Ok(NegativeReport {
fingerprint: self.fingerprint, fingerprint: self.fingerprint,
bridge_pok: self.bridge_pok, bridge_pok: self.bridge_pok,
country: self.country.to_string(), country: self.country.to_string(),
date: self.date.try_into().unwrap(), date: self.date.try_into().unwrap(),
nonce: self.nonce,
distributor: self.distributor, distributor: self.distributor,
}) })
} }
@ -184,9 +216,10 @@ pub struct HashOfBridgeLine {
} }
impl HashOfBridgeLine { impl HashOfBridgeLine {
pub fn new(bl: &BridgeLine, date: u32) -> Self { pub fn new(bl: &BridgeLine, date: u32, nonce: [u8; 32]) -> Self {
let mut hasher = Sha3_256::new(); let mut hasher = Sha3_256::new();
hasher.update(date.to_le_bytes()); hasher.update(date.to_le_bytes());
hasher.update(nonce);
hasher.update(bincode::serialize(&bl).unwrap()); hasher.update(bincode::serialize(&bl).unwrap());
let hash: [u8; 32] = hasher.finalize().into(); let hash: [u8; 32] = hasher.finalize().into();
Self { hash } Self { hash }
@ -200,9 +233,10 @@ pub struct HashOfBucket {
} }
impl HashOfBucket { impl HashOfBucket {
pub fn new(bucket: &Scalar, date: u32) -> Self { pub fn new(bucket: &Scalar, date: u32, nonce: [u8; 32]) -> Self {
let mut hasher = Sha3_256::new(); let mut hasher = Sha3_256::new();
hasher.update(date.to_le_bytes()); hasher.update(date.to_le_bytes());
hasher.update(nonce);
hasher.update(bucket.to_bytes()); hasher.update(bucket.to_bytes());
let hash: [u8; 32] = hasher.finalize().into(); let hash: [u8; 32] = hasher.finalize().into();
Self { hash } Self { hash }

View File

@ -1,7 +1,9 @@
// For Lox-related code where points are uppercase and scalars are lowercase // For Lox-related code where points are uppercase and scalars are lowercase
#![allow(non_snake_case)] #![allow(non_snake_case)]
use crate::{bridge_verification_info::BridgeVerificationInfo, get_date, COUNTRY_CODES}; use crate::{
bridge_verification_info::BridgeVerificationInfo, get_date, COUNTRY_CODES, MAX_BACKDATE,
};
use curve25519_dalek::ristretto::RistrettoBasepointTable; use curve25519_dalek::ristretto::RistrettoBasepointTable;
use ed25519_dalek::{Signature, Signer, SigningKey, Verifier}; use ed25519_dalek::{Signature, Signer, SigningKey, Verifier};
@ -15,6 +17,7 @@ pub const REQUIRE_BRIDGE_TOKEN: bool = false;
#[derive(Debug, Serialize)] #[derive(Debug, Serialize)]
pub enum PositiveReportError { pub enum PositiveReportError {
DateInFuture, DateInFuture,
DateInPast, // report is more than MAX_BACKDATE days old
FailedToDeserialize, // couldn't deserialize to SerializablePositiveReport FailedToDeserialize, // couldn't deserialize to SerializablePositiveReport
InvalidBridgeToken, InvalidBridgeToken,
InvalidCountryCode, InvalidCountryCode,
@ -180,10 +183,13 @@ impl SerializablePositiveReport {
if !COUNTRY_CODES.contains(self.country.as_str()) { if !COUNTRY_CODES.contains(self.country.as_str()) {
return Err(PositiveReportError::InvalidCountryCode); return Err(PositiveReportError::InvalidCountryCode);
} }
let date: u32 = get_date().into(); let date: u32 = get_date();
if self.date > date { if self.date > date {
return Err(PositiveReportError::DateInFuture); return Err(PositiveReportError::DateInFuture);
} }
if self.date < date - MAX_BACKDATE {
return Err(PositiveReportError::DateInPast);
}
if self.lox_proof.date != date { if self.lox_proof.date != date {
return Err(PositiveReportError::InvalidLoxProof); return Err(PositiveReportError::InvalidLoxProof);
} }

View File

@ -210,12 +210,64 @@ fn test_negative_reports() {
let report_2 = let report_2 =
NegativeReport::from_lox_bucket(bridges[1].fingerprint, cred.bucket, "ru".to_string()); NegativeReport::from_lox_bucket(bridges[1].fingerprint, cred.bucket, "ru".to_string());
let report_3 = let report_3 =
NegativeReport::from_lox_credential(bridges[2].fingerprint, cred, "ru".to_string()); NegativeReport::from_lox_credential(bridges[2].fingerprint, &cred, "ru".to_string());
// Backdated reports
let date = get_date();
let mut rng = rand::thread_rng();
let mut nonce = [0; 32];
rng.fill_bytes(&mut nonce);
let report_4 = NegativeReport::new(
bridges[0].fingerprint,
ProofOfBridgeKnowledge::HashOfBridgeLine(HashOfBridgeLine::new(
&bridges[0],
date - 1,
nonce,
)),
"ru".to_string(),
date - 1,
nonce,
BridgeDistributor::Lox,
);
let mut nonce = [0; 32];
rng.fill_bytes(&mut nonce);
let report_5 = NegativeReport::new(
bridges[1].fingerprint,
ProofOfBridgeKnowledge::HashOfBridgeLine(HashOfBridgeLine::new(
&bridges[1],
date - 2,
nonce,
)),
"ru".to_string(),
date - 2,
nonce,
BridgeDistributor::Lox,
);
let mut nonce = [0; 32];
rng.fill_bytes(&mut nonce);
let report_6 = NegativeReport::new(
bridges[2].fingerprint,
ProofOfBridgeKnowledge::HashOfBridgeLine(HashOfBridgeLine::new(
&bridges[2],
date - 3,
nonce,
)),
"ru".to_string(),
date - 3,
nonce,
BridgeDistributor::Lox,
);
// Verify reports // Verify reports
assert!(report_1.verify(&bridge_info_1)); assert!(report_1.verify(&bridge_info_1));
assert!(report_2.verify(&bridge_info_2)); assert!(report_2.verify(&bridge_info_2));
assert!(report_3.verify(&bridge_info_3)); assert!(report_3.verify(&bridge_info_3));
assert!(report_4.verify(&bridge_info_1));
assert!(report_5.verify(&bridge_info_2));
assert!(report_6.verify(&bridge_info_3));
// Check that deserialization fails under invalid conditions // Check that deserialization fails under invalid conditions
@ -225,41 +277,56 @@ fn test_negative_reports() {
.to_serializable_report(); .to_serializable_report();
invalid_report_1.date = invalid_report_1.date + 2; invalid_report_1.date = invalid_report_1.date + 2;
// Date too far in past
let mut invalid_report_2 =
NegativeReport::from_bridgeline(bridges[1], "ru".to_string(), BridgeDistributor::Lox)
.to_serializable_report();
invalid_report_2.date = invalid_report_2.date - MAX_BACKDATE - 1;
// Invalid country code // Invalid country code
let invalid_report_2 = let invalid_report_3 =
NegativeReport::from_bridgeline(bridges[1], "xx".to_string(), BridgeDistributor::Lox) NegativeReport::from_bridgeline(bridges[2], "xx".to_string(), BridgeDistributor::Lox)
.to_serializable_report(); .to_serializable_report();
assert!(invalid_report_1.to_report().is_err()); assert!(invalid_report_1.to_report().is_err());
assert!(invalid_report_2.to_report().is_err()); assert!(invalid_report_2.to_report().is_err());
assert!(invalid_report_3.to_report().is_err());
// Check that verification fails with incorrect data // Check that verification fails with incorrect data
let date = get_date(); let date = get_date();
let mut rng = rand::thread_rng();
// Incorrect BridgeLine hash // Incorrect BridgeLine hash
let invalid_report_3 = NegativeReport::new( let mut nonce = [0; 32];
rng.fill_bytes(&mut nonce);
let invalid_report_4 = NegativeReport::new(
bridges[0].fingerprint, bridges[0].fingerprint,
ProofOfBridgeKnowledge::HashOfBridgeLine(HashOfBridgeLine::new( ProofOfBridgeKnowledge::HashOfBridgeLine(HashOfBridgeLine::new(
&BridgeLine::default(), &BridgeLine::default(),
date, date,
nonce,
)), )),
"ru".to_string(), "ru".to_string(),
date, date,
nonce,
BridgeDistributor::Lox, BridgeDistributor::Lox,
); );
// Incorrect bucket hash // Incorrect bucket hash
let invalid_report_4 = NegativeReport::new( let mut nonce = [0; 32];
rng.fill_bytes(&mut nonce);
let invalid_report_5 = NegativeReport::new(
bridges[1].fingerprint, bridges[1].fingerprint,
ProofOfBridgeKnowledge::HashOfBucket(HashOfBucket::new(&Scalar::ZERO, date)), ProofOfBridgeKnowledge::HashOfBucket(HashOfBucket::new(&Scalar::ZERO, date, nonce)),
"ru".to_string(), "ru".to_string(),
date, date,
nonce,
BridgeDistributor::Lox, BridgeDistributor::Lox,
); );
assert!(!invalid_report_3.verify(&bridge_info_1)); assert!(!invalid_report_4.verify(&bridge_info_1));
assert!(!invalid_report_4.verify(&bridge_info_2)); assert!(!invalid_report_5.verify(&bridge_info_2));
} }
#[test] #[test]