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 "crypto/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 func _infinityPoint() JacobianPoint { return JacobianPoint{} }
17 18 // MakeJacobianPoint returns a Jacobian point with the provided X, Y, and Z
19 // coordinates.
20 func MakeJacobianPoint(x, y, z *FieldVal) JacobianPoint {
21 return secp256k1.MakeJacobianPoint(x, y, z)
22 }
23 24 // AddNonConst adds the passed Jacobian points together and stores the result
25 // in the provided result param in *non-constant* time.
26 func AddNonConst(p1, p2, result *JacobianPoint) {
27 secp256k1.AddNonConst(p1, p2, result)
28 }
29 30 // DecompressY attempts to calculate the Y coordinate for the given X
31 // coordinate such that the result pair is a point on the secp256k1 curve. It
32 // adjusts Y based on the desired oddness and returns whether or not it was
33 // successful since not all X coordinates are valid.
34 //
35 // The magnitude of the provided X coordinate field val must be a max of 8 for
36 // a correct result. The resulting Y field val will have a max magnitude of 2.
37 func DecompressY(x *FieldVal, odd bool, resultY *FieldVal) bool {
38 return secp256k1.DecompressY(x, odd, resultY)
39 }
40 41 // DoubleNonConst doubles the passed Jacobian point and stores the result in
42 // the provided result parameter in *non-constant* time.
43 //
44 // NOTE: The point must be normalized for this function to return the correct
45 // result. The resulting point will be normalized.
46 func DoubleNonConst(p, result *JacobianPoint) {
47 secp256k1.DoubleNonConst(p, result)
48 }
49 50 // ScalarBaseMultNonConst multiplies k*G where G is the base point of the group
51 // and k is a big endian integer. The result is stored in Jacobian coordinates
52 // (x1, y1, z1).
53 //
54 // NOTE: The resulting point will be normalized.
55 func ScalarBaseMultNonConst(k *ModNScalar, result *JacobianPoint) {
56 secp256k1.ScalarBaseMultNonConst(k, result)
57 }
58 59 // ScalarMultNonConst multiplies k*P where k is a big endian integer modulo the
60 // curve order and P is a point in Jacobian projective coordinates and stores
61 // the result in the provided Jacobian point.
62 //
63 // NOTE: The point must be normalized for this function to return the correct
64 // result. The resulting point will be normalized.
65 func ScalarMultNonConst(k *ModNScalar, point, result *JacobianPoint) {
66 secp256k1.ScalarMultNonConst(k, point, result)
67 }
68 69 // ParseJacobian parses a byte slice point as a secp256k1.Publickey and returns the
70 // pubkey as a JacobianPoint. If the nonce is a zero slice, the infinityPoint
71 // is returned.
72 func ParseJacobian(point []byte) (JacobianPoint, error) {
73 var result JacobianPoint
74 if len(point) != 33 {
75 str := fmt.Sprintf(
76 "invalid nonce: invalid length: %v",
77 len(point),
78 )
79 return JacobianPoint{}, makeError(secp256k1.ErrPubKeyInvalidLen, str)
80 }
81 if point[0] == 0x00 {
82 return _infinityPoint(), nil
83 }
84 noncePk, err := secp256k1.ParsePubKey(point)
85 if err != nil {
86 return JacobianPoint{}, err
87 }
88 noncePk.AsJacobian(&result)
89 return result, nil
90 }
91 92 // JacobianToByteSlice converts the passed JacobianPoint to a Pubkey
93 // and serializes that to a byte slice. If the JacobianPoint is the infinity
94 // point, a zero slice is returned.
95 func JacobianToByteSlice(point JacobianPoint) []byte {
96 inf := _infinityPoint()
97 if point.X == inf.X && point.Y == inf.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