Advertisement
Guest User

Untitled

a guest
Jul 11th, 2024
32
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 7.62 KB | None | 0 0
  1. import random
  2. from typing import List
  3. import matplotlib.pyplot as plt
  4.  
  5. class User:
  6.     def __init__(self, is_attacker=False, verified=False):
  7.         self.is_attacker = is_attacker
  8.         self.verified = verified
  9.  
  10. class Pair:
  11.     def __init__(self, user1: User, user2: User):
  12.         self.user1 = user1
  13.         self.user2 = user2
  14.         self.verified = False
  15.         self.disputed = False
  16.     def verify(self):
  17.         self.user1.verified = True
  18.         self.user2.verified = True
  19.         self.verified = True
  20.     def dispute(self, pairs: List['Pair'], courts: List['Court']):
  21.         if self.disputed or self.verified:
  22.             return
  23.         other_pairs = [p for p in pairs if p is not self]
  24.         pair1 = random.choice(other_pairs)
  25.         court1 = Court(self.user1, pair1)
  26.         courts.append(court1)
  27.         pair2 = random.choice(other_pairs)
  28.         court2 = Court(self.user2, pair2)
  29.         courts.append(court2)
  30.         self.disputed = True
  31.  
  32. class Court:
  33.     def __init__(self, user: User, pair: Pair):
  34.         self.user = user
  35.         self.pair = pair
  36.         self.verified = False
  37.     def verify(self):
  38.         if not self.pair.verified:
  39.             raise Exception("Pair not verified")
  40.         self.user.verified = True
  41.         self.verified = True
  42.  
  43. class System:
  44.     def __init__(self, starting_non_attackers, p_fv, non_attacker_growth_rate, fv_cost, invites_per_user):
  45.         self.starting_non_attackers = starting_non_attackers
  46.         if(starting_non_attackers % 2 == 0):
  47.             # enforce odd to make sure the lone attacker is not unpaired in the first period
  48.             self.starting_non_attackers = starting_non_attackers+1
  49.         self.p_fv = p_fv
  50.         self.non_attacker_growth_rate = non_attacker_growth_rate
  51.         self.invites_per_user = invites_per_user
  52.         self.fv_cost = fv_cost
  53.         self.users = [User(is_attacker=True, verified=True)]  # Start with one attacker
  54.         self.users.extend([User(verified= True) for _ in range(self.starting_non_attackers)])  # Add non-attacker users
  55.         self.attacker_cost = 0
  56.  
  57.     def run_period(self):
  58.         # Reset verification status
  59.         for user in self.users:
  60.             user.verified = False
  61.  
  62.         # Pair users
  63.         pairs:List[Pair] = []
  64.         random.shuffle(self.users)
  65.         for i in range(0, len(self.users), 2):
  66.             if i + 1 < len(self.users):
  67.                 pair = Pair(self.users[i], self.users[i+1])
  68.                 pairs.append(pair)
  69.  
  70.         # create new attacker accounts
  71.         attackers = sum(1 for user in self.users if user.is_attacker)
  72.         non_attackers = sum(1 for user in self.users if not user.is_attacker)
  73.         # attacker bribes/tricks for invites
  74.         attacker_invites_from_nonattackers = int(non_attackers * self.p_fv * self.invites_per_user)
  75.         self.attacker_cost += self.fv_cost*attacker_invites_from_nonattackers
  76.         attacker_invites_from_self = attackers * self.invites_per_user
  77.         attacker_invites = attacker_invites_from_nonattackers + attacker_invites_from_self
  78.         new_users = [User(is_attacker=True) for _ in range(attacker_invites)]
  79.  
  80.         # create new non-attacker accounts
  81.         non_attacker_invites = max(1, int(non_attackers * self.non_attacker_growth_rate))
  82.         max_non_attacker_invites = non_attackers * self.invites_per_user
  83.         # limit new invites to remaining invites
  84.         remaining_invites = max_non_attacker_invites - attacker_invites_from_nonattackers
  85.         non_attacker_invites = min(non_attacker_invites, remaining_invites)
  86.         new_users.extend([User() for _ in range(non_attacker_invites)])
  87.  
  88.         # Assign courts to random pairs
  89.         courts: List[Court] = []
  90.         for u in new_users:
  91.             self.users.append(u)
  92.             pair = random.choice(pairs)
  93.             court = Court(u, pair)
  94.             courts.append(court)
  95.  
  96.         # Handle non-attacker pairs
  97.         non_attacker_pairs = [p for p in pairs if not p.user1.is_attacker and not p.user2.is_attacker]
  98.         for p in non_attacker_pairs:
  99.             p.verify()
  100.  
  101.         # Handle attacker pairs
  102.         attacker_pairs = [p for p in pairs if p.user1.is_attacker and p.user2.is_attacker]
  103.         for p in attacker_pairs:
  104.             p.verify()
  105.  
  106.         # Handle attacker non-attacker pairs
  107.         attacker_non_pairs = [p for p in pairs if not p.verified and (p.user1.is_attacker or p.user2.is_attacker)]
  108.         for p in attacker_non_pairs:
  109.             self.attacker_cost += self.fv_cost  # Cost for attempting verification with non-attacker
  110.             if random.random() < self.p_fv:
  111.                 p.verify()
  112.             else:
  113.                 # Failed, dispute and reassign
  114.                 p.dispute(pairs, courts)
  115.  
  116.         # Handle non-attacker courts
  117.         non_attacker_courts = [c for c in courts if c.pair in non_attacker_pairs]
  118.         for c in non_attacker_courts:
  119.             if not c.user.is_attacker:
  120.                 c.verify()
  121.             else:
  122.                 # Attacker attempts to bribe/trick the two non-attackers
  123.                 self.attacker_cost += self.fv_cost*2
  124.                 if random.random() < self.p_fv**2:
  125.                     c.verify()
  126.  
  127.         # Handle attacker courts
  128.         attacker_courts = [c for c in courts if c.pair in attacker_pairs]
  129.         for c in attacker_courts:
  130.             if c.user.is_attacker:
  131.                 c.verify()
  132.  
  133.         # Handle attacker non-attacker courts
  134.         attacker_non_courts = [c for c in courts if c.pair in attacker_non_pairs]
  135.         for c in attacker_non_courts:
  136.             if c.pair.verified and c.user.is_attacker:
  137.                 c.verify()
  138.  
  139.         # remove unverified users
  140.         self.users = [u for u in self.users if u.verified]
  141.         if sum(1 for user in self.users if user.is_attacker) == 0:
  142.             # Ensure at least one attacker remains (the real person)
  143.             self.users.append(User(is_attacker=True, verified=True))
  144.  
  145. def run_simulation(starting_non_attackers, p_fv, non_attacker_growth_rate, fv_cost, invites_per_user, periods):
  146.     system = System(starting_non_attackers, p_fv, non_attacker_growth_rate, fv_cost, invites_per_user)
  147.     ratios = []
  148.     costs = []
  149.     for _ in range(periods):
  150.         system.run_period()
  151.         total_users = sum(1 for user in system.users if user.verified)
  152.         attackers = sum(1 for user in system.users if user.is_attacker and user.verified)
  153.         ratio = attackers / total_users if total_users else 0
  154.         ratios.append(ratio)
  155.         costs.append(system.attacker_cost)
  156.         if ratio > 1/2:
  157.             break
  158.     return ratios, costs
  159.    
  160. # Simulation parameters
  161. starting_non_attackers = 100
  162. p_fv = 0.2  # Probability of successful bribe/trick
  163. non_attacker_growth_rate = 0.05 # Growth rate of non-attacker accounts per existing non-attacker accounts
  164. fv_cost = 10  # Attacker cost per bribe/trick attempt
  165. invites_per_user = 4  # Per period
  166. max_periods = 24
  167.  
  168. num_simulations = 100
  169. periods_to_majority = []
  170. total_costs = []
  171. for _ in range(num_simulations):
  172.     ratios, costs = run_simulation(starting_non_attackers, p_fv, non_attacker_growth_rate, fv_cost, invites_per_user, max_periods)
  173.     periods_to_majority.append(len(ratios) if ratios[-1] > 1/2 else 0)
  174.     total_costs.append(costs[-1])
  175. print("% of simulations that reached majority: ", sum(1 for p in periods_to_majority if p > 0)/num_simulations)
  176. majority_periods = [p for p in periods_to_majority if p > 0]
  177. if len(majority_periods) > 0:
  178.     print("Average periods to reach majority: ", sum(p for p in majority_periods)/sum(1 for p in majority_periods))
  179. print("Average total attacker cost: ", sum(total_costs)/num_simulations)
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement