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