v / vlib / crypto / ed25519 / internal / edwards25519 / table.v
127 lines · 110 sloc · 3.6 KB · 4eb087a34755d0b184e6c13b34e25f1c89d9273a
Raw
1module edwards25519
2
3import crypto.internal.subtle
4
5// A precomputed lookup table for fixed-base, constant-time scalar muls.
6struct AffineLookupTable {
7mut:
8 points [8]AffineCached
9}
10
11// A dynamic lookup table for variable-base, constant-time scalar muls.
12struct ProjLookupTable {
13mut:
14 points [8]ProjectiveCached
15}
16
17// A dynamic lookup table for variable-base, variable-time scalar muls.
18struct NafLookupTable5 {
19mut:
20 points [8]ProjectiveCached
21}
22
23// A precomputed lookup table for fixed-base, variable-time scalar muls.
24struct NafLookupTable8 {
25mut:
26 points [64]AffineCached
27}
28
29// Constructors.
30
31// Builds a lookup table at runtime. Fast.
32fn (mut v ProjLookupTable) from_p3(q Point) {
33 // Goal: v.points[i] = (i+1)*Q, i.e., Q, 2Q, ..., 8Q
34 // This allows lookup of -8Q, ..., -Q, 0, Q, ..., 8Q
35 v.points[0].from_p3(q)
36 mut tmp_p3 := Point{}
37 mut tmp_p1 := ProjectiveP1{}
38 for i := 0; i < 7; i++ {
39 // Compute (i+1)*Q as Q + i*Q and convert to a ProjCached
40 // This is needlessly complicated because the API has explicit
41 // receivers instead of creating stack objects and relying on RVO
42 v.points[i + 1].from_p3(tmp_p3.from_p1(tmp_p1.add(q, v.points[i])))
43 }
44}
45
46// This is not optimised for speed; fixed-base tables should be precomputed.
47fn (mut v AffineLookupTable) from_p3(q Point) {
48 // Goal: v.points[i] = (i+1)*Q, i.e., Q, 2Q, ..., 8Q
49 // This allows lookup of -8Q, ..., -Q, 0, Q, ..., 8Q
50 v.points[0].from_p3(q)
51 mut tmp_p3 := Point{}
52 mut tmp_p1 := ProjectiveP1{}
53 for i := 0; i < 7; i++ {
54 // Compute (i+1)*Q as Q + i*Q and convert to AffineCached
55 v.points[i + 1].from_p3(tmp_p3.from_p1(tmp_p1.add_affine(q, v.points[i])))
56 }
57}
58
59// Builds a lookup table at runtime. Fast.
60fn (mut v NafLookupTable5) from_p3(q Point) {
61 // Goal: v.points[i] = (2*i+1)*Q, i.e., Q, 3Q, 5Q, ..., 15Q
62 // This allows lookup of -15Q, ..., -3Q, -Q, 0, Q, 3Q, ..., 15Q
63 v.points[0].from_p3(q)
64 mut q2 := Point{}
65 q2.add(q, q)
66 mut tmp_p3 := Point{}
67 mut tmp_p1 := ProjectiveP1{}
68 for i := 0; i < 7; i++ {
69 v.points[i + 1].from_p3(tmp_p3.from_p1(tmp_p1.add(q2, v.points[i])))
70 }
71}
72
73// This is not optimised for speed; fixed-base tables should be precomputed.
74fn (mut v NafLookupTable8) from_p3(q Point) {
75 v.points[0].from_p3(q)
76 mut q2 := Point{}
77 q2.add(q, q)
78 mut tmp_p3 := Point{}
79 mut tmp_p1 := ProjectiveP1{}
80 for i := 0; i < 63; i++ {
81 v.points[i + 1].from_p3(tmp_p3.from_p1(tmp_p1.add_affine(q2, v.points[i])))
82 }
83}
84
85// Selectors.
86
87// Set dest to x*Q, where -8 <= x <= 8, in constant time.
88fn (mut v ProjLookupTable) select_into(mut dest ProjectiveCached, x i8) {
89 // Compute xabs = |x|
90 xmask := x >> 7
91 xabs := u8((x + xmask) ^ xmask)
92
93 dest.zero()
94 for j := 1; j <= 8; j++ {
95 // Set dest = j*Q if |x| = j
96 cond := subtle.constant_time_byte_eq(xabs, u8(j))
97 dest.selected(v.points[j - 1], dest, cond)
98 }
99 // Now dest = |x|*Q, conditionally negate to get x*Q
100 dest.cond_neg(int(xmask & 1))
101}
102
103// Set dest to x*Q, where -8 <= x <= 8, in constant time.
104fn (mut v AffineLookupTable) select_into(mut dest AffineCached, x i8) {
105 // Compute xabs = |x|
106 xmask := x >> 7
107 xabs := u8((x + xmask) ^ xmask)
108
109 dest.zero()
110 for j := 1; j <= 8; j++ {
111 // Set dest = j*Q if |x| = j
112 cond := subtle.constant_time_byte_eq(xabs, u8(j))
113 dest.selected(v.points[j - 1], dest, cond)
114 }
115 // Now dest = |x|*Q, conditionally negate to get x*Q
116 dest.cond_neg(int(xmask & 1))
117}
118
119// Given odd x with 0 < x < 2^4, return x*Q (in variable time).
120fn (mut v NafLookupTable5) select_into(mut dest ProjectiveCached, x i8) {
121 dest = v.points[x / 2]
122}
123
124// Given odd x with 0 < x < 2^7, return x*Q (in variable time).
125fn (mut v NafLookupTable8) select_into(mut dest AffineCached, x i8) {
126 dest = v.points[x / 2]
127}
128