From 1576d7f4b273f7f54b5b8cc84b3222ea8029a03b Mon Sep 17 00:00:00 2001 From: Youssef El Housni Date: Tue, 18 Feb 2025 13:52:07 -0500 Subject: [PATCH 1/9] feat: koala-bear extension 4 --- field/koalabear/extensions/doc.go | 6 + field/koalabear/extensions/e2.go | 278 +++++++++++ field/koalabear/extensions/e2_amd64.go | 36 ++ field/koalabear/extensions/e2_amd64.s | 212 +++++++++ field/koalabear/extensions/e2_fallback.go | 24 + field/koalabear/extensions/e2_koalabear.go | 79 ++++ field/koalabear/extensions/e2_test.go | 508 +++++++++++++++++++++ field/koalabear/extensions/e4.go | 341 ++++++++++++++ field/koalabear/extensions/e4_test.go | 300 ++++++++++++ field/koalabear/extensions/utils.go | 48 ++ 10 files changed, 1832 insertions(+) create mode 100644 field/koalabear/extensions/doc.go create mode 100644 field/koalabear/extensions/e2.go create mode 100644 field/koalabear/extensions/e2_amd64.go create mode 100644 field/koalabear/extensions/e2_amd64.s create mode 100644 field/koalabear/extensions/e2_fallback.go create mode 100644 field/koalabear/extensions/e2_koalabear.go create mode 100644 field/koalabear/extensions/e2_test.go create mode 100644 field/koalabear/extensions/e4.go create mode 100644 field/koalabear/extensions/e4_test.go create mode 100644 field/koalabear/extensions/utils.go diff --git a/field/koalabear/extensions/doc.go b/field/koalabear/extensions/doc.go new file mode 100644 index 0000000000..12339a698f --- /dev/null +++ b/field/koalabear/extensions/doc.go @@ -0,0 +1,6 @@ +// Package extensions implements the fields arithmetic of the 𝔽p² and 𝔽p⁴ +// extensions of the Koala-bear field. +// +// 𝔽p²[u] = 𝔽r/u²-4 +// 𝔽p⁴[v] = 𝔽p²/v²-u +package extensions diff --git a/field/koalabear/extensions/e2.go b/field/koalabear/extensions/e2.go new file mode 100644 index 0000000000..5c6df7b218 --- /dev/null +++ b/field/koalabear/extensions/e2.go @@ -0,0 +1,278 @@ +package extensions + +import ( + "math/big" + + fr "github.com/consensys/gnark-crypto/field/koalabear" +) + +// E2 is a degree two finite field extension of fr.Element +type E2 struct { + A0, A1 fr.Element +} + +// Equal returns true if z equals x, false otherwise +func (z *E2) Equal(x *E2) bool { + return z.A0.Equal(&x.A0) && z.A1.Equal(&x.A1) +} + +// Cmp compares (lexicographic order) z and x and returns: +// +// -1 if z < x +// 0 if z == x +// +1 if z > x +func (z *E2) Cmp(x *E2) int { + if a1 := z.A1.Cmp(&x.A1); a1 != 0 { + return a1 + } + return z.A0.Cmp(&x.A0) +} + +// LexicographicallyLargest returns true if this element is strictly lexicographically +// larger than its negation, false otherwise +func (z *E2) LexicographicallyLargest() bool { + // adapted from github.com/zkcrypto/bls12_381 + if z.A1.IsZero() { + return z.A0.LexicographicallyLargest() + } + return z.A1.LexicographicallyLargest() +} + +// SetString sets a E2 element from strings +func (z *E2) SetString(s1, s2 string) *E2 { + z.A0.SetString(s1) + z.A1.SetString(s2) + return z +} + +// SetZero sets an E2 elmt to zero +func (z *E2) SetZero() *E2 { + z.A0.SetZero() + z.A1.SetZero() + return z +} + +// Set sets an E2 from x +func (z *E2) Set(x *E2) *E2 { + z.A0 = x.A0 + z.A1 = x.A1 + return z +} + +// SetOne sets z to 1 in Montgomery form and returns z +func (z *E2) SetOne() *E2 { + z.A0.SetOne() + z.A1.SetZero() + return z +} + +// SetRandom sets a0 and a1 to random values +func (z *E2) SetRandom() (*E2, error) { + if _, err := z.A0.SetRandom(); err != nil { + return nil, err + } + if _, err := z.A1.SetRandom(); err != nil { + return nil, err + } + return z, nil +} + +// IsZero returns true if z is zero, false otherwise +func (z *E2) IsZero() bool { + return z.A0.IsZero() && z.A1.IsZero() +} + +// IsOne returns true if z is one, false otherwise +func (z *E2) IsOne() bool { + return z.A0.IsOne() && z.A1.IsZero() +} + +// Add adds two elements of E2 +func (z *E2) Add(x, y *E2) *E2 { + z.A0.Add(&x.A0, &y.A0) + z.A1.Add(&x.A1, &y.A1) + return z +} + +// Sub subtracts two elements of E2 +func (z *E2) Sub(x, y *E2) *E2 { + z.A0.Sub(&x.A0, &y.A0) + z.A1.Sub(&x.A1, &y.A1) + return z +} + +// Double doubles an E2 element +func (z *E2) Double(x *E2) *E2 { + z.A0.Double(&x.A0) + z.A1.Double(&x.A1) + return z +} + +// Neg negates an E2 element +func (z *E2) Neg(x *E2) *E2 { + z.A0.Neg(&x.A0) + z.A1.Neg(&x.A1) + return z +} + +// String implements Stringer interface for fancy printing +func (z *E2) String() string { + return z.A0.String() + "+" + z.A1.String() + "*u" +} + +// MulByElement multiplies an element in E2 by an element in fr +func (z *E2) MulByElement(x *E2, y *fr.Element) *E2 { + var yCopy fr.Element + yCopy.Set(y) + z.A0.Mul(&x.A0, &yCopy) + z.A1.Mul(&x.A1, &yCopy) + return z +} + +// Conjugate conjugates an element in E2 +func (z *E2) Conjugate(x *E2) *E2 { + z.A0 = x.A0 + z.A1.Neg(&x.A1) + return z +} + +// Halve sets z to z / 2 +func (z *E2) Halve() { + z.A0.Halve() + z.A1.Halve() +} + +// Legendre returns the Legendre symbol of z +func (z *E2) Legendre() int { + var n fr.Element + z.norm(&n) + return n.Legendre() +} + +// Exp sets z=xᵏ (mod q²) and returns it +func (z *E2) Exp(x E2, k *big.Int) *E2 { + if k.IsUint64() && k.Uint64() == 0 { + return z.SetOne() + } + + e := k + if k.Sign() == -1 { + // negative k, we invert + // if k < 0: xᵏ (mod q²) == (x⁻¹)ᵏ (mod q²) + x.Inverse(&x) + + // we negate k in a temp big.Int since + // Int.Bit(_) of k and -k is different + e = bigIntPool.Get().(*big.Int) + defer bigIntPool.Put(e) + e.Neg(k) + } + + z.SetOne() + b := e.Bytes() + for i := 0; i < len(b); i++ { + w := b[i] + for j := 0; j < 8; j++ { + z.Square(z) + if (w & (0b10000000 >> j)) != 0 { + z.Mul(z, &x) + } + } + } + + return z +} + +// Sqrt sets z to the square root of and returns z +// The function does not test whether the square root +// exists or not, it's up to the caller to call +// Legendre beforehand. +// cf https://eprint.iacr.org/2012/685.pdf (algo 10) +func (z *E2) Sqrt(x *E2) *E2 { + + // precomputation + var b, c, d, e, f, x0 E2 + var _b, o fr.Element + + // c must be a non square (p = 1 mod 4) + c.A1.SetOne() + + q := fr.Modulus() + var exp, one big.Int + one.SetUint64(1) + exp.Set(q).Sub(&exp, &one).Rsh(&exp, 1) + d.Exp(c, &exp) + e.Mul(&d, &c).Inverse(&e) + f.Mul(&d, &c).Square(&f) + + // computation + exp.Rsh(&exp, 1) + b.Exp(*x, &exp) + b.norm(&_b) + o.SetOne() + if _b.Equal(&o) { + x0.Square(&b).Mul(&x0, x) + _b.Set(&x0.A0).Sqrt(&_b) + z.Conjugate(&b).MulByElement(z, &_b) + return z + } + x0.Square(&b).Mul(&x0, x).Mul(&x0, &f) + _b.Set(&x0.A0).Sqrt(&_b) + z.Conjugate(&b).MulByElement(z, &_b).Mul(z, &e) + + return z +} + +// BatchInvertE2 returns a new slice with every element in a inverted. +// It uses Montgomery batch inversion trick. +// +// if a[i] == 0, returns result[i] = a[i] +func BatchInvertE2(a []E2) []E2 { + res := make([]E2, len(a)) + if len(a) == 0 { + return res + } + + zeroes := make([]bool, len(a)) + var accumulator E2 + accumulator.SetOne() + + for i := 0; i < len(a); i++ { + if a[i].IsZero() { + zeroes[i] = true + continue + } + res[i].Set(&accumulator) + accumulator.Mul(&accumulator, &a[i]) + } + + accumulator.Inverse(&accumulator) + + for i := len(a) - 1; i >= 0; i-- { + if zeroes[i] { + continue + } + res[i].Mul(&res[i], &accumulator) + accumulator.Mul(&accumulator, &a[i]) + } + + return res +} + +// Select is conditional move. +// If cond = 0, it sets z to caseZ and returns it. otherwise caseNz. +func (z *E2) Select(cond int, caseZ *E2, caseNz *E2) *E2 { + //Might be able to save a nanosecond or two by an aggregate implementation + + z.A0.Select(cond, &caseZ.A0, &caseNz.A0) + z.A1.Select(cond, &caseZ.A1, &caseNz.A1) + + return z +} + +// Div divides an element in E2 by an element in E2 +func (z *E2) Div(x *E2, y *E2) *E2 { + var r E2 + r.Inverse(y).Mul(x, &r) + return z.Set(&r) +} diff --git a/field/koalabear/extensions/e2_amd64.go b/field/koalabear/extensions/e2_amd64.go new file mode 100644 index 0000000000..b0056f131c --- /dev/null +++ b/field/koalabear/extensions/e2_amd64.go @@ -0,0 +1,36 @@ +package extensions + +import ( + fr "github.com/consensys/gnark-crypto/field/koalabear" +) + +// q + r'.r = 1, i.e., qInvNeg = - q⁻¹ mod r +// used for Montgomery reduction +const qInvNeg uint64 = 725501752471715839 + +// Field modulus q (Fr) +const ( + q0 uint64 = 725501752471715841 + q1 uint64 = 6461107452199829505 + q2 uint64 = 6968279316240510977 + q3 uint64 = 1345280370688173398 +) + +var qElement = fr.Element{ + q0, + q1, + q2, + q3, +} + +//go:noescape +func addE2(res, x, y *E2) + +//go:noescape +func subE2(res, x, y *E2) + +//go:noescape +func doubleE2(res, x *E2) + +//go:noescape +func negE2(res, x *E2) diff --git a/field/koalabear/extensions/e2_amd64.s b/field/koalabear/extensions/e2_amd64.s new file mode 100644 index 0000000000..df1f55e922 --- /dev/null +++ b/field/koalabear/extensions/e2_amd64.s @@ -0,0 +1,212 @@ +#define REDUCE(ra0, ra1, ra2, ra3, rb0, rb1, rb2, rb3) \ + MOVQ ra0, rb0; \ + SUBQ ·qElement(SB), ra0; \ + MOVQ ra1, rb1; \ + SBBQ ·qElement+8(SB), ra1; \ + MOVQ ra2, rb2; \ + SBBQ ·qElement+16(SB), ra2; \ + MOVQ ra3, rb3; \ + SBBQ ·qElement+24(SB), ra3; \ + CMOVQCS rb0, ra0; \ + CMOVQCS rb1, ra1; \ + CMOVQCS rb2, ra2; \ + CMOVQCS rb3, ra3; \ + +TEXT ·addE2(SB), NOSPLIT, $0-24 + MOVQ x+8(FP), AX + MOVQ 0(AX), BX + MOVQ 8(AX), SI + MOVQ 16(AX), DI + MOVQ 24(AX), R8 + MOVQ y+16(FP), DX + ADDQ 0(DX), BX + ADCQ 8(DX), SI + ADCQ 16(DX), DI + ADCQ 24(DX), R8 + + // reduce element(BX,SI,DI,R8) using temp registers (R9,R10,R11,R12) + REDUCE(BX,SI,DI,R8,R9,R10,R11,R12) + + MOVQ res+0(FP), CX + MOVQ BX, 0(CX) + MOVQ SI, 8(CX) + MOVQ DI, 16(CX) + MOVQ R8, 24(CX) + MOVQ 32(AX), BX + MOVQ 40(AX), SI + MOVQ 48(AX), DI + MOVQ 56(AX), R8 + ADDQ 32(DX), BX + ADCQ 40(DX), SI + ADCQ 48(DX), DI + ADCQ 56(DX), R8 + + // reduce element(BX,SI,DI,R8) using temp registers (R13,R14,R15,R9) + REDUCE(BX,SI,DI,R8,R13,R14,R15,R9) + + MOVQ BX, 32(CX) + MOVQ SI, 40(CX) + MOVQ DI, 48(CX) + MOVQ R8, 56(CX) + RET + +TEXT ·doubleE2(SB), NOSPLIT, $0-16 + MOVQ res+0(FP), DX + MOVQ x+8(FP), AX + MOVQ 0(AX), CX + MOVQ 8(AX), BX + MOVQ 16(AX), SI + MOVQ 24(AX), DI + ADDQ CX, CX + ADCQ BX, BX + ADCQ SI, SI + ADCQ DI, DI + + // reduce element(CX,BX,SI,DI) using temp registers (R8,R9,R10,R11) + REDUCE(CX,BX,SI,DI,R8,R9,R10,R11) + + MOVQ CX, 0(DX) + MOVQ BX, 8(DX) + MOVQ SI, 16(DX) + MOVQ DI, 24(DX) + MOVQ 32(AX), CX + MOVQ 40(AX), BX + MOVQ 48(AX), SI + MOVQ 56(AX), DI + ADDQ CX, CX + ADCQ BX, BX + ADCQ SI, SI + ADCQ DI, DI + + // reduce element(CX,BX,SI,DI) using temp registers (R12,R13,R14,R15) + REDUCE(CX,BX,SI,DI,R12,R13,R14,R15) + + MOVQ CX, 32(DX) + MOVQ BX, 40(DX) + MOVQ SI, 48(DX) + MOVQ DI, 56(DX) + RET + +TEXT ·subE2(SB), NOSPLIT, $0-24 + XORQ DI, DI + MOVQ x+8(FP), SI + MOVQ 0(SI), AX + MOVQ 8(SI), DX + MOVQ 16(SI), CX + MOVQ 24(SI), BX + MOVQ y+16(FP), SI + SUBQ 0(SI), AX + SBBQ 8(SI), DX + SBBQ 16(SI), CX + SBBQ 24(SI), BX + MOVQ x+8(FP), SI + MOVQ $0x0a11800000000001, R8 + MOVQ $0x59aa76fed0000001, R9 + MOVQ $0x60b44d1e5c37b001, R10 + MOVQ $0x12ab655e9a2ca556, R11 + CMOVQCC DI, R8 + CMOVQCC DI, R9 + CMOVQCC DI, R10 + CMOVQCC DI, R11 + ADDQ R8, AX + ADCQ R9, DX + ADCQ R10, CX + ADCQ R11, BX + MOVQ res+0(FP), R12 + MOVQ AX, 0(R12) + MOVQ DX, 8(R12) + MOVQ CX, 16(R12) + MOVQ BX, 24(R12) + MOVQ 32(SI), AX + MOVQ 40(SI), DX + MOVQ 48(SI), CX + MOVQ 56(SI), BX + MOVQ y+16(FP), SI + SUBQ 32(SI), AX + SBBQ 40(SI), DX + SBBQ 48(SI), CX + SBBQ 56(SI), BX + MOVQ $0x0a11800000000001, R13 + MOVQ $0x59aa76fed0000001, R14 + MOVQ $0x60b44d1e5c37b001, R15 + MOVQ $0x12ab655e9a2ca556, R8 + CMOVQCC DI, R13 + CMOVQCC DI, R14 + CMOVQCC DI, R15 + CMOVQCC DI, R8 + ADDQ R13, AX + ADCQ R14, DX + ADCQ R15, CX + ADCQ R8, BX + MOVQ res+0(FP), SI + MOVQ AX, 32(SI) + MOVQ DX, 40(SI) + MOVQ CX, 48(SI) + MOVQ BX, 56(SI) + RET + +TEXT ·negE2(SB), NOSPLIT, $0-16 + MOVQ res+0(FP), DX + MOVQ x+8(FP), AX + MOVQ 0(AX), BX + MOVQ 8(AX), SI + MOVQ 16(AX), DI + MOVQ 24(AX), R8 + MOVQ BX, AX + ORQ SI, AX + ORQ DI, AX + ORQ R8, AX + TESTQ AX, AX + JNE l1 + MOVQ AX, 0(DX) + MOVQ AX, 8(DX) + MOVQ AX, 16(DX) + MOVQ AX, 24(DX) + JMP l3 + +l1: + MOVQ $0x0a11800000000001, CX + SUBQ BX, CX + MOVQ CX, 0(DX) + MOVQ $0x59aa76fed0000001, CX + SBBQ SI, CX + MOVQ CX, 8(DX) + MOVQ $0x60b44d1e5c37b001, CX + SBBQ DI, CX + MOVQ CX, 16(DX) + MOVQ $0x12ab655e9a2ca556, CX + SBBQ R8, CX + MOVQ CX, 24(DX) + +l3: + MOVQ x+8(FP), AX + MOVQ 32(AX), BX + MOVQ 40(AX), SI + MOVQ 48(AX), DI + MOVQ 56(AX), R8 + MOVQ BX, AX + ORQ SI, AX + ORQ DI, AX + ORQ R8, AX + TESTQ AX, AX + JNE l2 + MOVQ AX, 32(DX) + MOVQ AX, 40(DX) + MOVQ AX, 48(DX) + MOVQ AX, 56(DX) + RET + +l2: + MOVQ $0x0a11800000000001, CX + SUBQ BX, CX + MOVQ CX, 32(DX) + MOVQ $0x59aa76fed0000001, CX + SBBQ SI, CX + MOVQ CX, 40(DX) + MOVQ $0x60b44d1e5c37b001, CX + SBBQ DI, CX + MOVQ CX, 48(DX) + MOVQ $0x12ab655e9a2ca556, CX + SBBQ R8, CX + MOVQ CX, 56(DX) + RET diff --git a/field/koalabear/extensions/e2_fallback.go b/field/koalabear/extensions/e2_fallback.go new file mode 100644 index 0000000000..58cf038d1b --- /dev/null +++ b/field/koalabear/extensions/e2_fallback.go @@ -0,0 +1,24 @@ +//go:build !amd64 +// +build !amd64 + +package extensions + +func addE2(z, x, y *E2) { + z.A0.Add(&x.A0, &y.A0) + z.A1.Add(&x.A1, &y.A1) +} + +func subE2(z, x, y *E2) { + z.A0.Sub(&x.A0, &y.A0) + z.A1.Sub(&x.A1, &y.A1) +} + +func doubleE2(z, x *E2) { + z.A0.Double(&x.A0) + z.A1.Double(&x.A1) +} + +func negE2(z, x *E2) { + z.A0.Neg(&x.A0) + z.A1.Neg(&x.A1) +} diff --git a/field/koalabear/extensions/e2_koalabear.go b/field/koalabear/extensions/e2_koalabear.go new file mode 100644 index 0000000000..68d04c7a08 --- /dev/null +++ b/field/koalabear/extensions/e2_koalabear.go @@ -0,0 +1,79 @@ +package extensions + +import ( + fr "github.com/consensys/gnark-crypto/field/koalabear" +) + +// Mul sets z to the E2-product of x,y, returns z +func (z *E2) Mul(x, y *E2) *E2 { + var a, b, c fr.Element + a.Add(&x.A0, &x.A1) + b.Add(&y.A0, &y.A1) + a.Mul(&a, &b) + b.Mul(&x.A0, &y.A0) + c.Mul(&x.A1, &y.A1) + z.A1.Sub(&a, &b).Sub(&z.A1, &c) + fr.MulBy3(&c) + z.A0.Add(&b, &c) + return z +} + +// Square sets z to the E2-product of x,x returns z +func (z *E2) Square(x *E2) *E2 { + var a, b, c fr.Element + a.Mul(&x.A0, &x.A1).Double(&a) + c.Square(&x.A0) + b.Square(&x.A1) + fr.MulBy3(&b) + z.A0.Add(&c, &b) + z.A1 = a + return z +} + +// MulByNonResidue multiplies a E2 by (0,1) +func (z *E2) MulByNonResidue(x *E2) *E2 { + a := x.A0 + b := x.A1 // fetching x.A1 in the function below is slower + fr.MulBy3(&b) + z.A0 = b + z.A1 = a + return z +} + +// MulByNonResidueInv multiplies a E2 by (0,1)^{-1} +func (z *E2) MulByNonResidueInv(x *E2) *E2 { + a := x.A1 + // 1/3 mod r + var threeInv fr.Element + threeInv.SetUint64(710235478) + z.A1.Mul(&x.A0, &threeInv) + z.A0 = a + return z +} + +// Inverse sets z to the E2-inverse of x, returns z +func (z *E2) Inverse(x *E2) *E2 { + // Algorithm 8 from https://eprint.iacr.org/2010/354.pdf + var t0, t1, tmp fr.Element + a := &x.A0 // creating the buffers a, b is faster than querying &x.A0, &x.A1 in the functions call below + b := &x.A1 + t0.Square(a) + t1.Square(b) + tmp.Set(&t1) + fr.MulBy3(&tmp) + t0.Sub(&t0, &tmp) + t1.Inverse(&t0) + z.A0.Mul(a, &t1) + z.A1.Mul(b, &t1).Neg(&z.A1) + + return z +} + +// norm sets x to the norm of z +func (z *E2) norm(x *fr.Element) { + var tmp fr.Element + x.Square(&z.A1) + tmp.Set(x) + fr.MulBy3(&tmp) + x.Square(&z.A0).Sub(x, &tmp) +} diff --git a/field/koalabear/extensions/e2_test.go b/field/koalabear/extensions/e2_test.go new file mode 100644 index 0000000000..597b115fbd --- /dev/null +++ b/field/koalabear/extensions/e2_test.go @@ -0,0 +1,508 @@ +package extensions + +import ( + "crypto/rand" + "testing" + + fr "github.com/consensys/gnark-crypto/field/koalabear" + "github.com/leanovate/gopter" + "github.com/leanovate/gopter/prop" +) + +// ------------------------------------------------------------ +// tests + +const ( + nbFuzzShort = 10 + nbFuzz = 50 +) + +func TestE2ReceiverIsOperand(t *testing.T) { + + t.Parallel() + parameters := gopter.DefaultTestParameters() + if testing.Short() { + parameters.MinSuccessfulTests = nbFuzzShort + } else { + parameters.MinSuccessfulTests = nbFuzz + } + + properties := gopter.NewProperties(parameters) + + genA := GenE2() + genB := GenE2() + genfr := GenFr() + + properties.Property("[KOALABEAR] Having the receiver as operand (addition) should output the same result", prop.ForAll( + func(a, b *E2) bool { + var c, d E2 + d.Set(a) + c.Add(a, b) + a.Add(a, b) + b.Add(&d, b) + return a.Equal(b) && a.Equal(&c) && b.Equal(&c) + }, + genA, + genB, + )) + + properties.Property("[KOALABEAR] Having the receiver as operand (sub) should output the same result", prop.ForAll( + func(a, b *E2) bool { + var c, d E2 + d.Set(a) + c.Sub(a, b) + a.Sub(a, b) + b.Sub(&d, b) + return a.Equal(b) && a.Equal(&c) && b.Equal(&c) + }, + genA, + genB, + )) + + properties.Property("[KOALABEAR] Having the receiver as operand (mul) should output the same result", prop.ForAll( + func(a, b *E2) bool { + var c, d E2 + d.Set(a) + c.Mul(a, b) + a.Mul(a, b) + b.Mul(&d, b) + return a.Equal(b) && a.Equal(&c) && b.Equal(&c) + }, + genA, + genB, + )) + + properties.Property("[KOALABEAR] Having the receiver as operand (square) should output the same result", prop.ForAll( + func(a *E2) bool { + var b E2 + b.Square(a) + a.Square(a) + return a.Equal(&b) + }, + genA, + )) + + properties.Property("[KOALABEAR] Having the receiver as operand (neg) should output the same result", prop.ForAll( + func(a *E2) bool { + var b E2 + b.Neg(a) + a.Neg(a) + return a.Equal(&b) + }, + genA, + )) + + properties.Property("[KOALABEAR] Having the receiver as operand (double) should output the same result", prop.ForAll( + func(a *E2) bool { + var b E2 + b.Double(a) + a.Double(a) + return a.Equal(&b) + }, + genA, + )) + + properties.Property("[KOALABEAR] Having the receiver as operand (mul by non residue) should output the same result", prop.ForAll( + func(a *E2) bool { + var b E2 + b.MulByNonResidue(a) + a.MulByNonResidue(a) + return a.Equal(&b) + }, + genA, + )) + + properties.Property("[KOALABEAR] Having the receiver as operand (mul by non residue inverse) should output the same result", prop.ForAll( + func(a *E2) bool { + var b E2 + b.MulByNonResidueInv(a) + a.MulByNonResidueInv(a) + return a.Equal(&b) + }, + genA, + )) + + properties.Property("[KOALABEAR] Having the receiver as operand (Inverse) should output the same result", prop.ForAll( + func(a *E2) bool { + var b E2 + b.Inverse(a) + a.Inverse(a) + return a.Equal(&b) + }, + genA, + )) + + properties.Property("[KOALABEAR] Having the receiver as operand (Conjugate) should output the same result", prop.ForAll( + func(a *E2) bool { + var b E2 + b.Conjugate(a) + a.Conjugate(a) + return a.Equal(&b) + }, + genA, + )) + + properties.Property("[KOALABEAR] Having the receiver as operand (mul by element) should output the same result", prop.ForAll( + func(a *E2, b fr.Element) bool { + var c E2 + c.MulByElement(a, &b) + a.MulByElement(a, &b) + return a.Equal(&c) + }, + genA, + genfr, + )) + + properties.Property("[KOALABEAR] Having the receiver as operand (Sqrt) should output the same result", prop.ForAll( + func(a *E2) bool { + var b, c, d, s E2 + + s.Square(a) + a.Set(&s) + b.Set(&s) + + a.Sqrt(a) + b.Sqrt(&b) + + c.Square(a) + d.Square(&b) + return c.Equal(&d) + }, + genA, + )) + + properties.TestingRun(t, gopter.ConsoleReporter(false)) + +} + +func TestE2MulMaxed(t *testing.T) { + // let's pick a and b, with maxed A0 and A1 + var a, b E2 + frMaxValue := fr.Element{2130706432} + frMaxValue[0]-- + + a.A0 = frMaxValue + a.A1 = frMaxValue + b.A0 = frMaxValue + b.A1 = frMaxValue + + var c, d E2 + d.Inverse(&b) + c.Set(&a) + c.Mul(&c, &b).Mul(&c, &d) + if !c.Equal(&a) { + t.Fatal("mul with max fr failed") + } +} + +func TestE2Ops(t *testing.T) { + + t.Parallel() + parameters := gopter.DefaultTestParameters() + if testing.Short() { + parameters.MinSuccessfulTests = nbFuzzShort + } else { + parameters.MinSuccessfulTests = nbFuzz + } + + properties := gopter.NewProperties(parameters) + + genA := GenE2() + genB := GenE2() + genfr := GenFr() + + properties.Property("[KOALABEAR] sub & add should leave an element invariant", prop.ForAll( + func(a, b *E2) bool { + var c E2 + c.Set(a) + c.Add(&c, b).Sub(&c, b) + return c.Equal(a) + }, + genA, + genB, + )) + + properties.Property("[KOALABEAR] mul & inverse should leave an element invariant", prop.ForAll( + func(a, b *E2) bool { + var c, d E2 + d.Inverse(b) + c.Set(a) + c.Mul(&c, b).Mul(&c, &d) + return c.Equal(a) + }, + genA, + genB, + )) + + properties.Property("[KOALABEAR] BatchInvertE2 should output the same result as Inverse", prop.ForAll( + func(a, b, c *E2) bool { + + batch := BatchInvertE2([]E2{*a, *b, *c}) + a.Inverse(a) + b.Inverse(b) + c.Inverse(c) + return a.Equal(&batch[0]) && b.Equal(&batch[1]) && c.Equal(&batch[2]) + }, + genA, + genA, + genA, + )) + + properties.Property("[KOALABEAR] inverse twice should leave an element invariant", prop.ForAll( + func(a *E2) bool { + var b E2 + b.Inverse(a).Inverse(&b) + return a.Equal(&b) + }, + genA, + )) + + properties.Property("[KOALABEAR] neg twice should leave an element invariant", prop.ForAll( + func(a *E2) bool { + var b E2 + b.Neg(a).Neg(&b) + return a.Equal(&b) + }, + genA, + )) + + properties.Property("[KOALABEAR] square and mul should output the same result", prop.ForAll( + func(a *E2) bool { + var b, c E2 + b.Mul(a, a) + c.Square(a) + return b.Equal(&c) + }, + genA, + )) + + properties.Property("[KOALABEAR] MulByElement MulByElement inverse should leave an element invariant", prop.ForAll( + func(a *E2, b fr.Element) bool { + var c E2 + var d fr.Element + d.Inverse(&b) + c.MulByElement(a, &b).MulByElement(&c, &d) + return c.Equal(a) + }, + genA, + genfr, + )) + + properties.Property("[KOALABEAR] Double and mul by 2 should output the same result", prop.ForAll( + func(a *E2) bool { + var b E2 + var c fr.Element + c.SetUint64(2) + b.Double(a) + a.MulByElement(a, &c) + return a.Equal(&b) + }, + genA, + )) + + properties.Property("[KOALABEAR] Mulbynonres mulbynonresinv should leave the element invariant", prop.ForAll( + func(a *E2) bool { + var b E2 + b.MulByNonResidue(a).MulByNonResidueInv(&b) + return a.Equal(&b) + }, + genA, + )) + + properties.Property("[KOALABEAR] a + pi(a), a-pi(a) should be real", prop.ForAll( + func(a *E2) bool { + var b, c, d E2 + var e, f fr.Element + b.Conjugate(a) + c.Add(a, &b) + d.Sub(a, &b) + e.Double(&a.A0) + f.Double(&a.A1) + return c.A1.IsZero() && d.A0.IsZero() && e.Equal(&c.A0) && f.Equal(&d.A1) + }, + genA, + )) + + properties.Property("[KOALABEAR] Legendre on square should output 1", prop.ForAll( + func(a *E2) bool { + var b E2 + b.Square(a) + c := b.Legendre() + return c == 1 + }, + genA, + )) + + properties.Property("[KOALABEAR] square(sqrt) should leave an element invariant", prop.ForAll( + func(a *E2) bool { + var b, c, d, e E2 + b.Square(a) + c.Sqrt(&b) + d.Square(&c) + e.Neg(a) + return (c.Equal(a) || c.Equal(&e)) && d.Equal(&b) + }, + genA, + )) + + properties.Property("[KOALABEAR] neg(E2) == neg(E2.A0, E2.A1)", prop.ForAll( + func(a *E2) bool { + var b, c E2 + b.Neg(a) + c.A0.Neg(&a.A0) + c.A1.Neg(&a.A1) + return c.Equal(&b) + }, + genA, + )) + + properties.Property("[KOALABEAR] Cmp and LexicographicallyLargest should be consistent", prop.ForAll( + func(a *E2) bool { + var negA E2 + negA.Neg(a) + cmpResult := a.Cmp(&negA) + lResult := a.LexicographicallyLargest() + if lResult && cmpResult == 1 { + return true + } + if !lResult && cmpResult != 1 { + return true + } + return false + }, + genA, + )) + + properties.TestingRun(t, gopter.ConsoleReporter(false)) + +} + +// ------------------------------------------------------------ +// benches + +func BenchmarkE2Add(b *testing.B) { + var a, c E2 + _, _ = a.SetRandom() + _, _ = c.SetRandom() + b.ResetTimer() + for i := 0; i < b.N; i++ { + a.Add(&a, &c) + } +} + +func BenchmarkE2Sub(b *testing.B) { + var a, c E2 + _, _ = a.SetRandom() + _, _ = c.SetRandom() + b.ResetTimer() + for i := 0; i < b.N; i++ { + a.Sub(&a, &c) + } +} + +func BenchmarkE2Mul(b *testing.B) { + var a, c E2 + _, _ = a.SetRandom() + _, _ = c.SetRandom() + b.ResetTimer() + for i := 0; i < b.N; i++ { + a.Mul(&a, &c) + } +} + +func BenchmarkE2MulByElement(b *testing.B) { + var a E2 + var c fr.Element + _, _ = c.SetRandom() + _, _ = a.SetRandom() + b.ResetTimer() + for i := 0; i < b.N; i++ { + a.MulByElement(&a, &c) + } +} + +func BenchmarkE2Square(b *testing.B) { + var a E2 + _, _ = a.SetRandom() + b.ResetTimer() + for i := 0; i < b.N; i++ { + a.Square(&a) + } +} + +func BenchmarkE2Sqrt(b *testing.B) { + var a E2 + _, _ = a.SetRandom() + b.ResetTimer() + for i := 0; i < b.N; i++ { + a.Sqrt(&a) + } +} + +func BenchmarkE2Exp(b *testing.B) { + var x E2 + _, _ = x.SetRandom() + b1, _ := rand.Int(rand.Reader, fr.Modulus()) + b.ResetTimer() + for i := 0; i < b.N; i++ { + x.Exp(x, b1) + } +} + +func BenchmarkE2Inverse(b *testing.B) { + var a E2 + _, _ = a.SetRandom() + b.ResetTimer() + for i := 0; i < b.N; i++ { + a.Inverse(&a) + } +} + +func BenchmarkE2MulNonRes(b *testing.B) { + var a E2 + _, _ = a.SetRandom() + b.ResetTimer() + for i := 0; i < b.N; i++ { + a.MulByNonResidue(&a) + } +} + +func BenchmarkE2MulNonResInv(b *testing.B) { + var a E2 + _, _ = a.SetRandom() + b.ResetTimer() + for i := 0; i < b.N; i++ { + a.MulByNonResidueInv(&a) + } +} + +func BenchmarkE2Conjugate(b *testing.B) { + var a E2 + _, _ = a.SetRandom() + b.ResetTimer() + for i := 0; i < b.N; i++ { + a.Conjugate(&a) + } +} + +func TestE2Div(t *testing.T) { + + parameters := gopter.DefaultTestParameters() + properties := gopter.NewProperties(parameters) + + genA := GenE2() + genB := GenE2() + + properties.Property("[KOALABEAR] dividing then multiplying by the same element does nothing", prop.ForAll( + func(a, b *E2) bool { + var c E2 + c.Div(a, b) + c.Mul(&c, b) + return c.Equal(a) + }, + genA, + genB, + )) + + properties.TestingRun(t, gopter.ConsoleReporter(false)) +} diff --git a/field/koalabear/extensions/e4.go b/field/koalabear/extensions/e4.go new file mode 100644 index 0000000000..c6fd21bd09 --- /dev/null +++ b/field/koalabear/extensions/e4.go @@ -0,0 +1,341 @@ +package extensions + +import ( + "math/big" + + fr "github.com/consensys/gnark-crypto/field/koalabear" +) + +// E4 is a degree two finite field extension of fr2 +type E4 struct { + B0, B1 E2 +} + +// Equal returns true if z equals x, false otherwise +func (z *E4) Equal(x *E4) bool { + return z.B0.Equal(&x.B0) && z.B1.Equal(&x.B1) +} + +// Cmp compares (lexicographic order) z and x and returns: +// +// -1 if z < x +// 0 if z == x +// +1 if z > x +func (z *E4) Cmp(x *E4) int { + if a1 := z.B1.Cmp(&x.B1); a1 != 0 { + return a1 + } + return z.B0.Cmp(&x.B0) +} + +// LexicographicallyLargest returns true if this element is strictly lexicographically +// larger than its negation, false otherwise +func (z *E4) LexicographicallyLargest() bool { + // adapted from github.com/zkcrypto/bls12_381 + if z.B1.IsZero() { + return z.B0.LexicographicallyLargest() + } + return z.B1.LexicographicallyLargest() +} + +// String puts E4 in string form +func (z *E4) String() string { + return (z.B0.String() + "+(" + z.B1.String() + ")*v") +} + +// SetString sets a E4 from string +func (z *E4) SetString(s0, s1, s2, s3 string) *E4 { + z.B0.SetString(s0, s1) + z.B1.SetString(s2, s3) + return z +} + +// Set copies x into z and returns z +func (z *E4) Set(x *E4) *E4 { + z.B0 = x.B0 + z.B1 = x.B1 + return z +} + +// SetZero sets an E4 elmt to zero +func (z *E4) SetZero() *E4 { + z.B0.SetZero() + z.B1.SetZero() + return z +} + +// SetOne sets z to 1 in Montgomery form and returns z +func (z *E4) SetOne() *E4 { + *z = E4{} + z.B0.A0.SetOne() + return z +} + +// MulByElement multiplies an element in E4 by an element in fr +func (z *E4) MulByElement(x *E4, y *fr.Element) *E4 { + var yCopy fr.Element + yCopy.Set(y) + z.B0.MulByElement(&x.B0, &yCopy) + z.B1.MulByElement(&x.B1, &yCopy) + return z +} + +// MulByE2 multiplies an element in E4 by an element in E2 +func (z *E4) MulByE2(x *E4, y *E2) *E4 { + var yCopy E2 + yCopy.Set(y) + z.B0.Mul(&x.B0, &yCopy) + z.B1.Mul(&x.B1, &yCopy) + return z +} + +// Add sets z=x+y in E4 and returns z +func (z *E4) Add(x, y *E4) *E4 { + z.B0.Add(&x.B0, &y.B0) + z.B1.Add(&x.B1, &y.B1) + return z +} + +// Sub sets z to x-y and returns z +func (z *E4) Sub(x, y *E4) *E4 { + z.B0.Sub(&x.B0, &y.B0) + z.B1.Sub(&x.B1, &y.B1) + return z +} + +// Double sets z=2*x and returns z +func (z *E4) Double(x *E4) *E4 { + z.B0.Double(&x.B0) + z.B1.Double(&x.B1) + return z +} + +// Neg negates an E4 element +func (z *E4) Neg(x *E4) *E4 { + z.B0.Neg(&x.B0) + z.B1.Neg(&x.B1) + return z +} + +// SetRandom used only in tests +func (z *E4) SetRandom() (*E4, error) { + if _, err := z.B0.SetRandom(); err != nil { + return nil, err + } + if _, err := z.B1.SetRandom(); err != nil { + return nil, err + } + return z, nil +} + +// IsZero returns true if z is zero, false otherwise +func (z *E4) IsZero() bool { + return z.B0.IsZero() && z.B1.IsZero() +} + +// IsOne returns true if z is one, false otherwise +func (z *E4) IsOne() bool { + return z.B0.IsOne() && z.B1.IsZero() +} + +// MulByNonResidue mul x by (0,1) +func (z *E4) MulByNonResidue(x *E4) *E4 { + z.B1, z.B0 = x.B0, x.B1 + z.B0.MulByNonResidue(&z.B0) + return z +} + +// Mul sets z=x*y in E4 and returns z +func (z *E4) Mul(x, y *E4) *E4 { + var a, b, c E2 + a.Add(&x.B0, &x.B1) + b.Add(&y.B0, &y.B1) + a.Mul(&a, &b) + b.Mul(&x.B0, &y.B0) + c.Mul(&x.B1, &y.B1) + z.B1.Sub(&a, &b).Sub(&z.B1, &c) + z.B0.MulByNonResidue(&c).Add(&z.B0, &b) + return z +} + +// Square sets z=x*x in E4 and returns z +func (z *E4) Square(x *E4) *E4 { + + //Algorithm 22 from https://eprint.iacr.org/2010/354.pdf + var c0, c2, c3 E2 + c0.Sub(&x.B0, &x.B1) + c3.MulByNonResidue(&x.B1).Sub(&x.B0, &c3) + c2.Mul(&x.B0, &x.B1) + c0.Mul(&c0, &c3).Add(&c0, &c2) + z.B1.Double(&c2) + c2.MulByNonResidue(&c2) + z.B0.Add(&c0, &c2) + + return z +} + +// Inverse sets z to the inverse of x in E4 and returns z +// +// if x == 0, sets and returns z = x +func (z *E4) Inverse(x *E4) *E4 { + // Algorithm 23 from https://eprint.iacr.org/2010/354.pdf + + var t0, t1, tmp E2 + t0.Square(&x.B0) + t1.Square(&x.B1) + tmp.MulByNonResidue(&t1) + t0.Sub(&t0, &tmp) + t1.Inverse(&t0) + z.B0.Mul(&x.B0, &t1) + z.B1.Mul(&x.B1, &t1).Neg(&z.B1) + + return z +} + +// Exp sets z=xᵏ (mod q⁴) and returns it +func (z *E4) Exp(x E4, k *big.Int) *E4 { + if k.IsUint64() && k.Uint64() == 0 { + return z.SetOne() + } + + e := k + if k.Sign() == -1 { + // negative k, we invert + // if k < 0: xᵏ (mod q⁴) == (x⁻¹)ᵏ (mod q⁴) + x.Inverse(&x) + + // we negate k in a temp big.Int since + // Int.Bit(_) of k and -k is different + e = bigIntPool.Get().(*big.Int) + defer bigIntPool.Put(e) + e.Neg(k) + } + + z.SetOne() + b := e.Bytes() + for i := 0; i < len(b); i++ { + w := b[i] + for j := 0; j < 8; j++ { + z.Square(z) + if (w & (0b10000000 >> j)) != 0 { + z.Mul(z, &x) + } + } + } + + return z +} + +// Conjugate sets z to x conjugated and returns z +func (z *E4) Conjugate(x *E4) *E4 { + z.B0 = x.B0 + z.B1.Neg(&x.B1) + return z +} + +func (z *E4) Halve() { + + z.B0.A0.Halve() + z.B0.A1.Halve() + z.B1.A0.Halve() + z.B1.A1.Halve() +} + +// norm sets x to the norm of z +func (z *E4) norm(x *E2) { + var tmp E2 + tmp.Square(&z.B1).MulByNonResidue(&tmp) + x.Square(&z.B0).Sub(x, &tmp) +} + +// Legendre returns the Legendre symbol of z +func (z *E4) Legendre() int { + var n E2 + z.norm(&n) + return n.Legendre() +} + +// Sqrt sets z to the square root of and returns z +// The function does not test whether the square root +// exists or not, it's up to the caller to call +// Legendre beforehand. +// cf https://eprint.iacr.org/2012/685.pdf (algo 10) +func (z *E4) Sqrt(x *E4) *E4 { + + // precomputation + var b, c, d, e, f, x0, _g E4 + var _b, o E2 + + // c must be a non square (p = 1 mod 4) + c.B1.SetOne() + + q := fr.Modulus() + var exp, one big.Int + one.SetUint64(1) + exp.Mul(q, q).Sub(&exp, &one).Rsh(&exp, 1) + d.Exp(c, &exp) + e.Mul(&d, &c).Inverse(&e) + f.Mul(&d, &c).Square(&f) + + // computation + exp.Rsh(&exp, 1) + b.Exp(*x, &exp) + b.norm(&_b) + o.SetOne() + if _b.Equal(&o) { + x0.Square(&b).Mul(&x0, x) + _b.Set(&x0.B0).Sqrt(&_b) + _g.B0.Set(&_b) + z.Conjugate(&b).Mul(z, &_g) + return z + } + x0.Square(&b).Mul(&x0, x).Mul(&x0, &f) + _b.Set(&x0.B0).Sqrt(&_b) + _g.B0.Set(&_b) + z.Conjugate(&b).Mul(z, &_g).Mul(z, &e) + + return z +} + +// BatchInvertE4 returns a new slice with every element in a inverted. +// It uses Montgomery batch inversion trick. +// +// if a[i] == 0, returns result[i] = a[i] +func BatchInvertE4(a []E4) []E4 { + res := make([]E4, len(a)) + if len(a) == 0 { + return res + } + + zeroes := make([]bool, len(a)) + var accumulator E4 + accumulator.SetOne() + + for i := 0; i < len(a); i++ { + if a[i].IsZero() { + zeroes[i] = true + continue + } + res[i].Set(&accumulator) + accumulator.Mul(&accumulator, &a[i]) + } + + accumulator.Inverse(&accumulator) + + for i := len(a) - 1; i >= 0; i-- { + if zeroes[i] { + continue + } + res[i].Mul(&res[i], &accumulator) + accumulator.Mul(&accumulator, &a[i]) + } + + return res +} + +// Div divides an element in E4 by an element in E4 +func (z *E4) Div(x *E4, y *E4) *E4 { + var r E4 + r.Inverse(y).Mul(x, &r) + return z.Set(&r) +} diff --git a/field/koalabear/extensions/e4_test.go b/field/koalabear/extensions/e4_test.go new file mode 100644 index 0000000000..96f80cc099 --- /dev/null +++ b/field/koalabear/extensions/e4_test.go @@ -0,0 +1,300 @@ +package extensions + +import ( + "testing" + + "github.com/leanovate/gopter" + "github.com/leanovate/gopter/prop" +) + +// ------------------------------------------------------------ +// tests + +func TestE4ReceiverIsOperand(t *testing.T) { + + parameters := gopter.DefaultTestParameters() + parameters.MinSuccessfulTests = 100 + + properties := gopter.NewProperties(parameters) + + genA := GenE4() + genB := GenE4() + + properties.Property("[KOALABEAR] Having the receiver as operand (addition) should output the same result", prop.ForAll( + func(a, b *E4) bool { + var c, d E4 + d.Set(a) + c.Add(a, b) + a.Add(a, b) + b.Add(&d, b) + return a.Equal(b) && a.Equal(&c) && b.Equal(&c) + }, + genA, + genB, + )) + + properties.Property("[KOALABEAR] Having the receiver as operand (sub) should output the same result", prop.ForAll( + func(a, b *E4) bool { + var c, d E4 + d.Set(a) + c.Sub(a, b) + a.Sub(a, b) + b.Sub(&d, b) + return a.Equal(b) && a.Equal(&c) && b.Equal(&c) + }, + genA, + genB, + )) + + properties.Property("[KOALABEAR] Having the receiver as operand (mul) should output the same result", prop.ForAll( + func(a, b *E4) bool { + var c, d E4 + d.Set(a) + c.Mul(a, b) + a.Mul(a, b) + b.Mul(&d, b) + return a.Equal(b) && a.Equal(&c) && b.Equal(&c) + }, + genA, + genB, + )) + + properties.Property("[KOALABEAR] Having the receiver as operand (square) should output the same result", prop.ForAll( + func(a *E4) bool { + var b E4 + b.Square(a) + a.Square(a) + return a.Equal(&b) + }, + genA, + )) + + properties.Property("[KOALABEAR] Having the receiver as operand (double) should output the same result", prop.ForAll( + func(a *E4) bool { + var b E4 + b.Double(a) + a.Double(a) + return a.Equal(&b) + }, + genA, + )) + + properties.Property("[KOALABEAR] Having the receiver as operand (mul by non residue) should output the same result", prop.ForAll( + func(a *E4) bool { + var b E4 + b.MulByNonResidue(a) + a.MulByNonResidue(a) + return a.Equal(&b) + }, + genA, + )) + + properties.Property("[KOALABEAR] Having the receiver as operand (Inverse) should output the same result", prop.ForAll( + func(a *E4) bool { + var b E4 + b.Inverse(a) + a.Inverse(a) + return a.Equal(&b) + }, + genA, + )) + + properties.Property("[KOALABEAR] Having the receiver as operand (Conjugate) should output the same result", prop.ForAll( + func(a *E4) bool { + var b E4 + b.Conjugate(a) + a.Conjugate(a) + return a.Equal(&b) + }, + genA, + )) + + properties.Property("[KOALABEAR] Having the receiver as operand (Sqrt) should output the same result", prop.ForAll( + func(a *E4) bool { + var b, c, d, s E4 + + s.Square(a) + a.Set(&s) + b.Set(&s) + + a.Sqrt(a) + b.Sqrt(&b) + + c.Square(a) + d.Square(&b) + return c.Equal(&d) + }, + genA, + )) + + properties.TestingRun(t, gopter.ConsoleReporter(false)) +} + +func TestE4Ops(t *testing.T) { + + parameters := gopter.DefaultTestParameters() + parameters.MinSuccessfulTests = 100 + + properties := gopter.NewProperties(parameters) + + genA := GenE4() + genB := GenE4() + + properties.Property("[KOALABEAR] sub & add should leave an element invariant", prop.ForAll( + func(a, b *E4) bool { + var c E4 + c.Set(a) + c.Add(&c, b).Sub(&c, b) + return c.Equal(a) + }, + genA, + genB, + )) + + properties.Property("[KOALABEAR] mul & inverse should leave an element invariant", prop.ForAll( + func(a, b *E4) bool { + var c, d E4 + d.Inverse(b) + c.Set(a) + c.Mul(&c, b).Mul(&c, &d) + return c.Equal(a) + }, + genA, + genB, + )) + + properties.Property("[KOALABEAR] BatchInvertE4 should output the same result as Inverse", prop.ForAll( + func(a, b, c *E4) bool { + + batch := BatchInvertE4([]E4{*a, *b, *c}) + a.Inverse(a) + b.Inverse(b) + c.Inverse(c) + return a.Equal(&batch[0]) && b.Equal(&batch[1]) && c.Equal(&batch[2]) + }, + genA, + genA, + genB, + )) + + properties.Property("[KOALABEAR] inverse twice should leave an element invariant", prop.ForAll( + func(a *E4) bool { + var b E4 + b.Inverse(a).Inverse(&b) + return a.Equal(&b) + }, + genA, + )) + + properties.Property("[KOALABEAR] square and mul should output the same result", prop.ForAll( + func(a *E4) bool { + var b, c E4 + b.Mul(a, a) + c.Square(a) + return b.Equal(&c) + }, + genA, + )) + + properties.Property("[KOALABEAR] Legendre on square should output 1", prop.ForAll( + func(a *E4) bool { + var b E4 + b.Square(a) + c := b.Legendre() + return c == 1 + }, + genA, + )) + + properties.Property("[KOALABEAR] square(sqrt) should leave an element invariant", prop.ForAll( + func(a *E4) bool { + var b, c, d, e E4 + b.Square(a) + c.Sqrt(&b) + d.Square(&c) + e.Neg(a) + return (c.Equal(a) || c.Equal(&e)) && d.Equal(&b) + }, + genA, + )) + + properties.TestingRun(t, gopter.ConsoleReporter(false)) +} + +// ------------------------------------------------------------ +// benches + +func BenchmarkE4Add(b *testing.B) { + var a, c E4 + _, _ = a.SetRandom() + _, _ = c.SetRandom() + b.ResetTimer() + for i := 0; i < b.N; i++ { + a.Add(&a, &c) + } +} + +func BenchmarkE4Sub(b *testing.B) { + var a, c E4 + _, _ = a.SetRandom() + _, _ = c.SetRandom() + b.ResetTimer() + for i := 0; i < b.N; i++ { + a.Sub(&a, &c) + } +} + +func BenchmarkE4Mul(b *testing.B) { + var a, c E4 + _, _ = a.SetRandom() + _, _ = c.SetRandom() + b.ResetTimer() + for i := 0; i < b.N; i++ { + a.Mul(&a, &c) + } +} + +func BenchmarkE4Square(b *testing.B) { + var a E4 + _, _ = a.SetRandom() + b.ResetTimer() + for i := 0; i < b.N; i++ { + a.Square(&a) + } +} + +func BenchmarkE4Sqrt(b *testing.B) { + var a E4 + _, _ = a.SetRandom() + b.ResetTimer() + for i := 0; i < b.N; i++ { + a.Sqrt(&a) + } +} + +func BenchmarkE4Inverse(b *testing.B) { + var a E4 + _, _ = a.SetRandom() + b.ResetTimer() + for i := 0; i < b.N; i++ { + a.Inverse(&a) + } +} + +func BenchmarkE4MulNonRes(b *testing.B) { + var a E4 + _, _ = a.SetRandom() + b.ResetTimer() + for i := 0; i < b.N; i++ { + a.MulByNonResidue(&a) + } +} + +func BenchmarkE4Conjugate(b *testing.B) { + var a E4 + _, _ = a.SetRandom() + b.ResetTimer() + for i := 0; i < b.N; i++ { + a.Conjugate(&a) + } +} diff --git a/field/koalabear/extensions/utils.go b/field/koalabear/extensions/utils.go new file mode 100644 index 0000000000..998332f1e1 --- /dev/null +++ b/field/koalabear/extensions/utils.go @@ -0,0 +1,48 @@ +package extensions + +import ( + "math/big" + "sync" + + fr "github.com/consensys/gnark-crypto/field/koalabear" + "github.com/leanovate/gopter" +) + +var bigIntPool = sync.Pool{ + New: func() interface{} { + return new(big.Int) + }, +} + +// Fr generates an Fr element +func GenFr() gopter.Gen { + return func(genParams *gopter.GenParameters) *gopter.GenResult { + var elmt fr.Element + + if _, err := elmt.SetRandom(); err != nil { + panic(err) + } + genResult := gopter.NewGenResult(elmt, gopter.NoShrinker) + return genResult + } +} + +// E2 generates an E2 elmt +func GenE2() gopter.Gen { + return gopter.CombineGens( + GenFr(), + GenFr(), + ).Map(func(values []interface{}) *E2 { + return &E2{A0: values[0].(fr.Element), A1: values[1].(fr.Element)} + }) +} + +// E4 generates an E4 elmt +func GenE4() gopter.Gen { + return gopter.CombineGens( + GenE2(), + GenE2(), + ).Map(func(values []interface{}) *E4 { + return &E4{B0: *values[0].(*E2), B1: *values[1].(*E2)} + }) +} From e96f6bb4164af490a115a78148987a1db3248dbc Mon Sep 17 00:00:00 2001 From: Youssef El Housni Date: Tue, 18 Feb 2025 14:55:19 -0500 Subject: [PATCH 2/9] fix: e2 asm --- field/koalabear/extensions/e2_amd64.go | 15 +- field/koalabear/extensions/e2_amd64.s | 205 ++++++------------------- field/koalabear/extensions/e2_test.go | 4 +- 3 files changed, 54 insertions(+), 170 deletions(-) diff --git a/field/koalabear/extensions/e2_amd64.go b/field/koalabear/extensions/e2_amd64.go index b0056f131c..37013c4d55 100644 --- a/field/koalabear/extensions/e2_amd64.go +++ b/field/koalabear/extensions/e2_amd64.go @@ -6,21 +6,16 @@ import ( // q + r'.r = 1, i.e., qInvNeg = - q⁻¹ mod r // used for Montgomery reduction -const qInvNeg uint64 = 725501752471715839 +const qInvNeg uint64 = 2130706431 -// Field modulus q (Fr) +// Field modulus q (Fp) const ( - q0 uint64 = 725501752471715841 - q1 uint64 = 6461107452199829505 - q2 uint64 = 6968279316240510977 - q3 uint64 = 1345280370688173398 + q0 uint64 = 2130706433 + q uint64 = q0 ) -var qElement = fr.Element{ +var qElement = fp.Element{ q0, - q1, - q2, - q3, } //go:noescape diff --git a/field/koalabear/extensions/e2_amd64.s b/field/koalabear/extensions/e2_amd64.s index df1f55e922..216cd2f9b5 100644 --- a/field/koalabear/extensions/e2_amd64.s +++ b/field/koalabear/extensions/e2_amd64.s @@ -1,212 +1,99 @@ -#define REDUCE(ra0, ra1, ra2, ra3, rb0, rb1, rb2, rb3) \ - MOVQ ra0, rb0; \ - SUBQ ·qElement(SB), ra0; \ - MOVQ ra1, rb1; \ - SBBQ ·qElement+8(SB), ra1; \ - MOVQ ra2, rb2; \ - SBBQ ·qElement+16(SB), ra2; \ - MOVQ ra3, rb3; \ - SBBQ ·qElement+24(SB), ra3; \ - CMOVQCS rb0, ra0; \ - CMOVQCS rb1, ra1; \ - CMOVQCS rb2, ra2; \ - CMOVQCS rb3, ra3; \ +#include "textflag.h" +#include "funcdata.h" +#include "go_asm.h" + +#define REDUCE(ra0, rb0) \ + MOVQ ra0, rb0; \ + SUBQ ·qElement(SB), ra0; \ + CMOVQCS rb0, ra0; \ TEXT ·addE2(SB), NOSPLIT, $0-24 MOVQ x+8(FP), AX MOVQ 0(AX), BX - MOVQ 8(AX), SI - MOVQ 16(AX), DI - MOVQ 24(AX), R8 MOVQ y+16(FP), DX ADDQ 0(DX), BX - ADCQ 8(DX), SI - ADCQ 16(DX), DI - ADCQ 24(DX), R8 - // reduce element(BX,SI,DI,R8) using temp registers (R9,R10,R11,R12) - REDUCE(BX,SI,DI,R8,R9,R10,R11,R12) + // reduce element(BX) using temp registers (SI) + REDUCE(BX,SI) MOVQ res+0(FP), CX MOVQ BX, 0(CX) - MOVQ SI, 8(CX) - MOVQ DI, 16(CX) - MOVQ R8, 24(CX) - MOVQ 32(AX), BX - MOVQ 40(AX), SI - MOVQ 48(AX), DI - MOVQ 56(AX), R8 - ADDQ 32(DX), BX - ADCQ 40(DX), SI - ADCQ 48(DX), DI - ADCQ 56(DX), R8 - - // reduce element(BX,SI,DI,R8) using temp registers (R13,R14,R15,R9) - REDUCE(BX,SI,DI,R8,R13,R14,R15,R9) - - MOVQ BX, 32(CX) - MOVQ SI, 40(CX) - MOVQ DI, 48(CX) - MOVQ R8, 56(CX) + MOVQ 8(AX), BX + ADDQ 8(DX), BX + + // reduce element(BX) using temp registers (DI) + REDUCE(BX,DI) + + MOVQ BX, 8(CX) RET TEXT ·doubleE2(SB), NOSPLIT, $0-16 MOVQ res+0(FP), DX MOVQ x+8(FP), AX MOVQ 0(AX), CX - MOVQ 8(AX), BX - MOVQ 16(AX), SI - MOVQ 24(AX), DI ADDQ CX, CX - ADCQ BX, BX - ADCQ SI, SI - ADCQ DI, DI - // reduce element(CX,BX,SI,DI) using temp registers (R8,R9,R10,R11) - REDUCE(CX,BX,SI,DI,R8,R9,R10,R11) + // reduce element(CX) using temp registers (BX) + REDUCE(CX,BX) MOVQ CX, 0(DX) - MOVQ BX, 8(DX) - MOVQ SI, 16(DX) - MOVQ DI, 24(DX) - MOVQ 32(AX), CX - MOVQ 40(AX), BX - MOVQ 48(AX), SI - MOVQ 56(AX), DI + MOVQ 8(AX), CX ADDQ CX, CX - ADCQ BX, BX - ADCQ SI, SI - ADCQ DI, DI - // reduce element(CX,BX,SI,DI) using temp registers (R12,R13,R14,R15) - REDUCE(CX,BX,SI,DI,R12,R13,R14,R15) + // reduce element(CX) using temp registers (SI) + REDUCE(CX,SI) - MOVQ CX, 32(DX) - MOVQ BX, 40(DX) - MOVQ SI, 48(DX) - MOVQ DI, 56(DX) + MOVQ CX, 8(DX) RET TEXT ·subE2(SB), NOSPLIT, $0-24 - XORQ DI, DI - MOVQ x+8(FP), SI - MOVQ 0(SI), AX - MOVQ 8(SI), DX - MOVQ 16(SI), CX - MOVQ 24(SI), BX - MOVQ y+16(FP), SI - SUBQ 0(SI), AX - SBBQ 8(SI), DX - SBBQ 16(SI), CX - SBBQ 24(SI), BX - MOVQ x+8(FP), SI - MOVQ $0x0a11800000000001, R8 - MOVQ $0x59aa76fed0000001, R9 - MOVQ $0x60b44d1e5c37b001, R10 - MOVQ $0x12ab655e9a2ca556, R11 - CMOVQCC DI, R8 - CMOVQCC DI, R9 - CMOVQCC DI, R10 - CMOVQCC DI, R11 - ADDQ R8, AX - ADCQ R9, DX - ADCQ R10, CX - ADCQ R11, BX - MOVQ res+0(FP), R12 - MOVQ AX, 0(R12) - MOVQ DX, 8(R12) - MOVQ CX, 16(R12) - MOVQ BX, 24(R12) - MOVQ 32(SI), AX - MOVQ 40(SI), DX - MOVQ 48(SI), CX - MOVQ 56(SI), BX - MOVQ y+16(FP), SI - SUBQ 32(SI), AX - SBBQ 40(SI), DX - SBBQ 48(SI), CX - SBBQ 56(SI), BX - MOVQ $0x0a11800000000001, R13 - MOVQ $0x59aa76fed0000001, R14 - MOVQ $0x60b44d1e5c37b001, R15 - MOVQ $0x12ab655e9a2ca556, R8 - CMOVQCC DI, R13 - CMOVQCC DI, R14 - CMOVQCC DI, R15 - CMOVQCC DI, R8 - ADDQ R13, AX - ADCQ R14, DX - ADCQ R15, CX - ADCQ R8, BX + XORQ CX, CX + MOVQ x+8(FP), DX + MOVQ 0(DX), AX + MOVQ y+16(FP), DX + SUBQ 0(DX), AX + MOVQ x+8(FP), DX + MOVQ $0x000000007f000001, BX + CMOVQCC CX, BX + ADDQ BX, AX MOVQ res+0(FP), SI - MOVQ AX, 32(SI) - MOVQ DX, 40(SI) - MOVQ CX, 48(SI) - MOVQ BX, 56(SI) + MOVQ AX, 0(SI) + MOVQ 8(DX), AX + MOVQ y+16(FP), DX + SUBQ 8(DX), AX + MOVQ $0x000000007f000001, DI + CMOVQCC CX, DI + ADDQ DI, AX + MOVQ res+0(FP), DX + MOVQ AX, 8(DX) RET TEXT ·negE2(SB), NOSPLIT, $0-16 MOVQ res+0(FP), DX MOVQ x+8(FP), AX MOVQ 0(AX), BX - MOVQ 8(AX), SI - MOVQ 16(AX), DI - MOVQ 24(AX), R8 MOVQ BX, AX - ORQ SI, AX - ORQ DI, AX - ORQ R8, AX TESTQ AX, AX JNE l1 MOVQ AX, 0(DX) - MOVQ AX, 8(DX) - MOVQ AX, 16(DX) - MOVQ AX, 24(DX) JMP l3 l1: - MOVQ $0x0a11800000000001, CX + MOVQ $0x000000007f000001, CX SUBQ BX, CX MOVQ CX, 0(DX) - MOVQ $0x59aa76fed0000001, CX - SBBQ SI, CX - MOVQ CX, 8(DX) - MOVQ $0x60b44d1e5c37b001, CX - SBBQ DI, CX - MOVQ CX, 16(DX) - MOVQ $0x12ab655e9a2ca556, CX - SBBQ R8, CX - MOVQ CX, 24(DX) l3: MOVQ x+8(FP), AX - MOVQ 32(AX), BX - MOVQ 40(AX), SI - MOVQ 48(AX), DI - MOVQ 56(AX), R8 + MOVQ 8(AX), BX MOVQ BX, AX - ORQ SI, AX - ORQ DI, AX - ORQ R8, AX TESTQ AX, AX JNE l2 - MOVQ AX, 32(DX) - MOVQ AX, 40(DX) - MOVQ AX, 48(DX) - MOVQ AX, 56(DX) + MOVQ AX, 8(DX) RET l2: - MOVQ $0x0a11800000000001, CX + MOVQ $0x000000007f000001, CX SUBQ BX, CX - MOVQ CX, 32(DX) - MOVQ $0x59aa76fed0000001, CX - SBBQ SI, CX - MOVQ CX, 40(DX) - MOVQ $0x60b44d1e5c37b001, CX - SBBQ DI, CX - MOVQ CX, 48(DX) - MOVQ $0x12ab655e9a2ca556, CX - SBBQ R8, CX - MOVQ CX, 56(DX) + MOVQ CX, 8(DX) RET diff --git a/field/koalabear/extensions/e2_test.go b/field/koalabear/extensions/e2_test.go index 597b115fbd..998b5e6a51 100644 --- a/field/koalabear/extensions/e2_test.go +++ b/field/koalabear/extensions/e2_test.go @@ -178,7 +178,9 @@ func TestE2ReceiverIsOperand(t *testing.T) { func TestE2MulMaxed(t *testing.T) { // let's pick a and b, with maxed A0 and A1 var a, b E2 - frMaxValue := fr.Element{2130706432} + frMaxValue := fr.Element{ + 2130706433, + } frMaxValue[0]-- a.A0 = frMaxValue From 76c21fefef9220931c8b5309c7520991ec1b6eca Mon Sep 17 00:00:00 2001 From: Youssef El Housni Date: Tue, 18 Feb 2025 15:00:32 -0500 Subject: [PATCH 3/9] fix: confusion in Fp/r naming --- field/koalabear/extensions/doc.go | 6 +++--- field/koalabear/extensions/e2_amd64.go | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/field/koalabear/extensions/doc.go b/field/koalabear/extensions/doc.go index 12339a698f..f3a8775be3 100644 --- a/field/koalabear/extensions/doc.go +++ b/field/koalabear/extensions/doc.go @@ -1,6 +1,6 @@ -// Package extensions implements the fields arithmetic of the 𝔽p² and 𝔽p⁴ +// Package extensions implements the fields arithmetic of the 𝔽r² and 𝔽r⁴ // extensions of the Koala-bear field. // -// 𝔽p²[u] = 𝔽r/u²-4 -// 𝔽p⁴[v] = 𝔽p²/v²-u +// 𝔽r²[u] = 𝔽r/u²-4 +// 𝔽r⁴[v] = 𝔽r²/v²-u package extensions diff --git a/field/koalabear/extensions/e2_amd64.go b/field/koalabear/extensions/e2_amd64.go index 37013c4d55..8d9e0a3133 100644 --- a/field/koalabear/extensions/e2_amd64.go +++ b/field/koalabear/extensions/e2_amd64.go @@ -8,13 +8,13 @@ import ( // used for Montgomery reduction const qInvNeg uint64 = 2130706431 -// Field modulus q (Fp) +// Field modulus q (Fr) const ( q0 uint64 = 2130706433 q uint64 = q0 ) -var qElement = fp.Element{ +var qElement = fr.Element{ q0, } From d3e140c554b5cfa94845d82031634373c15191e3 Mon Sep 17 00:00:00 2001 From: Youssef El Housni Date: Tue, 18 Feb 2025 15:04:27 -0500 Subject: [PATCH 4/9] fix: uint32 --- field/koalabear/extensions/e2_amd64.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/field/koalabear/extensions/e2_amd64.go b/field/koalabear/extensions/e2_amd64.go index 8d9e0a3133..029bbafa08 100644 --- a/field/koalabear/extensions/e2_amd64.go +++ b/field/koalabear/extensions/e2_amd64.go @@ -6,12 +6,12 @@ import ( // q + r'.r = 1, i.e., qInvNeg = - q⁻¹ mod r // used for Montgomery reduction -const qInvNeg uint64 = 2130706431 +const qInvNeg uint32 = 2130706431 // Field modulus q (Fr) const ( - q0 uint64 = 2130706433 - q uint64 = q0 + q0 uint32 = 2130706433 + q uint32 = q0 ) var qElement = fr.Element{ From eb8ffa14b5804dfa7636918fd682772b2236d85d Mon Sep 17 00:00:00 2001 From: Youssef El Housni Date: Tue, 18 Feb 2025 15:52:39 -0500 Subject: [PATCH 5/9] feat: baby-bear extension 4 --- field/babybear/element_purego.go | 7 + field/babybear/extensions/doc.go | 6 + field/babybear/extensions/e2.go | 278 ++++++++++ field/babybear/extensions/e2_amd64.go | 58 ++ field/babybear/extensions/e2_amd64.s | 341 ++++++++++++ field/babybear/extensions/e2_babybear.go | 79 +++ field/babybear/extensions/e2_fallback.go | 23 + field/babybear/extensions/e2_test.go | 510 ++++++++++++++++++ field/babybear/extensions/e4.go | 341 ++++++++++++ field/babybear/extensions/e4_test.go | 300 +++++++++++ field/babybear/extensions/utils.go | 48 ++ field/generator/config/field_config.go | 9 +- .../internal/templates/element/ops_asm.go | 11 +- .../internal/templates/element/ops_purego.go | 8 +- field/goldilocks/element_purego.go | 7 + field/koalabear/element_purego.go | 7 + 16 files changed, 2030 insertions(+), 3 deletions(-) create mode 100644 field/babybear/extensions/doc.go create mode 100644 field/babybear/extensions/e2.go create mode 100644 field/babybear/extensions/e2_amd64.go create mode 100644 field/babybear/extensions/e2_amd64.s create mode 100644 field/babybear/extensions/e2_babybear.go create mode 100644 field/babybear/extensions/e2_fallback.go create mode 100644 field/babybear/extensions/e2_test.go create mode 100644 field/babybear/extensions/e4.go create mode 100644 field/babybear/extensions/e4_test.go create mode 100644 field/babybear/extensions/utils.go diff --git a/field/babybear/element_purego.go b/field/babybear/element_purego.go index c945436e98..7d2129b82e 100644 --- a/field/babybear/element_purego.go +++ b/field/babybear/element_purego.go @@ -19,6 +19,13 @@ func MulBy5(x *Element) { x.Mul(x, &y) } +// MulBy11 x *= 11 (mod q) +func MulBy11(x *Element) { + var y Element + y.SetUint64(11) + x.Mul(x, &y) +} + // MulBy13 x *= 13 (mod q) func MulBy13(x *Element) { var y Element diff --git a/field/babybear/extensions/doc.go b/field/babybear/extensions/doc.go new file mode 100644 index 0000000000..7557b8a6fd --- /dev/null +++ b/field/babybear/extensions/doc.go @@ -0,0 +1,6 @@ +// Package extensions implements the fields arithmetic of the 𝔽r² and 𝔽r⁴ +// extensions of the Koala-bear field. +// +// 𝔽r²[u] = 𝔽r/u²-11 +// 𝔽r⁴[v] = 𝔽r²/v²-u +package extensions diff --git a/field/babybear/extensions/e2.go b/field/babybear/extensions/e2.go new file mode 100644 index 0000000000..b602ba907e --- /dev/null +++ b/field/babybear/extensions/e2.go @@ -0,0 +1,278 @@ +package extensions + +import ( + "math/big" + + fr "github.com/consensys/gnark-crypto/field/babybear" +) + +// E2 is a degree two finite field extension of fr.Element +type E2 struct { + A0, A1 fr.Element +} + +// Equal returns true if z equals x, false otherwise +func (z *E2) Equal(x *E2) bool { + return z.A0.Equal(&x.A0) && z.A1.Equal(&x.A1) +} + +// Cmp compares (lexicographic order) z and x and returns: +// +// -1 if z < x +// 0 if z == x +// +1 if z > x +func (z *E2) Cmp(x *E2) int { + if a1 := z.A1.Cmp(&x.A1); a1 != 0 { + return a1 + } + return z.A0.Cmp(&x.A0) +} + +// LexicographicallyLargest returns true if this element is strictly lexicographically +// larger than its negation, false otherwise +func (z *E2) LexicographicallyLargest() bool { + // adapted from github.com/zkcrypto/bls12_381 + if z.A1.IsZero() { + return z.A0.LexicographicallyLargest() + } + return z.A1.LexicographicallyLargest() +} + +// SetString sets a E2 element from strings +func (z *E2) SetString(s1, s2 string) *E2 { + z.A0.SetString(s1) + z.A1.SetString(s2) + return z +} + +// SetZero sets an E2 elmt to zero +func (z *E2) SetZero() *E2 { + z.A0.SetZero() + z.A1.SetZero() + return z +} + +// Set sets an E2 from x +func (z *E2) Set(x *E2) *E2 { + z.A0 = x.A0 + z.A1 = x.A1 + return z +} + +// SetOne sets z to 1 in Montgomery form and returns z +func (z *E2) SetOne() *E2 { + z.A0.SetOne() + z.A1.SetZero() + return z +} + +// SetRandom sets a0 and a1 to random values +func (z *E2) SetRandom() (*E2, error) { + if _, err := z.A0.SetRandom(); err != nil { + return nil, err + } + if _, err := z.A1.SetRandom(); err != nil { + return nil, err + } + return z, nil +} + +// IsZero returns true if z is zero, false otherwise +func (z *E2) IsZero() bool { + return z.A0.IsZero() && z.A1.IsZero() +} + +// IsOne returns true if z is one, false otherwise +func (z *E2) IsOne() bool { + return z.A0.IsOne() && z.A1.IsZero() +} + +// Add adds two elements of E2 +func (z *E2) Add(x, y *E2) *E2 { + z.A0.Add(&x.A0, &y.A0) + z.A1.Add(&x.A1, &y.A1) + return z +} + +// Sub subtracts two elements of E2 +func (z *E2) Sub(x, y *E2) *E2 { + z.A0.Sub(&x.A0, &y.A0) + z.A1.Sub(&x.A1, &y.A1) + return z +} + +// Double doubles an E2 element +func (z *E2) Double(x *E2) *E2 { + z.A0.Double(&x.A0) + z.A1.Double(&x.A1) + return z +} + +// Neg negates an E2 element +func (z *E2) Neg(x *E2) *E2 { + z.A0.Neg(&x.A0) + z.A1.Neg(&x.A1) + return z +} + +// String implements Stringer interface for fancy printing +func (z *E2) String() string { + return z.A0.String() + "+" + z.A1.String() + "*u" +} + +// MulByElement multiplies an element in E2 by an element in fr +func (z *E2) MulByElement(x *E2, y *fr.Element) *E2 { + var yCopy fr.Element + yCopy.Set(y) + z.A0.Mul(&x.A0, &yCopy) + z.A1.Mul(&x.A1, &yCopy) + return z +} + +// Conjugate conjugates an element in E2 +func (z *E2) Conjugate(x *E2) *E2 { + z.A0 = x.A0 + z.A1.Neg(&x.A1) + return z +} + +// Halve sets z to z / 2 +func (z *E2) Halve() { + z.A0.Halve() + z.A1.Halve() +} + +// Legendre returns the Legendre symbol of z +func (z *E2) Legendre() int { + var n fr.Element + z.norm(&n) + return n.Legendre() +} + +// Exp sets z=xᵏ (mod q²) and returns it +func (z *E2) Exp(x E2, k *big.Int) *E2 { + if k.IsUint64() && k.Uint64() == 0 { + return z.SetOne() + } + + e := k + if k.Sign() == -1 { + // negative k, we invert + // if k < 0: xᵏ (mod q²) == (x⁻¹)ᵏ (mod q²) + x.Inverse(&x) + + // we negate k in a temp big.Int since + // Int.Bit(_) of k and -k is different + e = bigIntPool.Get().(*big.Int) + defer bigIntPool.Put(e) + e.Neg(k) + } + + z.SetOne() + b := e.Bytes() + for i := 0; i < len(b); i++ { + w := b[i] + for j := 0; j < 8; j++ { + z.Square(z) + if (w & (0b10000000 >> j)) != 0 { + z.Mul(z, &x) + } + } + } + + return z +} + +// Sqrt sets z to the square root of and returns z +// The function does not test whether the square root +// exists or not, it's up to the caller to call +// Legendre beforehand. +// cf https://eprint.iacr.org/2012/685.pdf (algo 10) +func (z *E2) Sqrt(x *E2) *E2 { + + // precomputation + var b, c, d, e, f, x0 E2 + var _b, o fr.Element + + // c must be a non square (p = 1 mod 4) + c.A1.SetOne() + + q := fr.Modulus() + var exp, one big.Int + one.SetUint64(1) + exp.Set(q).Sub(&exp, &one).Rsh(&exp, 1) + d.Exp(c, &exp) + e.Mul(&d, &c).Inverse(&e) + f.Mul(&d, &c).Square(&f) + + // computation + exp.Rsh(&exp, 1) + b.Exp(*x, &exp) + b.norm(&_b) + o.SetOne() + if _b.Equal(&o) { + x0.Square(&b).Mul(&x0, x) + _b.Set(&x0.A0).Sqrt(&_b) + z.Conjugate(&b).MulByElement(z, &_b) + return z + } + x0.Square(&b).Mul(&x0, x).Mul(&x0, &f) + _b.Set(&x0.A0).Sqrt(&_b) + z.Conjugate(&b).MulByElement(z, &_b).Mul(z, &e) + + return z +} + +// BatchInvertE2 returns a new slice with every element in a inverted. +// It uses Montgomery batch inversion trick. +// +// if a[i] == 0, returns result[i] = a[i] +func BatchInvertE2(a []E2) []E2 { + res := make([]E2, len(a)) + if len(a) == 0 { + return res + } + + zeroes := make([]bool, len(a)) + var accumulator E2 + accumulator.SetOne() + + for i := 0; i < len(a); i++ { + if a[i].IsZero() { + zeroes[i] = true + continue + } + res[i].Set(&accumulator) + accumulator.Mul(&accumulator, &a[i]) + } + + accumulator.Inverse(&accumulator) + + for i := len(a) - 1; i >= 0; i-- { + if zeroes[i] { + continue + } + res[i].Mul(&res[i], &accumulator) + accumulator.Mul(&accumulator, &a[i]) + } + + return res +} + +// Select is conditional move. +// If cond = 0, it sets z to caseZ and returns it. otherwise caseNz. +func (z *E2) Select(cond int, caseZ *E2, caseNz *E2) *E2 { + //Might be able to save a nanosecond or two by an aggregate implementation + + z.A0.Select(cond, &caseZ.A0, &caseNz.A0) + z.A1.Select(cond, &caseZ.A1, &caseNz.A1) + + return z +} + +// Div divides an element in E2 by an element in E2 +func (z *E2) Div(x *E2, y *E2) *E2 { + var r E2 + r.Inverse(y).Mul(x, &r) + return z.Set(&r) +} diff --git a/field/babybear/extensions/e2_amd64.go b/field/babybear/extensions/e2_amd64.go new file mode 100644 index 0000000000..11c064116c --- /dev/null +++ b/field/babybear/extensions/e2_amd64.go @@ -0,0 +1,58 @@ +package extensions + +import ( + fr "github.com/consensys/gnark-crypto/field/babybear" +) + +// q + r'.r = 1, i.e., qInvNeg = - q⁻¹ mod r +// used for Montgomery reduction +const qInvNeg uint64 = 2013265919 + +// Field modulus q (Fr) +const ( + q0 uint64 = 2013265921 + q uint64 = q0 +) + +var qElement = fr.Element{ + q0, +} + +//go:noescape +func addE2(res, x, y *E2) + +//go:noescape +func subE2(res, x, y *E2) + +//go:noescape +func doubleE2(res, x *E2) + +//go:noescape +func negE2(res, x *E2) + +//go:noescape +func mulNonResE2(res, x *E2) + +//go:noescape +func squareAdxE2(res, x *E2) + +//go:noescape +func mulAdxE2(res, x, y *E2) + +// MulByNonResidue multiplies a E2 by (9,1) +func (z *E2) MulByNonResidue(x *E2) *E2 { + mulNonResE2(z, x) + return z +} + +// Mul sets z to the E2-product of x,y, returns z +func (z *E2) Mul(x, y *E2) *E2 { + mulAdxE2(z, x, y) + return z +} + +// Square sets z to the E2-product of x,x, returns z +func (z *E2) Square(x *E2) *E2 { + squareAdxE2(z, x) + return z +} diff --git a/field/babybear/extensions/e2_amd64.s b/field/babybear/extensions/e2_amd64.s new file mode 100644 index 0000000000..0da2d2f8ba --- /dev/null +++ b/field/babybear/extensions/e2_amd64.s @@ -0,0 +1,341 @@ +// Copyright 2020-2025 Consensys Software Inc. +// Licensed under the Apache License, Version 2.0. See the LICENSE file for details. + +#include "textflag.h" +#include "funcdata.h" +#include "go_asm.h" + +#define REDUCE(ra0, rb0) \ + MOVQ ra0, rb0; \ + SUBQ ·qElement(SB), ra0; \ + CMOVQCS rb0, ra0; \ + +// this code is generated and identical to fr.Mul(...) +// A -> BP +// t -> CX +#define MACC(in0, in1, in2) \ + ADCXQ in0, in1 \ + MULXQ in2, AX, in0 \ + ADOXQ AX, in1 \ + +#define DIV_SHIFT() \ + MOVQ $const_qInvNeg, DX \ + IMULQ CX, DX \ + XORQ AX, AX \ + MULXQ ·qElement+0(SB), AX, BX \ + ADCXQ CX, AX \ + MOVQ BX, CX \ + MOVQ $0, AX \ + ADCXQ AX, CX \ + ADOXQ BP, CX \ + +#define MUL_WORD_0() \ + XORQ AX, AX \ + MULXQ R14, CX, BP \ + MOVQ $0, AX \ + ADOXQ AX, BP \ + DIV_SHIFT() \ + +#define MUL_WORD_N() \ + XORQ AX, AX \ + MULXQ R14, AX, BP \ + ADOXQ AX, CX \ + MOVQ $0, AX \ + ADCXQ AX, BP \ + ADOXQ AX, BP \ + DIV_SHIFT() \ + +#define MUL() \ + MOVQ R15, DX; \ + MUL_WORD_0(); \ + +TEXT ·addE2(SB), NOSPLIT, $0-24 + MOVQ x+8(FP), AX + MOVQ 0(AX), BX + MOVQ y+16(FP), DX + ADDQ 0(DX), BX + + // reduce element(BX) using temp registers (SI) + REDUCE(BX,SI) + + MOVQ res+0(FP), CX + MOVQ BX, 0(CX) + MOVQ 8(AX), BX + ADDQ 8(DX), BX + + // reduce element(BX) using temp registers (DI) + REDUCE(BX,DI) + + MOVQ BX, 8(CX) + RET + +TEXT ·doubleE2(SB), NOSPLIT, $0-16 + MOVQ res+0(FP), DX + MOVQ x+8(FP), AX + MOVQ 0(AX), CX + ADDQ CX, CX + + // reduce element(CX) using temp registers (BX) + REDUCE(CX,BX) + + MOVQ CX, 0(DX) + MOVQ 8(AX), CX + ADDQ CX, CX + + // reduce element(CX) using temp registers (SI) + REDUCE(CX,SI) + + MOVQ CX, 8(DX) + RET + +TEXT ·subE2(SB), NOSPLIT, $0-24 + XORQ CX, CX + MOVQ x+8(FP), DX + MOVQ 0(DX), AX + MOVQ y+16(FP), DX + SUBQ 0(DX), AX + MOVQ x+8(FP), DX + MOVQ $0x0000000078000001, BX + CMOVQCC CX, BX + ADDQ BX, AX + MOVQ res+0(FP), SI + MOVQ AX, 0(SI) + MOVQ 8(DX), AX + MOVQ y+16(FP), DX + SUBQ 8(DX), AX + MOVQ $0x0000000078000001, DI + CMOVQCC CX, DI + ADDQ DI, AX + MOVQ res+0(FP), DX + MOVQ AX, 8(DX) + RET + +TEXT ·negE2(SB), NOSPLIT, $0-16 + MOVQ res+0(FP), DX + MOVQ x+8(FP), AX + MOVQ 0(AX), BX + MOVQ BX, AX + TESTQ AX, AX + JNE l1 + MOVQ AX, 0(DX) + JMP l3 + +l1: + MOVQ $0x0000000078000001, CX + SUBQ BX, CX + MOVQ CX, 0(DX) + +l3: + MOVQ x+8(FP), AX + MOVQ 8(AX), BX + MOVQ BX, AX + TESTQ AX, AX + JNE l2 + MOVQ AX, 8(DX) + RET + +l2: + MOVQ $0x0000000078000001, CX + SUBQ BX, CX + MOVQ CX, 8(DX) + RET + +TEXT ·mulNonResE2(SB), NOSPLIT, $0-16 + MOVQ x+8(FP), CX + MOVQ 0(CX), AX + ADDQ AX, AX + + // reduce element(AX) using temp registers (BX) + REDUCE(AX,BX) + + ADDQ AX, AX + + // reduce element(AX) using temp registers (SI) + REDUCE(AX,SI) + + ADDQ AX, AX + + // reduce element(AX) using temp registers (DI) + REDUCE(AX,DI) + + ADDQ 0(CX), AX + + // reduce element(AX) using temp registers (R8) + REDUCE(AX,R8) + + MOVQ 8(CX), DX + XORQ R9, R9 + SUBQ DX, AX + MOVQ $0x0000000078000001, R10 + CMOVQCC R9, R10 + ADDQ R10, AX + ADDQ DX, DX + + // reduce element(DX) using temp registers (R11) + REDUCE(DX,R11) + + ADDQ DX, DX + + // reduce element(DX) using temp registers (R12) + REDUCE(DX,R12) + + ADDQ DX, DX + + // reduce element(DX) using temp registers (R13) + REDUCE(DX,R13) + + ADDQ 8(CX), DX + + // reduce element(DX) using temp registers (R14) + REDUCE(DX,R14) + + ADDQ 0(CX), DX + + // reduce element(DX) using temp registers (R15) + REDUCE(DX,R15) + + MOVQ res+0(FP), CX + MOVQ AX, 0(CX) + MOVQ DX, 8(CX) + RET + +TEXT ·mulAdxE2(SB), $24-24 + NO_LOCAL_POINTERS + + // var a, b, c fr.Element + // a.Add(&x.A0, &x.A1) + // b.Add(&y.A0, &y.A1) + // a.Mul(&a, &b) + // b.Mul(&x.A0, &y.A0) + // c.Mul(&x.A1, &y.A1) + // z.A1.Sub(&a, &b).Sub(&z.A1, &c) + // z.A0.Sub(&b, &c) + + CMPB ·supportAdx(SB), $1 + JNE l4 + MOVQ x+8(FP), AX + MOVQ y+16(FP), DX + MOVQ 8(AX), R14 + MOVQ 8(DX), R15 + + // mul (R14) with (R15) into (CX) + MUL() + + // reduce element(CX) using temp registers (R15) + REDUCE(CX,R15) + + MOVQ CX, s1-16(SP) + MOVQ x+8(FP), AX + MOVQ y+16(FP), DX + ADDQ 0(AX), R14 + MOVQ 0(DX), R15 + ADDQ 8(DX), R15 + + // mul (R14) with (R15) into (CX) + MUL() + + // reduce element(CX) using temp registers (R15) + REDUCE(CX,R15) + + MOVQ CX, s0-8(SP) + MOVQ x+8(FP), AX + MOVQ y+16(FP), DX + MOVQ 0(AX), R14 + MOVQ 0(DX), R15 + + // mul (R14) with (R15) into (CX) + MUL() + + // reduce element(CX) using temp registers (R15) + REDUCE(CX,R15) + + XORQ DX, DX + MOVQ s0-8(SP), R14 + SUBQ CX, R14 + MOVQ $0x0000000078000001, R15 + CMOVQCC DX, R15 + ADDQ R15, R14 + SUBQ s1-16(SP), R14 + MOVQ $0x0000000078000001, R15 + CMOVQCC DX, R15 + ADDQ R15, R14 + MOVQ res+0(FP), AX + MOVQ R14, 8(AX) + MOVQ s1-16(SP), R15 + SUBQ R15, CX + MOVQ $0x0000000078000001, R14 + CMOVQCC DX, R14 + ADDQ R14, CX + MOVQ CX, 0(AX) + RET + +l4: + MOVQ res+0(FP), AX + MOVQ AX, (SP) + MOVQ x+8(FP), AX + MOVQ AX, 8(SP) + MOVQ y+16(FP), AX + MOVQ AX, 16(SP) + CALL ·mulGenericE2(SB) + RET + +TEXT ·squareAdxE2(SB), $16-16 + NO_LOCAL_POINTERS + + // z.A0 = (x.A0 + x.A1) * (x.A0 - x.A1) + // z.A1 = 2 * x.A0 * x.A1 + + CMPB ·supportAdx(SB), $1 + JNE l5 + + // 2 * x.A0 * x.A1 + MOVQ x+8(FP), AX + + // x.A0 -> R15 + MOVQ 0(AX), R15 + + // 2 * x.A1 -> R14 + MOVQ 8(AX), R14 + ADDQ R14, R14 + + // mul (R14) with (R15) into (CX) + MUL() + + // reduce element(CX) using temp registers (R14) + REDUCE(CX,R14) + + MOVQ x+8(FP), AX + + // x.A1 -> R14 + MOVQ 8(AX), R14 + MOVQ res+0(FP), DX + MOVQ CX, 8(DX) + MOVQ R14, CX + + // Add(&x.A0, &x.A1) + ADDQ R15, R14 + XORQ BP, BP + + // Sub(&x.A0, &x.A1) + SUBQ CX, R15 + MOVQ $0x0000000078000001, CX + CMOVQCC BP, CX + ADDQ CX, R15 + + // mul (R14) with (R15) into (CX) + MUL() + + // reduce element(CX) using temp registers (R14) + REDUCE(CX,R14) + + MOVQ res+0(FP), AX + MOVQ CX, 0(AX) + RET + +l5: + MOVQ res+0(FP), AX + MOVQ AX, (SP) + MOVQ x+8(FP), AX + MOVQ AX, 8(SP) + CALL ·squareGenericE2(SB) + RET diff --git a/field/babybear/extensions/e2_babybear.go b/field/babybear/extensions/e2_babybear.go new file mode 100644 index 0000000000..5939d787ea --- /dev/null +++ b/field/babybear/extensions/e2_babybear.go @@ -0,0 +1,79 @@ +package extensions + +import ( + fr "github.com/consensys/gnark-crypto/field/babybear" +) + +// Mul sets z to the E2-product of x,y, returns z +func (z *E2) Mul(x, y *E2) *E2 { + var a, b, c fr.Element + a.Add(&x.A0, &x.A1) + b.Add(&y.A0, &y.A1) + a.Mul(&a, &b) + b.Mul(&x.A0, &y.A0) + c.Mul(&x.A1, &y.A1) + z.A1.Sub(&a, &b).Sub(&z.A1, &c) + fr.MulBy11(&c) + z.A0.Add(&b, &c) + return z +} + +// Square sets z to the E2-product of x,x returns z +func (z *E2) Square(x *E2) *E2 { + var a, b, c fr.Element + a.Mul(&x.A0, &x.A1).Double(&a) + c.Square(&x.A0) + b.Square(&x.A1) + fr.MulBy11(&b) + z.A0.Add(&c, &b) + z.A1 = a + return z +} + +// MulByNonResidue multiplies a E2 by (0,1) +func (z *E2) MulByNonResidue(x *E2) *E2 { + a := x.A0 + b := x.A1 // fetching x.A1 in the function below is slower + fr.MulBy11(&b) + z.A0 = b + z.A1 = a + return z +} + +// MulByNonResidueInv multiplies a E2 by (0,1)^{-1} +func (z *E2) MulByNonResidueInv(x *E2) *E2 { + a := x.A1 + // 1/11 mod r + var elevenInv fr.Element + elevenInv.SetUint64(549072524) + z.A1.Mul(&x.A0, &elevenInv) + z.A0 = a + return z +} + +// Inverse sets z to the E2-inverse of x, returns z +func (z *E2) Inverse(x *E2) *E2 { + // Algorithm 8 from https://eprint.iacr.org/2010/354.pdf + var t0, t1, tmp fr.Element + a := &x.A0 // creating the buffers a, b is faster than querying &x.A0, &x.A1 in the functions call below + b := &x.A1 + t0.Square(a) + t1.Square(b) + tmp.Set(&t1) + fr.MulBy11(&tmp) + t0.Sub(&t0, &tmp) + t1.Inverse(&t0) + z.A0.Mul(a, &t1) + z.A1.Mul(b, &t1).Neg(&z.A1) + + return z +} + +// norm sets x to the norm of z +func (z *E2) norm(x *fr.Element) { + var tmp fr.Element + x.Square(&z.A1) + tmp.Set(x) + fr.MulBy11(&tmp) + x.Square(&z.A0).Sub(x, &tmp) +} diff --git a/field/babybear/extensions/e2_fallback.go b/field/babybear/extensions/e2_fallback.go new file mode 100644 index 0000000000..643ca324e7 --- /dev/null +++ b/field/babybear/extensions/e2_fallback.go @@ -0,0 +1,23 @@ +//go:build !amd64 + +package extensions + +func addE2(z, x, y *E2) { + z.A0.Add(&x.A0, &y.A0) + z.A1.Add(&x.A1, &y.A1) +} + +func subE2(z, x, y *E2) { + z.A0.Sub(&x.A0, &y.A0) + z.A1.Sub(&x.A1, &y.A1) +} + +func doubleE2(z, x *E2) { + z.A0.Double(&x.A0) + z.A1.Double(&x.A1) +} + +func negE2(z, x *E2) { + z.A0.Neg(&x.A0) + z.A1.Neg(&x.A1) +} diff --git a/field/babybear/extensions/e2_test.go b/field/babybear/extensions/e2_test.go new file mode 100644 index 0000000000..103fec029c --- /dev/null +++ b/field/babybear/extensions/e2_test.go @@ -0,0 +1,510 @@ +package extensions + +import ( + "crypto/rand" + "testing" + + fr "github.com/consensys/gnark-crypto/field/babybear" + "github.com/leanovate/gopter" + "github.com/leanovate/gopter/prop" +) + +// ------------------------------------------------------------ +// tests + +const ( + nbFuzzShort = 10 + nbFuzz = 50 +) + +func TestE2ReceiverIsOperand(t *testing.T) { + + t.Parallel() + parameters := gopter.DefaultTestParameters() + if testing.Short() { + parameters.MinSuccessfulTests = nbFuzzShort + } else { + parameters.MinSuccessfulTests = nbFuzz + } + + properties := gopter.NewProperties(parameters) + + genA := GenE2() + genB := GenE2() + genfr := GenFr() + + properties.Property("[BABYBEAR] Having the receiver as operand (addition) should output the same result", prop.ForAll( + func(a, b *E2) bool { + var c, d E2 + d.Set(a) + c.Add(a, b) + a.Add(a, b) + b.Add(&d, b) + return a.Equal(b) && a.Equal(&c) && b.Equal(&c) + }, + genA, + genB, + )) + + properties.Property("[BABYBEAR] Having the receiver as operand (sub) should output the same result", prop.ForAll( + func(a, b *E2) bool { + var c, d E2 + d.Set(a) + c.Sub(a, b) + a.Sub(a, b) + b.Sub(&d, b) + return a.Equal(b) && a.Equal(&c) && b.Equal(&c) + }, + genA, + genB, + )) + + properties.Property("[BABYBEAR] Having the receiver as operand (mul) should output the same result", prop.ForAll( + func(a, b *E2) bool { + var c, d E2 + d.Set(a) + c.Mul(a, b) + a.Mul(a, b) + b.Mul(&d, b) + return a.Equal(b) && a.Equal(&c) && b.Equal(&c) + }, + genA, + genB, + )) + + properties.Property("[BABYBEAR] Having the receiver as operand (square) should output the same result", prop.ForAll( + func(a *E2) bool { + var b E2 + b.Square(a) + a.Square(a) + return a.Equal(&b) + }, + genA, + )) + + properties.Property("[BABYBEAR] Having the receiver as operand (neg) should output the same result", prop.ForAll( + func(a *E2) bool { + var b E2 + b.Neg(a) + a.Neg(a) + return a.Equal(&b) + }, + genA, + )) + + properties.Property("[BABYBEAR] Having the receiver as operand (double) should output the same result", prop.ForAll( + func(a *E2) bool { + var b E2 + b.Double(a) + a.Double(a) + return a.Equal(&b) + }, + genA, + )) + + properties.Property("[BABYBEAR] Having the receiver as operand (mul by non residue) should output the same result", prop.ForAll( + func(a *E2) bool { + var b E2 + b.MulByNonResidue(a) + a.MulByNonResidue(a) + return a.Equal(&b) + }, + genA, + )) + + properties.Property("[BABYBEAR] Having the receiver as operand (mul by non residue inverse) should output the same result", prop.ForAll( + func(a *E2) bool { + var b E2 + b.MulByNonResidueInv(a) + a.MulByNonResidueInv(a) + return a.Equal(&b) + }, + genA, + )) + + properties.Property("[BABYBEAR] Having the receiver as operand (Inverse) should output the same result", prop.ForAll( + func(a *E2) bool { + var b E2 + b.Inverse(a) + a.Inverse(a) + return a.Equal(&b) + }, + genA, + )) + + properties.Property("[BABYBEAR] Having the receiver as operand (Conjugate) should output the same result", prop.ForAll( + func(a *E2) bool { + var b E2 + b.Conjugate(a) + a.Conjugate(a) + return a.Equal(&b) + }, + genA, + )) + + properties.Property("[BABYBEAR] Having the receiver as operand (mul by element) should output the same result", prop.ForAll( + func(a *E2, b fr.Element) bool { + var c E2 + c.MulByElement(a, &b) + a.MulByElement(a, &b) + return a.Equal(&c) + }, + genA, + genfr, + )) + + properties.Property("[BABYBEAR] Having the receiver as operand (Sqrt) should output the same result", prop.ForAll( + func(a *E2) bool { + var b, c, d, s E2 + + s.Square(a) + a.Set(&s) + b.Set(&s) + + a.Sqrt(a) + b.Sqrt(&b) + + c.Square(a) + d.Square(&b) + return c.Equal(&d) + }, + genA, + )) + + properties.TestingRun(t, gopter.ConsoleReporter(false)) + +} + +func TestE2MulMaxed(t *testing.T) { + // let's pick a and b, with maxed A0 and A1 + var a, b E2 + frMaxValue := fr.Element{ + 2013265921, + } + frMaxValue[0]-- + + a.A0 = frMaxValue + a.A1 = frMaxValue + b.A0 = frMaxValue + b.A1 = frMaxValue + + var c, d E2 + d.Inverse(&b) + c.Set(&a) + c.Mul(&c, &b).Mul(&c, &d) + if !c.Equal(&a) { + t.Fatal("mul with max fr failed") + } +} + +func TestE2Ops(t *testing.T) { + + t.Parallel() + parameters := gopter.DefaultTestParameters() + if testing.Short() { + parameters.MinSuccessfulTests = nbFuzzShort + } else { + parameters.MinSuccessfulTests = nbFuzz + } + + properties := gopter.NewProperties(parameters) + + genA := GenE2() + genB := GenE2() + genfr := GenFr() + + properties.Property("[BABYBEAR] sub & add should leave an element invariant", prop.ForAll( + func(a, b *E2) bool { + var c E2 + c.Set(a) + c.Add(&c, b).Sub(&c, b) + return c.Equal(a) + }, + genA, + genB, + )) + + properties.Property("[BABYBEAR] mul & inverse should leave an element invariant", prop.ForAll( + func(a, b *E2) bool { + var c, d E2 + d.Inverse(b) + c.Set(a) + c.Mul(&c, b).Mul(&c, &d) + return c.Equal(a) + }, + genA, + genB, + )) + + properties.Property("[BABYBEAR] BatchInvertE2 should output the same result as Inverse", prop.ForAll( + func(a, b, c *E2) bool { + + batch := BatchInvertE2([]E2{*a, *b, *c}) + a.Inverse(a) + b.Inverse(b) + c.Inverse(c) + return a.Equal(&batch[0]) && b.Equal(&batch[1]) && c.Equal(&batch[2]) + }, + genA, + genA, + genA, + )) + + properties.Property("[BABYBEAR] inverse twice should leave an element invariant", prop.ForAll( + func(a *E2) bool { + var b E2 + b.Inverse(a).Inverse(&b) + return a.Equal(&b) + }, + genA, + )) + + properties.Property("[BABYBEAR] neg twice should leave an element invariant", prop.ForAll( + func(a *E2) bool { + var b E2 + b.Neg(a).Neg(&b) + return a.Equal(&b) + }, + genA, + )) + + properties.Property("[BABYBEAR] square and mul should output the same result", prop.ForAll( + func(a *E2) bool { + var b, c E2 + b.Mul(a, a) + c.Square(a) + return b.Equal(&c) + }, + genA, + )) + + properties.Property("[BABYBEAR] MulByElement MulByElement inverse should leave an element invariant", prop.ForAll( + func(a *E2, b fr.Element) bool { + var c E2 + var d fr.Element + d.Inverse(&b) + c.MulByElement(a, &b).MulByElement(&c, &d) + return c.Equal(a) + }, + genA, + genfr, + )) + + properties.Property("[BABYBEAR] Double and mul by 2 should output the same result", prop.ForAll( + func(a *E2) bool { + var b E2 + var c fr.Element + c.SetUint64(2) + b.Double(a) + a.MulByElement(a, &c) + return a.Equal(&b) + }, + genA, + )) + + properties.Property("[BABYBEAR] Mulbynonres mulbynonresinv should leave the element invariant", prop.ForAll( + func(a *E2) bool { + var b E2 + b.MulByNonResidue(a).MulByNonResidueInv(&b) + return a.Equal(&b) + }, + genA, + )) + + properties.Property("[BABYBEAR] a + pi(a), a-pi(a) should be real", prop.ForAll( + func(a *E2) bool { + var b, c, d E2 + var e, f fr.Element + b.Conjugate(a) + c.Add(a, &b) + d.Sub(a, &b) + e.Double(&a.A0) + f.Double(&a.A1) + return c.A1.IsZero() && d.A0.IsZero() && e.Equal(&c.A0) && f.Equal(&d.A1) + }, + genA, + )) + + properties.Property("[BABYBEAR] Legendre on square should output 1", prop.ForAll( + func(a *E2) bool { + var b E2 + b.Square(a) + c := b.Legendre() + return c == 1 + }, + genA, + )) + + properties.Property("[BABYBEAR] square(sqrt) should leave an element invariant", prop.ForAll( + func(a *E2) bool { + var b, c, d, e E2 + b.Square(a) + c.Sqrt(&b) + d.Square(&c) + e.Neg(a) + return (c.Equal(a) || c.Equal(&e)) && d.Equal(&b) + }, + genA, + )) + + properties.Property("[BABYBEAR] neg(E2) == neg(E2.A0, E2.A1)", prop.ForAll( + func(a *E2) bool { + var b, c E2 + b.Neg(a) + c.A0.Neg(&a.A0) + c.A1.Neg(&a.A1) + return c.Equal(&b) + }, + genA, + )) + + properties.Property("[BABYBEAR] Cmp and LexicographicallyLargest should be consistent", prop.ForAll( + func(a *E2) bool { + var negA E2 + negA.Neg(a) + cmpResult := a.Cmp(&negA) + lResult := a.LexicographicallyLargest() + if lResult && cmpResult == 1 { + return true + } + if !lResult && cmpResult != 1 { + return true + } + return false + }, + genA, + )) + + properties.TestingRun(t, gopter.ConsoleReporter(false)) + +} + +// ------------------------------------------------------------ +// benches + +func BenchmarkE2Add(b *testing.B) { + var a, c E2 + _, _ = a.SetRandom() + _, _ = c.SetRandom() + b.ResetTimer() + for i := 0; i < b.N; i++ { + a.Add(&a, &c) + } +} + +func BenchmarkE2Sub(b *testing.B) { + var a, c E2 + _, _ = a.SetRandom() + _, _ = c.SetRandom() + b.ResetTimer() + for i := 0; i < b.N; i++ { + a.Sub(&a, &c) + } +} + +func BenchmarkE2Mul(b *testing.B) { + var a, c E2 + _, _ = a.SetRandom() + _, _ = c.SetRandom() + b.ResetTimer() + for i := 0; i < b.N; i++ { + a.Mul(&a, &c) + } +} + +func BenchmarkE2MulByElement(b *testing.B) { + var a E2 + var c fr.Element + _, _ = c.SetRandom() + _, _ = a.SetRandom() + b.ResetTimer() + for i := 0; i < b.N; i++ { + a.MulByElement(&a, &c) + } +} + +func BenchmarkE2Square(b *testing.B) { + var a E2 + _, _ = a.SetRandom() + b.ResetTimer() + for i := 0; i < b.N; i++ { + a.Square(&a) + } +} + +func BenchmarkE2Sqrt(b *testing.B) { + var a E2 + _, _ = a.SetRandom() + b.ResetTimer() + for i := 0; i < b.N; i++ { + a.Sqrt(&a) + } +} + +func BenchmarkE2Exp(b *testing.B) { + var x E2 + _, _ = x.SetRandom() + b1, _ := rand.Int(rand.Reader, fr.Modulus()) + b.ResetTimer() + for i := 0; i < b.N; i++ { + x.Exp(x, b1) + } +} + +func BenchmarkE2Inverse(b *testing.B) { + var a E2 + _, _ = a.SetRandom() + b.ResetTimer() + for i := 0; i < b.N; i++ { + a.Inverse(&a) + } +} + +func BenchmarkE2MulNonRes(b *testing.B) { + var a E2 + _, _ = a.SetRandom() + b.ResetTimer() + for i := 0; i < b.N; i++ { + a.MulByNonResidue(&a) + } +} + +func BenchmarkE2MulNonResInv(b *testing.B) { + var a E2 + _, _ = a.SetRandom() + b.ResetTimer() + for i := 0; i < b.N; i++ { + a.MulByNonResidueInv(&a) + } +} + +func BenchmarkE2Conjugate(b *testing.B) { + var a E2 + _, _ = a.SetRandom() + b.ResetTimer() + for i := 0; i < b.N; i++ { + a.Conjugate(&a) + } +} + +func TestE2Div(t *testing.T) { + + parameters := gopter.DefaultTestParameters() + properties := gopter.NewProperties(parameters) + + genA := GenE2() + genB := GenE2() + + properties.Property("[BABYBEAR] dividing then multiplying by the same element does nothing", prop.ForAll( + func(a, b *E2) bool { + var c E2 + c.Div(a, b) + c.Mul(&c, b) + return c.Equal(a) + }, + genA, + genB, + )) + + properties.TestingRun(t, gopter.ConsoleReporter(false)) +} diff --git a/field/babybear/extensions/e4.go b/field/babybear/extensions/e4.go new file mode 100644 index 0000000000..d4af517b14 --- /dev/null +++ b/field/babybear/extensions/e4.go @@ -0,0 +1,341 @@ +package extensions + +import ( + "math/big" + + fr "github.com/consensys/gnark-crypto/field/babybear" +) + +// E4 is a degree two finite field extension of fr2 +type E4 struct { + B0, B1 E2 +} + +// Equal returns true if z equals x, false otherwise +func (z *E4) Equal(x *E4) bool { + return z.B0.Equal(&x.B0) && z.B1.Equal(&x.B1) +} + +// Cmp compares (lexicographic order) z and x and returns: +// +// -1 if z < x +// 0 if z == x +// +1 if z > x +func (z *E4) Cmp(x *E4) int { + if a1 := z.B1.Cmp(&x.B1); a1 != 0 { + return a1 + } + return z.B0.Cmp(&x.B0) +} + +// LexicographicallyLargest returns true if this element is strictly lexicographically +// larger than its negation, false otherwise +func (z *E4) LexicographicallyLargest() bool { + // adapted from github.com/zkcrypto/bls12_381 + if z.B1.IsZero() { + return z.B0.LexicographicallyLargest() + } + return z.B1.LexicographicallyLargest() +} + +// String puts E4 in string form +func (z *E4) String() string { + return (z.B0.String() + "+(" + z.B1.String() + ")*v") +} + +// SetString sets a E4 from string +func (z *E4) SetString(s0, s1, s2, s3 string) *E4 { + z.B0.SetString(s0, s1) + z.B1.SetString(s2, s3) + return z +} + +// Set copies x into z and returns z +func (z *E4) Set(x *E4) *E4 { + z.B0 = x.B0 + z.B1 = x.B1 + return z +} + +// SetZero sets an E4 elmt to zero +func (z *E4) SetZero() *E4 { + z.B0.SetZero() + z.B1.SetZero() + return z +} + +// SetOne sets z to 1 in Montgomery form and returns z +func (z *E4) SetOne() *E4 { + *z = E4{} + z.B0.A0.SetOne() + return z +} + +// MulByElement multiplies an element in E4 by an element in fr +func (z *E4) MulByElement(x *E4, y *fr.Element) *E4 { + var yCopy fr.Element + yCopy.Set(y) + z.B0.MulByElement(&x.B0, &yCopy) + z.B1.MulByElement(&x.B1, &yCopy) + return z +} + +// MulByE2 multiplies an element in E4 by an element in E2 +func (z *E4) MulByE2(x *E4, y *E2) *E4 { + var yCopy E2 + yCopy.Set(y) + z.B0.Mul(&x.B0, &yCopy) + z.B1.Mul(&x.B1, &yCopy) + return z +} + +// Add sets z=x+y in E4 and returns z +func (z *E4) Add(x, y *E4) *E4 { + z.B0.Add(&x.B0, &y.B0) + z.B1.Add(&x.B1, &y.B1) + return z +} + +// Sub sets z to x-y and returns z +func (z *E4) Sub(x, y *E4) *E4 { + z.B0.Sub(&x.B0, &y.B0) + z.B1.Sub(&x.B1, &y.B1) + return z +} + +// Double sets z=2*x and returns z +func (z *E4) Double(x *E4) *E4 { + z.B0.Double(&x.B0) + z.B1.Double(&x.B1) + return z +} + +// Neg negates an E4 element +func (z *E4) Neg(x *E4) *E4 { + z.B0.Neg(&x.B0) + z.B1.Neg(&x.B1) + return z +} + +// SetRandom used only in tests +func (z *E4) SetRandom() (*E4, error) { + if _, err := z.B0.SetRandom(); err != nil { + return nil, err + } + if _, err := z.B1.SetRandom(); err != nil { + return nil, err + } + return z, nil +} + +// IsZero returns true if z is zero, false otherwise +func (z *E4) IsZero() bool { + return z.B0.IsZero() && z.B1.IsZero() +} + +// IsOne returns true if z is one, false otherwise +func (z *E4) IsOne() bool { + return z.B0.IsOne() && z.B1.IsZero() +} + +// MulByNonResidue mul x by (0,1) +func (z *E4) MulByNonResidue(x *E4) *E4 { + z.B1, z.B0 = x.B0, x.B1 + z.B0.MulByNonResidue(&z.B0) + return z +} + +// Mul sets z=x*y in E4 and returns z +func (z *E4) Mul(x, y *E4) *E4 { + var a, b, c E2 + a.Add(&x.B0, &x.B1) + b.Add(&y.B0, &y.B1) + a.Mul(&a, &b) + b.Mul(&x.B0, &y.B0) + c.Mul(&x.B1, &y.B1) + z.B1.Sub(&a, &b).Sub(&z.B1, &c) + z.B0.MulByNonResidue(&c).Add(&z.B0, &b) + return z +} + +// Square sets z=x*x in E4 and returns z +func (z *E4) Square(x *E4) *E4 { + + //Algorithm 22 from https://eprint.iacr.org/2010/354.pdf + var c0, c2, c3 E2 + c0.Sub(&x.B0, &x.B1) + c3.MulByNonResidue(&x.B1).Sub(&x.B0, &c3) + c2.Mul(&x.B0, &x.B1) + c0.Mul(&c0, &c3).Add(&c0, &c2) + z.B1.Double(&c2) + c2.MulByNonResidue(&c2) + z.B0.Add(&c0, &c2) + + return z +} + +// Inverse sets z to the inverse of x in E4 and returns z +// +// if x == 0, sets and returns z = x +func (z *E4) Inverse(x *E4) *E4 { + // Algorithm 23 from https://eprint.iacr.org/2010/354.pdf + + var t0, t1, tmp E2 + t0.Square(&x.B0) + t1.Square(&x.B1) + tmp.MulByNonResidue(&t1) + t0.Sub(&t0, &tmp) + t1.Inverse(&t0) + z.B0.Mul(&x.B0, &t1) + z.B1.Mul(&x.B1, &t1).Neg(&z.B1) + + return z +} + +// Exp sets z=xᵏ (mod q⁴) and returns it +func (z *E4) Exp(x E4, k *big.Int) *E4 { + if k.IsUint64() && k.Uint64() == 0 { + return z.SetOne() + } + + e := k + if k.Sign() == -1 { + // negative k, we invert + // if k < 0: xᵏ (mod q⁴) == (x⁻¹)ᵏ (mod q⁴) + x.Inverse(&x) + + // we negate k in a temp big.Int since + // Int.Bit(_) of k and -k is different + e = bigIntPool.Get().(*big.Int) + defer bigIntPool.Put(e) + e.Neg(k) + } + + z.SetOne() + b := e.Bytes() + for i := 0; i < len(b); i++ { + w := b[i] + for j := 0; j < 8; j++ { + z.Square(z) + if (w & (0b10000000 >> j)) != 0 { + z.Mul(z, &x) + } + } + } + + return z +} + +// Conjugate sets z to x conjugated and returns z +func (z *E4) Conjugate(x *E4) *E4 { + z.B0 = x.B0 + z.B1.Neg(&x.B1) + return z +} + +func (z *E4) Halve() { + + z.B0.A0.Halve() + z.B0.A1.Halve() + z.B1.A0.Halve() + z.B1.A1.Halve() +} + +// norm sets x to the norm of z +func (z *E4) norm(x *E2) { + var tmp E2 + tmp.Square(&z.B1).MulByNonResidue(&tmp) + x.Square(&z.B0).Sub(x, &tmp) +} + +// Legendre returns the Legendre symbol of z +func (z *E4) Legendre() int { + var n E2 + z.norm(&n) + return n.Legendre() +} + +// Sqrt sets z to the square root of and returns z +// The function does not test whether the square root +// exists or not, it's up to the caller to call +// Legendre beforehand. +// cf https://eprint.iacr.org/2012/685.pdf (algo 10) +func (z *E4) Sqrt(x *E4) *E4 { + + // precomputation + var b, c, d, e, f, x0, _g E4 + var _b, o E2 + + // c must be a non square (p = 1 mod 4) + c.B1.SetOne() + + q := fr.Modulus() + var exp, one big.Int + one.SetUint64(1) + exp.Mul(q, q).Sub(&exp, &one).Rsh(&exp, 1) + d.Exp(c, &exp) + e.Mul(&d, &c).Inverse(&e) + f.Mul(&d, &c).Square(&f) + + // computation + exp.Rsh(&exp, 1) + b.Exp(*x, &exp) + b.norm(&_b) + o.SetOne() + if _b.Equal(&o) { + x0.Square(&b).Mul(&x0, x) + _b.Set(&x0.B0).Sqrt(&_b) + _g.B0.Set(&_b) + z.Conjugate(&b).Mul(z, &_g) + return z + } + x0.Square(&b).Mul(&x0, x).Mul(&x0, &f) + _b.Set(&x0.B0).Sqrt(&_b) + _g.B0.Set(&_b) + z.Conjugate(&b).Mul(z, &_g).Mul(z, &e) + + return z +} + +// BatchInvertE4 returns a new slice with every element in a inverted. +// It uses Montgomery batch inversion trick. +// +// if a[i] == 0, returns result[i] = a[i] +func BatchInvertE4(a []E4) []E4 { + res := make([]E4, len(a)) + if len(a) == 0 { + return res + } + + zeroes := make([]bool, len(a)) + var accumulator E4 + accumulator.SetOne() + + for i := 0; i < len(a); i++ { + if a[i].IsZero() { + zeroes[i] = true + continue + } + res[i].Set(&accumulator) + accumulator.Mul(&accumulator, &a[i]) + } + + accumulator.Inverse(&accumulator) + + for i := len(a) - 1; i >= 0; i-- { + if zeroes[i] { + continue + } + res[i].Mul(&res[i], &accumulator) + accumulator.Mul(&accumulator, &a[i]) + } + + return res +} + +// Div divides an element in E4 by an element in E4 +func (z *E4) Div(x *E4, y *E4) *E4 { + var r E4 + r.Inverse(y).Mul(x, &r) + return z.Set(&r) +} diff --git a/field/babybear/extensions/e4_test.go b/field/babybear/extensions/e4_test.go new file mode 100644 index 0000000000..69d43787f2 --- /dev/null +++ b/field/babybear/extensions/e4_test.go @@ -0,0 +1,300 @@ +package extensions + +import ( + "testing" + + "github.com/leanovate/gopter" + "github.com/leanovate/gopter/prop" +) + +// ------------------------------------------------------------ +// tests + +func TestE4ReceiverIsOperand(t *testing.T) { + + parameters := gopter.DefaultTestParameters() + parameters.MinSuccessfulTests = 100 + + properties := gopter.NewProperties(parameters) + + genA := GenE4() + genB := GenE4() + + properties.Property("[BABYBEAR] Having the receiver as operand (addition) should output the same result", prop.ForAll( + func(a, b *E4) bool { + var c, d E4 + d.Set(a) + c.Add(a, b) + a.Add(a, b) + b.Add(&d, b) + return a.Equal(b) && a.Equal(&c) && b.Equal(&c) + }, + genA, + genB, + )) + + properties.Property("[BABYBEAR] Having the receiver as operand (sub) should output the same result", prop.ForAll( + func(a, b *E4) bool { + var c, d E4 + d.Set(a) + c.Sub(a, b) + a.Sub(a, b) + b.Sub(&d, b) + return a.Equal(b) && a.Equal(&c) && b.Equal(&c) + }, + genA, + genB, + )) + + properties.Property("[BABYBEAR] Having the receiver as operand (mul) should output the same result", prop.ForAll( + func(a, b *E4) bool { + var c, d E4 + d.Set(a) + c.Mul(a, b) + a.Mul(a, b) + b.Mul(&d, b) + return a.Equal(b) && a.Equal(&c) && b.Equal(&c) + }, + genA, + genB, + )) + + properties.Property("[BABYBEAR] Having the receiver as operand (square) should output the same result", prop.ForAll( + func(a *E4) bool { + var b E4 + b.Square(a) + a.Square(a) + return a.Equal(&b) + }, + genA, + )) + + properties.Property("[BABYBEAR] Having the receiver as operand (double) should output the same result", prop.ForAll( + func(a *E4) bool { + var b E4 + b.Double(a) + a.Double(a) + return a.Equal(&b) + }, + genA, + )) + + properties.Property("[BABYBEAR] Having the receiver as operand (mul by non residue) should output the same result", prop.ForAll( + func(a *E4) bool { + var b E4 + b.MulByNonResidue(a) + a.MulByNonResidue(a) + return a.Equal(&b) + }, + genA, + )) + + properties.Property("[BABYBEAR] Having the receiver as operand (Inverse) should output the same result", prop.ForAll( + func(a *E4) bool { + var b E4 + b.Inverse(a) + a.Inverse(a) + return a.Equal(&b) + }, + genA, + )) + + properties.Property("[BABYBEAR] Having the receiver as operand (Conjugate) should output the same result", prop.ForAll( + func(a *E4) bool { + var b E4 + b.Conjugate(a) + a.Conjugate(a) + return a.Equal(&b) + }, + genA, + )) + + properties.Property("[BABYBEAR] Having the receiver as operand (Sqrt) should output the same result", prop.ForAll( + func(a *E4) bool { + var b, c, d, s E4 + + s.Square(a) + a.Set(&s) + b.Set(&s) + + a.Sqrt(a) + b.Sqrt(&b) + + c.Square(a) + d.Square(&b) + return c.Equal(&d) + }, + genA, + )) + + properties.TestingRun(t, gopter.ConsoleReporter(false)) +} + +func TestE4Ops(t *testing.T) { + + parameters := gopter.DefaultTestParameters() + parameters.MinSuccessfulTests = 100 + + properties := gopter.NewProperties(parameters) + + genA := GenE4() + genB := GenE4() + + properties.Property("[BABYBEAR] sub & add should leave an element invariant", prop.ForAll( + func(a, b *E4) bool { + var c E4 + c.Set(a) + c.Add(&c, b).Sub(&c, b) + return c.Equal(a) + }, + genA, + genB, + )) + + properties.Property("[BABYBEAR] mul & inverse should leave an element invariant", prop.ForAll( + func(a, b *E4) bool { + var c, d E4 + d.Inverse(b) + c.Set(a) + c.Mul(&c, b).Mul(&c, &d) + return c.Equal(a) + }, + genA, + genB, + )) + + properties.Property("[BABYBEAR] BatchInvertE4 should output the same result as Inverse", prop.ForAll( + func(a, b, c *E4) bool { + + batch := BatchInvertE4([]E4{*a, *b, *c}) + a.Inverse(a) + b.Inverse(b) + c.Inverse(c) + return a.Equal(&batch[0]) && b.Equal(&batch[1]) && c.Equal(&batch[2]) + }, + genA, + genA, + genB, + )) + + properties.Property("[BABYBEAR] inverse twice should leave an element invariant", prop.ForAll( + func(a *E4) bool { + var b E4 + b.Inverse(a).Inverse(&b) + return a.Equal(&b) + }, + genA, + )) + + properties.Property("[BABYBEAR] square and mul should output the same result", prop.ForAll( + func(a *E4) bool { + var b, c E4 + b.Mul(a, a) + c.Square(a) + return b.Equal(&c) + }, + genA, + )) + + properties.Property("[BABYBEAR] Legendre on square should output 1", prop.ForAll( + func(a *E4) bool { + var b E4 + b.Square(a) + c := b.Legendre() + return c == 1 + }, + genA, + )) + + properties.Property("[BABYBEAR] square(sqrt) should leave an element invariant", prop.ForAll( + func(a *E4) bool { + var b, c, d, e E4 + b.Square(a) + c.Sqrt(&b) + d.Square(&c) + e.Neg(a) + return (c.Equal(a) || c.Equal(&e)) && d.Equal(&b) + }, + genA, + )) + + properties.TestingRun(t, gopter.ConsoleReporter(false)) +} + +// ------------------------------------------------------------ +// benches + +func BenchmarkE4Add(b *testing.B) { + var a, c E4 + _, _ = a.SetRandom() + _, _ = c.SetRandom() + b.ResetTimer() + for i := 0; i < b.N; i++ { + a.Add(&a, &c) + } +} + +func BenchmarkE4Sub(b *testing.B) { + var a, c E4 + _, _ = a.SetRandom() + _, _ = c.SetRandom() + b.ResetTimer() + for i := 0; i < b.N; i++ { + a.Sub(&a, &c) + } +} + +func BenchmarkE4Mul(b *testing.B) { + var a, c E4 + _, _ = a.SetRandom() + _, _ = c.SetRandom() + b.ResetTimer() + for i := 0; i < b.N; i++ { + a.Mul(&a, &c) + } +} + +func BenchmarkE4Square(b *testing.B) { + var a E4 + _, _ = a.SetRandom() + b.ResetTimer() + for i := 0; i < b.N; i++ { + a.Square(&a) + } +} + +func BenchmarkE4Sqrt(b *testing.B) { + var a E4 + _, _ = a.SetRandom() + b.ResetTimer() + for i := 0; i < b.N; i++ { + a.Sqrt(&a) + } +} + +func BenchmarkE4Inverse(b *testing.B) { + var a E4 + _, _ = a.SetRandom() + b.ResetTimer() + for i := 0; i < b.N; i++ { + a.Inverse(&a) + } +} + +func BenchmarkE4MulNonRes(b *testing.B) { + var a E4 + _, _ = a.SetRandom() + b.ResetTimer() + for i := 0; i < b.N; i++ { + a.MulByNonResidue(&a) + } +} + +func BenchmarkE4Conjugate(b *testing.B) { + var a E4 + _, _ = a.SetRandom() + b.ResetTimer() + for i := 0; i < b.N; i++ { + a.Conjugate(&a) + } +} diff --git a/field/babybear/extensions/utils.go b/field/babybear/extensions/utils.go new file mode 100644 index 0000000000..1cb2425e1f --- /dev/null +++ b/field/babybear/extensions/utils.go @@ -0,0 +1,48 @@ +package extensions + +import ( + "math/big" + "sync" + + fr "github.com/consensys/gnark-crypto/field/babybear" + "github.com/leanovate/gopter" +) + +var bigIntPool = sync.Pool{ + New: func() interface{} { + return new(big.Int) + }, +} + +// Fr generates an Fr element +func GenFr() gopter.Gen { + return func(genParams *gopter.GenParameters) *gopter.GenResult { + var elmt fr.Element + + if _, err := elmt.SetRandom(); err != nil { + panic(err) + } + genResult := gopter.NewGenResult(elmt, gopter.NoShrinker) + return genResult + } +} + +// E2 generates an E2 elmt +func GenE2() gopter.Gen { + return gopter.CombineGens( + GenFr(), + GenFr(), + ).Map(func(values []interface{}) *E2 { + return &E2{A0: values[0].(fr.Element), A1: values[1].(fr.Element)} + }) +} + +// E4 generates an E4 elmt +func GenE4() gopter.Gen { + return gopter.CombineGens( + GenE2(), + GenE2(), + ).Map(func(values []interface{}) *E4 { + return &E4{B0: *values[0].(*E2), B1: *values[1].(*E2)} + }) +} diff --git a/field/generator/config/field_config.go b/field/generator/config/field_config.go index 5cbc09dac8..a8485cb8e3 100644 --- a/field/generator/config/field_config.go +++ b/field/generator/config/field_config.go @@ -42,7 +42,7 @@ type Field struct { QMinusOneHalvedP []uint64 // ((q-1) / 2 ) + 1 Mu uint64 // mu = 2^288 / q for 4.5 word barrett reduction RSquare []uint64 - One, Thirteen []uint64 + One, Eleven, Thirteen []uint64 LegendreExponent string // big.Int to base16 string NoCarry bool NoCarrySquare bool // used if NoCarry is set, but some op may overflow in square optimization @@ -182,6 +182,13 @@ func NewFieldConfig(packageName, elementName, modulus string, useAddChain bool) one.Lsh(&one, uint(F.NbWords)*radix).Mod(&one, &bModulus) F.One = toUint64Slice(&one, F.NbWords) + { + var n big.Int + n.SetUint64(11) + n.Lsh(&n, uint(F.NbWords)*radix).Mod(&n, &bModulus) + F.Eleven = toUint64Slice(&n, F.NbWords) + } + { var n big.Int n.SetUint64(13) diff --git a/field/generator/internal/templates/element/ops_asm.go b/field/generator/internal/templates/element/ops_asm.go index d82cfead74..db62884e4e 100644 --- a/field/generator/internal/templates/element/ops_asm.go +++ b/field/generator/internal/templates/element/ops_asm.go @@ -19,6 +19,9 @@ func MulBy5(x *{{.ElementName}}) //go:noescape func MulBy13(x *{{.ElementName}}) +//go:noescape +func MulBy13(x *{{.ElementName}}) + //go:noescape func mul(res,x,y *{{.ElementName}}) @@ -93,7 +96,7 @@ func (z *{{.ElementName}}) Square(x *{{.ElementName}}) *{{.ElementName}} { } -{{ $mulConsts := list 3 5 13 }} +{{ $mulConsts := list 3 5 11 13 }} {{- range $i := $mulConsts }} // MulBy{{$i}} x *= {{$i}} (mod q) @@ -109,6 +112,12 @@ func MulBy{{$i}}(x *{{$.ElementName}}) { {{- else if eq $i 5}} _x := *x x.Double(x).Double(x).Add(x, &_x) + {{- else if eq $i 11}} + var y = {{$.ElementName}}{ + {{- range $i := $.Eleven}} + {{$i}},{{end}} + } + x.Mul(x, &y) {{- else if eq $i 13}} var y = {{$.ElementName}}{ {{- range $i := $.Thirteen}} diff --git a/field/generator/internal/templates/element/ops_purego.go b/field/generator/internal/templates/element/ops_purego.go index 31d45c8d92..a9793c87c7 100644 --- a/field/generator/internal/templates/element/ops_purego.go +++ b/field/generator/internal/templates/element/ops_purego.go @@ -6,7 +6,7 @@ const OpsNoAsm = ` import "math/bits" {{- end}} -{{ $mulConsts := list 3 5 13 }} +{{ $mulConsts := list 3 5 11 13 }} {{- range $i := $mulConsts }} // MulBy{{$i}} x *= {{$i}} (mod q) @@ -22,6 +22,12 @@ func MulBy{{$i}}(x *{{$.ElementName}}) { {{- else if eq $i 5}} _x := *x x.Double(x).Double(x).Add(x, &_x) + {{- else if eq $i 11}} + var y = {{$.ElementName}}{ + {{- range $i := $.Eleven}} + {{$i}},{{end}} + } + x.Mul(x, &y) {{- else if eq $i 13}} var y = {{$.ElementName}}{ {{- range $i := $.Thirteen}} diff --git a/field/goldilocks/element_purego.go b/field/goldilocks/element_purego.go index 47da790b25..5e05644c8b 100644 --- a/field/goldilocks/element_purego.go +++ b/field/goldilocks/element_purego.go @@ -21,6 +21,13 @@ func MulBy5(x *Element) { x.Mul(x, &y) } +// MulBy11 x *= 11 (mod q) +func MulBy11(x *Element) { + var y Element + y.SetUint64(11) + x.Mul(x, &y) +} + // MulBy13 x *= 13 (mod q) func MulBy13(x *Element) { var y Element diff --git a/field/koalabear/element_purego.go b/field/koalabear/element_purego.go index cfcaaade6a..1627344a3d 100644 --- a/field/koalabear/element_purego.go +++ b/field/koalabear/element_purego.go @@ -19,6 +19,13 @@ func MulBy5(x *Element) { x.Mul(x, &y) } +// MulBy11 x *= 11 (mod q) +func MulBy11(x *Element) { + var y Element + y.SetUint64(11) + x.Mul(x, &y) +} + // MulBy13 x *= 13 (mod q) func MulBy13(x *Element) { var y Element From 25d0e0bc7ebb396f39780911b968f7de9320dca6 Mon Sep 17 00:00:00 2001 From: Youssef El Housni Date: Tue, 18 Feb 2025 16:04:35 -0500 Subject: [PATCH 6/9] fix: generify MulBy11 --- ecc/bls12-377/fp/element_amd64.go | 3 +++ ecc/bls12-377/fp/element_arm64.go | 13 +++++++++++++ ecc/bls12-377/fp/element_purego.go | 13 +++++++++++++ ecc/bls12-377/fr/element_amd64.go | 3 +++ ecc/bls12-377/fr/element_arm64.go | 11 +++++++++++ ecc/bls12-377/fr/element_purego.go | 11 +++++++++++ ecc/bls12-381/fp/element_amd64.go | 3 +++ ecc/bls12-381/fp/element_arm64.go | 13 +++++++++++++ ecc/bls12-381/fp/element_purego.go | 13 +++++++++++++ ecc/bls12-381/fr/element_amd64.go | 3 +++ ecc/bls12-381/fr/element_arm64.go | 11 +++++++++++ ecc/bls12-381/fr/element_purego.go | 11 +++++++++++ ecc/bls24-315/fp/element_amd64.go | 3 +++ ecc/bls24-315/fp/element_purego.go | 12 ++++++++++++ ecc/bls24-315/fr/element_amd64.go | 3 +++ ecc/bls24-315/fr/element_arm64.go | 11 +++++++++++ ecc/bls24-315/fr/element_purego.go | 11 +++++++++++ ecc/bls24-317/fp/element_amd64.go | 3 +++ ecc/bls24-317/fp/element_purego.go | 12 ++++++++++++ ecc/bls24-317/fr/element_amd64.go | 3 +++ ecc/bls24-317/fr/element_arm64.go | 11 +++++++++++ ecc/bls24-317/fr/element_purego.go | 11 +++++++++++ ecc/bn254/fp/element_amd64.go | 3 +++ ecc/bn254/fp/element_arm64.go | 11 +++++++++++ ecc/bn254/fp/element_purego.go | 11 +++++++++++ ecc/bn254/fr/element_amd64.go | 3 +++ ecc/bn254/fr/element_arm64.go | 11 +++++++++++ ecc/bn254/fr/element_purego.go | 11 +++++++++++ ecc/bw6-633/fp/element_amd64.go | 3 +++ ecc/bw6-633/fp/element_arm64.go | 17 +++++++++++++++++ ecc/bw6-633/fp/element_purego.go | 17 +++++++++++++++++ ecc/bw6-633/fr/element_amd64.go | 3 +++ ecc/bw6-633/fr/element_purego.go | 12 ++++++++++++ ecc/bw6-761/fp/element_amd64.go | 3 +++ ecc/bw6-761/fp/element_arm64.go | 19 +++++++++++++++++++ ecc/bw6-761/fp/element_purego.go | 19 +++++++++++++++++++ ecc/bw6-761/fr/element_amd64.go | 3 +++ ecc/bw6-761/fr/element_arm64.go | 13 +++++++++++++ ecc/bw6-761/fr/element_purego.go | 13 +++++++++++++ ecc/grumpkin/fp/element_amd64.go | 3 +++ ecc/grumpkin/fp/element_arm64.go | 11 +++++++++++ ecc/grumpkin/fp/element_purego.go | 11 +++++++++++ ecc/grumpkin/fr/element_amd64.go | 3 +++ ecc/grumpkin/fr/element_arm64.go | 11 +++++++++++ ecc/grumpkin/fr/element_purego.go | 11 +++++++++++ ecc/secp256k1/fp/element_purego.go | 11 +++++++++++ ecc/secp256k1/fr/element_purego.go | 11 +++++++++++ ecc/stark-curve/fp/element_amd64.go | 3 +++ ecc/stark-curve/fp/element_arm64.go | 11 +++++++++++ ecc/stark-curve/fp/element_purego.go | 11 +++++++++++ ecc/stark-curve/fr/element_amd64.go | 3 +++ ecc/stark-curve/fr/element_arm64.go | 11 +++++++++++ ecc/stark-curve/fr/element_purego.go | 11 +++++++++++ field/babybear/extensions/e2_amd64.go | 6 +++--- .../internal/templates/element/ops_asm.go | 2 +- 55 files changed, 486 insertions(+), 4 deletions(-) diff --git a/ecc/bls12-377/fp/element_amd64.go b/ecc/bls12-377/fp/element_amd64.go index ff2159178d..1ce1d184ce 100644 --- a/ecc/bls12-377/fp/element_amd64.go +++ b/ecc/bls12-377/fp/element_amd64.go @@ -20,6 +20,9 @@ func MulBy3(x *Element) //go:noescape func MulBy5(x *Element) +//go:noescape +func MulBy11(x *Element) + //go:noescape func MulBy13(x *Element) diff --git a/ecc/bls12-377/fp/element_arm64.go b/ecc/bls12-377/fp/element_arm64.go index a4510da8eb..e65783c173 100644 --- a/ecc/bls12-377/fp/element_arm64.go +++ b/ecc/bls12-377/fp/element_arm64.go @@ -51,6 +51,19 @@ func MulBy5(x *Element) { x.Double(x).Double(x).Add(x, &_x) } +// MulBy11 x *= 11 (mod q) +func MulBy11(x *Element) { + var y = Element{ + 10358208774207961461, + 4081601403594734745, + 9046765978545153897, + 18300367227737147024, + 18145387698699229771, + 74511027426447328, + } + x.Mul(x, &y) +} + // MulBy13 x *= 13 (mod q) func MulBy13(x *Element) { var y = Element{ diff --git a/ecc/bls12-377/fp/element_purego.go b/ecc/bls12-377/fp/element_purego.go index 8a2e93e999..086e226f2c 100644 --- a/ecc/bls12-377/fp/element_purego.go +++ b/ecc/bls12-377/fp/element_purego.go @@ -21,6 +21,19 @@ func MulBy5(x *Element) { x.Double(x).Double(x).Add(x, &_x) } +// MulBy11 x *= 11 (mod q) +func MulBy11(x *Element) { + var y = Element{ + 10358208774207961461, + 4081601403594734745, + 9046765978545153897, + 18300367227737147024, + 18145387698699229771, + 74511027426447328, + } + x.Mul(x, &y) +} + // MulBy13 x *= 13 (mod q) func MulBy13(x *Element) { var y = Element{ diff --git a/ecc/bls12-377/fr/element_amd64.go b/ecc/bls12-377/fr/element_amd64.go index c282ebc9fc..0d47036fea 100644 --- a/ecc/bls12-377/fr/element_amd64.go +++ b/ecc/bls12-377/fr/element_amd64.go @@ -20,6 +20,9 @@ func MulBy3(x *Element) //go:noescape func MulBy5(x *Element) +//go:noescape +func MulBy11(x *Element) + //go:noescape func MulBy13(x *Element) diff --git a/ecc/bls12-377/fr/element_arm64.go b/ecc/bls12-377/fr/element_arm64.go index fc80023171..d70ea940e9 100644 --- a/ecc/bls12-377/fr/element_arm64.go +++ b/ecc/bls12-377/fr/element_arm64.go @@ -51,6 +51,17 @@ func MulBy5(x *Element) { x.Double(x).Double(x).Add(x, &_x) } +// MulBy11 x *= 11 (mod q) +func MulBy11(x *Element) { + var y = Element{ + 1855201571499933546, + 8511318076631809892, + 6222514765367795509, + 1122129207579058019, + } + x.Mul(x, &y) +} + // MulBy13 x *= 13 (mod q) func MulBy13(x *Element) { var y = Element{ diff --git a/ecc/bls12-377/fr/element_purego.go b/ecc/bls12-377/fr/element_purego.go index 537648f3d1..5dfdfad5f1 100644 --- a/ecc/bls12-377/fr/element_purego.go +++ b/ecc/bls12-377/fr/element_purego.go @@ -21,6 +21,17 @@ func MulBy5(x *Element) { x.Double(x).Double(x).Add(x, &_x) } +// MulBy11 x *= 11 (mod q) +func MulBy11(x *Element) { + var y = Element{ + 1855201571499933546, + 8511318076631809892, + 6222514765367795509, + 1122129207579058019, + } + x.Mul(x, &y) +} + // MulBy13 x *= 13 (mod q) func MulBy13(x *Element) { var y = Element{ diff --git a/ecc/bls12-381/fp/element_amd64.go b/ecc/bls12-381/fp/element_amd64.go index ff2159178d..1ce1d184ce 100644 --- a/ecc/bls12-381/fp/element_amd64.go +++ b/ecc/bls12-381/fp/element_amd64.go @@ -20,6 +20,9 @@ func MulBy3(x *Element) //go:noescape func MulBy5(x *Element) +//go:noescape +func MulBy11(x *Element) + //go:noescape func MulBy13(x *Element) diff --git a/ecc/bls12-381/fp/element_arm64.go b/ecc/bls12-381/fp/element_arm64.go index 6cbd040cdb..1bab17d214 100644 --- a/ecc/bls12-381/fp/element_arm64.go +++ b/ecc/bls12-381/fp/element_arm64.go @@ -51,6 +51,19 @@ func MulBy5(x *Element) { x.Double(x).Double(x).Add(x, &_x) } +// MulBy11 x *= 11 (mod q) +func MulBy11(x *Element) { + var y = Element{ + 9830232086645309404, + 1112389714365644829, + 8603885298299447491, + 11361495444721768256, + 5788602283869803809, + 543934104870762216, + } + x.Mul(x, &y) +} + // MulBy13 x *= 13 (mod q) func MulBy13(x *Element) { var y = Element{ diff --git a/ecc/bls12-381/fp/element_purego.go b/ecc/bls12-381/fp/element_purego.go index f3170f77e0..51fa620cc5 100644 --- a/ecc/bls12-381/fp/element_purego.go +++ b/ecc/bls12-381/fp/element_purego.go @@ -21,6 +21,19 @@ func MulBy5(x *Element) { x.Double(x).Double(x).Add(x, &_x) } +// MulBy11 x *= 11 (mod q) +func MulBy11(x *Element) { + var y = Element{ + 9830232086645309404, + 1112389714365644829, + 8603885298299447491, + 11361495444721768256, + 5788602283869803809, + 543934104870762216, + } + x.Mul(x, &y) +} + // MulBy13 x *= 13 (mod q) func MulBy13(x *Element) { var y = Element{ diff --git a/ecc/bls12-381/fr/element_amd64.go b/ecc/bls12-381/fr/element_amd64.go index c282ebc9fc..0d47036fea 100644 --- a/ecc/bls12-381/fr/element_amd64.go +++ b/ecc/bls12-381/fr/element_amd64.go @@ -20,6 +20,9 @@ func MulBy3(x *Element) //go:noescape func MulBy5(x *Element) +//go:noescape +func MulBy11(x *Element) + //go:noescape func MulBy13(x *Element) diff --git a/ecc/bls12-381/fr/element_arm64.go b/ecc/bls12-381/fr/element_arm64.go index e8b6cb4d0f..4c0a693822 100644 --- a/ecc/bls12-381/fr/element_arm64.go +++ b/ecc/bls12-381/fr/element_arm64.go @@ -51,6 +51,17 @@ func MulBy5(x *Element) { x.Double(x).Double(x).Add(x, &_x) } +// MulBy11 x *= 11 (mod q) +func MulBy11(x *Element) { + var y = Element{ + 103079215080, + 2754126784762437656, + 3644466801193238400, + 2429780183658283323, + } + x.Mul(x, &y) +} + // MulBy13 x *= 13 (mod q) func MulBy13(x *Element) { var y = Element{ diff --git a/ecc/bls12-381/fr/element_purego.go b/ecc/bls12-381/fr/element_purego.go index 42ba2b9bbc..7a7f32273c 100644 --- a/ecc/bls12-381/fr/element_purego.go +++ b/ecc/bls12-381/fr/element_purego.go @@ -21,6 +21,17 @@ func MulBy5(x *Element) { x.Double(x).Double(x).Add(x, &_x) } +// MulBy11 x *= 11 (mod q) +func MulBy11(x *Element) { + var y = Element{ + 103079215080, + 2754126784762437656, + 3644466801193238400, + 2429780183658283323, + } + x.Mul(x, &y) +} + // MulBy13 x *= 13 (mod q) func MulBy13(x *Element) { var y = Element{ diff --git a/ecc/bls24-315/fp/element_amd64.go b/ecc/bls24-315/fp/element_amd64.go index f44ea0f280..58d6cab877 100644 --- a/ecc/bls24-315/fp/element_amd64.go +++ b/ecc/bls24-315/fp/element_amd64.go @@ -20,6 +20,9 @@ func MulBy3(x *Element) //go:noescape func MulBy5(x *Element) +//go:noescape +func MulBy11(x *Element) + //go:noescape func MulBy13(x *Element) diff --git a/ecc/bls24-315/fp/element_purego.go b/ecc/bls24-315/fp/element_purego.go index ce12129cb7..e6cd7b87f2 100644 --- a/ecc/bls24-315/fp/element_purego.go +++ b/ecc/bls24-315/fp/element_purego.go @@ -21,6 +21,18 @@ func MulBy5(x *Element) { x.Double(x).Double(x).Add(x, &_x) } +// MulBy11 x *= 11 (mod q) +func MulBy11(x *Element) { + var y = Element{ + 12060944069680954801, + 6533417917463940959, + 13731636354790192199, + 12113897946221733884, + 260104589233568614, + } + x.Mul(x, &y) +} + // MulBy13 x *= 13 (mod q) func MulBy13(x *Element) { var y = Element{ diff --git a/ecc/bls24-315/fr/element_amd64.go b/ecc/bls24-315/fr/element_amd64.go index c282ebc9fc..0d47036fea 100644 --- a/ecc/bls24-315/fr/element_amd64.go +++ b/ecc/bls24-315/fr/element_amd64.go @@ -20,6 +20,9 @@ func MulBy3(x *Element) //go:noescape func MulBy5(x *Element) +//go:noescape +func MulBy11(x *Element) + //go:noescape func MulBy13(x *Element) diff --git a/ecc/bls24-315/fr/element_arm64.go b/ecc/bls24-315/fr/element_arm64.go index 1adc4b91e8..9c430a1850 100644 --- a/ecc/bls24-315/fr/element_arm64.go +++ b/ecc/bls24-315/fr/element_arm64.go @@ -51,6 +51,17 @@ func MulBy5(x *Element) { x.Double(x).Double(x).Add(x, &_x) } +// MulBy11 x *= 11 (mod q) +func MulBy11(x *Element) { + var y = Element{ + 16738451865775112082, + 13515472034404387580, + 12502420588315234905, + 1352523014138543989, + } + x.Mul(x, &y) +} + // MulBy13 x *= 13 (mod q) func MulBy13(x *Element) { var y = Element{ diff --git a/ecc/bls24-315/fr/element_purego.go b/ecc/bls24-315/fr/element_purego.go index 6bf56f886f..0270404dee 100644 --- a/ecc/bls24-315/fr/element_purego.go +++ b/ecc/bls24-315/fr/element_purego.go @@ -21,6 +21,17 @@ func MulBy5(x *Element) { x.Double(x).Double(x).Add(x, &_x) } +// MulBy11 x *= 11 (mod q) +func MulBy11(x *Element) { + var y = Element{ + 16738451865775112082, + 13515472034404387580, + 12502420588315234905, + 1352523014138543989, + } + x.Mul(x, &y) +} + // MulBy13 x *= 13 (mod q) func MulBy13(x *Element) { var y = Element{ diff --git a/ecc/bls24-317/fp/element_amd64.go b/ecc/bls24-317/fp/element_amd64.go index f44ea0f280..58d6cab877 100644 --- a/ecc/bls24-317/fp/element_amd64.go +++ b/ecc/bls24-317/fp/element_amd64.go @@ -20,6 +20,9 @@ func MulBy3(x *Element) //go:noescape func MulBy5(x *Element) +//go:noescape +func MulBy11(x *Element) + //go:noescape func MulBy13(x *Element) diff --git a/ecc/bls24-317/fp/element_purego.go b/ecc/bls24-317/fp/element_purego.go index b5c1224c69..c47cf086ad 100644 --- a/ecc/bls24-317/fp/element_purego.go +++ b/ecc/bls24-317/fp/element_purego.go @@ -21,6 +21,18 @@ func MulBy5(x *Element) { x.Double(x).Double(x).Add(x, &_x) } +// MulBy11 x *= 11 (mod q) +func MulBy11(x *Element) { + var y = Element{ + 969643881593263388, + 10706493019329091321, + 15007745612662235239, + 533456672378067364, + 313053900571923917, + } + x.Mul(x, &y) +} + // MulBy13 x *= 13 (mod q) func MulBy13(x *Element) { var y = Element{ diff --git a/ecc/bls24-317/fr/element_amd64.go b/ecc/bls24-317/fr/element_amd64.go index c282ebc9fc..0d47036fea 100644 --- a/ecc/bls24-317/fr/element_amd64.go +++ b/ecc/bls24-317/fr/element_amd64.go @@ -20,6 +20,9 @@ func MulBy3(x *Element) //go:noescape func MulBy5(x *Element) +//go:noescape +func MulBy11(x *Element) + //go:noescape func MulBy13(x *Element) diff --git a/ecc/bls24-317/fr/element_arm64.go b/ecc/bls24-317/fr/element_arm64.go index 9610c74eda..06d2903cf4 100644 --- a/ecc/bls24-317/fr/element_arm64.go +++ b/ecc/bls24-317/fr/element_arm64.go @@ -51,6 +51,17 @@ func MulBy5(x *Element) { x.Double(x).Double(x).Add(x, &_x) } +// MulBy11 x *= 11 (mod q) +func MulBy11(x *Element) { + var y = Element{ + 10376293541461622743, + 7089204225672392271, + 10644163330234916682, + 1284003869223737804, + } + x.Mul(x, &y) +} + // MulBy13 x *= 13 (mod q) func MulBy13(x *Element) { var y = Element{ diff --git a/ecc/bls24-317/fr/element_purego.go b/ecc/bls24-317/fr/element_purego.go index 7c6745f270..cb8f035425 100644 --- a/ecc/bls24-317/fr/element_purego.go +++ b/ecc/bls24-317/fr/element_purego.go @@ -21,6 +21,17 @@ func MulBy5(x *Element) { x.Double(x).Double(x).Add(x, &_x) } +// MulBy11 x *= 11 (mod q) +func MulBy11(x *Element) { + var y = Element{ + 10376293541461622743, + 7089204225672392271, + 10644163330234916682, + 1284003869223737804, + } + x.Mul(x, &y) +} + // MulBy13 x *= 13 (mod q) func MulBy13(x *Element) { var y = Element{ diff --git a/ecc/bn254/fp/element_amd64.go b/ecc/bn254/fp/element_amd64.go index e02a9d04c2..339df6f656 100644 --- a/ecc/bn254/fp/element_amd64.go +++ b/ecc/bn254/fp/element_amd64.go @@ -20,6 +20,9 @@ func MulBy3(x *Element) //go:noescape func MulBy5(x *Element) +//go:noescape +func MulBy11(x *Element) + //go:noescape func MulBy13(x *Element) diff --git a/ecc/bn254/fp/element_arm64.go b/ecc/bn254/fp/element_arm64.go index 4d030715d6..b543f3a5e7 100644 --- a/ecc/bn254/fp/element_arm64.go +++ b/ecc/bn254/fp/element_arm64.go @@ -51,6 +51,17 @@ func MulBy5(x *Element) { x.Double(x).Double(x).Add(x, &_x) } +// MulBy11 x *= 11 (mod q) +func MulBy11(x *Element) { + var y = Element{ + 6962638497713659370, + 12442842200117091328, + 4454117921868872395, + 668285336232769164, + } + x.Mul(x, &y) +} + // MulBy13 x *= 13 (mod q) func MulBy13(x *Element) { var y = Element{ diff --git a/ecc/bn254/fp/element_purego.go b/ecc/bn254/fp/element_purego.go index 69565d890b..47d5834b0d 100644 --- a/ecc/bn254/fp/element_purego.go +++ b/ecc/bn254/fp/element_purego.go @@ -21,6 +21,17 @@ func MulBy5(x *Element) { x.Double(x).Double(x).Add(x, &_x) } +// MulBy11 x *= 11 (mod q) +func MulBy11(x *Element) { + var y = Element{ + 6962638497713659370, + 12442842200117091328, + 4454117921868872395, + 668285336232769164, + } + x.Mul(x, &y) +} + // MulBy13 x *= 13 (mod q) func MulBy13(x *Element) { var y = Element{ diff --git a/ecc/bn254/fr/element_amd64.go b/ecc/bn254/fr/element_amd64.go index c282ebc9fc..0d47036fea 100644 --- a/ecc/bn254/fr/element_amd64.go +++ b/ecc/bn254/fr/element_amd64.go @@ -20,6 +20,9 @@ func MulBy3(x *Element) //go:noescape func MulBy5(x *Element) +//go:noescape +func MulBy11(x *Element) + //go:noescape func MulBy13(x *Element) diff --git a/ecc/bn254/fr/element_arm64.go b/ecc/bn254/fr/element_arm64.go index b99b03a7e9..ed13fb0c7a 100644 --- a/ecc/bn254/fr/element_arm64.go +++ b/ecc/bn254/fr/element_arm64.go @@ -51,6 +51,17 @@ func MulBy5(x *Element) { x.Double(x).Double(x).Add(x, &_x) } +// MulBy11 x *= 11 (mod q) +func MulBy11(x *Element) { + var y = Element{ + 11443185389230096326, + 16446406505298427670, + 4454117921868872420, + 668285336232769164, + } + x.Mul(x, &y) +} + // MulBy13 x *= 13 (mod q) func MulBy13(x *Element) { var y = Element{ diff --git a/ecc/bn254/fr/element_purego.go b/ecc/bn254/fr/element_purego.go index 8b6bab2e09..a8f4aa372e 100644 --- a/ecc/bn254/fr/element_purego.go +++ b/ecc/bn254/fr/element_purego.go @@ -21,6 +21,17 @@ func MulBy5(x *Element) { x.Double(x).Double(x).Add(x, &_x) } +// MulBy11 x *= 11 (mod q) +func MulBy11(x *Element) { + var y = Element{ + 11443185389230096326, + 16446406505298427670, + 4454117921868872420, + 668285336232769164, + } + x.Mul(x, &y) +} + // MulBy13 x *= 13 (mod q) func MulBy13(x *Element) { var y = Element{ diff --git a/ecc/bw6-633/fp/element_amd64.go b/ecc/bw6-633/fp/element_amd64.go index cdc4e7d2cc..5f400bae79 100644 --- a/ecc/bw6-633/fp/element_amd64.go +++ b/ecc/bw6-633/fp/element_amd64.go @@ -20,6 +20,9 @@ func MulBy3(x *Element) //go:noescape func MulBy5(x *Element) +//go:noescape +func MulBy11(x *Element) + //go:noescape func MulBy13(x *Element) diff --git a/ecc/bw6-633/fp/element_arm64.go b/ecc/bw6-633/fp/element_arm64.go index 1a85c82439..3a4f73fcc4 100644 --- a/ecc/bw6-633/fp/element_arm64.go +++ b/ecc/bw6-633/fp/element_arm64.go @@ -51,6 +51,23 @@ func MulBy5(x *Element) { x.Double(x).Double(x).Add(x, &_x) } +// MulBy11 x *= 11 (mod q) +func MulBy11(x *Element) { + var y = Element{ + 6130771042861286320, + 11947466704102345269, + 5006184736040647654, + 10738967583325648129, + 6155303802163134778, + 6459686480506411032, + 14448065740527999419, + 1019798761927372322, + 5080373183861200608, + 66158761009468389, + } + x.Mul(x, &y) +} + // MulBy13 x *= 13 (mod q) func MulBy13(x *Element) { var y = Element{ diff --git a/ecc/bw6-633/fp/element_purego.go b/ecc/bw6-633/fp/element_purego.go index 0bf06ee060..1c5c4719ef 100644 --- a/ecc/bw6-633/fp/element_purego.go +++ b/ecc/bw6-633/fp/element_purego.go @@ -21,6 +21,23 @@ func MulBy5(x *Element) { x.Double(x).Double(x).Add(x, &_x) } +// MulBy11 x *= 11 (mod q) +func MulBy11(x *Element) { + var y = Element{ + 6130771042861286320, + 11947466704102345269, + 5006184736040647654, + 10738967583325648129, + 6155303802163134778, + 6459686480506411032, + 14448065740527999419, + 1019798761927372322, + 5080373183861200608, + 66158761009468389, + } + x.Mul(x, &y) +} + // MulBy13 x *= 13 (mod q) func MulBy13(x *Element) { var y = Element{ diff --git a/ecc/bw6-633/fr/element_amd64.go b/ecc/bw6-633/fr/element_amd64.go index 8577a5d289..5ad10bda95 100644 --- a/ecc/bw6-633/fr/element_amd64.go +++ b/ecc/bw6-633/fr/element_amd64.go @@ -20,6 +20,9 @@ func MulBy3(x *Element) //go:noescape func MulBy5(x *Element) +//go:noescape +func MulBy11(x *Element) + //go:noescape func MulBy13(x *Element) diff --git a/ecc/bw6-633/fr/element_purego.go b/ecc/bw6-633/fr/element_purego.go index 08da5bd7f8..eb3ed64910 100644 --- a/ecc/bw6-633/fr/element_purego.go +++ b/ecc/bw6-633/fr/element_purego.go @@ -21,6 +21,18 @@ func MulBy5(x *Element) { x.Double(x).Double(x).Add(x, &_x) } +// MulBy11 x *= 11 (mod q) +func MulBy11(x *Element) { + var y = Element{ + 12060944069680954801, + 6533417917463940959, + 13731636354790192199, + 12113897946221733884, + 260104589233568614, + } + x.Mul(x, &y) +} + // MulBy13 x *= 13 (mod q) func MulBy13(x *Element) { var y = Element{ diff --git a/ecc/bw6-761/fp/element_amd64.go b/ecc/bw6-761/fp/element_amd64.go index 72f398ecf0..d6bdef8f4b 100644 --- a/ecc/bw6-761/fp/element_amd64.go +++ b/ecc/bw6-761/fp/element_amd64.go @@ -20,6 +20,9 @@ func MulBy3(x *Element) //go:noescape func MulBy5(x *Element) +//go:noescape +func MulBy11(x *Element) + //go:noescape func MulBy13(x *Element) diff --git a/ecc/bw6-761/fp/element_arm64.go b/ecc/bw6-761/fp/element_arm64.go index bb6a6a7769..1d17426266 100644 --- a/ecc/bw6-761/fp/element_arm64.go +++ b/ecc/bw6-761/fp/element_arm64.go @@ -51,6 +51,25 @@ func MulBy5(x *Element) { x.Double(x).Double(x).Add(x, &_x) } +// MulBy11 x *= 11 (mod q) +func MulBy11(x *Element) { + var y = Element{ + 4056054414400208518, + 3320816571827031140, + 10263935383895698150, + 11003897938091601562, + 15597443347325643510, + 13135057492086854609, + 2659919018052618801, + 3683105852685266909, + 6137961753831301777, + 15077955943918945393, + 14961510259660508891, + 8138608324875079, + } + x.Mul(x, &y) +} + // MulBy13 x *= 13 (mod q) func MulBy13(x *Element) { var y = Element{ diff --git a/ecc/bw6-761/fp/element_purego.go b/ecc/bw6-761/fp/element_purego.go index 8c78ab1700..763cca7036 100644 --- a/ecc/bw6-761/fp/element_purego.go +++ b/ecc/bw6-761/fp/element_purego.go @@ -21,6 +21,25 @@ func MulBy5(x *Element) { x.Double(x).Double(x).Add(x, &_x) } +// MulBy11 x *= 11 (mod q) +func MulBy11(x *Element) { + var y = Element{ + 4056054414400208518, + 3320816571827031140, + 10263935383895698150, + 11003897938091601562, + 15597443347325643510, + 13135057492086854609, + 2659919018052618801, + 3683105852685266909, + 6137961753831301777, + 15077955943918945393, + 14961510259660508891, + 8138608324875079, + } + x.Mul(x, &y) +} + // MulBy13 x *= 13 (mod q) func MulBy13(x *Element) { var y = Element{ diff --git a/ecc/bw6-761/fr/element_amd64.go b/ecc/bw6-761/fr/element_amd64.go index 20f1f9a3f0..8e6398c7e9 100644 --- a/ecc/bw6-761/fr/element_amd64.go +++ b/ecc/bw6-761/fr/element_amd64.go @@ -20,6 +20,9 @@ func MulBy3(x *Element) //go:noescape func MulBy5(x *Element) +//go:noescape +func MulBy11(x *Element) + //go:noescape func MulBy13(x *Element) diff --git a/ecc/bw6-761/fr/element_arm64.go b/ecc/bw6-761/fr/element_arm64.go index f82cdfccd8..023ae341f2 100644 --- a/ecc/bw6-761/fr/element_arm64.go +++ b/ecc/bw6-761/fr/element_arm64.go @@ -51,6 +51,19 @@ func MulBy5(x *Element) { x.Double(x).Double(x).Add(x, &_x) } +// MulBy11 x *= 11 (mod q) +func MulBy11(x *Element) { + var y = Element{ + 10358208774207961461, + 4081601403594734745, + 9046765978545153897, + 18300367227737147024, + 18145387698699229771, + 74511027426447328, + } + x.Mul(x, &y) +} + // MulBy13 x *= 13 (mod q) func MulBy13(x *Element) { var y = Element{ diff --git a/ecc/bw6-761/fr/element_purego.go b/ecc/bw6-761/fr/element_purego.go index 2c60f3c457..b68970870d 100644 --- a/ecc/bw6-761/fr/element_purego.go +++ b/ecc/bw6-761/fr/element_purego.go @@ -21,6 +21,19 @@ func MulBy5(x *Element) { x.Double(x).Double(x).Add(x, &_x) } +// MulBy11 x *= 11 (mod q) +func MulBy11(x *Element) { + var y = Element{ + 10358208774207961461, + 4081601403594734745, + 9046765978545153897, + 18300367227737147024, + 18145387698699229771, + 74511027426447328, + } + x.Mul(x, &y) +} + // MulBy13 x *= 13 (mod q) func MulBy13(x *Element) { var y = Element{ diff --git a/ecc/grumpkin/fp/element_amd64.go b/ecc/grumpkin/fp/element_amd64.go index e02a9d04c2..339df6f656 100644 --- a/ecc/grumpkin/fp/element_amd64.go +++ b/ecc/grumpkin/fp/element_amd64.go @@ -20,6 +20,9 @@ func MulBy3(x *Element) //go:noescape func MulBy5(x *Element) +//go:noescape +func MulBy11(x *Element) + //go:noescape func MulBy13(x *Element) diff --git a/ecc/grumpkin/fp/element_arm64.go b/ecc/grumpkin/fp/element_arm64.go index 6a41dba9de..bfdaa68a63 100644 --- a/ecc/grumpkin/fp/element_arm64.go +++ b/ecc/grumpkin/fp/element_arm64.go @@ -51,6 +51,17 @@ func MulBy5(x *Element) { x.Double(x).Double(x).Add(x, &_x) } +// MulBy11 x *= 11 (mod q) +func MulBy11(x *Element) { + var y = Element{ + 11443185389230096326, + 16446406505298427670, + 4454117921868872420, + 668285336232769164, + } + x.Mul(x, &y) +} + // MulBy13 x *= 13 (mod q) func MulBy13(x *Element) { var y = Element{ diff --git a/ecc/grumpkin/fp/element_purego.go b/ecc/grumpkin/fp/element_purego.go index 247946286b..5e5b436a58 100644 --- a/ecc/grumpkin/fp/element_purego.go +++ b/ecc/grumpkin/fp/element_purego.go @@ -21,6 +21,17 @@ func MulBy5(x *Element) { x.Double(x).Double(x).Add(x, &_x) } +// MulBy11 x *= 11 (mod q) +func MulBy11(x *Element) { + var y = Element{ + 11443185389230096326, + 16446406505298427670, + 4454117921868872420, + 668285336232769164, + } + x.Mul(x, &y) +} + // MulBy13 x *= 13 (mod q) func MulBy13(x *Element) { var y = Element{ diff --git a/ecc/grumpkin/fr/element_amd64.go b/ecc/grumpkin/fr/element_amd64.go index c282ebc9fc..0d47036fea 100644 --- a/ecc/grumpkin/fr/element_amd64.go +++ b/ecc/grumpkin/fr/element_amd64.go @@ -20,6 +20,9 @@ func MulBy3(x *Element) //go:noescape func MulBy5(x *Element) +//go:noescape +func MulBy11(x *Element) + //go:noescape func MulBy13(x *Element) diff --git a/ecc/grumpkin/fr/element_arm64.go b/ecc/grumpkin/fr/element_arm64.go index 03421559cc..056977925b 100644 --- a/ecc/grumpkin/fr/element_arm64.go +++ b/ecc/grumpkin/fr/element_arm64.go @@ -51,6 +51,17 @@ func MulBy5(x *Element) { x.Double(x).Double(x).Add(x, &_x) } +// MulBy11 x *= 11 (mod q) +func MulBy11(x *Element) { + var y = Element{ + 6962638497713659370, + 12442842200117091328, + 4454117921868872395, + 668285336232769164, + } + x.Mul(x, &y) +} + // MulBy13 x *= 13 (mod q) func MulBy13(x *Element) { var y = Element{ diff --git a/ecc/grumpkin/fr/element_purego.go b/ecc/grumpkin/fr/element_purego.go index e4b9c87ac4..9e6469da4e 100644 --- a/ecc/grumpkin/fr/element_purego.go +++ b/ecc/grumpkin/fr/element_purego.go @@ -21,6 +21,17 @@ func MulBy5(x *Element) { x.Double(x).Double(x).Add(x, &_x) } +// MulBy11 x *= 11 (mod q) +func MulBy11(x *Element) { + var y = Element{ + 6962638497713659370, + 12442842200117091328, + 4454117921868872395, + 668285336232769164, + } + x.Mul(x, &y) +} + // MulBy13 x *= 13 (mod q) func MulBy13(x *Element) { var y = Element{ diff --git a/ecc/secp256k1/fp/element_purego.go b/ecc/secp256k1/fp/element_purego.go index 5650ed6925..1ffd1bb174 100644 --- a/ecc/secp256k1/fp/element_purego.go +++ b/ecc/secp256k1/fp/element_purego.go @@ -19,6 +19,17 @@ func MulBy5(x *Element) { x.Double(x).Double(x).Add(x, &_x) } +// MulBy11 x *= 11 (mod q) +func MulBy11(x *Element) { + var y = Element{ + 47244651003, + 0, + 0, + 0, + } + x.Mul(x, &y) +} + // MulBy13 x *= 13 (mod q) func MulBy13(x *Element) { var y = Element{ diff --git a/ecc/secp256k1/fr/element_purego.go b/ecc/secp256k1/fr/element_purego.go index 32720596b7..9fe91a36d9 100644 --- a/ecc/secp256k1/fr/element_purego.go +++ b/ecc/secp256k1/fr/element_purego.go @@ -19,6 +19,17 @@ func MulBy5(x *Element) { x.Double(x).Double(x).Add(x, &_x) } +// MulBy11 x *= 11 (mod q) +func MulBy11(x *Element) { + var y = Element{ + 13976340845799617077, + 18049444439606238574, + 13, + 0, + } + x.Mul(x, &y) +} + // MulBy13 x *= 13 (mod q) func MulBy13(x *Element) { var y = Element{ diff --git a/ecc/stark-curve/fp/element_amd64.go b/ecc/stark-curve/fp/element_amd64.go index e02a9d04c2..339df6f656 100644 --- a/ecc/stark-curve/fp/element_amd64.go +++ b/ecc/stark-curve/fp/element_amd64.go @@ -20,6 +20,9 @@ func MulBy3(x *Element) //go:noescape func MulBy5(x *Element) +//go:noescape +func MulBy11(x *Element) + //go:noescape func MulBy13(x *Element) diff --git a/ecc/stark-curve/fp/element_arm64.go b/ecc/stark-curve/fp/element_arm64.go index ee729af225..dca778dba7 100644 --- a/ecc/stark-curve/fp/element_arm64.go +++ b/ecc/stark-curve/fp/element_arm64.go @@ -51,6 +51,17 @@ func MulBy5(x *Element) { x.Double(x).Double(x).Add(x, &_x) } +// MulBy11 x *= 11 (mod q) +func MulBy11(x *Element) { + var y = Element{ + 18446744073709551265, + 18446744073709551615, + 18446744073709551615, + 576460752303417520, + } + x.Mul(x, &y) +} + // MulBy13 x *= 13 (mod q) func MulBy13(x *Element) { var y = Element{ diff --git a/ecc/stark-curve/fp/element_purego.go b/ecc/stark-curve/fp/element_purego.go index bfbebf9634..7c5f53408d 100644 --- a/ecc/stark-curve/fp/element_purego.go +++ b/ecc/stark-curve/fp/element_purego.go @@ -21,6 +21,17 @@ func MulBy5(x *Element) { x.Double(x).Double(x).Add(x, &_x) } +// MulBy11 x *= 11 (mod q) +func MulBy11(x *Element) { + var y = Element{ + 18446744073709551265, + 18446744073709551615, + 18446744073709551615, + 576460752303417520, + } + x.Mul(x, &y) +} + // MulBy13 x *= 13 (mod q) func MulBy13(x *Element) { var y = Element{ diff --git a/ecc/stark-curve/fr/element_amd64.go b/ecc/stark-curve/fr/element_amd64.go index c282ebc9fc..0d47036fea 100644 --- a/ecc/stark-curve/fr/element_amd64.go +++ b/ecc/stark-curve/fr/element_amd64.go @@ -20,6 +20,9 @@ func MulBy3(x *Element) //go:noescape func MulBy5(x *Element) +//go:noescape +func MulBy11(x *Element) + //go:noescape func MulBy13(x *Element) diff --git a/ecc/stark-curve/fr/element_arm64.go b/ecc/stark-curve/fr/element_arm64.go index 58e9415131..3c3e96fd2e 100644 --- a/ecc/stark-curve/fr/element_arm64.go +++ b/ecc/stark-curve/fr/element_arm64.go @@ -51,6 +51,17 @@ func MulBy5(x *Element) { x.Double(x).Double(x).Add(x, &_x) } +// MulBy11 x *= 11 (mod q) +func MulBy11(x *Element) { + var y = Element{ + 5856799317043195023, + 7352051035614129480, + 99, + 576460752303417521, + } + x.Mul(x, &y) +} + // MulBy13 x *= 13 (mod q) func MulBy13(x *Element) { var y = Element{ diff --git a/ecc/stark-curve/fr/element_purego.go b/ecc/stark-curve/fr/element_purego.go index a0cbe29f1c..c61471a299 100644 --- a/ecc/stark-curve/fr/element_purego.go +++ b/ecc/stark-curve/fr/element_purego.go @@ -21,6 +21,17 @@ func MulBy5(x *Element) { x.Double(x).Double(x).Add(x, &_x) } +// MulBy11 x *= 11 (mod q) +func MulBy11(x *Element) { + var y = Element{ + 5856799317043195023, + 7352051035614129480, + 99, + 576460752303417521, + } + x.Mul(x, &y) +} + // MulBy13 x *= 13 (mod q) func MulBy13(x *Element) { var y = Element{ diff --git a/field/babybear/extensions/e2_amd64.go b/field/babybear/extensions/e2_amd64.go index 11c064116c..6c35d844a2 100644 --- a/field/babybear/extensions/e2_amd64.go +++ b/field/babybear/extensions/e2_amd64.go @@ -6,12 +6,12 @@ import ( // q + r'.r = 1, i.e., qInvNeg = - q⁻¹ mod r // used for Montgomery reduction -const qInvNeg uint64 = 2013265919 +const qInvNeg uint32 = 2013265919 // Field modulus q (Fr) const ( - q0 uint64 = 2013265921 - q uint64 = q0 + q0 uint32 = 2013265921 + q uint32 = q0 ) var qElement = fr.Element{ diff --git a/field/generator/internal/templates/element/ops_asm.go b/field/generator/internal/templates/element/ops_asm.go index db62884e4e..4d402e4456 100644 --- a/field/generator/internal/templates/element/ops_asm.go +++ b/field/generator/internal/templates/element/ops_asm.go @@ -17,7 +17,7 @@ func MulBy3(x *{{.ElementName}}) func MulBy5(x *{{.ElementName}}) //go:noescape -func MulBy13(x *{{.ElementName}}) +func MulBy11(x *{{.ElementName}}) //go:noescape func MulBy13(x *{{.ElementName}}) From 4a839070fd5050c148a98870a13e7c521fd777a7 Mon Sep 17 00:00:00 2001 From: Youssef El Housni Date: Wed, 19 Feb 2025 09:22:32 -0500 Subject: [PATCH 7/9] fix: mul asm babybear --- field/babybear/extensions/e2_babybear.go | 10 ++++++---- field/babybear/extensions/e2_babybear_fallback.go | 13 +++++++++++++ 2 files changed, 19 insertions(+), 4 deletions(-) create mode 100644 field/babybear/extensions/e2_babybear_fallback.go diff --git a/field/babybear/extensions/e2_babybear.go b/field/babybear/extensions/e2_babybear.go index 5939d787ea..bc4bc20b82 100644 --- a/field/babybear/extensions/e2_babybear.go +++ b/field/babybear/extensions/e2_babybear.go @@ -4,8 +4,9 @@ import ( fr "github.com/consensys/gnark-crypto/field/babybear" ) -// Mul sets z to the E2-product of x,y, returns z -func (z *E2) Mul(x, y *E2) *E2 { +// mulGenericE2 sets z to the E2-product of x,y, returns z +// note: do not rename, this is referenced in the x86 assembly impl +func mulGenericE2(z, x, y *E2) *E2 { var a, b, c fr.Element a.Add(&x.A0, &x.A1) b.Add(&y.A0, &y.A1) @@ -18,8 +19,9 @@ func (z *E2) Mul(x, y *E2) *E2 { return z } -// Square sets z to the E2-product of x,x returns z -func (z *E2) Square(x *E2) *E2 { +// squareGenericE2 sets z to the E2-product of x,x returns z +// note: do not rename, this is referenced in the x86 assembly impl +func squareGenericE2(z, x *E2) *E2 { var a, b, c fr.Element a.Mul(&x.A0, &x.A1).Double(&a) c.Square(&x.A0) diff --git a/field/babybear/extensions/e2_babybear_fallback.go b/field/babybear/extensions/e2_babybear_fallback.go new file mode 100644 index 0000000000..2c2601f8c5 --- /dev/null +++ b/field/babybear/extensions/e2_babybear_fallback.go @@ -0,0 +1,13 @@ +package extensions + +// Mul sets z to the E2-product of x,y, returns z +func (z *E2) Mul(x, y *E2) *E2 { // E: undeclared name: E2 + mulGenericE2(z, x, y) // E: undeclared name: mulGenericE2 + return z +} + +// Square sets z to the E2-product of x,x returns z +func (z *E2) Square(x *E2) *E2 { // E: undeclared name: E2 + squareGenericE2(z, x) // E: undeclared name: squareGenericE2 + return z +} From e7f0ca4a8cc2a5db953f25801b622d33b09263e5 Mon Sep 17 00:00:00 2001 From: Youssef El Housni Date: Wed, 19 Feb 2025 09:34:40 -0500 Subject: [PATCH 8/9] refactor: remove asm --- field/babybear/extensions/e2_amd64.go | 58 --- field/babybear/extensions/e2_amd64.s | 341 ------------------ field/babybear/extensions/e2_babybear.go | 10 +- .../extensions/e2_babybear_fallback.go | 13 - field/babybear/extensions/e2_fallback.go | 23 -- field/koalabear/extensions/e2_amd64.go | 31 -- field/koalabear/extensions/e2_amd64.s | 99 ----- field/koalabear/extensions/e2_fallback.go | 24 -- 8 files changed, 4 insertions(+), 595 deletions(-) delete mode 100644 field/babybear/extensions/e2_amd64.go delete mode 100644 field/babybear/extensions/e2_amd64.s delete mode 100644 field/babybear/extensions/e2_babybear_fallback.go delete mode 100644 field/babybear/extensions/e2_fallback.go delete mode 100644 field/koalabear/extensions/e2_amd64.go delete mode 100644 field/koalabear/extensions/e2_amd64.s delete mode 100644 field/koalabear/extensions/e2_fallback.go diff --git a/field/babybear/extensions/e2_amd64.go b/field/babybear/extensions/e2_amd64.go deleted file mode 100644 index 6c35d844a2..0000000000 --- a/field/babybear/extensions/e2_amd64.go +++ /dev/null @@ -1,58 +0,0 @@ -package extensions - -import ( - fr "github.com/consensys/gnark-crypto/field/babybear" -) - -// q + r'.r = 1, i.e., qInvNeg = - q⁻¹ mod r -// used for Montgomery reduction -const qInvNeg uint32 = 2013265919 - -// Field modulus q (Fr) -const ( - q0 uint32 = 2013265921 - q uint32 = q0 -) - -var qElement = fr.Element{ - q0, -} - -//go:noescape -func addE2(res, x, y *E2) - -//go:noescape -func subE2(res, x, y *E2) - -//go:noescape -func doubleE2(res, x *E2) - -//go:noescape -func negE2(res, x *E2) - -//go:noescape -func mulNonResE2(res, x *E2) - -//go:noescape -func squareAdxE2(res, x *E2) - -//go:noescape -func mulAdxE2(res, x, y *E2) - -// MulByNonResidue multiplies a E2 by (9,1) -func (z *E2) MulByNonResidue(x *E2) *E2 { - mulNonResE2(z, x) - return z -} - -// Mul sets z to the E2-product of x,y, returns z -func (z *E2) Mul(x, y *E2) *E2 { - mulAdxE2(z, x, y) - return z -} - -// Square sets z to the E2-product of x,x, returns z -func (z *E2) Square(x *E2) *E2 { - squareAdxE2(z, x) - return z -} diff --git a/field/babybear/extensions/e2_amd64.s b/field/babybear/extensions/e2_amd64.s deleted file mode 100644 index 0da2d2f8ba..0000000000 --- a/field/babybear/extensions/e2_amd64.s +++ /dev/null @@ -1,341 +0,0 @@ -// Copyright 2020-2025 Consensys Software Inc. -// Licensed under the Apache License, Version 2.0. See the LICENSE file for details. - -#include "textflag.h" -#include "funcdata.h" -#include "go_asm.h" - -#define REDUCE(ra0, rb0) \ - MOVQ ra0, rb0; \ - SUBQ ·qElement(SB), ra0; \ - CMOVQCS rb0, ra0; \ - -// this code is generated and identical to fr.Mul(...) -// A -> BP -// t -> CX -#define MACC(in0, in1, in2) \ - ADCXQ in0, in1 \ - MULXQ in2, AX, in0 \ - ADOXQ AX, in1 \ - -#define DIV_SHIFT() \ - MOVQ $const_qInvNeg, DX \ - IMULQ CX, DX \ - XORQ AX, AX \ - MULXQ ·qElement+0(SB), AX, BX \ - ADCXQ CX, AX \ - MOVQ BX, CX \ - MOVQ $0, AX \ - ADCXQ AX, CX \ - ADOXQ BP, CX \ - -#define MUL_WORD_0() \ - XORQ AX, AX \ - MULXQ R14, CX, BP \ - MOVQ $0, AX \ - ADOXQ AX, BP \ - DIV_SHIFT() \ - -#define MUL_WORD_N() \ - XORQ AX, AX \ - MULXQ R14, AX, BP \ - ADOXQ AX, CX \ - MOVQ $0, AX \ - ADCXQ AX, BP \ - ADOXQ AX, BP \ - DIV_SHIFT() \ - -#define MUL() \ - MOVQ R15, DX; \ - MUL_WORD_0(); \ - -TEXT ·addE2(SB), NOSPLIT, $0-24 - MOVQ x+8(FP), AX - MOVQ 0(AX), BX - MOVQ y+16(FP), DX - ADDQ 0(DX), BX - - // reduce element(BX) using temp registers (SI) - REDUCE(BX,SI) - - MOVQ res+0(FP), CX - MOVQ BX, 0(CX) - MOVQ 8(AX), BX - ADDQ 8(DX), BX - - // reduce element(BX) using temp registers (DI) - REDUCE(BX,DI) - - MOVQ BX, 8(CX) - RET - -TEXT ·doubleE2(SB), NOSPLIT, $0-16 - MOVQ res+0(FP), DX - MOVQ x+8(FP), AX - MOVQ 0(AX), CX - ADDQ CX, CX - - // reduce element(CX) using temp registers (BX) - REDUCE(CX,BX) - - MOVQ CX, 0(DX) - MOVQ 8(AX), CX - ADDQ CX, CX - - // reduce element(CX) using temp registers (SI) - REDUCE(CX,SI) - - MOVQ CX, 8(DX) - RET - -TEXT ·subE2(SB), NOSPLIT, $0-24 - XORQ CX, CX - MOVQ x+8(FP), DX - MOVQ 0(DX), AX - MOVQ y+16(FP), DX - SUBQ 0(DX), AX - MOVQ x+8(FP), DX - MOVQ $0x0000000078000001, BX - CMOVQCC CX, BX - ADDQ BX, AX - MOVQ res+0(FP), SI - MOVQ AX, 0(SI) - MOVQ 8(DX), AX - MOVQ y+16(FP), DX - SUBQ 8(DX), AX - MOVQ $0x0000000078000001, DI - CMOVQCC CX, DI - ADDQ DI, AX - MOVQ res+0(FP), DX - MOVQ AX, 8(DX) - RET - -TEXT ·negE2(SB), NOSPLIT, $0-16 - MOVQ res+0(FP), DX - MOVQ x+8(FP), AX - MOVQ 0(AX), BX - MOVQ BX, AX - TESTQ AX, AX - JNE l1 - MOVQ AX, 0(DX) - JMP l3 - -l1: - MOVQ $0x0000000078000001, CX - SUBQ BX, CX - MOVQ CX, 0(DX) - -l3: - MOVQ x+8(FP), AX - MOVQ 8(AX), BX - MOVQ BX, AX - TESTQ AX, AX - JNE l2 - MOVQ AX, 8(DX) - RET - -l2: - MOVQ $0x0000000078000001, CX - SUBQ BX, CX - MOVQ CX, 8(DX) - RET - -TEXT ·mulNonResE2(SB), NOSPLIT, $0-16 - MOVQ x+8(FP), CX - MOVQ 0(CX), AX - ADDQ AX, AX - - // reduce element(AX) using temp registers (BX) - REDUCE(AX,BX) - - ADDQ AX, AX - - // reduce element(AX) using temp registers (SI) - REDUCE(AX,SI) - - ADDQ AX, AX - - // reduce element(AX) using temp registers (DI) - REDUCE(AX,DI) - - ADDQ 0(CX), AX - - // reduce element(AX) using temp registers (R8) - REDUCE(AX,R8) - - MOVQ 8(CX), DX - XORQ R9, R9 - SUBQ DX, AX - MOVQ $0x0000000078000001, R10 - CMOVQCC R9, R10 - ADDQ R10, AX - ADDQ DX, DX - - // reduce element(DX) using temp registers (R11) - REDUCE(DX,R11) - - ADDQ DX, DX - - // reduce element(DX) using temp registers (R12) - REDUCE(DX,R12) - - ADDQ DX, DX - - // reduce element(DX) using temp registers (R13) - REDUCE(DX,R13) - - ADDQ 8(CX), DX - - // reduce element(DX) using temp registers (R14) - REDUCE(DX,R14) - - ADDQ 0(CX), DX - - // reduce element(DX) using temp registers (R15) - REDUCE(DX,R15) - - MOVQ res+0(FP), CX - MOVQ AX, 0(CX) - MOVQ DX, 8(CX) - RET - -TEXT ·mulAdxE2(SB), $24-24 - NO_LOCAL_POINTERS - - // var a, b, c fr.Element - // a.Add(&x.A0, &x.A1) - // b.Add(&y.A0, &y.A1) - // a.Mul(&a, &b) - // b.Mul(&x.A0, &y.A0) - // c.Mul(&x.A1, &y.A1) - // z.A1.Sub(&a, &b).Sub(&z.A1, &c) - // z.A0.Sub(&b, &c) - - CMPB ·supportAdx(SB), $1 - JNE l4 - MOVQ x+8(FP), AX - MOVQ y+16(FP), DX - MOVQ 8(AX), R14 - MOVQ 8(DX), R15 - - // mul (R14) with (R15) into (CX) - MUL() - - // reduce element(CX) using temp registers (R15) - REDUCE(CX,R15) - - MOVQ CX, s1-16(SP) - MOVQ x+8(FP), AX - MOVQ y+16(FP), DX - ADDQ 0(AX), R14 - MOVQ 0(DX), R15 - ADDQ 8(DX), R15 - - // mul (R14) with (R15) into (CX) - MUL() - - // reduce element(CX) using temp registers (R15) - REDUCE(CX,R15) - - MOVQ CX, s0-8(SP) - MOVQ x+8(FP), AX - MOVQ y+16(FP), DX - MOVQ 0(AX), R14 - MOVQ 0(DX), R15 - - // mul (R14) with (R15) into (CX) - MUL() - - // reduce element(CX) using temp registers (R15) - REDUCE(CX,R15) - - XORQ DX, DX - MOVQ s0-8(SP), R14 - SUBQ CX, R14 - MOVQ $0x0000000078000001, R15 - CMOVQCC DX, R15 - ADDQ R15, R14 - SUBQ s1-16(SP), R14 - MOVQ $0x0000000078000001, R15 - CMOVQCC DX, R15 - ADDQ R15, R14 - MOVQ res+0(FP), AX - MOVQ R14, 8(AX) - MOVQ s1-16(SP), R15 - SUBQ R15, CX - MOVQ $0x0000000078000001, R14 - CMOVQCC DX, R14 - ADDQ R14, CX - MOVQ CX, 0(AX) - RET - -l4: - MOVQ res+0(FP), AX - MOVQ AX, (SP) - MOVQ x+8(FP), AX - MOVQ AX, 8(SP) - MOVQ y+16(FP), AX - MOVQ AX, 16(SP) - CALL ·mulGenericE2(SB) - RET - -TEXT ·squareAdxE2(SB), $16-16 - NO_LOCAL_POINTERS - - // z.A0 = (x.A0 + x.A1) * (x.A0 - x.A1) - // z.A1 = 2 * x.A0 * x.A1 - - CMPB ·supportAdx(SB), $1 - JNE l5 - - // 2 * x.A0 * x.A1 - MOVQ x+8(FP), AX - - // x.A0 -> R15 - MOVQ 0(AX), R15 - - // 2 * x.A1 -> R14 - MOVQ 8(AX), R14 - ADDQ R14, R14 - - // mul (R14) with (R15) into (CX) - MUL() - - // reduce element(CX) using temp registers (R14) - REDUCE(CX,R14) - - MOVQ x+8(FP), AX - - // x.A1 -> R14 - MOVQ 8(AX), R14 - MOVQ res+0(FP), DX - MOVQ CX, 8(DX) - MOVQ R14, CX - - // Add(&x.A0, &x.A1) - ADDQ R15, R14 - XORQ BP, BP - - // Sub(&x.A0, &x.A1) - SUBQ CX, R15 - MOVQ $0x0000000078000001, CX - CMOVQCC BP, CX - ADDQ CX, R15 - - // mul (R14) with (R15) into (CX) - MUL() - - // reduce element(CX) using temp registers (R14) - REDUCE(CX,R14) - - MOVQ res+0(FP), AX - MOVQ CX, 0(AX) - RET - -l5: - MOVQ res+0(FP), AX - MOVQ AX, (SP) - MOVQ x+8(FP), AX - MOVQ AX, 8(SP) - CALL ·squareGenericE2(SB) - RET diff --git a/field/babybear/extensions/e2_babybear.go b/field/babybear/extensions/e2_babybear.go index bc4bc20b82..5939d787ea 100644 --- a/field/babybear/extensions/e2_babybear.go +++ b/field/babybear/extensions/e2_babybear.go @@ -4,9 +4,8 @@ import ( fr "github.com/consensys/gnark-crypto/field/babybear" ) -// mulGenericE2 sets z to the E2-product of x,y, returns z -// note: do not rename, this is referenced in the x86 assembly impl -func mulGenericE2(z, x, y *E2) *E2 { +// Mul sets z to the E2-product of x,y, returns z +func (z *E2) Mul(x, y *E2) *E2 { var a, b, c fr.Element a.Add(&x.A0, &x.A1) b.Add(&y.A0, &y.A1) @@ -19,9 +18,8 @@ func mulGenericE2(z, x, y *E2) *E2 { return z } -// squareGenericE2 sets z to the E2-product of x,x returns z -// note: do not rename, this is referenced in the x86 assembly impl -func squareGenericE2(z, x *E2) *E2 { +// Square sets z to the E2-product of x,x returns z +func (z *E2) Square(x *E2) *E2 { var a, b, c fr.Element a.Mul(&x.A0, &x.A1).Double(&a) c.Square(&x.A0) diff --git a/field/babybear/extensions/e2_babybear_fallback.go b/field/babybear/extensions/e2_babybear_fallback.go deleted file mode 100644 index 2c2601f8c5..0000000000 --- a/field/babybear/extensions/e2_babybear_fallback.go +++ /dev/null @@ -1,13 +0,0 @@ -package extensions - -// Mul sets z to the E2-product of x,y, returns z -func (z *E2) Mul(x, y *E2) *E2 { // E: undeclared name: E2 - mulGenericE2(z, x, y) // E: undeclared name: mulGenericE2 - return z -} - -// Square sets z to the E2-product of x,x returns z -func (z *E2) Square(x *E2) *E2 { // E: undeclared name: E2 - squareGenericE2(z, x) // E: undeclared name: squareGenericE2 - return z -} diff --git a/field/babybear/extensions/e2_fallback.go b/field/babybear/extensions/e2_fallback.go deleted file mode 100644 index 643ca324e7..0000000000 --- a/field/babybear/extensions/e2_fallback.go +++ /dev/null @@ -1,23 +0,0 @@ -//go:build !amd64 - -package extensions - -func addE2(z, x, y *E2) { - z.A0.Add(&x.A0, &y.A0) - z.A1.Add(&x.A1, &y.A1) -} - -func subE2(z, x, y *E2) { - z.A0.Sub(&x.A0, &y.A0) - z.A1.Sub(&x.A1, &y.A1) -} - -func doubleE2(z, x *E2) { - z.A0.Double(&x.A0) - z.A1.Double(&x.A1) -} - -func negE2(z, x *E2) { - z.A0.Neg(&x.A0) - z.A1.Neg(&x.A1) -} diff --git a/field/koalabear/extensions/e2_amd64.go b/field/koalabear/extensions/e2_amd64.go deleted file mode 100644 index 029bbafa08..0000000000 --- a/field/koalabear/extensions/e2_amd64.go +++ /dev/null @@ -1,31 +0,0 @@ -package extensions - -import ( - fr "github.com/consensys/gnark-crypto/field/koalabear" -) - -// q + r'.r = 1, i.e., qInvNeg = - q⁻¹ mod r -// used for Montgomery reduction -const qInvNeg uint32 = 2130706431 - -// Field modulus q (Fr) -const ( - q0 uint32 = 2130706433 - q uint32 = q0 -) - -var qElement = fr.Element{ - q0, -} - -//go:noescape -func addE2(res, x, y *E2) - -//go:noescape -func subE2(res, x, y *E2) - -//go:noescape -func doubleE2(res, x *E2) - -//go:noescape -func negE2(res, x *E2) diff --git a/field/koalabear/extensions/e2_amd64.s b/field/koalabear/extensions/e2_amd64.s deleted file mode 100644 index 216cd2f9b5..0000000000 --- a/field/koalabear/extensions/e2_amd64.s +++ /dev/null @@ -1,99 +0,0 @@ -#include "textflag.h" -#include "funcdata.h" -#include "go_asm.h" - -#define REDUCE(ra0, rb0) \ - MOVQ ra0, rb0; \ - SUBQ ·qElement(SB), ra0; \ - CMOVQCS rb0, ra0; \ - -TEXT ·addE2(SB), NOSPLIT, $0-24 - MOVQ x+8(FP), AX - MOVQ 0(AX), BX - MOVQ y+16(FP), DX - ADDQ 0(DX), BX - - // reduce element(BX) using temp registers (SI) - REDUCE(BX,SI) - - MOVQ res+0(FP), CX - MOVQ BX, 0(CX) - MOVQ 8(AX), BX - ADDQ 8(DX), BX - - // reduce element(BX) using temp registers (DI) - REDUCE(BX,DI) - - MOVQ BX, 8(CX) - RET - -TEXT ·doubleE2(SB), NOSPLIT, $0-16 - MOVQ res+0(FP), DX - MOVQ x+8(FP), AX - MOVQ 0(AX), CX - ADDQ CX, CX - - // reduce element(CX) using temp registers (BX) - REDUCE(CX,BX) - - MOVQ CX, 0(DX) - MOVQ 8(AX), CX - ADDQ CX, CX - - // reduce element(CX) using temp registers (SI) - REDUCE(CX,SI) - - MOVQ CX, 8(DX) - RET - -TEXT ·subE2(SB), NOSPLIT, $0-24 - XORQ CX, CX - MOVQ x+8(FP), DX - MOVQ 0(DX), AX - MOVQ y+16(FP), DX - SUBQ 0(DX), AX - MOVQ x+8(FP), DX - MOVQ $0x000000007f000001, BX - CMOVQCC CX, BX - ADDQ BX, AX - MOVQ res+0(FP), SI - MOVQ AX, 0(SI) - MOVQ 8(DX), AX - MOVQ y+16(FP), DX - SUBQ 8(DX), AX - MOVQ $0x000000007f000001, DI - CMOVQCC CX, DI - ADDQ DI, AX - MOVQ res+0(FP), DX - MOVQ AX, 8(DX) - RET - -TEXT ·negE2(SB), NOSPLIT, $0-16 - MOVQ res+0(FP), DX - MOVQ x+8(FP), AX - MOVQ 0(AX), BX - MOVQ BX, AX - TESTQ AX, AX - JNE l1 - MOVQ AX, 0(DX) - JMP l3 - -l1: - MOVQ $0x000000007f000001, CX - SUBQ BX, CX - MOVQ CX, 0(DX) - -l3: - MOVQ x+8(FP), AX - MOVQ 8(AX), BX - MOVQ BX, AX - TESTQ AX, AX - JNE l2 - MOVQ AX, 8(DX) - RET - -l2: - MOVQ $0x000000007f000001, CX - SUBQ BX, CX - MOVQ CX, 8(DX) - RET diff --git a/field/koalabear/extensions/e2_fallback.go b/field/koalabear/extensions/e2_fallback.go deleted file mode 100644 index 58cf038d1b..0000000000 --- a/field/koalabear/extensions/e2_fallback.go +++ /dev/null @@ -1,24 +0,0 @@ -//go:build !amd64 -// +build !amd64 - -package extensions - -func addE2(z, x, y *E2) { - z.A0.Add(&x.A0, &y.A0) - z.A1.Add(&x.A1, &y.A1) -} - -func subE2(z, x, y *E2) { - z.A0.Sub(&x.A0, &y.A0) - z.A1.Sub(&x.A1, &y.A1) -} - -func doubleE2(z, x *E2) { - z.A0.Double(&x.A0) - z.A1.Double(&x.A1) -} - -func negE2(z, x *E2) { - z.A0.Neg(&x.A0) - z.A1.Neg(&x.A1) -} From 375c0d36ce702f425dc859aa6d3776ae1634e477 Mon Sep 17 00:00:00 2001 From: Youssef El Housni Date: Wed, 19 Feb 2025 16:47:12 -0500 Subject: [PATCH 9/9] refactor: remove MulBy11 --- ecc/bls12-377/fp/element_amd64.go | 3 --- ecc/bls12-377/fp/element_arm64.go | 13 ------------- ecc/bls12-377/fp/element_purego.go | 13 ------------- ecc/bls12-377/fr/element_amd64.go | 3 --- ecc/bls12-377/fr/element_arm64.go | 11 ----------- ecc/bls12-377/fr/element_purego.go | 11 ----------- ecc/bls12-381/fp/element_amd64.go | 3 --- ecc/bls12-381/fp/element_arm64.go | 13 ------------- ecc/bls12-381/fp/element_purego.go | 13 ------------- ecc/bls12-381/fr/element_amd64.go | 3 --- ecc/bls12-381/fr/element_arm64.go | 11 ----------- ecc/bls12-381/fr/element_purego.go | 11 ----------- ecc/bls24-315/fp/element_amd64.go | 3 --- ecc/bls24-315/fp/element_purego.go | 12 ------------ ecc/bls24-315/fr/element_amd64.go | 3 --- ecc/bls24-315/fr/element_arm64.go | 11 ----------- ecc/bls24-315/fr/element_purego.go | 11 ----------- ecc/bls24-317/fp/element_amd64.go | 3 --- ecc/bls24-317/fp/element_purego.go | 12 ------------ ecc/bls24-317/fr/element_amd64.go | 3 --- ecc/bls24-317/fr/element_arm64.go | 11 ----------- ecc/bls24-317/fr/element_purego.go | 11 ----------- ecc/bn254/fp/element_amd64.go | 3 --- ecc/bn254/fp/element_arm64.go | 11 ----------- ecc/bn254/fp/element_purego.go | 11 ----------- ecc/bn254/fr/element_amd64.go | 3 --- ecc/bn254/fr/element_arm64.go | 11 ----------- ecc/bn254/fr/element_purego.go | 11 ----------- ecc/bw6-633/fp/element_amd64.go | 3 --- ecc/bw6-633/fp/element_arm64.go | 17 ----------------- ecc/bw6-633/fp/element_purego.go | 17 ----------------- ecc/bw6-633/fr/element_amd64.go | 3 --- ecc/bw6-633/fr/element_purego.go | 12 ------------ ecc/bw6-761/fp/element_amd64.go | 3 --- ecc/bw6-761/fp/element_arm64.go | 19 ------------------- ecc/bw6-761/fp/element_purego.go | 19 ------------------- ecc/bw6-761/fr/element_amd64.go | 3 --- ecc/bw6-761/fr/element_arm64.go | 13 ------------- ecc/bw6-761/fr/element_purego.go | 13 ------------- ecc/grumpkin/fp/element_amd64.go | 3 --- ecc/grumpkin/fp/element_arm64.go | 11 ----------- ecc/grumpkin/fp/element_purego.go | 11 ----------- ecc/grumpkin/fr/element_amd64.go | 3 --- ecc/grumpkin/fr/element_arm64.go | 11 ----------- ecc/grumpkin/fr/element_purego.go | 11 ----------- ecc/secp256k1/fp/element_purego.go | 11 ----------- ecc/secp256k1/fr/element_purego.go | 11 ----------- ecc/stark-curve/fp/element_amd64.go | 3 --- ecc/stark-curve/fp/element_arm64.go | 11 ----------- ecc/stark-curve/fp/element_purego.go | 11 ----------- ecc/stark-curve/fr/element_amd64.go | 3 --- ecc/stark-curve/fr/element_arm64.go | 11 ----------- ecc/stark-curve/fr/element_purego.go | 11 ----------- field/babybear/element_purego.go | 7 ------- field/babybear/extensions/e2_babybear.go | 18 +++++++++++++----- .../internal/templates/element/ops_asm.go | 11 +---------- .../internal/templates/element/ops_purego.go | 8 +------- field/goldilocks/element_purego.go | 7 ------- field/koalabear/element_purego.go | 7 ------- 59 files changed, 15 insertions(+), 525 deletions(-) diff --git a/ecc/bls12-377/fp/element_amd64.go b/ecc/bls12-377/fp/element_amd64.go index 1ce1d184ce..ff2159178d 100644 --- a/ecc/bls12-377/fp/element_amd64.go +++ b/ecc/bls12-377/fp/element_amd64.go @@ -20,9 +20,6 @@ func MulBy3(x *Element) //go:noescape func MulBy5(x *Element) -//go:noescape -func MulBy11(x *Element) - //go:noescape func MulBy13(x *Element) diff --git a/ecc/bls12-377/fp/element_arm64.go b/ecc/bls12-377/fp/element_arm64.go index e65783c173..a4510da8eb 100644 --- a/ecc/bls12-377/fp/element_arm64.go +++ b/ecc/bls12-377/fp/element_arm64.go @@ -51,19 +51,6 @@ func MulBy5(x *Element) { x.Double(x).Double(x).Add(x, &_x) } -// MulBy11 x *= 11 (mod q) -func MulBy11(x *Element) { - var y = Element{ - 10358208774207961461, - 4081601403594734745, - 9046765978545153897, - 18300367227737147024, - 18145387698699229771, - 74511027426447328, - } - x.Mul(x, &y) -} - // MulBy13 x *= 13 (mod q) func MulBy13(x *Element) { var y = Element{ diff --git a/ecc/bls12-377/fp/element_purego.go b/ecc/bls12-377/fp/element_purego.go index 086e226f2c..8a2e93e999 100644 --- a/ecc/bls12-377/fp/element_purego.go +++ b/ecc/bls12-377/fp/element_purego.go @@ -21,19 +21,6 @@ func MulBy5(x *Element) { x.Double(x).Double(x).Add(x, &_x) } -// MulBy11 x *= 11 (mod q) -func MulBy11(x *Element) { - var y = Element{ - 10358208774207961461, - 4081601403594734745, - 9046765978545153897, - 18300367227737147024, - 18145387698699229771, - 74511027426447328, - } - x.Mul(x, &y) -} - // MulBy13 x *= 13 (mod q) func MulBy13(x *Element) { var y = Element{ diff --git a/ecc/bls12-377/fr/element_amd64.go b/ecc/bls12-377/fr/element_amd64.go index 0d47036fea..c282ebc9fc 100644 --- a/ecc/bls12-377/fr/element_amd64.go +++ b/ecc/bls12-377/fr/element_amd64.go @@ -20,9 +20,6 @@ func MulBy3(x *Element) //go:noescape func MulBy5(x *Element) -//go:noescape -func MulBy11(x *Element) - //go:noescape func MulBy13(x *Element) diff --git a/ecc/bls12-377/fr/element_arm64.go b/ecc/bls12-377/fr/element_arm64.go index d70ea940e9..fc80023171 100644 --- a/ecc/bls12-377/fr/element_arm64.go +++ b/ecc/bls12-377/fr/element_arm64.go @@ -51,17 +51,6 @@ func MulBy5(x *Element) { x.Double(x).Double(x).Add(x, &_x) } -// MulBy11 x *= 11 (mod q) -func MulBy11(x *Element) { - var y = Element{ - 1855201571499933546, - 8511318076631809892, - 6222514765367795509, - 1122129207579058019, - } - x.Mul(x, &y) -} - // MulBy13 x *= 13 (mod q) func MulBy13(x *Element) { var y = Element{ diff --git a/ecc/bls12-377/fr/element_purego.go b/ecc/bls12-377/fr/element_purego.go index 5dfdfad5f1..537648f3d1 100644 --- a/ecc/bls12-377/fr/element_purego.go +++ b/ecc/bls12-377/fr/element_purego.go @@ -21,17 +21,6 @@ func MulBy5(x *Element) { x.Double(x).Double(x).Add(x, &_x) } -// MulBy11 x *= 11 (mod q) -func MulBy11(x *Element) { - var y = Element{ - 1855201571499933546, - 8511318076631809892, - 6222514765367795509, - 1122129207579058019, - } - x.Mul(x, &y) -} - // MulBy13 x *= 13 (mod q) func MulBy13(x *Element) { var y = Element{ diff --git a/ecc/bls12-381/fp/element_amd64.go b/ecc/bls12-381/fp/element_amd64.go index 1ce1d184ce..ff2159178d 100644 --- a/ecc/bls12-381/fp/element_amd64.go +++ b/ecc/bls12-381/fp/element_amd64.go @@ -20,9 +20,6 @@ func MulBy3(x *Element) //go:noescape func MulBy5(x *Element) -//go:noescape -func MulBy11(x *Element) - //go:noescape func MulBy13(x *Element) diff --git a/ecc/bls12-381/fp/element_arm64.go b/ecc/bls12-381/fp/element_arm64.go index 1bab17d214..6cbd040cdb 100644 --- a/ecc/bls12-381/fp/element_arm64.go +++ b/ecc/bls12-381/fp/element_arm64.go @@ -51,19 +51,6 @@ func MulBy5(x *Element) { x.Double(x).Double(x).Add(x, &_x) } -// MulBy11 x *= 11 (mod q) -func MulBy11(x *Element) { - var y = Element{ - 9830232086645309404, - 1112389714365644829, - 8603885298299447491, - 11361495444721768256, - 5788602283869803809, - 543934104870762216, - } - x.Mul(x, &y) -} - // MulBy13 x *= 13 (mod q) func MulBy13(x *Element) { var y = Element{ diff --git a/ecc/bls12-381/fp/element_purego.go b/ecc/bls12-381/fp/element_purego.go index 51fa620cc5..f3170f77e0 100644 --- a/ecc/bls12-381/fp/element_purego.go +++ b/ecc/bls12-381/fp/element_purego.go @@ -21,19 +21,6 @@ func MulBy5(x *Element) { x.Double(x).Double(x).Add(x, &_x) } -// MulBy11 x *= 11 (mod q) -func MulBy11(x *Element) { - var y = Element{ - 9830232086645309404, - 1112389714365644829, - 8603885298299447491, - 11361495444721768256, - 5788602283869803809, - 543934104870762216, - } - x.Mul(x, &y) -} - // MulBy13 x *= 13 (mod q) func MulBy13(x *Element) { var y = Element{ diff --git a/ecc/bls12-381/fr/element_amd64.go b/ecc/bls12-381/fr/element_amd64.go index 0d47036fea..c282ebc9fc 100644 --- a/ecc/bls12-381/fr/element_amd64.go +++ b/ecc/bls12-381/fr/element_amd64.go @@ -20,9 +20,6 @@ func MulBy3(x *Element) //go:noescape func MulBy5(x *Element) -//go:noescape -func MulBy11(x *Element) - //go:noescape func MulBy13(x *Element) diff --git a/ecc/bls12-381/fr/element_arm64.go b/ecc/bls12-381/fr/element_arm64.go index 4c0a693822..e8b6cb4d0f 100644 --- a/ecc/bls12-381/fr/element_arm64.go +++ b/ecc/bls12-381/fr/element_arm64.go @@ -51,17 +51,6 @@ func MulBy5(x *Element) { x.Double(x).Double(x).Add(x, &_x) } -// MulBy11 x *= 11 (mod q) -func MulBy11(x *Element) { - var y = Element{ - 103079215080, - 2754126784762437656, - 3644466801193238400, - 2429780183658283323, - } - x.Mul(x, &y) -} - // MulBy13 x *= 13 (mod q) func MulBy13(x *Element) { var y = Element{ diff --git a/ecc/bls12-381/fr/element_purego.go b/ecc/bls12-381/fr/element_purego.go index 7a7f32273c..42ba2b9bbc 100644 --- a/ecc/bls12-381/fr/element_purego.go +++ b/ecc/bls12-381/fr/element_purego.go @@ -21,17 +21,6 @@ func MulBy5(x *Element) { x.Double(x).Double(x).Add(x, &_x) } -// MulBy11 x *= 11 (mod q) -func MulBy11(x *Element) { - var y = Element{ - 103079215080, - 2754126784762437656, - 3644466801193238400, - 2429780183658283323, - } - x.Mul(x, &y) -} - // MulBy13 x *= 13 (mod q) func MulBy13(x *Element) { var y = Element{ diff --git a/ecc/bls24-315/fp/element_amd64.go b/ecc/bls24-315/fp/element_amd64.go index 58d6cab877..f44ea0f280 100644 --- a/ecc/bls24-315/fp/element_amd64.go +++ b/ecc/bls24-315/fp/element_amd64.go @@ -20,9 +20,6 @@ func MulBy3(x *Element) //go:noescape func MulBy5(x *Element) -//go:noescape -func MulBy11(x *Element) - //go:noescape func MulBy13(x *Element) diff --git a/ecc/bls24-315/fp/element_purego.go b/ecc/bls24-315/fp/element_purego.go index e6cd7b87f2..ce12129cb7 100644 --- a/ecc/bls24-315/fp/element_purego.go +++ b/ecc/bls24-315/fp/element_purego.go @@ -21,18 +21,6 @@ func MulBy5(x *Element) { x.Double(x).Double(x).Add(x, &_x) } -// MulBy11 x *= 11 (mod q) -func MulBy11(x *Element) { - var y = Element{ - 12060944069680954801, - 6533417917463940959, - 13731636354790192199, - 12113897946221733884, - 260104589233568614, - } - x.Mul(x, &y) -} - // MulBy13 x *= 13 (mod q) func MulBy13(x *Element) { var y = Element{ diff --git a/ecc/bls24-315/fr/element_amd64.go b/ecc/bls24-315/fr/element_amd64.go index 0d47036fea..c282ebc9fc 100644 --- a/ecc/bls24-315/fr/element_amd64.go +++ b/ecc/bls24-315/fr/element_amd64.go @@ -20,9 +20,6 @@ func MulBy3(x *Element) //go:noescape func MulBy5(x *Element) -//go:noescape -func MulBy11(x *Element) - //go:noescape func MulBy13(x *Element) diff --git a/ecc/bls24-315/fr/element_arm64.go b/ecc/bls24-315/fr/element_arm64.go index 9c430a1850..1adc4b91e8 100644 --- a/ecc/bls24-315/fr/element_arm64.go +++ b/ecc/bls24-315/fr/element_arm64.go @@ -51,17 +51,6 @@ func MulBy5(x *Element) { x.Double(x).Double(x).Add(x, &_x) } -// MulBy11 x *= 11 (mod q) -func MulBy11(x *Element) { - var y = Element{ - 16738451865775112082, - 13515472034404387580, - 12502420588315234905, - 1352523014138543989, - } - x.Mul(x, &y) -} - // MulBy13 x *= 13 (mod q) func MulBy13(x *Element) { var y = Element{ diff --git a/ecc/bls24-315/fr/element_purego.go b/ecc/bls24-315/fr/element_purego.go index 0270404dee..6bf56f886f 100644 --- a/ecc/bls24-315/fr/element_purego.go +++ b/ecc/bls24-315/fr/element_purego.go @@ -21,17 +21,6 @@ func MulBy5(x *Element) { x.Double(x).Double(x).Add(x, &_x) } -// MulBy11 x *= 11 (mod q) -func MulBy11(x *Element) { - var y = Element{ - 16738451865775112082, - 13515472034404387580, - 12502420588315234905, - 1352523014138543989, - } - x.Mul(x, &y) -} - // MulBy13 x *= 13 (mod q) func MulBy13(x *Element) { var y = Element{ diff --git a/ecc/bls24-317/fp/element_amd64.go b/ecc/bls24-317/fp/element_amd64.go index 58d6cab877..f44ea0f280 100644 --- a/ecc/bls24-317/fp/element_amd64.go +++ b/ecc/bls24-317/fp/element_amd64.go @@ -20,9 +20,6 @@ func MulBy3(x *Element) //go:noescape func MulBy5(x *Element) -//go:noescape -func MulBy11(x *Element) - //go:noescape func MulBy13(x *Element) diff --git a/ecc/bls24-317/fp/element_purego.go b/ecc/bls24-317/fp/element_purego.go index c47cf086ad..b5c1224c69 100644 --- a/ecc/bls24-317/fp/element_purego.go +++ b/ecc/bls24-317/fp/element_purego.go @@ -21,18 +21,6 @@ func MulBy5(x *Element) { x.Double(x).Double(x).Add(x, &_x) } -// MulBy11 x *= 11 (mod q) -func MulBy11(x *Element) { - var y = Element{ - 969643881593263388, - 10706493019329091321, - 15007745612662235239, - 533456672378067364, - 313053900571923917, - } - x.Mul(x, &y) -} - // MulBy13 x *= 13 (mod q) func MulBy13(x *Element) { var y = Element{ diff --git a/ecc/bls24-317/fr/element_amd64.go b/ecc/bls24-317/fr/element_amd64.go index 0d47036fea..c282ebc9fc 100644 --- a/ecc/bls24-317/fr/element_amd64.go +++ b/ecc/bls24-317/fr/element_amd64.go @@ -20,9 +20,6 @@ func MulBy3(x *Element) //go:noescape func MulBy5(x *Element) -//go:noescape -func MulBy11(x *Element) - //go:noescape func MulBy13(x *Element) diff --git a/ecc/bls24-317/fr/element_arm64.go b/ecc/bls24-317/fr/element_arm64.go index 06d2903cf4..9610c74eda 100644 --- a/ecc/bls24-317/fr/element_arm64.go +++ b/ecc/bls24-317/fr/element_arm64.go @@ -51,17 +51,6 @@ func MulBy5(x *Element) { x.Double(x).Double(x).Add(x, &_x) } -// MulBy11 x *= 11 (mod q) -func MulBy11(x *Element) { - var y = Element{ - 10376293541461622743, - 7089204225672392271, - 10644163330234916682, - 1284003869223737804, - } - x.Mul(x, &y) -} - // MulBy13 x *= 13 (mod q) func MulBy13(x *Element) { var y = Element{ diff --git a/ecc/bls24-317/fr/element_purego.go b/ecc/bls24-317/fr/element_purego.go index cb8f035425..7c6745f270 100644 --- a/ecc/bls24-317/fr/element_purego.go +++ b/ecc/bls24-317/fr/element_purego.go @@ -21,17 +21,6 @@ func MulBy5(x *Element) { x.Double(x).Double(x).Add(x, &_x) } -// MulBy11 x *= 11 (mod q) -func MulBy11(x *Element) { - var y = Element{ - 10376293541461622743, - 7089204225672392271, - 10644163330234916682, - 1284003869223737804, - } - x.Mul(x, &y) -} - // MulBy13 x *= 13 (mod q) func MulBy13(x *Element) { var y = Element{ diff --git a/ecc/bn254/fp/element_amd64.go b/ecc/bn254/fp/element_amd64.go index 339df6f656..e02a9d04c2 100644 --- a/ecc/bn254/fp/element_amd64.go +++ b/ecc/bn254/fp/element_amd64.go @@ -20,9 +20,6 @@ func MulBy3(x *Element) //go:noescape func MulBy5(x *Element) -//go:noescape -func MulBy11(x *Element) - //go:noescape func MulBy13(x *Element) diff --git a/ecc/bn254/fp/element_arm64.go b/ecc/bn254/fp/element_arm64.go index b543f3a5e7..4d030715d6 100644 --- a/ecc/bn254/fp/element_arm64.go +++ b/ecc/bn254/fp/element_arm64.go @@ -51,17 +51,6 @@ func MulBy5(x *Element) { x.Double(x).Double(x).Add(x, &_x) } -// MulBy11 x *= 11 (mod q) -func MulBy11(x *Element) { - var y = Element{ - 6962638497713659370, - 12442842200117091328, - 4454117921868872395, - 668285336232769164, - } - x.Mul(x, &y) -} - // MulBy13 x *= 13 (mod q) func MulBy13(x *Element) { var y = Element{ diff --git a/ecc/bn254/fp/element_purego.go b/ecc/bn254/fp/element_purego.go index 47d5834b0d..69565d890b 100644 --- a/ecc/bn254/fp/element_purego.go +++ b/ecc/bn254/fp/element_purego.go @@ -21,17 +21,6 @@ func MulBy5(x *Element) { x.Double(x).Double(x).Add(x, &_x) } -// MulBy11 x *= 11 (mod q) -func MulBy11(x *Element) { - var y = Element{ - 6962638497713659370, - 12442842200117091328, - 4454117921868872395, - 668285336232769164, - } - x.Mul(x, &y) -} - // MulBy13 x *= 13 (mod q) func MulBy13(x *Element) { var y = Element{ diff --git a/ecc/bn254/fr/element_amd64.go b/ecc/bn254/fr/element_amd64.go index 0d47036fea..c282ebc9fc 100644 --- a/ecc/bn254/fr/element_amd64.go +++ b/ecc/bn254/fr/element_amd64.go @@ -20,9 +20,6 @@ func MulBy3(x *Element) //go:noescape func MulBy5(x *Element) -//go:noescape -func MulBy11(x *Element) - //go:noescape func MulBy13(x *Element) diff --git a/ecc/bn254/fr/element_arm64.go b/ecc/bn254/fr/element_arm64.go index ed13fb0c7a..b99b03a7e9 100644 --- a/ecc/bn254/fr/element_arm64.go +++ b/ecc/bn254/fr/element_arm64.go @@ -51,17 +51,6 @@ func MulBy5(x *Element) { x.Double(x).Double(x).Add(x, &_x) } -// MulBy11 x *= 11 (mod q) -func MulBy11(x *Element) { - var y = Element{ - 11443185389230096326, - 16446406505298427670, - 4454117921868872420, - 668285336232769164, - } - x.Mul(x, &y) -} - // MulBy13 x *= 13 (mod q) func MulBy13(x *Element) { var y = Element{ diff --git a/ecc/bn254/fr/element_purego.go b/ecc/bn254/fr/element_purego.go index a8f4aa372e..8b6bab2e09 100644 --- a/ecc/bn254/fr/element_purego.go +++ b/ecc/bn254/fr/element_purego.go @@ -21,17 +21,6 @@ func MulBy5(x *Element) { x.Double(x).Double(x).Add(x, &_x) } -// MulBy11 x *= 11 (mod q) -func MulBy11(x *Element) { - var y = Element{ - 11443185389230096326, - 16446406505298427670, - 4454117921868872420, - 668285336232769164, - } - x.Mul(x, &y) -} - // MulBy13 x *= 13 (mod q) func MulBy13(x *Element) { var y = Element{ diff --git a/ecc/bw6-633/fp/element_amd64.go b/ecc/bw6-633/fp/element_amd64.go index 5f400bae79..cdc4e7d2cc 100644 --- a/ecc/bw6-633/fp/element_amd64.go +++ b/ecc/bw6-633/fp/element_amd64.go @@ -20,9 +20,6 @@ func MulBy3(x *Element) //go:noescape func MulBy5(x *Element) -//go:noescape -func MulBy11(x *Element) - //go:noescape func MulBy13(x *Element) diff --git a/ecc/bw6-633/fp/element_arm64.go b/ecc/bw6-633/fp/element_arm64.go index 3a4f73fcc4..1a85c82439 100644 --- a/ecc/bw6-633/fp/element_arm64.go +++ b/ecc/bw6-633/fp/element_arm64.go @@ -51,23 +51,6 @@ func MulBy5(x *Element) { x.Double(x).Double(x).Add(x, &_x) } -// MulBy11 x *= 11 (mod q) -func MulBy11(x *Element) { - var y = Element{ - 6130771042861286320, - 11947466704102345269, - 5006184736040647654, - 10738967583325648129, - 6155303802163134778, - 6459686480506411032, - 14448065740527999419, - 1019798761927372322, - 5080373183861200608, - 66158761009468389, - } - x.Mul(x, &y) -} - // MulBy13 x *= 13 (mod q) func MulBy13(x *Element) { var y = Element{ diff --git a/ecc/bw6-633/fp/element_purego.go b/ecc/bw6-633/fp/element_purego.go index 1c5c4719ef..0bf06ee060 100644 --- a/ecc/bw6-633/fp/element_purego.go +++ b/ecc/bw6-633/fp/element_purego.go @@ -21,23 +21,6 @@ func MulBy5(x *Element) { x.Double(x).Double(x).Add(x, &_x) } -// MulBy11 x *= 11 (mod q) -func MulBy11(x *Element) { - var y = Element{ - 6130771042861286320, - 11947466704102345269, - 5006184736040647654, - 10738967583325648129, - 6155303802163134778, - 6459686480506411032, - 14448065740527999419, - 1019798761927372322, - 5080373183861200608, - 66158761009468389, - } - x.Mul(x, &y) -} - // MulBy13 x *= 13 (mod q) func MulBy13(x *Element) { var y = Element{ diff --git a/ecc/bw6-633/fr/element_amd64.go b/ecc/bw6-633/fr/element_amd64.go index 5ad10bda95..8577a5d289 100644 --- a/ecc/bw6-633/fr/element_amd64.go +++ b/ecc/bw6-633/fr/element_amd64.go @@ -20,9 +20,6 @@ func MulBy3(x *Element) //go:noescape func MulBy5(x *Element) -//go:noescape -func MulBy11(x *Element) - //go:noescape func MulBy13(x *Element) diff --git a/ecc/bw6-633/fr/element_purego.go b/ecc/bw6-633/fr/element_purego.go index eb3ed64910..08da5bd7f8 100644 --- a/ecc/bw6-633/fr/element_purego.go +++ b/ecc/bw6-633/fr/element_purego.go @@ -21,18 +21,6 @@ func MulBy5(x *Element) { x.Double(x).Double(x).Add(x, &_x) } -// MulBy11 x *= 11 (mod q) -func MulBy11(x *Element) { - var y = Element{ - 12060944069680954801, - 6533417917463940959, - 13731636354790192199, - 12113897946221733884, - 260104589233568614, - } - x.Mul(x, &y) -} - // MulBy13 x *= 13 (mod q) func MulBy13(x *Element) { var y = Element{ diff --git a/ecc/bw6-761/fp/element_amd64.go b/ecc/bw6-761/fp/element_amd64.go index d6bdef8f4b..72f398ecf0 100644 --- a/ecc/bw6-761/fp/element_amd64.go +++ b/ecc/bw6-761/fp/element_amd64.go @@ -20,9 +20,6 @@ func MulBy3(x *Element) //go:noescape func MulBy5(x *Element) -//go:noescape -func MulBy11(x *Element) - //go:noescape func MulBy13(x *Element) diff --git a/ecc/bw6-761/fp/element_arm64.go b/ecc/bw6-761/fp/element_arm64.go index 1d17426266..bb6a6a7769 100644 --- a/ecc/bw6-761/fp/element_arm64.go +++ b/ecc/bw6-761/fp/element_arm64.go @@ -51,25 +51,6 @@ func MulBy5(x *Element) { x.Double(x).Double(x).Add(x, &_x) } -// MulBy11 x *= 11 (mod q) -func MulBy11(x *Element) { - var y = Element{ - 4056054414400208518, - 3320816571827031140, - 10263935383895698150, - 11003897938091601562, - 15597443347325643510, - 13135057492086854609, - 2659919018052618801, - 3683105852685266909, - 6137961753831301777, - 15077955943918945393, - 14961510259660508891, - 8138608324875079, - } - x.Mul(x, &y) -} - // MulBy13 x *= 13 (mod q) func MulBy13(x *Element) { var y = Element{ diff --git a/ecc/bw6-761/fp/element_purego.go b/ecc/bw6-761/fp/element_purego.go index 763cca7036..8c78ab1700 100644 --- a/ecc/bw6-761/fp/element_purego.go +++ b/ecc/bw6-761/fp/element_purego.go @@ -21,25 +21,6 @@ func MulBy5(x *Element) { x.Double(x).Double(x).Add(x, &_x) } -// MulBy11 x *= 11 (mod q) -func MulBy11(x *Element) { - var y = Element{ - 4056054414400208518, - 3320816571827031140, - 10263935383895698150, - 11003897938091601562, - 15597443347325643510, - 13135057492086854609, - 2659919018052618801, - 3683105852685266909, - 6137961753831301777, - 15077955943918945393, - 14961510259660508891, - 8138608324875079, - } - x.Mul(x, &y) -} - // MulBy13 x *= 13 (mod q) func MulBy13(x *Element) { var y = Element{ diff --git a/ecc/bw6-761/fr/element_amd64.go b/ecc/bw6-761/fr/element_amd64.go index 8e6398c7e9..20f1f9a3f0 100644 --- a/ecc/bw6-761/fr/element_amd64.go +++ b/ecc/bw6-761/fr/element_amd64.go @@ -20,9 +20,6 @@ func MulBy3(x *Element) //go:noescape func MulBy5(x *Element) -//go:noescape -func MulBy11(x *Element) - //go:noescape func MulBy13(x *Element) diff --git a/ecc/bw6-761/fr/element_arm64.go b/ecc/bw6-761/fr/element_arm64.go index 023ae341f2..f82cdfccd8 100644 --- a/ecc/bw6-761/fr/element_arm64.go +++ b/ecc/bw6-761/fr/element_arm64.go @@ -51,19 +51,6 @@ func MulBy5(x *Element) { x.Double(x).Double(x).Add(x, &_x) } -// MulBy11 x *= 11 (mod q) -func MulBy11(x *Element) { - var y = Element{ - 10358208774207961461, - 4081601403594734745, - 9046765978545153897, - 18300367227737147024, - 18145387698699229771, - 74511027426447328, - } - x.Mul(x, &y) -} - // MulBy13 x *= 13 (mod q) func MulBy13(x *Element) { var y = Element{ diff --git a/ecc/bw6-761/fr/element_purego.go b/ecc/bw6-761/fr/element_purego.go index b68970870d..2c60f3c457 100644 --- a/ecc/bw6-761/fr/element_purego.go +++ b/ecc/bw6-761/fr/element_purego.go @@ -21,19 +21,6 @@ func MulBy5(x *Element) { x.Double(x).Double(x).Add(x, &_x) } -// MulBy11 x *= 11 (mod q) -func MulBy11(x *Element) { - var y = Element{ - 10358208774207961461, - 4081601403594734745, - 9046765978545153897, - 18300367227737147024, - 18145387698699229771, - 74511027426447328, - } - x.Mul(x, &y) -} - // MulBy13 x *= 13 (mod q) func MulBy13(x *Element) { var y = Element{ diff --git a/ecc/grumpkin/fp/element_amd64.go b/ecc/grumpkin/fp/element_amd64.go index 339df6f656..e02a9d04c2 100644 --- a/ecc/grumpkin/fp/element_amd64.go +++ b/ecc/grumpkin/fp/element_amd64.go @@ -20,9 +20,6 @@ func MulBy3(x *Element) //go:noescape func MulBy5(x *Element) -//go:noescape -func MulBy11(x *Element) - //go:noescape func MulBy13(x *Element) diff --git a/ecc/grumpkin/fp/element_arm64.go b/ecc/grumpkin/fp/element_arm64.go index bfdaa68a63..6a41dba9de 100644 --- a/ecc/grumpkin/fp/element_arm64.go +++ b/ecc/grumpkin/fp/element_arm64.go @@ -51,17 +51,6 @@ func MulBy5(x *Element) { x.Double(x).Double(x).Add(x, &_x) } -// MulBy11 x *= 11 (mod q) -func MulBy11(x *Element) { - var y = Element{ - 11443185389230096326, - 16446406505298427670, - 4454117921868872420, - 668285336232769164, - } - x.Mul(x, &y) -} - // MulBy13 x *= 13 (mod q) func MulBy13(x *Element) { var y = Element{ diff --git a/ecc/grumpkin/fp/element_purego.go b/ecc/grumpkin/fp/element_purego.go index 5e5b436a58..247946286b 100644 --- a/ecc/grumpkin/fp/element_purego.go +++ b/ecc/grumpkin/fp/element_purego.go @@ -21,17 +21,6 @@ func MulBy5(x *Element) { x.Double(x).Double(x).Add(x, &_x) } -// MulBy11 x *= 11 (mod q) -func MulBy11(x *Element) { - var y = Element{ - 11443185389230096326, - 16446406505298427670, - 4454117921868872420, - 668285336232769164, - } - x.Mul(x, &y) -} - // MulBy13 x *= 13 (mod q) func MulBy13(x *Element) { var y = Element{ diff --git a/ecc/grumpkin/fr/element_amd64.go b/ecc/grumpkin/fr/element_amd64.go index 0d47036fea..c282ebc9fc 100644 --- a/ecc/grumpkin/fr/element_amd64.go +++ b/ecc/grumpkin/fr/element_amd64.go @@ -20,9 +20,6 @@ func MulBy3(x *Element) //go:noescape func MulBy5(x *Element) -//go:noescape -func MulBy11(x *Element) - //go:noescape func MulBy13(x *Element) diff --git a/ecc/grumpkin/fr/element_arm64.go b/ecc/grumpkin/fr/element_arm64.go index 056977925b..03421559cc 100644 --- a/ecc/grumpkin/fr/element_arm64.go +++ b/ecc/grumpkin/fr/element_arm64.go @@ -51,17 +51,6 @@ func MulBy5(x *Element) { x.Double(x).Double(x).Add(x, &_x) } -// MulBy11 x *= 11 (mod q) -func MulBy11(x *Element) { - var y = Element{ - 6962638497713659370, - 12442842200117091328, - 4454117921868872395, - 668285336232769164, - } - x.Mul(x, &y) -} - // MulBy13 x *= 13 (mod q) func MulBy13(x *Element) { var y = Element{ diff --git a/ecc/grumpkin/fr/element_purego.go b/ecc/grumpkin/fr/element_purego.go index 9e6469da4e..e4b9c87ac4 100644 --- a/ecc/grumpkin/fr/element_purego.go +++ b/ecc/grumpkin/fr/element_purego.go @@ -21,17 +21,6 @@ func MulBy5(x *Element) { x.Double(x).Double(x).Add(x, &_x) } -// MulBy11 x *= 11 (mod q) -func MulBy11(x *Element) { - var y = Element{ - 6962638497713659370, - 12442842200117091328, - 4454117921868872395, - 668285336232769164, - } - x.Mul(x, &y) -} - // MulBy13 x *= 13 (mod q) func MulBy13(x *Element) { var y = Element{ diff --git a/ecc/secp256k1/fp/element_purego.go b/ecc/secp256k1/fp/element_purego.go index 1ffd1bb174..5650ed6925 100644 --- a/ecc/secp256k1/fp/element_purego.go +++ b/ecc/secp256k1/fp/element_purego.go @@ -19,17 +19,6 @@ func MulBy5(x *Element) { x.Double(x).Double(x).Add(x, &_x) } -// MulBy11 x *= 11 (mod q) -func MulBy11(x *Element) { - var y = Element{ - 47244651003, - 0, - 0, - 0, - } - x.Mul(x, &y) -} - // MulBy13 x *= 13 (mod q) func MulBy13(x *Element) { var y = Element{ diff --git a/ecc/secp256k1/fr/element_purego.go b/ecc/secp256k1/fr/element_purego.go index 9fe91a36d9..32720596b7 100644 --- a/ecc/secp256k1/fr/element_purego.go +++ b/ecc/secp256k1/fr/element_purego.go @@ -19,17 +19,6 @@ func MulBy5(x *Element) { x.Double(x).Double(x).Add(x, &_x) } -// MulBy11 x *= 11 (mod q) -func MulBy11(x *Element) { - var y = Element{ - 13976340845799617077, - 18049444439606238574, - 13, - 0, - } - x.Mul(x, &y) -} - // MulBy13 x *= 13 (mod q) func MulBy13(x *Element) { var y = Element{ diff --git a/ecc/stark-curve/fp/element_amd64.go b/ecc/stark-curve/fp/element_amd64.go index 339df6f656..e02a9d04c2 100644 --- a/ecc/stark-curve/fp/element_amd64.go +++ b/ecc/stark-curve/fp/element_amd64.go @@ -20,9 +20,6 @@ func MulBy3(x *Element) //go:noescape func MulBy5(x *Element) -//go:noescape -func MulBy11(x *Element) - //go:noescape func MulBy13(x *Element) diff --git a/ecc/stark-curve/fp/element_arm64.go b/ecc/stark-curve/fp/element_arm64.go index dca778dba7..ee729af225 100644 --- a/ecc/stark-curve/fp/element_arm64.go +++ b/ecc/stark-curve/fp/element_arm64.go @@ -51,17 +51,6 @@ func MulBy5(x *Element) { x.Double(x).Double(x).Add(x, &_x) } -// MulBy11 x *= 11 (mod q) -func MulBy11(x *Element) { - var y = Element{ - 18446744073709551265, - 18446744073709551615, - 18446744073709551615, - 576460752303417520, - } - x.Mul(x, &y) -} - // MulBy13 x *= 13 (mod q) func MulBy13(x *Element) { var y = Element{ diff --git a/ecc/stark-curve/fp/element_purego.go b/ecc/stark-curve/fp/element_purego.go index 7c5f53408d..bfbebf9634 100644 --- a/ecc/stark-curve/fp/element_purego.go +++ b/ecc/stark-curve/fp/element_purego.go @@ -21,17 +21,6 @@ func MulBy5(x *Element) { x.Double(x).Double(x).Add(x, &_x) } -// MulBy11 x *= 11 (mod q) -func MulBy11(x *Element) { - var y = Element{ - 18446744073709551265, - 18446744073709551615, - 18446744073709551615, - 576460752303417520, - } - x.Mul(x, &y) -} - // MulBy13 x *= 13 (mod q) func MulBy13(x *Element) { var y = Element{ diff --git a/ecc/stark-curve/fr/element_amd64.go b/ecc/stark-curve/fr/element_amd64.go index 0d47036fea..c282ebc9fc 100644 --- a/ecc/stark-curve/fr/element_amd64.go +++ b/ecc/stark-curve/fr/element_amd64.go @@ -20,9 +20,6 @@ func MulBy3(x *Element) //go:noescape func MulBy5(x *Element) -//go:noescape -func MulBy11(x *Element) - //go:noescape func MulBy13(x *Element) diff --git a/ecc/stark-curve/fr/element_arm64.go b/ecc/stark-curve/fr/element_arm64.go index 3c3e96fd2e..58e9415131 100644 --- a/ecc/stark-curve/fr/element_arm64.go +++ b/ecc/stark-curve/fr/element_arm64.go @@ -51,17 +51,6 @@ func MulBy5(x *Element) { x.Double(x).Double(x).Add(x, &_x) } -// MulBy11 x *= 11 (mod q) -func MulBy11(x *Element) { - var y = Element{ - 5856799317043195023, - 7352051035614129480, - 99, - 576460752303417521, - } - x.Mul(x, &y) -} - // MulBy13 x *= 13 (mod q) func MulBy13(x *Element) { var y = Element{ diff --git a/ecc/stark-curve/fr/element_purego.go b/ecc/stark-curve/fr/element_purego.go index c61471a299..a0cbe29f1c 100644 --- a/ecc/stark-curve/fr/element_purego.go +++ b/ecc/stark-curve/fr/element_purego.go @@ -21,17 +21,6 @@ func MulBy5(x *Element) { x.Double(x).Double(x).Add(x, &_x) } -// MulBy11 x *= 11 (mod q) -func MulBy11(x *Element) { - var y = Element{ - 5856799317043195023, - 7352051035614129480, - 99, - 576460752303417521, - } - x.Mul(x, &y) -} - // MulBy13 x *= 13 (mod q) func MulBy13(x *Element) { var y = Element{ diff --git a/field/babybear/element_purego.go b/field/babybear/element_purego.go index 7d2129b82e..c945436e98 100644 --- a/field/babybear/element_purego.go +++ b/field/babybear/element_purego.go @@ -19,13 +19,6 @@ func MulBy5(x *Element) { x.Mul(x, &y) } -// MulBy11 x *= 11 (mod q) -func MulBy11(x *Element) { - var y Element - y.SetUint64(11) - x.Mul(x, &y) -} - // MulBy13 x *= 13 (mod q) func MulBy13(x *Element) { var y Element diff --git a/field/babybear/extensions/e2_babybear.go b/field/babybear/extensions/e2_babybear.go index 5939d787ea..dd45cd43b9 100644 --- a/field/babybear/extensions/e2_babybear.go +++ b/field/babybear/extensions/e2_babybear.go @@ -4,6 +4,14 @@ import ( fr "github.com/consensys/gnark-crypto/field/babybear" ) +// MulBy11 x *= 11 (mod q) +func MulBy11(x *fr.Element) { + var y fr.Element + y.SetUint64(11) + x.Mul(x, &y) + +} + // Mul sets z to the E2-product of x,y, returns z func (z *E2) Mul(x, y *E2) *E2 { var a, b, c fr.Element @@ -13,7 +21,7 @@ func (z *E2) Mul(x, y *E2) *E2 { b.Mul(&x.A0, &y.A0) c.Mul(&x.A1, &y.A1) z.A1.Sub(&a, &b).Sub(&z.A1, &c) - fr.MulBy11(&c) + MulBy11(&c) z.A0.Add(&b, &c) return z } @@ -24,7 +32,7 @@ func (z *E2) Square(x *E2) *E2 { a.Mul(&x.A0, &x.A1).Double(&a) c.Square(&x.A0) b.Square(&x.A1) - fr.MulBy11(&b) + MulBy11(&b) z.A0.Add(&c, &b) z.A1 = a return z @@ -34,7 +42,7 @@ func (z *E2) Square(x *E2) *E2 { func (z *E2) MulByNonResidue(x *E2) *E2 { a := x.A0 b := x.A1 // fetching x.A1 in the function below is slower - fr.MulBy11(&b) + MulBy11(&b) z.A0 = b z.A1 = a return z @@ -60,7 +68,7 @@ func (z *E2) Inverse(x *E2) *E2 { t0.Square(a) t1.Square(b) tmp.Set(&t1) - fr.MulBy11(&tmp) + MulBy11(&tmp) t0.Sub(&t0, &tmp) t1.Inverse(&t0) z.A0.Mul(a, &t1) @@ -74,6 +82,6 @@ func (z *E2) norm(x *fr.Element) { var tmp fr.Element x.Square(&z.A1) tmp.Set(x) - fr.MulBy11(&tmp) + MulBy11(&tmp) x.Square(&z.A0).Sub(x, &tmp) } diff --git a/field/generator/internal/templates/element/ops_asm.go b/field/generator/internal/templates/element/ops_asm.go index 4d402e4456..d82cfead74 100644 --- a/field/generator/internal/templates/element/ops_asm.go +++ b/field/generator/internal/templates/element/ops_asm.go @@ -16,9 +16,6 @@ func MulBy3(x *{{.ElementName}}) //go:noescape func MulBy5(x *{{.ElementName}}) -//go:noescape -func MulBy11(x *{{.ElementName}}) - //go:noescape func MulBy13(x *{{.ElementName}}) @@ -96,7 +93,7 @@ func (z *{{.ElementName}}) Square(x *{{.ElementName}}) *{{.ElementName}} { } -{{ $mulConsts := list 3 5 11 13 }} +{{ $mulConsts := list 3 5 13 }} {{- range $i := $mulConsts }} // MulBy{{$i}} x *= {{$i}} (mod q) @@ -112,12 +109,6 @@ func MulBy{{$i}}(x *{{$.ElementName}}) { {{- else if eq $i 5}} _x := *x x.Double(x).Double(x).Add(x, &_x) - {{- else if eq $i 11}} - var y = {{$.ElementName}}{ - {{- range $i := $.Eleven}} - {{$i}},{{end}} - } - x.Mul(x, &y) {{- else if eq $i 13}} var y = {{$.ElementName}}{ {{- range $i := $.Thirteen}} diff --git a/field/generator/internal/templates/element/ops_purego.go b/field/generator/internal/templates/element/ops_purego.go index a9793c87c7..31d45c8d92 100644 --- a/field/generator/internal/templates/element/ops_purego.go +++ b/field/generator/internal/templates/element/ops_purego.go @@ -6,7 +6,7 @@ const OpsNoAsm = ` import "math/bits" {{- end}} -{{ $mulConsts := list 3 5 11 13 }} +{{ $mulConsts := list 3 5 13 }} {{- range $i := $mulConsts }} // MulBy{{$i}} x *= {{$i}} (mod q) @@ -22,12 +22,6 @@ func MulBy{{$i}}(x *{{$.ElementName}}) { {{- else if eq $i 5}} _x := *x x.Double(x).Double(x).Add(x, &_x) - {{- else if eq $i 11}} - var y = {{$.ElementName}}{ - {{- range $i := $.Eleven}} - {{$i}},{{end}} - } - x.Mul(x, &y) {{- else if eq $i 13}} var y = {{$.ElementName}}{ {{- range $i := $.Thirteen}} diff --git a/field/goldilocks/element_purego.go b/field/goldilocks/element_purego.go index 5e05644c8b..47da790b25 100644 --- a/field/goldilocks/element_purego.go +++ b/field/goldilocks/element_purego.go @@ -21,13 +21,6 @@ func MulBy5(x *Element) { x.Mul(x, &y) } -// MulBy11 x *= 11 (mod q) -func MulBy11(x *Element) { - var y Element - y.SetUint64(11) - x.Mul(x, &y) -} - // MulBy13 x *= 13 (mod q) func MulBy13(x *Element) { var y Element diff --git a/field/koalabear/element_purego.go b/field/koalabear/element_purego.go index 1627344a3d..cfcaaade6a 100644 --- a/field/koalabear/element_purego.go +++ b/field/koalabear/element_purego.go @@ -19,13 +19,6 @@ func MulBy5(x *Element) { x.Mul(x, &y) } -// MulBy11 x *= 11 (mod q) -func MulBy11(x *Element) { - var y Element - y.SetUint64(11) - x.Mul(x, &y) -} - // MulBy13 x *= 13 (mod q) func MulBy13(x *Element) { var y Element