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