From 3fc375b478dff36c44f59d4b4fe90ab1b342561c Mon Sep 17 00:00:00 2001 From: Gautam Botrel Date: Thu, 10 Apr 2025 11:25:39 -0500 Subject: [PATCH 1/3] feat: make <31 bit field generated using uint32 --- field/asm/.gitignore | 3 ++- field/generator/asm/amd64/build.go | 2 +- field/generator/asm/arm64/build.go | 2 +- field/generator/config/field_config.go | 6 ++---- field/generator/internal/templates/element/ops_purego.go | 2 +- field/generator/internal/templates/element/tests.go | 2 +- 6 files changed, 8 insertions(+), 9 deletions(-) diff --git a/field/asm/.gitignore b/field/asm/.gitignore index d21c226a7..a990dce9c 100644 --- a/field/asm/.gitignore +++ b/field/asm/.gitignore @@ -2,4 +2,5 @@ element_2w/** element_3w/** element_7w/** -element_8w/** \ No newline at end of file +element_8w/** +element_6b/** \ No newline at end of file diff --git a/field/generator/asm/amd64/build.go b/field/generator/asm/amd64/build.go index 0c348a80a..1d48110d6 100644 --- a/field/generator/asm/amd64/build.go +++ b/field/generator/asm/amd64/build.go @@ -246,7 +246,7 @@ func GenerateCommonASM(w io.Writer, nbWords, nbBits int, hasVector bool) error { f.WriteLn("") if nbWords == 1 { - if nbBits == 31 { + if nbBits <= 31 { return GenerateF31ASM(f, hasVector) } else { panic("not implemented") diff --git a/field/generator/asm/arm64/build.go b/field/generator/asm/arm64/build.go index 1fb96c9f1..ad4e12ea2 100644 --- a/field/generator/asm/arm64/build.go +++ b/field/generator/asm/arm64/build.go @@ -57,7 +57,7 @@ func GenerateCommonASM(w io.Writer, nbWords, nbBits int, hasVector bool) error { f.WriteLn("") if nbWords == 1 { - if nbBits == 31 { + if nbBits <= 31 { return GenerateF31ASM(f, hasVector) } else { panic("not implemented") diff --git a/field/generator/config/field_config.go b/field/generator/config/field_config.go index a8485cb8e..20c668495 100644 --- a/field/generator/config/field_config.go +++ b/field/generator/config/field_config.go @@ -105,10 +105,8 @@ func NewFieldConfig(packageName, elementName, modulus string, useAddChain bool) } // pre compute field constants F.NbBits = bModulus.BitLen() - // note: here we set F31 only for BabyBear and KoalaBear; - // we could do uint32 bit size for all fields with NbBits <= 31, but we keep it as is for now - // to avoid breaking changes - F.F31 = F.ModulusHex == "7f000001" || F.ModulusHex == "78000001" // F.NbBits <= 31 + + F.F31 = F.NbBits <= 31 F.NbWords = len(bModulus.Bits()) F.NbWordsLastIndex = F.NbWords - 1 diff --git a/field/generator/internal/templates/element/ops_purego.go b/field/generator/internal/templates/element/ops_purego.go index 31d45c8d9..69f1c7e1b 100644 --- a/field/generator/internal/templates/element/ops_purego.go +++ b/field/generator/internal/templates/element/ops_purego.go @@ -44,7 +44,7 @@ func MulBy{{$i}}(x *{{$.ElementName}}) { // works for 0 <= n <= 32. // // N.B. n must be < 33. -func (z *Element) Mul2ExpNegN(x *Element, n uint32) *Element { +func (z *{{.ElementName}}) Mul2ExpNegN(x *{{.ElementName}}, n uint32) *{{.ElementName}} { v := uint64(x[0]) << (32 - n) z[0] = montReduce(v) return z diff --git a/field/generator/internal/templates/element/tests.go b/field/generator/internal/templates/element/tests.go index 80584e64a..5ae1771ec 100644 --- a/field/generator/internal/templates/element/tests.go +++ b/field/generator/internal/templates/element/tests.go @@ -1584,7 +1584,7 @@ func Test{{toTitle .ElementName}}Mul2ExpNegN(t *testing.T) { genA := gen() properties.Property("x * 2⁻ᵏ == Mul2ExpNegN(x, k) for 0 <= k <= 32", prop.ForAll( - func(a testPairElement) bool { + func(a testPair{{.ElementName}}) bool { var b, e, two {{.ElementName}} var c [33]{{.ElementName}} From 4bda97a4d33ef817f7aa09dc9dda43582dc435e1 Mon Sep 17 00:00:00 2001 From: Ivo Kubjas Date: Fri, 11 Apr 2025 10:15:08 +0000 Subject: [PATCH 2/3] fix: do not generate asm operations when no configuration --- field/generator/generator_field.go | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/field/generator/generator_field.go b/field/generator/generator_field.go index 9e2cd5969..bf0acb792 100644 --- a/field/generator/generator_field.go +++ b/field/generator/generator_field.go @@ -143,6 +143,7 @@ func generateField(F *config.Field, outputDir, asmDirIncludePath, hashArm64, has if F.F31 { pureGoBuildTag = "" // always generate pure go for F31 + pureGoVectorBuildTag = "" } var g errgroup.Group @@ -154,18 +155,18 @@ func generateField(F *config.Field, outputDir, asmDirIncludePath, hashArm64, has g.Go(generate("element_test.go", testFiles)) g.Go(generate("vector_test.go", []string{element.TestVector})) - g.Go(generate("element_amd64.s", []string{element.IncludeASM}, only(F.GenerateOpsAMD64), withBuildTag("!purego"), withData(amd64d))) - g.Go(generate("element_arm64.s", []string{element.IncludeASM}, only(F.GenerateOpsARM64), withBuildTag("!purego"), withData(arm64d))) + g.Go(generate("element_amd64.s", []string{element.IncludeASM}, only(F.GenerateOpsAMD64 && hashAMD64 != ""), withBuildTag("!purego"), withData(amd64d))) + g.Go(generate("element_arm64.s", []string{element.IncludeASM}, only(F.GenerateOpsARM64 && hashArm64 != ""), withBuildTag("!purego"), withData(arm64d))) - g.Go(generate("element_amd64.go", []string{element.OpsAMD64, element.MulDoc}, only(F.GenerateOpsAMD64 && !F.F31), withBuildTag("!purego"))) - g.Go(generate("element_arm64.go", []string{element.OpsARM64, element.MulNoCarry, element.Reduce}, only(F.GenerateOpsARM64 && !F.F31), withBuildTag("!purego"))) + g.Go(generate("element_amd64.go", []string{element.OpsAMD64, element.MulDoc}, only(F.GenerateOpsAMD64 && !F.F31 && hashAMD64 != ""), withBuildTag("!purego"))) + g.Go(generate("element_arm64.go", []string{element.OpsARM64, element.MulNoCarry, element.Reduce}, only(F.GenerateOpsARM64 && !F.F31 && hashArm64 != ""), withBuildTag("!purego"))) g.Go(generate("element_purego.go", []string{element.OpsNoAsm, element.MulCIOS, element.MulNoCarry, element.Reduce, element.MulDoc}, withBuildTag(pureGoBuildTag))) - g.Go(generate("vector_amd64.go", []string{element.VectorOpsAmd64}, only(F.GenerateVectorOpsAMD64 && !F.F31), withBuildTag("!purego"))) - g.Go(generate("vector_amd64.go", []string{element.VectorOpsAmd64F31}, only(F.GenerateVectorOpsAMD64 && F.F31), withBuildTag("!purego"))) - g.Go(generate("vector_arm64.go", []string{element.VectorOpsArm64}, only(F.GenerateVectorOpsARM64 && !F.F31), withBuildTag("!purego"))) - g.Go(generate("vector_arm64.go", []string{element.VectorOpsArm64F31}, only(F.GenerateVectorOpsARM64 && F.F31), withBuildTag("!purego"))) + g.Go(generate("vector_amd64.go", []string{element.VectorOpsAmd64}, only(F.GenerateVectorOpsAMD64 && !F.F31 && hashAMD64 != ""), withBuildTag("!purego"))) + g.Go(generate("vector_amd64.go", []string{element.VectorOpsAmd64F31}, only(F.GenerateVectorOpsAMD64 && F.F31 && hashAMD64 != ""), withBuildTag("!purego"))) + g.Go(generate("vector_arm64.go", []string{element.VectorOpsArm64}, only(F.GenerateVectorOpsARM64 && !F.F31 && hashArm64 != ""), withBuildTag("!purego"))) + g.Go(generate("vector_arm64.go", []string{element.VectorOpsArm64F31}, only(F.GenerateVectorOpsARM64 && F.F31 && hashArm64 != ""), withBuildTag("!purego"))) g.Go(generate("vector_purego.go", []string{element.VectorOpsPureGo}, withBuildTag(pureGoVectorBuildTag))) From ff1eb644fdcfbe1439c6abbe9908bfdf1773722c Mon Sep 17 00:00:00 2001 From: Ivo Kubjas Date: Fri, 11 Apr 2025 10:41:20 +0000 Subject: [PATCH 3/3] fix: always generate asm for small field vector unless no config --- field/generator/generator_field.go | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/field/generator/generator_field.go b/field/generator/generator_field.go index bf0acb792..b495568f1 100644 --- a/field/generator/generator_field.go +++ b/field/generator/generator_field.go @@ -128,22 +128,21 @@ func generateField(F *config.Field, outputDir, asmDirIncludePath, hashArm64, has // purego files have no build tags if we don't generate asm pureGoBuildTag := "purego || (!amd64 && !arm64)" - if !F.GenerateOpsAMD64 && !F.GenerateOpsARM64 { + if !(F.GenerateOpsAMD64 && hashAMD64 != "") && !(F.GenerateOpsARM64 && hashArm64 != "") { pureGoBuildTag = "" - } else if !F.GenerateOpsARM64 { + } else if !(F.GenerateOpsARM64 && hashArm64 != "") { pureGoBuildTag = "purego || (!amd64)" } pureGoVectorBuildTag := "purego || (!amd64 && !arm64)" - if !F.GenerateVectorOpsAMD64 && !F.GenerateVectorOpsARM64 { + if !(F.GenerateVectorOpsAMD64 && hashAMD64 != "") && !(F.GenerateVectorOpsARM64 && hashArm64 != "") { pureGoVectorBuildTag = "" - } else if !F.GenerateVectorOpsARM64 { + } else if !(F.GenerateVectorOpsARM64 && hashArm64 != "") { pureGoVectorBuildTag = "purego || (!amd64)" } if F.F31 { pureGoBuildTag = "" // always generate pure go for F31 - pureGoVectorBuildTag = "" } var g errgroup.Group