github.com/cloudflare/circl@v1.5.0/math/wnaf.go (about)

     1  // Package math provides some utility functions for big integers.
     2  package math
     3  
     4  import "math/big"
     5  
     6  // SignedDigit obtains the signed-digit recoding of n and returns a list L of
     7  // digits such that n = sum( L[i]*2^(i*(w-1)) ), and each L[i] is an odd number
     8  // in the set {±1, ±3, ..., ±2^(w-1)-1}. The third parameter ensures that the
     9  // output has ceil(l/(w-1)) digits.
    10  //
    11  // Restrictions:
    12  //   - n is odd and n > 0.
    13  //   - 1 < w < 32.
    14  //   - l >= bit length of n.
    15  //
    16  // References:
    17  //   - Alg.6 in "Exponent Recoding and Regular Exponentiation Algorithms"
    18  //     by Joye-Tunstall. http://doi.org/10.1007/978-3-642-02384-2_21
    19  //   - Alg.6 in "Selecting Elliptic Curves for Cryptography: An Efficiency and
    20  //     Security Analysis" by Bos et al. http://doi.org/10.1007/s13389-015-0097-y
    21  func SignedDigit(n *big.Int, w, l uint) []int32 {
    22  	if n.Sign() <= 0 || n.Bit(0) == 0 {
    23  		panic("n must be non-zero, odd, and positive")
    24  	}
    25  	if w <= 1 || w >= 32 {
    26  		panic("Verify that 1 < w < 32")
    27  	}
    28  	if uint(n.BitLen()) > l {
    29  		panic("n is too big to fit in l digits")
    30  	}
    31  	lenN := (l + (w - 1) - 1) / (w - 1) // ceil(l/(w-1))
    32  	L := make([]int32, lenN+1)
    33  	var k, v big.Int
    34  	k.Set(n)
    35  
    36  	var i uint
    37  	for i = 0; i < lenN; i++ {
    38  		words := k.Bits()
    39  		value := int32(words[0] & ((1 << w) - 1))
    40  		value -= int32(1) << (w - 1)
    41  		L[i] = value
    42  		v.SetInt64(int64(value))
    43  		k.Sub(&k, &v)
    44  		k.Rsh(&k, w-1)
    45  	}
    46  	L[i] = int32(k.Int64())
    47  	return L
    48  }
    49  
    50  // OmegaNAF obtains the window-w Non-Adjacent Form of a positive number n and
    51  // 1 < w < 32. The returned slice L holds n = sum( L[i]*2^i ).
    52  //
    53  // Reference:
    54  //   - Alg.9 "Efficient arithmetic on Koblitz curves" by Solinas.
    55  //     http://doi.org/10.1023/A:1008306223194
    56  func OmegaNAF(n *big.Int, w uint) (L []int32) {
    57  	if n.Sign() < 0 {
    58  		panic("n must be positive")
    59  	}
    60  	if w <= 1 || w >= 32 {
    61  		panic("Verify that 1 < w < 32")
    62  	}
    63  
    64  	L = make([]int32, n.BitLen()+1)
    65  	var k, v big.Int
    66  	k.Set(n)
    67  
    68  	i := 0
    69  	for ; k.Sign() > 0; i++ {
    70  		value := int32(0)
    71  		if k.Bit(0) == 1 {
    72  			words := k.Bits()
    73  			value = int32(words[0] & ((1 << w) - 1))
    74  			if value >= (int32(1) << (w - 1)) {
    75  				value -= int32(1) << w
    76  			}
    77  			v.SetInt64(int64(value))
    78  			k.Sub(&k, &v)
    79  		}
    80  		L[i] = value
    81  		k.Rsh(&k, 1)
    82  	}
    83  	return L[:i]
    84  }