This is a repository for Trusta’s AI and machine learning framework for robust Sybil identification in airdrops
from graphframes import GraphFrame
import pyspark.sql.functions as F


def calculate_component(edges, ctype="weak"):
    
    edge_df = edges.select(["src", "dst"]).repartition(20).cache()
    node_df = edges.select(F.col("src").alias("id")).union(edges.select(F.col("dst").alias("id"))).groupby(["id"]).agg(F.lit(1).alias("_c"))
    
    g = GraphFrame(node_df, edge_df)
    if ctype == "weak":
        results = g.connectedComponents()
    elif ctype == "strong":
        results = g.stronglyConnectedComponents(maxIter=10)
    else:
        results = g.connectedComponents()

    results = results.select(["id", "component"]).withColumn("src", F.col("id"))
    size_count = results.groupby(["component"]).agg(F.count("id").alias("component_size")).filter("component_size>={size}".format(size=COMPONENT_SIZE_THRESHOLD))
    tmp_merge = results.join(size_count, ["component", ]).cache()

    edge_result = edges.join(tmp_merge, ["src"]).withColumnRenamed("src", "source").withColumnRenamed("dst", "target")
    node_result = node_df.join(tmp_merge, ["id"]).withColumnRenamed("id", "address").drop("src")

    return edge_result, node_result


def filtered_groups(groups):
    action_count = groups.groupby(["current_component", "address"]).agg(F.countDistinct("action").alias("_freq")).filter("_freq >={t}".format(t=GROUP_SIZE_THRESHOLD))
    action_filtered = groups.join(action_count, ["current_component", "address",]).drop("component_size").cache()

    address_count = action_filtered.groupby(["current_component", "component_id"]).agg(F.countDistinct("address").alias("component_size")).filter("component_size >={t}".format(t=COMPONENT_SIZE_THRESHOLD))
    result = action_filtered.join(address_count, ["current_component", "component_id",]).drop("_freq").cache()
    
    return result

    
def check_sybils(components):

    old_size = components.count()
    address_to_component = filtered_groups(components)
    current_size = address_to_component.count()
    while old_size > current_size and current_size > 0:
        old_size = current_size
        address_to_component = filtered_groups(address_to_component)
        current_size = address_to_component.count()

    return address_to_component


src/scripts/components_scripts.py
TrustaLabs/Airdrop-Sybil-Identification
import numpy as np
from sklearn.neighbors import KDTree
def assign_data_to_particles(particles, new_data):
    m, n = particles.shape
    k, _ = new_data.shape

    if n != new_data.shape[1]:
        raise ValueError("Number of columns in particles and new_data must match.")

    # Build a KD tree from the particles
    kdtree = KDTree(particles, metric='manhattan')

    # Calculate the sum of particle elements along columns
    sum_particles = np.sum(particles, axis=1)

    # Calculate the threshold for similarity based on 10% of sum_particles + 2
    threshold = 0.15 * sum_particles + 2

    # Query the KD tree to find the closest particles for each new data point
    distances, closest_particle_indices = kdtree.query(new_data, k=1)

    # Initialize the labels array
    labels = np.zeros(k, dtype=int)

    for i in range(k):
        if distances[i] > threshold[closest_particle_indices[i]]:  # Use the threshold corresponding to each new data point
            labels[i] = -999  # If the distance is greater than the threshold, mark as unassigned
        else:
            labels[i] = closest_particle_indices[i]  # Assign the label as the closest particle index

    return labels

src/scripts/kdtree_dist_cluster.py
TrustaLabs/Airdrop-Sybil-Identification
import networkx as nx
import matplotlib.pyplot as plt
from datetime import datetime
import community  


transactions = [
......
    # Add more transactions as needed
]


G = nx.Graph()
for sender, receiver, weight in transactions:
    if not G.has_node(sender):
        G.add_node(sender)
    if not G.has_node(receiver):
        G.add_node(receiver)

    G.add_edge(sender, receiver, weight=weight)


partition = community.best_partition(G)

pos = nx.spring_layout(G)
plt.figure(figsize=(10, 6))
cmap = plt.get_cmap('viridis', max(partition.values()) + 1)
nx.draw_networkx_nodes(G, pos, node_color=[cmap(partition[node]) for node in G.nodes()])
nx.draw_networkx_edges(G, pos, alpha=0.5)
plt.title('Community Detection using Louvain Algorithm')
plt.show()



src/scripts/network_community.py
TrustaLabs/Airdrop-Sybil-Identification