{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"pygments_lexer":"ipython3","nbconvert_exporter":"python","version":"3.6.4","file_extension":".py","codemirror_mode":{"name":"ipython","version":3},"name":"python","mimetype":"text/x-python"}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"markdown","source":"# Math Challenges","metadata":{}},{"cell_type":"markdown","source":"This set of challenges each provides some 2D matrixes.\n\n> This series of \"Math\" challenges is designed to introduce the concepts of dimensionality.\nData is often represented in a high dimensional space, but is actually several intrinsically low dimensional components that can be diagnosed. Intrinsic low-dimensionailty is incredibly important to machine learning because many ML algorithms rely on it. Medical EKG data is as single intrinsically 2 dimensional component, despite often being represented as 100 dimensions or more. The classic MNIST dataset is several components of 8-10 dimensions, depending on the digits class, despite being represented in 784 dimensions. The 4 math challenges are focused on this problem. **If you need a hint, ask Sven at the Art Booth.**\n\nOriginal problem Statement.\n\nThe participants are required to understand the dimensionality of the data. \nThis goes from understanding the correct number of clusters to finding the real dimensionality of a matrix using dimensionality reduction techniques.\n\n# Clustering \nClustering consists in finding groupings for datapoints. For example in the gif below data can be grouped in 3 groups.\nTo find these grouping I considered using KMeans (that is also the algorithm considered in the gif below).\n\n![](https://www.developersmaggioli.it/wp-content/uploads/2019/06/k4XcapI.gif)\n\n    \nI found this nice gif that shows KMeans clustering [here](https://www.developersmaggioli.it/blog/apprendimento-non-supervisionato-clustering-k-means).\n    \nIn particular for the challenge I used the [sklearn implementation](https://scikit-learn.org/stable/modules/generated/sklearn.cluster.KMeans.html) of KMeans as a clustering algorithm.\nI found several resources explaining K-means and i find always useful having a nice visual representation and guided explanation like the one from one of my favorite youtube channels, StatQuest ([link to KMeans video](https://www.youtube.com/watch?v=4b5d3muPQmA)),to listen to explanations about algorithms and concepts used in data science and machine learning. \n\n\n\n# Dimensionality reduction\n\nIn this challenges I used [sklearn implementation](https://scikit-learn.org/stable/modules/generated/sklearn.decomposition.PCA.html) of PCA (principal components analysis).\nAlso for PCA I suggest whatching an explanation [video](https://www.youtube.com/watch?v=FgakZw6K1QQ) which can cleanly break down the main ideas behind PCA.\n\nAs an intuitive idea we can consider the two images below, the first one shows some data in 3D space, the data however almost lies on a 2 plane inside the 3D space, we can say that the data itself can be specified by 2 coordinates. The second image shows the data in a 2D plane.\nBy reducing the dimensionality from 3D to 2D we can more easily observe the data.\n![](https://miro.medium.com/max/745/1*QinDfRawRskupf4mU5bYSA.png)\n![](https://miro.medium.com/max/875/1*LKTwaVmP4Dqxb-N3iD3CHw.png)\nImages from this [article](https://towardsdatascience.com/principal-component-analysis-pca-explained-visually-with-zero-math-1cbf392b9e7d).","metadata":{}},{"cell_type":"markdown","source":"# Imports and sub code","metadata":{}},{"cell_type":"code","source":"import pandas as pd\nimport numpy as np\nimport os\nimport requests\nimport matplotlib.pyplot as plt\nimport json\nimport shutil\nimport warnings\n\nwarnings.filterwarnings(\"ignore\")\ndir_name = \"/kaggle/input/ai-village-ctf\"\n\nfrom sklearn.cluster import KMeans\nfrom sklearn.decomposition import PCA","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","_kg_hide-input":true,"_kg_hide-output":false,"execution":{"iopub.status.busy":"2022-09-09T23:12:57.225792Z","iopub.execute_input":"2022-09-09T23:12:57.226248Z","iopub.status.idle":"2022-09-09T23:12:57.233178Z","shell.execute_reply.started":"2022-09-09T23:12:57.226210Z","shell.execute_reply":"2022-09-09T23:12:57.232027Z"},"jupyter":{"source_hidden":true},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def add_flag(challenge_id: str, flag: str) -> str:\n    try:\n        submission_path = \"/kaggle/working/submission.csv\"\n        template_path = f\"{dir_name}/submission.csv\"\n        if not os.path.isfile(submission_path) :\n            shutil.copyfile(template_path, submission_path)\n        flags = pd.read_csv(submission_path, index_col=\"challenge_id\")\n        valid = flags.index.to_list()\n        if challenge_id in valid:\n            flags.at[challenge_id] = flag\n            flags.to_csv(submission_path)\n            print(\"Flag saved. If you want to update the scoreboard, click 'submit' on the right. Remember that you can only update your score on the scoreboard 50 times per day\")\n        else:\n            print(\"Invalid challenge_id\")\n    except:\n        print(\"We had trouble saving that flag. Keep a copy of it and contact the CTF organizers.\")","metadata":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2022-09-09T23:12:57.238714Z","iopub.execute_input":"2022-09-09T23:12:57.239520Z","iopub.status.idle":"2022-09-09T23:12:57.248626Z","shell.execute_reply.started":"2022-09-09T23:12:57.239478Z","shell.execute_reply":"2022-09-09T23:12:57.247088Z"},"jupyter":{"source_hidden":true},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Math Challenge 1 (id: math_1) -- 100 Points\n\nHow many clusters are in the clusters1.npy, clusters2.npy, and clusters3.npy? The key is the number of clusters in order, with no spaces. These files are available in the input directory under `math`.","metadata":{}},{"cell_type":"markdown","source":"The goal of this challeng is finding the number of cluster for each of the three files clusters[1|2|3].npy.","metadata":{}},{"cell_type":"code","source":"#We start from loading data\na=np.load(\"../input/ai-village-ctf/math/clusters1.npy\")\nb=np.load(\"../input/ai-village-ctf/math/clusters2.npy\")\nc=np.load(\"../input/ai-village-ctf/math/clusters3.npy\")\na.shape,b.shape,c.shape","metadata":{"execution":{"iopub.status.busy":"2022-09-09T23:12:57.251152Z","iopub.execute_input":"2022-09-09T23:12:57.251696Z","iopub.status.idle":"2022-09-09T23:12:57.274200Z","shell.execute_reply.started":"2022-09-09T23:12:57.251664Z","shell.execute_reply":"2022-09-09T23:12:57.273132Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Here I define a helper function to perform knee/elbow analysis to get the correct number of clusters\ndef elbow_analysis(data,limit=30):\n    \n    inertias=[] #hold inertia values for different numbers of clusters\n    \n    K = range(1,limit) #range of number of clusters to try\n    inertia=0 # set initial intertia to 0 \n\n    fractions=[0,0] #padding for fraction of inertia at k clusters/ intertia at k+1 clusters\n    #we have no case with 0 or 1 clusters as correct output so i just set the result to 0 for those two sizes\n    for k in K:\n        #create and fit KMeans model\n        kmeanModel = KMeans(n_clusters=k)\n        kmeanModel.fit(data)\n        #retrieve inertia of the model and compute the change in inerta \n        if k>1:\n            new_inertia=kmeanModel.inertia_\n            fractions.append(inertia/new_inertia)\n            inertia=new_inertia\n        else:\n            inertia=kmeanModel.inertia_\n            \n        #save inertia value for plottin purpouses\n        inertias.append(kmeanModel.inertia_)\n        \n    plt.figure(figsize=(4,4))\n    plt.plot(K, inertias, 'bx-')\n    plt.xlabel('k')\n    plt.ylabel('Inertia')\n    plt.show()\n    return np.argmax(fractions)\n    ","metadata":{"execution":{"iopub.status.busy":"2022-09-09T23:12:57.275986Z","iopub.execute_input":"2022-09-09T23:12:57.276958Z","iopub.status.idle":"2022-09-09T23:12:57.286396Z","shell.execute_reply.started":"2022-09-09T23:12:57.276914Z","shell.execute_reply":"2022-09-09T23:12:57.285353Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#We perform knee/elbow analysis for the 3 matrices\na_size=elbow_analysis(a,limit=a.shape[1])\nb_size=elbow_analysis(b,limit=b.shape[1])\nc_size=elbow_analysis(c,limit=c.shape[1])","metadata":{"_kg_hide-output":true,"execution":{"iopub.status.busy":"2022-09-09T23:12:57.287534Z","iopub.execute_input":"2022-09-09T23:12:57.288182Z","iopub.status.idle":"2022-09-09T23:12:59.928063Z","shell.execute_reply.started":"2022-09-09T23:12:57.288148Z","shell.execute_reply":"2022-09-09T23:12:59.926917Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#We build the submission from the sizes found analyzing data \ntry:\n    r = requests.post(\"http://flags.fly.dev:5000/score\", json=json.dumps({\"challenge_id\": \"math_1\", \"submission\": f\"{a_size}{b_size}{c_size}\"}))\n    print(r.text)\nexcept requests.exceptions.ConnectionError:\n    print(\"Connection problems. Contact the CTF organizers.\")","metadata":{"execution":{"iopub.status.busy":"2022-09-09T23:12:59.930486Z","iopub.execute_input":"2022-09-09T23:12:59.930821Z","iopub.status.idle":"2022-09-09T23:13:00.032425Z","shell.execute_reply.started":"2022-09-09T23:12:59.930791Z","shell.execute_reply":"2022-09-09T23:13:00.031178Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"add_flag(\"math_1\", r.text[:-1].split(\"Nice work. The flag is \")[1])\nr.text[:-1].split(\"Nice work. The flag is \")[1]","metadata":{"execution":{"iopub.status.busy":"2022-09-09T23:13:00.034231Z","iopub.execute_input":"2022-09-09T23:13:00.034572Z","iopub.status.idle":"2022-09-09T23:13:00.047663Z","shell.execute_reply.started":"2022-09-09T23:13:00.034540Z","shell.execute_reply":"2022-09-09T23:13:00.046464Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Math Challenge 2 (id: math_2) -- 200 Points\n\nWhat's the dimensionality of the data in first_dim1.npy, first_dim2.npy, and first_dim3.npy? The key is the number of dimensions in order, with no spaces.  These files are available in the input directory under `math`.","metadata":{}},{"cell_type":"markdown","source":"The goal of this challeng is finding the dimensionality of the data for each of the three files first_dim[1|2|3].npy.","metadata":{}},{"cell_type":"code","source":"#Again we load the data\na=np.load(\"../input/ai-village-ctf/math/first_dim1.npy\")\nb=np.load(\"../input/ai-village-ctf/math/first_dim2.npy\")\nc=np.load(\"../input/ai-village-ctf/math/first_dim3.npy\")\na.shape,b.shape,c.shape","metadata":{"execution":{"iopub.status.busy":"2022-09-09T23:13:00.050131Z","iopub.execute_input":"2022-09-09T23:13:00.050639Z","iopub.status.idle":"2022-09-09T23:13:00.064535Z","shell.execute_reply.started":"2022-09-09T23:13:00.050585Z","shell.execute_reply":"2022-09-09T23:13:00.063492Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#we fit PCA model to the data for each matrix\na_transform=PCA().fit(a)\nb_transform=PCA().fit(b)\nc_transform=PCA().fit(c)\n\n#We get the number of singular values that are high enough\na_size = len(a_transform.singular_values_[a_transform.singular_values_>0.01])\nb_size = len(b_transform.singular_values_[b_transform.singular_values_>0.01])\nc_size = len(c_transform.singular_values_[c_transform.singular_values_>0.01])\n\na_transform.singular_values_,b_transform.singular_values_,c_transform.singular_values_","metadata":{"execution":{"iopub.status.busy":"2022-09-09T23:13:00.065663Z","iopub.execute_input":"2022-09-09T23:13:00.066007Z","iopub.status.idle":"2022-09-09T23:13:00.079834Z","shell.execute_reply.started":"2022-09-09T23:13:00.065976Z","shell.execute_reply":"2022-09-09T23:13:00.078385Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#We build the submission from the sizes found analyzing data \ntry:\n    r = requests.post(\"http://flags.fly.dev:5000/score\", json=json.dumps({\"challenge_id\": \"math_2\", \"submission\": f\"{a_size}{b_size}{c_size}\"}))\n    print(r.text)\nexcept requests.exceptions.ConnectionError:\n    print(\"Connection problems. Contact the CTF organizers.\")","metadata":{"execution":{"iopub.status.busy":"2022-09-09T23:13:00.081959Z","iopub.execute_input":"2022-09-09T23:13:00.082860Z","iopub.status.idle":"2022-09-09T23:13:00.182934Z","shell.execute_reply.started":"2022-09-09T23:13:00.082823Z","shell.execute_reply":"2022-09-09T23:13:00.181642Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"add_flag(\"math_2\", r.text[:-1].split(\"Nice work. The flag is \")[1])\nr.text[:-1].split(\"Nice work. The flag is \")[1]","metadata":{"execution":{"iopub.status.busy":"2022-09-09T23:13:00.184665Z","iopub.execute_input":"2022-09-09T23:13:00.185059Z","iopub.status.idle":"2022-09-09T23:13:00.199495Z","shell.execute_reply.started":"2022-09-09T23:13:00.185027Z","shell.execute_reply":"2022-09-09T23:13:00.198049Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Math Challenge 3 (id: math_3) -- 300 Points\n\nWhat's the dimensionality of the data in second_dim1.npy, second_dim2.npy, and second_dim3.npy? The key is the number of clusters in order, with no spaces.  These files are available in the input directory under `math`.","metadata":{}},{"cell_type":"markdown","source":"#### This challenge can be solved exactly using the same code as the previous one\nThe goal of this challeng is finding the dimensionality of the data for each of the three files second_dim[1|2|3].npy.","metadata":{}},{"cell_type":"code","source":"a=np.load(\"../input/ai-village-ctf/math/second_dim1.npy\")\nb=np.load(\"../input/ai-village-ctf/math/second_dim2.npy\")\nc=np.load(\"../input/ai-village-ctf/math/second_dim3.npy\")","metadata":{"execution":{"iopub.status.busy":"2022-09-09T23:13:00.204862Z","iopub.execute_input":"2022-09-09T23:13:00.205819Z","iopub.status.idle":"2022-09-09T23:13:00.216541Z","shell.execute_reply.started":"2022-09-09T23:13:00.205772Z","shell.execute_reply":"2022-09-09T23:13:00.215223Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"a_transform=PCA().fit(a)\nb_transform=PCA().fit(b)\nc_transform=PCA().fit(c)\n\n\na_size = len(a_transform.singular_values_[a_transform.singular_values_>0.01])\nb_size = len(b_transform.singular_values_[b_transform.singular_values_>0.01])\nc_size = len(c_transform.singular_values_[c_transform.singular_values_>0.01])\n\na_transform.singular_values_,b_transform.singular_values_,c_transform.singular_values_","metadata":{"execution":{"iopub.status.busy":"2022-09-09T23:13:00.217876Z","iopub.execute_input":"2022-09-09T23:13:00.218908Z","iopub.status.idle":"2022-09-09T23:13:00.232164Z","shell.execute_reply.started":"2022-09-09T23:13:00.218870Z","shell.execute_reply":"2022-09-09T23:13:00.231191Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"try:\n    r = requests.post(\"http://flags.fly.dev:5000/score\", json=json.dumps({\"challenge_id\": \"math_3\", \"submission\": f\"{a_size}{b_size}{c_size}\"}))\n    print(r.text)\nexcept requests.exceptions.ConnectionError:\n    print(\"Connection problems. Contact the CTF organizers.\")","metadata":{"execution":{"iopub.status.busy":"2022-09-09T23:13:00.233465Z","iopub.execute_input":"2022-09-09T23:13:00.233986Z","iopub.status.idle":"2022-09-09T23:13:00.338799Z","shell.execute_reply.started":"2022-09-09T23:13:00.233951Z","shell.execute_reply":"2022-09-09T23:13:00.337811Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"add_flag(\"math_3\", r.text[:-1].split(\"Nice work. The flag is \")[1])\nr.text[:-1].split(\"Nice work. The flag is \")[1]","metadata":{"execution":{"iopub.status.busy":"2022-09-09T23:13:00.340023Z","iopub.execute_input":"2022-09-09T23:13:00.340413Z","iopub.status.idle":"2022-09-09T23:13:00.353058Z","shell.execute_reply.started":"2022-09-09T23:13:00.340378Z","shell.execute_reply":"2022-09-09T23:13:00.352046Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Math Challenge 4 (id: math_4) -- 400 Points\n\nWhat's the dimensionality of the clusters in clusters1.npy? The key is the dimensions ordered by cluster size (smallest to largest), with no spaces.  These files are available in the input directory under `math`.","metadata":{}},{"cell_type":"markdown","source":"This challenge combines the 2 types of challenges seen above.\n> The key is the dimensions ordered by cluster size (smallest to largest).\n\nThis line may seem confusing but once we change \"dimensions\" with \"dimensionality of each cluster\" we get.\n> The key is the dimensionality of each cluster ordered by cluster size (smallest to largest).\n\nWe have to perform 3 steps:\n1. Use KMean clustering and cluster data from clusters1.npy\n2. Reorder the cluster by their size\n3. Calculate the dimensionality of each cluster","metadata":{}},{"cell_type":"code","source":"#First step:  load data, find correct number of clusters and perform clustering\na=np.load(\"../input/ai-village-ctf/math/clusters1.npy\")\na_size=elbow_analysis(a)\nkmeanModel=KMeans(n_clusters=a_size)\nkmeanModel.fit(a)","metadata":{"execution":{"iopub.status.busy":"2022-09-09T23:13:00.354373Z","iopub.execute_input":"2022-09-09T23:13:00.354878Z","iopub.status.idle":"2022-09-09T23:13:01.897964Z","shell.execute_reply.started":"2022-09-09T23:13:00.354847Z","shell.execute_reply":"2022-09-09T23:13:01.897124Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#this variable holds the cluster index\nkmeanModel.labels_","metadata":{"execution":{"iopub.status.busy":"2022-09-09T23:13:01.899133Z","iopub.execute_input":"2022-09-09T23:13:01.900017Z","iopub.status.idle":"2022-09-09T23:13:01.906066Z","shell.execute_reply.started":"2022-09-09T23:13:01.899981Z","shell.execute_reply":"2022-09-09T23:13:01.905298Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#STEP 2: Use the cluster indexes to compute cluster size\ncluster_size=[]\nfor k in range(5):\n    cluster_size.append((kmeanModel.labels_==k).sum())\ncluster_size","metadata":{"execution":{"iopub.status.busy":"2022-09-09T23:13:01.907171Z","iopub.execute_input":"2022-09-09T23:13:01.908088Z","iopub.status.idle":"2022-09-09T23:13:01.920402Z","shell.execute_reply.started":"2022-09-09T23:13:01.908052Z","shell.execute_reply":"2022-09-09T23:13:01.919457Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#STEP 2: sort cluster indexes \nsorted_clusters=np.argsort(cluster_size)","metadata":{"execution":{"iopub.status.busy":"2022-09-09T23:13:01.921610Z","iopub.execute_input":"2022-09-09T23:13:01.922465Z","iopub.status.idle":"2022-09-09T23:13:01.931815Z","shell.execute_reply.started":"2022-09-09T23:13:01.922430Z","shell.execute_reply":"2022-09-09T23:13:01.930613Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#STEP 3: For each cluster \"c\" get points in the cluster , compute PCA and get the number of singular values that are high enough\nvalues=[]\nfor c in sorted_clusters:\n    cluster=a[kmeanModel.labels_==c]\n    cluster_t=PCA().fit(cluster)\n    \n    values.append(len(cluster_t.singular_values_[cluster_t.singular_values_>0.01]))","metadata":{"execution":{"iopub.status.busy":"2022-09-09T23:13:01.933352Z","iopub.execute_input":"2022-09-09T23:13:01.933735Z","iopub.status.idle":"2022-09-09T23:13:01.947330Z","shell.execute_reply.started":"2022-09-09T23:13:01.933660Z","shell.execute_reply":"2022-09-09T23:13:01.946144Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#We build the submission from the sizes found analyzing data \ntry:\n    r = requests.post(\"http://flags.fly.dev:5000/score\", json=json.dumps({\"challenge_id\": \"math_4\", \"submission\": \"\".join([str(v) for v in values])}))\n    print(r.text)\nexcept requests.exceptions.ConnectionError:\n    print(\"Connection problems. Contact the CTF organizers.\")","metadata":{"execution":{"iopub.status.busy":"2022-09-09T23:13:01.948932Z","iopub.execute_input":"2022-09-09T23:13:01.950078Z","iopub.status.idle":"2022-09-09T23:13:02.054265Z","shell.execute_reply.started":"2022-09-09T23:13:01.950002Z","shell.execute_reply":"2022-09-09T23:13:02.052959Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"add_flag(\"math_4\", r.text[:-1].split(\"Nice work. The flag is \")[1])\nr.text[:-1].split(\"Nice work. The flag is \")[1]","metadata":{"execution":{"iopub.status.busy":"2022-09-09T23:13:02.056904Z","iopub.execute_input":"2022-09-09T23:13:02.057453Z","iopub.status.idle":"2022-09-09T23:13:02.071901Z","shell.execute_reply.started":"2022-09-09T23:13:02.057408Z","shell.execute_reply":"2022-09-09T23:13:02.070472Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# WIFI (id: wifi) -- 200 Points\n\n### Scenario\n\nYou really need to check your email, unfortunately you don't know the password.  Fortunately, someone wrote it down.  Unfortunately, it's written down on a low-dimensional manifold embedded in a very high-dimensional space.  Check out the `wifi/Embedded characters.npz` file -- a list of tokens is given in the `tokens` key with their corresponding embeddings in the same order under the `embeddings` key -- and recover the password.\n\n### Objective\n\nThe password is your flag, like all others, it has the format `FLAG{something}`","metadata":{}},{"cell_type":"markdown","source":"## Solving WIFI\nThis challenge was a first road block, at the beginning I couldn't see how to solve it.\n\nThis problem itself required seeing the data, not only manipulating it.","metadata":{}},{"cell_type":"code","source":"#load the data\ndata=np.load(\"../input/ai-village-ctf/wifi/Embedded_characters.npz\")\ntokens=data[\"tokens\"][()]\n\n#fit a PCA model to the embeddings matrix and visualize the first 20 singular values\nmodel=PCA().fit(data[\"embeddings\"])\nprint(model.singular_values_[:20])","metadata":{"execution":{"iopub.status.busy":"2022-09-09T23:13:02.073392Z","iopub.execute_input":"2022-09-09T23:13:02.073711Z","iopub.status.idle":"2022-09-09T23:13:02.123679Z","shell.execute_reply.started":"2022-09-09T23:13:02.073682Z","shell.execute_reply":"2022-09-09T23:13:02.122157Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"We see that the first 2 values have high values and the other values are really low.\nThe data is 2D","metadata":{}},{"cell_type":"code","source":"#get the dimensionality of the data and transform the embeddings \nnumber=(model.singular_values_>1).sum()\nemb_reduced=PCA(n_components=number).fit_transform(data[\"embeddings\"])","metadata":{"execution":{"iopub.status.busy":"2022-09-09T23:13:02.126024Z","iopub.execute_input":"2022-09-09T23:13:02.127013Z","iopub.status.idle":"2022-09-09T23:13:02.201665Z","shell.execute_reply.started":"2022-09-09T23:13:02.126952Z","shell.execute_reply":"2022-09-09T23:13:02.197710Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"2D data -> we can visualize it","metadata":{}},{"cell_type":"code","source":"plt.scatter(emb_reduced[:,0],emb_reduced[:,1])\nplt.show()","metadata":{"execution":{"iopub.status.busy":"2022-09-09T23:13:02.205589Z","iopub.execute_input":"2022-09-09T23:13:02.207024Z","iopub.status.idle":"2022-09-09T23:13:02.464419Z","shell.execute_reply.started":"2022-09-09T23:13:02.206948Z","shell.execute_reply":"2022-09-09T23:13:02.463309Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"This is a strange pattern, let's try to follow the spiral and read the tokens in the order","metadata":{}},{"cell_type":"code","source":"#transform the 2D data into 1D unrolling the spiral\nr=emb_reduced[:,0]**2+emb_reduced[:,1]**2\n#build the result reading the tokens following the order of the spiral\nres=\"\"\nfor index in r.reshape(-1).argsort():\n    res+=tokens[index]\nres","metadata":{"execution":{"iopub.status.busy":"2022-09-09T23:13:02.465832Z","iopub.execute_input":"2022-09-09T23:13:02.466220Z","iopub.status.idle":"2022-09-09T23:13:02.475323Z","shell.execute_reply.started":"2022-09-09T23:13:02.466187Z","shell.execute_reply":"2022-09-09T23:13:02.474044Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# submit the password we found\ntry:\n    r = requests.post(\"http://flags.fly.dev:5000/score\", json=json.dumps({\"challenge_id\": \"wifi\", \"submission\": res[:res.index(\"}\")+1]}))\n    print(r.text)\nexcept requests.exceptions.ConnectionError:\n    print(\"Connection problems. Contact the CTF organizers.\")","metadata":{"execution":{"iopub.status.busy":"2022-09-09T23:13:02.476885Z","iopub.execute_input":"2022-09-09T23:13:02.477506Z","iopub.status.idle":"2022-09-09T23:13:02.580880Z","shell.execute_reply.started":"2022-09-09T23:13:02.477450Z","shell.execute_reply":"2022-09-09T23:13:02.579817Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"add_flag(\"wifi\", r.text.split(\"The flag is \")[1].replace(\".\",\"\"))\nr.text.split(\"The flag is \")[1].replace(\".\",\"\")","metadata":{"execution":{"iopub.status.busy":"2022-09-09T23:13:02.582208Z","iopub.execute_input":"2022-09-09T23:13:02.582903Z","iopub.status.idle":"2022-09-09T23:13:02.601254Z","shell.execute_reply.started":"2022-09-09T23:13:02.582855Z","shell.execute_reply":"2022-09-09T23:13:02.599709Z"},"trusted":true},"execution_count":null,"outputs":[]}]}