]> Cypherpunks.ru repositories - gogost.git/blob - gost3410/curve.go
Slightly more endianness documentation
[gogost.git] / gost3410 / curve.go
1 // GoGOST -- Pure Go GOST cryptographic functions library
2 // Copyright (C) 2015-2023 Sergey Matveev <stargrave@stargrave.org>
3 //
4 // This program is free software: you can redistribute it and/or modify
5 // it under the terms of the GNU General Public License as published by
6 // the Free Software Foundation, version 3 of the License.
7 //
8 // This program is distributed in the hope that it will be useful,
9 // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11 // GNU General Public License for more details.
12 //
13 // You should have received a copy of the GNU General Public License
14 // along with this program.  If not, see <http://www.gnu.org/licenses/>.
15
16 package gost3410
17
18 import (
19         "errors"
20         "math/big"
21 )
22
23 var (
24         zero    *big.Int = big.NewInt(0)
25         bigInt1 *big.Int = big.NewInt(1)
26         bigInt2 *big.Int = big.NewInt(2)
27         bigInt3 *big.Int = big.NewInt(3)
28         bigInt4 *big.Int = big.NewInt(4)
29 )
30
31 type Curve struct {
32         Name string // Just simple identifier
33
34         P *big.Int // Characteristic of the underlying prime field
35         Q *big.Int // Elliptic curve subgroup order
36
37         Co *big.Int // Cofactor
38
39         // Equation coefficients of the elliptic curve in canonical form
40         A *big.Int
41         B *big.Int
42
43         // Equation coefficients of the elliptic curve in twisted Edwards form
44         E *big.Int
45         D *big.Int
46
47         // Basic point X and Y coordinates
48         X *big.Int
49         Y *big.Int
50
51         // Cached s/t parameters for Edwards curve points conversion
52         edS *big.Int
53         edT *big.Int
54 }
55
56 func NewCurve(p, q, a, b, x, y, e, d, co *big.Int) (*Curve, error) {
57         c := Curve{
58                 Name: "unknown",
59                 P:    p,
60                 Q:    q,
61                 A:    a,
62                 B:    b,
63                 X:    x,
64                 Y:    y,
65         }
66         r1 := big.NewInt(0)
67         r2 := big.NewInt(0)
68         r1.Mul(c.Y, c.Y)
69         r1.Mod(r1, c.P)
70         r2.Mul(c.X, c.X)
71         r2.Add(r2, c.A)
72         r2.Mul(r2, c.X)
73         r2.Add(r2, c.B)
74         r2.Mod(r2, c.P)
75         c.pos(r2)
76         if r1.Cmp(r2) != 0 {
77                 return nil, errors.New("gogost/gost3410: invalid curve parameters")
78         }
79         if e != nil && d != nil {
80                 c.E = e
81                 c.D = d
82         }
83         if co == nil {
84                 c.Co = bigInt1
85         } else {
86                 c.Co = co
87         }
88         return &c, nil
89 }
90
91 // Get the size of the point's coordinate in bytes.
92 // 32 for 256-bit curves, 64 for 512-bit ones.
93 func (c *Curve) PointSize() int {
94         return pointSize(c.P)
95 }
96
97 func (c *Curve) pos(v *big.Int) {
98         if v.Cmp(zero) < 0 {
99                 v.Add(v, c.P)
100         }
101 }
102
103 func (c *Curve) add(p1x, p1y, p2x, p2y *big.Int) {
104         var t, tx, ty big.Int
105         if p1x.Cmp(p2x) == 0 && p1y.Cmp(p2y) == 0 {
106                 // double
107                 t.Mul(p1x, p1x)
108                 t.Mul(&t, bigInt3)
109                 t.Add(&t, c.A)
110                 tx.Mul(bigInt2, p1y)
111                 tx.ModInverse(&tx, c.P)
112                 t.Mul(&t, &tx)
113                 t.Mod(&t, c.P)
114         } else {
115                 tx.Sub(p2x, p1x)
116                 tx.Mod(&tx, c.P)
117                 c.pos(&tx)
118                 ty.Sub(p2y, p1y)
119                 ty.Mod(&ty, c.P)
120                 c.pos(&ty)
121                 t.ModInverse(&tx, c.P)
122                 t.Mul(&t, &ty)
123                 t.Mod(&t, c.P)
124         }
125         tx.Mul(&t, &t)
126         tx.Sub(&tx, p1x)
127         tx.Sub(&tx, p2x)
128         tx.Mod(&tx, c.P)
129         c.pos(&tx)
130         ty.Sub(p1x, &tx)
131         ty.Mul(&ty, &t)
132         ty.Sub(&ty, p1y)
133         ty.Mod(&ty, c.P)
134         c.pos(&ty)
135         p1x.Set(&tx)
136         p1y.Set(&ty)
137 }
138
139 func (c *Curve) Exp(degree, xS, yS *big.Int) (*big.Int, *big.Int, error) {
140         if degree.Cmp(zero) == 0 {
141                 return nil, nil, errors.New("gogost/gost3410: zero degree value")
142         }
143         dg := big.NewInt(0).Sub(degree, bigInt1)
144         tx := big.NewInt(0).Set(xS)
145         ty := big.NewInt(0).Set(yS)
146         cx := big.NewInt(0).Set(xS)
147         cy := big.NewInt(0).Set(yS)
148         for dg.Cmp(zero) != 0 {
149                 if dg.Bit(0) == 1 {
150                         c.add(tx, ty, cx, cy)
151                 }
152                 dg.Rsh(dg, 1)
153                 c.add(cx, cy, cx, cy)
154         }
155         return tx, ty, nil
156 }
157
158 func (our *Curve) Equal(their *Curve) bool {
159         return our.P.Cmp(their.P) == 0 &&
160                 our.Q.Cmp(their.Q) == 0 &&
161                 our.A.Cmp(their.A) == 0 &&
162                 our.B.Cmp(their.B) == 0 &&
163                 our.X.Cmp(their.X) == 0 &&
164                 our.Y.Cmp(their.Y) == 0 &&
165                 ((our.E == nil && their.E == nil) || our.E.Cmp(their.E) == 0) &&
166                 ((our.D == nil && their.D == nil) || our.D.Cmp(their.D) == 0) &&
167                 our.Co.Cmp(their.Co) == 0
168 }
169
170 func (c *Curve) String() string {
171         return c.Name
172 }