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  }