Skip to content

Commit ece2b52

Browse files
committed
Adding an ioc calculator
1 parent 321324e commit ece2b52

File tree

5 files changed

+132
-0
lines changed

5 files changed

+132
-0
lines changed

cmd/calcioc/go.mod

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
module calcioc
2+
3+
go 1.24

cmd/calcioc/main.go

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
package main
2+
3+
import (
4+
"flag"
5+
"fmt"
6+
"ioc"
7+
"os"
8+
"strings"
9+
)
10+
11+
func main() {
12+
// Define command line flags
13+
alphabetType := flag.String("alphabet", "english", "Type of alphabet to use (english, runeglish, or rune)")
14+
text := flag.String("text", "", "Text to analyze")
15+
16+
// Parse the flags
17+
flag.Parse()
18+
19+
// Validate that text was provided
20+
if *text == "" {
21+
fmt.Println("Error: No text provided for analysis")
22+
flag.Usage()
23+
os.Exit(1)
24+
}
25+
26+
// Get the appropriate alphabet based on the flag
27+
var alphabet ioc.AlphabetType
28+
switch strings.ToLower(*alphabetType) {
29+
case "english":
30+
alphabet = ioc.Latin
31+
break
32+
case "runeglish":
33+
alphabet = ioc.Runeglish
34+
break
35+
case "rune":
36+
alphabet = ioc.Rune
37+
break
38+
default:
39+
fmt.Println("Error: Invalid alphabet type")
40+
flag.Usage()
41+
os.Exit(1)
42+
}
43+
44+
// Calculate the Index of Coincidence
45+
result := ioc.CalcIOC(*text, alphabet)
46+
47+
// Output the result
48+
fmt.Printf("IoC: %f\n", result)
49+
}

go.work

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,4 +42,6 @@ use (
4242
cmd/ipaddressgen
4343
cmd/checkmultihash
4444
cmd/winchafftext
45+
pkg/utility/ioc
46+
cmd/calcioc
4547
)

pkg/utility/ioc/go.mod

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
module ioc
2+
3+
go 1.24

pkg/utility/ioc/iocutil.go

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
package ioc
2+
3+
import "strings"
4+
5+
// AlphabetType represents different types of alphabets that can be used for IOC calculation
6+
type AlphabetType int
7+
8+
const (
9+
// Latin represents the standard 26-letter Latin alphabet (a-z)
10+
Latin AlphabetType = iota
11+
// Runeglish represents the standard Latin alphabet plus common runes/symbols
12+
Runeglish
13+
// Rune represents all possible Unicode runes in the text
14+
Rune
15+
)
16+
17+
// GetAlphabet returns the character set corresponding to the specified alphabet type
18+
func GetAlphabet(alphabetType AlphabetType) []string {
19+
var retval string
20+
21+
switch alphabetType {
22+
case Latin:
23+
retval = "abcdefghijklmnopqrstuvwxyz"
24+
case Runeglish:
25+
retval = "abcdefghijlmnoprstuwxy"
26+
case Rune:
27+
retval = "ᛝᛟᛇᛡᛠᚫᚦᚠᚢᚩᚱᚳᚷᚹᚻᚾᛁᛄᛈᛉᛋᛏᛒᛖᛗᛚᛞᚪᚣ"
28+
default:
29+
retval = "abcdefghijklmnopqrstuvwxyz"
30+
}
31+
32+
return strings.Split(retval, "")
33+
}
34+
35+
// CalcIOC calculates the incidence of coincidence for the given text using the provided alphabet.
36+
// The incidence of coincidence is a measure used in cryptanalysis that
37+
// reflects the likelihood of randomly selecting the same letter twice from a text.
38+
// It returns a float64 value between 0 and 1.
39+
// If an empty alphabet is provided, the function defaults to the standard English alphabet.
40+
func CalcIOC(text string, alphabetType AlphabetType) float64 {
41+
// Get the alphabet
42+
alphabet := GetAlphabet(alphabetType)
43+
44+
// Create a map for faster character lookup
45+
validChars := make(map[string]bool)
46+
for _, char := range alphabet {
47+
validChars[char] = true
48+
}
49+
50+
// Create a map to count occurrences of each letter
51+
counts := make(map[string]int)
52+
53+
// Count only characters in our alphabet
54+
totalLetters := 0
55+
for _, char := range strings.ToLower(text) {
56+
if validChars[string(char)] {
57+
counts[string(char)]++
58+
totalLetters++
59+
}
60+
}
61+
62+
// If there are fewer than 2 letters, return 0
63+
if totalLetters <= 1 {
64+
return 0.0
65+
}
66+
67+
// Calculate the sum of frequencies squared
68+
var sum float64 = 0.0
69+
for _, count := range counts {
70+
sum += float64(count) * float64(count)
71+
}
72+
73+
// Calculate and return the IOC
74+
return sum / (float64(totalLetters) * float64(totalLetters-1))
75+
}

0 commit comments

Comments
 (0)