Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
113 changes: 113 additions & 0 deletions curve/ecgfp5/point.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package ecgfp5

import (
"fmt"

g "github.com/elliottech/poseidon_crypto/field/goldilocks"
gFp5 "github.com/elliottech/poseidon_crypto/field/goldilocks_quintic_extension"
)
Expand Down Expand Up @@ -65,6 +67,73 @@ var (
u: gFp5.FP5_ONE,
t: gFp5.Element{4, 0, 0, 0, 0},
}

GeneratorWindowAffine = []AffinePoint{
{
x: gFp5.Element{12883135586176881569, 4356519642755055268, 5248930565894896907, 2165973894480315022, 2448410071095648785},
u: gFp5.Element{13835058052060938241, 18446744069414584321, 18446744069414584321, 18446744069414584321, 18446744069414584321},
},
{
x: gFp5.Element{16517537419581740386, 6962630169123120981, 12147752690379666704, 16637325971742264607, 2335078582315237010},
u: gFp5.Element{8457587110646932172, 138591869800252458, 3187444967472352324, 18179149801168653736, 9453003655195557048},
},
{
x: gFp5.Element{4546139357324501584, 1393728687664685160, 15208040286522119521, 7903224051455420834, 12463930627278381774},
u: gFp5.Element{16373828487211693378, 5899455736915524900, 17616512450102495476, 17643201028570366669, 2833280130550676525},
},
{
x: gFp5.Element{4341836049185169731, 9111482874850194930, 7798994609726992878, 12619124383509403661, 13047834166950680886},
u: gFp5.Element{3584786391427904733, 1717626083626375072, 16549008311909030594, 17550175197111849143, 18374971670674568416},
},
{
x: gFp5.Element{18121072711119258927, 3394315639035318724, 2648370499809919556, 13348924736921714137, 3428166646246873447},
u: gFp5.Element{9264305576790077869, 7426254234280836405, 5107777768036114824, 9390769538758625122, 9788182195111344062},
},
{
x: gFp5.Element{11080635543643017332, 3122290570793204485, 16632474826839786439, 14883711538614796285, 10396852362099782295},
u: gFp5.Element{14253916706639980511, 15728038457561632290, 3947138785484546318, 4740958322851071718, 17384736114265519442},
},
{
x: gFp5.Element{4763058716218401568, 17879823368956058516, 13578954599286698938, 8634670560943921567, 13706660844700767685},
u: gFp5.Element{3354778288360932917, 13842278303693121409, 4717821645259836467, 7978743897613094276, 10118963888992569394},
},
{
x: gFp5.Element{4026958896735257282, 13595990041314210204, 11499471878438064392, 10019455879458851233, 11986847968355927330},
u: gFp5.Element{14532821659997761913, 9582789969382797985, 3082219099923033594, 2859656980617778370, 3746047816071136016},
},
{
x: gFp5.Element{15935900828168308224, 8668680449802005535, 491315506768012688, 6584881037682113026, 12386385009372860460},
u: gFp5.Element{13217832923050551864, 51671271962049328, 15400792709153778477, 6752203529649104660, 2855313280735340066},
},
{
x: gFp5.Element{8473506523195244465, 2446964921175324878, 17962771942831363202, 6949608686158330138, 9315492999547366751},
u: gFp5.Element{5171814696081600409, 3025466154945175207, 453302446979841822, 14135305892339872079, 2556388051049291052},
},
{
x: gFp5.Element{3960231187580500028, 3695840168764199059, 2914577777792670911, 9249939676680902688, 17553522813502241416},
u: gFp5.Element{3015152305907361949, 10730034543155667220, 3314242046485170944, 1984395553885795852, 13781645774758249860},
},
{
x: gFp5.Element{11575997426281090678, 1534495174840625570, 7539338128385981583, 10393042019577161985, 10667466219175771157},
u: gFp5.Element{16681365912970185037, 11287896019745355117, 11069899752345274504, 15487604769605237513, 13467978440572613228},
},
{
x: gFp5.Element{11192179397773394280, 3555953455665397909, 5346523552109387121, 4514445299325204396, 3932728981135688453},
u: gFp5.Element{5421638117266109845, 204299445119713184, 6067390115784997081, 16191134954342419157, 4139938600224417293},
},
{
x: gFp5.Element{13189785832536261642, 8777097377506996162, 17497140949916325738, 15140279769427597032, 15517274717131999881},
u: gFp5.Element{1040464435413162742, 9262701069034606854, 2990438819650713743, 18129195737333990255, 12490074042478236606},
},
{
x: gFp5.Element{17716508479149156535, 14351380558651795729, 3644546258883003807, 5171318241596472386, 294806796132518330},
u: gFp5.Element{7535225611936271281, 14682077054502188499, 784215514926156349, 5280586574139275596, 14407528916988559545},
},
{
x: gFp5.Element{8681294642569802563, 7751765660802747503, 16382129702876313971, 7447155060842833278, 6859908403876474879},
u: gFp5.Element{9674486254207846385, 5248970165164951259, 3611784478790504991, 18437168019170350173, 3537959913875671086},
},
}
)

func (p ECgFp5Point) Equals(rhs ECgFp5Point) bool {
Expand Down Expand Up @@ -435,6 +504,26 @@ func BatchToAffine(src []ECgFp5Point) []AffinePoint {
return res
}

// To pre-compute G, 2G, 3G...15G
func GenerateG() {
p := GENERATOR_ECgFp5Point
tmp := make([]ECgFp5Point, WIN_SIZE)
tmp[0] = p
for i := 1; i < WIN_SIZE; i++ {
if (i & 1) == 0 {
tmp[i] = tmp[i-1].Add(p)
} else {
tmp[i] = tmp[i>>1].Double()
}
}
res := BatchToAffine(tmp)
for i := 0; i < 16; i++ {
elx := fmt.Sprintf("gFp5.Element{%d, %d, %d, %d, %d}", res[i].x[0], res[i].x[1], res[i].x[2], res[i].x[3], res[i].x[4])
elu := fmt.Sprintf("gFp5.Element{%d, %d, %d, %d, %d}", res[i].u[0], res[i].u[1], res[i].u[2], res[i].u[3], res[i].u[4])
fmt.Printf("AffinePoint{\n x : %s,\n u : %s,\n},\n", elx, elu)
}
}

func (p ECgFp5Point) MakeWindowAffine() []AffinePoint {
tmp := make([]ECgFp5Point, WIN_SIZE)
tmp[0] = p
Expand Down Expand Up @@ -466,3 +555,27 @@ func (r ECgFp5Point) Mul(s ECgFp5Scalar) ECgFp5Point {

return p
}

// Returns G*scalarA + b*scalarB
func MulAddG(b ECgFp5Point, scalarA, scalarB ECgFp5Scalar) ECgFp5Point {
winA := GeneratorWindowAffine
winB := b.MakeWindowAffine()

digitsA := make([]int32, (319+WINDOW)/WINDOW)
scalarA.RecodeSigned(digitsA, int32(WINDOW))
digitsB := make([]int32, (319+WINDOW)/WINDOW)
scalarB.RecodeSigned(digitsB, int32(WINDOW))

n := len(digitsA) // == len(digitsB)

// Top window digit of each scalar, combined into the running point.
p := LookupVarTime(winA, digitsA[n-1]).ToPoint()
p = p.AddAffine(LookupVarTime(winB, digitsB[n-1]))

for i := n - 2; i >= 0; i-- {
p.SetMDouble(uint32(WINDOW)) // ×2^WINDOW, shared by both scalars
p = p.AddAffine(LookupVarTime(winA, digitsA[i]))
p = p.AddAffine(LookupVarTime(winB, digitsB[i]))
}
return p
}
231 changes: 154 additions & 77 deletions field/goldilocks_quintic_extension/goldilocks_quintic_extension.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package goldilocks_quintic_extension

import (
"errors"
"math/bits"

g "github.com/elliottech/poseidon_crypto/field/goldilocks"
)
Expand Down Expand Up @@ -96,52 +97,103 @@ func Sub(a, b Element) Element {
}
}

// reduce128 reduces hi*2^64 + lo modulo the Goldilocks prime.
func reduce128(lo, hi uint64) uint64 {
x_hi_hi := hi >> 32
x_hi_lo := hi & g.EPSILON

t0, borrow := bits.Sub64(lo, x_hi_hi, 0)
t0 -= (g.EPSILON & -borrow)

t1 := x_hi_lo * g.EPSILON

resWrapped, carry := bits.Add64(t0, t1, 0)
t2 := resWrapped + (g.EPSILON & -carry)
return t2
}

// acc192 is a 192-bit accumulator of unreduced products
type acc192 struct{ lo, mid, hi uint64 }

func (s acc192) addProduct(a, b uint64) (res acc192) { // s += a*b (no reduction)
res = s
hi, lo := bits.Mul64(a, b)
var c uint64
res.lo, c = bits.Add64(s.lo, lo, 0)
res.mid, c = bits.Add64(s.mid, hi, c)
res.hi += c
return
}

func (s acc192) addProduct3(a, b uint64) (res acc192) { // s += 3*a*b (the X^5 = 3 fold)
res = s
hi, lo := bits.Mul64(a, b)
d0 := lo << 1 // 3*(hi:lo) = (hi:lo)<<1 + (hi:lo)
d1 := (hi << 1) | (lo >> 63)
d2 := hi >> 63
var c uint64
d0, c = bits.Add64(d0, lo, 0)
d1, c = bits.Add64(d1, hi, c)
d2 += c
res.lo, c = bits.Add64(s.lo, d0, 0)
res.mid, c = bits.Add64(s.mid, d1, c)
res.hi += d2 + c
return
}

func (s acc192) reduce() uint64 {
// value = (lo + mid*2^64) + hi*2^128 ; 2^128 ≡ -2^32 (mod p)
rLow := reduce128(s.lo, s.mid)
r2 := reduce128(s.hi<<32, s.hi>>32) // = hi*2^32 mod p
res, borrow := bits.Sub64(rLow, r2, 0)
return res - (g.EPSILON & -borrow)
}

// Mul multiplies two F_{p^5} elements with lazy reduction
func Mul(a, b Element) Element {
w := FP5_W
a0, a1, a2, a3, a4 := uint64(a[0]), uint64(a[1]), uint64(a[2]), uint64(a[3]), uint64(a[4])
b0, b1, b2, b3, b4 := uint64(b[0]), uint64(b[1]), uint64(b[2]), uint64(b[3]), uint64(b[4])

var s0, s1, s2, s3, s4 acc192

// c0 = a0b0 + 3(a1b4 + a2b3 + a3b2 + a4b1)
s0 = s0.addProduct(a0, b0)
s0 = s0.addProduct3(a1, b4)
s0 = s0.addProduct3(a2, b3)
s0 = s0.addProduct3(a3, b2)
s0 = s0.addProduct3(a4, b1)
// c1 = a0b1 + a1b0 + 3(a2b4 + a3b3 + a4b2)
s1 = s1.addProduct(a0, b1)
s1 = s1.addProduct(a1, b0)
s1 = s1.addProduct3(a2, b4)
s1 = s1.addProduct3(a3, b3)
s1 = s1.addProduct3(a4, b2)
// c2 = a0b2 + a1b1 + a2b0 + 3(a3b4 + a4b3)
s2 = s2.addProduct(a0, b2)
s2 = s2.addProduct(a1, b1)
s2 = s2.addProduct(a2, b0)
s2 = s2.addProduct3(a3, b4)
s2 = s2.addProduct3(a4, b3)
// c3 = a0b3 + a1b2 + a2b1 + a3b0 + 3 a4b4
s3 = s3.addProduct(a0, b3)
s3 = s3.addProduct(a1, b2)
s3 = s3.addProduct(a2, b1)
s3 = s3.addProduct(a3, b0)
s3 = s3.addProduct3(a4, b4)
// c4 = a0b4 + a1b3 + a2b2 + a3b1 + a4b0
s4 = s4.addProduct(a0, b4)
s4 = s4.addProduct(a1, b3)
s4 = s4.addProduct(a2, b2)
s4 = s4.addProduct(a3, b1)
s4 = s4.addProduct(a4, b0)

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}
return Element{
g.GoldilocksField(s0.reduce()),
g.GoldilocksField(s1.reduce()),
g.GoldilocksField(s2.reduce()),
g.GoldilocksField(s3.reduce()),
g.GoldilocksField(s4.reduce()),
}
}

// Returns a / b. Panics if b == 0.
Expand All @@ -162,40 +214,65 @@ func ExpPowerOf2(x Element, power int) Element {
return res
}

// add3 adds the 3-limb value v2:v1:v0 into the accumulator.
func (s acc192) add3(v0, v1, v2 uint64) (res acc192) {
res = s
var c uint64
res.lo, c = bits.Add64(s.lo, v0, 0)
res.mid, c = bits.Add64(s.mid, v1, c)
res.hi += v2 + c
return
}

func (s acc192) addProduct2(a, b uint64) acc192 { // s += 2*a*b (shift the product left 1)
hi, lo := bits.Mul64(a, b)
return s.add3(lo<<1, (hi<<1)|(lo>>63), hi>>63)
}

func (s acc192) addProduct6(a, b uint64) acc192 { // s += 6*a*b = 4*ab + 2*ab
hi, lo := bits.Mul64(a, b)
q0, q1, q2 := lo<<2, (hi<<2)|(lo>>62), hi>>62 // 4x
r0, r1, r2 := lo<<1, (hi<<1)|(lo>>63), hi>>63 // 2x
var c uint64
q0, c = bits.Add64(q0, r0, 0)
q1, c = bits.Add64(q1, r1, c)
q2 += r2 + c
return s.add3(q0, q1, q2)
}

// Square squares an F_{p^5} element with lazy reduction
func Square(a Element) Element {
w := FP5_W
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}
a0, a1, a2, a3, a4 := uint64(a[0]), uint64(a[1]), uint64(a[2]), uint64(a[3]), uint64(a[4])
var s0, s1, s2, s3, s4 acc192

// c0 = a0^2 + 6 a1a4 + 6 a2a3
s0 = s0.addProduct(a0, a0)
s0 = s0.addProduct6(a1, a4)
s0 = s0.addProduct6(a2, a3)
// c1 = 2 a0a1 + 6 a2a4 + 3 a3^2
s1 = s1.addProduct2(a0, a1)
s1 = s1.addProduct6(a2, a4)
s1 = s1.addProduct3(a3, a3)
// c2 = 2 a0a2 + a1^2 + 6 a3a4
s2 = s2.addProduct2(a0, a2)
s2 = s2.addProduct(a1, a1)
s2 = s2.addProduct6(a3, a4)
// c3 = 2 a0a3 + 2 a1a2 + 3 a4^2
s3 = s3.addProduct2(a0, a3)
s3 = s3.addProduct2(a1, a2)
s3 = s3.addProduct3(a4, a4)
// c4 = 2 a0a4 + 2 a1a3 + a2^2
s4 = s4.addProduct2(a0, a4)
s4 = s4.addProduct2(a1, a3)
s4 = s4.addProduct(a2, a2)

return Element{
g.GoldilocksField(s0.reduce()),
g.GoldilocksField(s1.reduce()),
g.GoldilocksField(s2.reduce()),
g.GoldilocksField(s3.reduce()),
g.GoldilocksField(s4.reduce()),
}
}

func Triple(a Element) Element {
Expand Down
Loading
Loading