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 }