arnaucube
arnaucube/go-iden3-cryptoPublic Self-hosted repository
go-iden3-crypto/babyjub/babyjub.go
babyjub/babyjub.goRaw
  1package babyjub
  2
  3import (
  4	"fmt"
  5	"math/big"
  6
  7	"github.com/iden3/go-iden3-crypto/constants"
  8	"github.com/iden3/go-iden3-crypto/utils"
  9)
 10
 11// A is one of the babyjub constants.
 12var A *big.Int
 13
 14// D is one of the babyjub constants.
 15var D *big.Int
 16
 17// Order of the babyjub curve.
 18var Order *big.Int
 19
 20// SubOrder is the order of the subgroup of the babyjub curve that contains the
 21// points that we use.
 22var SubOrder *big.Int
 23
 24// B8 is a base point of the babyjub multiplied by 8 to make it a base point of
 25// the subgroup in the curve.
 26var B8 *Point
 27
 28// init initializes global numbers and the subgroup base.
 29func init() {
 30	A = utils.NewIntFromString("168700")
 31	D = utils.NewIntFromString("168696")
 32
 33	Order = utils.NewIntFromString(
 34		"21888242871839275222246405745257275088614511777268538073601725287587578984328")
 35	SubOrder = new(big.Int).Rsh(Order, 3)
 36
 37	B8 = NewPoint()
 38	B8.X = utils.NewIntFromString(
 39		"5299619240641551281634865583518297030282874472190772894086521144482721001553")
 40	B8.Y = utils.NewIntFromString(
 41		"16950150798460657717958625567821834550301663161624707787222815936182638968203")
 42}
 43
 44// Point represents a point of the babyjub curve.
 45type Point struct {
 46	X *big.Int
 47	Y *big.Int
 48}
 49
 50// NewPoint creates a new Point.
 51func NewPoint() *Point {
 52	return &Point{X: big.NewInt(0), Y: big.NewInt(1)}
 53}
 54
 55// Set copies a Point c into the Point p
 56func (p *Point) Set(c *Point) *Point {
 57	p.X.Set(c.X)
 58	p.Y.Set(c.Y)
 59	return p
 60}
 61
 62// Add adds Point a and b into res
 63func (res *Point) Add(a *Point, b *Point) *Point {
 64	// x = (a.x * b.y + b.x * a.y) * (1 + D * a.x * b.x * a.y * b.y)^-1 mod q
 65	x1a := new(big.Int).Mul(a.X, b.Y)
 66	x1b := new(big.Int).Mul(b.X, a.Y)
 67	x1a.Add(x1a, x1b) // x1a = a.x * b.y + b.x * a.y
 68
 69	x2 := new(big.Int).Set(D)
 70	x2.Mul(x2, a.X)
 71	x2.Mul(x2, b.X)
 72	x2.Mul(x2, a.Y)
 73	x2.Mul(x2, b.Y)
 74	x2.Add(constants.One, x2)
 75	x2.Mod(x2, constants.Q)
 76	x2.ModInverse(x2, constants.Q) // x2 = (1 + D * a.x * b.x * a.y * b.y)^-1
 77
 78	// y = (a.y * b.y - A * a.x * b.x) * (1 - D * a.x * b.x * a.y * b.y)^-1 mod q
 79	y1a := new(big.Int).Mul(a.Y, b.Y)
 80	y1b := new(big.Int).Set(A)
 81	y1b.Mul(y1b, a.X)
 82	y1b.Mul(y1b, b.X)
 83
 84	y1a.Sub(y1a, y1b) // y1a = a.y * b.y - A * a.x * b.x
 85
 86	y2 := new(big.Int).Set(D)
 87	y2.Mul(y2, a.X)
 88	y2.Mul(y2, b.X)
 89	y2.Mul(y2, a.Y)
 90	y2.Mul(y2, b.Y)
 91	y2.Sub(constants.One, y2)
 92	y2.Mod(y2, constants.Q)
 93	y2.ModInverse(y2, constants.Q) // y2 = (1 - D * a.x * b.x * a.y * b.y)^-1
 94
 95	res.X = x1a.Mul(x1a, x2)
 96	res.X = res.X.Mod(res.X, constants.Q)
 97
 98	res.Y = y1a.Mul(y1a, y2)
 99	res.Y = res.Y.Mod(res.Y, constants.Q)
100
101	return res
102}
103
104// Mul multiplies the Point p by the scalar s and stores the result in res,
105// which is also returned.
106func (res *Point) Mul(s *big.Int, p *Point) *Point {
107	res.X = big.NewInt(0)
108	res.Y = big.NewInt(1)
109	exp := NewPoint().Set(p)
110
111	for i := 0; i < s.BitLen(); i++ {
112		if s.Bit(i) == 1 {
113			res.Add(res, exp)
114		}
115		exp.Add(exp, exp)
116	}
117
118	return res
119}
120
121// InCurve returns true when the Point p is in the babyjub curve.
122func (p *Point) InCurve() bool {
123	x2 := new(big.Int).Set(p.X)
124	x2.Mul(x2, x2)
125	x2.Mod(x2, constants.Q)
126
127	y2 := new(big.Int).Set(p.Y)
128	y2.Mul(y2, y2)
129	y2.Mod(y2, constants.Q)
130
131	a := new(big.Int).Mul(A, x2)
132	a.Add(a, y2)
133	a.Mod(a, constants.Q)
134
135	b := new(big.Int).Set(D)
136	b.Mul(b, x2)
137	b.Mul(b, y2)
138	b.Add(constants.One, b)
139	b.Mod(b, constants.Q)
140
141	return a.Cmp(b) == 0
142}
143
144// InSubGroup returns true when the Point p is in the subgroup of the babyjub
145// curve.
146func (p *Point) InSubGroup() bool {
147	if !p.InCurve() {
148		return false
149	}
150	res := NewPoint().Mul(SubOrder, p)
151	return (res.X.Cmp(constants.Zero) == 0) && (res.Y.Cmp(constants.One) == 0)
152}
153
154// PointCoordSign returns the sign of the curve point coordinate.  It returns
155// false if the sign is positive and false if the sign is negative.
156func PointCoordSign(c *big.Int) bool {
157	if c.Cmp(new(big.Int).Rsh(constants.Q, 1)) == 1 {
158		return true
159	}
160	return false
161}
162
163func PackPoint(ay *big.Int, sign bool) [32]byte {
164	leBuf := utils.BigIntLEBytes(ay)
165	if sign {
166		leBuf[31] = leBuf[31] | 0x80
167	}
168	return leBuf
169}
170
171// Compress the point into a 32 byte array that contains the y coordinate in
172// little endian and the sign of the x coordinate.
173func (p *Point) Compress() [32]byte {
174	sign := false
175	if PointCoordSign(p.X) {
176		sign = true
177	}
178	return PackPoint(p.Y, sign)
179}
180
181// Decompress a compressed Point into p, and also returns the decompressed
182// Point.  Returns error if the compressed Point is invalid.
183func (p *Point) Decompress(leBuf [32]byte) (*Point, error) {
184	sign := false
185	if (leBuf[31] & 0x80) != 0x00 {
186		sign = true
187		leBuf[31] = leBuf[31] & 0x7F
188	}
189	utils.SetBigIntFromLEBytes(p.Y, leBuf[:])
190	if p.Y.Cmp(constants.Q) >= 0 {
191		return nil, fmt.Errorf("p.y >= Q")
192	}
193
194	y2 := new(big.Int).Mul(p.Y, p.Y)
195	y2.Mod(y2, constants.Q)
196	xa := big.NewInt(1)
197	xa.Sub(xa, y2) // xa == 1 - y^2
198
199	xb := new(big.Int).Mul(D, y2)
200	xb.Mod(xb, constants.Q)
201	xb.Sub(A, xb) // xb = A - d * y^2
202
203	if xb.Cmp(big.NewInt(0)) == 0 {
204		return nil, fmt.Errorf("division by 0")
205	}
206	xb.ModInverse(xb, constants.Q)
207	p.X.Mul(xa, xb) // xa / xb
208	p.X.Mod(p.X, constants.Q)
209	p.X.ModSqrt(p.X, constants.Q)
210	if (sign && !PointCoordSign(p.X)) || (!sign && PointCoordSign(p.X)) {
211		p.X.Mul(p.X, constants.MinusOne)
212	}
213	p.X.Mod(p.X, constants.Q)
214
215	return p, nil
216}