github.com/cloudflare/circl@v1.5.0/ecc/goldilocks/twist.go (about)

     1  package goldilocks
     2  
     3  import (
     4  	"crypto/subtle"
     5  	"math/bits"
     6  
     7  	"github.com/cloudflare/circl/internal/conv"
     8  	"github.com/cloudflare/circl/math"
     9  	fp "github.com/cloudflare/circl/math/fp448"
    10  )
    11  
    12  // twistCurve is -x^2+y^2=1-39082x^2y^2 and is 4-isogenous to Goldilocks.
    13  type twistCurve struct{}
    14  
    15  // Identity returns the identity point.
    16  func (twistCurve) Identity() *twistPoint {
    17  	return &twistPoint{
    18  		y: fp.One(),
    19  		z: fp.One(),
    20  	}
    21  }
    22  
    23  // subYDiv16 update x = (x - y) / 16.
    24  func subYDiv16(x *scalar64, y int64) {
    25  	s := uint64(y >> 63)
    26  	x0, b0 := bits.Sub64((*x)[0], uint64(y), 0)
    27  	x1, b1 := bits.Sub64((*x)[1], s, b0)
    28  	x2, b2 := bits.Sub64((*x)[2], s, b1)
    29  	x3, b3 := bits.Sub64((*x)[3], s, b2)
    30  	x4, b4 := bits.Sub64((*x)[4], s, b3)
    31  	x5, b5 := bits.Sub64((*x)[5], s, b4)
    32  	x6, _ := bits.Sub64((*x)[6], s, b5)
    33  	x[0] = (x0 >> 4) | (x1 << 60)
    34  	x[1] = (x1 >> 4) | (x2 << 60)
    35  	x[2] = (x2 >> 4) | (x3 << 60)
    36  	x[3] = (x3 >> 4) | (x4 << 60)
    37  	x[4] = (x4 >> 4) | (x5 << 60)
    38  	x[5] = (x5 >> 4) | (x6 << 60)
    39  	x[6] = (x6 >> 4)
    40  }
    41  
    42  func recodeScalar(d *[113]int8, k *Scalar) {
    43  	var k64 scalar64
    44  	k64.fromScalar(k)
    45  	for i := 0; i < 112; i++ {
    46  		d[i] = int8((k64[0] & 0x1f) - 16)
    47  		subYDiv16(&k64, int64(d[i]))
    48  	}
    49  	d[112] = int8(k64[0])
    50  }
    51  
    52  // ScalarMult returns kP.
    53  func (e twistCurve) ScalarMult(k *Scalar, P *twistPoint) *twistPoint {
    54  	var TabP [8]preTwistPointProy
    55  	var S preTwistPointProy
    56  	var d [113]int8
    57  
    58  	var isZero int
    59  	if k.IsZero() {
    60  		isZero = 1
    61  	}
    62  	subtle.ConstantTimeCopy(isZero, k[:], order[:])
    63  
    64  	minusK := *k
    65  	isEven := 1 - int(k[0]&0x1)
    66  	minusK.Neg()
    67  	subtle.ConstantTimeCopy(isEven, k[:], minusK[:])
    68  	recodeScalar(&d, k)
    69  
    70  	P.oddMultiples(TabP[:])
    71  	Q := e.Identity()
    72  	for i := 112; i >= 0; i-- {
    73  		Q.Double()
    74  		Q.Double()
    75  		Q.Double()
    76  		Q.Double()
    77  		mask := d[i] >> 7
    78  		absDi := (d[i] + mask) ^ mask
    79  		inx := int32((absDi - 1) >> 1)
    80  		sig := int((d[i] >> 7) & 0x1)
    81  		for j := range TabP {
    82  			S.cmov(&TabP[j], uint(subtle.ConstantTimeEq(inx, int32(j))))
    83  		}
    84  		S.cneg(sig)
    85  		Q.mixAdd(&S)
    86  	}
    87  	Q.cneg(uint(isEven))
    88  	return Q
    89  }
    90  
    91  const (
    92  	omegaFix = 7
    93  	omegaVar = 5
    94  )
    95  
    96  // CombinedMult returns mG+nP.
    97  func (e twistCurve) CombinedMult(m, n *Scalar, P *twistPoint) *twistPoint {
    98  	nafFix := math.OmegaNAF(conv.BytesLe2BigInt(m[:]), omegaFix)
    99  	nafVar := math.OmegaNAF(conv.BytesLe2BigInt(n[:]), omegaVar)
   100  
   101  	if len(nafFix) > len(nafVar) {
   102  		nafVar = append(nafVar, make([]int32, len(nafFix)-len(nafVar))...)
   103  	} else if len(nafFix) < len(nafVar) {
   104  		nafFix = append(nafFix, make([]int32, len(nafVar)-len(nafFix))...)
   105  	}
   106  
   107  	var TabQ [1 << (omegaVar - 2)]preTwistPointProy
   108  	P.oddMultiples(TabQ[:])
   109  	Q := e.Identity()
   110  	for i := len(nafFix) - 1; i >= 0; i-- {
   111  		Q.Double()
   112  		// Generator point
   113  		if nafFix[i] != 0 {
   114  			idxM := absolute(nafFix[i]) >> 1
   115  			R := tabVerif[idxM]
   116  			if nafFix[i] < 0 {
   117  				R.neg()
   118  			}
   119  			Q.mixAddZ1(&R)
   120  		}
   121  		// Variable input point
   122  		if nafVar[i] != 0 {
   123  			idxN := absolute(nafVar[i]) >> 1
   124  			S := TabQ[idxN]
   125  			if nafVar[i] < 0 {
   126  				S.neg()
   127  			}
   128  			Q.mixAdd(&S)
   129  		}
   130  	}
   131  	return Q
   132  }
   133  
   134  // absolute returns always a positive value.
   135  func absolute(x int32) int32 {
   136  	mask := x >> 31
   137  	return (x + mask) ^ mask
   138  }