github.com/zhiqiangxu/util@v0.0.0-20230112053021-0a7aee056cd5/crypto/wnaf/lr.go (about)

     1  package wnaf
     2  
     3  import (
     4  	"math/big"
     5  	"math/bits"
     6  )
     7  
     8  // FYI https://rd.springer.com/content/pdf/10.1007/978-3-540-68914-0_26.pdf
     9  
    10  // the returned wnaf "bits" are in big endian and in modified wNAF* version
    11  func ToWnafLR(d *big.Int, w uint8) (wnaf []int64) {
    12  	if d.Cmp(zero) < 0 {
    13  		panic("negative d not supported")
    14  	}
    15  	if w >= 64 {
    16  		panic("w >= 64 not supported")
    17  	}
    18  
    19  	n := d.BitLen()
    20  	if n == 0 {
    21  		return []int64{0}
    22  	}
    23  
    24  	i := n - 1
    25  	c := 0
    26  
    27  	mod := big.NewInt(0).Exp(two, big.NewInt(int64(w)), nil)
    28  	w_all1 := big.NewInt(0).Sub(mod, one)
    29  	appendWnaf := func(r int64, w uint8) {
    30  		// the caller ensures that |r| is < 2^(w-1)
    31  
    32  		var abs uint64
    33  		if r > 0 {
    34  			abs = uint64(r)
    35  		} else {
    36  			abs = uint64(-r)
    37  		}
    38  		nz := bits.TrailingZeros64(abs)
    39  		// append w-1-nz 0 to wnaf
    40  		wnaf = append(wnaf, make([]int64, w-1-uint8(nz))...)
    41  		wnaf = append(wnaf, r>>nz)
    42  		// append nz 0 to wnaf
    43  		wnaf = append(wnaf, make([]int64, nz)...)
    44  	}
    45  
    46  	for {
    47  		if i < -1 {
    48  			break
    49  		}
    50  
    51  		var di uint
    52  		// when i < 0, di is 0
    53  		if i >= 0 {
    54  			di = d.Bit(i)
    55  		}
    56  
    57  		switch c {
    58  		case 0:
    59  			if di == 0 {
    60  				if i < 0 {
    61  					return
    62  				}
    63  
    64  				wnaf = append(wnaf, 0)
    65  				i -= 1
    66  				continue
    67  			}
    68  
    69  			// here it's guaranteed that di == 1
    70  			j := i - int(w) + 1
    71  			if j < 0 || d.Bit(j) == 0 {
    72  				if j < 0 {
    73  					mod := big.NewInt(0).Exp(two, big.NewInt(int64(i+1)), nil)
    74  					r := big.NewInt(0).Mod(d, mod).Uint64()
    75  					appendWnaf(int64(r), uint8(i+1))
    76  
    77  					i = -1
    78  				} else {
    79  					r := big.NewInt(0).Mod(big.NewInt(0).Rsh(d, uint(j)), mod).Uint64()
    80  					appendWnaf(int64(r), w)
    81  
    82  					i -= int(w)
    83  				}
    84  				continue
    85  			}
    86  
    87  			// here it's guaranteed that j >= 0 and dj == 1
    88  
    89  			r := big.NewInt(0).Mod(big.NewInt(0).Rsh(d, uint(j)), mod)
    90  			if r.Cmp(w_all1) == 0 {
    91  				// all w bits are 1
    92  				wnaf = append(wnaf, 2)
    93  				// append w-1 0 to wnaf
    94  				zeros := make([]int64, w-1)
    95  				wnaf = append(wnaf, zeros...)
    96  
    97  				i -= int(w)
    98  				c = -2
    99  			} else {
   100  				// with 0 between i and j
   101  
   102  				rPlus1 := r.Uint64() + 1
   103  				appendWnaf(int64(rPlus1), w)
   104  
   105  				i -= int(w)
   106  				c = -2
   107  			}
   108  		case -2:
   109  			if di == 1 {
   110  				wnaf = append(wnaf, 0)
   111  				i -= 1
   112  				// c doesn't change
   113  				continue
   114  			}
   115  
   116  			// here it's guaranteed that di == 0
   117  			j := i - int(w) + 1
   118  			if j < 0 || d.Bit(j) == 0 {
   119  
   120  				if j < 0 {
   121  					if i < 0 {
   122  						wnaf = append(wnaf, -2)
   123  						return
   124  					} else {
   125  						mod := big.NewInt(0).Exp(two, big.NewInt(int64(i+1)), nil)
   126  						r := big.NewInt(0).Mod(d, mod)
   127  						appendWnaf(-int64(big.NewInt(0).Sub(mod, r).Uint64()), uint8(i+1))
   128  						i = -1
   129  					}
   130  
   131  				} else {
   132  					r := big.NewInt(0).Mod(big.NewInt(0).Rsh(d, uint(j)), mod)
   133  					appendWnaf(-int64(big.NewInt(0).Sub(mod, r).Uint64()), w)
   134  
   135  					i -= int(w)
   136  				}
   137  
   138  				c = 0
   139  				continue
   140  			}
   141  
   142  			// here it's guaranteed that j >=0 and dj == 1
   143  
   144  			r := big.NewInt(0).Mod(big.NewInt(0).Rsh(d, uint(j)), mod)
   145  			appendWnaf(-int64(big.NewInt(0).Sub(mod, big.NewInt(0).Add(r, one)).Uint64()), w) // w < 64, so the type cast is safe
   146  
   147  			i -= int(w)
   148  			// c doesn't change
   149  		}
   150  
   151  	}
   152  
   153  	return
   154  }