diff --git a/cmd/modSqrt.go b/cmd/modSqrt.go new file mode 100644 index 0000000..8adebc1 --- /dev/null +++ b/cmd/modSqrt.go @@ -0,0 +1,88 @@ +/* +Copyright © 2025 filifa + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . +*/ +package cmd + +import ( + "fmt" + "math/big" + + "github.com/spf13/cobra" +) + +var modSqrtQ string +var modSqrtN string + +func modSqrt(cmd *cobra.Command, args []string) { + q, ok := new(big.Int).SetString(modSqrtQ, 10) + if !ok { + cobra.CheckErr("invalid input " + modSqrtQ) + } + + n, ok := new(big.Int).SetString(modSqrtN, 10) + if !ok { + cobra.CheckErr("invalid input " + modSqrtN) + } + + // TODO: support moduli that are not odd primes + // can use Hansel's lemma for prime powers + // can use CRT for constructing answers for composite moduli + // see https://en.wikipedia.org/wiki/Quadratic_residue#Complexity_of_finding_square_roots + + rounds := 10 + z := new(big.Int).Mod(n, big.NewInt(2)) + if z.Cmp(big.NewInt(0)) == 0 || !n.ProbablyPrime(rounds) { + cobra.CheckErr(modSqrtN + " is not an odd prime") + } + + res := z.ModSqrt(q, n) + if res == nil { + cobra.CheckErr("cannot find a modular square root: " + modSqrtQ + " is not a quadratic residue modulo " + modSqrtN) + } else { + fmt.Println(z) + } +} + +// modSqrtCmd represents the modSqrt command +var modSqrtCmd = &cobra.Command{ + Use: "mod-sqrt -q Q -m M", + Short: "Compute a modular square root", + Long: `Compute a modular square root. + +Given an integer q and a modulus m, this will compute a value x such that +x^2 = q (mod n)`, + Run: modSqrt, +} + +func init() { + rootCmd.AddCommand(modSqrtCmd) + + // Here you will define your flags and configuration settings. + + // Cobra supports Persistent Flags which will work for this command + // and all subcommands, e.g.: + // modSqrtCmd.PersistentFlags().String("foo", "", "A help for foo") + + // Cobra supports local flags which will only run when this command + // is called directly, e.g.: + // modSqrtCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle") + + modSqrtCmd.Flags().StringVarP(&modSqrtQ, "residue", "q", "", "candidate to test") + modSqrtCmd.MarkFlagRequired("residue") + + modSqrtCmd.Flags().StringVarP(&modSqrtN, "modulus", "m", "", "modulus") + modSqrtCmd.MarkFlagRequired("modulus") +}