You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

213 lines
5.1 KiB

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