go-iden3-crypto/babyjub/eddsa.go
babyjub/eddsa.goRaw
1package babyjub
2
3import (
4 "crypto/rand"
5
6 "github.com/iden3/go-iden3-crypto/mimc7"
7 "github.com/iden3/go-iden3-crypto/utils"
8
9 "math/big"
10)
11
12// pruneBuffer prunes the buffer during key generation according to RFC 8032.
13// https://tools.ietf.org/html/rfc8032#page-13
14func pruneBuffer(buf *[32]byte) *[32]byte {
15 buf[0] = buf[0] & 0xF8
16 buf[31] = buf[31] & 0x7F
17 buf[31] = buf[31] | 0x40
18 return buf
19}
20
21// PrivateKey is an EdDSA private key, which is a 32byte buffer.
22type PrivateKey [32]byte
23
24// NewRandPrivKey generates a new random private key (using cryptographically
25// secure randomness).
26func NewRandPrivKey() PrivateKey {
27 var k PrivateKey
28 _, err := rand.Read(k[:])
29 if err != nil {
30 panic(err)
31 }
32 return k
33}
34
35// Scalar converts a private key into the scalar value s following the EdDSA
36// standard, and using blake-512 hash.
37func (k *PrivateKey) Scalar() *PrivKeyScalar {
38 sBuf := Blake512(k[:])
39 sBuf32 := [32]byte{}
40 copy(sBuf32[:], sBuf[:32])
41 pruneBuffer(&sBuf32)
42 s := new(big.Int)
43 utils.SetBigIntFromLEBytes(s, sBuf32[:])
44 s.Rsh(s, 3)
45 return NewPrivKeyScalar(s)
46}
47
48// Pub returns the public key corresponding to a private key.
49func (k *PrivateKey) Public() *PublicKey {
50 return k.Scalar().Public()
51}
52
53// PrivKeyScalar represents the scalar s output of a private key
54type PrivKeyScalar big.Int
55
56// NewPrivKeyScalar creates a new PrivKeyScalar from a big.Int
57func NewPrivKeyScalar(s *big.Int) *PrivKeyScalar {
58 sk := PrivKeyScalar(*s)
59 return &sk
60}
61
62// Pub returns the public key corresponding to the scalar value s of a private
63// key.
64func (s *PrivKeyScalar) Public() *PublicKey {
65 p := NewPoint().Mul((*big.Int)(s), B8)
66 pk := PublicKey(*p)
67 return &pk
68}
69
70// BigInt returns the big.Int corresponding to a PrivKeyScalar.
71func (s *PrivKeyScalar) BigInt() *big.Int {
72 return (*big.Int)(s)
73}
74
75// PublicKey represents an EdDSA public key, which is a curve point.
76type PublicKey Point
77
78func (pk PublicKey) MarshalText() ([]byte, error) {
79 pkc := pk.Compress()
80 return utils.Hex(pkc[:]).MarshalText()
81}
82
83func (pk PublicKey) String() string {
84 pkc := pk.Compress()
85 return utils.Hex(pkc[:]).String()
86}
87
88func (pk *PublicKey) UnmarshalText(h []byte) error {
89 var pkc PublicKeyComp
90 if err := utils.HexDecodeInto(pkc[:], h); err != nil {
91 return err
92 }
93 pkd, err := pkc.Decompress()
94 if err != nil {
95 return err
96 }
97 *pk = *pkd
98 return nil
99}
100
101// Point returns the Point corresponding to a PublicKey.
102func (p *PublicKey) Point() *Point {
103 return (*Point)(p)
104}
105
106// PublicKeyComp represents a compressed EdDSA Public key; it's a compressed curve
107// point.
108type PublicKeyComp [32]byte
109
110func (buf PublicKeyComp) MarshalText() ([]byte, error) { return utils.Hex(buf[:]).MarshalText() }
111func (buf PublicKeyComp) String() string { return utils.Hex(buf[:]).String() }
112func (buf *PublicKeyComp) UnmarshalText(h []byte) error { return utils.HexDecodeInto(buf[:], h) }
113
114func (p *PublicKey) Compress() PublicKeyComp {
115 return PublicKeyComp((*Point)(p).Compress())
116}
117
118func (p *PublicKeyComp) Decompress() (*PublicKey, error) {
119 point, err := NewPoint().Decompress(*p)
120 if err != nil {
121 return nil, err
122 }
123 pk := PublicKey(*point)
124 return &pk, nil
125}
126
127// Signature represents an EdDSA uncompressed signature.
128type Signature struct {
129 R8 *Point
130 S *big.Int
131}
132
133// SignatureComp represents a compressed EdDSA signature.
134type SignatureComp [64]byte
135
136func (buf SignatureComp) MarshalText() ([]byte, error) { return utils.Hex(buf[:]).MarshalText() }
137func (buf SignatureComp) String() string { return utils.Hex(buf[:]).String() }
138func (buf *SignatureComp) UnmarshalText(h []byte) error { return utils.HexDecodeInto(buf[:], h) }
139
140// Compress an EdDSA signature by concatenating the compression of
141// the point R8 and the Little-Endian encoding of S.
142func (s *Signature) Compress() SignatureComp {
143 R8p := s.R8.Compress()
144 Sp := utils.BigIntLEBytes(s.S)
145 buf := [64]byte{}
146 copy(buf[:32], R8p[:])
147 copy(buf[32:], Sp[:])
148 return SignatureComp(buf)
149}
150
151// Decompress a compressed signature into s, and also returns the decompressed
152// signature. Returns error if the Point decompression fails.
153func (s *Signature) Decompress(buf [64]byte) (*Signature, error) {
154 R8p := [32]byte{}
155 copy(R8p[:], buf[:32])
156 var err error
157 if s.R8, err = NewPoint().Decompress(R8p); err != nil {
158 return nil, err
159 }
160 s.S = utils.SetBigIntFromLEBytes(new(big.Int), buf[32:])
161 return s, nil
162}
163
164// Decompress a compressed signature. Returns error if the Point decompression
165// fails.
166func (s *SignatureComp) Decompress() (*Signature, error) {
167 return new(Signature).Decompress(*s)
168}
169
170// SignMimc7 signs a message encoded as a big.Int in Zq using blake-512 hash
171// for buffer hashing and mimc7 for big.Int hashing.
172func (k *PrivateKey) SignMimc7(msg *big.Int) *Signature {
173 h1 := Blake512(k[:])
174 msgBuf := utils.BigIntLEBytes(msg)
175 msgBuf32 := [32]byte{}
176 copy(msgBuf32[:], msgBuf[:])
177 rBuf := Blake512(append(h1[32:], msgBuf32[:]...))
178 r := utils.SetBigIntFromLEBytes(new(big.Int), rBuf) // r = H(H_{32..63}(k), msg)
179 r.Mod(r, SubOrder)
180 R8 := NewPoint().Mul(r, B8) // R8 = r * 8 * B
181 A := k.Public().Point()
182 hmInput, err := mimc7.BigIntsToRElems([]*big.Int{R8.X, R8.Y, A.X, A.Y, msg})
183 if err != nil {
184 panic(err)
185 }
186 hm := mimc7.Hash(hmInput, nil) // hm = H1(8*R.x, 8*R.y, A.x, A.y, msg)
187 S := new(big.Int).Lsh(k.Scalar().BigInt(), 3)
188 S = S.Mul(hm, S)
189 S.Add(r, S)
190 S.Mod(S, SubOrder) // S = r + hm * 8 * s
191
192 return &Signature{R8: R8, S: S}
193}
194
195// VerifyMimc7 verifies the signature of a message encoded as a big.Int in Zq
196// using blake-512 hash for buffer hashing and mimc7 for big.Int hashing.
197func (p *PublicKey) VerifyMimc7(msg *big.Int, sig *Signature) bool {
198 hmInput, err := mimc7.BigIntsToRElems([]*big.Int{sig.R8.X, sig.R8.Y, p.X, p.Y, msg})
199 if err != nil {
200 panic(err)
201 }
202 hm := mimc7.Hash(hmInput, nil) // hm = H1(8*R.x, 8*R.y, A.x, A.y, msg)
203
204 left := NewPoint().Mul(sig.S, B8) // left = s * 8 * B
205 r1 := big.NewInt(8)
206 r1.Mul(r1, hm)
207 right := NewPoint().Mul(r1, p.Point())
208 right.Add(sig.R8, right) // right = 8 * R + 8 * hm * A
209 return (left.X.Cmp(right.X) == 0) && (left.Y.Cmp(right.Y) == 0)
210}