curve.mx raw

   1  // Copyright (c) 2015-2021 The btcsuite developers
   2  // Copyright (c) 2015-2021 The Decred developers
   3  
   4  package btcec
   5  
   6  import (
   7  	"fmt"
   8  
   9  	"smesh.lol/pkg/nostr/ec/secp256k1"
  10  )
  11  
  12  // JacobianPoint is an element of the group formed by the secp256k1 curve in
  13  // Jacobian projective coordinates and thus represents a point on the curve.
  14  type JacobianPoint = secp256k1.JacobianPoint
  15  
  16  // infinityPoint is the jacobian representation of the point at infinity.
  17  var infinityPoint JacobianPoint
  18  
  19  // MakeJacobianPoint returns a Jacobian point with the provided X, Y, and Z
  20  // coordinates.
  21  func MakeJacobianPoint(x, y, z *FieldVal) JacobianPoint {
  22  	return secp256k1.MakeJacobianPoint(x, y, z)
  23  }
  24  
  25  // AddNonConst adds the passed Jacobian points together and stores the result
  26  // in the provided result param in *non-constant* time.
  27  func AddNonConst(p1, p2, result *JacobianPoint) {
  28  	secp256k1.AddNonConst(p1, p2, result)
  29  }
  30  
  31  // DecompressY attempts to calculate the Y coordinate for the given X
  32  // coordinate such that the result pair is a point on the secp256k1 curve. It
  33  // adjusts Y based on the desired oddness and returns whether or not it was
  34  // successful since not all X coordinates are valid.
  35  //
  36  // The magnitude of the provided X coordinate field val must be a max of 8 for
  37  // a correct result. The resulting Y field val will have a max magnitude of 2.
  38  func DecompressY(x *FieldVal, odd bool, resultY *FieldVal) bool {
  39  	return secp256k1.DecompressY(x, odd, resultY)
  40  }
  41  
  42  // DoubleNonConst doubles the passed Jacobian point and stores the result in
  43  // the provided result parameter in *non-constant* time.
  44  //
  45  // NOTE: The point must be normalized for this function to return the correct
  46  // result. The resulting point will be normalized.
  47  func DoubleNonConst(p, result *JacobianPoint) {
  48  	secp256k1.DoubleNonConst(p, result)
  49  }
  50  
  51  // ScalarBaseMultNonConst multiplies k*G where G is the base point of the group
  52  // and k is a big endian integer. The result is stored in Jacobian coordinates
  53  // (x1, y1, z1).
  54  //
  55  // NOTE: The resulting point will be normalized.
  56  func ScalarBaseMultNonConst(k *ModNScalar, result *JacobianPoint) {
  57  	secp256k1.ScalarBaseMultNonConst(k, result)
  58  }
  59  
  60  // ScalarMultNonConst multiplies k*P where k is a big endian integer modulo the
  61  // curve order and P is a point in Jacobian projective coordinates and stores
  62  // the result in the provided Jacobian point.
  63  //
  64  // NOTE: The point must be normalized for this function to return the correct
  65  // result. The resulting point will be normalized.
  66  func ScalarMultNonConst(k *ModNScalar, point, result *JacobianPoint) {
  67  	secp256k1.ScalarMultNonConst(k, point, result)
  68  }
  69  
  70  // ParseJacobian parses a byte slice point as a secp256k1.Publickey and returns the
  71  // pubkey as a JacobianPoint. If the nonce is a zero slice, the infinityPoint
  72  // is returned.
  73  func ParseJacobian(point []byte) (JacobianPoint, error) {
  74  	var result JacobianPoint
  75  	if len(point) != 33 {
  76  		str := fmt.Sprintf(
  77  			"invalid nonce: invalid length: %v",
  78  			len(point),
  79  		)
  80  		return JacobianPoint{}, makeError(secp256k1.ErrPubKeyInvalidLen, str)
  81  	}
  82  	if point[0] == 0x00 {
  83  		return infinityPoint, nil
  84  	}
  85  	noncePk, err := secp256k1.ParsePubKey(point)
  86  	if err != nil {
  87  		return JacobianPoint{}, err
  88  	}
  89  	noncePk.AsJacobian(&result)
  90  	return result, nil
  91  }
  92  
  93  // JacobianToByteSlice converts the passed JacobianPoint to a Pubkey
  94  // and serializes that to a byte slice. If the JacobianPoint is the infinity
  95  // point, a zero slice is returned.
  96  func JacobianToByteSlice(point JacobianPoint) []byte {
  97  	if point.X == infinityPoint.X && point.Y == infinityPoint.Y {
  98  		return []byte{:33}
  99  	}
 100  	point.ToAffine()
 101  	return NewPublicKey(
 102  		&point.X, &point.Y,
 103  	).SerializeCompressed()
 104  }
 105  
 106  // GeneratorJacobian sets the passed JacobianPoint to the Generator Point.
 107  func GeneratorJacobian(jacobian *JacobianPoint) {
 108  	var k ModNScalar
 109  	k.SetInt(1)
 110  	ScalarBaseMultNonConst(&k, jacobian)
 111  }
 112