sm9/bn256: avoid value copy #136

This commit is contained in:
emmansun 2023-07-02 11:23:36 +08:00
parent c7b3d97304
commit b493f8cb99
10 changed files with 460 additions and 107 deletions

View File

@ -1,35 +1,34 @@
// Package bn256 defines/implements ShangMi(SM) sm9's curves and pairing. // Package bn256 defines/implements ShangMi(SM) sm9's curves and pairing.
package bn256 package bn256
func lineFunctionAdd(r, p *twistPoint, q *curvePoint, r2 *gfP2) (a, b, c *gfP2, rOut *twistPoint) { func lineFunctionAdd(r, p, rOut *twistPoint, q *curvePoint, r2, a, b, c *gfP2) {
// See the mixed addition algorithm from "Faster Computation of the // See the mixed addition algorithm from "Faster Computation of the
// Tate Pairing", http://arxiv.org/pdf/0904.0854v3.pdf // Tate Pairing", http://arxiv.org/pdf/0904.0854v3.pdf
B := (&gfP2{}).Mul(&p.x, &r.t) // B = Xp * Zr^2 B := (&gfP2{}).MulNC(&p.x, &r.t) // B = Xp * Zr^2
D := (&gfP2{}).Add(&p.y, &r.z) // D = Yp + Zr D := (&gfP2{}).Add(&p.y, &r.z) // D = Yp + Zr
D.Square(D).Sub(D, r2).Sub(D, &r.t).Mul(D, &r.t) // D = ((Yp + Zr)^2 - Zr^2 - Yp^2)*Zr^2 = 2Yp*Zr^3 D.Square(D).Sub(D, r2).Sub(D, &r.t).Mul(D, &r.t) // D = ((Yp + Zr)^2 - Zr^2 - Yp^2)*Zr^2 = 2Yp*Zr^3
H := (&gfP2{}).Sub(B, &r.x) // H = Xp * Zr^2 - Xr H := (&gfP2{}).Sub(B, &r.x) // H = Xp * Zr^2 - Xr
I := (&gfP2{}).Square(H) // I = (Xp * Zr^2 - Xr)^2 = Xp^2*Zr^4 + Xr^2 - 2Xr*Xp*Zr^2 I := (&gfP2{}).SquareNC(H) // I = (Xp * Zr^2 - Xr)^2 = Xp^2*Zr^4 + Xr^2 - 2Xr*Xp*Zr^2
E := (&gfP2{}).Add(I, I) // E = 2*(Xp * Zr^2 - Xr)^2 E := (&gfP2{}).Add(I, I) // E = 2*(Xp * Zr^2 - Xr)^2
E.Add(E, E) // E = 4*(Xp * Zr^2 - Xr)^2 E.Add(E, E) // E = 4*(Xp * Zr^2 - Xr)^2
J := (&gfP2{}).Mul(H, E) // J = 4*(Xp * Zr^2 - Xr)^3 J := (&gfP2{}).MulNC(H, E) // J = 4*(Xp * Zr^2 - Xr)^3
L1 := (&gfP2{}).Sub(D, &r.y) // L1 = 2Yp*Zr^3 - Yr L1 := (&gfP2{}).Sub(D, &r.y) // L1 = 2Yp*Zr^3 - Yr
L1.Sub(L1, &r.y) // L1 = 2Yp*Zr^3 - 2*Yr L1.Sub(L1, &r.y) // L1 = 2Yp*Zr^3 - 2*Yr
V := (&gfP2{}).Mul(&r.x, E) // V = 4 * Xr * (Xp * Zr^2 - Xr)^2 V := (&gfP2{}).MulNC(&r.x, E) // V = 4 * Xr * (Xp * Zr^2 - Xr)^2
rOut = &twistPoint{}
rOut.x.Square(L1).Sub(&rOut.x, J).Sub(&rOut.x, V).Sub(&rOut.x, V) // rOut.x = L1^2 - J - 2V rOut.x.Square(L1).Sub(&rOut.x, J).Sub(&rOut.x, V).Sub(&rOut.x, V) // rOut.x = L1^2 - J - 2V
rOut.z.Add(&r.z, H).Square(&rOut.z).Sub(&rOut.z, &r.t).Sub(&rOut.z, I) // rOut.z = (Zr + H)^2 - Zr^2 - I rOut.z.Add(&r.z, H).Square(&rOut.z).Sub(&rOut.z, &r.t).Sub(&rOut.z, I) // rOut.z = (Zr + H)^2 - Zr^2 - I
t := (&gfP2{}).Sub(V, &rOut.x) // t = V - rOut.x t := (&gfP2{}).Sub(V, &rOut.x) // t = V - rOut.x
t.Mul(t, L1) // t = L1*(V-rOut.x) t.Mul(t, L1) // t = L1*(V-rOut.x)
t2 := (&gfP2{}).Mul(&r.y, J) t2 := (&gfP2{}).MulNC(&r.y, J)
t2.Add(t2, t2) // t2 = 2Yr * J t2.Add(t2, t2) // t2 = 2Yr * J
rOut.y.Sub(t, t2) // rOut.y = L1*(V-rOut.x) - 2Yr*J rOut.y.Sub(t, t2) // rOut.y = L1*(V-rOut.x) - 2Yr*J
@ -39,23 +38,21 @@ func lineFunctionAdd(r, p *twistPoint, q *curvePoint, r2 *gfP2) (a, b, c *gfP2,
t2.Mul(L1, &p.x) t2.Mul(L1, &p.x)
t2.Add(t2, t2) // t2 = 2 L1 * Xp t2.Add(t2, t2) // t2 = 2 L1 * Xp
a = (&gfP2{}).Sub(t2, t) // a = 2 L1 * Xp - 2 Yp * rOut.z a.Sub(t2, t) // a = 2 L1 * Xp - 2 Yp * rOut.z
c = (&gfP2{}).MulScalar(&rOut.z, &q.y) c.MulScalar(&rOut.z, &q.y)
c.Add(c, c) c.Add(c, c)
b = (&gfP2{}).Neg(L1) b.Neg(L1)
b.MulScalar(b, &q.x).Add(b, b) b.MulScalar(b, &q.x).Add(b, b)
return
} }
func lineFunctionDouble(r *twistPoint, q *curvePoint) (a, b, c *gfP2, rOut *twistPoint) { func lineFunctionDouble(r, rOut *twistPoint, q *curvePoint, a, b, c *gfP2) {
// See the doubling algorithm for a=0 from "Faster Computation of the // See the doubling algorithm for a=0 from "Faster Computation of the
// Tate Pairing", http://arxiv.org/pdf/0904.0854v3.pdf // Tate Pairing", http://arxiv.org/pdf/0904.0854v3.pdf
A := (&gfP2{}).Square(&r.x) A := (&gfP2{}).SquareNC(&r.x)
B := (&gfP2{}).Square(&r.y) B := (&gfP2{}).SquareNC(&r.y)
C := (&gfP2{}).Square(B) // C = Yr ^ 4 C := (&gfP2{}).SquareNC(B) // C = Yr ^ 4
D := (&gfP2{}).Add(&r.x, B) D := (&gfP2{}).Add(&r.x, B)
D.Square(D).Sub(D, A).Sub(D, C).Add(D, D) D.Square(D).Sub(D, A).Sub(D, C).Add(D, D)
@ -63,9 +60,8 @@ func lineFunctionDouble(r *twistPoint, q *curvePoint) (a, b, c *gfP2, rOut *twis
E := (&gfP2{}).Add(A, A) // E := (&gfP2{}).Add(A, A) //
E.Add(E, A) // E = 3 * Xr ^ 2 E.Add(E, A) // E = 3 * Xr ^ 2
G := (&gfP2{}).Square(E) // G = 9 * Xr^4 G := (&gfP2{}).SquareNC(E) // G = 9 * Xr^4
rOut = &twistPoint{}
rOut.x.Sub(G, D).Sub(&rOut.x, D) rOut.x.Sub(G, D).Sub(&rOut.x, D)
rOut.z.Add(&r.y, &r.z).Square(&rOut.z).Sub(&rOut.z, B).Sub(&rOut.z, &r.t) // Z3 = (Yr + Zr)^2 - Yr^2 - Zr^2 = 2Yr*Zr rOut.z.Add(&r.y, &r.z).Square(&rOut.z).Sub(&rOut.z, B).Sub(&rOut.z, &r.t) // Z3 = (Yr + Zr)^2 - Yr^2 - Zr^2 = 2Yr*Zr
@ -78,18 +74,16 @@ func lineFunctionDouble(r *twistPoint, q *curvePoint) (a, b, c *gfP2, rOut *twis
rOut.t.Square(&rOut.z) rOut.t.Square(&rOut.z)
t.Mul(E, &r.t).Add(t, t) t.Mul(E, &r.t).Add(t, t)
b = (&gfP2{}).Neg(t) b.Neg(t)
b.MulScalar(b, &q.x) b.MulScalar(b, &q.x)
a = (&gfP2{}).Add(&r.x, E) a.Add(&r.x, E)
a.Square(a).Sub(a, A).Sub(a, G) a.Square(a).Sub(a, A).Sub(a, G)
t.Add(B, B).Add(t, t) t.Add(B, B).Add(t, t)
a.Sub(a, t) a.Sub(a, t)
c = (&gfP2{}).Mul(&rOut.z, &r.t) c.Mul(&rOut.z, &r.t)
c.Add(c, c).MulScalar(c, &q.y) c.Add(c, c).MulScalar(c, &q.y)
return
} }
// (ret.z + ret.y*w + ret.x*w^2)* ((cv+a) + b*w^2) // (ret.z + ret.y*w + ret.x*w^2)* ((cv+a) + b*w^2)
@ -98,15 +92,15 @@ func mulLine(ret *gfP12, a, b, c *gfP2) {
gfp2Copy(&bz.x, c) gfp2Copy(&bz.x, c)
gfp2Copy(&bz.y, a) gfp2Copy(&bz.y, a)
tz.Mul(&ret.z, bz) tz.MulNC(&ret.z, bz)
t.MulScalar(&ret.y, b).MulV1(t) t.MulScalar(&ret.y, b).MulV1(t)
tz.Add(tz, t) tz.Add(tz, t)
t1.Mul(&ret.y, bz) t1.MulNC(&ret.y, bz)
t.MulScalar(&ret.x, b).MulV1(t) t.MulScalar(&ret.x, b).MulV1(t)
ret.y.Add(t1, t) ret.y.Add(t1, t)
t.Mul(&ret.x, bz) t.MulNC(&ret.x, bz)
t1.MulScalar(&ret.z, b) t1.MulScalar(&ret.z, b)
ret.x.Add(t1, t) ret.x.Add(t1, t)
gfp4Copy(&ret.z, tz) gfp4Copy(&ret.z, tz)
@ -134,26 +128,33 @@ func miller(q *twistPoint, p *curvePoint) *gfP12 {
r := &twistPoint{} r := &twistPoint{}
r.Set(aAffine) r.Set(aAffine)
r2 := (&gfP2{}).Square(&aAffine.y) r2 := (&gfP2{}).SquareNC(&aAffine.y)
a, b, c := &gfP2{}, &gfP2{}, &gfP2{}
newR := &twistPoint{}
var tmpR *twistPoint
for i := len(sixUPlus2NAF) - 1; i > 0; i-- { for i := len(sixUPlus2NAF) - 1; i > 0; i-- {
a, b, c, newR := lineFunctionDouble(r, bAffine) lineFunctionDouble(r, newR, bAffine, a, b, c)
if i != len(sixUPlus2NAF)-1 { if i != len(sixUPlus2NAF)-1 {
ret.Square(ret) ret.Square(ret)
} }
mulLine(ret, a, b, c) mulLine(ret, a, b, c)
tmpR= r
r = newR r = newR
newR= tmpR
switch sixUPlus2NAF[i-1] { switch sixUPlus2NAF[i-1] {
case 1: case 1:
a, b, c, newR = lineFunctionAdd(r, aAffine, bAffine, r2) lineFunctionAdd(r, aAffine, newR, bAffine, r2, a, b, c)
case -1: case -1:
a, b, c, newR = lineFunctionAdd(r, minusA, bAffine, r2) lineFunctionAdd(r, minusA, newR, bAffine, r2, a, b, c)
default: default:
continue continue
} }
mulLine(ret, a, b, c) mulLine(ret, a, b, c)
tmpR= r
r = newR r = newR
newR= tmpR
} }
// In order to calculate Q1 we have to convert q from the sextic twist // In order to calculate Q1 we have to convert q from the sextic twist
@ -184,12 +185,14 @@ func miller(q *twistPoint, p *curvePoint) *gfP12 {
minusQ2.t.SetOne() minusQ2.t.SetOne()
r2.Square(&q1.y) r2.Square(&q1.y)
a, b, c, newR := lineFunctionAdd(r, q1, bAffine, r2) lineFunctionAdd(r, q1, newR, bAffine, r2, a, b, c)
mulLine(ret, a, b, c) mulLine(ret, a, b, c)
tmpR= r
r = newR r = newR
newR= tmpR
r2.Square(&minusQ2.y) r2.Square(&minusQ2.y)
a, b, c, _ = lineFunctionAdd(r, minusQ2, bAffine, r2) lineFunctionAdd(r, minusQ2, newR, bAffine, r2, a, b, c)
mulLine(ret, a, b, c) mulLine(ret, a, b, c)
return ret return ret
@ -225,18 +228,18 @@ func finalExponentiation(in *gfP12) *gfP12 {
y2 := (&gfP12{}).FrobeniusP2(fu2) y2 := (&gfP12{}).FrobeniusP2(fu2)
y0 := &gfP12{} y0 := &gfP12{}
y0.Mul(fp, fp2).Mul(y0, fp3) y0.MulNC(fp, fp2).Mul(y0, fp3)
y1 := (&gfP12{}).Conjugate(t1) y1 := (&gfP12{}).Conjugate(t1)
y5 := (&gfP12{}).Conjugate(fu2) y5 := (&gfP12{}).Conjugate(fu2)
y3.Conjugate(y3) y3.Conjugate(y3)
y4 := (&gfP12{}).Mul(fu, fu2p) y4 := (&gfP12{}).MulNC(fu, fu2p)
y4.Conjugate(y4) y4.Conjugate(y4)
y6 := (&gfP12{}).Mul(fu3, fu3p) y6 := (&gfP12{}).MulNC(fu3, fu3p)
y6.Conjugate(y6) y6.Conjugate(y6)
t0 := (&gfP12{}).Square(y6) t0 := (&gfP12{}).SquareNC(y6)
t0.Mul(t0, y4).Mul(t0, y5) t0.Mul(t0, y4).Mul(t0, y5)
t1.Mul(y3, y5).Mul(t1, t0) t1.Mul(y3, y5).Mul(t1, t0)
t0.Mul(t0, y2) t0.Mul(t0, y2)

View File

@ -1,9 +1,128 @@
package bn256 package bn256
// (ret.x t + ret.y) * ((cs)t + (bs+a))
//= ((ret.x * (bs+a))+ret.y*cs) t + (ret.y*(bs+a) + ret.x*cs*s)
//= (ret.x*bs + ret.x*a + ret.y*cs) t + (ret.y*bs + ret.x*cs*s + ret.y * a)
//ret.x = (ret.x + ret.y)(cs + bs + a) - ret.y(bs+a) - ret.x*cs
//ret.y = ret.y(bs+a) + ret.x*cs *s
func mulLineB6(ret *gfP12b6, a, b, c *gfP2) {
a2 := &gfP6{}
a2.y.Set(b)
a2.z.Set(a)
a2.Mul(&ret.y, a2)
t3 := &gfP6{}
t3.MulScalar(&ret.x, c).MulS(t3)
t := (&gfP2{}).Add(b, c)
t2 := &gfP6{}
t2.y.Set(t)
t2.z.Set(a)
ret.x.Add(&ret.x, &ret.y)
ret.y.Set(t3)
ret.x.Mul(&ret.x, t2).Sub(&ret.x, a2).Sub(&ret.x, &ret.y)
ret.y.MulS(&ret.y)
ret.y.Add(&ret.y, a2)
}
// R-ate Pairing G2 x G1 -> GT
//
// P is a point of order q in G1. Q(x,y) is a point of order q in G2.
// Note that Q is a point on the sextic twist of the curve over Fp^2, P(x,y) is a point on the
// curve over the base field Fp
//
func millerB6(q *twistPoint, p *curvePoint) *gfP12b6 {
ret := (&gfP12b6{}).SetOne()
aAffine := &twistPoint{}
aAffine.Set(q)
aAffine.MakeAffine()
minusA := &twistPoint{}
minusA.Neg(aAffine)
bAffine := &curvePoint{}
bAffine.Set(p)
bAffine.MakeAffine()
r := &twistPoint{}
r.Set(aAffine)
r2 := (&gfP2{}).Square(&aAffine.y)
a, b, c := &gfP2{}, &gfP2{}, &gfP2{}
newR := &twistPoint{}
var tmpR *twistPoint
for i := len(sixUPlus2NAF) - 1; i > 0; i-- {
lineFunctionDouble(r, newR, bAffine, a, b, c)
if i != len(sixUPlus2NAF)-1 {
ret.Square(ret)
}
mulLineB6(ret, a, b, c)
tmpR= r
r = newR
newR= tmpR
switch sixUPlus2NAF[i-1] {
case 1:
lineFunctionAdd(r, aAffine, newR, bAffine, r2, a, b, c)
case -1:
lineFunctionAdd(r, minusA, newR, bAffine, r2, a, b, c)
default:
continue
}
mulLineB6(ret, a, b, c)
tmpR= r
r = newR
newR= tmpR
}
// In order to calculate Q1 we have to convert q from the sextic twist
// to the full GF(p^12) group, apply the Frobenius there, and convert
// back.
//
// The twist isomorphism is (x', y') -> (x*β^(-1/3), y*β^(-1/2)). If we consider just
// x for a moment, then after applying the Frobenius, we have x̄*β^(-p/3)
// where x̄ is the conjugate of x. If we are going to apply the inverse
// isomorphism we need a value with a single coefficient of β^(-1/3) so we
// rewrite this as x̄*β^((-p+1)/3)*β^(-1/3).
//
// A similar argument can be made for the y value.
q1 := &twistPoint{}
q1.x.Conjugate(&aAffine.x)
q1.x.MulScalar(&q1.x, betaToNegPPlus1Over3)
q1.y.Conjugate(&aAffine.y)
q1.y.MulScalar(&q1.y, betaToNegPPlus1Over2)
q1.z.SetOne()
q1.t.SetOne()
minusQ2 := &twistPoint{}
minusQ2.x.Set(&aAffine.x)
minusQ2.x.MulScalar(&minusQ2.x, betaToNegP2Plus1Over3)
minusQ2.y.Neg(&aAffine.y)
minusQ2.y.MulScalar(&minusQ2.y, betaToNegP2Plus1Over2)
minusQ2.z.SetOne()
minusQ2.t.SetOne()
r2.Square(&q1.y)
lineFunctionAdd(r, q1, newR, bAffine, r2, a, b, c)
mulLineB6(ret, a, b, c)
tmpR= r
r = newR
newR= tmpR
r2.Square(&minusQ2.y)
lineFunctionAdd(r, minusQ2, newR, bAffine, r2, a, b, c)
mulLineB6(ret, a, b, c)
return ret
}
func pairingB6(a *twistPoint, b *curvePoint) *gfP12 { func pairingB6(a *twistPoint, b *curvePoint) *gfP12 {
e := miller(a, b) e := millerB6(a, b)
eb6 := (&gfP12b6{}).SetGfP12(e) ret := finalExponentiationB6(e)
ret := finalExponentiationB6(eb6)
if a.IsInfinity() || b.IsInfinity() { if a.IsInfinity() || b.IsInfinity() {
ret.SetOne() ret.SetOne()

View File

@ -1,10 +1,21 @@
package bn256 package bn256
import ( import (
"fmt"
"math/big" "math/big"
"testing" "testing"
) )
func TestToGfP12_1(t *testing.T) {
x := &gfP12b6{}
x.SetGfP12(expected1)
fmt.Printf("%v\n", gfP12b6Decode(x))
x.SetGfP12(expected_b2)
fmt.Printf("%v\n", gfP12b6Decode(x))
x.SetGfP12(expected_b2_2)
fmt.Printf("%v\n", gfP12b6Decode(x))
}
func Test_finalExponentiationB6(t *testing.T) { func Test_finalExponentiationB6(t *testing.T) {
x := &gfP12b6{ x := &gfP12b6{
p6, p6,
@ -89,3 +100,20 @@ func BenchmarkFinalExponentiationB6(b *testing.B) {
} }
} }
} }
func BenchmarkPairingB6(b *testing.B) {
pk := bigFromHex("0130E78459D78545CB54C587E02CF480CE0B66340F319F348A1D5B1F2DC5F4")
g2 := &G2{}
_, err := g2.ScalarBaseMult(NormalizeScalar(pk.Bytes()))
if err != nil {
b.Fatal(err)
}
b.ReportAllocs()
b.ResetTimer()
for i := 0; i < b.N; i++ {
ret := pairingB6(g2.p, curveGen)
if *ret != *expected1 {
b.Errorf("not expected")
}
}
}

View File

@ -161,3 +161,20 @@ func BenchmarkFinalExponentiation(b *testing.B) {
} }
} }
} }
func BenchmarkPairingB4(b *testing.B) {
pk := bigFromHex("0130E78459D78545CB54C587E02CF480CE0B66340F319F348A1D5B1F2DC5F4")
g2 := &G2{}
_, err := g2.ScalarBaseMult(NormalizeScalar(pk.Bytes()))
if err != nil {
b.Fatal(err)
}
b.ReportAllocs()
b.ResetTimer()
for i := 0; i < b.N; i++ {
ret := pairing(g2.p, curveGen)
if *ret != *expected1 {
b.Errorf("not expected")
}
}
}

View File

@ -144,9 +144,9 @@ func (e *gfP12) Mul(a, b *gfP12) *gfP12 {
ty := &tmp.y ty := &tmp.y
tz := &tmp.z tz := &tmp.z
t, v0, v1, v2 := &gfP4{}, &gfP4{}, &gfP4{}, &gfP4{} t, v0, v1, v2 := &gfP4{}, &gfP4{}, &gfP4{}, &gfP4{}
v0.Mul(&a.z, &b.z) v0.MulNC(&a.z, &b.z)
v1.Mul(&a.y, &b.y) v1.MulNC(&a.y, &b.y)
v2.Mul(&a.x, &b.x) v2.MulNC(&a.x, &b.x)
t.Add(&a.y, &a.x) t.Add(&a.y, &a.x)
tz.Add(&b.y, &b.x) tz.Add(&b.y, &b.x)
@ -174,6 +174,45 @@ func (e *gfP12) Mul(a, b *gfP12) *gfP12 {
return e return e
} }
func (e *gfP12) MulNC(a, b *gfP12) *gfP12 {
// (z0 + y0*w + x0*w^2)* (z1 + y1*w + x1*w^2)
// z0*z1 + z0*y1*w + z0*x1*w^2
// +y0*z1*w + y0*y1*w^2 + y0*x1*v
// +x0*z1*w^2 + x0*y1*v + x0*x1*v*w
//=(z0*z1+y0*x1*v+x0*y1*v) + (z0*y1+y0*z1+x0*x1*v)w + (z0*x1 + y0*y1 + x0*z1)*w^2
tx := &e.x
ty := &e.y
tz := &e.z
t, v0, v1, v2 := &gfP4{}, &gfP4{}, &gfP4{}, &gfP4{}
v0.MulNC(&a.z, &b.z)
v1.MulNC(&a.y, &b.y)
v2.MulNC(&a.x, &b.x)
t.Add(&a.y, &a.x)
tz.Add(&b.y, &b.x)
t.Mul(t, tz)
t.Sub(t, v1)
t.Sub(t, v2)
t.MulV1(t)
tz.Add(t, v0)
t.Add(&a.z, &a.y)
ty.Add(&b.z, &b.y)
ty.Mul(t, ty)
ty.Sub(ty, v0)
ty.Sub(ty, v1)
t.MulV1(v2)
ty.Add(ty, t)
t.Add(&a.z, &a.x)
tx.Add(&b.z, &b.x)
tx.Mul(tx, t)
tx.Sub(tx, v0)
tx.Add(tx, v1)
tx.Sub(tx, v2)
return e
}
func (e *gfP12) Square(a *gfP12) *gfP12 { func (e *gfP12) Square(a *gfP12) *gfP12 {
// (z + y*w + x*w^2)* (z + y*w + x*w^2) // (z + y*w + x*w^2)* (z + y*w + x*w^2)
// z^2 + z*y*w + z*x*w^2 + y*z*w + y^2*w^2 + y*x*v + x*z*w^2 + x*y*v + x^2 *v *w // z^2 + z*y*w + z*x*w^2 + y*z*w + y^2*w^2 + y*x*v + x*z*w^2 + x*y*v + x^2 *v *w
@ -185,17 +224,17 @@ func (e *gfP12) Square(a *gfP12) *gfP12 {
tz := &tmp.z tz := &tmp.z
t := &gfP4{} t := &gfP4{}
tz.Square(&a.z) tz.SquareNC(&a.z)
t.MulV(&a.x, &a.y) t.MulV(&a.x, &a.y)
t.Add(t, t) t.Add(t, t)
tz.Add(tz, t) tz.Add(tz, t)
ty.SquareV(&a.x) ty.SquareVNC(&a.x)
t.Mul(&a.y, &a.z) t.Mul(&a.y, &a.z)
t.Add(t, t) t.Add(t, t)
ty.Add(ty, t) ty.Add(ty, t)
tx.Square(&a.y) tx.SquareNC(&a.y)
t.Mul(&a.x, &a.z) t.Mul(&a.x, &a.z)
t.Add(t, t) t.Add(t, t)
tx.Add(tx, t) tx.Add(tx, t)
@ -203,6 +242,33 @@ func (e *gfP12) Square(a *gfP12) *gfP12 {
return e return e
} }
func (e *gfP12) SquareNC(a *gfP12) *gfP12 {
// (z + y*w + x*w^2)* (z + y*w + x*w^2)
// z^2 + z*y*w + z*x*w^2 + y*z*w + y^2*w^2 + y*x*v + x*z*w^2 + x*y*v + x^2 *v *w
// (z^2 + y*x*v + x*y*v) + (z*y + y*z + v * x^2)w + (z*x + y^2 + x*z)*w^2
// (z^2 + 2*x*y*v) + (v*x^2 + 2*y*z) *w + (y^2 + 2*x*z) * w^2
tx := &e.x
ty := &e.y
tz := &e.z
t := &gfP4{}
tz.SquareNC(&a.z)
t.MulV(&a.x, &a.y)
t.Add(t, t)
tz.Add(tz, t)
ty.SquareVNC(&a.x)
t.Mul(&a.y, &a.z)
t.Add(t, t)
ty.Add(ty, t)
tx.SquareNC(&a.y)
t.Mul(&a.x, &a.z)
t.Add(t, t)
tx.Add(tx, t)
return e
}
func (e *gfP12) Squares(a *gfP12, n int) *gfP12 { func (e *gfP12) Squares(a *gfP12, n int) *gfP12 {
// Square first round // Square first round
in := &gfP12{} in := &gfP12{}
@ -211,17 +277,17 @@ func (e *gfP12) Squares(a *gfP12, n int) *gfP12 {
tz := &in.z tz := &in.z
t := &gfP4{} t := &gfP4{}
tz.Square(&a.z) tz.SquareNC(&a.z)
t.MulV(&a.x, &a.y) t.MulV(&a.x, &a.y)
t.Add(t, t) t.Add(t, t)
tz.Add(tz, t) tz.Add(tz, t)
ty.SquareV(&a.x) ty.SquareVNC(&a.x)
t.Mul(&a.y, &a.z) t.Mul(&a.y, &a.z)
t.Add(t, t) t.Add(t, t)
ty.Add(ty, t) ty.Add(ty, t)
tx.Square(&a.y) tx.SquareNC(&a.y)
t.Mul(&a.x, &a.z) t.Mul(&a.x, &a.z)
t.Add(t, t) t.Add(t, t)
tx.Add(tx, t) tx.Add(tx, t)
@ -232,17 +298,17 @@ func (e *gfP12) Squares(a *gfP12, n int) *gfP12 {
ty = &tmp.y ty = &tmp.y
tz = &tmp.z tz = &tmp.z
for i := 1; i < n; i++ { for i := 1; i < n; i++ {
tz.Square(&in.z) tz.SquareNC(&in.z)
t.MulV(&in.x, &in.y) t.MulV(&in.x, &in.y)
t.Add(t, t) t.Add(t, t)
tz.Add(tz, t) tz.Add(tz, t)
ty.SquareV(&in.x) ty.SquareVNC(&in.x)
t.Mul(&in.y, &in.z) t.Mul(&in.y, &in.z)
t.Add(t, t) t.Add(t, t)
ty.Add(ty, t) ty.Add(ty, t)
tx.Square(&in.y) tx.SquareNC(&in.y)
t.Mul(&in.x, &in.z) t.Mul(&in.x, &in.z)
t.Add(t, t) t.Add(t, t)
tx.Add(tx, t) tx.Add(tx, t)
@ -289,19 +355,19 @@ func (e *gfP12) Invert(a *gfP12) *gfP12 {
// = τ²(y²-ξxz) + τ(ξx²-yz) + (z²-ξxy) // = τ²(y²-ξxz) + τ(ξx²-yz) + (z²-ξxy)
// //
// So that's why A = (z²-ξxy), B = (ξx²-yz), C = (y²-ξxz) // So that's why A = (z²-ξxy), B = (ξx²-yz), C = (y²-ξxz)
t1 := (&gfP4{}).MulV(&a.x, &a.y) t1 := (&gfP4{}).MulVNC(&a.x, &a.y)
A := (&gfP4{}).Square(&a.z) A := (&gfP4{}).SquareNC(&a.z)
A.Sub(A, t1) A.Sub(A, t1)
B := (&gfP4{}).SquareV(&a.x) B := (&gfP4{}).SquareVNC(&a.x)
t1.Mul(&a.y, &a.z) t1.Mul(&a.y, &a.z)
B.Sub(B, t1) B.Sub(B, t1)
C := (&gfP4{}).Square(&a.y) C := (&gfP4{}).SquareNC(&a.y)
t1.Mul(&a.x, &a.z) t1.Mul(&a.x, &a.z)
C.Sub(C, t1) C.Sub(C, t1)
F := (&gfP4{}).MulV(C, &a.y) F := (&gfP4{}).MulVNC(C, &a.y)
t1.Mul(A, &a.z) t1.Mul(A, &a.z)
F.Add(F, t1) F.Add(F, t1)
t1.MulV(B, &a.x) t1.MulV(B, &a.x)

View File

@ -14,18 +14,18 @@ func (e *gfP12) gfP12ExpU(x *gfP12) *gfP12 {
// i69 = (2*(i56 << 4 + _1001) + 1) << 6 // i69 = (2*(i56 << 4 + _1001) + 1) << 6
// return 2*(_101 + i69) // return 2*(_101 + i69)
// //
var z = new(gfP12) var z = e
var t0 = new(gfP12) var t0 = new(gfP12)
var t1 = new(gfP12) var t1 = new(gfP12)
var t2 = new(gfP12) var t2 = new(gfP12)
var t3 = new(gfP12) var t3 = new(gfP12)
t2.Square(x) t2.SquareNC(x)
t1.Square(t2) t1.SquareNC(t2)
z.Mul(x, t1) z.MulNC(x, t1)
t0.Mul(t1, z) t0.MulNC(t1, z)
t2.Mul(t2, t0) t2.Mul(t2, t0)
t3.Mul(x, t2) t3.MulNC(x, t2)
t3.Squares(t3, 40) t3.Squares(t3, 40)
t3.Mul(t2, t3) t3.Mul(t2, t3)
t3.Squares(t3, 7) t3.Squares(t3, 7)
@ -38,6 +38,5 @@ func (e *gfP12) gfP12ExpU(x *gfP12) *gfP12 {
t0.Squares(t0, 6) t0.Squares(t0, 6)
z.Mul(z, t0) z.Mul(z, t0)
z.Square(z) z.Square(z)
gfp12Copy(e, z)
return e return e
} }

View File

@ -129,6 +129,27 @@ func (e *gfP2) Mul(a, b *gfP2) *gfP2 {
return e return e
} }
// Mul without Copy
func (e *gfP2) MulNC(a, b *gfP2) *gfP2 {
tx := &e.x
ty := &e.y
v0, v1 := &gfP{}, &gfP{}
gfpMul(v0, &a.y, &b.y)
gfpMul(v1, &a.x, &b.x)
gfpAdd(tx, &a.x, &a.y)
gfpAdd(ty, &b.x, &b.y)
gfpMul(tx, tx, ty)
gfpSub(tx, tx, v0)
gfpSub(tx, tx, v1)
gfpSub(ty, v0, v1)
gfpSub(ty, ty, v1)
return e
}
// MulU: a * b * u // MulU: a * b * u
// (a0+a1*u)(b0+b1*u)*u=c0+c1*u, where // (a0+a1*u)(b0+b1*u)*u=c0+c1*u, where
// c1 = (a0*b0 - 2a1*b1)u // c1 = (a0*b0 - 2a1*b1)u
@ -189,6 +210,21 @@ func (e *gfP2) Square(a *gfP2) *gfP2 {
return e return e
} }
func (e *gfP2) SquareNC(a *gfP2) *gfP2 {
// Complex squaring algorithm:
// (xu+y)² = y^2-2*x^2 + 2*u*x*y
tx := &e.x
ty := &e.y
gfpSqr(tx, &a.x, 1)
gfpSqr(ty, &a.y, 1)
gfpSub(ty, ty, tx)
gfpSub(ty, ty, tx)
gfpMul(tx, &a.x, &a.y)
gfpAdd(tx, tx, tx)
return e
}
func (e *gfP2) SquareU(a *gfP2) *gfP2 { func (e *gfP2) SquareU(a *gfP2) *gfP2 {
// Complex squaring algorithm: // Complex squaring algorithm:
// (xu+y)²*u = (y^2-2*x^2)u - 4*x*y // (xu+y)²*u = (y^2-2*x^2)u - 4*x*y
@ -212,6 +248,27 @@ func (e *gfP2) SquareU(a *gfP2) *gfP2 {
return e return e
} }
func (e *gfP2) SquareUNC(a *gfP2) *gfP2 {
// Complex squaring algorithm:
// (xu+y)²*u = (y^2-2*x^2)u - 4*x*y
tx := &e.x
ty := &e.y
// tx = a0^2 - 2 * a1^2
gfpSqr(ty, &a.x, 1)
gfpSqr(tx, &a.y, 1)
gfpAdd(ty, ty, ty)
gfpSub(tx, tx, ty)
// ty = -4 * a0 * a1
gfpMul(ty, &a.x, &a.y)
gfpAdd(ty, ty, ty)
gfpAdd(ty, ty, ty)
gfpNeg(ty, ty)
return e
}
func (e *gfP2) MulScalar(a *gfP2, b *gfP) *gfP2 { func (e *gfP2) MulScalar(a *gfP2, b *gfP) *gfP2 {
gfpMul(&e.x, &a.x, b) gfpMul(&e.x, &a.x, b)
gfpMul(&e.y, &a.y, b) gfpMul(&e.y, &a.y, b)

View File

@ -102,8 +102,8 @@ func (e *gfP4) Mul(a, b *gfP4) *gfP4 {
tx := &tmp.x tx := &tmp.x
ty := &tmp.y ty := &tmp.y
v0, v1 := &gfP2{}, &gfP2{} v0, v1 := &gfP2{}, &gfP2{}
v0.Mul(&a.y, &b.y) v0.MulNC(&a.y, &b.y)
v1.Mul(&a.x, &b.x) v1.MulNC(&a.x, &b.x)
tx.Add(&a.x, &a.y) tx.Add(&a.x, &a.y)
ty.Add(&b.x, &b.y) ty.Add(&b.x, &b.y)
@ -118,6 +118,31 @@ func (e *gfP4) Mul(a, b *gfP4) *gfP4 {
return e return e
} }
func (e *gfP4) MulNC(a, b *gfP4) *gfP4 {
// "Multiplication and Squaring on Pairing-Friendly Fields"
// Section 4, Karatsuba method.
// http://eprint.iacr.org/2006/471.pdf
//(a0+a1*v)(b0+b1*v)=c0+c1*v, where
//c0 = a0*b0 +a1*b1*u
//c1 = (a0 + a1)(b0 + b1) - a0*b0 - a1*b1 = a0*b1 + a1*b0
tx := &e.x
ty := &e.y
v0, v1 := &gfP2{}, &gfP2{}
v0.MulNC(&a.y, &b.y)
v1.MulNC(&a.x, &b.x)
tx.Add(&a.x, &a.y)
ty.Add(&b.x, &b.y)
tx.Mul(tx, ty)
tx.Sub(tx, v0)
tx.Sub(tx, v1)
ty.MulU1(v1)
ty.Add(ty, v0)
return e
}
// MulV: a * b * v // MulV: a * b * v
// (a0+a1*v)(b0+b1*v)*v=c0+c1*v, where // (a0+a1*v)(b0+b1*v)*v=c0+c1*v, where
// (a0*b0 + a0*b1v + a1*b0*v + a1*b1*u)*v // (a0*b0 + a0*b1v + a1*b0*v + a1*b1*u)*v
@ -129,8 +154,8 @@ func (e *gfP4) MulV(a, b *gfP4) *gfP4 {
tx := &tmp.x tx := &tmp.x
ty := &tmp.y ty := &tmp.y
v0, v1 := &gfP2{}, &gfP2{} v0, v1 := &gfP2{}, &gfP2{}
v0.Mul(&a.y, &b.y) v0.MulNC(&a.y, &b.y)
v1.Mul(&a.x, &b.x) v1.MulNC(&a.x, &b.x)
tx.Add(&a.x, &a.y) tx.Add(&a.x, &a.y)
ty.Add(&b.x, &b.y) ty.Add(&b.x, &b.y)
@ -146,6 +171,26 @@ func (e *gfP4) MulV(a, b *gfP4) *gfP4 {
return e return e
} }
func (e *gfP4) MulVNC(a, b *gfP4) *gfP4 {
tx := &e.x
ty := &e.y
v0, v1 := &gfP2{}, &gfP2{}
v0.MulNC(&a.y, &b.y)
v1.MulNC(&a.x, &b.x)
tx.Add(&a.x, &a.y)
ty.Add(&b.x, &b.y)
ty.Mul(tx, ty)
ty.Sub(ty, v0)
ty.Sub(ty, v1)
ty.MulU1(ty)
tx.MulU1(v1)
tx.Add(tx, v0)
return e
}
// MulV1: a * v // MulV1: a * v
// (a0+a1*v)*v=c0+c1*v, where // (a0+a1*v)*v=c0+c1*v, where
// c0 = a1*u // c0 = a1*u
@ -165,8 +210,8 @@ func (e *gfP4) Square(a *gfP4) *gfP4 {
tmp := &gfP4{} tmp := &gfP4{}
tx := &tmp.x tx := &tmp.x
ty := &tmp.y ty := &tmp.y
tx.SquareU(&a.x) tx.SquareUNC(&a.x)
ty.Square(&a.y) ty.SquareNC(&a.y)
ty.Add(tx, ty) ty.Add(tx, ty)
tx.Mul(&a.x, &a.y) tx.Mul(&a.x, &a.y)
@ -176,14 +221,29 @@ func (e *gfP4) Square(a *gfP4) *gfP4 {
return e return e
} }
func (e *gfP4) SquareNC(a *gfP4) *gfP4 {
// Complex squaring algorithm:
// (xv+y)² = (x^2*u + y^2) + 2*x*y*v
tx := &e.x
ty := &e.y
tx.SquareUNC(&a.x)
ty.SquareNC(&a.y)
ty.Add(tx, ty)
tx.Mul(&a.x, &a.y)
tx.Add(tx, tx)
return e
}
// SquareV: (a^2) * v // SquareV: (a^2) * v
// v*(xv+y)² = (x^2*u + y^2)v + 2*x*y*u // v*(xv+y)² = (x^2*u + y^2)v + 2*x*y*u
func (e *gfP4) SquareV(a *gfP4) *gfP4 { func (e *gfP4) SquareV(a *gfP4) *gfP4 {
tmp := &gfP4{} tmp := &gfP4{}
tx := &tmp.x tx := &tmp.x
ty := &tmp.y ty := &tmp.y
tx.SquareU(&a.x) tx.SquareUNC(&a.x)
ty.Square(&a.y) ty.SquareNC(&a.y)
tx.Add(tx, ty) tx.Add(tx, ty)
ty.MulU(&a.x, &a.y) ty.MulU(&a.x, &a.y)
@ -193,6 +253,19 @@ func (e *gfP4) SquareV(a *gfP4) *gfP4 {
return e return e
} }
func (e *gfP4) SquareVNC(a *gfP4) *gfP4 {
tx := &e.x
ty := &e.y
tx.SquareUNC(&a.x)
ty.SquareNC(&a.y)
tx.Add(tx, ty)
ty.MulU(&a.x, &a.y)
ty.Add(ty, ty)
return e
}
func (e *gfP4) Invert(a *gfP4) *gfP4 { func (e *gfP4) Invert(a *gfP4) *gfP4 {
// See "Implementing cryptographic pairings", M. Scott, section 3.2. // See "Implementing cryptographic pairings", M. Scott, section 3.2.
// ftp://136.206.11.249/pub/crypto/pairings.pdf // ftp://136.206.11.249/pub/crypto/pairings.pdf
@ -202,15 +275,15 @@ func (e *gfP4) Invert(a *gfP4) *gfP4 {
t3 := &gfP2{} t3 := &gfP2{}
t3.SquareU(&a.x) t3.SquareUNC(&a.x)
t1.Square(&a.y) t1.SquareNC(&a.y)
t3.Sub(t3, t1) t3.Sub(t3, t1)
t3.Invert(t3) t3.Invert(t3)
t1.Mul(&a.y, t3) t1.Mul(&a.y, t3)
t1.Neg(t1) t1.Neg(t1)
t2.Mul(&a.x, t3) t2.MulNC(&a.x, t3)
gfp4Copy(e, tmp) gfp4Copy(e, tmp)
return e return e
@ -242,7 +315,7 @@ func (e *gfP4) Frobenius(a *gfP4) *gfP4 {
tmp := &gfP4{} tmp := &gfP4{}
x := &tmp.x x := &tmp.x
y := &tmp.y y := &tmp.y
x.Conjugate(&a.x) x.Conjugate(&a.x)
y.Conjugate(&a.y) y.Conjugate(&a.y)
x.MulScalar(x, vToPMinus1) x.MulScalar(x, vToPMinus1)

View File

@ -227,15 +227,12 @@ func GenerateGTFieldTable(basePoint *GT) *[32 * 2]GTFieldTable {
for j := 1; j < 15; j += 2 { for j := 1; j < 15; j += 2 {
table[i][j] = &GT{} table[i][j] = &GT{}
table[i][j].p = &gfP12{} table[i][j].p = &gfP12{}
table[i][j].p.Square(table[i][j/2].p) table[i][j].p.SquareNC(table[i][j/2].p)
table[i][j+1] = &GT{} table[i][j+1] = &GT{}
table[i][j+1].p = &gfP12{} table[i][j+1].p = &gfP12{}
table[i][j+1].Add(table[i][j], base) table[i][j+1].Add(table[i][j], base)
} }
base.p.Square(base.p) base.p.Squares(base.p, 4)
base.p.Square(base.p)
base.p.Square(base.p)
base.p.Square(base.p)
} }
return table return table
} }
@ -277,7 +274,7 @@ func ScalarMultGT(a *GT, scalar []byte) (*GT, error) {
for i := 1; i < 15; i += 2 { for i := 1; i < 15; i += 2 {
table[i] = &GT{} table[i] = &GT{}
table[i].p = &gfP12{} table[i].p = &gfP12{}
table[i].p.Square(table[i/2].p) table[i].p.SquareNC(table[i/2].p)
table[i+1] = &GT{} table[i+1] = &GT{}
table[i+1].p = &gfP12{} table[i+1].p = &gfP12{}
@ -292,18 +289,12 @@ func ScalarMultGT(a *GT, scalar []byte) (*GT, error) {
// No need to double on the first iteration, as p is the identity at // No need to double on the first iteration, as p is the identity at
// this point, and [N]∞ = ∞. // this point, and [N]∞ = ∞.
if i != 0 { if i != 0 {
e.p.Square(e.p) e.p.Squares(e.p, 4)
e.p.Square(e.p)
e.p.Square(e.p)
e.p.Square(e.p)
} }
windowValue := byte >> 4 windowValue := byte >> 4
table.Select(t, windowValue) table.Select(t, windowValue)
e.Add(e, t) e.Add(e, t)
e.p.Square(e.p) e.p.Squares(e.p, 4)
e.p.Square(e.p)
e.p.Square(e.p)
e.p.Square(e.p)
windowValue = byte & 0b1111 windowValue = byte & 0b1111
table.Select(t, windowValue) table.Select(t, windowValue)
e.Add(e, t) e.Add(e, t)

View File

@ -100,23 +100,23 @@ func (c *twistPoint) Add(a, b *twistPoint) {
} }
// See http://hyperelliptic.org/EFD/g1p/auto-code/shortw/jacobian-0/addition/add-2007-bl.op3 // See http://hyperelliptic.org/EFD/g1p/auto-code/shortw/jacobian-0/addition/add-2007-bl.op3
z12 := (&gfP2{}).Square(&a.z) z12 := (&gfP2{}).SquareNC(&a.z)
z22 := (&gfP2{}).Square(&b.z) z22 := (&gfP2{}).SquareNC(&b.z)
u1 := (&gfP2{}).Mul(&a.x, z22) u1 := (&gfP2{}).MulNC(&a.x, z22)
u2 := (&gfP2{}).Mul(&b.x, z12) u2 := (&gfP2{}).MulNC(&b.x, z12)
t := (&gfP2{}).Mul(&b.z, z22) t := (&gfP2{}).MulNC(&b.z, z22)
s1 := (&gfP2{}).Mul(&a.y, t) s1 := (&gfP2{}).MulNC(&a.y, t)
t.Mul(&a.z, z12) t.Mul(&a.z, z12)
s2 := (&gfP2{}).Mul(&b.y, t) s2 := (&gfP2{}).MulNC(&b.y, t)
h := (&gfP2{}).Sub(u2, u1) h := (&gfP2{}).Sub(u2, u1)
xEqual := h.IsZero() xEqual := h.IsZero()
t.Add(h, h) t.Add(h, h)
i := (&gfP2{}).Square(t) i := (&gfP2{}).SquareNC(t)
j := (&gfP2{}).Mul(h, i) j := (&gfP2{}).MulNC(h, i)
t.Sub(s2, s1) t.Sub(s2, s1)
yEqual := t.IsZero() yEqual := t.IsZero()
@ -126,9 +126,9 @@ func (c *twistPoint) Add(a, b *twistPoint) {
} }
r := (&gfP2{}).Add(t, t) r := (&gfP2{}).Add(t, t)
v := (&gfP2{}).Mul(u1, i) v := (&gfP2{}).MulNC(u1, i)
t4 := (&gfP2{}).Square(r) t4 := (&gfP2{}).SquareNC(r)
t.Add(v, v) t.Add(v, v)
t6 := (&gfP2{}).Sub(t4, j) t6 := (&gfP2{}).Sub(t4, j)
c.x.Sub(t6, t) c.x.Sub(t6, t)
@ -148,18 +148,18 @@ func (c *twistPoint) Add(a, b *twistPoint) {
func (c *twistPoint) Double(a *twistPoint) { func (c *twistPoint) Double(a *twistPoint) {
// See http://hyperelliptic.org/EFD/g1p/auto-code/shortw/jacobian-0/doubling/dbl-2009-l.op3 // See http://hyperelliptic.org/EFD/g1p/auto-code/shortw/jacobian-0/doubling/dbl-2009-l.op3
A := (&gfP2{}).Square(&a.x) A := (&gfP2{}).SquareNC(&a.x)
B := (&gfP2{}).Square(&a.y) B := (&gfP2{}).SquareNC(&a.y)
C := (&gfP2{}).Square(B) C := (&gfP2{}).SquareNC(B)
t := (&gfP2{}).Add(&a.x, B) t := (&gfP2{}).Add(&a.x, B)
t2 := (&gfP2{}).Square(t) t2 := (&gfP2{}).SquareNC(t)
t.Sub(t2, A) t.Sub(t2, A)
t2.Sub(t, C) t2.Sub(t, C)
d := (&gfP2{}).Add(t2, t2) d := (&gfP2{}).Add(t2, t2)
t.Add(A, A) t.Add(A, A)
e := (&gfP2{}).Add(t, A) e := (&gfP2{}).Add(t, A)
f := (&gfP2{}).Square(e) f := (&gfP2{}).SquareNC(e)
t.Add(d, d) t.Add(d, d)
c.x.Sub(f, t) c.x.Sub(f, t)
@ -201,8 +201,8 @@ func (c *twistPoint) MakeAffine() {
} }
zInv := (&gfP2{}).Invert(&c.z) zInv := (&gfP2{}).Invert(&c.z)
t := (&gfP2{}).Mul(&c.y, zInv) t := (&gfP2{}).MulNC(&c.y, zInv)
zInv2 := (&gfP2{}).Square(zInv) zInv2 := (&gfP2{}).SquareNC(zInv)
c.y.Mul(t, zInv2) c.y.Mul(t, zInv2)
t.Mul(&c.x, zInv2) t.Mul(&c.x, zInv2)
c.x.Set(t) c.x.Set(t)