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