go-iden3-crypto/babyjub/eddsa.go
babyjub/eddsa.goRaw
1// Package babyjub eddsa implements the EdDSA over the BabyJubJub curve
2//nolint:gomnd
3package babyjub
4
5import (
6 "crypto/rand"
7 "database/sql/driver"
8 "fmt"
9 "math/big"
10
11 "github.com/iden3/go-iden3-crypto/mimc7"
12 "github.com/iden3/go-iden3-crypto/poseidon"
13 "github.com/iden3/go-iden3-crypto/utils"
14)
15
16// pruneBuffer prunes the buffer during key generation according to RFC 8032.
17// https://tools.ietf.org/html/rfc8032#page-13
18func pruneBuffer(buf *[32]byte) *[32]byte {
19 buf[0] = buf[0] & 0xF8
20 buf[31] = buf[31] & 0x7F
21 buf[31] = buf[31] | 0x40
22 return buf
23}
24
25// PrivateKey is an EdDSA private key, which is a 32byte buffer.
26type PrivateKey [32]byte
27
28// NewRandPrivKey generates a new random private key (using cryptographically
29// secure randomness).
30func NewRandPrivKey() PrivateKey {
31 var k PrivateKey
32 _, err := rand.Read(k[:])
33 if err != nil {
34 panic(err)
35 }
36 return k
37}
38
39// Scalar converts a private key into the scalar value s following the EdDSA
40// standard, and using blake-512 hash.
41func (k *PrivateKey) Scalar() *PrivKeyScalar {
42 s := SkToBigInt(k)
43 return NewPrivKeyScalar(s)
44}
45
46// SkToBigInt converts a private key into the *big.Int value following the
47// EdDSA standard, and using blake-512 hash
48func SkToBigInt(k *PrivateKey) *big.Int {
49 sBuf := Blake512(k[:])
50 sBuf32 := [32]byte{}
51 copy(sBuf32[:], sBuf[:32])
52 pruneBuffer(&sBuf32)
53 s := new(big.Int)
54 utils.SetBigIntFromLEBytes(s, sBuf32[:])
55 s.Rsh(s, 3)
56 return s
57}
58
59// Public returns the public key corresponding to a private key.
60func (k *PrivateKey) Public() *PublicKey {
61 return k.Scalar().Public()
62}
63
64// PrivKeyScalar represents the scalar s output of a private key
65type PrivKeyScalar big.Int
66
67// NewPrivKeyScalar creates a new PrivKeyScalar from a big.Int
68func NewPrivKeyScalar(s *big.Int) *PrivKeyScalar {
69 sk := PrivKeyScalar(*s)
70 return &sk
71}
72
73// Public returns the public key corresponding to the scalar value s of a
74// private key.
75func (s *PrivKeyScalar) Public() *PublicKey {
76 p := NewPoint().Mul((*big.Int)(s), B8)
77 pk := PublicKey(*p)
78 return &pk
79}
80
81// BigInt returns the big.Int corresponding to a PrivKeyScalar.
82func (s *PrivKeyScalar) BigInt() *big.Int {
83 return (*big.Int)(s)
84}
85
86// PublicKey represents an EdDSA public key, which is a curve point.
87type PublicKey Point
88
89// MarshalText implements the marshaler for PublicKey
90func (pk PublicKey) MarshalText() ([]byte, error) {
91 pkc := pk.Compress()
92 return utils.Hex(pkc[:]).MarshalText()
93}
94
95// String returns the string representation of the PublicKey
96func (pk PublicKey) String() string {
97 pkc := pk.Compress()
98 return utils.Hex(pkc[:]).String()
99}
100
101// UnmarshalText implements the unmarshaler for the PublicKey
102func (pk *PublicKey) UnmarshalText(h []byte) error {
103 var pkc PublicKeyComp
104 if err := utils.HexDecodeInto(pkc[:], h); err != nil {
105 return err
106 }
107 pkd, err := pkc.Decompress()
108 if err != nil {
109 return err
110 }
111 *pk = *pkd
112 return nil
113}
114
115// Point returns the Point corresponding to a PublicKey.
116func (pk *PublicKey) Point() *Point {
117 return (*Point)(pk)
118}
119
120// PublicKeyComp represents a compressed EdDSA Public key; it's a compressed curve
121// point.
122type PublicKeyComp [32]byte
123
124// MarshalText implements the marshaler for the PublicKeyComp
125func (pkComp PublicKeyComp) MarshalText() ([]byte, error) {
126 return utils.Hex(pkComp[:]).MarshalText()
127}
128
129// String returns the string representation of the PublicKeyComp
130func (pkComp PublicKeyComp) String() string { return utils.Hex(pkComp[:]).String() }
131
132// UnmarshalText implements the unmarshaler for the PublicKeyComp
133func (pkComp *PublicKeyComp) UnmarshalText(h []byte) error {
134 return utils.HexDecodeInto(pkComp[:], h)
135}
136
137// Compress returns the PublicKeyCompr for the given PublicKey
138func (pk *PublicKey) Compress() PublicKeyComp {
139 return PublicKeyComp((*Point)(pk).Compress())
140}
141
142// Decompress returns the PublicKey for the given PublicKeyComp
143func (pkComp *PublicKeyComp) Decompress() (*PublicKey, error) {
144 point, err := NewPoint().Decompress(*pkComp)
145 if err != nil {
146 return nil, err
147 }
148 pk := PublicKey(*point)
149 return &pk, nil
150}
151
152// Signature represents an EdDSA uncompressed signature.
153type Signature struct {
154 R8 *Point
155 S *big.Int
156}
157
158// SignatureComp represents a compressed EdDSA signature.
159type SignatureComp [64]byte
160
161// MarshalText implements the marshaler for the SignatureComp
162func (sComp SignatureComp) MarshalText() ([]byte, error) {
163 return utils.Hex(sComp[:]).MarshalText()
164}
165
166// String returns the string representation of the SignatureComp
167func (sComp SignatureComp) String() string { return utils.Hex(sComp[:]).String() }
168
169// UnmarshalText implements the unmarshaler for the SignatureComp
170func (sComp *SignatureComp) UnmarshalText(h []byte) error {
171 return utils.HexDecodeInto(sComp[:], h)
172}
173
174// Compress an EdDSA signature by concatenating the compression of
175// the point R8 and the Little-Endian encoding of S.
176func (s *Signature) Compress() SignatureComp {
177 R8p := s.R8.Compress()
178 Sp := utils.BigIntLEBytes(s.S)
179 buf := [64]byte{}
180 copy(buf[:32], R8p[:])
181 copy(buf[32:], Sp[:])
182 return SignatureComp(buf)
183}
184
185// Decompress a compressed signature into s, and also returns the decompressed
186// signature. Returns error if the Point decompression fails.
187func (s *Signature) Decompress(buf [64]byte) (*Signature, error) {
188 R8p := [32]byte{}
189 copy(R8p[:], buf[:32])
190 var err error
191 if s.R8, err = NewPoint().Decompress(R8p); err != nil {
192 return nil, err
193 }
194 s.S = utils.SetBigIntFromLEBytes(new(big.Int), buf[32:])
195 return s, nil
196}
197
198// Decompress a compressed signature. Returns error if the Point decompression
199// fails.
200func (sComp *SignatureComp) Decompress() (*Signature, error) {
201 return new(Signature).Decompress(*sComp)
202}
203
204// Scan implements Scanner for database/sql.
205func (sComp *SignatureComp) Scan(src interface{}) error {
206 srcB, ok := src.([]byte)
207 if !ok {
208 return fmt.Errorf("can't scan %T into Signature", src)
209 }
210 if len(srcB) != 64 {
211 return fmt.Errorf("can't scan []byte of len %d into Signature, want %d", len(srcB), 64)
212 }
213 copy(sComp[:], srcB[:])
214 return nil
215}
216
217// Value implements valuer for database/sql.
218func (sComp SignatureComp) Value() (driver.Value, error) {
219 return sComp[:], nil
220}
221
222// Scan implements Scanner for database/sql.
223func (s *Signature) Scan(src interface{}) error {
224 srcB, ok := src.([]byte)
225 if !ok {
226 return fmt.Errorf("can't scan %T into Signature", src)
227 }
228 if len(srcB) != 64 {
229 return fmt.Errorf("can't scan []byte of len %d into Signature, want %d", len(srcB), 64)
230 }
231 buf := [64]byte{}
232 copy(buf[:], srcB[:])
233 _, err := s.Decompress(buf)
234 return err
235}
236
237// Value implements valuer for database/sql.
238func (s Signature) Value() (driver.Value, error) {
239 comp := s.Compress()
240 return comp[:], nil
241}
242
243// SignMimc7 signs a message encoded as a big.Int in Zq using blake-512 hash
244// for buffer hashing and mimc7 for big.Int hashing.
245func (k *PrivateKey) SignMimc7(msg *big.Int) *Signature {
246 h1 := Blake512(k[:])
247 msgBuf := utils.BigIntLEBytes(msg)
248 msgBuf32 := [32]byte{}
249 copy(msgBuf32[:], msgBuf[:])
250 rBuf := Blake512(append(h1[32:], msgBuf32[:]...))
251 r := utils.SetBigIntFromLEBytes(new(big.Int), rBuf) // r = H(H_{32..63}(k), msg)
252 r.Mod(r, SubOrder)
253 R8 := NewPoint().Mul(r, B8) // R8 = r * 8 * B
254 A := k.Public().Point()
255 hmInput := []*big.Int{R8.X, R8.Y, A.X, A.Y, msg}
256 hm, err := mimc7.Hash(hmInput, nil) // hm = H1(8*R.x, 8*R.y, A.x, A.y, msg)
257 if err != nil {
258 panic(err)
259 }
260 S := new(big.Int).Lsh(k.Scalar().BigInt(), 3)
261 S = S.Mul(hm, S)
262 S.Add(r, S)
263 S.Mod(S, SubOrder) // S = r + hm * 8 * s
264
265 return &Signature{R8: R8, S: S}
266}
267
268// VerifyMimc7 verifies the signature of a message encoded as a big.Int in Zq
269// using blake-512 hash for buffer hashing and mimc7 for big.Int hashing.
270func (pk *PublicKey) VerifyMimc7(msg *big.Int, sig *Signature) bool {
271 hmInput := []*big.Int{sig.R8.X, sig.R8.Y, pk.X, pk.Y, msg}
272 hm, err := mimc7.Hash(hmInput, nil) // hm = H1(8*R.x, 8*R.y, A.x, A.y, msg)
273 if err != nil {
274 return false
275 }
276
277 left := NewPoint().Mul(sig.S, B8) // left = s * 8 * B
278 r1 := big.NewInt(8)
279 r1.Mul(r1, hm)
280 right := NewPoint().Mul(r1, pk.Point())
281 rightProj := right.Projective()
282 rightProj.Add(sig.R8.Projective(), rightProj) // right = 8 * R + 8 * hm * A
283 right = rightProj.Affine()
284 return (left.X.Cmp(right.X) == 0) && (left.Y.Cmp(right.Y) == 0)
285}
286
287// SignPoseidon signs a message encoded as a big.Int in Zq using blake-512 hash
288// for buffer hashing and Poseidon for big.Int hashing.
289func (k *PrivateKey) SignPoseidon(msg *big.Int) *Signature {
290 h1 := Blake512(k[:])
291 msgBuf := utils.BigIntLEBytes(msg)
292 msgBuf32 := [32]byte{}
293 copy(msgBuf32[:], msgBuf[:])
294 rBuf := Blake512(append(h1[32:], msgBuf32[:]...))
295 r := utils.SetBigIntFromLEBytes(new(big.Int), rBuf) // r = H(H_{32..63}(k), msg)
296 r.Mod(r, SubOrder)
297 R8 := NewPoint().Mul(r, B8) // R8 = r * 8 * B
298 A := k.Public().Point()
299
300 hmInput := []*big.Int{R8.X, R8.Y, A.X, A.Y, msg}
301 hm, err := poseidon.Hash(hmInput) // hm = H1(8*R.x, 8*R.y, A.x, A.y, msg)
302 if err != nil {
303 panic(err)
304 }
305
306 S := new(big.Int).Lsh(k.Scalar().BigInt(), 3)
307 S = S.Mul(hm, S)
308 S.Add(r, S)
309 S.Mod(S, SubOrder) // S = r + hm * 8 * s
310
311 return &Signature{R8: R8, S: S}
312}
313
314// VerifyPoseidon verifies the signature of a message encoded as a big.Int in Zq
315// using blake-512 hash for buffer hashing and Poseidon for big.Int hashing.
316func (pk *PublicKey) VerifyPoseidon(msg *big.Int, sig *Signature) bool {
317 hmInput := []*big.Int{sig.R8.X, sig.R8.Y, pk.X, pk.Y, msg}
318 hm, err := poseidon.Hash(hmInput) // hm = H1(8*R.x, 8*R.y, A.x, A.y, msg)
319 if err != nil {
320 return false
321 }
322
323 left := NewPoint().Mul(sig.S, B8) // left = s * 8 * B
324 r1 := big.NewInt(8)
325 r1.Mul(r1, hm)
326 right := NewPoint().Mul(r1, pk.Point())
327 rightProj := right.Projective()
328 rightProj.Add(sig.R8.Projective(), rightProj) // right = 8 * R + 8 * hm * A
329 right = rightProj.Affine()
330 return (left.X.Cmp(right.X) == 0) && (left.Y.Cmp(right.Y) == 0)
331}
332
333// Scan implements Scanner for database/sql.
334func (pk *PublicKey) Scan(src interface{}) error {
335 srcB, ok := src.([]byte)
336 if !ok {
337 return fmt.Errorf("can't scan %T into PublicKey", src)
338 }
339 if len(srcB) != 32 {
340 return fmt.Errorf("can't scan []byte of len %d into PublicKey, want %d", len(srcB), 32)
341 }
342 var comp PublicKeyComp
343 copy(comp[:], srcB)
344 decomp, err := comp.Decompress()
345 if err != nil {
346 return err
347 }
348 *pk = *decomp
349 return nil
350}
351
352// Value implements valuer for database/sql.
353func (pk PublicKey) Value() (driver.Value, error) {
354 comp := pk.Compress()
355 return comp[:], nil
356}
357
358// Scan implements Scanner for database/sql.
359func (pkComp *PublicKeyComp) Scan(src interface{}) error {
360 srcB, ok := src.([]byte)
361 if !ok {
362 return fmt.Errorf("can't scan %T into PublicKeyComp", src)
363 }
364 if len(srcB) != 32 {
365 return fmt.Errorf("can't scan []byte of len %d into PublicKeyComp, want %d", len(srcB), 32)
366 }
367 copy(pkComp[:], srcB)
368 return nil
369}
370
371// Value implements valuer for database/sql.
372func (pkComp PublicKeyComp) Value() (driver.Value, error) {
373 return pkComp[:], nil
374}