curve.go 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  	secp "github.com/decred/dcrd/dcrec/secp256k1/v4"
  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 = secp.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 secp.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  	secp.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 secp.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  	secp.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  	secp.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  	secp.ScalarMultNonConst(k, point, result)
  68  }
  69  
  70  // ParseJacobian parses a byte slice point as a secp.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  
  76  	if len(point) != 33 {
  77  		str := fmt.Sprintf("invalid nonce: invalid length: %v",
  78  			len(point))
  79  		return JacobianPoint{}, makeError(secp.ErrPubKeyInvalidLen, str)
  80  	}
  81  
  82  	if point[0] == 0x00 {
  83  		return infinityPoint, nil
  84  	}
  85  
  86  	noncePk, err := secp.ParsePubKey(point)
  87  	if err != nil {
  88  		return JacobianPoint{}, err
  89  	}
  90  	noncePk.AsJacobian(&result)
  91  
  92  	return result, nil
  93  }
  94  
  95  // JacobianToByteSlice converts the passed JacobianPoint to a Pubkey
  96  // and serializes that to a byte slice. If the JacobianPoint is the infinity
  97  // point, a zero slice is returned.
  98  func JacobianToByteSlice(point JacobianPoint) []byte {
  99  	if point.X == infinityPoint.X && point.Y == infinityPoint.Y {
 100  		return make([]byte, 33)
 101  	}
 102  
 103  	point.ToAffine()
 104  
 105  	return NewPublicKey(
 106  		&point.X, &point.Y,
 107  	).SerializeCompressed()
 108  }
 109  
 110  // GeneratorJacobian sets the passed JacobianPoint to the Generator Point.
 111  func GeneratorJacobian(jacobian *JacobianPoint) {
 112  	var k ModNScalar
 113  	k.SetInt(1)
 114  	ScalarBaseMultNonConst(&k, jacobian)
 115  }
 116