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/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}