github.com/cloudflare/circl@v1.5.0/ecc/bls12381/ff/fp.go (about)

     1  package ff
     2  
     3  import (
     4  	"io"
     5  
     6  	"github.com/cloudflare/circl/internal/conv"
     7  )
     8  
     9  // FpSize is the length in bytes of an Fp element.
    10  const FpSize = 48
    11  
    12  // fpMont represents an element in the Montgomery domain (little-endian).
    13  type fpMont = [FpSize / 8]uint64
    14  
    15  // fpRaw represents an element in the integers domain (little-endian).
    16  type fpRaw = [FpSize / 8]uint64
    17  
    18  // Fp represents prime field elements as positive integers less than FpOrder.
    19  type Fp struct{ i fpMont }
    20  
    21  func (z Fp) String() string            { x := z.fromMont(); return conv.Uint64Le2Hex(x[:]) }
    22  func (z *Fp) SetUint64(n uint64)       { z.toMont(&fpRaw{n}) }
    23  func (z *Fp) SetOne()                  { z.SetUint64(1) }
    24  func (z *Fp) Random(r io.Reader) error { return randomInt(z.i[:], r, fpOrder[:]) }
    25  
    26  // IsNegative returns 0 if the least absolute residue for z is in [0,(p-1)/2],
    27  // and 1 otherwise. Equivalently, this function returns 1 if z is
    28  // lexicographically larger than -z.
    29  func (z Fp) IsNegative() int {
    30  	b, _ := z.MarshalBinary()
    31  	return 1 - isLessThan(b, fpOrderPlus1Div2[:])
    32  }
    33  
    34  // IsZero returns 1 if z == 0 and 0 otherwise.
    35  func (z Fp) IsZero() int { return ctUint64Eq(z.i[:], (&fpMont{})[:]) }
    36  
    37  // IsEqual returns 1 if z == x and 0 otherwise.
    38  func (z Fp) IsEqual(x *Fp) int     { return ctUint64Eq(z.i[:], x.i[:]) }
    39  func (z *Fp) Neg()                 { fiatFpMontSub(&z.i, &fpMont{}, &z.i) }
    40  func (z *Fp) Add(x, y *Fp)         { fiatFpMontAdd(&z.i, &x.i, &y.i) }
    41  func (z *Fp) Sub(x, y *Fp)         { fiatFpMontSub(&z.i, &x.i, &y.i) }
    42  func (z *Fp) Mul(x, y *Fp)         { fiatFpMontMul(&z.i, &x.i, &y.i) }
    43  func (z *Fp) Sqr(x *Fp)            { fiatFpMontSquare(&z.i, &x.i) }
    44  func (z *Fp) toMont(in *fpRaw)     { fiatFpMontMul(&z.i, in, &fpRSquare) }
    45  func (z Fp) fromMont() (out fpRaw) { fiatFpMontMul(&out, &z.i, &fpMont{1}); return }
    46  func (z Fp) Sgn0() int             { return int(z.fromMont()[0]) & 1 }
    47  
    48  // Sqrt returns 1 and sets z=sqrt(x) only if x is a quadratic-residue; otherwise, returns 0 and z is unmodified.
    49  func (z *Fp) Sqrt(x *Fp) int {
    50  	var y, y2 Fp
    51  	y.ExpVarTime(x, fpOrderPlus1Div4[:])
    52  	y2.Sqr(&y)
    53  	isQR := y2.IsEqual(x)
    54  	z.CMov(z, &y, isQR)
    55  	return isQR
    56  }
    57  
    58  // CMov sets z=x if b == 0 and z=y if b == 1. Its behavior is undefined if b takes any other value.
    59  func (z *Fp) CMov(x, y *Fp, b int) {
    60  	mask := -uint64(b & 0x1)
    61  	for i := 0; i < FpSize/8; i++ {
    62  		z.i[i] = (x.i[i] &^ mask) | (y.i[i] & mask)
    63  	}
    64  }
    65  
    66  // FpOrder is the order of the base field for towering returned as a big-endian slice.
    67  //
    68  //	FpOrder = 0x1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffaaab.
    69  func FpOrder() []byte { o := fpOrder; return o[:] }
    70  
    71  // ExpVarTime calculates z=x^n, where n is the exponent in big-endian order.
    72  func (z *Fp) ExpVarTime(x *Fp, n []byte) {
    73  	zz := new(Fp)
    74  	zz.SetOne()
    75  	N := 8 * len(n)
    76  	for i := 0; i < N; i++ {
    77  		zz.Sqr(zz)
    78  		bit := 0x1 & (n[i/8] >> uint(7-i%8))
    79  		if bit != 0 {
    80  			zz.Mul(zz, x)
    81  		}
    82  	}
    83  	*z = *zz
    84  }
    85  
    86  // SetBytes assigns to z the number modulo FpOrder stored in the slice
    87  // (in big-endian order).
    88  func (z *Fp) SetBytes(data []byte) {
    89  	in64 := setBytesUnbounded(data, fpOrder[:])
    90  	s := &fpRaw{}
    91  	copy(s[:], in64[:FpSize/8])
    92  	z.toMont(s)
    93  }
    94  
    95  // MarshalBinary returns a slice of FpSize bytes that contains the minimal
    96  // residue of z such that 0 <= z < FpOrder (in big-endian order).
    97  func (z *Fp) MarshalBinary() ([]byte, error) {
    98  	x := z.fromMont()
    99  	return conv.Uint64Le2BytesBe(x[:]), nil
   100  }
   101  
   102  // UnmarshalBinary reconstructs a Fp from a slice that must have at least
   103  // FpSize bytes and contain a number (in big-endian order) from 0
   104  // to FpOrder-1.
   105  func (z *Fp) UnmarshalBinary(b []byte) error {
   106  	if len(b) < FpSize {
   107  		return errInputLength
   108  	}
   109  	in64, err := setBytesBounded(b[:FpSize], fpOrder[:])
   110  	if err == nil {
   111  		s := &fpRaw{}
   112  		copy(s[:], in64[:FpSize/8])
   113  		z.toMont(s)
   114  	}
   115  	return err
   116  }
   117  
   118  // SetString reconstructs a Fp from a numeric string from 0 to FpOrder-1.
   119  func (z *Fp) SetString(s string) error {
   120  	in64, err := setString(s, fpOrder[:])
   121  	if err == nil {
   122  		s := &fpRaw{}
   123  		copy(s[:], in64[:FpSize/8])
   124  		z.toMont(s)
   125  	}
   126  	return err
   127  }
   128  
   129  func fiatFpMontCmovznzU64(z *uint64, b, x, y uint64) { cselectU64(z, b, x, y) }
   130  
   131  func (z *Fp) Inv(x *Fp) {
   132  	// Addition chain found using mmcloughlin/addchain: v0.3.0
   133  	// McLoughlin, Michael Ben. (2021). https://doi.org/10.5281/zenodo.4758226
   134  	var i2, i4, i8, i9, i11, i13, i17, i20, i25, i26, i52, i54, i55, i77, i79,
   135  		i86, i93, i103, i105, i119, i123, i137, i149, i151, i169, i177, i191,
   136  		i195, i208, i215, i225, i229, i235, i245, i255 Fp
   137  
   138  	i2.Sqr(x)
   139  	i4.Sqr(&i2)
   140  	i8.Sqr(&i4)
   141  	i9.Mul(&i8, x)
   142  	i11.Mul(&i9, &i2)
   143  	i13.Mul(&i11, &i2)
   144  	i17.Mul(&i13, &i4)
   145  	i20.Mul(&i11, &i9)
   146  	i25.Mul(&i17, &i8)
   147  	i26.Mul(&i25, x)
   148  	i52.Sqr(&i26)
   149  	i54.Mul(&i52, &i2)
   150  	i55.Mul(&i54, x)
   151  	i77.Mul(&i52, &i25)
   152  	i79.Mul(&i77, &i2)
   153  	i86.Mul(&i77, &i8)
   154  	i93.Mul(&i86, &i8)
   155  	i103.Mul(&i77, &i26)
   156  	i105.Mul(&i103, &i2)
   157  	i119.Mul(&i93, &i26)
   158  	i123.Mul(&i119, &i4)
   159  	i137.Mul(&i86, &i52)
   160  	i149.Mul(&i123, &i26)
   161  	i151.Mul(&i149, &i2)
   162  	i169.Mul(&i149, &i20)
   163  	i177.Mul(&i169, &i8)
   164  	i191.Mul(&i137, &i54)
   165  	i195.Mul(&i191, &i4)
   166  	i208.Mul(&i195, &i13)
   167  	i215.Mul(&i195, &i20)
   168  	i225.Mul(&i208, &i17)
   169  	i229.Mul(&i225, &i4)
   170  	i235.Mul(&i215, &i20)
   171  	i245.Mul(&i225, &i20)
   172  	i255.Mul(&i235, &i20)
   173  	z.Mul(&i225, &i191)
   174  
   175  	for _, s := range []struct {
   176  		l int
   177  		x *Fp
   178  	}{
   179  		{8, &i17},
   180  		{11, &i245},
   181  		{11, &i229},
   182  		{8, &i255},
   183  		{7, &i77},
   184  		{9, &i105},
   185  		{10, &i177},
   186  		{7, &i93},
   187  		{9, &i123},
   188  		{6, &i25},
   189  		{11, &i105},
   190  		{9, &i235},
   191  		{10, &i215},
   192  		{6, &i25},
   193  		{10, &i119},
   194  		{9, &i151},
   195  		{11, &i79},
   196  		{10, &i225},
   197  		{9, &i137},
   198  		{9, &i191},
   199  		{8, &i103},
   200  		{10, &i195},
   201  		{9, &i149},
   202  		{12, &i123},
   203  		{5, &i11},
   204  		{11, &i123},
   205  		{7, &i9},
   206  		{13, &i245},
   207  		{9, &i191},
   208  		{8, &i255},
   209  		{8, &i235},
   210  		{11, &i169},
   211  		{8, &i255},
   212  		{8, &i255},
   213  		{6, &i55},
   214  		{10, &i255},
   215  		{9, &i255},
   216  		{8, &i255},
   217  		{8, &i255},
   218  		{8, &i255},
   219  		{7, &i86},
   220  		{9, &i169},
   221  	} {
   222  		for i := 0; i < s.l; i++ {
   223  			z.Sqr(z)
   224  		}
   225  		z.Mul(z, s.x)
   226  	}
   227  }
   228  
   229  var (
   230  	// fpOrder is the order of the Fp field (big-endian).
   231  	fpOrder = [FpSize]byte{
   232  		0x1a, 0x01, 0x11, 0xea, 0x39, 0x7f, 0xe6, 0x9a,
   233  		0x4b, 0x1b, 0xa7, 0xb6, 0x43, 0x4b, 0xac, 0xd7,
   234  		0x64, 0x77, 0x4b, 0x84, 0xf3, 0x85, 0x12, 0xbf,
   235  		0x67, 0x30, 0xd2, 0xa0, 0xf6, 0xb0, 0xf6, 0x24,
   236  		0x1e, 0xab, 0xff, 0xfe, 0xb1, 0x53, 0xff, 0xff,
   237  		0xb9, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xaa, 0xab,
   238  	}
   239  	// fpOrderPlus1Div2 is the half of (fpOrder plus one) used for lexicographically order (big-endian).
   240  	fpOrderPlus1Div2 = [FpSize]byte{
   241  		0x0d, 0x00, 0x88, 0xf5, 0x1c, 0xbf, 0xf3, 0x4d,
   242  		0x25, 0x8d, 0xd3, 0xdb, 0x21, 0xa5, 0xd6, 0x6b,
   243  		0xb2, 0x3b, 0xa5, 0xc2, 0x79, 0xc2, 0x89, 0x5f,
   244  		0xb3, 0x98, 0x69, 0x50, 0x7b, 0x58, 0x7b, 0x12,
   245  		0x0f, 0x55, 0xff, 0xff, 0x58, 0xa9, 0xff, 0xff,
   246  		0xdc, 0xff, 0x7f, 0xff, 0xff, 0xff, 0xd5, 0x56,
   247  	}
   248  	// fpOrderPlus1Div4 is (fpOrder plus one) divided by four used for square-roots (big-endian).
   249  	fpOrderPlus1Div4 = [FpSize]byte{
   250  		0x06, 0x80, 0x44, 0x7a, 0x8e, 0x5f, 0xf9, 0xa6,
   251  		0x92, 0xc6, 0xe9, 0xed, 0x90, 0xd2, 0xeb, 0x35,
   252  		0xd9, 0x1d, 0xd2, 0xe1, 0x3c, 0xe1, 0x44, 0xaf,
   253  		0xd9, 0xcc, 0x34, 0xa8, 0x3d, 0xac, 0x3d, 0x89,
   254  		0x07, 0xaa, 0xff, 0xff, 0xac, 0x54, 0xff, 0xff,
   255  		0xee, 0x7f, 0xbf, 0xff, 0xff, 0xff, 0xea, 0xab,
   256  	}
   257  	// fpRSquare is R^2 mod fpOrder, where R=2^384 (little-endian).
   258  	fpRSquare = fpMont{
   259  		0xf4df1f341c341746, 0x0a76e6a609d104f1,
   260  		0x8de5476c4c95b6d5, 0x67eb88a9939d83c0,
   261  		0x9a793e85b519952d, 0x11988fe592cae3aa,
   262  	}
   263  )