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  }