From dc219ae8dbd4faf908652eb801673e352ee35dd8 Mon Sep 17 00:00:00 2001 From: Afshin Arani Date: Fri, 28 Apr 2023 20:23:30 +0330 Subject: [PATCH] Directory,Utility: use binary search This commit changes the search algorithm for finding hs directories from linear to binary search. --- NOnion/Directory/TorDirectory.fs | 58 ++++++++++++++------------------ NOnion/NOnion.fsproj | 1 + NOnion/Utility/ByteArrayUtil.fs | 36 ++++++++++++++++++++ 3 files changed, 62 insertions(+), 33 deletions(-) create mode 100644 NOnion/Utility/ByteArrayUtil.fs diff --git a/NOnion/Directory/TorDirectory.fs b/NOnion/Directory/TorDirectory.fs index f045f40c..8304a932 100644 --- a/NOnion/Directory/TorDirectory.fs +++ b/NOnion/Directory/TorDirectory.fs @@ -12,6 +12,7 @@ open NOnion.Crypto open NOnion.Network open NOnion.Http open NOnion.Utility +open NOnion.Utility.ByteArrayUtil type RouterType = | Normal @@ -456,33 +457,6 @@ type TorDirectory = let! networkStatus = self.GetLiveNetworkStatus() - let ByteArrayCompare (x: array) (y: array) = - let xlen = x.Length - let ylen = y.Length - - let len = - if xlen < ylen then - xlen - else - ylen - - let mutable index = 0 - let mutable result = 0 - - while index < len do - let diff = (int(x.[index])) - int(y.[index]) - - if diff <> 0 then - index <- len + 1 // breaks out of the loop, and signals that result is valid - result <- diff - else - index <- index + 1 - - if index > len then - result - else - (xlen - ylen) - let directories = networkStatus.GetHiddenServiceDirectories() |> List.choose(fun node -> @@ -528,13 +502,31 @@ type TorDirectory = ] |> HiddenServicesCipher.SHA3256 - //FIXME: binary serach idx here let start = - directories - |> Seq.tryFindIndex(fun (_, index) -> - ByteArrayCompare index hsIndex >= 0 - ) - |> Option.defaultValue 0 + let maybeStart = + let hsIndexes = + directories + |> Array.ofList + |> Array.map(fun (_, hsIndex) -> hsIndex) + + Array.BinarySearch( + hsIndexes, + hsIndex, + ByteArrayComparer() + ) + + if maybeStart < 0 then + let complement = ~~~maybeStart + + // Getting the length of the list if no member is greater than the key we + // are looking for so start at the first element. + if complement >= directories.Length then + let arrayStartIndex = 0 + arrayStartIndex + else + complement + else + maybeStart let rec pickNodes startIndex nToAdd state = if nToAdd = 0 then diff --git a/NOnion/NOnion.fsproj b/NOnion/NOnion.fsproj index b7a72d39..e162fbea 100644 --- a/NOnion/NOnion.fsproj +++ b/NOnion/NOnion.fsproj @@ -18,6 +18,7 @@ + diff --git a/NOnion/Utility/ByteArrayUtil.fs b/NOnion/Utility/ByteArrayUtil.fs new file mode 100644 index 00000000..0faccc65 --- /dev/null +++ b/NOnion/Utility/ByteArrayUtil.fs @@ -0,0 +1,36 @@ +namespace NOnion.Utility + +open System.Collections.Generic + +module ByteArrayUtil = + let ByteArrayCompare (x: array) (y: array) = + let xlen = x.Length + let ylen = y.Length + + let len = + if xlen < ylen then + xlen + else + ylen + + let mutable index = 0 + let mutable result = 0 + + while index < len do + let diff = (int(x.[index])) - int(y.[index]) + + if diff <> 0 then + index <- len + 1 // breaks out of the loop, and signals that result is valid + result <- diff + else + index <- index + 1 + + if index > len then + result + else + (xlen - ylen) + + type ByteArrayComparer() = + interface IComparer> with + member __.Compare(first, second) = + ByteArrayCompare first second