github.com/cloudflare/circl@v1.5.0/ecc/bls12381/ff/fp2.go (about) 1 package ff 2 3 import "fmt" 4 5 // Fp2Size is the length in bytes of an Fp2 element. 6 const Fp2Size = 2 * FpSize 7 8 type Fp2 [2]Fp 9 10 func (z Fp2) String() string { return fmt.Sprintf("0: %v\n1: %v", z[0], z[1]) } 11 func (z *Fp2) SetOne() { z[0].SetOne(); z[1] = Fp{} } 12 13 // IsNegative returns 1 if z is lexicographically larger than -z; otherwise returns 0. 14 func (z Fp2) IsNegative() int { return z[1].IsNegative() | (z[1].IsZero() & z[0].IsNegative()) } 15 func (z Fp2) IsZero() int { return z.IsEqual(&Fp2{}) } 16 func (z Fp2) IsEqual(x *Fp2) int { return z[0].IsEqual(&x[0]) & z[1].IsEqual(&x[1]) } 17 func (z *Fp2) MulBeta() { t := z[0]; z[0].Sub(&z[0], &z[1]); z[1].Add(&t, &z[1]) } 18 func (z *Fp2) Frob(x *Fp2) { *z = *x; z.Cjg() } 19 func (z *Fp2) Cjg() { z[1].Neg() } 20 func (z *Fp2) Neg() { z[0].Neg(); z[1].Neg() } 21 func (z *Fp2) Add(x, y *Fp2) { z[0].Add(&x[0], &y[0]); z[1].Add(&x[1], &y[1]) } 22 func (z *Fp2) Sub(x, y *Fp2) { z[0].Sub(&x[0], &y[0]); z[1].Sub(&x[1], &y[1]) } 23 func (z *Fp2) Mul(x, y *Fp2) { 24 var x0y0, x1y1, sx, sy, k Fp 25 x0y0.Mul(&x[0], &y[0]) 26 x1y1.Mul(&x[1], &y[1]) 27 sx.Add(&x[0], &x[1]) 28 sy.Add(&y[0], &y[1]) 29 k.Mul(&sx, &sy) 30 z[0].Sub(&x0y0, &x1y1) 31 z[1].Sub(&k, &x0y0) 32 z[1].Sub(&z[1], &x1y1) 33 } 34 35 func (z *Fp2) Sqr(x *Fp2) { 36 var x02, x12, k Fp 37 x02.Sqr(&x[0]) 38 x12.Sqr(&x[1]) 39 k.Mul(&x[0], &x[1]) 40 z[0].Sub(&x02, &x12) 41 z[1].Add(&k, &k) 42 } 43 44 func (z *Fp2) Inv(x *Fp2) { 45 var x02, x12, den Fp 46 x02.Sqr(&x[0]) 47 x12.Sqr(&x[1]) 48 den.Add(&x02, &x12) 49 den.Inv(&den) 50 z[0].Mul(&x[0], &den) 51 z[1].Mul(&x[1], &den) 52 z[1].Neg() 53 } 54 55 func (z Fp2) Sgn0() int { 56 s0, s1 := z[0].Sgn0(), z[1].Sgn0() 57 z0 := z[0].IsZero() 58 return s0 | (z0 & s1) 59 } 60 61 func (z *Fp2) UnmarshalBinary(b []byte) error { 62 if len(b) < Fp2Size { 63 return errInputLength 64 } 65 return errFirst( 66 z[1].UnmarshalBinary(b[:FpSize]), 67 z[0].UnmarshalBinary(b[FpSize:2*FpSize]), 68 ) 69 } 70 71 func (z Fp2) MarshalBinary() (b []byte, e error) { 72 var b0, b1 []byte 73 if b1, e = z[1].MarshalBinary(); e == nil { 74 if b0, e = z[0].MarshalBinary(); e == nil { 75 return append(b1, b0...), e 76 } 77 } 78 return 79 } 80 81 // SetString reconstructs a Fp2 element as s0+s1*i, where s0 and s1 are numeric 82 // strings from 0 to FpOrder-1. 83 func (z *Fp2) SetString(s0, s1 string) (err error) { 84 if err = z[0].SetString(s0); err == nil { 85 err = z[1].SetString(s1) 86 } 87 return 88 } 89 90 func (z *Fp2) CMov(x, y *Fp2, b int) { 91 z[0].CMov(&x[0], &y[0], b) 92 z[1].CMov(&x[1], &y[1], b) 93 } 94 95 // ExpVarTime calculates z=x^n, where n is the exponent in big-endian order. 96 func (z *Fp2) ExpVarTime(x *Fp2, n []byte) { 97 zz := new(Fp2) 98 zz.SetOne() 99 N := 8 * len(n) 100 for i := 0; i < N; i++ { 101 zz.Sqr(zz) 102 bit := 0x1 & (n[i/8] >> uint(7-i%8)) 103 if bit != 0 { 104 zz.Mul(zz, x) 105 } 106 } 107 *z = *zz 108 } 109 110 // Sqrt returns 1 and sets z=sqrt(x) only if x is a quadratic-residue; otherwise, returns 0 and z is unmodified. 111 func (z *Fp2) Sqrt(x *Fp2) int { 112 // "Square-root for q = p^2 = 9 (mod 16)" Appendix I.3 of Hashing to elliptic curves. 113 // https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-hash-to-curve-11#appendix-I.3 114 var t, tv1, tv2, tv3, tv4 Fp2 115 tv1.ExpVarTime(x, fp2SqrtConst.c4[:]) 116 tv2.Mul(&fp2SqrtConst.c1, &tv1) 117 tv3.Mul(&fp2SqrtConst.c2, &tv1) 118 tv4.Mul(&fp2SqrtConst.c3, &tv1) 119 120 t.Sqr(&tv1) 121 e1 := t.IsEqual(x) 122 z.CMov(z, &tv1, e1) 123 124 t.Sqr(&tv2) 125 e2 := t.IsEqual(x) 126 z.CMov(z, &tv2, e2) 127 128 t.Sqr(&tv3) 129 e3 := t.IsEqual(x) 130 z.CMov(z, &tv3, e3) 131 132 t.Sqr(&tv4) 133 e4 := t.IsEqual(x) 134 z.CMov(z, &tv4, e4) 135 136 return e1 | e2 | e3 | e4 137 } 138 139 var fp2SqrtConst = struct { 140 // "Square-root for q = p^2 = 9 (mod 16)" Appendix I.3 of Hashing to elliptic curves. 141 // https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-hash-to-curve-11#appendix-I.3 142 c1 Fp2 // c1 = sqrt( -1) = u 143 c2 Fp2 // c2 = sqrt( c1) 144 c3 Fp2 // c3 = sqrt(-c1) 145 c4 [95]byte // c4 = (p^2 + 7) / 16 (big-endian) 146 }{ 147 c1: Fp2{ // (little-endian) 148 Fp{fpMont{}}, 149 Fp{fpMont{0x760900000002fffd, 0xebf4000bc40c0002, 0x5f48985753c758ba, 0x77ce585370525745, 0x5c071a97a256ec6d, 0x15f65ec3fa80e493}}, 150 }, 151 c2: Fp2{ // (little-endian) 152 Fp{fpMont{0x3e2f585da55c9ad1, 0x4294213d86c18183, 0x382844c88b623732, 0x92ad2afd19103e18, 0x1d794e4fac7cf0b9, 0x0bd592fc7d825ec8}}, 153 Fp{fpMont{0x7bcfa7a25aa30fda, 0xdc17dec12a927e7c, 0x2f088dd86b4ebef1, 0xd1ca2087da74d4a7, 0x2da2596696cebc1d, 0x0e2b7eedbbfd87d2}}, 154 }, 155 c3: Fp2{ // (little-endian) 156 Fp{fpMont{0x7bcfa7a25aa30fda, 0xdc17dec12a927e7c, 0x2f088dd86b4ebef1, 0xd1ca2087da74d4a7, 0x2da2596696cebc1d, 0x0e2b7eedbbfd87d2}}, 157 Fp{fpMont{0x7bcfa7a25aa30fda, 0xdc17dec12a927e7c, 0x2f088dd86b4ebef1, 0xd1ca2087da74d4a7, 0x2da2596696cebc1d, 0x0e2b7eedbbfd87d2}}, 158 }, 159 c4: [95]byte{ // (big-endian) 160 0x2a, 0x43, 0x7a, 0x4b, 0x8c, 0x35, 0xfc, 0x74, 0xbd, 0x27, 0x8e, 0xaa, 161 0x22, 0xf2, 0x5e, 0x9e, 0x2d, 0xc9, 0x0e, 0x50, 0xe7, 0x04, 0x6b, 0x46, 162 0x6e, 0x59, 0xe4, 0x93, 0x49, 0xe8, 0xbd, 0x05, 0x0a, 0x62, 0xcf, 0xd1, 163 0x6d, 0xdc, 0xa6, 0xef, 0x53, 0x14, 0x93, 0x30, 0x97, 0x8e, 0xf0, 0x11, 164 0xd6, 0x86, 0x19, 0xc8, 0x61, 0x85, 0xc7, 0xb2, 0x92, 0xe8, 0x5a, 0x87, 165 0x09, 0x1a, 0x04, 0x96, 0x6b, 0xf9, 0x1e, 0xd3, 0xe7, 0x1b, 0x74, 0x31, 166 0x62, 0xc3, 0x38, 0x36, 0x21, 0x13, 0xcf, 0xd7, 0xce, 0xd6, 0xb1, 0xd7, 167 0x63, 0x82, 0xea, 0xb2, 0x6a, 0xa0, 0x00, 0x01, 0xc7, 0x18, 0xe4, 168 }, 169 }