/ GrothCurves / src / BN254Fp2.jl
BN254Fp2.jl
  1  # BN254 curve field implementations.
  2  #
  3  # Defines the BN254 base and quadratic extension fields used throughout the
  4  # pairing engine.
  5  
  6  # using GrothAlgebra
  7  # using StaticArrays
  8  
  9  # BN254Field is now provided by GrothAlgebra
 10  # Just re-export what we need
 11  const BN254_PRIME = prime(BN254Field)
 12  
 13  """
 14      Fp2Element
 15  
 16  Element of the quadratic extension field Fp2 = Fp[u]/(u² + 1).
 17  Represented as c0 + c1*u where c0, c1 ∈ Fp.
 18  """
 19  struct Fp2Element
 20      coeffs::SVector{2,BN254Field}
 21  
 22      function Fp2Element(c0::BN254Field, c1::BN254Field)
 23          new(SVector(c0, c1))
 24      end
 25  end
 26  
 27  # Convenient constructors
 28  Fp2Element(c0::Integer, c1::Integer) = Fp2Element(bn254_field(c0), bn254_field(c1))
 29  Fp2Element(c0) = Fp2Element(bn254_field(c0), zero(BN254Field))
 30  
 31  # Access components
 32  Base.getindex(a::Fp2Element, i::Int) = a.coeffs[i]
 33  real(a::Fp2Element) = a.coeffs[1]
 34  imag(a::Fp2Element) = a.coeffs[2]
 35  
 36  # Basic operations
 37  Base.zero(::Type{Fp2Element}) = Fp2Element(zero(BN254Field), zero(BN254Field))
 38  Base.one(::Type{Fp2Element}) = Fp2Element(one(BN254Field), zero(BN254Field))
 39  Base.zero(::Fp2Element) = zero(Fp2Element)
 40  Base.one(::Fp2Element) = one(Fp2Element)
 41  
 42  Base.iszero(a::Fp2Element) = iszero(a[1]) && iszero(a[2])
 43  Base.isone(a::Fp2Element) = isone(a[1]) && iszero(a[2])
 44  
 45  # Equality
 46  Base.:(==)(a::Fp2Element, b::Fp2Element) = a.coeffs == b.coeffs
 47  Base.isequal(a::Fp2Element, b::Fp2Element) = isequal(a.coeffs, b.coeffs)
 48  
 49  # Arithmetic operations
 50  Base.:+(a::Fp2Element, b::Fp2Element) = Fp2Element(a[1] + b[1], a[2] + b[2])
 51  Base.:-(a::Fp2Element, b::Fp2Element) = Fp2Element(a[1] - b[1], a[2] - b[2])
 52  Base.:-(a::Fp2Element) = Fp2Element(-a[1], -a[2])
 53  
 54  """
 55      *(a::Fp2Element, b::Fp2Element)
 56  
 57  Multiply two `Fp2Element`s using the relation `u² = -1`.
 58  The product `(a₀ + a₁u)(b₀ + b₁u)` equals `(a₀b₀ - a₁b₁) + (a₀b₁ + a₁b₀)u`.
 59  """
 60  function Base.:*(a::Fp2Element, b::Fp2Element)
 61      # Real part: a0*b0 - a1*b1
 62      c0 = a[1] * b[1] - a[2] * b[2]
 63      # Imaginary part: a0*b1 + a1*b0
 64      c1 = a[1] * b[2] + a[2] * b[1]
 65      return Fp2Element(c0, c1)
 66  end
 67  
 68  # Scalar multiplication
 69  Base.:*(a::Fp2Element, k::Integer) = Fp2Element(a[1] * k, a[2] * k)
 70  Base.:*(k::Integer, a::Fp2Element) = a * k
 71  Base.:*(a::Fp2Element, k::BN254Field) = Fp2Element(a[1] * k, a[2] * k)
 72  Base.:*(k::BN254Field, a::Fp2Element) = a * k
 73  
 74  """
 75      conjugate(a::Fp2Element)
 76  
 77  Return the conjugate `a - b*u` of `a + b*u`.
 78  """
 79  conjugate(a::Fp2Element) = Fp2Element(a[1], -a[2])
 80  
 81  """
 82      norm(a::Fp2Element)
 83  
 84  Compute the norm `a² + b²` of `a + b*u`.
 85  """
 86  norm(a::Fp2Element) = a[1]^2 + a[2]^2
 87  
 88  """
 89      inv(a::Fp2Element)
 90  
 91  Compute the multiplicative inverse `(a - b*u) / (a² + b²)`.
 92  """
 93  function Base.inv(a::Fp2Element)
 94      if iszero(a)
 95          throw(DivideError())
 96      end
 97      n = norm(a)
 98      n_inv = inv(n)
 99      conj = conjugate(a)
100      return Fp2Element(conj[1] * n_inv, conj[2] * n_inv)
101  end
102  
103  Base.:/(a::Fp2Element, b::Fp2Element) = a * inv(b)
104  
105  """
106      ^(a::Fp2Element, n::Integer)
107  
108  Raise an `Fp2Element` to the integer power `n` using binary exponentiation.
109  """
110  function Base.:^(a::Fp2Element, n::Integer)
111      if n == 0
112          return one(Fp2Element)
113      elseif n < 0
114          return inv(a)^(-n)
115      end
116  
117      result = one(Fp2Element)
118      base = a
119      exp = n
120  
121      while exp > 0
122          if exp & 1 == 1
123              result = result * base
124          end
125          base = base * base
126          exp >>= 1
127      end
128  
129      return result
130  end
131  
132  """
133      frobenius(a::Fp2Element)
134  
135  Apply the Frobenius endomorphism `(a + b*u) ↦ (a - b*u)` (since `u^p = -u`).
136  """
137  frobenius(a::Fp2Element) = conjugate(a)
138  
139  # Display
140  function Base.show(io::IO, a::Fp2Element)
141      if iszero(a[2])
142          print(io, "Fp2(", a[1].value, ")")
143      else
144          print(io, "Fp2(", a[1].value, " + ", a[2].value, "*u)")
145      end
146  end
147  
148  # Export types and functions
149  export BN254Field, bn254_field, BN254_PRIME
150  export Fp2Element, conjugate, norm, frobenius, real, imag