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