tables.go 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129
  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. package edwards25519
  5. import (
  6. "crypto/subtle"
  7. )
  8. // A dynamic lookup table for variable-base, constant-time scalar muls.
  9. type projLookupTable struct {
  10. points [8]projCached
  11. }
  12. // A precomputed lookup table for fixed-base, constant-time scalar muls.
  13. type affineLookupTable struct {
  14. points [8]affineCached
  15. }
  16. // A dynamic lookup table for variable-base, variable-time scalar muls.
  17. type nafLookupTable5 struct {
  18. points [8]projCached
  19. }
  20. // A precomputed lookup table for fixed-base, variable-time scalar muls.
  21. type nafLookupTable8 struct {
  22. points [64]affineCached
  23. }
  24. // Constructors.
  25. // Builds a lookup table at runtime. Fast.
  26. func (v *projLookupTable) FromP3(q *Point) {
  27. // Goal: v.points[i] = (i+1)*Q, i.e., Q, 2Q, ..., 8Q
  28. // This allows lookup of -8Q, ..., -Q, 0, Q, ..., 8Q
  29. v.points[0].FromP3(q)
  30. tmpP3 := Point{}
  31. tmpP1xP1 := projP1xP1{}
  32. for i := 0; i < 7; i++ {
  33. // Compute (i+1)*Q as Q + i*Q and convert to a projCached
  34. // This is needlessly complicated because the API has explicit
  35. // receivers instead of creating stack objects and relying on RVO
  36. v.points[i+1].FromP3(tmpP3.fromP1xP1(tmpP1xP1.Add(q, &v.points[i])))
  37. }
  38. }
  39. // This is not optimised for speed; fixed-base tables should be precomputed.
  40. func (v *affineLookupTable) FromP3(q *Point) {
  41. // Goal: v.points[i] = (i+1)*Q, i.e., Q, 2Q, ..., 8Q
  42. // This allows lookup of -8Q, ..., -Q, 0, Q, ..., 8Q
  43. v.points[0].FromP3(q)
  44. tmpP3 := Point{}
  45. tmpP1xP1 := projP1xP1{}
  46. for i := 0; i < 7; i++ {
  47. // Compute (i+1)*Q as Q + i*Q and convert to affineCached
  48. v.points[i+1].FromP3(tmpP3.fromP1xP1(tmpP1xP1.AddAffine(q, &v.points[i])))
  49. }
  50. }
  51. // Builds a lookup table at runtime. Fast.
  52. func (v *nafLookupTable5) FromP3(q *Point) {
  53. // Goal: v.points[i] = (2*i+1)*Q, i.e., Q, 3Q, 5Q, ..., 15Q
  54. // This allows lookup of -15Q, ..., -3Q, -Q, 0, Q, 3Q, ..., 15Q
  55. v.points[0].FromP3(q)
  56. q2 := Point{}
  57. q2.Add(q, q)
  58. tmpP3 := Point{}
  59. tmpP1xP1 := projP1xP1{}
  60. for i := 0; i < 7; i++ {
  61. v.points[i+1].FromP3(tmpP3.fromP1xP1(tmpP1xP1.Add(&q2, &v.points[i])))
  62. }
  63. }
  64. // This is not optimised for speed; fixed-base tables should be precomputed.
  65. func (v *nafLookupTable8) FromP3(q *Point) {
  66. v.points[0].FromP3(q)
  67. q2 := Point{}
  68. q2.Add(q, q)
  69. tmpP3 := Point{}
  70. tmpP1xP1 := projP1xP1{}
  71. for i := 0; i < 63; i++ {
  72. v.points[i+1].FromP3(tmpP3.fromP1xP1(tmpP1xP1.AddAffine(&q2, &v.points[i])))
  73. }
  74. }
  75. // Selectors.
  76. // Set dest to x*Q, where -8 <= x <= 8, in constant time.
  77. func (v *projLookupTable) SelectInto(dest *projCached, x int8) {
  78. // Compute xabs = |x|
  79. xmask := x >> 7
  80. xabs := uint8((x + xmask) ^ xmask)
  81. dest.Zero()
  82. for j := 1; j <= 8; j++ {
  83. // Set dest = j*Q if |x| = j
  84. cond := subtle.ConstantTimeByteEq(xabs, uint8(j))
  85. dest.Select(&v.points[j-1], dest, cond)
  86. }
  87. // Now dest = |x|*Q, conditionally negate to get x*Q
  88. dest.CondNeg(int(xmask & 1))
  89. }
  90. // Set dest to x*Q, where -8 <= x <= 8, in constant time.
  91. func (v *affineLookupTable) SelectInto(dest *affineCached, x int8) {
  92. // Compute xabs = |x|
  93. xmask := x >> 7
  94. xabs := uint8((x + xmask) ^ xmask)
  95. dest.Zero()
  96. for j := 1; j <= 8; j++ {
  97. // Set dest = j*Q if |x| = j
  98. cond := subtle.ConstantTimeByteEq(xabs, uint8(j))
  99. dest.Select(&v.points[j-1], dest, cond)
  100. }
  101. // Now dest = |x|*Q, conditionally negate to get x*Q
  102. dest.CondNeg(int(xmask & 1))
  103. }
  104. // Given odd x with 0 < x < 2^4, return x*Q (in variable time).
  105. func (v *nafLookupTable5) SelectInto(dest *projCached, x int8) {
  106. *dest = v.points[x/2]
  107. }
  108. // Given odd x with 0 < x < 2^7, return x*Q (in variable time).
  109. func (v *nafLookupTable8) SelectInto(dest *affineCached, x int8) {
  110. *dest = v.points[x/2]
  111. }