1 package hybrid
2
3
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 }
208
View as plain text