arnaucube
arnaucube/go-iden3-cryptoPublic Self-hosted repository
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 *SignatureComp) 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	copy(s[:], srcB[:])
190	return nil
191}
192
193// Value implements valuer for database/sql.
194func (s SignatureComp) Value() (driver.Value, error) {
195	return s[:], nil
196}
197
198// Scan implements Scanner for database/sql.
199func (s *Signature) Scan(src interface{}) error {
200	srcB, ok := src.([]byte)
201	if !ok {
202		return fmt.Errorf("can't scan %T into Signature", src)
203	}
204	if len(srcB) != 64 {
205		return fmt.Errorf("can't scan []byte of len %d into Signature, want %d", len(srcB), 64)
206	}
207	buf := [64]byte{}
208	copy(buf[:], srcB[:])
209	_, err := s.Decompress(buf)
210	return err
211}
212
213// Value implements valuer for database/sql.
214func (s Signature) Value() (driver.Value, error) {
215	comp := s.Compress()
216	return comp[:], nil
217}
218
219// SignMimc7 signs a message encoded as a big.Int in Zq using blake-512 hash
220// for buffer hashing and mimc7 for big.Int hashing.
221func (k *PrivateKey) SignMimc7(msg *big.Int) *Signature {
222	h1 := Blake512(k[:])
223	msgBuf := utils.BigIntLEBytes(msg)
224	msgBuf32 := [32]byte{}
225	copy(msgBuf32[:], msgBuf[:])
226	rBuf := Blake512(append(h1[32:], msgBuf32[:]...))
227	r := utils.SetBigIntFromLEBytes(new(big.Int), rBuf) // r = H(H_{32..63}(k), msg)
228	r.Mod(r, SubOrder)
229	R8 := NewPoint().Mul(r, B8) // R8 = r * 8 * B
230	A := k.Public().Point()
231	hmInput := []*big.Int{R8.X, R8.Y, A.X, A.Y, msg}
232	hm, err := mimc7.Hash(hmInput, nil) // hm = H1(8*R.x, 8*R.y, A.x, A.y, msg)
233	if err != nil {
234		panic(err)
235	}
236	S := new(big.Int).Lsh(k.Scalar().BigInt(), 3)
237	S = S.Mul(hm, S)
238	S.Add(r, S)
239	S.Mod(S, SubOrder) // S = r + hm * 8 * s
240
241	return &Signature{R8: R8, S: S}
242}
243
244// VerifyMimc7 verifies the signature of a message encoded as a big.Int in Zq
245// using blake-512 hash for buffer hashing and mimc7 for big.Int hashing.
246func (p *PublicKey) VerifyMimc7(msg *big.Int, sig *Signature) bool {
247	hmInput := []*big.Int{sig.R8.X, sig.R8.Y, p.X, p.Y, msg}
248	hm, err := mimc7.Hash(hmInput, nil) // hm = H1(8*R.x, 8*R.y, A.x, A.y, msg)
249	if err != nil {
250		panic(err)
251	}
252
253	left := NewPoint().Mul(sig.S, B8) // left = s * 8 * B
254	r1 := big.NewInt(8)
255	r1.Mul(r1, hm)
256	right := NewPoint().Mul(r1, p.Point())
257	rightProj := right.Projective()
258	rightProj.Add(sig.R8.Projective(), rightProj) // right = 8 * R + 8 * hm * A
259	right = rightProj.Affine()
260	return (left.X.Cmp(right.X) == 0) && (left.Y.Cmp(right.Y) == 0)
261}
262
263// SignPoseidon signs a message encoded as a big.Int in Zq using blake-512 hash
264// for buffer hashing and Poseidon for big.Int hashing.
265func (k *PrivateKey) SignPoseidon(msg *big.Int) *Signature {
266	h1 := Blake512(k[:])
267	msgBuf := utils.BigIntLEBytes(msg)
268	msgBuf32 := [32]byte{}
269	copy(msgBuf32[:], msgBuf[:])
270	rBuf := Blake512(append(h1[32:], msgBuf32[:]...))
271	r := utils.SetBigIntFromLEBytes(new(big.Int), rBuf) // r = H(H_{32..63}(k), msg)
272	r.Mod(r, SubOrder)
273	R8 := NewPoint().Mul(r, B8) // R8 = r * 8 * B
274	A := k.Public().Point()
275
276	hmInput := []*big.Int{R8.X, R8.Y, A.X, A.Y, msg, big.NewInt(int64(0))}
277	hm, err := poseidon.Hash(hmInput) // hm = H1(8*R.x, 8*R.y, A.x, A.y, msg)
278	if err != nil {
279		panic(err)
280	}
281
282	S := new(big.Int).Lsh(k.Scalar().BigInt(), 3)
283	S = S.Mul(hm, S)
284	S.Add(r, S)
285	S.Mod(S, SubOrder) // S = r + hm * 8 * s
286
287	return &Signature{R8: R8, S: S}
288}
289
290// VerifyPoseidon verifies the signature of a message encoded as a big.Int in Zq
291// using blake-512 hash for buffer hashing and Poseidon for big.Int hashing.
292func (p *PublicKey) VerifyPoseidon(msg *big.Int, sig *Signature) bool {
293	hmInput := []*big.Int{sig.R8.X, sig.R8.Y, p.X, p.Y, msg, big.NewInt(int64(0))}
294	hm, err := poseidon.Hash(hmInput) // hm = H1(8*R.x, 8*R.y, A.x, A.y, msg)
295	if err != nil {
296		panic(err)
297	}
298
299	left := NewPoint().Mul(sig.S, B8) // left = s * 8 * B
300	r1 := big.NewInt(8)
301	r1.Mul(r1, hm)
302	right := NewPoint().Mul(r1, p.Point())
303	rightProj := right.Projective()
304	rightProj.Add(sig.R8.Projective(), rightProj) // right = 8 * R + 8 * hm * A
305	right = rightProj.Affine()
306	return (left.X.Cmp(right.X) == 0) && (left.Y.Cmp(right.Y) == 0)
307}
308
309// Scan implements Scanner for database/sql.
310func (p *PublicKey) Scan(src interface{}) error {
311	srcB, ok := src.([]byte)
312	if !ok {
313		return fmt.Errorf("can't scan %T into PublicKey", src)
314	}
315	if len(srcB) != 32 {
316		return fmt.Errorf("can't scan []byte of len %d into PublicKey, want %d", len(srcB), 32)
317	}
318	var comp PublicKeyComp
319	copy(comp[:], srcB)
320	decomp, err := comp.Decompress()
321	if err != nil {
322		return err
323	}
324	*p = *decomp
325	return nil
326}
327
328// Value implements valuer for database/sql.
329func (p PublicKey) Value() (driver.Value, error) {
330	comp := p.Compress()
331	return comp[:], nil
332}