123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214 |
- // Copyright (c) 2019 The Go Authors. All rights reserved.
- // Use of this source code is governed by a BSD-style
- // license that can be found in the LICENSE file.
- package edwards25519
- import "sync"
- // basepointTable is a set of 32 affineLookupTables, where table i is generated
- // from 256i * basepoint. It is precomputed the first time it's used.
- func basepointTable() *[32]affineLookupTable {
- basepointTablePrecomp.initOnce.Do(func() {
- p := NewGeneratorPoint()
- for i := 0; i < 32; i++ {
- basepointTablePrecomp.table[i].FromP3(p)
- for j := 0; j < 8; j++ {
- p.Add(p, p)
- }
- }
- })
- return &basepointTablePrecomp.table
- }
- var basepointTablePrecomp struct {
- table [32]affineLookupTable
- initOnce sync.Once
- }
- // ScalarBaseMult sets v = x * B, where B is the canonical generator, and
- // returns v.
- //
- // The scalar multiplication is done in constant time.
- func (v *Point) ScalarBaseMult(x *Scalar) *Point {
- basepointTable := basepointTable()
- // Write x = sum(x_i * 16^i) so x*B = sum( B*x_i*16^i )
- // as described in the Ed25519 paper
- //
- // Group even and odd coefficients
- // x*B = x_0*16^0*B + x_2*16^2*B + ... + x_62*16^62*B
- // + x_1*16^1*B + x_3*16^3*B + ... + x_63*16^63*B
- // x*B = x_0*16^0*B + x_2*16^2*B + ... + x_62*16^62*B
- // + 16*( x_1*16^0*B + x_3*16^2*B + ... + x_63*16^62*B)
- //
- // We use a lookup table for each i to get x_i*16^(2*i)*B
- // and do four doublings to multiply by 16.
- digits := x.signedRadix16()
- multiple := &affineCached{}
- tmp1 := &projP1xP1{}
- tmp2 := &projP2{}
- // Accumulate the odd components first
- v.Set(NewIdentityPoint())
- for i := 1; i < 64; i += 2 {
- basepointTable[i/2].SelectInto(multiple, digits[i])
- tmp1.AddAffine(v, multiple)
- v.fromP1xP1(tmp1)
- }
- // Multiply by 16
- tmp2.FromP3(v) // tmp2 = v in P2 coords
- tmp1.Double(tmp2) // tmp1 = 2*v in P1xP1 coords
- tmp2.FromP1xP1(tmp1) // tmp2 = 2*v in P2 coords
- tmp1.Double(tmp2) // tmp1 = 4*v in P1xP1 coords
- tmp2.FromP1xP1(tmp1) // tmp2 = 4*v in P2 coords
- tmp1.Double(tmp2) // tmp1 = 8*v in P1xP1 coords
- tmp2.FromP1xP1(tmp1) // tmp2 = 8*v in P2 coords
- tmp1.Double(tmp2) // tmp1 = 16*v in P1xP1 coords
- v.fromP1xP1(tmp1) // now v = 16*(odd components)
- // Accumulate the even components
- for i := 0; i < 64; i += 2 {
- basepointTable[i/2].SelectInto(multiple, digits[i])
- tmp1.AddAffine(v, multiple)
- v.fromP1xP1(tmp1)
- }
- return v
- }
- // ScalarMult sets v = x * q, and returns v.
- //
- // The scalar multiplication is done in constant time.
- func (v *Point) ScalarMult(x *Scalar, q *Point) *Point {
- checkInitialized(q)
- var table projLookupTable
- table.FromP3(q)
- // Write x = sum(x_i * 16^i)
- // so x*Q = sum( Q*x_i*16^i )
- // = Q*x_0 + 16*(Q*x_1 + 16*( ... + Q*x_63) ... )
- // <------compute inside out---------
- //
- // We use the lookup table to get the x_i*Q values
- // and do four doublings to compute 16*Q
- digits := x.signedRadix16()
- // Unwrap first loop iteration to save computing 16*identity
- multiple := &projCached{}
- tmp1 := &projP1xP1{}
- tmp2 := &projP2{}
- table.SelectInto(multiple, digits[63])
- v.Set(NewIdentityPoint())
- tmp1.Add(v, multiple) // tmp1 = x_63*Q in P1xP1 coords
- for i := 62; i >= 0; i-- {
- tmp2.FromP1xP1(tmp1) // tmp2 = (prev) in P2 coords
- tmp1.Double(tmp2) // tmp1 = 2*(prev) in P1xP1 coords
- tmp2.FromP1xP1(tmp1) // tmp2 = 2*(prev) in P2 coords
- tmp1.Double(tmp2) // tmp1 = 4*(prev) in P1xP1 coords
- tmp2.FromP1xP1(tmp1) // tmp2 = 4*(prev) in P2 coords
- tmp1.Double(tmp2) // tmp1 = 8*(prev) in P1xP1 coords
- tmp2.FromP1xP1(tmp1) // tmp2 = 8*(prev) in P2 coords
- tmp1.Double(tmp2) // tmp1 = 16*(prev) in P1xP1 coords
- v.fromP1xP1(tmp1) // v = 16*(prev) in P3 coords
- table.SelectInto(multiple, digits[i])
- tmp1.Add(v, multiple) // tmp1 = x_i*Q + 16*(prev) in P1xP1 coords
- }
- v.fromP1xP1(tmp1)
- return v
- }
- // basepointNafTable is the nafLookupTable8 for the basepoint.
- // It is precomputed the first time it's used.
- func basepointNafTable() *nafLookupTable8 {
- basepointNafTablePrecomp.initOnce.Do(func() {
- basepointNafTablePrecomp.table.FromP3(NewGeneratorPoint())
- })
- return &basepointNafTablePrecomp.table
- }
- var basepointNafTablePrecomp struct {
- table nafLookupTable8
- initOnce sync.Once
- }
- // VarTimeDoubleScalarBaseMult sets v = a * A + b * B, where B is the canonical
- // generator, and returns v.
- //
- // Execution time depends on the inputs.
- func (v *Point) VarTimeDoubleScalarBaseMult(a *Scalar, A *Point, b *Scalar) *Point {
- checkInitialized(A)
- // Similarly to the single variable-base approach, we compute
- // digits and use them with a lookup table. However, because
- // we are allowed to do variable-time operations, we don't
- // need constant-time lookups or constant-time digit
- // computations.
- //
- // So we use a non-adjacent form of some width w instead of
- // radix 16. This is like a binary representation (one digit
- // for each binary place) but we allow the digits to grow in
- // magnitude up to 2^{w-1} so that the nonzero digits are as
- // sparse as possible. Intuitively, this "condenses" the
- // "mass" of the scalar onto sparse coefficients (meaning
- // fewer additions).
- basepointNafTable := basepointNafTable()
- var aTable nafLookupTable5
- aTable.FromP3(A)
- // Because the basepoint is fixed, we can use a wider NAF
- // corresponding to a bigger table.
- aNaf := a.nonAdjacentForm(5)
- bNaf := b.nonAdjacentForm(8)
- // Find the first nonzero coefficient.
- i := 255
- for j := i; j >= 0; j-- {
- if aNaf[j] != 0 || bNaf[j] != 0 {
- break
- }
- }
- multA := &projCached{}
- multB := &affineCached{}
- tmp1 := &projP1xP1{}
- tmp2 := &projP2{}
- tmp2.Zero()
- // Move from high to low bits, doubling the accumulator
- // at each iteration and checking whether there is a nonzero
- // coefficient to look up a multiple of.
- for ; i >= 0; i-- {
- tmp1.Double(tmp2)
- // Only update v if we have a nonzero coeff to add in.
- if aNaf[i] > 0 {
- v.fromP1xP1(tmp1)
- aTable.SelectInto(multA, aNaf[i])
- tmp1.Add(v, multA)
- } else if aNaf[i] < 0 {
- v.fromP1xP1(tmp1)
- aTable.SelectInto(multA, -aNaf[i])
- tmp1.Sub(v, multA)
- }
- if bNaf[i] > 0 {
- v.fromP1xP1(tmp1)
- basepointNafTable.SelectInto(multB, bNaf[i])
- tmp1.AddAffine(v, multB)
- } else if bNaf[i] < 0 {
- v.fromP1xP1(tmp1)
- basepointNafTable.SelectInto(multB, -bNaf[i])
- tmp1.SubAffine(v, multB)
- }
- tmp2.FromP1xP1(tmp1)
- }
- v.fromP2(tmp2)
- return v
- }
|