Field Subtyping

This example demonstrates the flexibility and extensibility of the CryptoGroups package, showcasing how custom field implementations can be seamlessly integrated with existing elliptic curve operations. Specifically, it illustrates how to wrap and use GaloisFields's binary extension field implementation within the CryptoGroups to do computations with elliptic curves.

The modular approach of CryptoGroups allows users to integrate custom field implementations with elliptic curves easily. By defining a few key methods and ensuring proper subtyping, users can drop in their optimised field implementations - be it binary fields as shown here or Mersenne primes and test different optimisations with elliptic curves while allowing the use of existing implementations as reference. This design promotes the separation of concerns where one can focus on optimising fields, one new elliptic curve support or new arithmetic formulas like projective coordinates separately from each other.

using Test
using CryptoGroups
import CryptoGroups: BinaryField, concretize_type, PB, bitlength
import GaloisFields: ExtensionField, GaloisField

struct GF₂{F <: ExtensionField} <: BinaryField
    x::F

    GF₂{F}(coeffs::NTuple{N, GaloisField(2)}) where {N, F <: ExtensionField} = new(F(coeffs))

    function GF₂{F}(xrev::BitVector) where F <: ExtensionField
        x = reverse(xrev)
        𝔽₂ = GaloisField(2)
        coeffs = Tuple(𝔽₂(i) for i in x) # May need a reverse
        return GF₂{F}(coeffs)
    end

    GF₂{F}(x::F) where F <: ExtensionField = new{F}(x)
    GF₂(x::F) where F <: ExtensionField = new{F}(x)

    function GF₂(f::BitVector)
        F, x = GaloisField(2, :x=>f)
        return GF₂{F}
    end

    GF₂(poly::Vector{Int}) = GF₂(BitVector(i in poly for i in 0:maximum(poly)))
end

bitlength(::Type{F}) where F <: ExtensionField = length(F.parameters[4]) - 1
bitlength(::Type{GF₂{F}}) where F <: ExtensionField = bitlength(F)

concretize_type(::Type{GF₂}, basis::PB) = GF₂(basis.f)

Base.convert(::Type{F}, a::BitVector) where F <: GF₂ = F(a)
Base.convert(::Type{BitVector}, a::GF₂) = reverse(BitVector(i.n for i in a.x.coeffs))

Base.:+(a::F, b::F) where F <: GF₂ = F(a.x + b.x)
Base.:*(a::F, b::F) where F <: GF₂ = F(a.x * b.x)

Base.inv(a::F) where F <: GF₂ = F(inv(a.x))

Base.zero(::Type{GF₂{F}}) where F <: ExtensionField = GF₂(zero(F))
Base.one(::Type{GF₂{F}}) where F <: ExtensionField = GF₂(one(F))


########################## This one we can test easally as follows ##################

import CryptoGroups.Curves: oncurve, order, AffinePoint, ECPoint, BinaryCurve
import CryptoGroups: generator
import CryptoGroups.Specs: Curve_B_163_PB, Curve_K_163_PB

let
    B_163v3 = concretize_type(AffinePoint{BinaryCurve, GF₂}, Curve_B_163_PB)

    g = B_163v3(generator(Curve_B_163_PB))
    q = order(Curve_B_163_PB)

    @test oncurve(g)
    @test oncurve(g*3)
    @test g * (q + 1) == g
end

let
    K_163v3 = concretize_type(ECPoint{AffinePoint{BinaryCurve, GF₂}}, Curve_K_163_PB)

    g = K_163v3(generator(Curve_K_163_PB))
    q = order(Curve_K_163_PB)

    @test oncurve(g)
    @test oncurve(g*3)
    @test g * (q + 1) == g
end
Test Passed

This page was generated using Literate.jl.