...

Source file src/crypto/internal/edwards25519/scalarmult.go

Documentation: crypto/internal/edwards25519

     1  // Copyright (c) 2019 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package edwards25519
     6  
     7  import "sync"
     8  
     9  // basepointTable is a set of 32 affineLookupTables, where table i is generated
    10  // from 256i * basepoint. It is precomputed the first time it's used.
    11  func basepointTable() *[32]affineLookupTable {
    12  	basepointTablePrecomp.initOnce.Do(func() {
    13  		p := NewGeneratorPoint()
    14  		for i := 0; i < 32; i++ {
    15  			basepointTablePrecomp.table[i].FromP3(p)
    16  			for j := 0; j < 8; j++ {
    17  				p.Add(p, p)
    18  			}
    19  		}
    20  	})
    21  	return &basepointTablePrecomp.table
    22  }
    23  
    24  var basepointTablePrecomp struct {
    25  	table    [32]affineLookupTable
    26  	initOnce sync.Once
    27  }
    28  
    29  // ScalarBaseMult sets v = x * B, where B is the canonical generator, and
    30  // returns v.
    31  //
    32  // The scalar multiplication is done in constant time.
    33  func (v *Point) ScalarBaseMult(x *Scalar) *Point {
    34  	basepointTable := basepointTable()
    35  
    36  	// Write x = sum(x_i * 16^i) so  x*B = sum( B*x_i*16^i )
    37  	// as described in the Ed25519 paper
    38  	//
    39  	// Group even and odd coefficients
    40  	// x*B     = x_0*16^0*B + x_2*16^2*B + ... + x_62*16^62*B
    41  	//         + x_1*16^1*B + x_3*16^3*B + ... + x_63*16^63*B
    42  	// x*B     = x_0*16^0*B + x_2*16^2*B + ... + x_62*16^62*B
    43  	//    + 16*( x_1*16^0*B + x_3*16^2*B + ... + x_63*16^62*B)
    44  	//
    45  	// We use a lookup table for each i to get x_i*16^(2*i)*B
    46  	// and do four doublings to multiply by 16.
    47  	digits := x.signedRadix16()
    48  
    49  	multiple := &affineCached{}
    50  	tmp1 := &projP1xP1{}
    51  	tmp2 := &projP2{}
    52  
    53  	// Accumulate the odd components first
    54  	v.Set(NewIdentityPoint())
    55  	for i := 1; i < 64; i += 2 {
    56  		basepointTable[i/2].SelectInto(multiple, digits[i])
    57  		tmp1.AddAffine(v, multiple)
    58  		v.fromP1xP1(tmp1)
    59  	}
    60  
    61  	// Multiply by 16
    62  	tmp2.FromP3(v)       // tmp2 =    v in P2 coords
    63  	tmp1.Double(tmp2)    // tmp1 =  2*v in P1xP1 coords
    64  	tmp2.FromP1xP1(tmp1) // tmp2 =  2*v in P2 coords
    65  	tmp1.Double(tmp2)    // tmp1 =  4*v in P1xP1 coords
    66  	tmp2.FromP1xP1(tmp1) // tmp2 =  4*v in P2 coords
    67  	tmp1.Double(tmp2)    // tmp1 =  8*v in P1xP1 coords
    68  	tmp2.FromP1xP1(tmp1) // tmp2 =  8*v in P2 coords
    69  	tmp1.Double(tmp2)    // tmp1 = 16*v in P1xP1 coords
    70  	v.fromP1xP1(tmp1)    // now v = 16*(odd components)
    71  
    72  	// Accumulate the even components
    73  	for i := 0; i < 64; i += 2 {
    74  		basepointTable[i/2].SelectInto(multiple, digits[i])
    75  		tmp1.AddAffine(v, multiple)
    76  		v.fromP1xP1(tmp1)
    77  	}
    78  
    79  	return v
    80  }
    81  
    82  // ScalarMult sets v = x * q, and returns v.
    83  //
    84  // The scalar multiplication is done in constant time.
    85  func (v *Point) ScalarMult(x *Scalar, q *Point) *Point {
    86  	checkInitialized(q)
    87  
    88  	var table projLookupTable
    89  	table.FromP3(q)
    90  
    91  	// Write x = sum(x_i * 16^i)
    92  	// so  x*Q = sum( Q*x_i*16^i )
    93  	//         = Q*x_0 + 16*(Q*x_1 + 16*( ... + Q*x_63) ... )
    94  	//           <------compute inside out---------
    95  	//
    96  	// We use the lookup table to get the x_i*Q values
    97  	// and do four doublings to compute 16*Q
    98  	digits := x.signedRadix16()
    99  
   100  	// Unwrap first loop iteration to save computing 16*identity
   101  	multiple := &projCached{}
   102  	tmp1 := &projP1xP1{}
   103  	tmp2 := &projP2{}
   104  	table.SelectInto(multiple, digits[63])
   105  
   106  	v.Set(NewIdentityPoint())
   107  	tmp1.Add(v, multiple) // tmp1 = x_63*Q in P1xP1 coords
   108  	for i := 62; i >= 0; i-- {
   109  		tmp2.FromP1xP1(tmp1) // tmp2 =    (prev) in P2 coords
   110  		tmp1.Double(tmp2)    // tmp1 =  2*(prev) in P1xP1 coords
   111  		tmp2.FromP1xP1(tmp1) // tmp2 =  2*(prev) in P2 coords
   112  		tmp1.Double(tmp2)    // tmp1 =  4*(prev) in P1xP1 coords
   113  		tmp2.FromP1xP1(tmp1) // tmp2 =  4*(prev) in P2 coords
   114  		tmp1.Double(tmp2)    // tmp1 =  8*(prev) in P1xP1 coords
   115  		tmp2.FromP1xP1(tmp1) // tmp2 =  8*(prev) in P2 coords
   116  		tmp1.Double(tmp2)    // tmp1 = 16*(prev) in P1xP1 coords
   117  		v.fromP1xP1(tmp1)    //    v = 16*(prev) in P3 coords
   118  		table.SelectInto(multiple, digits[i])
   119  		tmp1.Add(v, multiple) // tmp1 = x_i*Q + 16*(prev) in P1xP1 coords
   120  	}
   121  	v.fromP1xP1(tmp1)
   122  	return v
   123  }
   124  
   125  // basepointNafTable is the nafLookupTable8 for the basepoint.
   126  // It is precomputed the first time it's used.
   127  func basepointNafTable() *nafLookupTable8 {
   128  	basepointNafTablePrecomp.initOnce.Do(func() {
   129  		basepointNafTablePrecomp.table.FromP3(NewGeneratorPoint())
   130  	})
   131  	return &basepointNafTablePrecomp.table
   132  }
   133  
   134  var basepointNafTablePrecomp struct {
   135  	table    nafLookupTable8
   136  	initOnce sync.Once
   137  }
   138  
   139  // VarTimeDoubleScalarBaseMult sets v = a * A + b * B, where B is the canonical
   140  // generator, and returns v.
   141  //
   142  // Execution time depends on the inputs.
   143  func (v *Point) VarTimeDoubleScalarBaseMult(a *Scalar, A *Point, b *Scalar) *Point {
   144  	checkInitialized(A)
   145  
   146  	// Similarly to the single variable-base approach, we compute
   147  	// digits and use them with a lookup table.  However, because
   148  	// we are allowed to do variable-time operations, we don't
   149  	// need constant-time lookups or constant-time digit
   150  	// computations.
   151  	//
   152  	// So we use a non-adjacent form of some width w instead of
   153  	// radix 16.  This is like a binary representation (one digit
   154  	// for each binary place) but we allow the digits to grow in
   155  	// magnitude up to 2^{w-1} so that the nonzero digits are as
   156  	// sparse as possible.  Intuitively, this "condenses" the
   157  	// "mass" of the scalar onto sparse coefficients (meaning
   158  	// fewer additions).
   159  
   160  	basepointNafTable := basepointNafTable()
   161  	var aTable nafLookupTable5
   162  	aTable.FromP3(A)
   163  	// Because the basepoint is fixed, we can use a wider NAF
   164  	// corresponding to a bigger table.
   165  	aNaf := a.nonAdjacentForm(5)
   166  	bNaf := b.nonAdjacentForm(8)
   167  
   168  	// Find the first nonzero coefficient.
   169  	i := 255
   170  	for j := i; j >= 0; j-- {
   171  		if aNaf[j] != 0 || bNaf[j] != 0 {
   172  			break
   173  		}
   174  	}
   175  
   176  	multA := &projCached{}
   177  	multB := &affineCached{}
   178  	tmp1 := &projP1xP1{}
   179  	tmp2 := &projP2{}
   180  	tmp2.Zero()
   181  
   182  	// Move from high to low bits, doubling the accumulator
   183  	// at each iteration and checking whether there is a nonzero
   184  	// coefficient to look up a multiple of.
   185  	for ; i >= 0; i-- {
   186  		tmp1.Double(tmp2)
   187  
   188  		// Only update v if we have a nonzero coeff to add in.
   189  		if aNaf[i] > 0 {
   190  			v.fromP1xP1(tmp1)
   191  			aTable.SelectInto(multA, aNaf[i])
   192  			tmp1.Add(v, multA)
   193  		} else if aNaf[i] < 0 {
   194  			v.fromP1xP1(tmp1)
   195  			aTable.SelectInto(multA, -aNaf[i])
   196  			tmp1.Sub(v, multA)
   197  		}
   198  
   199  		if bNaf[i] > 0 {
   200  			v.fromP1xP1(tmp1)
   201  			basepointNafTable.SelectInto(multB, bNaf[i])
   202  			tmp1.AddAffine(v, multB)
   203  		} else if bNaf[i] < 0 {
   204  			v.fromP1xP1(tmp1)
   205  			basepointNafTable.SelectInto(multB, -bNaf[i])
   206  			tmp1.SubAffine(v, multB)
   207  		}
   208  
   209  		tmp2.FromP1xP1(tmp1)
   210  	}
   211  
   212  	v.fromP2(tmp2)
   213  	return v
   214  }
   215  

View as plain text