]> Cypherpunks.ru repositories - gogost.git/blob - gost3410/public.go
Raise copyright years in advance
[gogost.git] / gost3410 / public.go
1 // GoGOST -- Pure Go GOST cryptographic functions library
2 // Copyright (C) 2015-2024 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         "crypto"
20         "fmt"
21         "math/big"
22 )
23
24 type PublicKey struct {
25         C    *Curve
26         X, Y *big.Int
27 }
28
29 // Unmarshal LE(X)||LE(Y) public key. "raw" must be 2*c.PointSize() length.
30 func NewPublicKeyLE(c *Curve, raw []byte) (*PublicKey, error) {
31         pointSize := c.PointSize()
32         key := make([]byte, 2*pointSize)
33         if len(raw) != len(key) {
34                 return nil, fmt.Errorf("gogost/gost3410: len(key) != %d", len(key))
35         }
36         for i := 0; i < len(key); i++ {
37                 key[i] = raw[len(raw)-i-1]
38         }
39         return &PublicKey{
40                 c,
41                 bytes2big(key[pointSize : 2*pointSize]),
42                 bytes2big(key[:pointSize]),
43         }, nil
44 }
45
46 // Unmarshal BE(X)||BE(Y) public key. "raw" must be 2*c.PointSize() length.
47 func NewPublicKeyBE(c *Curve, raw []byte) (*PublicKey, error) {
48         pointSize := c.PointSize()
49         if len(raw) != 2*pointSize {
50                 return nil, fmt.Errorf("gogost/gost3410: len(key) != %d", 2*pointSize)
51         }
52         return &PublicKey{
53                 c,
54                 bytes2big(raw[:pointSize]),
55                 bytes2big(raw[pointSize:]),
56         }, nil
57 }
58
59 // This is an alias for NewPublicKeyLE().
60 func NewPublicKey(c *Curve, raw []byte) (*PublicKey, error) {
61         return NewPublicKeyLE(c, raw)
62 }
63
64 // Marshal LE(X)||LE(Y) public key. raw will be 2*pub.C.PointSize() length.
65 func (pub *PublicKey) RawLE() []byte {
66         pointSize := pub.C.PointSize()
67         raw := append(
68                 pad(pub.Y.Bytes(), pointSize),
69                 pad(pub.X.Bytes(), pointSize)...,
70         )
71         reverse(raw)
72         return raw
73 }
74
75 // Marshal BE(X)||BE(Y) public key. raw will be 2*pub.C.PointSize() length.
76 func (pub *PublicKey) RawBE() []byte {
77         pointSize := pub.C.PointSize()
78         return append(
79                 pad(pub.X.Bytes(), pointSize),
80                 pad(pub.Y.Bytes(), pointSize)...,
81         )
82 }
83
84 // This is an alias for RawLE().
85 func (pub *PublicKey) Raw() []byte {
86         return pub.RawLE()
87 }
88
89 func (pub *PublicKey) VerifyDigest(digest, signature []byte) (bool, error) {
90         pointSize := pub.C.PointSize()
91         if len(signature) != 2*pointSize {
92                 return false, fmt.Errorf("gogost/gost3410: len(signature)=%d != %d", len(signature), 2*pointSize)
93         }
94         s := bytes2big(signature[:pointSize])
95         r := bytes2big(signature[pointSize:])
96         if r.Cmp(zero) <= 0 ||
97                 r.Cmp(pub.C.Q) >= 0 ||
98                 s.Cmp(zero) <= 0 ||
99                 s.Cmp(pub.C.Q) >= 0 {
100                 return false, nil
101         }
102         e := bytes2big(digest)
103         e.Mod(e, pub.C.Q)
104         if e.Cmp(zero) == 0 {
105                 e = big.NewInt(1)
106         }
107         v := big.NewInt(0)
108         v.ModInverse(e, pub.C.Q)
109         z1 := big.NewInt(0)
110         z2 := big.NewInt(0)
111         z1.Mul(s, v)
112         z1.Mod(z1, pub.C.Q)
113         z2.Mul(r, v)
114         z2.Mod(z2, pub.C.Q)
115         z2.Sub(pub.C.Q, z2)
116         p1x, p1y, err := pub.C.Exp(z1, pub.C.X, pub.C.Y)
117         if err != nil {
118                 return false, err
119         }
120         q1x, q1y, err := pub.C.Exp(z2, pub.X, pub.Y)
121         if err != nil {
122                 return false, err
123         }
124         lm := big.NewInt(0)
125         lm.Sub(q1x, p1x)
126         if lm.Cmp(zero) < 0 {
127                 lm.Add(lm, pub.C.P)
128         }
129         lm.ModInverse(lm, pub.C.P)
130         z1.Sub(q1y, p1y)
131         lm.Mul(lm, z1)
132         lm.Mod(lm, pub.C.P)
133         lm.Mul(lm, lm)
134         lm.Mod(lm, pub.C.P)
135         lm.Sub(lm, p1x)
136         lm.Sub(lm, q1x)
137         lm.Mod(lm, pub.C.P)
138         if lm.Cmp(zero) < 0 {
139                 lm.Add(lm, pub.C.P)
140         }
141         lm.Mod(lm, pub.C.Q)
142         return lm.Cmp(r) == 0, nil
143 }
144
145 func (our *PublicKey) Equal(theirKey crypto.PublicKey) bool {
146         their, ok := theirKey.(*PublicKey)
147         if !ok {
148                 return false
149         }
150         return our.X.Cmp(their.X) == 0 && our.Y.Cmp(their.Y) == 0 && our.C.Equal(their.C)
151 }
152
153 type PublicKeyReverseDigest struct {
154         Pub *PublicKey
155 }
156
157 func (pub PublicKeyReverseDigest) VerifyDigest(
158         digest, signature []byte,
159 ) (bool, error) {
160         dgst := make([]byte, len(digest))
161         for i := 0; i < len(digest); i++ {
162                 dgst[i] = digest[len(digest)-i-1]
163         }
164         return pub.Pub.VerifyDigest(dgst, signature)
165 }
166
167 func (pub PublicKeyReverseDigest) Equal(theirKey crypto.PublicKey) bool {
168         return pub.Pub.Equal(theirKey)
169 }
170
171 type PublicKeyReverseDigestAndSignature struct {
172         Pub *PublicKey
173 }
174
175 func (pub PublicKeyReverseDigestAndSignature) VerifyDigest(
176         digest, signature []byte,
177 ) (bool, error) {
178         dgst := make([]byte, len(digest))
179         for i := 0; i < len(digest); i++ {
180                 dgst[i] = digest[len(digest)-i-1]
181         }
182         sign := make([]byte, len(signature))
183         for i := 0; i < len(signature); i++ {
184                 sign[i] = signature[len(signature)-i-1]
185         }
186         return pub.Pub.VerifyDigest(dgst, sign)
187 }
188
189 func (pub PublicKeyReverseDigestAndSignature) Equal(theirKey crypto.PublicKey) bool {
190         return pub.Pub.Equal(theirKey)
191 }