]> Cypherpunks.ru repositories - gogost.git/blob - gost3410/curve.go
More thread-safe gost3410
[gogost.git] / gost3410 / curve.go
1 // GoGOST -- Pure Go GOST cryptographic functions library
2 // Copyright (C) 2015-2021 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 func (c *Curve) PointSize() int {
92         return PointSize(c.P)
93 }
94
95 func (c *Curve) pos(v *big.Int) {
96         if v.Cmp(zero) < 0 {
97                 v.Add(v, c.P)
98         }
99 }
100
101 func (c *Curve) add(p1x, p1y, p2x, p2y *big.Int) {
102         var t, tx, ty big.Int
103         if p1x.Cmp(p2x) == 0 && p1y.Cmp(p2y) == 0 {
104                 // double
105                 t.Mul(p1x, p1x)
106                 t.Mul(&t, bigInt3)
107                 t.Add(&t, c.A)
108                 tx.Mul(bigInt2, p1y)
109                 tx.ModInverse(&tx, c.P)
110                 t.Mul(&t, &tx)
111                 t.Mod(&t, c.P)
112         } else {
113                 tx.Sub(p2x, p1x)
114                 tx.Mod(&tx, c.P)
115                 c.pos(&tx)
116                 ty.Sub(p2y, p1y)
117                 ty.Mod(&ty, c.P)
118                 c.pos(&ty)
119                 t.ModInverse(&tx, c.P)
120                 t.Mul(&t, &ty)
121                 t.Mod(&t, c.P)
122         }
123         tx.Mul(&t, &t)
124         tx.Sub(&tx, p1x)
125         tx.Sub(&tx, p2x)
126         tx.Mod(&tx, c.P)
127         c.pos(&tx)
128         ty.Sub(p1x, &tx)
129         ty.Mul(&ty, &t)
130         ty.Sub(&ty, p1y)
131         ty.Mod(&ty, c.P)
132         c.pos(&ty)
133         p1x.Set(&tx)
134         p1y.Set(&ty)
135 }
136
137 func (c *Curve) Exp(degree, xS, yS *big.Int) (*big.Int, *big.Int, error) {
138         if degree.Cmp(zero) == 0 {
139                 return nil, nil, errors.New("gogost/gost3410: zero degree value")
140         }
141         dg := big.NewInt(0).Sub(degree, bigInt1)
142         tx := big.NewInt(0).Set(xS)
143         ty := big.NewInt(0).Set(yS)
144         cx := big.NewInt(0).Set(xS)
145         cy := big.NewInt(0).Set(yS)
146         for dg.Cmp(zero) != 0 {
147                 if dg.Bit(0) == 1 {
148                         c.add(tx, ty, cx, cy)
149                 }
150                 dg.Rsh(dg, 1)
151                 c.add(cx, cy, cx, cy)
152         }
153         return tx, ty, nil
154 }
155
156 func (our *Curve) Equal(their *Curve) bool {
157         return our.P.Cmp(their.P) == 0 &&
158                 our.Q.Cmp(their.Q) == 0 &&
159                 our.A.Cmp(their.A) == 0 &&
160                 our.B.Cmp(their.B) == 0 &&
161                 our.X.Cmp(their.X) == 0 &&
162                 our.Y.Cmp(their.Y) == 0 &&
163                 ((our.E == nil && their.E == nil) || our.E.Cmp(their.E) == 0) &&
164                 ((our.D == nil && their.D == nil) || our.D.Cmp(their.D) == 0) &&
165                 our.Co.Cmp(their.Co) == 0
166 }