From 17381be98d0d83628c3bc466c6cc0686bec4b774 Mon Sep 17 00:00:00 2001 From: Yolan Romailler Date: Tue, 10 Dec 2024 19:37:05 +0100 Subject: [PATCH] Updating our dependencies and patching a bug in bn254/twist --- encrypt/ibe/ibe.go | 44 +++++++++++++++---------- go.mod | 16 +++++----- go.sum | 33 ++++++++++--------- pairing/bn254/gfp_decl.go | 2 +- pairing/bn254/point.go | 19 +++++++---- pairing/bn254/point_test.go | 64 +++++++++++++++++++++++++++++++++++++ pairing/bn254/suite.go | 2 +- pairing/bn254/twist.go | 1 + pairing/bn256/gfp_decl.go | 3 +- 9 files changed, 134 insertions(+), 50 deletions(-) diff --git a/encrypt/ibe/ibe.go b/encrypt/ibe/ibe.go index 4e688153b..fea7df77f 100644 --- a/encrypt/ibe/ibe.go +++ b/encrypt/ibe/ibe.go @@ -6,6 +6,7 @@ import ( "encoding/binary" "errors" "fmt" + "github.com/drand/kyber" "github.com/drand/kyber/group/mod" "github.com/drand/kyber/pairing" @@ -70,7 +71,7 @@ func EncryptCCAonG1(s pairing.Suite, master kyber.Point, ID, msg []byte) (*Ciphe return nil, err } // 4. Compute U = rP - U := s.G1().Point().Mul(r, s.G1().Point().Base()) + U := s.G1().Point().Mul(r, nil) // 5. Compute V = sigma XOR H2(rGid) rGid := Gid.Mul(r, Gid) // even in Gt, it's additive notation @@ -124,7 +125,7 @@ func DecryptCCAonG1(s pairing.Suite, private kyber.Point, c *Ciphertext) ([]byte if err != nil { return nil, err } - rP := s.G1().Point().Mul(r, s.G1().Point().Base()) + rP := s.G1().Point().Mul(r, nil) if !rP.Equal(c.U) { return nil, fmt.Errorf("invalid proof: rP check failed") } @@ -165,11 +166,13 @@ func EncryptCCAonG2(s pairing.Suite, master kyber.Point, ID, msg []byte) (*Ciphe return nil, err } // 4. Compute U = rP - U := s.G2().Point().Mul(r, s.G2().Point().Base()) + U := s.G2().Point().Mul(r, nil) // 5. Compute V = sigma XOR H2(rGid) rGid := Gid.Mul(r, Gid) // even in Gt, it's additive notation + hrGid, err := gtToHash(s, rGid, len(msg)) + if err != nil { return nil, err } @@ -197,6 +200,7 @@ func DecryptCCAonG2(s pairing.Suite, private kyber.Point, c *Ciphertext) ([]byte // 1. Compute sigma = V XOR H2(e(rP,private)) rGid := s.Pair(private, c.U) + hrGid, err := gtToHash(s, rGid, len(c.W)) if err != nil { return nil, err @@ -219,9 +223,9 @@ func DecryptCCAonG2(s pairing.Suite, private kyber.Point, c *Ciphertext) ([]byte if err != nil { return nil, err } - rP := s.G2().Point().Mul(r, s.G2().Point().Base()) + rP := s.G2().Point().Mul(r, nil) if !rP.Equal(c.U) { - return nil, fmt.Errorf("invalid proof: rP check failed") + return nil, fmt.Errorf("invalid proof: rP check failed on msg %s, r %x", msg, r) } return msg, nil } @@ -230,6 +234,10 @@ func DecryptCCAonG2(s pairing.Suite, private kyber.Point, c *Ciphertext) ([]byte func h3(s pairing.Suite, sigma, msg []byte) (kyber.Scalar, error) { h := s.Hash() + if h.Size() != s.G1().ScalarLen() { + return nil, fmt.Errorf("hash size mismatch with scalar length %d != %d", h.Size(), s.G1().ScalarLen()) + } + if _, err := h.Write(H3Tag()); err != nil { return nil, fmt.Errorf("err hashing h3 tag: %v", err) } @@ -265,9 +273,10 @@ func h3(s pairing.Suite, sigma, msg []byte) (kyber.Scalar, error) { } else { hashed[len(hashed)-1] = hashed[len(hashed)-1] >> toMask } + // NOTE: Here we unmarshal as a test if the buffer is within the modulo // because we know unmarshal does this test. This implementation - // is almost generic if not for this line. TO make it truly generic + // is almost generic if not for this line. To make it truly generic // we would need to add methods to create a scalar from bytes without // reduction and a method to check if it is within the modulo on the // Scalar interface. @@ -288,9 +297,8 @@ func h4(s pairing.Suite, sigma []byte, length int) ([]byte, error) { if _, err := h4.Write(sigma); err != nil { return nil, fmt.Errorf("err writing sigma to h4: %v", err) } - h4sigma := h4.Sum(nil)[:length] - return h4sigma, nil + return h4.Sum(nil)[:length], nil } func gtToHash(s pairing.Suite, gt kyber.Point, length int) ([]byte, error) { @@ -339,13 +347,15 @@ type CiphertextCPA struct { // H1: {0,1}^n -> G1 // H2: GT -> {0,1}^n // ID: Qid = H1(ID) = xP \in G2 -// secret did = s*Qid \in G2 +// +// secret did = s*Qid \in G2 +// // Encrypt: -// - random r scalar -// - Gid = e(Ppub, r*Qid) == e(P, P)^(x*s*r) \in GT -// = GidT -// - U = rP \in G1, -// - V = M XOR H2(Gid)) = M XOR H2(GidT) \in {0,1}^n +// - random r scalar +// - Gid = e(Ppub, r*Qid) == e(P, P)^(x*s*r) \in GT +// = GidT +// - U = rP \in G1, +// - V = M XOR H2(Gid)) = M XOR H2(GidT) \in {0,1}^n func EncryptCPAonG1(s pairing.Suite, basePoint, public kyber.Point, ID, msg []byte) (*CiphertextCPA, error) { if len(msg)>>16 > 0 { // we're using blake2 as XOF which only outputs 2^16-1 length @@ -382,9 +392,9 @@ func EncryptCPAonG1(s pairing.Suite, basePoint, public kyber.Point, ID, msg []by // SigGroup = G2 (large secret identities) // KeyGroup = G1 (short master public keys) // Decrypt: -// - V XOR H2(e(U, did)) = V XOR H2(e(rP, s*Qid)) -// = V XOR H2(e(P, P)^(r*s*x)) -// = V XOR H2(GidT) = M +// - V XOR H2(e(U, did)) = V XOR H2(e(rP, s*Qid)) +// = V XOR H2(e(P, P)^(r*s*x)) +// = V XOR H2(GidT) = M func DecryptCPAonG1(s pairing.Suite, private kyber.Point, c *CiphertextCPA) ([]byte, error) { GidT := s.Pair(c.RP, private) hGidT, err := gtToHash(s, GidT, len(c.C)) diff --git a/go.mod b/go.mod index b4505e7a2..b226988be 100644 --- a/go.mod +++ b/go.mod @@ -1,22 +1,22 @@ module github.com/drand/kyber -go 1.18 +go 1.22.10 require ( - github.com/cloudflare/circl v1.3.7 - github.com/consensys/gnark-crypto v0.12.1 + github.com/cloudflare/circl v1.5.0 + github.com/consensys/gnark-crypto v0.14.0 github.com/drand/kyber-bls12381 v0.3.1 github.com/jonboulle/clockwork v0.4.0 - github.com/stretchr/testify v1.9.0 + github.com/stretchr/testify v1.10.0 go.dedis.ch/fixbuf v1.0.3 go.dedis.ch/protobuf v1.0.11 - golang.org/x/crypto v0.21.0 - golang.org/x/sys v0.18.0 + golang.org/x/crypto v0.30.0 + golang.org/x/sys v0.28.0 ) require ( - github.com/bits-and-blooms/bitset v1.13.0 // indirect - github.com/consensys/bavard v0.1.13 // indirect + github.com/bits-and-blooms/bitset v1.19.1 // indirect + github.com/consensys/bavard v0.1.22 // indirect github.com/davecgh/go-spew v1.1.1 // indirect github.com/kilic/bls12-381 v0.1.0 // indirect github.com/kr/text v0.2.0 // indirect diff --git a/go.sum b/go.sum index d300c7cab..12d8ee47a 100644 --- a/go.sum +++ b/go.sum @@ -1,11 +1,11 @@ -github.com/bits-and-blooms/bitset v1.13.0 h1:bAQ9OPNFYbGHV6Nez0tmNI0RiEu7/hxlYJRUA0wFAVE= -github.com/bits-and-blooms/bitset v1.13.0/go.mod h1:7hO7Gc7Pp1vODcmWvKMRA9BNmbv6a/7QIWpPxHddWR8= -github.com/cloudflare/circl v1.3.7 h1:qlCDlTPz2n9fu58M0Nh1J/JzcFpfgkFHHX3O35r5vcU= -github.com/cloudflare/circl v1.3.7/go.mod h1:sRTcRWXGLrKw6yIGJ+l7amYJFfAXbZG0kBSc8r4zxgA= -github.com/consensys/bavard v0.1.13 h1:oLhMLOFGTLdlda/kma4VOJazblc7IM5y5QPd2A/YjhQ= -github.com/consensys/bavard v0.1.13/go.mod h1:9ItSMtA/dXMAiL7BG6bqW2m3NdSEObYWoH223nGHukI= -github.com/consensys/gnark-crypto v0.12.1 h1:lHH39WuuFgVHONRl3J0LRBtuYdQTumFSDtJF7HpyG8M= -github.com/consensys/gnark-crypto v0.12.1/go.mod h1:v2Gy7L/4ZRosZ7Ivs+9SfUDr0f5UlG+EM5t7MPHiLuY= +github.com/bits-and-blooms/bitset v1.19.1 h1:mv2yVhy96D2CuskLPXnc58oJNMs5PCWjAZuyYU0p12M= +github.com/bits-and-blooms/bitset v1.19.1/go.mod h1:7hO7Gc7Pp1vODcmWvKMRA9BNmbv6a/7QIWpPxHddWR8= +github.com/cloudflare/circl v1.5.0 h1:hxIWksrX6XN5a1L2TI/h53AGPhNHoUBo+TD1ms9+pys= +github.com/cloudflare/circl v1.5.0/go.mod h1:uddAzsPgqdMAYatqJ0lsjX1oECcQLIlRpzZh3pJrofs= +github.com/consensys/bavard v0.1.22 h1:Uw2CGvbXSZWhqK59X0VG/zOjpTFuOMcPLStrp1ihI0A= +github.com/consensys/bavard v0.1.22/go.mod h1:k/zVjHHC4B+PQy1Pg7fgvG3ALicQw540Crag8qx+dZs= +github.com/consensys/gnark-crypto v0.14.0 h1:DDBdl4HaBtdQsq/wfMwJvZNE80sHidrK3Nfrefatm0E= +github.com/consensys/gnark-crypto v0.14.0/go.mod h1:CU4UijNPsHawiVGNxe9co07FkzCeWHHrb1li/n1XoU0= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= @@ -18,9 +18,11 @@ github.com/jonboulle/clockwork v0.4.0/go.mod h1:xgRqUGwRcjKCO1vbZUEtSLrqKoPSsUpK github.com/kilic/bls12-381 v0.1.0 h1:encrdjqKMEvabVQ7qYOKu1OvhqpK4s47wDYtNiPtlp4= github.com/kilic/bls12-381 v0.1.0/go.mod h1:vDTTHJONJ6G+P2R74EhnyotQDTliQDnFEwhdmfzw1ig= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= +github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= -github.com/leanovate/gopter v0.2.9 h1:fQjYxZaynp97ozCzfOyOuAGOU4aU/z37zf/tOujFk7c= +github.com/leanovate/gopter v0.2.11 h1:vRjThO1EKPb/1NsDXuDrzldR28RLkBflWYcU9CvzWu4= +github.com/leanovate/gopter v0.2.11/go.mod h1:aK3tzZP/C+p1m3SPRE4SYZFGP7jjkuSI4f7Xvpt0S9c= github.com/mmcloughlin/addchain v0.4.0 h1:SobOdjm2xLj1KkXN5/n0xTIWyZA2+s99UCY1iPfkHRY= github.com/mmcloughlin/addchain v0.4.0/go.mod h1:A86O+tHqZLMNO4w6ZZ4FlVQEadcoqkyU72HC5wJ4RlU= github.com/mmcloughlin/profile v0.1.1/go.mod h1:IhHD7q1ooxgwTgjxQYkACGA77oFTDdFVejUS1/tS/qU= @@ -30,8 +32,8 @@ github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZV github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= -github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= -github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= +github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= go.dedis.ch/fixbuf v1.0.3 h1:hGcV9Cd/znUxlusJ64eAlExS+5cJDIyTyEG+otu5wQs= go.dedis.ch/fixbuf v1.0.3/go.mod h1:yzJMt34Wa5xD37V5RTdmp38cz3QhMagdGoem9anUalw= go.dedis.ch/kyber/v3 v3.0.4/go.mod h1:OzvaEnPvKlyrWyp3kGXlFdp7ap1VC6RkZDTaPikqhsQ= @@ -42,14 +44,15 @@ go.dedis.ch/protobuf v1.0.7/go.mod h1:pv5ysfkDX/EawiPqcW3ikOxsL5t+BqnV6xHSmE79KI go.dedis.ch/protobuf v1.0.11 h1:FTYVIEzY/bfl37lu3pR4lIj+F9Vp1jE8oh91VmxKgLo= go.dedis.ch/protobuf v1.0.11/go.mod h1:97QR256dnkimeNdfmURz0wAMNVbd1VmLXhG1CrTYrJ4= golang.org/x/crypto v0.0.0-20190123085648-057139ce5d2b/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= -golang.org/x/crypto v0.21.0 h1:X31++rzVUdKhX5sWmSOFZxx8UW/ldWx55cbf08iNAMA= -golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs= +golang.org/x/crypto v0.30.0 h1:RwoQn3GkWiMkzlX562cLB7OxWvjH1L8xutO2WoJcRoY= +golang.org/x/crypto v0.30.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk= golang.org/x/sys v0.0.0-20190124100055-b90733256f2e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20201101102859-da207088b7d1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.18.0 h1:DBdB3niSjOA/O0blCZBqDefyWNYveAYMNF1Wum0DYQ4= -golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA= +golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= rsc.io/tmplfunc v0.0.3 h1:53XFQh69AfOa8Tw0Jm7t+GV7KZhOi6jzsCzTtKbMvzU= diff --git a/pairing/bn254/gfp_decl.go b/pairing/bn254/gfp_decl.go index 8c5429c52..ca56b6c4f 100644 --- a/pairing/bn254/gfp_decl.go +++ b/pairing/bn254/gfp_decl.go @@ -12,7 +12,7 @@ import ( var hasBMI2 = cpu.X86.HasBMI2 -// go:noescape +//go:noescape func gfpNeg(c, a *gfP) //go:noescape diff --git a/pairing/bn254/point.go b/pairing/bn254/point.go index b50d50906..9c60e218b 100644 --- a/pairing/bn254/point.go +++ b/pairing/bn254/point.go @@ -193,7 +193,7 @@ func (p *pointG1) ElementSize() int { } func (p *pointG1) String() string { - return "bn254.G1" + p.g.String() + return "bn254.G1(DST: " + string(p.dst) + ")" + p.g.String() } func (p *pointG1) Hash(m []byte) kyber.Point { @@ -342,16 +342,21 @@ func (p *pointG2) Equal(q kyber.Point) bool { return subtle.ConstantTimeCompare(x, y) == 1 } +// Null returns the point p set to Infinity on G2. Be careful: it mutates p. +// Consider using Clone if you're using this in a comparison. func (p *pointG2) Null() kyber.Point { p.g.SetInfinity() return p } +// Base returns the point p set to the generator on G2. Be careful: it mutates p. +// Consider using Clone first if you're using this in a comparison. func (p *pointG2) Base() kyber.Point { p.g.Set(twistGen) return p } +// Pick returns the point p set to a random point on G2. Be careful: it mutates p. func (p *pointG2) Pick(rand cipher.Stream) kyber.Point { s := mod.NewInt64(0, Order).Pick(rand) p.Base() @@ -524,16 +529,16 @@ func (p *pointGT) Equal(q kyber.Point) bool { return subtle.ConstantTimeCompare(x, y) == 1 } +var nullGT = newPointGT().Pair(newPointG1(nil).Null(), newPointG2(nil).Null()) + func (p *pointGT) Null() kyber.Point { - // TODO: This can be a precomputed constant - p.Pair(newPointG1([]byte{}).Null(), newPointG2([]byte{}).Null()) - return p + return nullGT.Clone() } +var baseGT = newPointGT().Pair(newPointG1(nil).Base(), newPointG2(nil).Base()) + func (p *pointGT) Base() kyber.Point { - // TODO: This can be a precomputed constant - p.Pair(newPointG1([]byte{}).Base(), newPointG2([]byte{}).Base()) - return p + return baseGT.Clone() } func (p *pointGT) Pick(rand cipher.Stream) kyber.Point { diff --git a/pairing/bn254/point_test.go b/pairing/bn254/point_test.go index 2275b996d..d8d975128 100644 --- a/pairing/bn254/point_test.go +++ b/pairing/bn254/point_test.go @@ -6,6 +6,7 @@ import ( "errors" "testing" + "github.com/drand/kyber" "golang.org/x/crypto/sha3" ) @@ -206,3 +207,66 @@ func min(a, b int) int { } return b } + +func Test_pointG1_Equal(t *testing.T) { + tests := []struct { + name string + p1 kyber.Point + p2 kyber.Point + want bool + }{ + { + "g1 inf", + newPointG1(nil).Null(), + newPointG1(nil).Null(), + true, + }, { + "g1 base", + newPointG1(nil).Base(), + newPointG1(nil).Base(), + true, + }, { + "g1 base!=inf", + newPointG1(nil).Base(), + newPointG1(nil).Null(), + false, + }, { + "g2 base!=inf", + newPointG2(nil).Base(), + newPointG2(nil).Null(), + false, + }, { + "g2 inf", + newPointG2(nil).Null(), + newPointG2(nil).Null(), + true, + }, { + "g2 base", + newPointG2(nil).Base(), + newPointG2(nil).Base(), + true, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + p := tt.p1 + if got := p.Equal(tt.p2); got != tt.want { + t.Errorf("Equal() = %v, want %v", got, tt.want) + } + }) + } +} + +func Test_pointGT_Null(t *testing.T) { + inf := newPointGT().Pair(newPointG1([]byte{}).Null(), newPointG2([]byte{}).Null()) + if !inf.Equal(newPointGT().Null()) { + t.Fatal("Null isn't the same null") + } +} + +func Test_pointGT_Base(t *testing.T) { + base := newPointGT().Pair(newPointG1([]byte{}).Base(), newPointG2([]byte{}).Base()) + if !base.Equal(newPointGT().Base()) { + t.Fatal("Null isn't the same null") + } +} diff --git a/pairing/bn254/suite.go b/pairing/bn254/suite.go index 5986057c9..1751965bf 100644 --- a/pairing/bn254/suite.go +++ b/pairing/bn254/suite.go @@ -198,7 +198,7 @@ func (c *commonSuite) Hash() hash.Hash { return sha3.NewLegacyKeccak256() } -// XOF returns a newlly instantiated blake2xb XOF function. +// XOF returns a newly instantiated blake2xb XOF function. func (c *commonSuite) XOF(seed []byte) kyber.XOF { return blake2xb.New(seed) } diff --git a/pairing/bn254/twist.go b/pairing/bn254/twist.go index d1da036c7..15102bf4d 100644 --- a/pairing/bn254/twist.go +++ b/pairing/bn254/twist.go @@ -186,6 +186,7 @@ func (c *twistPoint) MakeAffine() { g.x.SetZero() g.y.SetOne() g.t.SetZero() + c.Set(g) return } diff --git a/pairing/bn256/gfp_decl.go b/pairing/bn256/gfp_decl.go index be1b80906..bdb6a8915 100644 --- a/pairing/bn256/gfp_decl.go +++ b/pairing/bn256/gfp_decl.go @@ -1,3 +1,4 @@ +//go:build (amd64 && !generic) || (arm64 && !generic) // +build amd64,!generic arm64,!generic package bn256 @@ -11,7 +12,7 @@ import ( var hasBMI2 = cpu.X86.HasBMI2 -// go:noescape +//go:noescape func gfpNeg(c, a *gfP) //go:noescape