ecutil.go 2.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110
  1. // Package ecutil defines tools that help with elliptic curve related
  2. // computation
  3. package ecutil
  4. import (
  5. "crypto/elliptic"
  6. "math/big"
  7. "sync"
  8. "github.com/lestrrat-go/jwx/jwa"
  9. )
  10. // data for available curves. Some algorithms may be compiled in/out
  11. var curveToAlg = map[elliptic.Curve]jwa.EllipticCurveAlgorithm{}
  12. var algToCurve = map[jwa.EllipticCurveAlgorithm]elliptic.Curve{}
  13. var availableAlgs []jwa.EllipticCurveAlgorithm
  14. var availableCrvs []elliptic.Curve
  15. func RegisterCurve(crv elliptic.Curve, alg jwa.EllipticCurveAlgorithm) {
  16. curveToAlg[crv] = alg
  17. algToCurve[alg] = crv
  18. availableAlgs = append(availableAlgs, alg)
  19. availableCrvs = append(availableCrvs, crv)
  20. }
  21. func IsAvailable(alg jwa.EllipticCurveAlgorithm) bool {
  22. _, ok := algToCurve[alg]
  23. return ok
  24. }
  25. func AvailableAlgorithms() []jwa.EllipticCurveAlgorithm {
  26. return availableAlgs
  27. }
  28. func AvailableCurves() []elliptic.Curve {
  29. return availableCrvs
  30. }
  31. func AlgorithmForCurve(crv elliptic.Curve) (jwa.EllipticCurveAlgorithm, bool) {
  32. v, ok := curveToAlg[crv]
  33. return v, ok
  34. }
  35. func CurveForAlgorithm(alg jwa.EllipticCurveAlgorithm) (elliptic.Curve, bool) {
  36. v, ok := algToCurve[alg]
  37. return v, ok
  38. }
  39. const (
  40. // size of buffer that needs to be allocated for EC521 curve
  41. ec521BufferSize = 66 // (521 / 8) + 1
  42. )
  43. var ecpointBufferPool = sync.Pool{
  44. New: func() interface{} {
  45. // In most cases the curve bit size will be less than this length
  46. // so allocate the maximum, and keep reusing
  47. buf := make([]byte, 0, ec521BufferSize)
  48. return &buf
  49. },
  50. }
  51. func getCrvFixedBuffer(size int) []byte {
  52. //nolint:forcetypeassert
  53. buf := *(ecpointBufferPool.Get().(*[]byte))
  54. if size > ec521BufferSize && cap(buf) < size {
  55. buf = append(buf, make([]byte, size-cap(buf))...)
  56. }
  57. return buf[:size]
  58. }
  59. // ReleaseECPointBuffer releases the []byte buffer allocated.
  60. func ReleaseECPointBuffer(buf []byte) {
  61. buf = buf[:cap(buf)]
  62. buf[0] = 0x0
  63. for i := 1; i < len(buf); i *= 2 {
  64. copy(buf[i:], buf[:i])
  65. }
  66. buf = buf[:0]
  67. ecpointBufferPool.Put(&buf)
  68. }
  69. // AllocECPointBuffer allocates a buffer for the given point in the given
  70. // curve. This buffer should be released using the ReleaseECPointBuffer
  71. // function.
  72. func AllocECPointBuffer(v *big.Int, crv elliptic.Curve) []byte {
  73. // We need to create a buffer that fits the entire curve.
  74. // If the curve size is 66, that fits in 9 bytes. If the curve
  75. // size is 64, it fits in 8 bytes.
  76. bits := crv.Params().BitSize
  77. // For most common cases we know before hand what the byte length
  78. // is going to be. optimize
  79. var inBytes int
  80. switch bits {
  81. case 224, 256, 384: // TODO: use constant?
  82. inBytes = bits / 8
  83. case 521:
  84. inBytes = ec521BufferSize
  85. default:
  86. inBytes = bits / 8
  87. if (bits % 8) != 0 {
  88. inBytes++
  89. }
  90. }
  91. buf := getCrvFixedBuffer(inBytes)
  92. v.FillBytes(buf)
  93. return buf
  94. }