aboutsummaryrefslogtreecommitdiff
path: root/src/crypto/ed25519/internal/edwards25519/tables.go
blob: 5ca40f7bfa7a87f1b54ff65ced24d56db7142e6a (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
// 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 (
	"crypto/subtle"
)

// A dynamic lookup table for variable-base, constant-time scalar muls.
type projLookupTable struct {
	points [8]projCached
}

// A precomputed lookup table for fixed-base, constant-time scalar muls.
type affineLookupTable struct {
	points [8]affineCached
}

// A dynamic lookup table for variable-base, variable-time scalar muls.
type nafLookupTable5 struct {
	points [8]projCached
}

// A precomputed lookup table for fixed-base, variable-time scalar muls.
type nafLookupTable8 struct {
	points [64]affineCached
}

// Constructors.

// Builds a lookup table at runtime. Fast.
func (v *projLookupTable) FromP3(q *Point) {
	// Goal: v.points[i] = (i+1)*Q, i.e., Q, 2Q, ..., 8Q
	// This allows lookup of -8Q, ..., -Q, 0, Q, ..., 8Q
	v.points[0].FromP3(q)
	tmpP3 := Point{}
	tmpP1xP1 := projP1xP1{}
	for i := 0; i < 7; i++ {
		// Compute (i+1)*Q as Q + i*Q and convert to a ProjCached
		// This is needlessly complicated because the API has explicit
		// receivers instead of creating stack objects and relying on RVO
		v.points[i+1].FromP3(tmpP3.fromP1xP1(tmpP1xP1.Add(q, &v.points[i])))
	}
}

// This is not optimised for speed; fixed-base tables should be precomputed.
func (v *affineLookupTable) FromP3(q *Point) {
	// Goal: v.points[i] = (i+1)*Q, i.e., Q, 2Q, ..., 8Q
	// This allows lookup of -8Q, ..., -Q, 0, Q, ..., 8Q
	v.points[0].FromP3(q)
	tmpP3 := Point{}
	tmpP1xP1 := projP1xP1{}
	for i := 0; i < 7; i++ {
		// Compute (i+1)*Q as Q + i*Q and convert to AffineCached
		v.points[i+1].FromP3(tmpP3.fromP1xP1(tmpP1xP1.AddAffine(q, &v.points[i])))
	}
}

// Builds a lookup table at runtime. Fast.
func (v *nafLookupTable5) FromP3(q *Point) {
	// Goal: v.points[i] = (2*i+1)*Q, i.e., Q, 3Q, 5Q, ..., 15Q
	// This allows lookup of -15Q, ..., -3Q, -Q, 0, Q, 3Q, ..., 15Q
	v.points[0].FromP3(q)
	q2 := Point{}
	q2.Add(q, q)
	tmpP3 := Point{}
	tmpP1xP1 := projP1xP1{}
	for i := 0; i < 7; i++ {
		v.points[i+1].FromP3(tmpP3.fromP1xP1(tmpP1xP1.Add(&q2, &v.points[i])))
	}
}

// This is not optimised for speed; fixed-base tables should be precomputed.
func (v *nafLookupTable8) FromP3(q *Point) {
	v.points[0].FromP3(q)
	q2 := Point{}
	q2.Add(q, q)
	tmpP3 := Point{}
	tmpP1xP1 := projP1xP1{}
	for i := 0; i < 63; i++ {
		v.points[i+1].FromP3(tmpP3.fromP1xP1(tmpP1xP1.AddAffine(&q2, &v.points[i])))
	}
}

// Selectors.

// Set dest to x*Q, where -8 <= x <= 8, in constant time.
func (v *projLookupTable) SelectInto(dest *projCached, x int8) {
	// Compute xabs = |x|
	xmask := x >> 7
	xabs := uint8((x + xmask) ^ xmask)

	dest.Zero()
	for j := 1; j <= 8; j++ {
		// Set dest = j*Q if |x| = j
		cond := subtle.ConstantTimeByteEq(xabs, uint8(j))
		dest.Select(&v.points[j-1], dest, cond)
	}
	// Now dest = |x|*Q, conditionally negate to get x*Q
	dest.CondNeg(int(xmask & 1))
}

// Set dest to x*Q, where -8 <= x <= 8, in constant time.
func (v *affineLookupTable) SelectInto(dest *affineCached, x int8) {
	// Compute xabs = |x|
	xmask := x >> 7
	xabs := uint8((x + xmask) ^ xmask)

	dest.Zero()
	for j := 1; j <= 8; j++ {
		// Set dest = j*Q if |x| = j
		cond := subtle.ConstantTimeByteEq(xabs, uint8(j))
		dest.Select(&v.points[j-1], dest, cond)
	}
	// Now dest = |x|*Q, conditionally negate to get x*Q
	dest.CondNeg(int(xmask & 1))
}

// Given odd x with 0 < x < 2^4, return x*Q (in variable time).
func (v *nafLookupTable5) SelectInto(dest *projCached, x int8) {
	*dest = v.points[x/2]
}

// Given odd x with 0 < x < 2^7, return x*Q (in variable time).
func (v *nafLookupTable8) SelectInto(dest *affineCached, x int8) {
	*dest = v.points[x/2]
}