diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index ad7ce2a..440be87 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -12,7 +12,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - go-version: ['1.22.x', '1.23.x', '1.24.x'] + go-version: ['1.23.x', '1.24.x'] steps: - uses: actions/checkout@v4 with: @@ -33,3 +33,25 @@ jobs: - name: Run fuzzy field tests run: | go test -tags=fuzz -fuzz=Fuzz -fuzztime=30s github.com/elliottech/poseidon_crypto/field + + lint: + name: Lint + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + with: + ref: ${{ github.event.pull_request.head.sha }} + + - name: Setup Go 1.23.x + uses: actions/setup-go@v5 + with: + go-version: 1.23.x + + # TODO: update version + - name: Install golangci-lint + run: | + go install github.com/golangci/golangci-lint/cmd/golangci-lint@v1.61.0 + + - name: Run golangci-lint + run: | + golangci-lint run ./... diff --git a/.golangci.yaml b/.golangci.yaml new file mode 100644 index 0000000..420ac23 --- /dev/null +++ b/.golangci.yaml @@ -0,0 +1,35 @@ +run: + # The default concurrency value is the number of available CPU. + concurrency: 4 + timeout: 5m + +linters: + enable: + - unparam + - bidichk + - durationcheck + - gocritic + - gosec + - unconvert + - exhaustruct + +linters-settings: + govet: + enable: + - nilness + disable: + - composites + gocritic: + disabled-checks: + - captLocal + - ifElseChain + +issues: + max-issues-per-linter: 100 + max-same-issues: 100 + + exclude-rules: + - path: ".*_test.go" + linters: + - gosec + text: "G115" diff --git a/curve/ecgfp5/affine_point.go b/curve/ecgfp5/affine_point.go index 10a089f..0d6e229 100644 --- a/curve/ecgfp5/affine_point.go +++ b/curve/ecgfp5/affine_point.go @@ -32,18 +32,18 @@ func (p *AffinePoint) SetNeg() { // i*P for i = 1 to n (win[0] contains P, win[1] contains 2*P, and // so on). Index value k is an integer in the -n to n range; returned // point is k*P. -func (p *AffinePoint) SetLookup(win []AffinePoint, k int32) { +func Lookup(win []AffinePoint, k int32) AffinePoint { // sign = 0xFFFFFFFF if k < 0, 0x00000000 otherwise - sign := uint32(k >> 31) + sign := uint32(k >> 31) //nolint:gosec // ka = abs(k) - ka := (uint32(k) ^ sign) - sign + ka := (uint32(k) ^ sign) - sign //nolint:gosec // km1 = ka - 1 km1 := ka - 1 x := gFp5.FP5_ZERO u := gFp5.FP5_ZERO for i := 0; i < len(win); i++ { - m := km1 - uint32(i) + m := km1 - uint32(i) //nolint:gosec c_1 := (m | (^m + 1)) >> 31 c := uint64(c_1) - 1 if c != 0 { @@ -55,18 +55,12 @@ func (p *AffinePoint) SetLookup(win []AffinePoint, k int32) { // If k < 0, then we must negate the point. c := uint64(sign) | (uint64(sign) << 32) - p.x = x - p.u = u if c != 0 { - p.u = gFp5.Neg(p.u) + u = gFp5.Neg(u) } -} -func Lookup(win []AffinePoint, k int32) AffinePoint { - r := AFFINE_NEUTRAL - r.SetLookup(win, k) - return r + return AffinePoint{x, u} } // Same as lookup(), except this implementation is variable-time. diff --git a/curve/ecgfp5/curve_test.go b/curve/ecgfp5/curve_test.go index aa1fec1..ea90cb9 100644 --- a/curve/ecgfp5/curve_test.go +++ b/curve/ecgfp5/curve_test.go @@ -7,36 +7,41 @@ import ( gFp5 "github.com/elliottech/poseidon_crypto/field/goldilocks_quintic_extension" ) +func canBeDecodedIntoPoint(w gFp5.Element) bool { + // Value w can be decoded if and only if it is zero, or + // (w^2 - a)^2 - 4*b is a quadratic residue. + e := gFp5.Sub(gFp5.Square(w), A_ECgFp5Point) + delta := gFp5.Sub(gFp5.Square(e), B_MUL4_ECgFp5Point) + deltaLegendre := gFp5.Legendre(delta) + return gFp5.IsZero(w) || deltaLegendre.ToCanonicalUint64() == 1 +} + func TestEncode(t *testing.T) { point := ECgFp5Point{ - x: gFp5.FromUint64Array([5]uint64{ + x: gFp5.Element{ 8219099146870311261, 1751466925979295147, 7427996218561204331, 5499363376829590386, 17146362437196146248}, - ), - z: gFp5.FromUint64Array([5]uint64{ + z: gFp5.Element{ 9697849239028047855, 5846309906783017685, 10545493423738651463, 2054382452661947581, 7470471124463677860}, - ), - u: gFp5.FromUint64Array([5]uint64{ + u: gFp5.Element{ 2901139745109740356, 15850005224840060392, 3464972059371886732, 15264046134718393739, 9208307769190416697}, - ), - t: gFp5.FromUint64Array([5]uint64{ + t: gFp5.Element{ 4691886900801030369, 14793814721360336872, 14452533794393275351, 3652664841353278369, 4894903405053011144}, - ), } encoded := point.Encode() @@ -49,7 +54,7 @@ func TestEncode(t *testing.T) { } for i := 0; i < 5; i++ { - if encoded[i] != g.FromUint64(expected[i]) { + if encoded[i].ToCanonicalUint64() != expected[i] { t.Fatalf("Encode: Expected limb %d to be %x, but got %x", i, expected[i], encoded[i]) } } @@ -57,64 +62,62 @@ func TestEncode(t *testing.T) { func TestAdd(t *testing.T) { a := ECgFp5Point{ - x: gFp5.FromUint64Array([5]uint64{ + x: gFp5.Element{ 6598630105941849408, 1859688128646629097, 17294281002801957241, 14913942670710662913, 10914775081841233526}, - ), - z: gFp5.FromUint64Array([5]uint64{ + + z: gFp5.Element{ 5768577777379827814, 1670898087452303151, 149395834104961848, 10215820955974196778, 12220782198555404872}, - ), - u: gFp5.FromUint64Array([5]uint64{ + + u: gFp5.Element{ 8222038236695704789, 7213480445243459136, 12261234501547702974, 16991275954331307770, 13268460265795104226}, - ), - t: gFp5.FromUint64Array([5]uint64{ + + t: gFp5.Element{ 13156365331881093743, 1228071764139434927, 12765463901361527883, 708052950516284594, 2091843551884526165}, - ), } b := ECgFp5Point{ - x: gFp5.FromUint64Array([5]uint64{ + x: gFp5.Element{ 12601734882931894875, 8567855799503419472, 10972305351681971938, 10379631676278166937, 14389591363895654229}, - ), - z: gFp5.FromUint64Array([5]uint64{ + + z: gFp5.Element{ 7813541982583063146, 5326831614826269688, 674248499729254112, 6075985944329658642, 4509699573536613779}, - ), - u: gFp5.FromUint64Array([5]uint64{ + + u: gFp5.Element{ 18059989919748409029, 4197498098921379230, 8619952860870967373, 4771999616217997413, 18075221430709764120}, - ), - t: gFp5.FromUint64Array([5]uint64{ + + t: gFp5.Element{ 14710659590503370792, 13425914726164358056, 15027060927285830507, 17361235517359536873, 1738580404337116326}, - ), } c := a.Add(b) @@ -148,16 +151,16 @@ func TestAdd(t *testing.T) { } for i := 0; i < 5; i++ { - if c.x[i] != g.FromUint64(expectedX[i]) { + if c.x[i].ToCanonicalUint64() != expectedX[i] { t.Fatalf("Add: Expected c.x[%d] to be %x, but got %x", i, expectedX[i], c.x[i]) } - if c.z[i] != g.FromUint64(expectedZ[i]) { + if c.z[i].ToCanonicalUint64() != expectedZ[i] { t.Fatalf("Add: Expected c.z[%d] to be %x, but got %x", i, expectedZ[i], c.z[i]) } - if c.u[i] != g.FromUint64(expectedU[i]) { + if c.u[i].ToCanonicalUint64() != expectedU[i] { t.Fatalf("Add: Expected c.u[%d] to be %x, but got %x", i, expectedU[i], c.u[i]) } - if c.t[i] != g.FromUint64(expectedT[i]) { + if c.t[i].ToCanonicalUint64() != expectedT[i] { t.Fatalf("Add: Expected c.t[%d] to be %x, but got %x", i, expectedT[i], c.t[i]) } } @@ -165,67 +168,65 @@ func TestAdd(t *testing.T) { func TestDouble(t *testing.T) { point := ECgFp5Point{ - x: gFp5.FromUint64Array([5]uint64{ + x: gFp5.Element{ 2091129225269376836, 9405624996184206232, 3901502046808513894, 17705383837126423407, 9421907235969101682}, - ), - z: gFp5.FromUint64Array([5]uint64{ + + z: gFp5.Element{ 5829667370837222420, 11237187675958101957, 1807194474973812009, 15957008761806494676, 16213732873017933964}, - ), - u: gFp5.FromUint64Array([5]uint64{ + + u: gFp5.Element{ 17708743171457526148, 7256550674326982355, 4002326258245501339, 5920160861215573533, 6620019694807786845}, - ), - t: gFp5.FromUint64Array([5]uint64{ + + t: gFp5.Element{ 8994820555257560065, 3865139429644955984, 222111198601608498, 5080186348564946426, 910404641634132272}, - ), } point.SetDouble() expected := ECgFp5Point{ - x: gFp5.FromUint64Array([5]uint64{ + x: gFp5.Element{ 17841786997947248136, 6795260826091178564, 17040031878202156690, 17452087436690889171, 3812897545652133031}, - ), - z: gFp5.FromUint64Array([5]uint64{ + + z: gFp5.Element{ 11020726505488657009, 1091762938184204841, 4410430720558219763, 4363379995258938087, 13994951776877072532}, - ), - u: gFp5.FromUint64Array([5]uint64{ + + u: gFp5.Element{ 9442293568698796309, 11629160327398360345, 1740514571594869537, 1168842489343203981, 5537908027019165338}, - ), - t: gFp5.FromUint64Array([5]uint64{ + + t: gFp5.Element{ 14684689082562511355, 9795998745315395469, 11643703245601798489, 9164627329631566444, 14463660178939261073}, - ), } if !point.Equals(expected) { @@ -235,67 +236,65 @@ func TestDouble(t *testing.T) { func TestMDouble(t *testing.T) { point := ECgFp5Point{ - x: gFp5.FromUint64Array([5]uint64{ + x: gFp5.Element{ 2091129225269376836, 9405624996184206232, 3901502046808513894, 17705383837126423407, 9421907235969101682}, - ), - z: gFp5.FromUint64Array([5]uint64{ + + z: gFp5.Element{ 5829667370837222420, 11237187675958101957, 1807194474973812009, 15957008761806494676, 16213732873017933964}, - ), - u: gFp5.FromUint64Array([5]uint64{ + + u: gFp5.Element{ 17708743171457526148, 7256550674326982355, 4002326258245501339, 5920160861215573533, 6620019694807786845}, - ), - t: gFp5.FromUint64Array([5]uint64{ + + t: gFp5.Element{ 8994820555257560065, 3865139429644955984, 222111198601608498, 5080186348564946426, 910404641634132272}, - ), } point.SetMDouble(35) expectedDouble := ECgFp5Point{ - x: gFp5.FromUint64Array([5]uint64{ + x: gFp5.Element{ 5913227576680434070, 7982325190863789325, 996872074809285515, 13250982632111464330, 12283818425722177845}, - ), - z: gFp5.FromUint64Array([5]uint64{ + + z: gFp5.Element{ 11109298682748378964, 10740549672355474144, 8575099619865922741, 7569981484002838575, 8334331076253814622}, - ), - u: gFp5.FromUint64Array([5]uint64{ + + u: gFp5.Element{ 2081907484718321711, 2871920152785433924, 16079876071712475691, 12304725828108396137, 5091453661983356959}, - ), - t: gFp5.FromUint64Array([5]uint64{ + + t: gFp5.Element{ 16573251802693900474, 18328109793157914401, 5893679867263862011, 8243272292726266031, 9080497760919830159}, - ), } for i := 0; i < 5; i++ { @@ -316,34 +315,33 @@ func TestMDouble(t *testing.T) { func TestToAffineAndLookup(t *testing.T) { point := ECgFp5Point{ - x: gFp5.FromUint64Array([5]uint64{ + x: gFp5.Element{ 6641938805100417611, 4637251792794046952, 9680215716198734904, 7124887799004433445, 3695446893682682870}, - ), - z: gFp5.FromUint64Array([5]uint64{ + + z: gFp5.Element{ 1, 0, 0, 0, 0}, - ), - u: gFp5.FromUint64Array([5]uint64{ + + u: gFp5.Element{ 1, 0, 0, 0, 0}, - ), - t: gFp5.FromUint64Array([5]uint64{ + + t: gFp5.Element{ 12539254003028696409, 15524144070600887654, 15092036948424041984, 11398871370327264211, 10958391180505708567}, - ), } tab1 := make([]ECgFp5Point, 8) @@ -396,71 +394,69 @@ func TestToAffineAndLookup(t *testing.T) { func TestScalarMul(t *testing.T) { p1 := ECgFp5Point{ - x: gFp5.FromUint64Array([5]uint64{ + x: gFp5.Element{ 16818074783491816710, 5830279414330569119, 3449083115922675783, 1268145320872323641, 12614816166275380125}, - ), - z: gFp5.FromUint64Array([5]uint64{ + + z: gFp5.Element{ 1, 0, 0, 0, 0}, - ), - u: gFp5.FromUint64Array([5]uint64{ + + u: gFp5.Element{ 1, 0, 0, 0, 0}, - ), - t: gFp5.FromUint64Array([5]uint64{ + + t: gFp5.Element{ 7534507442095725921, 16658460051907528927, 12417574136563175256, 2750788641759288856, 620002843272906439}, - ), } - if !p1.Mul(&ECgFp5Scalar{ + if !p1.Mul(ECgFp5Scalar{ 996458928865875995, 7368213710557165165, 8553572641065079816, 15282443801767955752, 251150557732720826, }).Equals(ECgFp5Point{ - x: gFp5.FromUint64Array([5]uint64{ + x: gFp5.Element{ 16885333682092300432, 5595343485914691669, 13188593663496831978, 10414629856394645794, 5668658507670629815}, - ), - z: gFp5.FromUint64Array([5]uint64{ + + z: gFp5.Element{ 1, 0, 0, 0, 0}, - ), - u: gFp5.FromUint64Array([5]uint64{ + + u: gFp5.Element{ 1, 0, 0, 0, 0}, - ), - t: gFp5.FromUint64Array([5]uint64{ + + t: gFp5.Element{ 9486104512504676657, 14312981644741144668, 5159846406177847664, 15978863787033795628, 3249948839313771192}, - ), }) { t.Fail() } @@ -478,53 +474,53 @@ func testVectors() [8]gFp5.Element { w0 := gFp5.FP5_ZERO w1 := gFp5.Element{ - g.FromUint64(12539254003028696409), - g.FromUint64(15524144070600887654), - g.FromUint64(15092036948424041984), - g.FromUint64(11398871370327264211), - g.FromUint64(10958391180505708567), + g.GoldilocksField(12539254003028696409), + g.GoldilocksField(15524144070600887654), + g.GoldilocksField(15092036948424041984), + g.GoldilocksField(11398871370327264211), + g.GoldilocksField(10958391180505708567), } w2 := gFp5.Element{ - g.FromUint64(11001943240060308920), - g.FromUint64(17075173755187928434), - g.FromUint64(3940989555384655766), - g.FromUint64(15017795574860011099), - g.FromUint64(5548543797011402287), + g.GoldilocksField(11001943240060308920), + g.GoldilocksField(17075173755187928434), + g.GoldilocksField(3940989555384655766), + g.GoldilocksField(15017795574860011099), + g.GoldilocksField(5548543797011402287), } w3 := gFp5.Element{ - g.FromUint64(246872606398642312), - g.FromUint64(4900963247917836450), - g.FromUint64(7327006728177203977), - g.FromUint64(13945036888436667069), - g.FromUint64(3062018119121328861), + g.GoldilocksField(246872606398642312), + g.GoldilocksField(4900963247917836450), + g.GoldilocksField(7327006728177203977), + g.GoldilocksField(13945036888436667069), + g.GoldilocksField(3062018119121328861), } w4 := gFp5.Element{ - g.FromUint64(8058035104653144162), - g.FromUint64(16041715455419993830), - g.FromUint64(7448530016070824199), - g.FromUint64(11253639182222911208), - g.FromUint64(6228757819849640866), + g.GoldilocksField(8058035104653144162), + g.GoldilocksField(16041715455419993830), + g.GoldilocksField(7448530016070824199), + g.GoldilocksField(11253639182222911208), + g.GoldilocksField(6228757819849640866), } w5 := gFp5.Element{ - g.FromUint64(10523134687509281194), - g.FromUint64(11148711503117769087), - g.FromUint64(9056499921957594891), - g.FromUint64(13016664454465495026), - g.FromUint64(16494247923890248266), + g.GoldilocksField(10523134687509281194), + g.GoldilocksField(11148711503117769087), + g.GoldilocksField(9056499921957594891), + g.GoldilocksField(13016664454465495026), + g.GoldilocksField(16494247923890248266), } w6 := gFp5.Element{ - g.FromUint64(12173306542237620), - g.FromUint64(6587231965341539782), - g.FromUint64(17027985748515888117), - g.FromUint64(17194831817613584995), - g.FromUint64(10056734072351459010), + g.GoldilocksField(12173306542237620), + g.GoldilocksField(6587231965341539782), + g.GoldilocksField(17027985748515888117), + g.GoldilocksField(17194831817613584995), + g.GoldilocksField(10056734072351459010), } w7 := gFp5.Element{ - g.FromUint64(9420857400785992333), - g.FromUint64(4695934009314206363), - g.FromUint64(14471922162341187302), - g.FromUint64(13395190104221781928), - g.FromUint64(16359223219913018041), + g.GoldilocksField(9420857400785992333), + g.GoldilocksField(4695934009314206363), + g.GoldilocksField(14471922162341187302), + g.GoldilocksField(13395190104221781928), + g.GoldilocksField(16359223219913018041), } return [8]gFp5.Element{w0, w1, w2, w3, w4, w5, w6, w7} @@ -534,50 +530,50 @@ func TestBasicOps(t *testing.T) { // Values that should not decode succeslly. bww := [6]gFp5.Element{ { - g.FromUint64(13557832913345268708), - g.FromUint64(15669280705791538619), - g.FromUint64(8534654657267986396), - g.FromUint64(12533218303838131749), - g.FromUint64(5058070698878426028), + g.GoldilocksField(13557832913345268708), + g.GoldilocksField(15669280705791538619), + g.GoldilocksField(8534654657267986396), + g.GoldilocksField(12533218303838131749), + g.GoldilocksField(5058070698878426028), }, { - g.FromUint64(135036726621282077), - g.FromUint64(17283229938160287622), - g.FromUint64(13113167081889323961), - g.FromUint64(1653240450380825271), - g.FromUint64(520025869628727862), + g.GoldilocksField(135036726621282077), + g.GoldilocksField(17283229938160287622), + g.GoldilocksField(13113167081889323961), + g.GoldilocksField(1653240450380825271), + g.GoldilocksField(520025869628727862), }, { - g.FromUint64(6727960962624180771), - g.FromUint64(17240764188796091916), - g.FromUint64(3954717247028503753), - g.FromUint64(1002781561619501488), - g.FromUint64(4295357288570643789), + g.GoldilocksField(6727960962624180771), + g.GoldilocksField(17240764188796091916), + g.GoldilocksField(3954717247028503753), + g.GoldilocksField(1002781561619501488), + g.GoldilocksField(4295357288570643789), }, { - g.FromUint64(4578929270179684956), - g.FromUint64(3866930513245945042), - g.FromUint64(7662265318638150701), - g.FromUint64(9503686272550423634), - g.FromUint64(12241691520798116285), + g.GoldilocksField(4578929270179684956), + g.GoldilocksField(3866930513245945042), + g.GoldilocksField(7662265318638150701), + g.GoldilocksField(9503686272550423634), + g.GoldilocksField(12241691520798116285), }, { - g.FromUint64(16890297404904119082), - g.FromUint64(6169724643582733633), - g.FromUint64(9725973298012340311), - g.FromUint64(5977049210035183790), - g.FromUint64(11379332130141664883), + g.GoldilocksField(16890297404904119082), + g.GoldilocksField(6169724643582733633), + g.GoldilocksField(9725973298012340311), + g.GoldilocksField(5977049210035183790), + g.GoldilocksField(11379332130141664883), }, { - g.FromUint64(13777379982711219130), - g.FromUint64(14715168412651470168), - g.FromUint64(17942199593791635585), - g.FromUint64(6188824164976547520), - g.FromUint64(15461469634034461986), + g.GoldilocksField(13777379982711219130), + g.GoldilocksField(14715168412651470168), + g.GoldilocksField(17942199593791635585), + g.GoldilocksField(6188824164976547520), + g.GoldilocksField(15461469634034461986), }, } for _, w := range bww { - if CanBeDecodedIntoPoint(w) { + if canBeDecodedIntoPoint(w) { t.Fatalf("Validation should fail for element: %v", w) } if _, success := Decode(w); success { @@ -587,7 +583,7 @@ func TestBasicOps(t *testing.T) { vectors := testVectors() for _, w := range vectors { - if !CanBeDecodedIntoPoint(w) { + if !canBeDecodedIntoPoint(w) { t.Fatalf("Validation failed for element: %v", w) } } @@ -631,7 +627,7 @@ func TestBasicOps(t *testing.T) { if p1.IsNeutral() || p2.IsNeutral() || p3.IsNeutral() || p4.IsNeutral() || p5.IsNeutral() || p6.IsNeutral() || p7.IsNeutral() { t.Fatalf("p1...p7 should not be neutral") } - if !p0.Equals(p0) || !p1.Equals(p1) || p0.Equals(p1) || p1.Equals(p0) || p1.Equals(p2) { + if !p0.Equals(p0) || !p1.Equals(p1) || p0.Equals(p1) || p1.Equals(p0) || p1.Equals(p2) { //nolint:gocritic t.Fatalf("Equality checks failed") } @@ -639,7 +635,22 @@ func TestBasicOps(t *testing.T) { t.Fatalf("Encoding checks failed") } - if !gFp5.Equals(p1.Add(p2).Encode(), vectors[3]) || !gFp5.Equals(p1.Add(p1).Encode(), vectors[4]) || !gFp5.Equals(p2.Double().Encode(), vectors[5]) || !gFp5.Equals(p1.Double().Add(p2).Encode(), vectors[6]) || !gFp5.Equals(p1.Add(p2).Add(p2).Encode(), vectors[7]) { + if !gFp5.Equals(p1.Add(p2).Encode(), vectors[3]) { + t.Fatalf("Addition and doubling checks failed") + } + + if !gFp5.Equals(p1.Add(p1).Encode(), vectors[4]) { + t.Fatalf("Addition and doubling checks failed") + } + + if !gFp5.Equals(p2.Double().Encode(), vectors[5]) { + t.Fatalf("Addition and doubling checks failed") + } + if !gFp5.Equals(p1.Double().Add(p2).Encode(), vectors[6]) { + t.Fatalf("Addition and doubling checks failed") + } + + if !gFp5.Equals(p1.Add(p2).Add(p2).Encode(), vectors[7]) { t.Fatalf("Addition and doubling checks failed") } @@ -672,11 +683,11 @@ func TestDecodeAsWeierstrass(t *testing.T) { p0Expected := WeierstrassPoint{ X: gFp5.Element{ - g.FromUint64(6148914689804861440), - g.FromUint64(0), - g.FromUint64(0), - g.FromUint64(0), - g.FromUint64(0), + g.GoldilocksField(6148914689804861440), + g.GoldilocksField(0), + g.GoldilocksField(0), + g.GoldilocksField(0), + g.GoldilocksField(0), }, Y: gFp5.FP5_ZERO, IsInf: true, @@ -691,18 +702,18 @@ func TestDecodeAsWeierstrass(t *testing.T) { p1Expected := WeierstrassPoint{ X: gFp5.Element{ - g.FromUint64(7887569478949190020), - g.FromUint64(11586418388990522938), - g.FromUint64(13676447623055915878), - g.FromUint64(5945168854809921881), - g.FromUint64(16291886980725359814), + g.GoldilocksField(7887569478949190020), + g.GoldilocksField(11586418388990522938), + g.GoldilocksField(13676447623055915878), + g.GoldilocksField(5945168854809921881), + g.GoldilocksField(16291886980725359814), }, Y: gFp5.Element{ - g.FromUint64(7556511254681645335), - g.FromUint64(17611929280367064763), - g.FromUint64(9410908488141053806), - g.FromUint64(11351540010214108766), - g.FromUint64(4846226015431423207), + g.GoldilocksField(7556511254681645335), + g.GoldilocksField(17611929280367064763), + g.GoldilocksField(9410908488141053806), + g.GoldilocksField(11351540010214108766), + g.GoldilocksField(4846226015431423207), }, IsInf: false, } @@ -716,18 +727,18 @@ func TestDecodeAsWeierstrass(t *testing.T) { p2Expected := WeierstrassPoint{ X: gFp5.Element{ - g.FromUint64(11231216549003316587), - g.FromUint64(17312878720767554617), - g.FromUint64(5614299211412933260), - g.FromUint64(2256199868722187419), - g.FromUint64(14229722163821261464), + g.GoldilocksField(11231216549003316587), + g.GoldilocksField(17312878720767554617), + g.GoldilocksField(5614299211412933260), + g.GoldilocksField(2256199868722187419), + g.GoldilocksField(14229722163821261464), }, Y: gFp5.Element{ - g.FromUint64(11740132275098847128), - g.FromUint64(18250632754932612452), - g.FromUint64(6988589976052950880), - g.FromUint64(13612651576898186637), - g.FromUint64(16040252831112129154), + g.GoldilocksField(11740132275098847128), + g.GoldilocksField(18250632754932612452), + g.GoldilocksField(6988589976052950880), + g.GoldilocksField(13612651576898186637), + g.GoldilocksField(16040252831112129154), }, IsInf: false, } @@ -741,18 +752,18 @@ func TestDecodeAsWeierstrass(t *testing.T) { p3Expected := WeierstrassPoint{ X: gFp5.Element{ - g.FromUint64(567456832026211571), - g.FromUint64(6401615614732569674), - g.FromUint64(7303004494044972219), - g.FromUint64(4332356015409706768), - g.FromUint64(4663512734739523713), + g.GoldilocksField(567456832026211571), + g.GoldilocksField(6401615614732569674), + g.GoldilocksField(7303004494044972219), + g.GoldilocksField(4332356015409706768), + g.GoldilocksField(4663512734739523713), }, Y: gFp5.Element{ - g.FromUint64(13838792670272995877), - g.FromUint64(11742686110311813089), - g.FromUint64(17972799251722850796), - g.FromUint64(8534723577625674697), - g.FromUint64(3138422718990519265), + g.GoldilocksField(13838792670272995877), + g.GoldilocksField(11742686110311813089), + g.GoldilocksField(17972799251722850796), + g.GoldilocksField(8534723577625674697), + g.GoldilocksField(3138422718990519265), }, IsInf: false, } @@ -766,18 +777,18 @@ func TestDecodeAsWeierstrass(t *testing.T) { p4Expected := WeierstrassPoint{ X: gFp5.Element{ - g.FromUint64(2626390539619063455), - g.FromUint64(3069873143820007175), - g.FromUint64(16481805966921623903), - g.FromUint64(2169403494164322467), - g.FromUint64(15849876939764656634), + g.GoldilocksField(2626390539619063455), + g.GoldilocksField(3069873143820007175), + g.GoldilocksField(16481805966921623903), + g.GoldilocksField(2169403494164322467), + g.GoldilocksField(15849876939764656634), }, Y: gFp5.Element{ - g.FromUint64(8052493994140007067), - g.FromUint64(12476750341447220703), - g.FromUint64(7297584762312352412), - g.FromUint64(4456043296886321460), - g.FromUint64(17416054515469523789), + g.GoldilocksField(8052493994140007067), + g.GoldilocksField(12476750341447220703), + g.GoldilocksField(7297584762312352412), + g.GoldilocksField(4456043296886321460), + g.GoldilocksField(17416054515469523789), }, IsInf: false, } @@ -791,18 +802,18 @@ func TestDecodeAsWeierstrass(t *testing.T) { p5Expected := WeierstrassPoint{ X: gFp5.Element{ - g.FromUint64(3378618241466923429), - g.FromUint64(1600085176765664645), - g.FromUint64(8450735902517439914), - g.FromUint64(879305481131694650), - g.FromUint64(9249368002914244868), + g.GoldilocksField(3378618241466923429), + g.GoldilocksField(1600085176765664645), + g.GoldilocksField(8450735902517439914), + g.GoldilocksField(879305481131694650), + g.GoldilocksField(9249368002914244868), }, Y: gFp5.Element{ - g.FromUint64(7063301786803892166), - g.FromUint64(16450112846546843898), - g.FromUint64(13291990378137922105), - g.FromUint64(17122501309646837992), - g.FromUint64(13551174888872382132), + g.GoldilocksField(7063301786803892166), + g.GoldilocksField(16450112846546843898), + g.GoldilocksField(13291990378137922105), + g.GoldilocksField(17122501309646837992), + g.GoldilocksField(13551174888872382132), }, IsInf: false, } @@ -816,18 +827,18 @@ func TestDecodeAsWeierstrass(t *testing.T) { p6Expected := WeierstrassPoint{ X: gFp5.Element{ - g.FromUint64(12792842147978866906), - g.FromUint64(10605017725125541653), - g.FromUint64(7515179057747849898), - g.FromUint64(4244613931017322576), - g.FromUint64(5015379385130367832), + g.GoldilocksField(12792842147978866906), + g.GoldilocksField(10605017725125541653), + g.GoldilocksField(7515179057747849898), + g.GoldilocksField(4244613931017322576), + g.GoldilocksField(5015379385130367832), }, Y: gFp5.Element{ - g.FromUint64(11618884250209642346), - g.FromUint64(14788516166813429253), - g.FromUint64(7317520700234795285), - g.FromUint64(12825292405177435802), - g.FromUint64(17658454967394645353), + g.GoldilocksField(11618884250209642346), + g.GoldilocksField(14788516166813429253), + g.GoldilocksField(7317520700234795285), + g.GoldilocksField(12825292405177435802), + g.GoldilocksField(17658454967394645353), }, IsInf: false, } @@ -841,18 +852,18 @@ func TestDecodeAsWeierstrass(t *testing.T) { p7Expected := WeierstrassPoint{ X: gFp5.Element{ - g.FromUint64(10440794216646581227), - g.FromUint64(13992847258701590930), - g.FromUint64(11213401763785319360), - g.FromUint64(12830171931568113117), - g.FromUint64(6220154342199499160), + g.GoldilocksField(10440794216646581227), + g.GoldilocksField(13992847258701590930), + g.GoldilocksField(11213401763785319360), + g.GoldilocksField(12830171931568113117), + g.GoldilocksField(6220154342199499160), }, Y: gFp5.Element{ - g.FromUint64(7971683838841472962), - g.FromUint64(1639066249976938469), - g.FromUint64(15015315060237521031), - g.FromUint64(10847769264696425470), - g.FromUint64(9177491810370773777), + g.GoldilocksField(7971683838841472962), + g.GoldilocksField(1639066249976938469), + g.GoldilocksField(15015315060237521031), + g.GoldilocksField(10847769264696425470), + g.GoldilocksField(9177491810370773777), }, IsInf: false, } @@ -877,18 +888,18 @@ func TestDecodeAsWeierstrass(t *testing.T) { func TestWeierstrassPrecomputeWindow(t *testing.T) { qwe := WeierstrassPoint{ X: gFp5.Element{ - g.FromUint64(7887569478949190020), - g.FromUint64(11586418388990522938), - g.FromUint64(13676447623055915878), - g.FromUint64(5945168854809921881), - g.FromUint64(16291886980725359814), + g.GoldilocksField(7887569478949190020), + g.GoldilocksField(11586418388990522938), + g.GoldilocksField(13676447623055915878), + g.GoldilocksField(5945168854809921881), + g.GoldilocksField(16291886980725359814), }, Y: gFp5.Element{ - g.FromUint64(7556511254681645335), - g.FromUint64(17611929280367064763), - g.FromUint64(9410908488141053806), - g.FromUint64(11351540010214108766), - g.FromUint64(4846226015431423207), + g.GoldilocksField(7556511254681645335), + g.GoldilocksField(17611929280367064763), + g.GoldilocksField(9410908488141053806), + g.GoldilocksField(11351540010214108766), + g.GoldilocksField(4846226015431423207), }, IsInf: false, } @@ -898,267 +909,267 @@ func TestWeierstrassPrecomputeWindow(t *testing.T) { expectedWindow := []WeierstrassPoint{ { X: gFp5.Element{ - g.FromUint64(0), - g.FromUint64(0), - g.FromUint64(0), - g.FromUint64(0), - g.FromUint64(0), + g.GoldilocksField(0), + g.GoldilocksField(0), + g.GoldilocksField(0), + g.GoldilocksField(0), + g.GoldilocksField(0), }, Y: gFp5.FP5_ZERO, IsInf: true, }, { X: gFp5.Element{ - g.FromUint64(7887569478949190020), - g.FromUint64(11586418388990522938), - g.FromUint64(13676447623055915878), - g.FromUint64(5945168854809921881), - g.FromUint64(16291886980725359814), + g.GoldilocksField(7887569478949190020), + g.GoldilocksField(11586418388990522938), + g.GoldilocksField(13676447623055915878), + g.GoldilocksField(5945168854809921881), + g.GoldilocksField(16291886980725359814), }, Y: gFp5.Element{ - g.FromUint64(7556511254681645335), - g.FromUint64(17611929280367064763), - g.FromUint64(9410908488141053806), - g.FromUint64(11351540010214108766), - g.FromUint64(4846226015431423207), + g.GoldilocksField(7556511254681645335), + g.GoldilocksField(17611929280367064763), + g.GoldilocksField(9410908488141053806), + g.GoldilocksField(11351540010214108766), + g.GoldilocksField(4846226015431423207), }, IsInf: false, }, { X: gFp5.Element{ - g.FromUint64(2626390539619063455), - g.FromUint64(3069873143820007175), - g.FromUint64(16481805966921623903), - g.FromUint64(2169403494164322467), - g.FromUint64(15849876939764656634), + g.GoldilocksField(2626390539619063455), + g.GoldilocksField(3069873143820007175), + g.GoldilocksField(16481805966921623903), + g.GoldilocksField(2169403494164322467), + g.GoldilocksField(15849876939764656634), }, Y: gFp5.Element{ - g.FromUint64(8052493994140007067), - g.FromUint64(12476750341447220703), - g.FromUint64(7297584762312352412), - g.FromUint64(4456043296886321460), - g.FromUint64(17416054515469523789), + g.GoldilocksField(8052493994140007067), + g.GoldilocksField(12476750341447220703), + g.GoldilocksField(7297584762312352412), + g.GoldilocksField(4456043296886321460), + g.GoldilocksField(17416054515469523789), }, IsInf: false, }, { X: gFp5.Element{ - g.FromUint64(18176398362578182379), - g.FromUint64(4436023520237554199), - g.FromUint64(3215180516398562719), - g.FromUint64(6557371017655524187), - g.FromUint64(5543821526507387228), + g.GoldilocksField(18176398362578182379), + g.GoldilocksField(4436023520237554199), + g.GoldilocksField(3215180516398562719), + g.GoldilocksField(6557371017655524187), + g.GoldilocksField(5543821526507387228), }, Y: gFp5.Element{ - g.FromUint64(13231520129332295641), - g.FromUint64(12272620923537119667), - g.FromUint64(2190001779233679631), - g.FromUint64(17429746542415208975), - g.FromUint64(3337887399771893342), + g.GoldilocksField(13231520129332295641), + g.GoldilocksField(12272620923537119667), + g.GoldilocksField(2190001779233679631), + g.GoldilocksField(17429746542415208975), + g.GoldilocksField(3337887399771893342), }, IsInf: false, }, { X: gFp5.Element{ - g.FromUint64(5948298497167270001), - g.FromUint64(15488083211069840053), - g.FromUint64(7462878240499130449), - g.FromUint64(5465845052061152523), - g.FromUint64(14272165321414720409), + g.GoldilocksField(5948298497167270001), + g.GoldilocksField(15488083211069840053), + g.GoldilocksField(7462878240499130449), + g.GoldilocksField(5465845052061152523), + g.GoldilocksField(14272165321414720409), }, Y: gFp5.Element{ - g.FromUint64(7229037630209827809), - g.FromUint64(10702348517645256990), - g.FromUint64(8760795746058875829), - g.FromUint64(9846744510637391346), - g.FromUint64(3236820900223784510), + g.GoldilocksField(7229037630209827809), + g.GoldilocksField(10702348517645256990), + g.GoldilocksField(8760795746058875829), + g.GoldilocksField(9846744510637391346), + g.GoldilocksField(3236820900223784510), }, IsInf: false, }, { X: gFp5.Element{ - g.FromUint64(568906556912793428), - g.FromUint64(12270416106652192091), - g.FromUint64(17277438866839882878), - g.FromUint64(18290317522638929974), - g.FromUint64(7546670826452401067), + g.GoldilocksField(568906556912793428), + g.GoldilocksField(12270416106652192091), + g.GoldilocksField(17277438866839882878), + g.GoldilocksField(18290317522638929974), + g.GoldilocksField(7546670826452401067), }, Y: gFp5.Element{ - g.FromUint64(1322178101989677577), - g.FromUint64(18254974566546618836), - g.FromUint64(1119202239871436890), - g.FromUint64(13885721715120393435), - g.FromUint64(7665289671288386226), + g.GoldilocksField(1322178101989677577), + g.GoldilocksField(18254974566546618836), + g.GoldilocksField(1119202239871436890), + g.GoldilocksField(13885721715120393435), + g.GoldilocksField(7665289671288386226), }, IsInf: false, }, { X: gFp5.Element{ - g.FromUint64(6854724460063782323), - g.FromUint64(7010495484231564745), - g.FromUint64(15016688843001273184), - g.FromUint64(9083584169580443423), - g.FromUint64(6530832684770892589), + g.GoldilocksField(6854724460063782323), + g.GoldilocksField(7010495484231564745), + g.GoldilocksField(15016688843001273184), + g.GoldilocksField(9083584169580443423), + g.GoldilocksField(6530832684770892589), }, Y: gFp5.Element{ - g.FromUint64(13188019294905205452), - g.FromUint64(9894649816252217734), - g.FromUint64(4035350096343221693), - g.FromUint64(9024914229517462288), - g.FromUint64(14523942737067589623), + g.GoldilocksField(13188019294905205452), + g.GoldilocksField(9894649816252217734), + g.GoldilocksField(4035350096343221693), + g.GoldilocksField(9024914229517462288), + g.GoldilocksField(14523942737067589623), }, IsInf: false, }, { X: gFp5.Element{ - g.FromUint64(173069451201741305), - g.FromUint64(16407881748070922395), - g.FromUint64(1843877769060049981), - g.FromUint64(8394477401224475023), - g.FromUint64(15455323212667110231), + g.GoldilocksField(173069451201741305), + g.GoldilocksField(16407881748070922395), + g.GoldilocksField(1843877769060049981), + g.GoldilocksField(8394477401224475023), + g.GoldilocksField(15455323212667110231), }, Y: gFp5.Element{ - g.FromUint64(7073462480600858335), - g.FromUint64(1218835901499910502), - g.FromUint64(4884985224204572316), - g.FromUint64(8579676009424088446), - g.FromUint64(8272242895251038218), + g.GoldilocksField(7073462480600858335), + g.GoldilocksField(1218835901499910502), + g.GoldilocksField(4884985224204572316), + g.GoldilocksField(8579676009424088446), + g.GoldilocksField(8272242895251038218), }, IsInf: false, }, { X: gFp5.Element{ - g.FromUint64(1164943004740104550), - g.FromUint64(6494467951550829605), - g.FromUint64(11394395084895053958), - g.FromUint64(11002214393170970880), - g.FromUint64(6198152590137047423), + g.GoldilocksField(1164943004740104550), + g.GoldilocksField(6494467951550829605), + g.GoldilocksField(11394395084895053958), + g.GoldilocksField(11002214393170970880), + g.GoldilocksField(6198152590137047423), }, Y: gFp5.Element{ - g.FromUint64(6293376713015748154), - g.FromUint64(3978302408397307263), - g.FromUint64(10305750348797825360), - g.FromUint64(2653356225991763726), - g.FromUint64(18032604437344362964), + g.GoldilocksField(6293376713015748154), + g.GoldilocksField(3978302408397307263), + g.GoldilocksField(10305750348797825360), + g.GoldilocksField(2653356225991763726), + g.GoldilocksField(18032604437344362964), }, IsInf: false, }, { X: gFp5.Element{ - g.FromUint64(8412524841879898340), - g.FromUint64(5906329857715512849), - g.FromUint64(7781506052219784033), - g.FromUint64(747934326178282629), - g.FromUint64(9789520974115787951), + g.GoldilocksField(8412524841879898340), + g.GoldilocksField(5906329857715512849), + g.GoldilocksField(7781506052219784033), + g.GoldilocksField(747934326178282629), + g.GoldilocksField(9789520974115787951), }, Y: gFp5.Element{ - g.FromUint64(16402983360046062715), - g.FromUint64(2610048768344810351), - g.FromUint64(1409991662255990973), - g.FromUint64(8262322794139104006), - g.FromUint64(17162526866400736394), + g.GoldilocksField(16402983360046062715), + g.GoldilocksField(2610048768344810351), + g.GoldilocksField(1409991662255990973), + g.GoldilocksField(8262322794139104006), + g.GoldilocksField(17162526866400736394), }, IsInf: false, }, { X: gFp5.Element{ - g.FromUint64(10048515622314644986), - g.FromUint64(12205112414027757400), - g.FromUint64(6798899797395644410), - g.FromUint64(5508399081833065246), - g.FromUint64(2545381917899893146), + g.GoldilocksField(10048515622314644986), + g.GoldilocksField(12205112414027757400), + g.GoldilocksField(6798899797395644410), + g.GoldilocksField(5508399081833065246), + g.GoldilocksField(2545381917899893146), }, Y: gFp5.Element{ - g.FromUint64(13967674179646477901), - g.FromUint64(7464072417461755698), - g.FromUint64(10620790885582225633), - g.FromUint64(2124420630858145666), - g.FromUint64(1715438731398823203), + g.GoldilocksField(13967674179646477901), + g.GoldilocksField(7464072417461755698), + g.GoldilocksField(10620790885582225633), + g.GoldilocksField(2124420630858145666), + g.GoldilocksField(1715438731398823203), }, IsInf: false, }, { X: gFp5.Element{ - g.FromUint64(8945074870943081799), - g.FromUint64(6323068672198034776), - g.FromUint64(628757110948609554), - g.FromUint64(463667364946291331), - g.FromUint64(18333500614767793034), + g.GoldilocksField(8945074870943081799), + g.GoldilocksField(6323068672198034776), + g.GoldilocksField(628757110948609554), + g.GoldilocksField(463667364946291331), + g.GoldilocksField(18333500614767793034), }, Y: gFp5.Element{ - g.FromUint64(1585562137944898917), - g.FromUint64(6965134006182209177), - g.FromUint64(7287494396640097306), - g.FromUint64(6989295600772373751), - g.FromUint64(4694512086109041789), + g.GoldilocksField(1585562137944898917), + g.GoldilocksField(6965134006182209177), + g.GoldilocksField(7287494396640097306), + g.GoldilocksField(6989295600772373751), + g.GoldilocksField(4694512086109041789), }, IsInf: false, }, { X: gFp5.Element{ - g.FromUint64(1353084308423766252), - g.FromUint64(9017409530297494922), - g.FromUint64(17666541873916336431), - g.FromUint64(11263790843735091100), - g.FromUint64(8436577988671463853), + g.GoldilocksField(1353084308423766252), + g.GoldilocksField(9017409530297494922), + g.GoldilocksField(17666541873916336431), + g.GoldilocksField(11263790843735091100), + g.GoldilocksField(8436577988671463853), }, Y: gFp5.Element{ - g.FromUint64(2338633593176970866), - g.FromUint64(2404810229101070877), - g.FromUint64(16146490466464907277), - g.FromUint64(5696273511305368024), - g.FromUint64(15148244810777170464), + g.GoldilocksField(2338633593176970866), + g.GoldilocksField(2404810229101070877), + g.GoldilocksField(16146490466464907277), + g.GoldilocksField(5696273511305368024), + g.GoldilocksField(15148244810777170464), }, IsInf: false, }, { X: gFp5.Element{ - g.FromUint64(1474147635627813906), - g.FromUint64(11643377203770626355), - g.FromUint64(9314121941510315318), - g.FromUint64(9763644728022466505), - g.FromUint64(17192017882693797779), + g.GoldilocksField(1474147635627813906), + g.GoldilocksField(11643377203770626355), + g.GoldilocksField(9314121941510315318), + g.GoldilocksField(9763644728022466505), + g.GoldilocksField(17192017882693797779), }, Y: gFp5.Element{ - g.FromUint64(4381200527555648826), - g.FromUint64(13015101990350251010), - g.FromUint64(16047910726372959546), - g.FromUint64(11605287252021821360), - g.FromUint64(10725156729712381290), + g.GoldilocksField(4381200527555648826), + g.GoldilocksField(13015101990350251010), + g.GoldilocksField(16047910726372959546), + g.GoldilocksField(11605287252021821360), + g.GoldilocksField(10725156729712381290), }, IsInf: false, }, { X: gFp5.Element{ - g.FromUint64(14169389411955179775), - g.FromUint64(18405651482817201996), - g.FromUint64(13913583073406638188), - g.FromUint64(7468262161993545065), - g.FromUint64(14000137716301361841), + g.GoldilocksField(14169389411955179775), + g.GoldilocksField(18405651482817201996), + g.GoldilocksField(13913583073406638188), + g.GoldilocksField(7468262161993545065), + g.GoldilocksField(14000137716301361841), }, Y: gFp5.Element{ - g.FromUint64(14787739045021338943), - g.FromUint64(4141115345494939173), - g.FromUint64(10070258119240548823), - g.FromUint64(11477026875407130857), - g.FromUint64(6299768551826493717), + g.GoldilocksField(14787739045021338943), + g.GoldilocksField(4141115345494939173), + g.GoldilocksField(10070258119240548823), + g.GoldilocksField(11477026875407130857), + g.GoldilocksField(6299768551826493717), }, IsInf: false, }, { X: gFp5.Element{ - g.FromUint64(2020949939443349975), - g.FromUint64(4576727228132381036), - g.FromUint64(11685880123997658374), - g.FromUint64(10781236098739931544), - g.FromUint64(354959600421572530), + g.GoldilocksField(2020949939443349975), + g.GoldilocksField(4576727228132381036), + g.GoldilocksField(11685880123997658374), + g.GoldilocksField(10781236098739931544), + g.GoldilocksField(354959600421572530), }, Y: gFp5.Element{ - g.FromUint64(2226472037177585493), - g.FromUint64(8680432113228524002), - g.FromUint64(5532575929311408085), - g.FromUint64(17286717775780223599), - g.FromUint64(7476327786946640228), + g.GoldilocksField(2226472037177585493), + g.GoldilocksField(8680432113228524002), + g.GoldilocksField(5532575929311408085), + g.GoldilocksField(17286717775780223599), + g.GoldilocksField(7476327786946640228), }, IsInf: false, }, @@ -1174,36 +1185,36 @@ func TestWeierstrassPrecomputeWindow(t *testing.T) { func TestWeierstrassDoubleAndWeierstrassAdd(t *testing.T) { qwe := WeierstrassPoint{ X: gFp5.Element{ - g.FromUint64(7887569478949190020), - g.FromUint64(11586418388990522938), - g.FromUint64(13676447623055915878), - g.FromUint64(5945168854809921881), - g.FromUint64(16291886980725359814), + g.GoldilocksField(7887569478949190020), + g.GoldilocksField(11586418388990522938), + g.GoldilocksField(13676447623055915878), + g.GoldilocksField(5945168854809921881), + g.GoldilocksField(16291886980725359814), }, Y: gFp5.Element{ - g.FromUint64(7556511254681645335), - g.FromUint64(17611929280367064763), - g.FromUint64(9410908488141053806), - g.FromUint64(11351540010214108766), - g.FromUint64(4846226015431423207), + g.GoldilocksField(7556511254681645335), + g.GoldilocksField(17611929280367064763), + g.GoldilocksField(9410908488141053806), + g.GoldilocksField(11351540010214108766), + g.GoldilocksField(4846226015431423207), }, IsInf: false, } doubled := qwe.Double() expectedX := gFp5.Element{ - g.FromUint64(2626390539619063455), - g.FromUint64(3069873143820007175), - g.FromUint64(16481805966921623903), - g.FromUint64(2169403494164322467), - g.FromUint64(15849876939764656634), + g.GoldilocksField(2626390539619063455), + g.GoldilocksField(3069873143820007175), + g.GoldilocksField(16481805966921623903), + g.GoldilocksField(2169403494164322467), + g.GoldilocksField(15849876939764656634), } expectedY := gFp5.Element{ - g.FromUint64(8052493994140007067), - g.FromUint64(12476750341447220703), - g.FromUint64(7297584762312352412), - g.FromUint64(4456043296886321460), - g.FromUint64(17416054515469523789), + g.GoldilocksField(8052493994140007067), + g.GoldilocksField(12476750341447220703), + g.GoldilocksField(7297584762312352412), + g.GoldilocksField(4456043296886321460), + g.GoldilocksField(17416054515469523789), } for i := 0; i < len(expectedX); i++ { @@ -1227,18 +1238,18 @@ func TestWeierstrassDoubleAndWeierstrassAdd(t *testing.T) { abc := WeierstrassPoint{ X: gFp5.Element{ - g.FromUint64(10440794216646581227), - g.FromUint64(13992847258701590930), - g.FromUint64(11213401763785319360), - g.FromUint64(12830171931568113117), - g.FromUint64(6220154342199499160), + g.GoldilocksField(10440794216646581227), + g.GoldilocksField(13992847258701590930), + g.GoldilocksField(11213401763785319360), + g.GoldilocksField(12830171931568113117), + g.GoldilocksField(6220154342199499160), }, Y: gFp5.Element{ - g.FromUint64(7971683838841472962), - g.FromUint64(1639066249976938469), - g.FromUint64(15015315060237521031), - g.FromUint64(10847769264696425470), - g.FromUint64(9177491810370773777), + g.GoldilocksField(7971683838841472962), + g.GoldilocksField(1639066249976938469), + g.GoldilocksField(15015315060237521031), + g.GoldilocksField(10847769264696425470), + g.GoldilocksField(9177491810370773777), }, IsInf: false, } @@ -1246,18 +1257,18 @@ func TestWeierstrassDoubleAndWeierstrassAdd(t *testing.T) { added := qwe.Add(abc) expectedAddedX := gFp5.Element{ - g.FromUint64(15147435967142035350), - g.FromUint64(4142330994743253079), - g.FromUint64(5589541853421788480), - g.FromUint64(8174056014411977160), - g.FromUint64(6779289104727130815), + g.GoldilocksField(15147435967142035350), + g.GoldilocksField(4142330994743253079), + g.GoldilocksField(5589541853421788480), + g.GoldilocksField(8174056014411977160), + g.GoldilocksField(6779289104727130815), } expectedAddedY := gFp5.Element{ - g.FromUint64(6941633164497114792), - g.FromUint64(102684445415310288), - g.FromUint64(3954903931673222082), - g.FromUint64(5355092272832152159), - g.FromUint64(15982629021221531228), + g.GoldilocksField(6941633164497114792), + g.GoldilocksField(102684445415310288), + g.GoldilocksField(3954903931673222082), + g.GoldilocksField(5355092272832152159), + g.GoldilocksField(15982629021221531228), } for i := 0; i < len(expectedAddedX); i++ { @@ -1281,36 +1292,36 @@ func TestWeierstrassDoubleAndWeierstrassAdd(t *testing.T) { a := WeierstrassPoint{ X: gFp5.Element{ - g.FromUint64(568906556912793428), - g.FromUint64(12270416106652192091), - g.FromUint64(17277438866839882878), - g.FromUint64(18290317522638929974), - g.FromUint64(7546670826452401067), + g.GoldilocksField(568906556912793428), + g.GoldilocksField(12270416106652192091), + g.GoldilocksField(17277438866839882878), + g.GoldilocksField(18290317522638929974), + g.GoldilocksField(7546670826452401067), }, Y: gFp5.Element{ - g.FromUint64(1322178101989677577), - g.FromUint64(18254974566546618836), - g.FromUint64(1119202239871436890), - g.FromUint64(13885721715120393435), - g.FromUint64(7665289671288386226), + g.GoldilocksField(1322178101989677577), + g.GoldilocksField(18254974566546618836), + g.GoldilocksField(1119202239871436890), + g.GoldilocksField(13885721715120393435), + g.GoldilocksField(7665289671288386226), }, IsInf: false, } b := WeierstrassPoint{ X: gFp5.Element{ - g.FromUint64(6853785572863472834), - g.FromUint64(11312233137032236241), - g.FromUint64(10155632987885765027), - g.FromUint64(761788325161687206), - g.FromUint64(10399811161072514291), + g.GoldilocksField(6853785572863472834), + g.GoldilocksField(11312233137032236241), + g.GoldilocksField(10155632987885765027), + g.GoldilocksField(761788325161687206), + g.GoldilocksField(10399811161072514291), }, Y: gFp5.Element{ - g.FromUint64(7631903676079326707), - g.FromUint64(10538051161007880093), - g.FromUint64(515356923921201259), - g.FromUint64(2139317767893795964), - g.FromUint64(17894501390404592328), + g.GoldilocksField(7631903676079326707), + g.GoldilocksField(10538051161007880093), + g.GoldilocksField(515356923921201259), + g.GoldilocksField(2139317767893795964), + g.GoldilocksField(17894501390404592328), }, IsInf: false, } @@ -1318,18 +1329,18 @@ func TestWeierstrassDoubleAndWeierstrassAdd(t *testing.T) { added = a.Add(b) expectedAdded := WeierstrassPoint{ X: gFp5.Element{ - g.FromUint64(14961006762295990506), - g.FromUint64(17765806093265157085), - g.FromUint64(6029983000119323104), - g.FromUint64(14198599897861826986), - g.FromUint64(2432992229534936263), + g.GoldilocksField(14961006762295990506), + g.GoldilocksField(17765806093265157085), + g.GoldilocksField(6029983000119323104), + g.GoldilocksField(14198599897861826986), + g.GoldilocksField(2432992229534936263), }, Y: gFp5.Element{ - g.FromUint64(9056990811557987042), - g.FromUint64(5949732889787570233), - g.FromUint64(5696931170027194764), - g.FromUint64(9998144444122976852), - g.FromUint64(13118328774200361975), + g.GoldilocksField(9056990811557987042), + g.GoldilocksField(5949732889787570233), + g.GoldilocksField(5696931170027194764), + g.GoldilocksField(9998144444122976852), + g.GoldilocksField(13118328774200361975), }, IsInf: false, } @@ -1351,35 +1362,35 @@ func TestWeierstrassDoubleAndWeierstrassAdd(t *testing.T) { func TestWeierstrassMulAdd2(t *testing.T) { qwe := WeierstrassPoint{ X: gFp5.Element{ - g.FromUint64(7887569478949190020), - g.FromUint64(11586418388990522938), - g.FromUint64(13676447623055915878), - g.FromUint64(5945168854809921881), - g.FromUint64(16291886980725359814), + g.GoldilocksField(7887569478949190020), + g.GoldilocksField(11586418388990522938), + g.GoldilocksField(13676447623055915878), + g.GoldilocksField(5945168854809921881), + g.GoldilocksField(16291886980725359814), }, Y: gFp5.Element{ - g.FromUint64(7556511254681645335), - g.FromUint64(17611929280367064763), - g.FromUint64(9410908488141053806), - g.FromUint64(11351540010214108766), - g.FromUint64(4846226015431423207), + g.GoldilocksField(7556511254681645335), + g.GoldilocksField(17611929280367064763), + g.GoldilocksField(9410908488141053806), + g.GoldilocksField(11351540010214108766), + g.GoldilocksField(4846226015431423207), }, IsInf: false, } abc := WeierstrassPoint{ X: gFp5.Element{ - g.FromUint64(10440794216646581227), - g.FromUint64(13992847258701590930), - g.FromUint64(11213401763785319360), - g.FromUint64(12830171931568113117), - g.FromUint64(6220154342199499160), + g.GoldilocksField(10440794216646581227), + g.GoldilocksField(13992847258701590930), + g.GoldilocksField(11213401763785319360), + g.GoldilocksField(12830171931568113117), + g.GoldilocksField(6220154342199499160), }, Y: gFp5.Element{ - g.FromUint64(7971683838841472962), - g.FromUint64(1639066249976938469), - g.FromUint64(15015315060237521031), - g.FromUint64(10847769264696425470), - g.FromUint64(9177491810370773777), + g.GoldilocksField(7971683838841472962), + g.GoldilocksField(1639066249976938469), + g.GoldilocksField(15015315060237521031), + g.GoldilocksField(10847769264696425470), + g.GoldilocksField(9177491810370773777), }, IsInf: false, } @@ -1404,18 +1415,18 @@ func TestWeierstrassMulAdd2(t *testing.T) { muladd := MulAdd2(qwe, abc, s, e) expectedMulAdd := WeierstrassPoint{ X: gFp5.Element{ - g.FromUint64(16860216879980764002), - g.FromUint64(13774182223913431169), - g.FromUint64(3778637410337906635), - g.FromUint64(7996647345600328210), - g.FromUint64(17994036749345991288), + g.GoldilocksField(16860216879980764002), + g.GoldilocksField(13774182223913431169), + g.GoldilocksField(3778637410337906635), + g.GoldilocksField(7996647345600328210), + g.GoldilocksField(17994036749345991288), }, Y: gFp5.Element{ - g.FromUint64(2325740112090595939), - g.FromUint64(18412478076524955076), - g.FromUint64(8648800055674409134), - g.FromUint64(7238972640284452927), - g.FromUint64(17572285593460315724), + g.GoldilocksField(2325740112090595939), + g.GoldilocksField(18412478076524955076), + g.GoldilocksField(8648800055674409134), + g.GoldilocksField(7238972640284452927), + g.GoldilocksField(17572285593460315724), }, IsInf: false, } diff --git a/curve/ecgfp5/point.go b/curve/ecgfp5/point.go index 9ea7241..d01efbf 100644 --- a/curve/ecgfp5/point.go +++ b/curve/ecgfp5/point.go @@ -15,13 +15,13 @@ type ECgFp5Point struct { // Constants for ECgFp5Point var ( - A_ECgFp5Point = gFp5.FromUint64Array([5]uint64{2, 0, 0, 0, 0}) + A_ECgFp5Point = gFp5.Element{2, 0, 0, 0, 0} - B1 = uint64(263) - B_ECgFp5Point = gFp5.FromUint64Array([5]uint64{0, B1, 0, 0, 0}) - B_MUL2_ECgFp5Point = gFp5.FromUint64Array([5]uint64{0, 2 * B1, 0, 0, 0}) - B_MUL4_ECgFp5Point = gFp5.FromUint64Array([5]uint64{0, 4 * B1, 0, 0, 0}) - B_MUL16_ECgFp5Point = gFp5.FromUint64Array([5]uint64{0, 16 * B1, 0, 0, 0}) + B1 = g.GoldilocksField(263) + B_ECgFp5Point = gFp5.Element{0, B1, 0, 0, 0} + B_MUL2_ECgFp5Point = gFp5.Element{0, 2 * B1, 0, 0, 0} + B_MUL4_ECgFp5Point = gFp5.Element{0, 4 * B1, 0, 0, 0} + B_MUL16_ECgFp5Point = gFp5.Element{0, 16 * B1, 0, 0, 0} NEUTRAL_ECgFp5Point = ECgFp5Point{ x: gFp5.FP5_ZERO, @@ -31,17 +31,16 @@ var ( } GENERATOR_ECgFp5Point = ECgFp5Point{ - x: gFp5.FromUint64Array([5]uint64{ + x: gFp5.Element{ 12883135586176881569, 4356519642755055268, 5248930565894896907, 2165973894480315022, 2448410071095648785, }, - ), z: gFp5.FP5_ONE, u: gFp5.FP5_ONE, - t: gFp5.FromUint64Array([5]uint64{4, 0, 0, 0, 0}), + t: gFp5.Element{4, 0, 0, 0, 0}, } ) @@ -52,15 +51,6 @@ func (p ECgFp5Point) Equals(rhs ECgFp5Point) bool { ) } -func CanBeDecodedIntoPoint(w gFp5.Element) bool { - // Value w can be decoded if and only if it is zero, or - // (w^2 - a)^2 - 4*b is a quadratic residue. - e := gFp5.Sub(gFp5.Square(w), A_ECgFp5Point) - delta := gFp5.Sub(gFp5.Square(e), B_MUL4_ECgFp5Point) - deltaLegendre := gFp5.Legendre(delta) - return gFp5.IsZero(w) || deltaLegendre.IsOne() -} - func (p ECgFp5Point) Encode() gFp5.Element { return gFp5.Mul(p.t, gFp5.InverseOrZero(p.u)) } @@ -83,12 +73,11 @@ func Decode(w gFp5.Element) (ECgFp5Point, bool) { x1 := gFp5.Div(gFp5.Add(e, r), gFp5.FP5_TWO) x2 := gFp5.Div(gFp5.Sub(e, r), gFp5.FP5_TWO) - x := x2 + x := x1 x1Legendre := gFp5.Legendre(x1) - one := g.One() - if !one.Equal(&x1Legendre) { - x = x1 + if x1Legendre.ToCanonicalUint64() == 1 { + x = x2 } // If c == true (delta is not a sqrt) then we want to get the neutral here; note that if @@ -112,7 +101,7 @@ func Decode(w gFp5.Element) (ECgFp5Point, bool) { return ECgFp5Point{x: x, z: z, u: u, t: t}, true } - return ECgFp5Point{}, false + return NEUTRAL_ECgFp5Point, false } func (p ECgFp5Point) IsNeutral() bool { @@ -210,7 +199,7 @@ func (p *ECgFp5Point) SetDouble() { tNew := gFp5.Sub( gFp5.Double(x1), gFp5.Add( - gFp5.Mul(t4, gFp5.FromUint64Array([5]uint64{4, 0, 0, 0, 0})), + gFp5.Mul(t4, gFp5.Element{4, 0, 0, 0, 0}), zNew, ), ) @@ -260,7 +249,7 @@ func (p *ECgFp5Point) SetMDouble(n uint32) { w := gFp5.Sub( gFp5.Double(x1), gFp5.Add( - gFp5.Mul(t5, gFp5.FromUint64Array([5]uint64{4, 0, 0, 0, 0})), + gFp5.Mul(t5, gFp5.Element{4, 0, 0, 0, 0}), t4, ), ) @@ -293,7 +282,7 @@ func (p *ECgFp5Point) SetMDouble(n uint32) { t2, gFp5.Sub( B_MUL4_ECgFp5Point, - gFp5.FromUint64Array([5]uint64{4, 0, 0, 0, 0}), + gFp5.Element{4, 0, 0, 0, 0}, ), ), ), @@ -363,7 +352,7 @@ func BatchToAffine(src []ECgFp5Point) []AffinePoint { // cost of 1 inversion and 3*(n-1) multiplications. n := len(src) if n == 0 { - return []AffinePoint{} + return nil } if n == 1 { p := src[0] @@ -420,22 +409,20 @@ func (p ECgFp5Point) MakeWindowAffine() []AffinePoint { } // Multiply this point by a scalar. -func (p *ECgFp5Point) SetMul(s *ECgFp5Scalar) { +func (r ECgFp5Point) Mul(s ECgFp5Scalar) ECgFp5Point { + p := r + // Make a window with affine points. win := p.MakeWindowAffine() digits := make([]int32, (319+WINDOW)/WINDOW) s.RecodeSigned(digits, int32(WINDOW)) - *p = LookupVarTime(win, digits[len(digits)-1]).ToPoint() + p = LookupVarTime(win, digits[len(digits)-1]).ToPoint() for i := len(digits) - 2; i >= 0; i-- { p.SetMDouble(uint32(WINDOW)) lookup := Lookup(win, digits[i]) - *p = p.AddAffine(lookup) + p = p.AddAffine(lookup) } -} -func (p ECgFp5Point) Mul(s *ECgFp5Scalar) ECgFp5Point { - newPoint := p - newPoint.SetMul(s) - return newPoint + return p } diff --git a/curve/ecgfp5/scalar_field.go b/curve/ecgfp5/scalar_field.go index 30be035..81e9635 100644 --- a/curve/ecgfp5/scalar_field.go +++ b/curve/ecgfp5/scalar_field.go @@ -2,34 +2,45 @@ package ecgfp5 import ( cryptorand "crypto/rand" - "crypto/sha256" "encoding/binary" "math/big" - "math/rand" gFp5 "github.com/elliottech/poseidon_crypto/field/goldilocks_quintic_extension" + . "github.com/elliottech/poseidon_crypto/int" ) // ECgFp5Scalar represents the scalar field of the ECgFP5 elliptic curve where // p = 1067993516717146951041484916571792702745057740581727230159139685185762082554198619328292418486241 type ECgFp5Scalar [5]uint64 -func (s *ECgFp5Scalar) DeepCopy() ECgFp5Scalar { - return ECgFp5Scalar{s[0], s[1], s[2], s[3], s[4]} +func (s ECgFp5Scalar) IsCanonical() bool { + return ToNonCanonicalBigInt(s).Cmp(ORDER) < 0 } +var ( + ORDER, _ = new(big.Int).SetString("1067993516717146951041484916571792702745057740581727230159139685185762082554198619328292418486241", 10) + ZERO = ECgFp5Scalar{} + ONE = ECgFp5Scalar{1, 0, 0, 0, 0} + TWO = ECgFp5Scalar{2, 0, 0, 0, 0} + NEG_ONE = ECgFp5Scalar{ + 0xE80FD996948BFFE0, + 0xE8885C39D724A09C, + 0x7FFFFFE6CFB80639, + 0x7FFFFFF100000016, + 0x7FFFFFFD80000007, + } +) + func (s ECgFp5Scalar) ToLittleEndianBytes() []byte { - var result [40]byte + result := make([]byte, 40) for i := 0; i < 5; i++ { binary.LittleEndian.PutUint64(result[i*8:], s[i]) } - return result[:] + return result } func ScalarElementFromLittleEndianBytes(data []byte) ECgFp5Scalar { - if len(data) != 40 { - panic("invalid length") - } + _ = data[39] // bounds check var value ECgFp5Scalar for i := 0; i < 5; i++ { @@ -39,17 +50,16 @@ func ScalarElementFromLittleEndianBytes(data []byte) ECgFp5Scalar { } func (s ECgFp5Scalar) SplitTo4BitLimbs() [80]uint8 { - limbs := s[:] var result [80]uint8 for i := 0; i < 5; i++ { for j := 0; j < 16; j++ { - result[i*16+j] = uint8((limbs[i] >> uint(j*4)) & 0xF) + result[i*16+j] = uint8((s[i] >> uint(j*4)) & 0xF) //nolint:gosec } } return result } -func SampleScalarCrypto() ECgFp5Scalar { +func SampleScalar() ECgFp5Scalar { rng, err := cryptorand.Int(cryptorand.Reader, ORDER) if err != nil { panic("failed to read random bytes into buffer") @@ -57,40 +67,6 @@ func SampleScalarCrypto() ECgFp5Scalar { return FromNonCanonicalBigInt(rng) } -func SampleScalar(seed *string) ECgFp5Scalar { - var rng *rand.Rand - if seed == nil { - return SampleScalarCrypto() - } - - hash := sha256.Sum256([]byte(*seed)) - var intSeed int64 - for _, b := range hash[:8] { - intSeed = (intSeed << 8) | int64(b) - } - rng = rand.New(rand.NewSource(intSeed)) - - return FromNonCanonicalBigInt(new(big.Int).Rand(rng, ORDER)) -} - -var ( - ORDER, _ = new(big.Int).SetString("1067993516717146951041484916571792702745057740581727230159139685185762082554198619328292418486241", 10) - ZERO = ECgFp5Scalar{} - ONE = ECgFp5Scalar{1, 0, 0, 0, 0} - TWO = ECgFp5Scalar{2, 0, 0, 0, 0} - NEG_ONE = ECgFp5Scalar{ - 0xE80FD996948BFFE0, - 0xE8885C39D724A09C, - 0x7FFFFFE6CFB80639, - 0x7FFFFFF100000016, - 0x7FFFFFFD80000007, - } -) - -func (s ECgFp5Scalar) Order() *big.Int { - return ORDER -} - var ( // Group order n is slightly below 2^319. We store values over five // 64-bit limbs. We use Montgomery multiplication to perform @@ -129,22 +105,8 @@ var ( } ) -func (s *ECgFp5Scalar) IsZero() bool { - for i := 0; i < 5; i++ { - if s[i] != 0 { - return false - } - } - return true -} - -func (s *ECgFp5Scalar) Equals(rhs *ECgFp5Scalar) bool { - for i := 0; i < 5; i++ { - if s[i] != rhs[i] { - return false - } - } - return true +func (s ECgFp5Scalar) Equals(rhs ECgFp5Scalar) bool { + return s[0] == rhs[0] && s[1] == rhs[1] && s[2] == rhs[2] && s[3] == rhs[3] && s[4] == rhs[4] } // raw addition (no reduction) @@ -152,7 +114,7 @@ func (s ECgFp5Scalar) AddInner(a ECgFp5Scalar) ECgFp5Scalar { var r ECgFp5Scalar var c uint64 = 0 for i := 0; i < 5; i++ { - z := U128From64(s[i]).Add64(a[i]).Add64(c) + z := AddUint128AndUint64(AddUint64(s[i], a[i]), c) r[i] = z.Lo c = z.Hi @@ -162,12 +124,12 @@ func (s ECgFp5Scalar) AddInner(a ECgFp5Scalar) ECgFp5Scalar { // raw subtraction (no reduction) // Final borrow is returned (0xFFFFFFFFFFFFFFFF if borrow, 0 otherwise). -func (s *ECgFp5Scalar) SubInner(a *ECgFp5Scalar) (*ECgFp5Scalar, uint64) { - r := new(ECgFp5Scalar) +func (s ECgFp5Scalar) SubInner(a ECgFp5Scalar) (ECgFp5Scalar, uint64) { + var r ECgFp5Scalar c := uint64(0) for i := 0; i < 5; i++ { - z := U128From64(s[i]).Sub64(a[i]).Sub64(c) + z := SubUint128AndUint64(SubUint128AndUint64(UInt128FromUint64(s[i]), a[i]), c) r[i] = z.Lo c = z.Hi & 1 } @@ -181,8 +143,8 @@ func (s *ECgFp5Scalar) SubInner(a *ECgFp5Scalar) (*ECgFp5Scalar, uint64) { // If c == 0, return a0. // If c == 0xFFFFFFFFFFFFFFFF, return a1. // c MUST be equal to 0 or 0xFFFFFFFFFFFFFFFF. -func Select(c uint64, a0, a1 *ECgFp5Scalar) *ECgFp5Scalar { - return &ECgFp5Scalar{ +func Select(c uint64, a0, a1 ECgFp5Scalar) ECgFp5Scalar { + return ECgFp5Scalar{ a0[0] ^ (c & (a0[0] ^ a1[0])), a0[1] ^ (c & (a0[1] ^ a1[1])), a0[2] ^ (c & (a0[2] ^ a1[2])), @@ -193,34 +155,27 @@ func Select(c uint64, a0, a1 *ECgFp5Scalar) *ECgFp5Scalar { func (s ECgFp5Scalar) Add(rhs ECgFp5Scalar) ECgFp5Scalar { r0 := s.AddInner(rhs) - r1, c := r0.SubInner(&N) - return *Select(c, r1, &r0) -} - -func (s ECgFp5Scalar) Sub(rhs ECgFp5Scalar) ECgFp5Scalar { - r0, c := s.SubInner(&rhs) - r1 := r0.AddInner(N) - return *Select(c, r0, &r1) + r1, c := r0.SubInner(N) // one reduce is enough if s < n and rhs < n + return Select(c, r1, r0) } -func (s ECgFp5Scalar) Neg() ECgFp5Scalar { - return ZERO.Sub(s) +func (s *ECgFp5Scalar) Sub(rhs ECgFp5Scalar) ECgFp5Scalar { + r0, c := s.SubInner(rhs) + r1 := r0.AddInner(N) // one add is enough if s < n and rhs < n + return Select(c, r0, r1) } -func (s *ECgFp5Scalar) Mul(rhs *ECgFp5Scalar) *ECgFp5Scalar { - res := s.MontyMul(&R2).MontyMul(rhs) +// 's' must be less than n. +func (s ECgFp5Scalar) Mul(rhs ECgFp5Scalar) ECgFp5Scalar { + res := s.MontyMul(R2).MontyMul(rhs) return res } -func (s *ECgFp5Scalar) Square() *ECgFp5Scalar { - return s.Mul(s) -} - // Montgomery multiplication. -// Returns (self*rhs)/2^320 mod n. -// 'self' MUST be less than n (the other operand can be up to 2^320-1). -func (s *ECgFp5Scalar) MontyMul(rhs *ECgFp5Scalar) *ECgFp5Scalar { - r := new(ECgFp5Scalar) +// Returns (s*rhs)/2^320 mod n. +// 's' MUST be less than n (the other operand can be up to 2^320-1). +func (s ECgFp5Scalar) MontyMul(rhs ECgFp5Scalar) ECgFp5Scalar { + var r ECgFp5Scalar for i := 0; i < 5; i++ { // Iteration i computes r <- (r + self*rhs_i + f*n)/2^64. // Factor f is at most 2^64-1 and set so that the division @@ -240,9 +195,9 @@ func (s *ECgFp5Scalar) MontyMul(rhs *ECgFp5Scalar) *ECgFp5Scalar { cc1, cc2 := uint64(0), uint64(0) for j := 0; j < 5; j++ { - z := U128From64(s[j]).Mul64(m).Add64(r[j]).Add64(cc1) + z := AddUint128AndUint64(AddUint128AndUint64(MulUInt64(s[j], m), r[j]), cc1) cc1 = z.Hi - z = U128From64(f).Mul64(N[j]).Add64(z.Lo).Add64(cc2) + z = AddUint128AndUint64(AddUint128AndUint64(MulUInt64(f, N[j]), z.Lo), cc2) cc2 = z.Hi if j > 0 { r[j-1] = z.Lo @@ -257,49 +212,36 @@ func (s *ECgFp5Scalar) MontyMul(rhs *ECgFp5Scalar) *ECgFp5Scalar { // ff < 2^320 // Thus, the value we obtained is lower than 2*n. Subtracting n // once (conditionally) is sufficient to achieve full reduction. - r2, c := r.SubInner(&N) + r2, c := r.SubInner(N) return Select(c, r2, r) } -func (s ECgFp5Scalar) expPowerOf2(exp int) ECgFp5Scalar { - result := s - for i := 0; i < exp; i++ { - result = *result.Square() - } - return result -} - func FromGfp5(fp5 gFp5.Element) ECgFp5Scalar { - return FromNonCanonicalBigInt(BigIntFromArray([5]uint64{ - fp5[0].Uint64(), fp5[1].Uint64(), fp5[2].Uint64(), fp5[3].Uint64(), fp5[4].Uint64(), - })) -} - -func BigIntFromArray(arr [5]uint64) *big.Int { result := new(big.Int) for i := 4; i >= 0; i-- { result.Lsh(result, 64) - result.Or(result, new(big.Int).SetUint64(arr[i])) + result.Or(result, new(big.Int).SetUint64(fp5[i].ToCanonicalUint64())) // it always fit to } - return result + + return FromNonCanonicalBigInt(result) } +// Warn: This won't work in 32-bit systems! func FromNonCanonicalBigInt(val *big.Int) ECgFp5Scalar { limbs := new(big.Int).Mod(val, ORDER).Bits() if len(limbs) < 5 { - limbs = append(limbs, 0) + limbs = append(limbs, make([]big.Word, 5-len(limbs))...) } - return ECgFp5Scalar{uint64(limbs[0]), uint64(limbs[1]), uint64(limbs[2]), uint64(limbs[3]), uint64(limbs[4])} -} -func (s ECgFp5Scalar) ToCanonicalBigInt() *big.Int { - result := BigIntFromArray(s) + return ECgFp5Scalar{uint64(limbs[0]), uint64(limbs[1]), uint64(limbs[2]), uint64(limbs[3]), uint64(limbs[4])} // assuming big.Word is 64 bits +} - order := ORDER - if result.Cmp(order) >= 0 { - result.Sub(result, order) +func ToNonCanonicalBigInt(s ECgFp5Scalar) *big.Int { + result := new(big.Int) + for i := 4; i >= 0; i-- { + result.Lsh(result, 64) + result.Or(result, new(big.Int).SetUint64(s[i])) } - return result } @@ -312,38 +254,3 @@ func (s ECgFp5Scalar) ToCanonicalBigInt() *big.Int { func (s ECgFp5Scalar) RecodeSigned(ss []int32, w int32) { RecodeSignedFromLimbs(s[:], ss, w) } - -func RecodeSignedFromLimbs(limbs []uint64, ss []int32, w int32) { - var acc uint64 = 0 - var accLen int32 = 0 - var j int = 0 - mw := (uint32(1) << w) - 1 - hw := uint32(1) << (w - 1) - var cc uint32 = 0 - for i := 0; i < len(ss); i++ { - // Get next w-bit chunk in bb. - var bb uint32 - if accLen < w { - if j < len(limbs) { - nl := limbs[j] - j++ - bb = (uint32(acc | (nl << accLen))) & mw - acc = nl >> (w - accLen) - } else { - bb = uint32(acc) & mw - acc = 0 - } - accLen += 64 - w - } else { - bb = uint32(acc) & mw - accLen -= w - acc >>= w - } - - // If bb is greater than 2^(w-1), subtract 2^w and propagate a carry. - bb += cc - - cc = (hw - bb) >> 31 - ss[i] = int32(bb) - int32(cc<> 32) + 1) << 33 - return [3]uint64{s[0], s[1], x} -} - -// Recode this integer into 33 signed digits for a 5-bit window. -func (s Signed161) RecodeSigned5() [33]int32 { - // We first sign-extend the value to 192 bits, then add - // 2^160 to get a nonnegative value in the 0 to 2^161-1 - // range. We then recode that value; and finally we fix - // the result by subtracting 1 from the top digit. - tmp := s.ToU192() - tmp[2] += 0x0000000100000000 - var ss [33]int32 - RecodeSignedFromLimbs(tmp[:], ss[:], 5) - ss[32] -= 1 - return ss -} - -// Add v*2^s to this value. -func (s *Signed161) AddShifted(v *Signed161, shift int32) { - if shift == 0 { - s.Add(v[:]) - } else if shift < 64 { - s.AddShiftedSmall(v[:], shift) - } else if shift < 161 { - s.AddShiftedSmall(v[(shift>>6):], shift&63) - } -} - -func (s *Signed161) AddShiftedSmall(v []uint64, shift int32) { - cc, vbits, j := uint64(0), uint64(0), 3-len(v) - for i := j; i < 3; i++ { - vw := v[i-j] - - vws := (vw << (uint32(shift) % 64)) | vbits - vbits = vw >> ((64 - uint32(shift)) % 64) - - z := U128From64(s[i]).Add64(vws).Add64(cc) - s[i] = z.Lo - cc = z.Hi - } -} - -func (s *Signed161) Add(v []uint64) { - cc, j := uint64(0), 3-len(v) - for i := j; i < 3; i++ { - z := U128From64(s[i]).Add64(v[i-j]).Add64(cc) - s[i] = z.Lo - cc = z.Hi - } -} - -// Subtract v*2^s from this value. -func (s *Signed161) SubShifted(v *Signed161, shift int32) { - if shift == 0 { - s.Sub(v[:]) - } else if shift < 64 { - s.SubShiftedSmall(v[:], shift) - } else if shift < 161 { - s.SubShiftedSmall(v[(shift>>6):], shift&63) - } -} - -func (s *Signed161) SubShiftedSmall(v []uint64, shift int32) { - cc, vbits, j := uint64(0), uint64(0), 3-len(v) - for i := j; i < 3; i++ { - vw := v[i-j] - vws := (vw << (uint32(shift) % 64)) | vbits - vbits = vw >> ((64 - uint32(shift)) % 64) - - z := U128From64(s[i]).Sub64(vws).Sub64(cc) - s[i] = z.Lo - cc = z.Hi & 1 - } -} - -func (s *Signed161) Sub(v []uint64) { - cc, j := uint64(0), 3-len(v) - for i := j; i < 3; i++ { - z := U128From64(s[i]).Sub64(v[i-j]).Sub64(cc) - s[i] = z.Lo - cc = z.Hi & 1 - } -} diff --git a/curve/ecgfp5/signed640.go b/curve/ecgfp5/signed640.go deleted file mode 100644 index eece81b..0000000 --- a/curve/ecgfp5/signed640.go +++ /dev/null @@ -1,182 +0,0 @@ -package ecgfp5 - -// A custom 640-bit integer type (signed). -// Elements are mutable containers. -// WARNING: everything in here is vartime; do not use on secret values. -type Signed640 [10]uint64 - -// Obtain an instance containing n^2. -func FromNsquared() *Signed640 { - return &Signed640{ - 0x8E6B7A18061803C1, - 0x0AD8BDEE1594E2CF, - 0x17640E465F2598BC, - 0x90465B4214B27B1C, - 0xD308FECCB1878B88, - 0x3CC55EB2EAC07502, - 0x59F038FB784335CE, - 0xBFFFFE954FB808EA, - 0xBFFFFFCB80000099, - 0x3FFFFFFD8000000D, - } -} - -// Obtain an instance containing a*b (both a and b are interpreted -// as integers in the 0..n-1 range). -func FromMulScalars(a, b *ECgFp5Scalar) *Signed640 { - var r Signed640 - for i := 0; i < 5; i++ { - aw := a[i] - cc := uint64(0) - for j := 0; j < 5; j++ { - z := U128From64(aw).Mul64(b[j]).Add64(r[i+j]).Add64(cc) - r[i+j] = z.Lo - cc = z.Hi - } - r[i+5] = cc - } - return &r -} - -// Add 1 to this instance. -func (s *Signed640) Add1() { - for i := 0; i < 10; i++ { - s[i]++ - if s[i] != 0 { - return - } - } -} - -func (s *Signed640) IsNonnegative() bool { - return (s[9] >> 63) == 0 -} - -func (s *Signed640) LtUnsigned(rhs *Signed640) bool { - for i := 9; i >= 0; i-- { - aw := s[i] - bw := rhs[i] - if aw < bw { - return true - } - if aw > bw { - return false - } - } - return false -} - -// Get the bit length of this value. The bit length is defined as the -// minimal size of the binary representation in two's complement, -// _excluding_ the sign bit (thus, -2^k has bit length k, whereas +2^k -// has bit length k+1). -func (s *Signed640) Bitlength() int32 { - sm := (^(s[9] >> 63) + 1) - for i := 9; i >= 0; i-- { - w := s[i] ^ sm - if w != 0 { - return (int32(i) << 6) + U64Bitlength(w) - } - } - return 0 -} - -func U64Bitlength(w uint64) int32 { - // We use here a portable algorithm; some architectures have - // dedicated opcodes that could speed up this operation - // greatly (e.g. lzcnt on recent x86). - var x = w - var r int32 - if x > 0xFFFFFFFF { - x >>= 32 - r += 32 - } - if x > 0x0000FFFF { - x >>= 16 - r += 16 - } - if x > 0x000000FF { - x >>= 8 - r += 8 - } - if x > 0x0000000F { - x >>= 4 - r += 4 - } - if x > 0x00000003 { - x >>= 2 - r += 2 - } - return r + int32(x) - int32((x+1)>>2) -} - -// Add v*2^s to this instance. -func (s *Signed640) AddShifted(v *Signed640, shift int32) { - if shift == 0 { - s.Add(v[:]) - } else if shift < 64 { - s.AddShiftedSmall(v[:], shift) - } else if shift < 640 { - s.AddShiftedSmall(v[(shift>>6):], shift&63) - } -} - -func (s *Signed640) AddShiftedSmall(v []uint64, shift int32) { - cc := uint64(0) - j := 10 - len(v) - vbits := uint64(0) - for i := j; i < 10; i++ { - vw := v[i-j] - - vws := (vw << (uint32(shift) % 64)) | vbits - vbits = vw >> ((64 - uint32(shift)) % 64) - - z := U128From64(s[i]).Add64(vws).Add64(cc) - s[i] = z.Lo - cc = z.Hi - } -} - -func (s *Signed640) Add(v []uint64) { - cc := uint64(0) - j := 10 - len(v) - for i := j; i < 10; i++ { - z := U128From64(s[i]).Add64(v[i-j]).Add64(cc) - s[i] = z.Lo - cc = z.Hi - } -} - -// Subtract v*2^s from this instance. -func (s *Signed640) SubShifted(v *Signed640, shift int32) { - if shift == 0 { - s.Sub(v[:]) - } else if shift < 64 { - s.SubShiftedSmall(v[:], shift) - } else if shift < 640 { - s.SubShiftedSmall(v[(shift>>6):], shift&63) - } -} - -func (s *Signed640) SubShiftedSmall(v []uint64, shift int32) { - cc, vbits, j := uint64(0), uint64(0), 10-len(v) - for i := j; i < 10; i++ { - vw := v[i-j] - - vws := (vw << (uint32(shift) % 64)) | vbits - vbits = vw >> ((64 - uint32(shift)) % 64) - - z := U128From64(s[i]).Sub64(vws).Sub64(cc) - s[i] = z.Lo - cc = z.Hi & 1 - } -} - -func (s *Signed640) Sub(v []uint64) { - cc, j := uint64(0), 10-len(v) - for i := j; i < 10; i++ { - z := U128From64(s[i]).Sub64(v[i-j]).Sub64(cc) - s[i] = z.Lo - cc = z.Hi & 1 - } -} diff --git a/curve/ecgfp5/u128.go b/curve/ecgfp5/u128.go deleted file mode 100644 index 10bd6d4..0000000 --- a/curve/ecgfp5/u128.go +++ /dev/null @@ -1,29 +0,0 @@ -package ecgfp5 - -import ( - "math/bits" -) - -type U128 struct{ Hi, Lo uint64 } - -func U128From64(v uint64) U128 { return U128{Lo: v} } - -func (u U128) Add64(n uint64) (v U128) { - var carry uint64 - v.Lo, carry = bits.Add64(u.Lo, n, 0) - v.Hi = u.Hi + carry - return v -} - -func (u U128) Sub64(n uint64) (v U128) { - var borrowed uint64 - v.Lo, borrowed = bits.Sub64(u.Lo, n, 0) - v.Hi = u.Hi - borrowed - return v -} - -func (u U128) Mul64(n uint64) (dest U128) { - dest.Hi, dest.Lo = bits.Mul64(u.Lo, n) - dest.Hi += u.Hi * n - return dest -} diff --git a/curve/ecgfp5/weierstrass_point.go b/curve/ecgfp5/weierstrass_point.go index 747aea7..44ea3c3 100644 --- a/curve/ecgfp5/weierstrass_point.go +++ b/curve/ecgfp5/weierstrass_point.go @@ -15,28 +15,28 @@ type WeierstrassPoint struct { var ( GENERATOR_WEIERSTRASS = WeierstrassPoint{ X: gFp5.Element{ - g.FromUint64(11712523173042564207), - g.FromUint64(14090224426659529053), - g.FromUint64(13197813503519687414), - g.FromUint64(16280770174934269299), - g.FromUint64(15998333998318935536), + g.GoldilocksField(11712523173042564207), + g.GoldilocksField(14090224426659529053), + g.GoldilocksField(13197813503519687414), + g.GoldilocksField(16280770174934269299), + g.GoldilocksField(15998333998318935536), }, Y: gFp5.Element{ - g.FromUint64(14639054205878357578), - g.FromUint64(17426078571020221072), - g.FromUint64(2548978194165003307), - g.FromUint64(8663895577921260088), - g.FromUint64(9793640284382595140), + g.GoldilocksField(14639054205878357578), + g.GoldilocksField(17426078571020221072), + g.GoldilocksField(2548978194165003307), + g.GoldilocksField(8663895577921260088), + g.GoldilocksField(9793640284382595140), }, IsInf: false, } A_WEIERSTRASS = gFp5.Element{ - g.FromUint64(6148914689804861439), - g.FromUint64(263), - g.FromUint64(0), - g.FromUint64(0), - g.FromUint64(0), + g.GoldilocksField(6148914689804861439), + g.GoldilocksField(263), + g.GoldilocksField(0), + g.GoldilocksField(0), + g.GoldilocksField(0), } NEUTRAL_WEIERSTRASS = WeierstrassPoint{ @@ -68,10 +68,10 @@ func DecodeFp5AsWeierstrass(w gFp5.Element) (WeierstrassPoint, bool) { x1 := gFp5.Div(gFp5.Add(e, r), gFp5.FP5_TWO) x2 := gFp5.Div(gFp5.Sub(e, r), gFp5.FP5_TWO) - x := x1 + x := x2 x1Legendre := gFp5.Legendre(x1) - if !x1Legendre.IsOne() { - x = x2 + if x1Legendre.ToCanonicalUint64() == 1 { + x = x1 } y := gFp5.Neg(gFp5.Mul(w, x)) @@ -87,7 +87,7 @@ func DecodeFp5AsWeierstrass(w gFp5.Element) (WeierstrassPoint, bool) { if success || gFp5.IsZero(w) { return WeierstrassPoint{X: x, Y: y, IsInf: isInf}, true } - return WeierstrassPoint{}, false + return NEUTRAL_WEIERSTRASS, false } func (p WeierstrassPoint) Add(q WeierstrassPoint) WeierstrassPoint { diff --git a/field/field_test.go b/field/field_test.go index e0ad6eb..b89ee06 100644 --- a/field/field_test.go +++ b/field/field_test.go @@ -7,6 +7,7 @@ import ( g "github.com/elliottech/poseidon_crypto/field/goldilocks" gFp5 "github.com/elliottech/poseidon_crypto/field/goldilocks_quintic_extension" + . "github.com/elliottech/poseidon_crypto/int" "math/big" "math/rand/v2" @@ -28,7 +29,7 @@ func TestBytes(t *testing.T) { t.Fatalf("bytes do not match") } - r := rand.Uint64N(g.ORDER) + r := rand.Uint64N(g.ORDER) //nolint:gosec leBytesUint64 := make([]byte, 8) binary.LittleEndian.PutUint64(leBytesUint64, r) @@ -42,7 +43,7 @@ func TestBytes(t *testing.T) { } func TestBytesF(t *testing.T) { - r := rand.Uint64N(g.ORDER) + r := rand.Uint64N(g.ORDER) //nolint:gosec f := g.GoldilocksField(r) rBytes := make([]byte, 8) @@ -205,7 +206,7 @@ func TestMulAccF(t *testing.T) { } func TestReduce128Bit(t *testing.T) { - testValues := []g.UInt128{ + testValues := []UInt128{ {0, 0}, {1, 0}, {math.MaxUint64, math.MaxUint64}, @@ -231,7 +232,7 @@ func TestReduce128Bit(t *testing.T) { } func TestReduce96Bit(t *testing.T) { - testValues := []g.UInt128{ + testValues := []UInt128{ {0, 0}, {1, 0}, {math.MaxUint32, math.MaxUint64}, @@ -307,8 +308,8 @@ func FuzzTestF(f *testing.F) { f.Add(uint64(1), uint64(1)) f.Add(uint64(math.MaxUint64), uint64(math.MaxUint64)) f.Add(uint64(math.MaxUint32), uint64(math.MaxUint64)) - f.Add(uint64(g.ORDER-1), uint64(g.ORDER-1)) - f.Add(uint64(g.ORDER), uint64(g.ORDER)) + f.Add(g.ORDER-1, g.ORDER-1) + f.Add(g.ORDER, g.ORDER) f.Fuzz(func(t *testing.T, lhs, rhs uint64) { // AddF @@ -369,7 +370,7 @@ func FuzzTestF(f *testing.F) { // Reduce128Bit { - val := g.UInt128{Hi: lhs, Lo: rhs} + val := UInt128{Hi: lhs, Lo: rhs} reduced := g.Reduce128Bit(val) bigVal := new(big.Int).SetUint64(val.Hi) bigVal.Lsh(bigVal, 64) @@ -384,7 +385,7 @@ func FuzzTestF(f *testing.F) { // Reduce96Bit { - val := g.UInt128{Hi: uint64(uint32(lhs)), Lo: rhs} + val := UInt128{Hi: uint64(uint32(lhs)), Lo: rhs} reduced := g.Reduce96Bit(val) bigVal := new(big.Int).SetUint64(val.Hi) bigVal.Lsh(bigVal, 64) @@ -396,6 +397,33 @@ func FuzzTestF(f *testing.F) { t.Fatalf("Reduce96Bit: Expected reduction of %v to be %d, but got %d", val, expected, reduced.ToCanonicalUint64()) } } + + { // InverseOrZero + val := g.GoldilocksField(lhs) + inv := val.InverseOrZero() + if val.IsZero() { + if !inv.IsZero() { + t.Fatalf("InverseOrZero: Expected inverse of 0 to be 0, but got %v", inv) + } + } else { + prod := g.MulF(val, inv).ToCanonicalUint64() + if prod != 1 { + t.Fatalf("InverseOrZero: Expected %d * inv(%d) = 1, but got %d", lhs, lhs, prod) + } + } + } + + { // SqrtF + val := g.GoldilocksField(lhs) + val2 := g.SquareF(val) + s := g.SqrtF(val2) + if s == nil { + t.Fatalf("SqrtF: Expected sqrt to exist for square of %d, but got nil", lhs) + } + if g.SquareF(*s).ToCanonicalUint64() != val2.ToCanonicalUint64() { + t.Fatalf("SqrtF: Expected sqrt^2 to be %d, but got %d", val2.ToCanonicalUint64(), g.SquareF(*s).ToCanonicalUint64()) + } + } }) } @@ -403,24 +431,24 @@ func FuzzTestF(f *testing.F) { func TestQuinticExtensionAddSubMulSquare(t *testing.T) { val1 := gFp5.Element{ - g.FromUint64(0x1234567890ABCDEF), - g.FromUint64(0x0FEDCBA987654321), - g.FromUint64(0x1122334455667788), - g.FromUint64(0x8877665544332211), - g.FromUint64(0xAABBCCDDEEFF0011), + g.GoldilocksField(0x1234567890ABCDEF), + g.GoldilocksField(0x0FEDCBA987654321), + g.GoldilocksField(0x1122334455667788), + g.GoldilocksField(0x8877665544332211), + g.GoldilocksField(0xAABBCCDDEEFF0011), } val2 := gFp5.Element{ - g.FromUint64(0xFFFFFFFFFFFFFFFF), - g.FromUint64(0xFFFFFFFFFFFFFFFF), - g.FromUint64(0xFFFFFFFFFFFFFFFF), - g.FromUint64(0xFFFFFFFFFFFFFFFF), - g.FromUint64(0xFFFFFFFFFFFFFFFF), + g.GoldilocksField(0xFFFFFFFFFFFFFFFF), + g.GoldilocksField(0xFFFFFFFFFFFFFFFF), + g.GoldilocksField(0xFFFFFFFFFFFFFFFF), + g.GoldilocksField(0xFFFFFFFFFFFFFFFF), + g.GoldilocksField(0xFFFFFFFFFFFFFFFF), } add := gFp5.Add(val1, val2) expectedAdd := [5]uint64{1311768471589866989, 1147797413325783839, 1234605620731475846, 9833440832084189711, 12302652064957136911} for i := 0; i < 5; i++ { - if add[i].Uint64() != expectedAdd[i] { + if add[i].ToCanonicalUint64() != expectedAdd[i] { t.Fatalf("Addition: Expected limb %d to be %x, but got %x", i, expectedAdd[i], add[i]) } } @@ -428,7 +456,7 @@ func TestQuinticExtensionAddSubMulSquare(t *testing.T) { sub := gFp5.Sub(val1, val2) expectedSub := [5]uint64{1311768462999932401, 1147797404735849251, 1234605612141541258, 9833440823494255123, 12302652056367202323} for i := 0; i < 5; i++ { - if sub[i].Uint64() != expectedSub[i] { + if sub[i].ToCanonicalUint64() != expectedSub[i] { t.Fatalf("Subtraction: Expected limb %d to be %x, but got %x", i, expectedSub[i], sub[i]) } } @@ -436,7 +464,7 @@ func TestQuinticExtensionAddSubMulSquare(t *testing.T) { mul := gFp5.Mul(val1, val2) expectedMul := [5]uint64{12801331769143413385, 14031114708135177824, 4192851210753422088, 14031114723597060086, 4193451712464626164} for i := 0; i < 5; i++ { - if mul[i].Uint64() != expectedMul[i] { + if mul[i].ToCanonicalUint64() != expectedMul[i] { t.Fatalf("Multiplication: Expected limb %d to be %x, but got %x", i, expectedMul[i], mul[i]) } } @@ -450,7 +478,7 @@ func TestQuinticExtensionAddSubMulSquare(t *testing.T) { 2864528669572451733, } for i := 0; i < 5; i++ { - if square[i].Uint64() != expectedSquare[i] { + if square[i].ToCanonicalUint64() != expectedSquare[i] { t.Fatalf("Square: Expected limb %d to be %x, but got %x", i, expectedSquare[i], square[i]) } } @@ -475,7 +503,7 @@ func TestQuinticExtensionAddSubMulSquareF(t *testing.T) { add := gFp5.Add(val1, val2) expectedAdd := [5]uint64{1311768471589866989, 1147797413325783839, 1234605620731475846, 9833440832084189711, 12302652064957136911} for i := 0; i < 5; i++ { - if add[i].Uint64() != expectedAdd[i] { + if add[i].ToCanonicalUint64() != expectedAdd[i] { t.Fatalf("Addition: Expected limb %d to be %x, but got %x", i, expectedAdd[i], add[i]) } } @@ -483,7 +511,7 @@ func TestQuinticExtensionAddSubMulSquareF(t *testing.T) { sub := gFp5.Sub(val1, val2) expectedSub := [5]uint64{1311768462999932401, 1147797404735849251, 1234605612141541258, 9833440823494255123, 12302652056367202323} for i := 0; i < 5; i++ { - if sub[i].Uint64() != expectedSub[i] { + if sub[i].ToCanonicalUint64() != expectedSub[i] { t.Fatalf("Subtraction: Expected limb %d to be %x, but got %x", i, expectedSub[i], sub[i]) } } @@ -491,7 +519,7 @@ func TestQuinticExtensionAddSubMulSquareF(t *testing.T) { mul := gFp5.Mul(val1, val2) expectedMul := [5]uint64{12801331769143413385, 14031114708135177824, 4192851210753422088, 14031114723597060086, 4193451712464626164} for i := 0; i < 5; i++ { - if mul[i].Uint64() != expectedMul[i] { + if mul[i].ToCanonicalUint64() != expectedMul[i] { t.Fatalf("Multiplication: Expected limb %d to be %x, but got %x", i, expectedMul[i], mul[i]) } } @@ -505,7 +533,7 @@ func TestQuinticExtensionAddSubMulSquareF(t *testing.T) { 2864528669572451733, } for i := 0; i < 5; i++ { - if square[i].Uint64() != expectedSquare[i] { + if square[i].ToCanonicalUint64() != expectedSquare[i] { t.Fatalf("Square: Expected limb %d to be %x, but got %x", i, expectedSquare[i], square[i]) } } @@ -513,11 +541,11 @@ func TestQuinticExtensionAddSubMulSquareF(t *testing.T) { func TestRepeatedFrobeniusgFp5(t *testing.T) { val := gFp5.Element{ - g.FromUint64(0x1234567890ABCDEF), - g.FromUint64(0x0FEDCBA987654321), - g.FromUint64(0x1122334455667788), - g.FromUint64(0x8877665544332211), - g.FromUint64(0xAABBCCDDEEFF0011), + g.GoldilocksField(0x1234567890ABCDEF), + g.GoldilocksField(0x0FEDCBA987654321), + g.GoldilocksField(0x1122334455667788), + g.GoldilocksField(0x8877665544332211), + g.GoldilocksField(0xAABBCCDDEEFF0011), } res := gFp5.RepeatedFrobenius(val, 1) @@ -530,7 +558,7 @@ func TestRepeatedFrobeniusgFp5(t *testing.T) { 17855579289599571296, } for i := 0; i < 5; i++ { - if res[i] != g.FromUint64(expected[i]) { + if res[i] != g.GoldilocksField(expected[i]) { t.Fatalf("Assertion failed at index %d: expected %d, got %d", i, expected[i], res[i]) } } @@ -538,11 +566,11 @@ func TestRepeatedFrobeniusgFp5(t *testing.T) { func TestTryInverse(t *testing.T) { val := gFp5.Element{ - g.FromUint64(0x1234567890ABCDEF), - g.FromUint64(0x0FEDCBA987654321), - g.FromUint64(0x1122334455667788), - g.FromUint64(0x8877665544332211), - g.FromUint64(0xAABBCCDDEEFF0011), + g.GoldilocksField(0x1234567890ABCDEF), + g.GoldilocksField(0x0FEDCBA987654321), + g.GoldilocksField(0x1122334455667788), + g.GoldilocksField(0x8877665544332211), + g.GoldilocksField(0xAABBCCDDEEFF0011), } result := gFp5.InverseOrZero(val) @@ -555,8 +583,8 @@ func TestTryInverse(t *testing.T) { 8256636258983026155, } - for i, elem := range result.ToBasefieldArray() { - if elem.Uint64() != expected[i] { + for i, elem := range result { + if elem.ToCanonicalUint64() != expected[i] { t.Fatalf("Assertion failed at index %d: expected %d, got %d", i, expected[i], elem) } } @@ -564,11 +592,11 @@ func TestTryInverse(t *testing.T) { func TestQuinticExtSgn0(t *testing.T) { if !gFp5.Sgn0(gFp5.Element{ - g.FromUint64(7146494650688613286), - g.FromUint64(2524706331227574337), - g.FromUint64(2805008444831673606), - g.FromUint64(10342159727506097401), - g.FromUint64(5582307593199735986), + g.GoldilocksField(7146494650688613286), + g.GoldilocksField(2524706331227574337), + g.GoldilocksField(2805008444831673606), + g.GoldilocksField(10342159727506097401), + g.GoldilocksField(5582307593199735986), }) { t.Fatalf("Expected sign to be true, but got false") } @@ -576,19 +604,27 @@ func TestQuinticExtSgn0(t *testing.T) { func TestSqrtFunctions(t *testing.T) { x := gFp5.Element{ - g.FromUint64(17397692312497920520), - g.FromUint64(4597259071399531684), - g.FromUint64(15835726694542307225), - g.FromUint64(16979717054676631815), - g.FromUint64(12876043227925845432), + g.GoldilocksField(17397692312497920520), + g.GoldilocksField(4597259071399531684), + g.GoldilocksField(15835726694542307225), + g.GoldilocksField(16979717054676631815), + g.GoldilocksField(12876043227925845432), + } + + expectedCanonical := gFp5.Element{ + g.GoldilocksField(16260118390353633405), + g.GoldilocksField(2204473665618140400), + g.GoldilocksField(10421517006653550782), + g.GoldilocksField(4618467884536173852), + g.GoldilocksField(15556190572415033139), } expected := gFp5.Element{ - g.FromUint64(16260118390353633405), - g.FromUint64(2204473665618140400), - g.FromUint64(10421517006653550782), - g.FromUint64(4618467884536173852), - g.FromUint64(15556190572415033139), + g.GoldilocksField(2186625679060950916), + g.GoldilocksField(16242270403796443921), + g.GoldilocksField(8025227062761033539), + g.GoldilocksField(13828276184878410469), + g.GoldilocksField(2890553496999551182), } result, exists := gFp5.CanonicalSqrt(x) @@ -596,8 +632,8 @@ func TestSqrtFunctions(t *testing.T) { t.Fatalf("Expected canonical sqrt to exist, but it does not") } - if !gFp5.Equals(result, expected) { - t.Fatalf("Expected canonical sqrt to be %v, but got %v", expected, result) + if !gFp5.Equals(result, expectedCanonical) { + t.Fatalf("Expected canonical sqrt to be %v, but got %v", expectedCanonical, result) } result2, exists2 := gFp5.Sqrt(x) @@ -612,15 +648,20 @@ func TestSqrtFunctions(t *testing.T) { func TestSqrtNonExistent(t *testing.T) { _, exists := gFp5.Sqrt(gFp5.Element{ - g.FromUint64(3558249639744866495), - g.FromUint64(2615658757916804776), - g.FromUint64(14375546700029059319), - g.FromUint64(16160052538060569780), - g.FromUint64(8366525948816396307), + g.GoldilocksField(3558249639744866495), + g.GoldilocksField(2615658757916804776), + g.GoldilocksField(14375546700029059319), + g.GoldilocksField(16160052538060569780), + g.GoldilocksField(8366525948816396307), }) if exists { t.Fatalf("Expected sqrt not to exist, but it does") } + + _, exists = gFp5.Sqrt(gFp5.FromUint64(263)) // B of the curve, not a square + if exists { + t.Fatalf("Expected sqrt of -1 not to exist, but it does") + } } func TestLegendre(t *testing.T) { @@ -642,9 +683,7 @@ func TestLegendre(t *testing.T) { } legendreSym := gFp5.Legendre(x) - negOne := g.NegOne() - - if !negOne.Equal(&legendreSym) { + if legendreSym.ToCanonicalUint64() != g.ORDER-1 { t.Fatalf("Expected Legendre symbol of non-square to be -1, but got %v", legendreSym) } } @@ -655,7 +694,7 @@ func TestLegendre(t *testing.T) { square := gFp5.Square(x) legendreSym := gFp5.Legendre(square) - if !legendreSym.IsOne() { + if legendreSym.ToCanonicalUint64() != 1 { t.Fatalf("Expected Legendre symbol of square to be 1, but got %v", legendreSym) } } diff --git a/field/goldilocks/goldilocks_gnark.go b/field/goldilocks/goldilocks_gnark.go index 0f0fc33..10f950b 100644 --- a/field/goldilocks/goldilocks_gnark.go +++ b/field/goldilocks/goldilocks_gnark.go @@ -10,8 +10,6 @@ import ( type Element = g.Element -const Bytes = 8 - func NewElement(value uint64) Element { return g.NewElement(value) } @@ -39,7 +37,7 @@ func ArrayFromCanonicalLittleEndianBytes(in []byte) ([]Element, error) { } slice := make([]byte, 8) - copy(slice[:], in[i:nextStart]) + copy(slice, in[i:nextStart]) if len(slice) < 8 { slice = append(slice, make([]byte, missing)...) } @@ -88,17 +86,6 @@ func ToString(e ...Element) string { return res } -func FromBool(value bool) Element { - if value { - return One() - } - return Zero() -} - -func FromInt64Abs(value int64) Element { - return FromUint64(uint64(value & 0x7FFFFFFFFFFFFFFF)) -} - func FromInt64(value int64) Element { elem := g.NewElement(0) elem.SetInt64(value) @@ -119,10 +106,6 @@ func Equals(a, b *Element) bool { return a.Equal(b) } -func Modulus() uint64 { - return g.Modulus().Uint64() -} - func Zero() Element { return g.NewElement(0) } @@ -144,55 +127,24 @@ func NegOne() *Element { func Sample() Element { elem := g.NewElement(0) - elem.SetRandom() - return elem -} - -func RandArray(count int) []Element { - ret := make([]Element, count) - for i := 0; i < count; i++ { - ret[i] = Sample() - } - return ret -} - -func Add(elems ...Element) Element { - res := g.NewElement(0) - for _, elem := range elems { - res.Add(&res, &elem) - } - return res -} - -func Sub(a, b *Element) Element { - res := g.NewElement(0) - res.Sub(a, b) - return res -} - -func Mul(elems ...*Element) Element { - res := g.NewElement(1) - for _, elem := range elems { - res.Mul(&res, elem) + _, err := elem.SetRandom() + if err != nil { + panic(fmt.Sprintf("failed to sample random field element: %v", err)) } - return res + return elem } func Sqrt(elem *Element) *Element { - elemCopy := DeepCopy(elem) - return elemCopy.Sqrt(&elemCopy) + elemCopy := new(Element).Set(elem) + return elemCopy.Sqrt(elemCopy) } // Powers starting from 1 func Powers(e *Element, count int) []Element { ret := make([]Element, count) ret[0] = g.One() - for i := 1; i < int(count); i++ { + for i := 1; i < count; i++ { ret[i].Mul(&ret[i-1], e) } return ret } - -func DeepCopy(source *Element) Element { - return Element{source[0]} -} diff --git a/field/goldilocks/goldilocks_plonky2.go b/field/goldilocks/goldilocks_plonky2.go index a226f46..3d6b019 100644 --- a/field/goldilocks/goldilocks_plonky2.go +++ b/field/goldilocks/goldilocks_plonky2.go @@ -5,14 +5,19 @@ import ( "encoding/binary" "math/big" "math/bits" + + . "github.com/elliottech/poseidon_crypto/int" ) type GoldilocksField uint64 +const Bytes = 8 const EPSILON = uint64((1 << 32) - 1) const ORDER = uint64(0xffffffff00000001) +const TWO_ADICITY = 32 +const POWER_OF_TWO_GENERATOR = GoldilocksField(7277203076849721926) -var ORDER_BIG, _ = new(big.Int).SetString("0xffffffff00000001", 16) +var ORDER_BIG = new(big.Int).SetUint64(ORDER) func NonCannonicalGoldilocksField(x int64) GoldilocksField { if x < 0 { @@ -61,7 +66,7 @@ func AddF(lhs, rhs GoldilocksField) GoldilocksField { // Assuming lhs or rhs is in the field, i.e. x < ORDER and other in non-canonical form(u64). This assumption can be used to remove second overflow check. func AddCanonicalUint64(lhs GoldilocksField, rhs uint64) GoldilocksField { - sum, over := bits.Add64(uint64(lhs), uint64(rhs), 0) + sum, over := bits.Add64(uint64(lhs), rhs, 0) // if overflowed, sum := lhs + rhs - 2^64 => sum + EPSILON = lhs + rhs - 2^64 + 2^32 -1 = lhs + rhs - ORDER < ORDER + 2^64 - ORDER = 2^64, so there is no overflow in this case. return GoldilocksField(sum + over*EPSILON) } @@ -120,6 +125,21 @@ func ExpPowerOf2(x GoldilocksField, n uint) GoldilocksField { return z } +func ExpF(x GoldilocksField, exponent uint64) GoldilocksField { + current := x + product := OneF() + + for exponent > 0 { + if exponent&1 == 1 { + product = MulF(product, current) + } + current = SquareF(current) + exponent >>= 1 + } + + return product +} + func NegF(x GoldilocksField) GoldilocksField { z := GoldilocksField(0) if !x.IsZero() { @@ -148,27 +168,10 @@ func FromCanonicalLittleEndianBytesF(b []byte) GoldilocksField { return GoldilocksField(binary.LittleEndian.Uint64(b)) } -type UInt128 struct { - Hi, Lo uint64 -} - // NonCanonical conversion func AsUInt128(f GoldilocksField) UInt128 { u := uint64(f) - return UInt128{0, u} -} - -func AddUInt128(x, y UInt128) UInt128 { - var carry uint64 - var z UInt128 - z.Lo, carry = bits.Add64(x.Lo, y.Lo, 0) - z.Hi = x.Hi + y.Hi + carry - return z -} - -func MulUInt64(x, y uint64) UInt128 { - hi, lo := bits.Mul64(x, y) - return UInt128{hi, lo} + return UInt128{Hi: 0, Lo: u} } // Assumes x is 96-bit number @@ -195,24 +198,99 @@ func Reduce128Bit(x UInt128) GoldilocksField { return GoldilocksField(t2) } -// func (z *GoldilocksField) Inverse(x *GoldilocksField) *GoldilocksField { -// if x.IsZero() { -// z.SetZero() -// return z -// } +func SqrtF(self GoldilocksField) *GoldilocksField { + if self.IsZero() { + z := GoldilocksField(0) + return &z + } + if IsQuadraticResidueF(self) { + // reduce first + self := GoldilocksField(self.ToCanonicalUint64()) + + t := (ORDER - 1) / (1 << TWO_ADICITY) + z := POWER_OF_TWO_GENERATOR + w := ExpF(self, (t-1)/2) + x := MulF(self, w) + b := MulF(x, w) + + v := TWO_ADICITY + + for b.ToCanonicalUint64() != 1 { + k := 0 + b2k := b + for b2k.ToCanonicalUint64() != 1 { + b2k = SquareF(b2k) + k++ + } + + j := v - k - 1 + w = z + for n := int(0); n < j; n++ { + w = SquareF(w) + } + + z = SquareF(w) + b = MulF(b, z) + x = MulF(x, w) + v = k + } + + return &x + } + + return nil +} + +func IsQuadraticResidueF(x GoldilocksField) bool { + if x.IsZero() { + return true + } + + power := NegF(1).ToCanonicalUint64() >> 1 + exp := ExpF(x, power) + switch exp.ToCanonicalUint64() { + case 1: + return true + case ORDER - 1: + return false + default: + panic("unreachable") + } +} + +func (self GoldilocksField) InverseOrZero() GoldilocksField { + if self.IsZero() { + return ZeroF() + } + + // base.exp_power_of_2(N) * tail + t2 := MulF(SquareF(self), self) + t3 := MulF(SquareF(t2), self) + t6 := MulF(ExpPowerOf2(t3, 3), t3) + t12 := MulF(ExpPowerOf2(t6, 6), t6) + t24 := MulF(ExpPowerOf2(t12, 12), t12) + t30 := MulF(ExpPowerOf2(t24, 6), t6) + t31 := MulF(SquareF(t30), self) -// var tmp *GoldilocksField + t63 := MulF(ExpPowerOf2(t31, 32), t31) + + return MulF(SquareF(t63), self) +} -// t2 := *tmp.Square(x).Mul(tmp, x) -// t3 := *tmp.Square(&t2).Mul(tmp, x) -// t6 := *tmp.ExpPowerOf2(&t3, 3).Mul(tmp, &t3) -// t12 := *tmp.ExpPowerOf2(&t6, 6).Mul(tmp, &t6) -// t24 := *tmp.ExpPowerOf2(&t12, 12).Mul(tmp, &t12) -// t30 := *tmp.ExpPowerOf2(&t24, 6).Mul(tmp, &t6) -// t31 := *tmp.Square(&t30).Mul(tmp, x) -// t63 := *tmp.ExpPowerOf2(&t31, 32).Mul(tmp, &t31) +func (self GoldilocksField) Inverse() GoldilocksField { + if self.IsZero() { + panic("inverse of zero") + } -// z.Square(&t63).Mul(z, x) + return self.InverseOrZero() +} -// return z -// } +// Powers starting from 1 +func PowersF(e GoldilocksField, count int) []GoldilocksField { + ret := make([]GoldilocksField, count) + ret[0] = OneF() + for i := 1; i < count; i++ { + ret[i] = MulF(ret[i-1], e) + } + return ret +} diff --git a/field/goldilocks_quintic_extension/goldilocks_quintic_extension.go b/field/goldilocks_quintic_extension/goldilocks_quintic_extension.go index b4d7a5b..f4b2907 100644 --- a/field/goldilocks_quintic_extension/goldilocks_quintic_extension.go +++ b/field/goldilocks_quintic_extension/goldilocks_quintic_extension.go @@ -1,177 +1,150 @@ package goldilocks_quintic_extension import ( - "fmt" - "math/big" + "errors" g "github.com/elliottech/poseidon_crypto/field/goldilocks" ) -type Element [5]g.Element - -type NumericalElement [5]uint64 +type Element [5]g.GoldilocksField const Bytes = g.Bytes * 5 var ( FP5_D = 5 - FP5_ZERO = Element{g.Zero(), g.Zero(), g.Zero(), g.Zero(), g.Zero()} - FP5_ONE = Element{g.One(), g.Zero(), g.Zero(), g.Zero(), g.Zero()} - FP5_TWO = FromF(g.FromUint64(2)) + FP5_ZERO = Element{0, 0, 0, 0, 0} + FP5_ONE = Element{1, 0, 0, 0, 0} + FP5_TWO = Element{2, 0, 0, 0, 0} - FP5_W = g.FromUint64(3) - FP5_DTH_ROOT = g.FromUint64(1041288259238279555) + FP5_W = g.GoldilocksField(3) + FP5_DTH_ROOT = g.GoldilocksField(1041288259238279555) ) -func (e *Element) ToString() string { - return fmt.Sprintf("%d,%d,%d,%d,%d", e[0].Uint64(), e[1].Uint64(), e[2].Uint64(), e[3].Uint64(), e[4].Uint64()) -} - func (e Element) ToUint64Array() [5]uint64 { - return [5]uint64{e[0].Uint64(), e[1].Uint64(), e[2].Uint64(), e[3].Uint64(), e[4].Uint64()} -} - -func gFp5FromUint64Array(arr [5]uint64) Element { - return Element{g.FromUint64(arr[0]), g.FromUint64(arr[1]), g.FromUint64(arr[2]), g.FromUint64(arr[3]), g.FromUint64(arr[4])} -} - -func (e Element) ToBasefieldArray() [5]g.Element { - return [5]g.Element{e[0], e[1], e[2], e[3], e[4]} -} - -func gFp5FromBasefieldArray(arr [5]g.Element) Element { - return Element{arr[0], arr[1], arr[2], arr[3], arr[4]} + return [5]uint64{e[0].ToCanonicalUint64(), e[1].ToCanonicalUint64(), e[2].ToCanonicalUint64(), e[3].ToCanonicalUint64(), e[4].ToCanonicalUint64()} } func (e Element) ToLittleEndianBytes() []byte { - elemBytes := [Bytes]byte{} + elemBytes := make([]byte, Bytes) for i, limb := range e { - copy(elemBytes[i*g.Bytes:], g.ToLittleEndianBytes(limb)) + copy(elemBytes[i*g.Bytes:], g.ToLittleEndianBytesF(limb)) } - return elemBytes[:] + return elemBytes } func FromCanonicalLittleEndianBytes(in []byte) (Element, error) { if len(in) != Bytes { - return Element{}, fmt.Errorf("input bytes len should be 40 but is %d", len(in)) + return FP5_ZERO, errors.New("invalid input length. Expected 40 bytes") } var elem Element - for i := 0; i < 5; i++ { - e, err := g.FromCanonicalLittleEndianBytes(in[i*8 : (i+1)*8]) - if err != nil { - return Element{}, fmt.Errorf("failed to convert bytes to goldilocks: %w", err) - } - elem[i] = *e - } + elem[0] = g.FromCanonicalLittleEndianBytesF(in[0:8]) + elem[1] = g.FromCanonicalLittleEndianBytesF(in[8:16]) + elem[2] = g.FromCanonicalLittleEndianBytesF(in[16:24]) + elem[3] = g.FromCanonicalLittleEndianBytesF(in[24:32]) + elem[4] = g.FromCanonicalLittleEndianBytesF(in[32:40]) return elem, nil } func Sample() Element { - arr := g.RandArray(5) - return Element{arr[0], arr[1], arr[2], arr[3], arr[4]} + return Element{g.SampleF(), g.SampleF(), g.SampleF(), g.SampleF(), g.SampleF()} } func Equals(a, b Element) bool { - return a[0] == b[0] && a[1] == b[1] && a[2] == b[2] && a[3] == b[3] && a[4] == b[4] + return a[0].ToCanonicalUint64() == b[0].ToCanonicalUint64() && + a[1].ToCanonicalUint64() == b[1].ToCanonicalUint64() && + a[2].ToCanonicalUint64() == b[2].ToCanonicalUint64() && + a[3].ToCanonicalUint64() == b[3].ToCanonicalUint64() && + a[4].ToCanonicalUint64() == b[4].ToCanonicalUint64() } func IsZero(e Element) bool { return e[0].IsZero() && e[1].IsZero() && e[2].IsZero() && e[3].IsZero() && e[4].IsZero() } -func FromF(elem g.Element) Element { - return Element{elem, g.Zero(), g.Zero(), g.Zero(), g.Zero()} +func FromF(elem g.GoldilocksField) Element { + return Element{elem, 0, 0, 0, 0} } func FromUint64(a uint64) Element { - return Element{g.FromUint64(a), g.Zero(), g.Zero(), g.Zero(), g.Zero()} -} - -func FromUint64Array(elems [5]uint64) Element { - return Element{ - g.FromUint64(elems[0]), - g.FromUint64(elems[1]), - g.FromUint64(elems[2]), - g.FromUint64(elems[3]), - g.FromUint64(elems[4]), - } + return Element{g.GoldilocksField(a), 0, 0, 0, 0} } func Neg(e Element) Element { - return Element{g.Neg(e[0]), g.Neg(e[1]), g.Neg(e[2]), g.Neg(e[3]), g.Neg(e[4])} + return Element{g.NegF(e[0]), g.NegF(e[1]), g.NegF(e[2]), g.NegF(e[3]), g.NegF(e[4])} } func Add(a, b Element) Element { return Element{ - g.Add(a[0], b[0]), - g.Add(a[1], b[1]), - g.Add(a[2], b[2]), - g.Add(a[3], b[3]), - g.Add(a[4], b[4]), + g.AddF(a[0], b[0]), + g.AddF(a[1], b[1]), + g.AddF(a[2], b[2]), + g.AddF(a[3], b[3]), + g.AddF(a[4], b[4]), } } func Sub(a, b Element) Element { return Element{ - g.Sub(&a[0], &b[0]), - g.Sub(&a[1], &b[1]), - g.Sub(&a[2], &b[2]), - g.Sub(&a[3], &b[3]), - g.Sub(&a[4], &b[4]), + g.SubF(a[0], b[0]), + g.SubF(a[1], b[1]), + g.SubF(a[2], b[2]), + g.SubF(a[3], b[3]), + g.SubF(a[4], b[4]), } } func Mul(a, b Element) Element { w := FP5_W - a0b0 := g.Mul(&a[0], &b[0]) - a1b4 := g.Mul(&a[1], &b[4]) - a2b3 := g.Mul(&a[2], &b[3]) - a3b2 := g.Mul(&a[3], &b[2]) - a4b1 := g.Mul(&a[4], &b[1]) - added := g.Add(a1b4, a2b3, a3b2, a4b1) - muld := g.Mul(&w, &added) - c0 := g.Add(a0b0, muld) - - a0b1 := g.Mul(&a[0], &b[1]) - a1b0 := g.Mul(&a[1], &b[0]) - a2b4 := g.Mul(&a[2], &b[4]) - a3b3 := g.Mul(&a[3], &b[3]) - a4b2 := g.Mul(&a[4], &b[2]) - added = g.Add(a2b4, a3b3, a4b2) - muld = g.Mul(&w, &added) - c1 := g.Add(a0b1, a1b0, muld) - - a0b2 := g.Mul(&a[0], &b[2]) - a1b1 := g.Mul(&a[1], &b[1]) - a2b0 := g.Mul(&a[2], &b[0]) - a3b4 := g.Mul(&a[3], &b[4]) - a4b3 := g.Mul(&a[4], &b[3]) - added = g.Add(a3b4, a4b3) - muld = g.Mul(&w, &added) - c2 := g.Add(a0b2, a1b1, a2b0, muld) - - a0b3 := g.Mul(&a[0], &b[3]) - a1b2 := g.Mul(&a[1], &b[2]) - a2b1 := g.Mul(&a[2], &b[1]) - a3b0 := g.Mul(&a[3], &b[0]) - a4b4 := g.Mul(&a[4], &b[4]) - muld = g.Mul(&w, &a4b4) - c3 := g.Add(a0b3, a1b2, a2b1, a3b0, muld) - - a0b4 := g.Mul(&a[0], &b[4]) - a1b3 := g.Mul(&a[1], &b[3]) - a2b2 := g.Mul(&a[2], &b[2]) - a3b1 := g.Mul(&a[3], &b[1]) - a4b0 := g.Mul(&a[4], &b[0]) - c4 := g.Add(a0b4, a1b3, a2b2, a3b1, a4b0) + a0b0 := g.MulF(a[0], b[0]) + a1b4 := g.MulF(a[1], b[4]) + a2b3 := g.MulF(a[2], b[3]) + a3b2 := g.MulF(a[3], b[2]) + a4b1 := g.MulF(a[4], b[1]) + added := g.AddF(g.AddF(a1b4, a2b3), g.AddF(a3b2, a4b1)) + muld := g.MulF(w, added) + c0 := g.AddF(a0b0, muld) + + a0b1 := g.MulF(a[0], b[1]) + a1b0 := g.MulF(a[1], b[0]) + a2b4 := g.MulF(a[2], b[4]) + a3b3 := g.MulF(a[3], b[3]) + a4b2 := g.MulF(a[4], b[2]) + added = g.AddF(g.AddF(a2b4, a3b3), a4b2) + muld = g.MulF(w, added) + c1 := g.AddF(g.AddF(a0b1, a1b0), muld) + + a0b2 := g.MulF(a[0], b[2]) + a1b1 := g.MulF(a[1], b[1]) + a2b0 := g.MulF(a[2], b[0]) + a3b4 := g.MulF(a[3], b[4]) + a4b3 := g.MulF(a[4], b[3]) + added = g.AddF(a3b4, a4b3) + muld = g.MulF(w, added) + c2 := g.AddF(g.AddF(a0b2, a1b1), g.AddF(a2b0, muld)) + + a0b3 := g.MulF(a[0], b[3]) + a1b2 := g.MulF(a[1], b[2]) + a2b1 := g.MulF(a[2], b[1]) + a3b0 := g.MulF(a[3], b[0]) + a4b4 := g.MulF(a[4], b[4]) + muld = g.MulF(w, a4b4) + c3 := g.AddF(g.AddF(g.AddF(a0b3, a1b2), g.AddF(a2b1, a3b0)), muld) + + a0b4 := g.MulF(a[0], b[4]) + a1b3 := g.MulF(a[1], b[3]) + a2b2 := g.MulF(a[2], b[2]) + a3b1 := g.MulF(a[3], b[1]) + a4b0 := g.MulF(a[4], b[0]) + c4 := g.AddF(g.AddF(g.AddF(a0b4, a1b3), g.AddF(a2b2, a3b1)), a4b0) return Element{c0, c1, c2, c3, c4} } +// Returns a / b. Panics if b == 0. func Div(a, b Element) Element { bInv := InverseOrZero(b) if IsZero(bInv) { @@ -180,6 +153,7 @@ func Div(a, b Element) Element { return Mul(a, bInv) } +// x^(2^power) func ExpPowerOf2(x Element, power int) Element { res := Element{x[0], x[1], x[2], x[3], x[4]} for i := 0; i < power; i++ { @@ -190,69 +164,70 @@ func ExpPowerOf2(x Element, power int) Element { func Square(a Element) Element { w := FP5_W - double_w := g.Add(w, w) - - a0s := g.Mul(&a[0], &a[0]) - a1a4 := g.Mul(&a[1], &a[4]) - a2a3 := g.Mul(&a[2], &a[3]) - added := g.Add(a1a4, a2a3) - muld := g.Mul(&double_w, &added) - c0 := g.Add(a0s, muld) - - a0Double := g.Add(a[0], a[0]) - a0Doublea1 := g.Mul(&a0Double, &a[1]) - a2a4DoubleW := g.Mul(&a[2], &a[4], &double_w) - a3a3w := g.Mul(&a[3], &a[3], &w) - c1 := g.Add(a0Doublea1, a2a4DoubleW, a3a3w) - - a0Doublea2 := g.Mul(&a0Double, &a[2]) - a1Square := g.Mul(&a[1], &a[1]) - a4a3DoubleW := g.Mul(&a[4], &a[3], &double_w) - c2 := g.Add(a0Doublea2, a1Square, a4a3DoubleW) - - a1Double := g.Add(a[1], a[1]) - a0Doublea3 := g.Mul(&a0Double, &a[3]) - a1Doublea2 := g.Mul(&a1Double, &a[2]) - a4SquareW := g.Mul(&a[4], &a[4], &w) - c3 := g.Add(a0Doublea3, a1Doublea2, a4SquareW) - - a0Doublea4 := g.Mul(&a0Double, &a[4]) - a1Doublea3 := g.Mul(&a1Double, &a[3]) - a2Square := g.Mul(&a[2], &a[2]) - c4 := g.Add(a0Doublea4, a1Doublea3, a2Square) + double_w := g.AddF(w, w) + + a0s := g.MulF(a[0], a[0]) + a1a4 := g.MulF(a[1], a[4]) + a2a3 := g.MulF(a[2], a[3]) + added := g.AddF(a1a4, a2a3) + muld := g.MulF(double_w, added) + c0 := g.AddF(a0s, muld) + + a0Double := g.AddF(a[0], a[0]) + a0Doublea1 := g.MulF(a0Double, a[1]) + a2a4DoubleW := g.MulF(g.MulF(a[2], a[4]), double_w) + a3a3w := g.MulF(g.MulF(a[3], a[3]), w) + c1 := g.AddF(g.AddF(a0Doublea1, a2a4DoubleW), a3a3w) + + a0Doublea2 := g.MulF(a0Double, a[2]) + a1Square := g.MulF(a[1], a[1]) + a4a3DoubleW := g.MulF(g.MulF(a[4], a[3]), double_w) + c2 := g.AddF(g.AddF(a0Doublea2, a1Square), a4a3DoubleW) + + a1Double := g.AddF(a[1], a[1]) + a0Doublea3 := g.MulF(a0Double, a[3]) + a1Doublea2 := g.MulF(a1Double, a[2]) + a4SquareW := g.MulF(g.MulF(a[4], a[4]), w) + c3 := g.AddF(g.AddF(a0Doublea3, a1Doublea2), a4SquareW) + + a0Doublea4 := g.MulF(a0Double, a[4]) + a1Doublea3 := g.MulF(a1Double, a[3]) + a2Square := g.MulF(a[2], a[2]) + c4 := g.AddF(g.AddF(a0Doublea4, a1Doublea3), a2Square) return Element{c0, c1, c2, c3, c4} } func Triple(a Element) Element { - three := g.FromUint64(3) + three := g.GoldilocksField(3) return Element{ - g.Mul(&a[0], &three), - g.Mul(&a[1], &three), - g.Mul(&a[2], &three), - g.Mul(&a[3], &three), - g.Mul(&a[4], &three), + g.MulF(a[0], three), + g.MulF(a[1], three), + g.MulF(a[2], three), + g.MulF(a[3], three), + g.MulF(a[4], three), } } func Sqrt(x Element) (Element, bool) { + three := g.GoldilocksField(3) + v := ExpPowerOf2(x, 31) d := Mul(Mul(x, ExpPowerOf2(v, 32)), InverseOrZero(v)) e := Frobenius(Mul(d, RepeatedFrobenius(d, 2))) _f := Square(e) - x1f4 := g.Mul(&x[1], &_f[4]) - x2f3 := g.Mul(&x[2], &_f[3]) - x3f2 := g.Mul(&x[3], &_f[2]) - x4f1 := g.Mul(&x[4], &_f[1]) - added := g.Add(x1f4, x2f3, x3f2, x4f1) - three := g.FromUint64(3) - muld := g.Mul(&three, &added) - x0f0 := g.Mul(&x[0], &_f[0]) - _g := g.Add(x0f0, muld) - s := g.Sqrt(&_g) + x1f4 := g.MulF(x[1], _f[4]) + x2f3 := g.MulF(x[2], _f[3]) + x3f2 := g.MulF(x[3], _f[2]) + x4f1 := g.MulF(x[4], _f[1]) + added := g.AddF(g.AddF(x1f4, x2f3), g.AddF(x3f2, x4f1)) + muld := g.MulF(three, added) + x0f0 := g.MulF(x[0], _f[0]) + _g := g.AddF(x0f0, muld) + s := g.SqrtF(_g) if s == nil { - return Element{}, false + return FP5_ZERO, false } eInv := InverseOrZero(e) @@ -265,7 +240,7 @@ func Sgn0(x Element) bool { sign := false zero := true for _, limb := range x { - sign_i := (limb.Uint64() & 1) == 0 + sign_i := (limb.ToCanonicalUint64() & 1) == 0 zero_i := limb.IsZero() sign = sign || (zero && sign_i) zero = zero && zero_i @@ -276,7 +251,7 @@ func Sgn0(x Element) bool { func CanonicalSqrt(x Element) (Element, bool) { sqrtX, exists := Sqrt(x) if !exists { - return Element{}, false + return FP5_ZERO, false } if Sgn0(sqrtX) { @@ -285,13 +260,13 @@ func CanonicalSqrt(x Element) (Element, bool) { return sqrtX, true } -func ScalarMul(a Element, scalar g.Element) Element { +func ScalarMul(a Element, scalar g.GoldilocksField) Element { return Element{ - g.Mul(&a[0], &scalar), - g.Mul(&a[1], &scalar), - g.Mul(&a[2], &scalar), - g.Mul(&a[3], &scalar), - g.Mul(&a[4], &scalar), + g.MulF(a[0], scalar), + g.MulF(a[1], scalar), + g.MulF(a[2], scalar), + g.MulF(a[3], scalar), + g.MulF(a[4], scalar), } } @@ -308,16 +283,16 @@ func InverseOrZero(a Element) Element { e := Mul(d, Frobenius(d)) f := Mul(e, RepeatedFrobenius(e, 2)) - a0b0 := g.Mul(&a[0], &f[0]) - a1b4 := g.Mul(&a[1], &f[4]) - a2b3 := g.Mul(&a[2], &f[3]) - a3b2 := g.Mul(&a[3], &f[2]) - a4b1 := g.Mul(&a[4], &f[1]) - added := g.Add(a1b4, a2b3, a3b2, a4b1) - muld := g.Mul(&FP5_W, &added) - g := g.Add(a0b0, muld) + a0b0 := g.MulF(a[0], f[0]) + a1b4 := g.MulF(a[1], f[4]) + a2b3 := g.MulF(a[2], f[3]) + a3b2 := g.MulF(a[3], f[2]) + a4b1 := g.MulF(a[4], f[1]) + added := g.AddF(g.AddF(a1b4, a2b3), g.AddF(a3b2, a4b1)) + muld := g.MulF(FP5_W, added) + gg := g.AddF(a0b0, muld) - return ScalarMul(f, *g.Inverse(&g)) + return ScalarMul(f, gg.Inverse()) } func Frobenius(x Element) Element { @@ -333,17 +308,17 @@ func RepeatedFrobenius(x Element, count int) Element { z0 := FP5_DTH_ROOT for i := 1; i < count; i++ { - z0 = g.Mul(&FP5_DTH_ROOT, &z0) + z0 = g.MulF(FP5_DTH_ROOT, z0) } res := Element{} - for i, z := range g.Powers(&z0, FP5_D) { - res[i] = g.Mul(&x[i], &z) + for i, z := range g.PowersF(z0, FP5_D) { + res[i] = g.MulF(x[i], z) } return res } -func Legendre(x Element) g.Element { +func Legendre(x Element) g.GoldilocksField { frob1 := Frobenius(x) frob2 := Frobenius(frob1) @@ -351,23 +326,32 @@ func Legendre(x Element) g.Element { frob2Frob1TimesFrob2 := RepeatedFrobenius(frob1TimesFrob2, 2) xrExt := Mul(Mul(x, frob1TimesFrob2), frob2Frob1TimesFrob2) - xr := g.FromUint64(xrExt[0].Uint64()) + xr := xrExt[0] - xr31 := xr.Exp(xr, new(big.Int).SetUint64(1<<31)) - xr31InvOrZero := g.FromUint64(0) - xr31InvOrZero = *xr31InvOrZero.Inverse(xr31) + xr31 := g.ExpPowerOf2(xr, 31) + xr31InvOrZero := xr31.InverseOrZero() - xr63 := xr31.Exp(*xr31, new(big.Int).SetUint64(1<<32)) + xr63 := g.ExpPowerOf2(xr31, 32) - return g.Mul(xr63, &xr31InvOrZero) + return g.MulF(xr63, xr31InvOrZero) } func FromPlonky2GoldilocksField(f []g.GoldilocksField) Element { return Element{ - g.NewElement(uint64(f[0])), - g.NewElement(uint64(f[1])), - g.NewElement(uint64(f[2])), - g.NewElement(uint64(f[3])), - g.NewElement(uint64(f[4])), + f[0], + f[1], + f[2], + f[3], + f[4], + } +} + +func FromGnarkGoldilocksField(f []g.Element) Element { + return Element{ + g.GoldilocksField(f[0].Uint64()), + g.GoldilocksField(f[1].Uint64()), + g.GoldilocksField(f[2].Uint64()), + g.GoldilocksField(f[3].Uint64()), + g.GoldilocksField(f[4].Uint64()), } } diff --git a/go.mod b/go.mod index e17e2a2..a7a561a 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,6 @@ module github.com/elliottech/poseidon_crypto -go 1.22 +go 1.23 require ( github.com/consensys/gnark-crypto v0.12.2-0.20240215234832-d72fcb379d3e diff --git a/hash/poseidon2_goldilocks/poseidon2.go b/hash/poseidon2_goldilocks/poseidon2.go index 78eadfa..5343464 100644 --- a/hash/poseidon2_goldilocks/poseidon2.go +++ b/hash/poseidon2_goldilocks/poseidon2.go @@ -10,8 +10,6 @@ import ( type HashOut [4]g.Element -type NumericalHashOut [4]uint64 - func (h HashOut) ToLittleEndianBytes() []byte { return g.ArrayToLittleEndianBytes([]g.Element{h[0], h[1], h[2], h[3]}) } @@ -21,8 +19,7 @@ func (h HashOut) ToUint64Array() [4]uint64 { } func HashToQuinticExtension(m []g.Element) gFp5.Element { - res := HashNToMNoPad(m, 5) - return gFp5.Element(res[:]) + return gFp5.FromGnarkGoldilocksField(HashNToMNoPad(m, 5)) } func HashOutFromUint64Array(arr [4]uint64) HashOut { diff --git a/hash/poseidon2_goldilocks/poseidon2_test.go b/hash/poseidon2_goldilocks/poseidon2_test.go index 643dda1..6543ae7 100644 --- a/hash/poseidon2_goldilocks/poseidon2_test.go +++ b/hash/poseidon2_goldilocks/poseidon2_test.go @@ -271,7 +271,7 @@ func TestHashToQuinticExtension(t *testing.T) { 14449776097783372302, } for i := 0; i < 5; i++ { - if result[i] != g.FromUint64(expected[i]) { + if result[i].ToCanonicalUint64() != expected[i] { t.Logf("Expected limb %d to be %x, but got %x", i, expected[i], result[i]) t.Fail() } diff --git a/hash/poseidon2_goldilocks_plonky2/poseidon2.go b/hash/poseidon2_goldilocks_plonky2/poseidon2.go index fa11dc5..33302a9 100644 --- a/hash/poseidon2_goldilocks_plonky2/poseidon2.go +++ b/hash/poseidon2_goldilocks_plonky2/poseidon2.go @@ -6,10 +6,10 @@ import ( g "github.com/elliottech/poseidon_crypto/field/goldilocks" gFp5 "github.com/elliottech/poseidon_crypto/field/goldilocks_quintic_extension" + . "github.com/elliottech/poseidon_crypto/int" ) type HashOut [4]g.GoldilocksField -type NumericalHashOut [4]uint64 func EmptyHashOut() HashOut { return HashOut{g.ZeroF(), g.ZeroF(), g.ZeroF(), g.ZeroF()} @@ -44,8 +44,7 @@ func HashOutFromUint64Array(arr [4]uint64) HashOut { } func HashToQuinticExtension(m []g.GoldilocksField) gFp5.Element { - res := HashNToMNoPad(m, 5) - return gFp5.FromPlonky2GoldilocksField(res[:]) + return gFp5.FromPlonky2GoldilocksField(HashNToMNoPad(m, 5)) } type Poseidon2 struct{} @@ -149,7 +148,7 @@ func partialRounds(state *[WIDTH]g.GoldilocksField) { } func externalLinearLayer(s *[WIDTH]g.GoldilocksField) { - s128 := [WIDTH]g.UInt128{} + s128 := [WIDTH]UInt128{} for i := 0; i < WIDTH; i++ { s128[i] = g.AsUInt128(s[i]) } @@ -161,44 +160,44 @@ func externalLinearLayer(s *[WIDTH]g.GoldilocksField) { } } -func externalLinearLayer128(s *[WIDTH]g.UInt128) { +func externalLinearLayer128(s *[WIDTH]UInt128) { for i := 0; i < WIDTH; i += 4 { - t01 := g.AddUInt128(s[i], s[i+1]) - t23 := g.AddUInt128(s[i+2], s[i+3]) - t0123 := g.AddUInt128(t01, t23) + t01 := AddUInt128(s[i], s[i+1]) + t23 := AddUInt128(s[i+2], s[i+3]) + t0123 := AddUInt128(t01, t23) x0 := s[i] x2 := s[i+2] - s[i] = g.AddUInt128(g.AddUInt128(t0123, t01), s[i+1]) - s[i+1] = g.AddUInt128(g.AddUInt128(g.AddUInt128(t0123, s[i+1]), x2), x2) - s[i+2] = g.AddUInt128(g.AddUInt128(t0123, t23), s[i+3]) - s[i+3] = g.AddUInt128(g.AddUInt128(g.AddUInt128(t0123, s[i+3]), x0), x0) + s[i] = AddUInt128(AddUInt128(t0123, t01), s[i+1]) + s[i+1] = AddUInt128(AddUInt128(AddUInt128(t0123, s[i+1]), x2), x2) + s[i+2] = AddUInt128(AddUInt128(t0123, t23), s[i+3]) + s[i+3] = AddUInt128(AddUInt128(AddUInt128(t0123, s[i+3]), x0), x0) } - sums := [4]g.UInt128{} + sums := [4]UInt128{} for i := 0; i < 4; i++ { - sums[i] = g.AddUInt128(g.AddUInt128(s[i], s[i+4]), s[i+8]) + sums[i] = AddUInt128(AddUInt128(s[i], s[i+4]), s[i+8]) } for i := 0; i < WIDTH; i++ { - s[i] = g.AddUInt128(s[i], sums[i%4]) + s[i] = AddUInt128(s[i], sums[i%4]) } } func internalLinearLayer(state *[WIDTH]g.GoldilocksField) { sum := g.AsUInt128(state[0]) - sum = g.AddUInt128(sum, g.AsUInt128(state[1])) - sum = g.AddUInt128(sum, g.AsUInt128(state[2])) - sum = g.AddUInt128(sum, g.AsUInt128(state[3])) - sum = g.AddUInt128(sum, g.AsUInt128(state[4])) - sum = g.AddUInt128(sum, g.AsUInt128(state[5])) - sum = g.AddUInt128(sum, g.AsUInt128(state[6])) - sum = g.AddUInt128(sum, g.AsUInt128(state[7])) - sum = g.AddUInt128(sum, g.AsUInt128(state[8])) - sum = g.AddUInt128(sum, g.AsUInt128(state[9])) - sum = g.AddUInt128(sum, g.AsUInt128(state[10])) - sum = g.AddUInt128(sum, g.AsUInt128(state[11])) + sum = AddUInt128(sum, g.AsUInt128(state[1])) + sum = AddUInt128(sum, g.AsUInt128(state[2])) + sum = AddUInt128(sum, g.AsUInt128(state[3])) + sum = AddUInt128(sum, g.AsUInt128(state[4])) + sum = AddUInt128(sum, g.AsUInt128(state[5])) + sum = AddUInt128(sum, g.AsUInt128(state[6])) + sum = AddUInt128(sum, g.AsUInt128(state[7])) + sum = AddUInt128(sum, g.AsUInt128(state[8])) + sum = AddUInt128(sum, g.AsUInt128(state[9])) + sum = AddUInt128(sum, g.AsUInt128(state[10])) + sum = AddUInt128(sum, g.AsUInt128(state[11])) sumF := g.Reduce96Bit(sum) state[0] = g.MulAccF(sumF, state[0], MATRIX_DIAG_12_U64[0]) diff --git a/hash/poseidon2_goldilocks_plonky2/poseidon2_test.go b/hash/poseidon2_goldilocks_plonky2/poseidon2_test.go index ad4bfbc..6da36f9 100644 --- a/hash/poseidon2_goldilocks_plonky2/poseidon2_test.go +++ b/hash/poseidon2_goldilocks_plonky2/poseidon2_test.go @@ -277,7 +277,7 @@ func TestHashToQuinticExtension(t *testing.T) { 14449776097783372302, } for i := 0; i < 5; i++ { - if result[i] != g.FromUint64(expected[i]) { + if result[i].ToCanonicalUint64() != expected[i] { t.Logf("Expected limb %d to be %x, but got %x", i, expected[i], result[i]) t.Fail() } diff --git a/hash/poseidon2_test.go b/hash/poseidon2_test.go index d0ab681..9fe85c6 100644 --- a/hash/poseidon2_test.go +++ b/hash/poseidon2_test.go @@ -29,7 +29,7 @@ func TestLongRunningCompare(t *testing.T) { for j := 0; j < 1_000_000_000; j++ { inputs := make([]uint64, 12) for i := 0; i < 12; i++ { - inputs[i] = rand.Uint64N(g.ORDER) + inputs[i] = rand.Uint64N(g.ORDER) //nolint:gosec } // Convert to GoldilocksField diff --git a/int/int_test.go b/int/int_test.go new file mode 100644 index 0000000..3b1c627 --- /dev/null +++ b/int/int_test.go @@ -0,0 +1,20 @@ +package int + +import "testing" + +func TestRecodeSigned5_161(t *testing.T) { + scalar1 := Signed161{ + 0x1234567890abcdef, + 0xfedcba0987654321, + 0x0fedcba987654321, + } + + expectedValues := [33]int32{ + 15, 15, -13, -8, 11, 8, 2, 15, -10, 3, 13, 4, -15, -15, 13, 8, 5, -5, 2, -13, 1, -3, -13, -4, -1, 16, 8, 6, -12, -13, -2, -15, 0, + } + for i, elem := range RecodeSigned5(scalar1) { + if elem != expectedValues[i] { + t.Fatalf("Expected ss[%d] to be %d, but got %d", i, expectedValues[i], elem) + } + } +} diff --git a/int/signed161.go b/int/signed161.go new file mode 100644 index 0000000..0cd83c0 --- /dev/null +++ b/int/signed161.go @@ -0,0 +1,64 @@ +package int + +// A custom 161-bit integer type; used for splitting a scalar into a +// fraction. Negative values use two's complement notation; the value +// is truncated to 161 bits (upper bits in the top limb are ignored). +// Elements are mutable containers. +// WARNING: everything in here is vartime; do not use on secret values. +type Signed161 [3]uint64 + +// Export this value as a 192-bit integer (three 64-bit limbs, in little-endian order). +func (s Signed161) ToU192() [3]uint64 { + x := s[2] & 0x00000001FFFFFFFF + x |= (^(x >> 32) + 1) << 33 + return [3]uint64{s[0], s[1], x} +} + +// Recode this integer into 33 signed digits for a 5-bit window. +func RecodeSigned5(s Signed161) [33]int32 { + // We first sign-extend the value to 192 bits, then add + // 2^160 to get a nonnegative value in the 0 to 2^161-1 + // range. We then recode that value; and finally we fix + // the result by subtracting 1 from the top digit. + tmp := s.ToU192() + tmp[2] += 0x0000000100000000 + var ss [33]int32 + RecodeSignedFromLimbs(tmp[:], ss[:], 5) + ss[32] -= 1 + return ss +} + +func RecodeSignedFromLimbs(limbs []uint64, ss []int32, w int32) { + var acc uint64 = 0 + var accLen int32 = 0 + var j int = 0 + mw := (uint32(1) << w) - 1 + hw := uint32(1) << (w - 1) + var cc uint32 = 0 + for i := 0; i < len(ss); i++ { + // Get next w-bit chunk in bb. + var bb uint32 + if accLen < w { + if j < len(limbs) { + nl := limbs[j] + j++ + bb = (uint32(acc | (nl << accLen))) & mw //nolint:gosec + acc = nl >> (w - accLen) + } else { + bb = uint32(acc) & mw //nolint:gosec + acc = 0 + } + accLen += 64 - w + } else { + bb = uint32(acc) & mw //nolint:gosec + accLen -= w + acc >>= w + } + + // If bb is greater than 2^(w-1), subtract 2^w and propagate a carry. + bb += cc + + cc = (hw - bb) >> 31 + ss[i] = int32(bb) - int32(cc<