From dc952746a942c65de12c2aa075c51d3f1b6ca948 Mon Sep 17 00:00:00 2001 From: filifa Date: Wed, 10 Sep 2025 00:36:40 -0400 Subject: [PATCH] add discrete log command --- cmd/discreteLog.go | 120 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 120 insertions(+) create mode 100644 cmd/discreteLog.go diff --git a/cmd/discreteLog.go b/cmd/discreteLog.go new file mode 100644 index 0000000..b3cbab1 --- /dev/null +++ b/cmd/discreteLog.go @@ -0,0 +1,120 @@ +/* +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 discreteLogOrder string +var discreteLogGenerator string +var discreteLogElement string + +// whyyyy doesn't math/big have a ceil functionnnn +func ceilSqrt(x *big.Int) *big.Int { + z := new(big.Int).Sqrt(x) + s := new(big.Int).Exp(z, big.NewInt(2), nil) + if s.Cmp(x) != 0 { + z.Add(z, big.NewInt(1)) + } + + return z +} + +func babyStepGiantStep(n, g, x *big.Int) *big.Int { + m := ceilSqrt(n) + + table := make(map[string]*big.Int) + for j := big.NewInt(0); j.Cmp(m) == -1; j.Add(j, big.NewInt(1)) { + a := new(big.Int).Exp(g, j, n) + table[a.String()] = new(big.Int).Set(j) + } + + // p = g^-m modulo n + p := new(big.Int).Neg(m) + p.Exp(g, p, n) + + gamma := new(big.Int).Set(x) + + for i := big.NewInt(0); i.Cmp(m) == -1; i.Add(i, big.NewInt(1)) { + j, ok := table[gamma.String()] + if ok { + i.Mul(i, m) + i.Add(i, j) + return i + } + + gamma.Mul(gamma, p) + gamma.Mod(gamma, n) + } + + return nil +} + +func discreteLog(cmd *cobra.Command, args []string) { + n, ok := new(big.Int).SetString(discreteLogOrder, 10) + if !ok { + cobra.CheckErr("invalid order " + discreteLogOrder) + } + + g, ok := new(big.Int).SetString(discreteLogGenerator, 10) + if !ok { + cobra.CheckErr("invalid generator " + discreteLogGenerator) + } + + x, ok := new(big.Int).SetString(discreteLogElement, 10) + if !ok { + cobra.CheckErr("invalid element " + discreteLogElement) + } + + k := babyStepGiantStep(n, g, x) + fmt.Println(k) +} + +// discreteLogCmd represents the discreteLog command +var discreteLogCmd = &cobra.Command{ + Use: "discrete-log", + Short: "Compute the discrete logarithm", + Long: `Compute the discrete logarithm`, + Run: discreteLog, +} + +func init() { + rootCmd.AddCommand(discreteLogCmd) + + // Here you will define your flags and configuration settings. + + // Cobra supports Persistent Flags which will work for this command + // and all subcommands, e.g.: + // discreteLogCmd.PersistentFlags().String("foo", "", "A help for foo") + + // Cobra supports local flags which will only run when this command + // is called directly, e.g.: + // discreteLogCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle") + + discreteLogCmd.Flags().StringVarP(&discreteLogOrder, "order", "n", "", "order of the cyclic group") + discreteLogCmd.MarkFlagRequired("order") + + discreteLogCmd.Flags().StringVarP(&discreteLogGenerator, "generator", "g", "", "generator of the cyclic group") + discreteLogCmd.MarkFlagRequired("generator") + + discreteLogCmd.Flags().StringVarP(&discreteLogElement, "element", "e", "", "element of the cyclic group to compute logarithm of") + discreteLogCmd.MarkFlagRequired("element") +}