github.com/cloudflare/circl@v1.5.0/kem/hybrid/ckem.go (about) 1 package hybrid 2 3 // TODO move over to crypto/ecdh once we can assume Go 1.20. 4 5 import ( 6 "crypto/elliptic" 7 cryptoRand "crypto/rand" 8 "crypto/subtle" 9 "math/big" 10 11 "github.com/cloudflare/circl/kem" 12 "github.com/cloudflare/circl/xof" 13 ) 14 15 type cPublicKey struct { 16 scheme *cScheme 17 x, y *big.Int 18 } 19 type cPrivateKey struct { 20 scheme *cScheme 21 key []byte 22 } 23 type cScheme struct { 24 curve elliptic.Curve 25 } 26 27 var p256Kem = &cScheme{elliptic.P256()} 28 29 func (sch *cScheme) scSize() int { 30 return (sch.curve.Params().N.BitLen() + 7) / 8 31 } 32 33 func (sch *cScheme) ptSize() int { 34 return (sch.curve.Params().BitSize + 7) / 8 35 } 36 37 func (sch *cScheme) Name() string { 38 return sch.curve.Params().Name 39 } 40 41 func (sch *cScheme) PublicKeySize() int { 42 return 2*sch.ptSize() + 1 43 } 44 45 func (sch *cScheme) PrivateKeySize() int { 46 return sch.scSize() 47 } 48 49 func (sch *cScheme) SeedSize() int { 50 return sch.PrivateKeySize() 51 } 52 53 func (sch *cScheme) SharedKeySize() int { 54 return sch.ptSize() 55 } 56 57 func (sch *cScheme) CiphertextSize() int { 58 return sch.PublicKeySize() 59 } 60 61 func (sch *cScheme) EncapsulationSeedSize() int { 62 return sch.SeedSize() 63 } 64 65 func (sk *cPrivateKey) Scheme() kem.Scheme { return sk.scheme } 66 func (pk *cPublicKey) Scheme() kem.Scheme { return pk.scheme } 67 68 func (sk *cPrivateKey) MarshalBinary() ([]byte, error) { 69 ret := make([]byte, len(sk.key)) 70 copy(ret, sk.key) 71 return ret, nil 72 } 73 74 func (sk *cPrivateKey) Equal(other kem.PrivateKey) bool { 75 oth, ok := other.(*cPrivateKey) 76 if !ok { 77 return false 78 } 79 if oth.scheme != sk.scheme { 80 return false 81 } 82 return subtle.ConstantTimeCompare(oth.key, sk.key) == 1 83 } 84 85 func (sk *cPrivateKey) Public() kem.PublicKey { 86 x, y := sk.scheme.curve.ScalarBaseMult(sk.key) 87 return &cPublicKey{ 88 sk.scheme, 89 x, 90 y, 91 } 92 } 93 94 func (pk *cPublicKey) Equal(other kem.PublicKey) bool { 95 oth, ok := other.(*cPublicKey) 96 if !ok { 97 return false 98 } 99 if oth.scheme != pk.scheme { 100 return false 101 } 102 return oth.x.Cmp(pk.x) == 0 && oth.y.Cmp(pk.y) == 0 103 } 104 105 func (pk *cPublicKey) MarshalBinary() ([]byte, error) { 106 return elliptic.Marshal(pk.scheme.curve, pk.x, pk.y), nil 107 } 108 109 func (sch *cScheme) GenerateKeyPair() (kem.PublicKey, kem.PrivateKey, error) { 110 seed := make([]byte, sch.SeedSize()) 111 _, err := cryptoRand.Read(seed) 112 if err != nil { 113 return nil, nil, err 114 } 115 pk, sk := sch.DeriveKeyPair(seed) 116 return pk, sk, nil 117 } 118 119 func (sch *cScheme) DeriveKeyPair(seed []byte) (kem.PublicKey, kem.PrivateKey) { 120 if len(seed) != sch.SeedSize() { 121 panic(kem.ErrSeedSize) 122 } 123 h := xof.SHAKE256.New() 124 _, _ = h.Write(seed) 125 key, x, y, err := elliptic.GenerateKey(sch.curve, h) 126 if err != nil { 127 panic(err) 128 } 129 130 sk := cPrivateKey{scheme: sch, key: key} 131 pk := cPublicKey{scheme: sch, x: x, y: y} 132 133 return &pk, &sk 134 } 135 136 func (sch *cScheme) Encapsulate(pk kem.PublicKey) (ct, ss []byte, err error) { 137 seed := make([]byte, sch.EncapsulationSeedSize()) 138 _, err = cryptoRand.Read(seed) 139 if err != nil { 140 return 141 } 142 return sch.EncapsulateDeterministically(pk, seed) 143 } 144 145 func (pk *cPublicKey) X(sk *cPrivateKey) []byte { 146 if pk.scheme != sk.scheme { 147 panic(kem.ErrTypeMismatch) 148 } 149 150 sharedKey := make([]byte, pk.scheme.SharedKeySize()) 151 xShared, _ := pk.scheme.curve.ScalarMult(pk.x, pk.y, sk.key) 152 xShared.FillBytes(sharedKey) 153 return sharedKey 154 } 155 156 func (sch *cScheme) EncapsulateDeterministically( 157 pk kem.PublicKey, seed []byte, 158 ) (ct, ss []byte, err error) { 159 if len(seed) != sch.EncapsulationSeedSize() { 160 return nil, nil, kem.ErrSeedSize 161 } 162 pub, ok := pk.(*cPublicKey) 163 if !ok || pub.scheme != sch { 164 return nil, nil, kem.ErrTypeMismatch 165 } 166 167 pk2, sk2 := sch.DeriveKeyPair(seed) 168 ss = pub.X(sk2.(*cPrivateKey)) 169 ct, _ = pk2.MarshalBinary() 170 return 171 } 172 173 func (sch *cScheme) Decapsulate(sk kem.PrivateKey, ct []byte) ([]byte, error) { 174 if len(ct) != sch.CiphertextSize() { 175 return nil, kem.ErrCiphertextSize 176 } 177 178 priv, ok := sk.(*cPrivateKey) 179 if !ok || priv.scheme != sch { 180 return nil, kem.ErrTypeMismatch 181 } 182 183 pk, err := sch.UnmarshalBinaryPublicKey(ct) 184 if err != nil { 185 return nil, err 186 } 187 188 ss := pk.(*cPublicKey).X(priv) 189 return ss, nil 190 } 191 192 func (sch *cScheme) UnmarshalBinaryPublicKey(buf []byte) (kem.PublicKey, error) { 193 if len(buf) != sch.PublicKeySize() { 194 return nil, kem.ErrPubKeySize 195 } 196 x, y := elliptic.Unmarshal(sch.curve, buf) 197 return &cPublicKey{sch, x, y}, nil 198 } 199 200 func (sch *cScheme) UnmarshalBinaryPrivateKey(buf []byte) (kem.PrivateKey, error) { 201 if len(buf) != sch.PrivateKeySize() { 202 return nil, kem.ErrPrivKeySize 203 } 204 ret := cPrivateKey{sch, make([]byte, sch.PrivateKeySize())} 205 copy(ret.key, buf) 206 return &ret, nil 207 }