1 package hybrid
2
3 import (
4 "bytes"
5 cryptoRand "crypto/rand"
6 "crypto/subtle"
7
8 "github.com/cloudflare/circl/dh/x25519"
9 "github.com/cloudflare/circl/dh/x448"
10 "github.com/cloudflare/circl/internal/sha3"
11 "github.com/cloudflare/circl/kem"
12 )
13
14 type xPublicKey struct {
15 scheme *xScheme
16 key []byte
17 }
18 type xPrivateKey struct {
19 scheme *xScheme
20 key []byte
21 }
22 type xScheme struct {
23 size int
24 }
25
26 var (
27 x25519Kem = &xScheme{x25519.Size}
28 x448Kem = &xScheme{x448.Size}
29 )
30
31 func (sch *xScheme) Name() string {
32 switch sch.size {
33 case x25519.Size:
34 return "X25519"
35 case x448.Size:
36 return "X448"
37 }
38 panic(kem.ErrTypeMismatch)
39 }
40
41 func (sch *xScheme) PublicKeySize() int { return sch.size }
42 func (sch *xScheme) PrivateKeySize() int { return sch.size }
43 func (sch *xScheme) SeedSize() int { return sch.size }
44 func (sch *xScheme) SharedKeySize() int { return sch.size }
45 func (sch *xScheme) CiphertextSize() int { return sch.size }
46 func (sch *xScheme) EncapsulationSeedSize() int { return sch.size }
47
48 func (sk *xPrivateKey) Scheme() kem.Scheme { return sk.scheme }
49 func (pk *xPublicKey) Scheme() kem.Scheme { return pk.scheme }
50
51 func (sk *xPrivateKey) MarshalBinary() ([]byte, error) {
52 ret := make([]byte, len(sk.key))
53 copy(ret, sk.key)
54 return ret, nil
55 }
56
57 func (sk *xPrivateKey) Equal(other kem.PrivateKey) bool {
58 oth, ok := other.(*xPrivateKey)
59 if !ok {
60 return false
61 }
62 if oth.scheme != sk.scheme {
63 return false
64 }
65 return subtle.ConstantTimeCompare(oth.key, sk.key) == 1
66 }
67
68 func (sk *xPrivateKey) Public() kem.PublicKey {
69 pk := xPublicKey{sk.scheme, make([]byte, sk.scheme.size)}
70 switch sk.scheme.size {
71 case x25519.Size:
72 var sk2, pk2 x25519.Key
73 copy(sk2[:], sk.key)
74 x25519.KeyGen(&pk2, &sk2)
75 copy(pk.key, pk2[:])
76 case x448.Size:
77 var sk2, pk2 x448.Key
78 copy(sk2[:], sk.key)
79 x448.KeyGen(&pk2, &sk2)
80 copy(pk.key, pk2[:])
81 }
82 return &pk
83 }
84
85 func (pk *xPublicKey) Equal(other kem.PublicKey) bool {
86 oth, ok := other.(*xPublicKey)
87 if !ok {
88 return false
89 }
90 if oth.scheme != pk.scheme {
91 return false
92 }
93 return bytes.Equal(oth.key, pk.key)
94 }
95
96 func (pk *xPublicKey) MarshalBinary() ([]byte, error) {
97 ret := make([]byte, pk.scheme.size)
98 copy(ret, pk.key)
99 return ret, nil
100 }
101
102 func (sch *xScheme) GenerateKeyPair() (kem.PublicKey, kem.PrivateKey, error) {
103 seed := make([]byte, sch.SeedSize())
104 _, err := cryptoRand.Read(seed)
105 if err != nil {
106 return nil, nil, err
107 }
108 pk, sk := sch.DeriveKeyPair(seed)
109 return pk, sk, nil
110 }
111
112 func (sch *xScheme) DeriveKeyPair(seed []byte) (kem.PublicKey, kem.PrivateKey) {
113 if len(seed) != sch.SeedSize() {
114 panic(kem.ErrSeedSize)
115 }
116 sk := xPrivateKey{scheme: sch, key: make([]byte, sch.size)}
117
118 h := sha3.NewShake256()
119 _, _ = h.Write(seed)
120 _, _ = h.Read(sk.key)
121
122 return sk.Public(), &sk
123 }
124
125 func (sch *xScheme) Encapsulate(pk kem.PublicKey) (ct, ss []byte, err error) {
126 seed := make([]byte, sch.EncapsulationSeedSize())
127 _, err = cryptoRand.Read(seed)
128 if err != nil {
129 return
130 }
131 return sch.EncapsulateDeterministically(pk, seed)
132 }
133
134 func (pk *xPublicKey) X(sk *xPrivateKey) []byte {
135 if pk.scheme != sk.scheme {
136 panic(kem.ErrTypeMismatch)
137 }
138
139 switch pk.scheme.size {
140 case x25519.Size:
141 var ss2, pk2, sk2 x25519.Key
142 copy(pk2[:], pk.key)
143 copy(sk2[:], sk.key)
144 x25519.Shared(&ss2, &sk2, &pk2)
145 return ss2[:]
146 case x448.Size:
147 var ss2, pk2, sk2 x448.Key
148 copy(pk2[:], pk.key)
149 copy(sk2[:], sk.key)
150 x448.Shared(&ss2, &sk2, &pk2)
151 return ss2[:]
152 }
153 panic(kem.ErrTypeMismatch)
154 }
155
156 func (sch *xScheme) 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.(*xPublicKey)
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.(*xPrivateKey))
169 ct, _ = pk2.MarshalBinary()
170 return
171 }
172
173 func (sch *xScheme) 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.(*xPrivateKey)
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.(*xPublicKey).X(priv)
189 return ss, nil
190 }
191
192 func (sch *xScheme) UnmarshalBinaryPublicKey(buf []byte) (kem.PublicKey, error) {
193 if len(buf) != sch.PublicKeySize() {
194 return nil, kem.ErrPubKeySize
195 }
196 ret := xPublicKey{sch, make([]byte, sch.size)}
197 copy(ret.key, buf)
198 return &ret, nil
199 }
200
201 func (sch *xScheme) UnmarshalBinaryPrivateKey(buf []byte) (kem.PrivateKey, error) {
202 if len(buf) != sch.PrivateKeySize() {
203 return nil, kem.ErrPrivKeySize
204 }
205 ret := xPrivateKey{sch, make([]byte, sch.size)}
206 copy(ret.key, buf)
207 return &ret, nil
208 }
209
View as plain text