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