github.com/emmansun/gmsm@v0.29.1/sm9/bn256/gfp.go (about)

     1  package bn256
     2  
     3  import (
     4  	"encoding/binary"
     5  	"errors"
     6  	"fmt"
     7  	"math/big"
     8  	"math/bits"
     9  )
    10  
    11  type gfP [4]uint64
    12  
    13  var zero = newGFp(0)
    14  var one = newGFp(1)
    15  var two = newGFp(2)
    16  
    17  func newGFp(x int64) (out *gfP) {
    18  	if x >= 0 {
    19  		out = &gfP{uint64(x)}
    20  	} else {
    21  		out = &gfP{uint64(-x)}
    22  		gfpNeg(out, out)
    23  	}
    24  
    25  	montEncode(out, out)
    26  	return out
    27  }
    28  
    29  func fromBigInt(x *big.Int) (out *gfP) {
    30  	out = &gfP{}
    31  	var a *big.Int
    32  	if x.Sign() >= 0 {
    33  		a = x
    34  	} else {
    35  		a = new(big.Int).Neg(x)
    36  	}
    37  	bytes := a.Bytes()
    38  	if len(bytes) > 32 {
    39  		panic("sm9: invalid byte length")
    40  	} else if len(bytes) < 32 {
    41  		fixedBytes := make([]byte, 32)
    42  		copy(fixedBytes[32-len(bytes):], bytes)
    43  		bytes = fixedBytes
    44  	}
    45  	for i := 0; i < 4; i++ {
    46  		start := len(bytes) - 8
    47  		out[i] = binary.BigEndian.Uint64(bytes[start:])
    48  		bytes = bytes[:start]
    49  	}
    50  	if x.Sign() < 0 {
    51  		gfpNeg(out, out)
    52  	}
    53  	if x.Sign() != 0 {
    54  		montEncode(out, out)
    55  	}
    56  	return out
    57  }
    58  
    59  func (e *gfP) String() string {
    60  	return fmt.Sprintf("%16.16x%16.16x%16.16x%16.16x", e[3], e[2], e[1], e[0])
    61  }
    62  
    63  func (e *gfP) Set(f *gfP) *gfP {
    64  	gfpCopy(e, f)
    65  	return e
    66  }
    67  
    68  func (e *gfP) exp(f *gfP, bits [4]uint64) {
    69  	sum, power := &gfP{}, &gfP{}
    70  	sum.Set(rN1)
    71  	power.Set(f)
    72  
    73  	for word := 0; word < 4; word++ {
    74  		for bit := uint(0); bit < 64; bit++ {
    75  			if (bits[word]>>bit)&1 == 1 {
    76  				gfpMul(sum, sum, power)
    77  			}
    78  			gfpSqr(power, power, 1)
    79  		}
    80  	}
    81  
    82  	gfpMul(sum, sum, r3)
    83  	e.Set(sum)
    84  }
    85  
    86  func (e *gfP) Mul(a, b *gfP) *gfP {
    87  	gfpMul(e, a, b)
    88  	return e
    89  }
    90  
    91  func (e *gfP) Square(a *gfP, n int) *gfP {
    92  	gfpSqr(e, a, n)
    93  	return e
    94  }
    95  
    96  // Equal returns 1 if e == t, and zero otherwise.
    97  func (e *gfP) Equal(t *gfP) int {
    98  	var acc uint64
    99  	for i := range e {
   100  		acc |= e[i] ^ t[i]
   101  	}
   102  	return uint64IsZero(acc)
   103  }
   104  
   105  func (e *gfP) Sqrt(f *gfP) {
   106  	// Since p = 8k+5,
   107  	// Atkin algorithm
   108  	// https://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.896.6057&rep=rep1&type=pdf
   109  	// https://eprint.iacr.org/2012/685.pdf
   110  	//
   111  	a1, b, i := &gfP{}, &gfP{}, &gfP{}
   112  	sqrtCandidate(a1, f)
   113  	gfpMul(b, twoExpPMinus5Over8, a1) // b=ta1
   114  	gfpMul(a1, f, b)                  // a1=fb
   115  	gfpMul(i, two, a1)                // i=2(fb)
   116  	gfpMul(i, i, b)                   // i=2(fb)b
   117  	gfpSub(i, i, one)                 // i=2(fb)b-1
   118  	gfpMul(i, a1, i)                  // i=(fb)(2(fb)b-1)
   119  	e.Set(i)
   120  }
   121  
   122  func (e *gfP) Marshal(out []byte) {
   123  	gfpMarshal((*[32]byte)(out), e)
   124  }
   125  
   126  // uint64IsZero returns 1 if x is zero and zero otherwise.
   127  func uint64IsZero(x uint64) int {
   128  	x = ^x
   129  	x &= x >> 32
   130  	x &= x >> 16
   131  	x &= x >> 8
   132  	x &= x >> 4
   133  	x &= x >> 2
   134  	x &= x >> 1
   135  	return int(x & 1)
   136  }
   137  
   138  func lessThanP(x *gfP) int {
   139  	var b uint64
   140  	_, b = bits.Sub64(x[0], p2[0], b)
   141  	_, b = bits.Sub64(x[1], p2[1], b)
   142  	_, b = bits.Sub64(x[2], p2[2], b)
   143  	_, b = bits.Sub64(x[3], p2[3], b)
   144  	return int(b)
   145  }
   146  
   147  func (e *gfP) Unmarshal(in []byte) error {
   148  	gfpUnmarshal(e, (*[32]byte)(in))
   149  	// Ensure the point respects the curve modulus
   150  	// TODO: Do we need to change it to constant time version ?
   151  	for i := 3; i >= 0; i-- {
   152  		if e[i] < p2[i] {
   153  			return nil
   154  		}
   155  		if e[i] > p2[i] {
   156  			return errors.New("sm9: coordinate exceeds modulus")
   157  		}
   158  	}
   159  	return errors.New("sm9: coordinate equals modulus")
   160  }
   161  
   162  func montEncode(c, a *gfP) { gfpMul(c, a, r2) }
   163  func montDecode(c, a *gfP) { gfpFromMont(c, a) }
   164  
   165  // cmovznzU64 is a single-word conditional move.
   166  //
   167  // Postconditions:
   168  //
   169  //	out1 = (if arg1 = 0 then arg2 else arg3)
   170  //
   171  // Input Bounds:
   172  //
   173  //	arg1: [0x0 ~> 0x1]
   174  //	arg2: [0x0 ~> 0xffffffffffffffff]
   175  //	arg3: [0x0 ~> 0xffffffffffffffff]
   176  //
   177  // Output Bounds:
   178  //
   179  //	out1: [0x0 ~> 0xffffffffffffffff]
   180  func cmovznzU64(out1 *uint64, arg1 uint64, arg2 uint64, arg3 uint64) {
   181  	x1 := (uint64(arg1) * 0xffffffffffffffff)
   182  	x2 := ((x1 & arg3) | ((^x1) & arg2))
   183  	*out1 = x2
   184  }
   185  
   186  // Select sets e to p1 if cond == 1, and to p2 if cond == 0.
   187  func (e *gfP) Select(p1, p2 *gfP, cond int) *gfP {
   188  	var x1 uint64
   189  	cmovznzU64(&x1, uint64(cond), p2[0], p1[0])
   190  	var x2 uint64
   191  	cmovznzU64(&x2, uint64(cond), p2[1], p1[1])
   192  	var x3 uint64
   193  	cmovznzU64(&x3, uint64(cond), p2[2], p1[2])
   194  	var x4 uint64
   195  	cmovznzU64(&x4, uint64(cond), p2[3], p1[3])
   196  	e[0] = x1
   197  	e[1] = x2
   198  	e[2] = x3
   199  	e[3] = x4
   200  	return e
   201  }