1 package sidh
2
3 import (
4 "errors"
5 "io"
6
7 "github.com/cloudflare/circl/dh/sidh/internal/common"
8 "github.com/cloudflare/circl/dh/sidh/internal/p434"
9 "github.com/cloudflare/circl/dh/sidh/internal/p503"
10 "github.com/cloudflare/circl/dh/sidh/internal/p751"
11 )
12
13
14
15
16 type KeyVariant uint
17
18
19
20 type key struct {
21
22 params *common.SidhParams
23
24 keyVariant KeyVariant
25 }
26
27
28
29
30 type PublicKey struct {
31 key
32
33 affine3Pt [3]common.Fp2
34 }
35
36
37
38
39 type PrivateKey struct {
40 key
41
42 Scalar []byte
43
44 S []byte
45 }
46
47
48 const (
49 Fp434 = common.Fp434
50 Fp503 = common.Fp503
51 Fp751 = common.Fp751
52 )
53
54 const (
55
56
57
58
59 KeyVariantSidhA KeyVariant = 1 << 0
60
61 KeyVariantSidhB = 1 << 1
62
63 KeyVariantSike = 1<<2 | KeyVariantSidhB
64 )
65
66
67 func (key *key) Variant() KeyVariant {
68 return key.keyVariant
69 }
70
71
72
73
74
75 func NewPublicKey(id uint8, v KeyVariant) *PublicKey {
76 return &PublicKey{key: key{params: common.Params(id), keyVariant: v}}
77 }
78
79
80
81
82 func (pub *PublicKey) Import(input []byte) error {
83 if len(input) != pub.Size() {
84 return errors.New("sidh: input to short")
85 }
86 ssSz := pub.params.SharedSecretSize
87 common.BytesToFp2(&pub.affine3Pt[0], input[0:ssSz], pub.params.Bytelen)
88 common.BytesToFp2(&pub.affine3Pt[1], input[ssSz:2*ssSz], pub.params.Bytelen)
89 common.BytesToFp2(&pub.affine3Pt[2], input[2*ssSz:3*ssSz], pub.params.Bytelen)
90 switch pub.params.ID {
91 case Fp434:
92 p434.ToMontgomery(&pub.affine3Pt[0], &pub.affine3Pt[0])
93 p434.ToMontgomery(&pub.affine3Pt[1], &pub.affine3Pt[1])
94 p434.ToMontgomery(&pub.affine3Pt[2], &pub.affine3Pt[2])
95 case Fp503:
96 p503.ToMontgomery(&pub.affine3Pt[0], &pub.affine3Pt[0])
97 p503.ToMontgomery(&pub.affine3Pt[1], &pub.affine3Pt[1])
98 p503.ToMontgomery(&pub.affine3Pt[2], &pub.affine3Pt[2])
99 case Fp751:
100 p751.ToMontgomery(&pub.affine3Pt[0], &pub.affine3Pt[0])
101 p751.ToMontgomery(&pub.affine3Pt[1], &pub.affine3Pt[1])
102 p751.ToMontgomery(&pub.affine3Pt[2], &pub.affine3Pt[2])
103 default:
104 panic("Unsupported key")
105 }
106 return nil
107 }
108
109
110
111 func (pub *PublicKey) Export(out []byte) {
112 var feTmp [3]common.Fp2
113 ssSz := pub.params.SharedSecretSize
114 switch pub.params.ID {
115 case Fp434:
116 p434.FromMontgomery(&feTmp[0], &pub.affine3Pt[0])
117 p434.FromMontgomery(&feTmp[1], &pub.affine3Pt[1])
118 p434.FromMontgomery(&feTmp[2], &pub.affine3Pt[2])
119 case Fp503:
120 p503.FromMontgomery(&feTmp[0], &pub.affine3Pt[0])
121 p503.FromMontgomery(&feTmp[1], &pub.affine3Pt[1])
122 p503.FromMontgomery(&feTmp[2], &pub.affine3Pt[2])
123 case Fp751:
124 p751.FromMontgomery(&feTmp[0], &pub.affine3Pt[0])
125 p751.FromMontgomery(&feTmp[1], &pub.affine3Pt[1])
126 p751.FromMontgomery(&feTmp[2], &pub.affine3Pt[2])
127 default:
128 panic("Unsupported key")
129 }
130 common.Fp2ToBytes(out[0:ssSz], &feTmp[0], pub.params.Bytelen)
131 common.Fp2ToBytes(out[ssSz:2*ssSz], &feTmp[1], pub.params.Bytelen)
132 common.Fp2ToBytes(out[2*ssSz:3*ssSz], &feTmp[2], pub.params.Bytelen)
133 }
134
135
136 func (pub *PublicKey) Size() int {
137 return pub.params.PublicKeySize
138 }
139
140
141
142
143
144 func NewPrivateKey(id uint8, v KeyVariant) *PrivateKey {
145 prv := &PrivateKey{key: key{params: common.Params(id), keyVariant: v}}
146 if (v & KeyVariantSidhA) == KeyVariantSidhA {
147 prv.Scalar = make([]byte, prv.params.A.SecretByteLen)
148 } else {
149 prv.Scalar = make([]byte, prv.params.B.SecretByteLen)
150 }
151 if v == KeyVariantSike {
152 prv.S = make([]byte, prv.params.MsgLen)
153 }
154 return prv
155 }
156
157
158
159 func (prv *PrivateKey) Export(out []byte) {
160 copy(out, prv.S)
161 copy(out[len(prv.S):], prv.Scalar)
162 }
163
164
165 func (prv *PrivateKey) Size() int {
166 tmp := len(prv.Scalar)
167 if prv.Variant() == KeyVariantSike {
168 tmp += prv.params.MsgLen
169 }
170 return tmp
171 }
172
173
174 func (prv *PrivateKey) SharedSecretSize() int {
175 return prv.params.SharedSecretSize
176 }
177
178
179
180
181
182 func (prv *PrivateKey) Import(input []byte) error {
183 if len(input) != prv.Size() {
184 return errors.New("sidh: input to short")
185 }
186 copy(prv.S, input[:len(prv.S)])
187 copy(prv.Scalar, input[len(prv.S):])
188 return nil
189 }
190
191
192
193
194
195
196
197 func (prv *PrivateKey) Generate(rand io.Reader) error {
198 var dp *common.DomainParams
199
200 if (prv.keyVariant & KeyVariantSidhA) == KeyVariantSidhA {
201 dp = &prv.params.A
202 } else {
203 dp = &prv.params.B
204 }
205
206 if prv.keyVariant == KeyVariantSike {
207 if _, err := io.ReadFull(rand, prv.S); err != nil {
208 return err
209 }
210 }
211
212
213
214
215
216
217
218 if _, err := io.ReadFull(rand, prv.Scalar); err != nil {
219 return err
220 }
221
222 prv.Scalar[len(prv.Scalar)-1] &= (1 << (dp.SecretBitLen % 8)) - 1
223
224
225
226
227 prv.Scalar[len(prv.Scalar)-1] |= 1 << ((dp.SecretBitLen % 8) - 1)
228
229 return nil
230 }
231
232
233 func (prv *PrivateKey) GeneratePublicKey(pub *PublicKey) {
234 isA := (prv.keyVariant & KeyVariantSidhA) == KeyVariantSidhA
235
236 if (pub.keyVariant != prv.keyVariant) || (pub.params.ID != prv.params.ID) {
237 panic("sidh: incompatible public key")
238 }
239
240 switch prv.params.ID {
241 case Fp434:
242 if isA {
243 p434.PublicKeyGenA(&pub.affine3Pt, prv.Scalar)
244 } else {
245 p434.PublicKeyGenB(&pub.affine3Pt, prv.Scalar)
246 }
247 case Fp503:
248 if isA {
249 p503.PublicKeyGenA(&pub.affine3Pt, prv.Scalar)
250 } else {
251 p503.PublicKeyGenB(&pub.affine3Pt, prv.Scalar)
252 }
253 case Fp751:
254 if isA {
255 p751.PublicKeyGenA(&pub.affine3Pt, prv.Scalar)
256 } else {
257 p751.PublicKeyGenB(&pub.affine3Pt, prv.Scalar)
258 }
259 default:
260 panic("Field not supported")
261 }
262 }
263
264
265
266
267
268
269 func (prv *PrivateKey) DeriveSecret(ss []byte, pub *PublicKey) {
270 isA := (prv.keyVariant & KeyVariantSidhA) == KeyVariantSidhA
271
272 if (pub.keyVariant == prv.keyVariant) || (pub.params.ID != prv.params.ID) {
273 panic("sidh: public and private are incompatible")
274 }
275
276 switch prv.params.ID {
277 case Fp434:
278 if isA {
279 p434.DeriveSecretA(ss, prv.Scalar, &pub.affine3Pt)
280 } else {
281 p434.DeriveSecretB(ss, prv.Scalar, &pub.affine3Pt)
282 }
283 case Fp503:
284 if isA {
285 p503.DeriveSecretA(ss, prv.Scalar, &pub.affine3Pt)
286 } else {
287 p503.DeriveSecretB(ss, prv.Scalar, &pub.affine3Pt)
288 }
289 case Fp751:
290 if isA {
291 p751.DeriveSecretA(ss, prv.Scalar, &pub.affine3Pt)
292 } else {
293 p751.DeriveSecretB(ss, prv.Scalar, &pub.affine3Pt)
294 }
295 default:
296 panic("Field not supported")
297 }
298 }
299
View as plain text