github.com/consensys/gnark-crypto@v0.14.0/field/generator/generator.go (about) 1 package generator 2 3 import ( 4 "fmt" 5 "io" 6 "os" 7 "os/exec" 8 "path/filepath" 9 "strings" 10 "text/template" 11 12 "github.com/consensys/bavard" 13 "github.com/consensys/gnark-crypto/field/generator/asm/amd64" 14 "github.com/consensys/gnark-crypto/field/generator/config" 15 "github.com/consensys/gnark-crypto/field/generator/internal/addchain" 16 "github.com/consensys/gnark-crypto/field/generator/internal/templates/element" 17 ) 18 19 // GenerateFF will generate go (and .s) files in outputDir for modulus (in base 10) 20 // 21 // Example usage 22 // 23 // fp, _ = config.NewField("fp", "Element", fpModulus") 24 // generator.GenerateFF(fp, filepath.Join(baseDir, "fp")) 25 func GenerateFF(F *config.FieldConfig, outputDir string) error { 26 // source file templates 27 sourceFiles := []string{ 28 element.Base, 29 element.Reduce, 30 element.Exp, 31 element.Conv, 32 element.MulDoc, 33 element.MulCIOS, 34 element.MulNoCarry, 35 element.Sqrt, 36 element.Inverse, 37 element.BigNum, 38 } 39 40 // test file templates 41 testFiles := []string{ 42 element.MulCIOS, 43 element.MulNoCarry, 44 element.Reduce, 45 element.Test, 46 element.InverseTests, 47 } 48 // output files 49 eName := strings.ToLower(F.ElementName) 50 51 pathSrc := filepath.Join(outputDir, eName+".go") 52 pathSrcVector := filepath.Join(outputDir, "vector.go") 53 pathSrcFixedExp := filepath.Join(outputDir, eName+"_exp.go") 54 pathSrcArith := filepath.Join(outputDir, "arith.go") 55 pathTest := filepath.Join(outputDir, eName+"_test.go") 56 pathTestVector := filepath.Join(outputDir, "vector_test.go") 57 58 // remove old format generated files 59 oldFiles := []string{"_mul.go", "_mul_amd64.go", 60 "_square.go", "_square_amd64.go", "_ops_decl.go", "_square_amd64.s", 61 "_mul_amd64.s", 62 "_mul_arm64.s", 63 "_mul_arm64.go", 64 "_ops_amd64.s", 65 "_ops_noasm.go", 66 "_mul_adx_amd64.s", 67 "_ops_amd64.go", 68 "_fuzz.go", 69 } 70 71 for _, of := range oldFiles { 72 _ = os.Remove(filepath.Join(outputDir, eName+of)) 73 } 74 _ = os.Remove(filepath.Join(outputDir, "asm.go")) 75 _ = os.Remove(filepath.Join(outputDir, "asm_noadx.go")) 76 77 funcs := template.FuncMap{} 78 if F.UseAddChain { 79 for _, f := range addchain.Functions { 80 funcs[f.Name] = f.Func 81 } 82 } 83 84 funcs["shorten"] = shorten 85 funcs["ltu64"] = func(a, b uint64) bool { 86 return a < b 87 } 88 89 bavardOpts := []func(*bavard.Bavard) error{ 90 bavard.Apache2("ConsenSys Software Inc.", 2020), 91 bavard.Package(F.PackageName), 92 bavard.GeneratedBy("consensys/gnark-crypto"), 93 bavard.Funcs(funcs), 94 } 95 96 // generate source file 97 if err := bavard.GenerateFromString(pathSrc, sourceFiles, F, bavardOpts...); err != nil { 98 return err 99 } 100 101 // generate vector 102 if err := bavard.GenerateFromString(pathSrcVector, []string{element.Vector}, F, bavardOpts...); err != nil { 103 return err 104 } 105 106 // generate arithmetics source file 107 if err := bavard.GenerateFromString(pathSrcArith, []string{element.Arith}, F, bavardOpts...); err != nil { 108 return err 109 } 110 111 // generate fixed exp source file 112 if F.UseAddChain { 113 if err := bavard.GenerateFromString(pathSrcFixedExp, []string{element.FixedExp}, F, bavardOpts...); err != nil { 114 return err 115 } 116 } 117 118 // generate test file 119 if err := bavard.GenerateFromString(pathTest, testFiles, F, bavardOpts...); err != nil { 120 return err 121 } 122 123 if err := bavard.GenerateFromString(pathTestVector, []string{element.TestVector}, F, bavardOpts...); err != nil { 124 return err 125 } 126 127 // if we generate assembly code 128 if F.ASM { 129 // generate ops.s 130 { 131 pathSrc := filepath.Join(outputDir, eName+"_ops_amd64.s") 132 fmt.Println("generating", pathSrc) 133 f, err := os.Create(pathSrc) 134 if err != nil { 135 return err 136 } 137 138 _, _ = io.WriteString(f, "// +build !purego\n") 139 140 if err := amd64.Generate(f, F); err != nil { 141 _ = f.Close() 142 return err 143 } 144 _ = f.Close() 145 146 // run asmfmt 147 // run go fmt on whole directory 148 cmd := exec.Command("asmfmt", "-w", pathSrc) 149 cmd.Stdout = os.Stdout 150 cmd.Stderr = os.Stderr 151 if err := cmd.Run(); err != nil { 152 return err 153 } 154 } 155 156 { 157 pathSrc := filepath.Join(outputDir, eName+"_mul_amd64.s") 158 fmt.Println("generating", pathSrc) 159 f, err := os.Create(pathSrc) 160 if err != nil { 161 return err 162 } 163 164 _, _ = io.WriteString(f, "// +build !purego\n") 165 166 if err := amd64.GenerateMul(f, F); err != nil { 167 _ = f.Close() 168 return err 169 } 170 _ = f.Close() 171 172 // run asmfmt 173 // run go fmt on whole directory 174 cmd := exec.Command("asmfmt", "-w", pathSrc) 175 cmd.Stdout = os.Stdout 176 cmd.Stderr = os.Stderr 177 if err := cmd.Run(); err != nil { 178 return err 179 } 180 } 181 182 } 183 184 if F.ASM { 185 // generate ops_amd64.go 186 src := []string{ 187 element.MulDoc, 188 element.OpsAMD64, 189 } 190 pathSrc := filepath.Join(outputDir, eName+"_ops_amd64.go") 191 bavardOptsCpy := make([]func(*bavard.Bavard) error, len(bavardOpts)) 192 copy(bavardOptsCpy, bavardOpts) 193 if F.ASM { 194 bavardOptsCpy = append(bavardOptsCpy, bavard.BuildTag("!purego")) 195 } 196 if err := bavard.GenerateFromString(pathSrc, src, F, bavardOptsCpy...); err != nil { 197 return err 198 } 199 } 200 201 { 202 // generate ops.go 203 src := []string{ 204 element.OpsNoAsm, 205 element.MulCIOS, 206 element.MulNoCarry, 207 element.Reduce, 208 element.MulDoc, 209 } 210 pathSrc := filepath.Join(outputDir, eName+"_ops_purego.go") 211 bavardOptsCpy := make([]func(*bavard.Bavard) error, len(bavardOpts)) 212 copy(bavardOptsCpy, bavardOpts) 213 if F.ASM { 214 bavardOptsCpy = append(bavardOptsCpy, bavard.BuildTag("!amd64 purego")) 215 } 216 if err := bavard.GenerateFromString(pathSrc, src, F, bavardOptsCpy...); err != nil { 217 return err 218 } 219 } 220 221 { 222 // generate doc.go 223 src := []string{ 224 element.Doc, 225 } 226 pathSrc := filepath.Join(outputDir, "doc.go") 227 if err := bavard.GenerateFromString(pathSrc, src, F, bavardOpts...); err != nil { 228 return err 229 } 230 } 231 232 if F.ASM { 233 // generate asm.go and asm_noadx.go 234 src := []string{ 235 element.Asm, 236 } 237 pathSrc := filepath.Join(outputDir, "asm.go") 238 bavardOptsCpy := make([]func(*bavard.Bavard) error, len(bavardOpts)) 239 copy(bavardOptsCpy, bavardOpts) 240 bavardOptsCpy = append(bavardOptsCpy, bavard.BuildTag("!noadx")) 241 if err := bavard.GenerateFromString(pathSrc, src, F, bavardOptsCpy...); err != nil { 242 return err 243 } 244 } 245 if F.ASM { 246 // generate asm.go and asm_noadx.go 247 src := []string{ 248 element.AsmNoAdx, 249 } 250 pathSrc := filepath.Join(outputDir, "asm_noadx.go") 251 bavardOptsCpy := make([]func(*bavard.Bavard) error, len(bavardOpts)) 252 copy(bavardOptsCpy, bavardOpts) 253 bavardOptsCpy = append(bavardOptsCpy, bavard.BuildTag("noadx")) 254 if err := bavard.GenerateFromString(pathSrc, src, F, bavardOptsCpy...); err != nil { 255 return err 256 } 257 } 258 259 // run go fmt on whole directory 260 cmd := exec.Command("gofmt", "-s", "-w", outputDir) 261 cmd.Stdout = os.Stdout 262 cmd.Stderr = os.Stderr 263 if err := cmd.Run(); err != nil { 264 return err 265 } 266 267 return nil 268 } 269 270 func shorten(input string) string { 271 const maxLen = 15 272 if len(input) > maxLen { 273 return input[:6] + "..." + input[len(input)-6:] 274 } 275 return input 276 }