| // 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 |
| } |