diff --git a/Changelog.md b/Changelog.md index 0b2100d..77d0d6b 100644 --- a/Changelog.md +++ b/Changelog.md @@ -6,6 +6,7 @@ Small and insignificant changes may not be included in this log. ## Unversioned Changes +* Improved the identity hash generation tool. The fastest quantity of goroutines is now identified and used. - *Simon Sarasova* * Improved the creation procedures, encoding format, and graphical presentation of genetic analyses. Map lists have been replaced by custom objects. - *Simon Sarasova* * Upgraded Circl to version 1.3.8. - *Simon Sarasova* diff --git a/Contributors.md b/Contributors.md index f5a0c97..1c28c69 100644 --- a/Contributors.md +++ b/Contributors.md @@ -9,4 +9,4 @@ Many other people have written code for modules which are imported by Seekia. Th Name | Date Of First Commit | Number Of Commits --- | --- | --- -Simon Sarasova | June 13, 2023 | 248 \ No newline at end of file +Simon Sarasova | June 13, 2023 | 249 \ No newline at end of file diff --git a/gui/createIdentityGui.go b/gui/createIdentityGui.go index 7d533e6..4c9b950 100644 --- a/gui/createIdentityGui.go +++ b/gui/createIdentityGui.go @@ -26,6 +26,7 @@ import "math" import "time" import "errors" + func setChooseNewIdentityHashPage(window fyne.Window, myIdentityType string, previousPage func(), onceCompletePage func()){ currentPage := func(){ setChooseNewIdentityHashPage(window, myIdentityType, previousPage, onceCompletePage) } @@ -59,7 +60,7 @@ func setChooseNewIdentityHashPage(window fyne.Window, myIdentityType string, pre } createCustomIdentityHashButton := getWidgetCentered(widget.NewButtonWithIcon("Create Custom", theme.SearchReplaceIcon(), func(){ - setCreateCustomIdentityHashPage(window, myIdentityType, currentPage, submitPageFunction) + setCreateCustomIdentityHashPage(window, myIdentityType, false, 0, 0, currentPage, submitPageFunction) })) selectRandomIdentityHashLabel := getLabelCentered("Select a random identity hash:") @@ -253,114 +254,145 @@ func setEnterMyNewSeedPhrasePage(window fyne.Window, myIdentityType string, newS setPageContent(page, window) } +//Inputs: +// -fyne.Window +// -string: Identity Type ("Mate"/"Host"/"Moderator") +// -bool: Benchmark is done (is false if we need to perform the benchmark +// -int64: Hashes per second (is 0 if benchmark hasn't been performed) +// -int: Optimal number of goroutines +// -previousPage() +// func(string, func()): submitPage function = func(newSeedPhrase string, previousPage func()) +func setCreateCustomIdentityHashPage(window fyne.Window, identityType string, benchmarkIsDone bool, computerHashesPerSecond int64, optimalNumberOfGoroutines int, previousPage func(), submitPage func(string, func()) ){ -// submitPage function = func(newSeedPhrase string, previousPage func()) + if (benchmarkIsDone == false){ + setLoadingScreen(window, "Create Custom Identity Hash", "Performing benchmark, this will take 4 seconds...") -func setCreateCustomIdentityHashPage(window fyne.Window, identityType string, previousPage func(), submitPage func(string, func()) ){ + // Output: + // -int64: Hashes per second + // -int: Optimal number of goroutines + // -error + performBenchmark := func()(int64, int, error){ - setLoadingScreen(window, "Create Custom Identity Hash", "Loading...") + //TODO: Fix to retrieve language from settings + currentLanguage := "English" + currentLanguageWordList, err := wordLists.GetWordListFromLanguage(currentLanguage) + if (err != nil) { return 0, 0, err } - currentPage := func(){ setCreateCustomIdentityHashPage(window, identityType, previousPage, submitPage) } + optimalNumberOfGoroutines := 0 + optimalNumberOfGoroutinesHashesPerSecond := int64(0) - // Output: - // -int64: Hashes per second - // -error - getIdentityHashGenerationSpeed := func()(int64, error){ + // We will try 1-8 goroutines to see which is the fastest - //TODO: Fix to retrieve language from settings - currentLanguage := "English" - currentLanguageWordList, err := wordLists.GetWordListFromLanguage(currentLanguage) - if (err != nil) { return 0, err } + for numberOfGoroutines:=1; numberOfGoroutines<=8; numberOfGoroutines++{ - // This counter will store the number of hashes we can compute in 1 second - var counterMutex sync.Mutex - counter := int64(0) + // This counter will store the number of hashes we can compute in 1 second + var counterMutex sync.Mutex + counter := int64(0) - // This bool keeps track of if the identity hash benchmark is happening - var generateHashesStatusBoolMutex sync.RWMutex - generateHashesStatusBool := false + // This bool keeps track of if the identity hash benchmark is happening + var generateHashesStatusBoolMutex sync.RWMutex + generateHashesStatusBool := false - var errorEncounteredMutex sync.Mutex - var errorEncountered error + var errorEncounteredMutex sync.Mutex + var errorEncountered error - setErrorEncounteredFunction := func(inputError error){ + setErrorEncounteredFunction := func(inputError error){ - errorEncounteredMutex.Lock() - errorEncountered = inputError - errorEncounteredMutex.Unlock() + errorEncounteredMutex.Lock() + errorEncountered = inputError + errorEncounteredMutex.Unlock() - generateHashesStatusBoolMutex.Lock() - generateHashesStatusBool = false - generateHashesStatusBoolMutex.Unlock() - } - - var identityHashGenerationWaitgroup sync.WaitGroup - - generateIdentityHashesFunction := func(){ - - subCounter := int64(0) - - for{ - - _, newSeedPhraseHash, err := seedPhrase.GetNewSeedPhraseFromWordList(currentLanguageWordList) - if (err != nil) { - setErrorEncounteredFunction(err) - break + generateHashesStatusBoolMutex.Lock() + generateHashesStatusBool = false + generateHashesStatusBoolMutex.Unlock() } - currentIdentityHashPrefix, err := identity.GetIdentityHash16CharacterPrefixFromSeedPhraseHash(newSeedPhraseHash) - if (err != nil) { - setErrorEncounteredFunction(err) - break + var identityHashGenerationWaitgroup sync.WaitGroup + + generateIdentityHashesFunction := func(){ + + subCounter := int64(0) + + for{ + + _, newSeedPhraseHash, err := seedPhrase.GetNewSeedPhraseFromWordList(currentLanguageWordList) + if (err != nil) { + setErrorEncounteredFunction(err) + break + } + + currentIdentityHashPrefix, err := identity.GetIdentityHash16CharacterPrefixFromSeedPhraseHash(newSeedPhraseHash) + if (err != nil) { + setErrorEncounteredFunction(err) + break + } + + // We have this check because we want to simulate how long it would take to check for a prefix + // The majority of the time is spent performing the hashing and ed25519 operations + strings.HasPrefix(currentIdentityHashPrefix, "seekia") + + subCounter += 1 + + generateHashesStatusBoolMutex.RLock() + generatingStatus := generateHashesStatusBool + generateHashesStatusBoolMutex.RUnlock() + + if (generatingStatus == false){ + counterMutex.Lock() + counter += subCounter + counterMutex.Unlock() + break + } + } + + identityHashGenerationWaitgroup.Done() } - // We have this check because we want to simulate how long it would take to check for a prefix - // The majority of the time is spent performing the hashing and ed25519 operations - strings.HasPrefix(currentIdentityHashPrefix, "seekia") + generateHashesStatusBool = true - subCounter += 1 + identityHashGenerationWaitgroup.Add(numberOfGoroutines) - generateHashesStatusBoolMutex.RLock() - generatingStatus := generateHashesStatusBool - generateHashesStatusBoolMutex.RUnlock() + for i:=0; i < numberOfGoroutines; i++{ - if (generatingStatus == false){ - counterMutex.Lock() - counter += subCounter - counterMutex.Unlock() - break + go generateIdentityHashesFunction() + } + + // We run all goroutines for 1/2 of a second + time.Sleep(time.Second/2) + + generateHashesStatusBoolMutex.Lock() + generateHashesStatusBool = false + generateHashesStatusBoolMutex.Unlock() + + identityHashGenerationWaitgroup.Wait() + + if (errorEncountered != nil){ + return 0, 0, errorEncountered + } + + currentGoroutinesNumberOfHashesPerSecond := counter*2 + + if (currentGoroutinesNumberOfHashesPerSecond > optimalNumberOfGoroutinesHashesPerSecond){ + optimalNumberOfGoroutines = numberOfGoroutines + optimalNumberOfGoroutinesHashesPerSecond = currentGoroutinesNumberOfHashesPerSecond } } - identityHashGenerationWaitgroup.Done() + return optimalNumberOfGoroutinesHashesPerSecond, optimalNumberOfGoroutines, nil } - generateHashesStatusBool = true - - identityHashGenerationWaitgroup.Add(2) - - go generateIdentityHashesFunction() - go generateIdentityHashesFunction() - - time.Sleep(time.Second) - - generateHashesStatusBoolMutex.Lock() - generateHashesStatusBool = false - generateHashesStatusBoolMutex.Unlock() - - identityHashGenerationWaitgroup.Wait() - - if (errorEncountered != nil){ - return 0, errorEncountered + optimalNumberOfGoroutinesHashesPerSecond, optimalNumberOfGoroutines, err := performBenchmark() + if (err != nil){ + setErrorEncounteredPage(window, err, previousPage) + return } - return counter, nil + setCreateCustomIdentityHashPage(window, identityType, true, optimalNumberOfGoroutinesHashesPerSecond, optimalNumberOfGoroutines, previousPage, submitPage) + return } - hashGenerationSpeed, err := getIdentityHashGenerationSpeed() - if (err != nil){ - setErrorEncounteredPage(window, err, previousPage) - return + currentPage := func(){ + setCreateCustomIdentityHashPage(window, identityType, true, computerHashesPerSecond, optimalNumberOfGoroutines, previousPage, submitPage) } title := getPageTitleCentered("Create Custom Identity Hash") @@ -385,7 +417,7 @@ func setCreateCustomIdentityHashPage(window fyne.Window, identityType string, pr customPrefixEntryOnChangedFunction := func(newPrefix string){ if (newPrefix == ""){ - err = estimatedTimeLabelBinding.Set("") + err := estimatedTimeLabelBinding.Set("") if (err != nil) { setErrorEncounteredPage(window, err, previousPage) return @@ -400,7 +432,7 @@ func setCreateCustomIdentityHashPage(window fyne.Window, identityType string, pr prefixLength := len(newPrefix) if (prefixLength >= 13){ - err = estimatedTimeLabelBinding.Set("Prefix is too long.") + err := estimatedTimeLabelBinding.Set("Prefix is too long.") if (err != nil) { setErrorEncounteredPage(window, err, previousPage) return @@ -415,7 +447,7 @@ func setCreateCustomIdentityHashPage(window fyne.Window, identityType string, pr isBase32, invalidCharacter := encoding.VerifyStringContainsOnlyBase32Charset(newPrefix) if (isBase32 == false){ - err = estimatedTimeLabelBinding.Set("Invalid character detected: " + invalidCharacter) + err := estimatedTimeLabelBinding.Set("Invalid character detected: " + invalidCharacter) if (err != nil) { setErrorEncounteredPage(window, err, previousPage) return @@ -432,7 +464,7 @@ func setCreateCustomIdentityHashPage(window fyne.Window, identityType string, pr numberOfBits := float64(numberOfCharacters * 5) numberOfRequiredHashes := math.Pow(2, numberOfBits) - estimatedTimeToGenerateInSeconds := numberOfRequiredHashes / float64(hashGenerationSpeed) + estimatedTimeToGenerateInSeconds := numberOfRequiredHashes / float64(computerHashesPerSecond) estimatedTimeUnitsTranslated, err := helpers.ConvertUnixTimeDurationToUnitsTimeTranslated(int64(estimatedTimeToGenerateInSeconds), false) if (err != nil) { @@ -489,7 +521,7 @@ func setCreateCustomIdentityHashPage(window fyne.Window, identityType string, pr } emptyList := make([]string, 0) - setRunCustomIdentityHashGenerationPage(window, identityType, prefix, estimatedTimeUnitsTranslated, hashGenerationSpeed, emptyList, currentPage, submitPage) + setRunCustomIdentityHashGenerationPage(window, identityType, prefix, estimatedTimeUnitsTranslated, optimalNumberOfGoroutines, computerHashesPerSecond, emptyList, currentPage, submitPage) })) customPrefixEntrySection := getContainerCentered(container.NewGridWithColumns(1, enterDesiredPrefixText, customPrefixEntry, startGeneratingHashesButton)) @@ -499,13 +531,11 @@ func setCreateCustomIdentityHashPage(window fyne.Window, identityType string, pr setPageContent(page, window) } - //TODO: Update the estimated time every ~10 seconds -//TODO: Figure out optimal number of goroutines to use for maximum speed -func setRunCustomIdentityHashGenerationPage(window fyne.Window, identityType string, desiredPrefix string, estimatedTimeRequired string, initialHashesPerSecond int64, seedPhrasesFoundList []string, previousPage func(), submitPage func(string, func()) ){ +func setRunCustomIdentityHashGenerationPage(window fyne.Window, identityType string, desiredPrefix string, estimatedTimeRequired string, numberOfGoroutines int, initialHashesPerSecond int64, seedPhrasesFoundList []string, previousPage func(), submitPage func(string, func()) ){ - currentPage := func(){setRunCustomIdentityHashGenerationPage(window, identityType, desiredPrefix, estimatedTimeRequired, initialHashesPerSecond, seedPhrasesFoundList, previousPage, submitPage)} + currentPage := func(){setRunCustomIdentityHashGenerationPage(window, identityType, desiredPrefix, estimatedTimeRequired, numberOfGoroutines, initialHashesPerSecond, seedPhrasesFoundList, previousPage, submitPage)} appMemory.SetMemoryEntry("CurrentViewedPage", "RunCustomIdentityHashGeneration") @@ -627,7 +657,7 @@ func setRunCustomIdentityHashGenerationPage(window fyne.Window, identityType str retryButton := getWidgetCentered(widget.NewButtonWithIcon("Retry", theme.ViewRefreshIcon(), func(){ emptyList := make([]string, 0) - setRunCustomIdentityHashGenerationPage(window, identityType, desiredPrefix, estimatedTimeRequired, initialHashesPerSecond, emptyList, previousPage, submitPage) + setRunCustomIdentityHashGenerationPage(window, identityType, desiredPrefix, estimatedTimeRequired, numberOfGoroutines, initialHashesPerSecond, emptyList, previousPage, submitPage) })) page := container.NewVBox(title, backButton, widget.NewSeparator(), doneDescription1, doneDescription2, widget.NewSeparator(), foundHashesGrid, retryButton) @@ -801,10 +831,11 @@ func setRunCustomIdentityHashGenerationPage(window fyne.Window, identityType str setGenerateHashesStatusBool(true) - generateHashesWaitgroup.Add(2) + generateHashesWaitgroup.Add(numberOfGoroutines) - go generateIdentityHashesFunction() - go generateIdentityHashesFunction() + for i:=0; i < numberOfGoroutines; i++{ + go generateIdentityHashesFunction() + } numberOfSecondsElapsed := 0 @@ -882,7 +913,7 @@ func setRunCustomIdentityHashGenerationPage(window fyne.Window, identityType str // We wait for all loops to exit generateHashesWaitgroup.Wait() - setRunCustomIdentityHashGenerationPage(window, identityType, desiredPrefix, estimatedTimeRequired, currentHashesPerSecond, seedPhrasesFoundList, previousPage, submitPage) + setRunCustomIdentityHashGenerationPage(window, identityType, desiredPrefix, estimatedTimeRequired, numberOfGoroutines, currentHashesPerSecond, seedPhrasesFoundList, previousPage, submitPage) return } diff --git a/gui/toolsGui.go b/gui/toolsGui.go index 1962ef9..37faf0a 100644 --- a/gui/toolsGui.go +++ b/gui/toolsGui.go @@ -93,7 +93,7 @@ func setChooseIdentityTypeForNewIdentityHashPage(window fyne.Window, previousPag } chooseIdentityTypeButton := widget.NewButton(identityType, func(){ - setCreateCustomIdentityHashPage(window, identityType, currentPage, submitPage) + setCreateCustomIdentityHashPage(window, identityType, false, 0, 0, currentPage, submitPage) }) buttonWithIcon := container.NewGridWithColumns(1, identityTypeIcon, chooseIdentityTypeButton)