diff --git a/README.md b/README.md index 166f533..75375e8 100644 --- a/README.md +++ b/README.md @@ -282,6 +282,11 @@ you can supply arguments the most common prefixes i.e. n= -n= --n= multiple values can be supplied as a list or with multiple argument prefixes e.g. -n=1,2,3 or -n=1 -n=2 -n=3 +this command opportunistically makes use of the following tools to perform factorization: + + - gmp-ecm + - pari-gp + for example: ```bash $ ret factor -n=1807415580361109435231633835400969 diff --git a/commands/factor.go b/commands/factor.go index 6e49784..ad24b77 100644 --- a/commands/factor.go +++ b/commands/factor.go @@ -8,6 +8,7 @@ import ( "ret/util" "strings" "sync" + "time" ) var ( @@ -37,6 +38,10 @@ func FactorHelp() string { "you can supply arguments the most common prefixes i.e. " + theme.ColorBlue + "n= -n= --n= " + theme.ColorReset + "\n\n" + "multiple values can be supplied as a list or with multiple argument prefixes e.g. " + theme.ColorBlue + "-n=1,2,3 or -n=1 -n=2 -n=3" + theme.ColorReset + "\n\n" + + "this command opportunistically makes use of the following tools to perform factorization:\n\n" + + " - gmp-ecm\n" + + " - pari-gp\n\n" + + "for example:\n" + "```bash\n" + theme.ColorGray + "$ " + theme.ColorBlue + "ret factor -n=1807415580361109435231633835400969\n" + theme.ColorReset + @@ -63,6 +68,8 @@ func parseFactorArgs(args []string) { } func Factor(args []string) { + startTime := time.Now() + parseFactorArgs(args) var wg sync.WaitGroup @@ -72,6 +79,7 @@ func Factor(args []string) { go func() { defer wg.Done() + factors, url, err := util.FactorDB(n) if err != nil { log.Fatalf("💥 "+theme.ColorRed+" error"+theme.ColorReset+": %v\n", err) @@ -85,9 +93,74 @@ func Factor(args []string) { return } - fmt.Printf("%v\n%v\n", factors, url) + diff := time.Now().Sub(startTime) + + fmt.Printf(theme.ColorGreen+"🪓 [factordb]"+theme.ColorReset+" in "+ + theme.ColorYellow+"%v"+theme.ColorGray+" %v"+theme.ColorReset+"\n"+"%v\n\n", + diff, url, factors) }() } + if util.CheckIfECMInstalled() { + + for _, n := range N { + wg.Add(1) + + go func() { + defer wg.Done() + + factors, cmdStr, err := util.FactorWithECM(n) + if err != nil { + log.Fatalf("💥 "+theme.ColorRed+" error"+theme.ColorReset+": %v\n", err) + } + + if factors == nil { + return + } + + if len(factors) == 0 { + return + } + + diff := time.Now().Sub(startTime) + + fmt.Printf(theme.ColorGreen+"🪓 [ecm]"+theme.ColorReset+" in "+ + theme.ColorYellow+"%v"+theme.ColorGray+" %v"+theme.ColorReset+"\n"+"%v\n\n", + diff, cmdStr, factors) + }() + } + } + + if util.CheckIfPariInstalled() { + + for _, n := range N { + wg.Add(1) + + go func() { + defer wg.Done() + + factors, cmdStr, err := util.FactorWithPari(n) + if err != nil { + log.Fatalf("💥 "+theme.ColorRed+" error"+theme.ColorReset+": %v\n", err) + } + + if factors == nil { + return + } + + if len(factors) == 0 { + return + } + + diff := time.Now().Sub(startTime) + + fmt.Printf(theme.ColorGreen+"🪓 [gp-pari]"+theme.ColorReset+" in "+ + theme.ColorYellow+"%v"+theme.ColorGray+" %v"+theme.ColorReset+"\n"+"%v\n\n", + diff, cmdStr, factors) + }() + } + + } + wg.Wait() } diff --git a/rsa/factor_with_ecm.go b/rsa/factor_with_ecm.go index 144bd51..ae70c4c 100644 --- a/rsa/factor_with_ecm.go +++ b/rsa/factor_with_ecm.go @@ -1,13 +1,11 @@ package rsa import ( - "bufio" "fmt" "log" "math/big" - "os/exec" "ret/theme" - "strings" + "ret/util" "sync" ) @@ -71,54 +69,13 @@ func scriptFactorECMManyFactors(cmd string, factors []*big.Int, n *big.Int, e *b fmt.Print(script) } func factorWithECM(strategy *Strategy, n *big.Int) { - cmd := exec.Command("/usr/bin/ecm", "-c", "1000000000", "-one", "2000") + factors, cmdStr, err := util.FactorWithECM(n) - stdin, err := cmd.StdinPipe() if err != nil { log.Printf("💥 "+theme.ColorRed+" error"+theme.ColorReset+": %v\n", err) return } - stdout, err := cmd.StdoutPipe() - if err != nil { - log.Printf("💥 "+theme.ColorRed+" error"+theme.ColorReset+": %v\n", err) - return - } - - factors := make([]*big.Int, 0) - - cofactor := new(big.Int).Set(n) - - stdin.Write([]byte(fmt.Sprintf("%s\n", cofactor))) - - cmd.Start() - - scanner := bufio.NewScanner(stdout) - - for scanner.Scan() { - line := scanner.Text() - - splits := strings.Split(line, " ") - - if strings.Contains(line, "Found prime factor of ") { - factor, _ := new(big.Int).SetString(splits[len(splits)-1], 10) - factors = append(factors, factor) - continue - } - - if strings.Contains(line, "Composite cofactor") { - cofactor.SetString(splits[2], 10) - stdin.Write([]byte(fmt.Sprintf("%s\n", cofactor))) - continue - } - - if strings.Contains(line, "Prime cofactor") { - factor, _ := new(big.Int).SetString(splits[2], 10) - factors = append(factors, factor) - break - } - } - if len(factors) == 2 { // special case for N = p * q where p and q and two distinct primes p := factors[0] @@ -135,7 +92,7 @@ func factorWithECM(strategy *Strategy, n *big.Int) { continue } - scriptFactorECM(cmd.String(), p, q, n, e, c, mBytes) + scriptFactorECM(cmdStr, p, q, n, e, c, mBytes) } } } else { @@ -156,20 +113,15 @@ func factorWithECM(strategy *Strategy, n *big.Int) { continue } - scriptFactorECMManyFactors(cmd.String(), factors, n, e, c, mBytes) + scriptFactorECMManyFactors(cmdStr, factors, n, e, c, mBytes) } } } } func StrategyFactorWithECM(strategy *Strategy) { - // check that ecm is installed - cmd := exec.Command("/usr/bin/ecm", "--help") - - err := cmd.Run() - if err != nil { - fmt.Printf("😰"+theme.ColorGray+" \""+theme.ColorReset+"%v"+theme.ColorGray+"\""+theme.ColorYellow+ - " failed"+theme.ColorReset+"! consider installing "+theme.ColorCyan+"gmp-ecm"+theme.ColorReset+"\n", cmd.String()) + installed := util.CheckIfECMInstalled() + if installed != true { return } diff --git a/rsa/factor_with_pari.go b/rsa/factor_with_pari.go index ecfc10a..62587f5 100644 --- a/rsa/factor_with_pari.go +++ b/rsa/factor_with_pari.go @@ -1,15 +1,11 @@ package rsa import ( - "bufio" "fmt" "log" "math/big" - "os" - "os/exec" "ret/theme" - "strconv" - "strings" + "ret/util" "sync" ) @@ -73,49 +69,13 @@ func scriptFactorPariManyFactors(cmd string, factors []*big.Int, n *big.Int, e * fmt.Print(script) } func factorWithPari(strategy *Strategy, n *big.Int) { - file, err := os.CreateTemp("", "ret_rsa_factorme") + factors, cmdStr, err := util.FactorWithPari(n) - fmt.Fprintf(file, "print(factorint(%s))\n", n) - - file.Close() - - cmd := exec.Command("/usr/bin/gp", "--stacksize", "1073741824", "--fast", "--quiet", file.Name()) - - stdout, err := cmd.StdoutPipe() if err != nil { log.Printf("💥 "+theme.ColorRed+" error"+theme.ColorReset+": %v\n", err) return } - factors := make([]*big.Int, 0) - - cmd.Start() - - scanner := bufio.NewScanner(stdout) - - if !scanner.Scan() { - return - } - - line := scanner.Text() - splits := strings.Split(line[1:len(line)-1], ";") - - for _, split := range splits { - nums := strings.Split(split, ",") - - count, err := strconv.Atoi(strings.TrimSpace(nums[1])) - if err != nil { - log.Printf("💥 "+theme.ColorRed+" error"+theme.ColorReset+": %v\n", err) - return - } - - factor, _ := new(big.Int).SetString(strings.TrimSpace(nums[0]), 10) - - for range count { - factors = append(factors, factor) - } - } - if len(factors) == 2 { // special case for N = p * q where p and q and two distinct primes p := factors[0] @@ -132,7 +92,7 @@ func factorWithPari(strategy *Strategy, n *big.Int) { continue } - scriptFactorPari(cmd.String(), p, q, n, e, c, mBytes) + scriptFactorPari(cmdStr, p, q, n, e, c, mBytes) } } } else { @@ -153,20 +113,15 @@ func factorWithPari(strategy *Strategy, n *big.Int) { continue } - scriptFactorPariManyFactors(cmd.String(), factors, n, e, c, mBytes) + scriptFactorPariManyFactors(cmdStr, factors, n, e, c, mBytes) } } } } func StrategyFactorWithPari(strategy *Strategy) { - // check that pari-gp is installed - cmd := exec.Command("/usr/bin/gp", "-v") - - err := cmd.Run() - if err != nil { - fmt.Printf("😰"+theme.ColorGray+" \""+theme.ColorReset+"%v"+theme.ColorGray+"\""+theme.ColorYellow+ - " failed"+theme.ColorReset+"! consider installing "+theme.ColorCyan+"pari-gp"+theme.ColorReset+"\n", cmd.String()) + installed := util.CheckIfPariInstalled() + if installed != true { return } diff --git a/util/factor_with_ecm.go b/util/factor_with_ecm.go new file mode 100644 index 0000000..6eb84c3 --- /dev/null +++ b/util/factor_with_ecm.go @@ -0,0 +1,73 @@ +package util + +import ( + "bufio" + "fmt" + "math/big" + "os/exec" + "ret/theme" + "strings" +) + +func CheckIfECMInstalled() bool { + cmd := exec.Command("/usr/bin/ecm", "--help") + + err := cmd.Run() + if err != nil { + fmt.Printf("😰"+theme.ColorGray+" \""+theme.ColorReset+"%v"+theme.ColorGray+"\""+theme.ColorYellow+ + " failed"+theme.ColorReset+"! consider installing "+theme.ColorCyan+"gmp-ecm"+theme.ColorReset+"\n\n", cmd.String()) + return false + } + + return true +} + +func FactorWithECM(n *big.Int) ([]*big.Int, string, error) { + cmd := exec.Command("/usr/bin/ecm", "-c", "1000000000", "-one", "2000") + + stdin, err := cmd.StdinPipe() + if err != nil { + return nil, cmd.String(), err + } + + stdout, err := cmd.StdoutPipe() + if err != nil { + return nil, cmd.String(), err + } + + factors := make([]*big.Int, 0) + + cofactor := new(big.Int).Set(n) + + stdin.Write([]byte(fmt.Sprintf("%s\n", cofactor))) + + cmd.Start() + + scanner := bufio.NewScanner(stdout) + + for scanner.Scan() { + line := scanner.Text() + + splits := strings.Split(line, " ") + + if strings.Contains(line, "Found prime factor of ") { + factor, _ := new(big.Int).SetString(splits[len(splits)-1], 10) + factors = append(factors, factor) + continue + } + + if strings.Contains(line, "Composite cofactor") { + cofactor.SetString(splits[2], 10) + stdin.Write([]byte(fmt.Sprintf("%s\n", cofactor))) + continue + } + + if strings.Contains(line, "Prime cofactor") { + factor, _ := new(big.Int).SetString(splits[2], 10) + factors = append(factors, factor) + break + } + } + + return factors, cmd.String(), nil +} diff --git a/util/factor_with_pari.go b/util/factor_with_pari.go new file mode 100644 index 0000000..329085c --- /dev/null +++ b/util/factor_with_pari.go @@ -0,0 +1,71 @@ +package util + +import ( + "bufio" + "fmt" + "math/big" + "os" + "os/exec" + "ret/theme" + "strconv" + "strings" +) + +func CheckIfPariInstalled() bool { + cmd := exec.Command("/usr/bin/gp", "-v") + + err := cmd.Run() + if err != nil { + fmt.Printf("😰"+theme.ColorGray+" \""+theme.ColorReset+"%v"+theme.ColorGray+"\""+theme.ColorYellow+ + " failed"+theme.ColorReset+"! consider installing "+theme.ColorCyan+"pari-gp"+theme.ColorReset+"\n\n", cmd.String()) + return false + } + + return true +} + +func FactorWithPari(n *big.Int) ([]*big.Int, string, error) { + + file, err := os.CreateTemp("", "ret_rsa_factorme") + + fmt.Fprintf(file, "print(factorint(%s))\n", n) + + file.Close() + + cmd := exec.Command("/usr/bin/gp", "--stacksize", "1073741824", "--fast", "--quiet", file.Name()) + + stdout, err := cmd.StdoutPipe() + if err != nil { + return nil, cmd.String(), err + } + + factors := make([]*big.Int, 0) + + cmd.Start() + + scanner := bufio.NewScanner(stdout) + + if !scanner.Scan() { + return nil, cmd.String(), err + } + + line := scanner.Text() + splits := strings.Split(line[1:len(line)-1], ";") + + for _, split := range splits { + nums := strings.Split(split, ",") + + count, err := strconv.Atoi(strings.TrimSpace(nums[1])) + if err != nil { + return nil, cmd.String(), err + } + + factor, _ := new(big.Int).SetString(strings.TrimSpace(nums[0]), 10) + + for range count { + factors = append(factors, factor) + } + } + + return factors, cmd.String(), nil +}