github.com/cloudflare/circl@v1.5.0/dh/sidh/sidh.go (about) 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 // I keep it bool in order to be able to apply logical NOT. 14 // 15 // Deprecated: not cryptographically secure. 16 type KeyVariant uint 17 18 // Base type for public and private key. Used mainly to carry domain 19 // parameters. 20 type key struct { 21 // Domain parameters of the algorithm to be used with a key 22 params *common.SidhParams 23 // Flag indicates whether corresponds to 2-, 3-torsion group or SIKE 24 keyVariant KeyVariant 25 } 26 27 // Defines operations on public key 28 // 29 // Deprecated: not cryptographically secure. 30 type PublicKey struct { 31 key 32 // x-coordinates of P,Q,P-Q in this exact order 33 affine3Pt [3]common.Fp2 34 } 35 36 // Defines operations on private key 37 // 38 // Deprecated: not cryptographically secure. 39 type PrivateKey struct { 40 key 41 // Secret key 42 Scalar []byte 43 // Used only by KEM 44 S []byte 45 } 46 47 // Identifiers correspond to the bitlength of the prime field characteristic. 48 const ( 49 Fp434 = common.Fp434 50 Fp503 = common.Fp503 51 Fp751 = common.Fp751 52 ) 53 54 const ( 55 // First 2 bits identify SIDH variant third bit indicates 56 // whether key is a SIKE variant (set) or SIDH (not set) 57 58 // 001 - SIDH: corresponds to 2-torsion group 59 KeyVariantSidhA KeyVariant = 1 << 0 60 // 010 - SIDH: corresponds to 3-torsion group 61 KeyVariantSidhB = 1 << 1 62 // 110 - SIKE 63 KeyVariantSike = 1<<2 | KeyVariantSidhB 64 ) 65 66 // Accessor to key variant. 67 func (key *key) Variant() KeyVariant { 68 return key.keyVariant 69 } 70 71 // NewPublicKey initializes public key. 72 // Usage of this function guarantees that the object is correctly initialized. 73 // 74 // Deprecated: not cryptographically secure. 75 func NewPublicKey(id uint8, v KeyVariant) *PublicKey { 76 return &PublicKey{key: key{params: common.Params(id), keyVariant: v}} 77 } 78 79 // Import clears content of the public key currently stored in the structure 80 // and imports key stored in the byte string. Returns error in case byte string 81 // size is wrong. Doesn't perform any validation. 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 // Exports currently stored key. In case structure hasn't been filled with key data 110 // returned byte string is filled with zeros. 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 // Size returns size of the public key in bytes. 136 func (pub *PublicKey) Size() int { 137 return pub.params.PublicKeySize 138 } 139 140 // NewPrivateKey initializes private key. 141 // Usage of this function guarantees that the object is correctly initialized. 142 // 143 // Deprecated: not cryptographically secure. 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 // Exports currently stored key. In case structure hasn't been filled with key data 158 // returned byte string is filled with zeros. 159 func (prv *PrivateKey) Export(out []byte) { 160 copy(out, prv.S) 161 copy(out[len(prv.S):], prv.Scalar) 162 } 163 164 // Size returns size of the private key in bytes. 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 // Size returns size of the shared secret. 174 func (prv *PrivateKey) SharedSecretSize() int { 175 return prv.params.SharedSecretSize 176 } 177 178 // Import clears content of the private key currently stored in the structure 179 // and imports key from octet string. In case of SIKE, the random value 'S' 180 // must be prepended to the value of actual private key (see SIKE spec for details). 181 // Function doesn't import public key value to PrivateKey object. 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 // Generates random private key for SIDH or SIKE. Generated value is 192 // formed as little-endian integer from key-space <2^(e2-1)..2^e2 - 1> 193 // for KeyVariant_A or <2^(s-1)..2^s - 1>, where s = floor(log_2(3^e3)), 194 // for KeyVariant_B. 195 // 196 // Returns error in case user provided RNG fails. 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 // Private key generation takes advantage of the fact that keyspace for secret 213 // key is (0, 2^x - 1), for some positive value of 'x' (see SIKE, 1.3.8). 214 // It means that all bytes in the secret key, but the last one, can take any 215 // value between <0x00,0xFF>. Similarly for the last byte, but generation 216 // needs to chop off some bits, to make sure generated value is an element of 217 // a key-space. 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 // Make sure scalar is SecretBitLen long. SIKE spec says that key 224 // space starts from 0, but I'm not comfortable with having low 225 // value scalars used for private keys. It is still secure as per 226 // table 5.1 in [SIKE]. 227 prv.Scalar[len(prv.Scalar)-1] |= 1 << ((dp.SecretBitLen % 8) - 1) 228 229 return nil 230 } 231 232 // Generates public key. 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 // Computes a SIDH shared secret. Function requires that pub has different 265 // KeyVariant than prv. Length of returned output is 2*ceil(log_2 P)/8), 266 // where P is a prime defining finite field. 267 // 268 // Caller must make sure key SIDH key pair is not used more than once. 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 }