arnaucube
arnaucube/cryptofunPublic Self-hosted repository
cryptofun/schnorr/schnorr.go
schnorr/schnorr.goRaw
  1package schnorr
  2
  3import (
  4	"crypto/rand"
  5	"crypto/sha256"
  6	"math/big"
  7
  8	"github.com/arnaucube/cryptofun/ecc"
  9)
 10
 11const (
 12	bits = 512 // 2048
 13)
 14
 15// PubK is the public key of the Schnorr scheme
 16type PubK struct {
 17	P ecc.Point
 18	Q ecc.Point
 19}
 20
 21// PrivK is the private key of the Schnorr scheme
 22type PrivK struct {
 23	PubK PubK
 24	A    *big.Int
 25}
 26
 27// Schnorr is the data structure for the Schnorr scheme
 28type Schnorr struct {
 29	EC ecc.EC
 30	D  *big.Int // K
 31	G  ecc.Point
 32	Q  ecc.Point // P
 33	N  int       // order of curve
 34}
 35
 36// Hash calculates a hash concatenating a given message bytes with a given EC Point. H(M||R)
 37func Hash(m []byte, c ecc.Point) *big.Int {
 38	var b []byte
 39	b = append(b, m...)
 40	cXBytes := c.X.Bytes()
 41	cYBytes := c.Y.Bytes()
 42	b = append(b, cXBytes...)
 43	b = append(b, cYBytes...)
 44	h := sha256.New()
 45	h.Write(b)
 46	hash := h.Sum(nil)
 47	r := new(big.Int).SetBytes(hash)
 48	return r
 49}
 50
 51// Gen generates the Schnorr scheme
 52func Gen(ec ecc.EC, g ecc.Point, r *big.Int) (Schnorr, PrivK, error) {
 53	var err error
 54	var schnorr Schnorr
 55	var sk PrivK
 56	schnorr.EC = ec
 57	schnorr.G = g
 58
 59	sk.PubK.P, _, err = ec.At(r)
 60	if err != nil {
 61		return schnorr, sk, err
 62	}
 63
 64	orderP, err := ec.Order(sk.PubK.P)
 65	if err != nil {
 66		return schnorr, sk, err
 67	}
 68
 69	// rand int between 1 and oerder of P
 70	sk.A, err = rand.Int(rand.Reader, orderP)
 71	if err != nil {
 72		return schnorr, sk, err
 73	}
 74	sk.A = big.NewInt(int64(7))
 75	skACopy := new(big.Int).SetBytes(sk.A.Bytes())
 76	// pk.Q = k x P
 77	sk.PubK.Q, err = ec.Mul(sk.PubK.P, skACopy)
 78	if err != nil {
 79		return schnorr, sk, err
 80	}
 81	return schnorr, sk, nil
 82}
 83
 84// Sign performs the signature of the message m with the given private key
 85func (schnorr Schnorr) Sign(sk PrivK, m []byte) (*big.Int, ecc.Point, error) {
 86	var e *big.Int
 87	orderP, err := schnorr.EC.Order(sk.PubK.P)
 88	if err != nil {
 89		return e, ecc.Point{}, err
 90	}
 91	// rand k <-[1,r]
 92	k, err := rand.Int(rand.Reader, orderP)
 93	if err != nil {
 94		return e, ecc.Point{}, err
 95	}
 96
 97	// R = k x P
 98	rPoint, err := schnorr.EC.Mul(sk.PubK.P, k)
 99	if err != nil {
100		return e, ecc.Point{}, err
101	}
102	// e = H(M||R)
103	e = Hash(m, rPoint)
104	// a*e
105	ae := new(big.Int).Mul(sk.A, e)
106	// k + a*e
107	kae := new(big.Int).Add(k, ae)
108	// k + a*e mod r, where r is order of P
109	s := new(big.Int).Mod(kae, orderP)
110	return s, rPoint, nil
111}
112
113// Verify checks if the given public key matches with the given signature of the message m, in the given EC
114func Verify(ec ecc.EC, pk PubK, m []byte, s *big.Int, rPoint ecc.Point) (bool, error) {
115	// e = H(M||R)
116	e := Hash(m, rPoint)
117	eCopy := new(big.Int).SetBytes(e.Bytes())
118
119	// e x Q
120	eQ, err := ec.Mul(pk.Q, eCopy)
121	if err != nil {
122		return false, err
123	}
124
125	// R + e x Q
126	// reQ, err := schnorr.EC.Add(rPoint, eQ)
127	// if err != nil {
128	// 	return false, err
129	// }
130
131	// s x P
132	sp, err := ec.Mul(pk.P, s)
133	if err != nil {
134		return false, err
135	}
136
137	// return reQ.Equal(sp), nil
138	return eQ.Equal(sp), nil
139}