github.com/cloudflare/circl@v1.5.0/ecc/fourq/fq.go (about)

     1  package fourq
     2  
     3  import (
     4  	"crypto/subtle"
     5  	"math/big"
     6  )
     7  
     8  // Fq implements operations of a field of size q=p^2 as a quadratic
     9  // extension of the base field where i^2=-1.
    10  // An element in Fq is represented as f[0]+f[1]*i, where f[0],f[1] are in Fp.
    11  type Fq [2]Fp
    12  
    13  func (e *Fq) String() string              { return e[1].String() + " *i+ " + e[0].String() }
    14  func (e *Fq) toBigInt() (f0, f1 *big.Int) { return e[0].toBigInt(), e[1].toBigInt() }
    15  func (e *Fq) setBigInt(f0, f1 *big.Int)   { e[0].setBigInt(f0); e[1].setBigInt(f1) }
    16  func (e *Fq) setZero()                    { var z Fp; e[0] = z; e[1] = z }
    17  func (e *Fq) setOne()                     { e.setZero(); e[0][0] = 1 }
    18  func (e *Fq) isZero() bool                { return e[0].isZero() && e[1].isZero() }
    19  
    20  func (e *Fq) toBytes(buf []byte) {
    21  	if len(buf) == 2*SizeFp {
    22  		e[0].toBytes(buf[:SizeFp])
    23  		e[1].toBytes(buf[SizeFp:])
    24  	}
    25  }
    26  
    27  func (e *Fq) fromBytes(buf []byte) bool {
    28  	if len(buf) == 2*SizeFp {
    29  		return e[0].fromBytes(buf[:SizeFp]) &&
    30  			e[1].fromBytes(buf[SizeFp:])
    31  	}
    32  	return false
    33  }
    34  
    35  func fqSgn(c *Fq) int {
    36  	s0 := fpSgn(&c[0])
    37  	s1 := fpSgn(&c[1])
    38  	return subtle.ConstantTimeSelect(s0&0x1, s0, s1)
    39  }
    40  func fqCopy(c, a *Fq) { *c = *a }
    41  func fqNeg(c, a *Fq)  { fpNeg(&c[0], &a[0]); fpNeg(&c[1], &a[1]) }
    42  
    43  // fqSqrt calculates c = sqrt(u/v) such that sgn(c)=s.
    44  func fqSqrt(c, u, v *Fq, s int) {
    45  	t0, t1, t, r := &Fp{}, &Fp{}, &Fp{}, &Fp{}
    46  	a, b, g := &Fp{}, &Fp{}, &Fp{}
    47  
    48  	// a = u0*v0 + u1*v1
    49  	fpMul(a, &u[0], &v[0])
    50  	fpMul(t0, &u[1], &v[1])
    51  	fpAdd(a, a, t0)
    52  
    53  	// b = v0^2 + v1^2
    54  	fpSqr(b, &v[0])
    55  	fpSqr(t0, &v[1])
    56  	fpAdd(b, b, t0)
    57  
    58  	// g = u1*v0 - u0*v1
    59  	fpMul(g, &u[1], &v[0])
    60  	fpMul(t0, &u[0], &v[1])
    61  	fpSub(g, g, t0)
    62  
    63  	// t = 2(a + sqrt(a^2+g^2)) = 2*(a + (a^2+g^2)^(2^125))
    64  	// if t=0; then t = 2*(a - (a^2+g^2)^(2^125))
    65  	fpSqr(t0, a)
    66  	fpSqr(t1, g)
    67  	fpAdd(t0, t0, t1)
    68  	for i := 0; i < 125; i++ {
    69  		fpSqr(t0, t0)
    70  	}
    71  	fpAdd(t, a, t0)
    72  	if t.isZero() {
    73  		fpSub(t, a, t0)
    74  	}
    75  	fpAdd(t, t, t)
    76  
    77  	// r = (t*b^3)^(2^125-1)
    78  	fpSqr(r, b)
    79  	fpMul(r, r, b)
    80  	fpMul(r, r, t)
    81  	fpTwo1251(r, r)
    82  
    83  	// x0 = (r*b*t)/2
    84  	// x1 = (r*b*g)
    85  	fpMul(&c[1], r, b)
    86  	fpMul(&c[0], &c[1], t)
    87  	fpHlf(&c[0], &c[0])
    88  	fpMul(&c[1], &c[1], g)
    89  
    90  	// if b*(2*x0)^2 == t then (x0,x1) <- (x1,x0)
    91  	fpAdd(t0, &c[0], &c[0])
    92  	fpSqr(t0, t0)
    93  	fpMul(t0, t0, b)
    94  	fpSub(t0, t0, t)
    95  	if !t0.isZero() {
    96  		*t0 = c[0]
    97  		c[0] = c[1]
    98  		c[1] = *t0
    99  	}
   100  
   101  	if fqSgn(c) != s {
   102  		fqNeg(c, c)
   103  	}
   104  }
   105  
   106  func fqInv(c, a *Fq) {
   107  	t1, t2 := &Fp{}, &Fp{}
   108  	fpSqr(t1, &a[0])
   109  	fpSqr(t2, &a[1])
   110  	fpAdd(t1, t1, t2)
   111  	fpInv(t1, t1)
   112  	fpMul(&c[0], &a[0], t1)
   113  	fpNeg(t1, t1)
   114  	fpMul(&c[1], &a[1], t1)
   115  }