loadprecomputed.go 2.9 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091
  1. // Copyright 2015 The btcsuite developers
  2. // Copyright (c) 2015-2021 The Decred developers
  3. // Use of this source code is governed by an ISC
  4. // license that can be found in the LICENSE file.
  5. package secp256k1
  6. import (
  7. "compress/zlib"
  8. "encoding/base64"
  9. "encoding/binary"
  10. "io/ioutil"
  11. "strings"
  12. "sync"
  13. )
  14. //go:generate go run -tags gensecp256k1 genprecomps.go
  15. // bytePointTable describes a table used to house pre-computed values for
  16. // accelerating scalar base multiplication.
  17. type bytePointTable [32][256][2]FieldVal
  18. // s256BytePoints houses pre-computed values used to accelerate scalar base
  19. // multiplication such that they are only loaded on first use.
  20. var s256BytePoints = func() func() *bytePointTable {
  21. // mustLoadBytePoints decompresses and deserializes the pre-computed byte
  22. // points used to accelerate scalar base multiplication for the secp256k1
  23. // curve.
  24. //
  25. // This approach is used since it allows the compile to use significantly
  26. // less ram and be performed much faster than it is with hard-coding the
  27. // final in-memory data structure. At the same time, it is quite fast to
  28. // generate the in-memory data structure on first use with this approach
  29. // versus computing the table.
  30. //
  31. // It will panic on any errors because the data is hard coded and thus any
  32. // errors means something is wrong in the source code.
  33. var data *bytePointTable
  34. mustLoadBytePoints := func() {
  35. // There will be no byte points to load when generating them.
  36. bp := compressedBytePoints
  37. if len(bp) == 0 {
  38. return
  39. }
  40. // Decompress the pre-computed table used to accelerate scalar base
  41. // multiplication.
  42. decoder := base64.NewDecoder(base64.StdEncoding, strings.NewReader(bp))
  43. r, err := zlib.NewReader(decoder)
  44. if err != nil {
  45. panic(err)
  46. }
  47. serialized, err := ioutil.ReadAll(r)
  48. if err != nil {
  49. panic(err)
  50. }
  51. // Deserialize the precomputed byte points and set the memory table to
  52. // them.
  53. offset := 0
  54. var bytePoints bytePointTable
  55. for byteNum := 0; byteNum < len(bytePoints); byteNum++ {
  56. // All points in this window.
  57. for i := 0; i < len(bytePoints[byteNum]); i++ {
  58. px := &bytePoints[byteNum][i][0]
  59. py := &bytePoints[byteNum][i][1]
  60. for i := 0; i < len(px.n); i++ {
  61. px.n[i] = binary.LittleEndian.Uint32(serialized[offset:])
  62. offset += 4
  63. }
  64. for i := 0; i < len(py.n); i++ {
  65. py.n[i] = binary.LittleEndian.Uint32(serialized[offset:])
  66. offset += 4
  67. }
  68. }
  69. }
  70. data = &bytePoints
  71. }
  72. // Return a closure that initializes the data on first access. This is done
  73. // because the table takes a non-trivial amount of memory and initializing
  74. // it unconditionally would cause anything that imports the package, either
  75. // directly, or indirectly via transitive deps, to use that memory even if
  76. // the caller never accesses any parts of the package that actually needs
  77. // access to it.
  78. var loadBytePointsOnce sync.Once
  79. return func() *bytePointTable {
  80. loadBytePointsOnce.Do(mustLoadBytePoints)
  81. return data
  82. }
  83. }()