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

     1  package ff
     2  
     3  import (
     4  	"io"
     5  
     6  	"github.com/cloudflare/circl/internal/conv"
     7  )
     8  
     9  // ScalarSize is the length in bytes of a Scalar.
    10  const ScalarSize = 32
    11  
    12  // scMont represents an element in the Montgomery domain (little-endian).
    13  type scMont = [ScalarSize / 8]uint64
    14  
    15  // scRaw represents a scalar in the integers domain (little-endian).
    16  type scRaw = [ScalarSize / 8]uint64
    17  
    18  // Scalar represents positive integers less than ScalarOrder.
    19  type Scalar struct{ i scMont }
    20  
    21  func (z Scalar) String() string            { x := z.fromMont(); return conv.Uint64Le2Hex(x[:]) }
    22  func (z *Scalar) Set(x *Scalar)            { z.i = x.i }
    23  func (z *Scalar) SetUint64(n uint64)       { z.toMont(&scRaw{n}) }
    24  func (z *Scalar) SetOne()                  { z.SetUint64(1) }
    25  func (z *Scalar) Random(r io.Reader) error { return randomInt(z.i[:], r, scOrder[:]) }
    26  func (z Scalar) IsZero() int               { return ctUint64Eq(z.i[:], (&scMont{})[:]) }
    27  func (z Scalar) IsEqual(x *Scalar) int     { return ctUint64Eq(z.i[:], x.i[:]) }
    28  func (z *Scalar) Neg()                     { fiatScMontSub(&z.i, &scMont{}, &z.i) }
    29  func (z *Scalar) Add(x, y *Scalar)         { fiatScMontAdd(&z.i, &x.i, &y.i) }
    30  func (z *Scalar) Sub(x, y *Scalar)         { fiatScMontSub(&z.i, &x.i, &y.i) }
    31  func (z *Scalar) Mul(x, y *Scalar)         { fiatScMontMul(&z.i, &x.i, &y.i) }
    32  func (z *Scalar) Sqr(x *Scalar)            { fiatScMontSquare(&z.i, &x.i) }
    33  func (z *Scalar) Inv(x *Scalar)            { z.expVarTime(x, scOrderMinus2[:]) }
    34  func (z *Scalar) toMont(in *scRaw)         { fiatScMontMul(&z.i, in, &scRSquare) }
    35  func (z Scalar) fromMont() (out scRaw)     { fiatScMontMul(&out, &z.i, &scMont{1}); return }
    36  
    37  // ScalarOrder is the order of the scalar field of the pairing groups, order is
    38  // returned as a big-endian slice.
    39  //
    40  //	ScalarOrder = 0x73eda753299d7d483339d80809a1d80553bda402fffe5bfeffffffff00000001
    41  func ScalarOrder() []byte { o := scOrder; return o[:] }
    42  
    43  // exp calculates z=x^n, where n is in big-endian order.
    44  func (z *Scalar) expVarTime(x *Scalar, n []byte) {
    45  	zz := new(Scalar)
    46  	zz.SetOne()
    47  	N := 8 * len(n)
    48  	for i := 0; i < N; i++ {
    49  		zz.Sqr(zz)
    50  		bit := 0x1 & (n[i/8] >> uint(7-i%8))
    51  		if bit != 0 {
    52  			zz.Mul(zz, x)
    53  		}
    54  	}
    55  	z.Set(zz)
    56  }
    57  
    58  // SetBytes assigns to z the number modulo ScalarOrder stored in the slice
    59  // (in big-endian order).
    60  func (z *Scalar) SetBytes(data []byte) {
    61  	in64 := setBytesUnbounded(data, scOrder[:])
    62  	s := &scRaw{}
    63  	copy(s[:], in64[:ScalarSize/8])
    64  	z.toMont(s)
    65  }
    66  
    67  // MarshalBinary returns a slice of ScalarSize bytes that contains the minimal
    68  // residue of z such that 0 <= z < ScalarOrder (in big-endian order).
    69  func (z *Scalar) MarshalBinary() ([]byte, error) {
    70  	x := z.fromMont()
    71  	return conv.Uint64Le2BytesBe(x[:]), nil
    72  }
    73  
    74  // UnmarshalBinary reconstructs a Scalar from a slice that must have at least
    75  // ScalarSize bytes and contain a number (in big-endian order) from 0
    76  // to ScalarOrder-1.
    77  func (z *Scalar) UnmarshalBinary(data []byte) error {
    78  	if len(data) < ScalarSize {
    79  		return errInputLength
    80  	}
    81  	in64, err := setBytesBounded(data[:ScalarSize], scOrder[:])
    82  	if err == nil {
    83  		s := &scRaw{}
    84  		copy(s[:], in64[:ScalarSize/8])
    85  		z.toMont(s)
    86  	}
    87  	return err
    88  }
    89  
    90  // SetString reconstructs a Fp from a numeric string from 0 to ScalarOrder-1.
    91  func (z *Scalar) SetString(s string) error {
    92  	in64, err := setString(s, scOrder[:])
    93  	if err == nil {
    94  		s := &scRaw{}
    95  		copy(s[:], in64[:ScalarSize/8])
    96  		z.toMont(s)
    97  	}
    98  	return err
    99  }
   100  
   101  func fiatScMontCmovznzU64(z *uint64, b, x, y uint64) { cselectU64(z, b, x, y) }
   102  
   103  var (
   104  	// scOrder is the order of the Scalar field (big-endian).
   105  	scOrder = [ScalarSize]byte{
   106  		0x73, 0xed, 0xa7, 0x53, 0x29, 0x9d, 0x7d, 0x48,
   107  		0x33, 0x39, 0xd8, 0x08, 0x09, 0xa1, 0xd8, 0x05,
   108  		0x53, 0xbd, 0xa4, 0x02, 0xff, 0xfe, 0x5b, 0xfe,
   109  		0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x01,
   110  	}
   111  	// scOrderMinus2 is the scOrder minus two used for inversion (big-endian).
   112  	scOrderMinus2 = [ScalarSize]byte{
   113  		0x73, 0xed, 0xa7, 0x53, 0x29, 0x9d, 0x7d, 0x48,
   114  		0x33, 0x39, 0xd8, 0x08, 0x09, 0xa1, 0xd8, 0x05,
   115  		0x53, 0xbd, 0xa4, 0x02, 0xff, 0xfe, 0x5b, 0xfe,
   116  		0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xff,
   117  	}
   118  	// scRSquare is R^2 mod scOrder, where R=2^256 (little-endian).
   119  	scRSquare = scMont{
   120  		0xc999e990f3f29c6d, 0x2b6cedcb87925c23,
   121  		0x05d314967254398f, 0x0748d9d99f59ff11,
   122  	}
   123  )