Skip to content
Sonr Crypto
Esc
navigateopen⌘Jpreview
On this page

Curves

Every named curve constructor in core/curves, the complete Point and Scalar method sets, pairing curves, and a map of the low-level native field arithmetic underneath.

core/curves is the catalog. It exposes one constructor per supported group, all of which hand back a *curves.Curve (or a *curves.PairingCurve for the pairing-friendly ones). Everything on this page was read out of go doc github.com/sonr-io/crypto/core/curves.

Reach for this page when you need to know which curve a package will accept, what a serialized point looks like on the wire, or which method on Point/Scalar does the thing you want. You do not need this page if you are just passing a curve through — curves.K256() and go.

Named curves

Constructor Name value Constant Notes
curves.K256() secp256k1 K256Name Bitcoin/Ethereum curve. 33-byte compressed points.
curves.P256() P-256 P256Name NIST P-256 / secp256r1.
curves.ED25519() ed25519 ED25519Name Edwards curve; 32-byte compressed points.
curves.BLS12381G1() BLS12381G1 BLS12381G1Name G1 of BLS12-381; 48-byte compressed points.
curves.BLS12381G2() BLS12381G2 BLS12381G2Name G2 of BLS12-381; 96-byte compressed points.
curves.BLS12377G1() BLS12377G1 BLS12377G1Name G1 of BLS12-377 (gnark-crypto backed).
curves.BLS12377G2() BLS12377G2 BLS12377G2Name G2 of BLS12-377.
curves.PALLAS() pallas PallasName Pasta/Pallas curve.

Two extra string constants exist for “the pairing construction, group unspecified”: BLS12831Name = "BLS12831" and BLS12377Name = "BLS12377".

Lookup by name

curve := curves.GetCurveByName(curves.K256Name)
if curve == nil {
	return fmt.Errorf("unsupported curve")
}

GetCurveByName accepts every constant above. BLS12831Name and BLS12377Name both resolve to the G1 curve. Anything else returns nil.

Pairing curves

BBS+ and the accumulator need a pairing, so they take a *curves.PairingCurve — a different type from *curves.Curve. Passing curves.BLS12381G1() where a *PairingCurve is wanted will not compile.

type PairingCurve struct {
	Scalar  PairingScalar
	PointG1 PairingPoint
	PointG2 PairingPoint
	GT      Scalar
	Name    string
}
PropType
BLS12381(preferredPoint Point)?*PairingCurve

Builds the BLS12-381 pairing curve. The argument selects which group the curve's scalars prefer to project into — pass BLS12381G1().NewIdentityPoint() or the G2 equivalent.

Type*PairingCurve
GetPairingCurveByName(name string)?*PairingCurve

Accepts BLS12381G1Name, BLS12381G2Name, or BLS12831Name. Returns nil for anything else.

Type*PairingCurve
NewG1GeneratorPoint() / NewG2GeneratorPoint()?PairingPoint

Generators of G1 and G2.

TypePairingPoint
NewG1IdentityPoint() / NewG2IdentityPoint()?PairingPoint

Identity elements of G1 and G2.

TypePairingPoint
NewScalar()?PairingScalar

Zero scalar carrying the preferred-point projection.

TypePairingScalar
ScalarG1BaseMult(sc) / ScalarG2BaseMult(sc)?PairingPoint

Fixed-base multiplication in G1 or G2 respectively.

TypePairingPoint

PairingPoint and PairingScalar are extensions of the ordinary interfaces, so every Point/Scalar method is still available:

type PairingPoint interface {
	Point
	OtherGroup() PairingPoint          // G1 <-> G2
	Pairing(rhs PairingPoint) Scalar   // e(self, rhs) as a GT element
	MultiPairing(...PairingPoint) Scalar
}

type PairingScalar interface {
	Scalar
	SetPoint(p Point) PairingScalar
}

Note that Pairing returns a Scalar, not a distinct GT type — the target group element is modelled as a ScalarBls12381Gt. It supports the Scalar arithmetic surface (Mul, Add, Invert, Bytes) but it is a group element in the target group GT, not a field element mod the group order. Do not feed it back into ScalarBaseMult.

package main

import (
	"crypto/rand"
	"fmt"

	"github.com/sonr-io/crypto/core/curves"
)

func main() {
	pc := curves.BLS12381(curves.BLS12381G1().NewIdentityPoint())

	s := pc.NewScalar().Random(rand.Reader)
	g1 := pc.ScalarG1BaseMult(s) // s·G1
	g2 := pc.NewG2GeneratorPoint()

	gt := g1.Pairing(g2) // e(s·G1, G2)
	fmt.Println(pc.Name, len(gt.Bytes()))
	fmt.Println(g1.OtherGroup().CurveName()) // BLS12381G2
}

The Point interface

Twenty methods, no error returns except on the two deserializers and Set.

Method Signature Purpose
Random Random(reader io.Reader) Point Uniform random group element from the reader.
Hash Hash(bytes []byte) Point Hash-to-curve. Deterministic; the domain separation tag is fixed inside each implementation.
Identity Identity() Point Point at infinity.
Generator Generator() Point Group generator.
IsIdentity IsIdentity() bool Identity test.
IsNegative IsNegative() bool Sign-of-y test, curve-specific convention.
IsOnCurve IsOnCurve() bool Curve-equation check.
Double Double() Point 2·self.
Scalar Scalar() Scalar A zero scalar of the matching field — a convenience constructor, not a discrete log.
Neg Neg() Point -self.
Add / Sub Add(rhs Point) Point Group law.
Mul Mul(rhs Scalar) Point Variable-base scalar multiplication.
Equal Equal(rhs Point) bool Group equality (compares in affine, handles differing projective representations).
Set Set(x, y *big.Int) (Point, error) Build from affine coordinates; errors if off-curve.
ToAffineCompressed ToAffineCompressed() []byte Canonical short encoding.
ToAffineUncompressed ToAffineUncompressed() []byte Canonical long encoding.
FromAffineCompressed FromAffineCompressed(bytes []byte) (Point, error) Inverse of the above.
FromAffineUncompressed FromAffineUncompressed(bytes []byte) (Point, error) Inverse of the above.
CurveName CurveName() string The Name string of the owning curve.
SumOfProducts SumOfProducts(points []Point, scalars []Scalar) Point Multi-scalar multiplication.

Serialization

Concrete point types also implement MarshalBinary/UnmarshalBinary, MarshalText/UnmarshalText, and MarshalJSON/UnmarshalJSON — that is how the higher layers (BBS+ proofs, accumulator witnesses, DKG round messages) persist points. The interface itself does not declare them, so if you need marshalling through the interface you type-assert to encoding.BinaryMarshaler.

SumOfProducts — multi-scalar multiplication

This is the MSM entry point, and the reason Bulletproofs and the accumulator are tractable. Call it on the curve’s point prototype; the receiver’s own value is ignored.

// Computes sum(scalars[i] · points[i]) using a 4-bit windowed bucket
// (Pippenger-style) multi-exponentiation, not n independent scalar mults.
result := curve.Point.SumOfProducts(points, scalars)
if result == nil {
	return errors.New("length mismatch or foreign point/scalar type")
}

The Scalar interface

The doc comment describes it as “an element of the scalar field F_q of the elliptic curve construction” — that is, arithmetic is mod the group order, not the field characteristic.

Group Methods
Construction Random(io.Reader), Hash([]byte), Zero(), One(), New(value int), Clone()
Predicates IsZero(), IsOne(), IsOdd(), IsEven(), Cmp(rhs) int
Arithmetic Add, Sub, Mul, Div, Neg, Double, Square, Cube, MulAdd(y, z)
Fallible arithmetic Invert() (Scalar, error), Sqrt() (Scalar, error)
Conversion SetBigInt(*big.Int) (Scalar, error), BigInt() *big.Int, Bytes() []byte, SetBytes([]byte) (Scalar, error), SetBytesWide([]byte) (Scalar, error)
Crossing over Point() Point — the associated point type’s prototype

Three behaviours that catch people:

  • Cmp returns -2 if the two scalars belong to different fields. It is the library’s only cross-curve mismatch signal. -1/0/1 are the usual ordering.
  • New(value int) takes a signed int and reduces it, so New(-1) is q - 1. Since q is odd for these curves, New(-1).IsEven() is true — the parity predicates describe the reduced representative, not the integer you passed.
  • SetBytes demands the exact width, while SetBytesWide wants double the width and reduces. Use SetBytesWide when converting hash output into a scalar without modulo bias; use Hash if you just want “bytes to scalar” done correctly.
// Uniform scalar from arbitrary input, no bias, no length constraints:
s := curve.Scalar.Hash([]byte("some transcript bytes"))

// Exact-width canonical decoding, e.g. reading a stored private key:
s, err := curve.Scalar.SetBytes(keyBytes) // len(keyBytes) must be exactly 32 for K256

The crypto/elliptic bridge

Some code (Go’s crypto/ecdsa, X.509 marshalling, the legacy EcPoint API) needs an elliptic.Curve. Several shims exist, and they are not interchangeable:

Function Returns Backing implementation
curves.K256Curve() *Koblitz256 native k256 field arithmetic
curves.NistP256Curve() *NistP256 native p256 field arithmetic
curves.SP256() elliptic.Curve github.com/dustinxie/ecc secp256k1
secp256k1.S256() *secp256k1.BitCurve the vendored Koblitz a=0 implementation
curves.Pallas() *PallasCurve Pallas as an elliptic.Curve

All of them satisfy elliptic.Curve. Curve.ToEllipticCurve() is the generic entry point:

ec, err := curves.K256().ToEllipticCurve() // -> *Koblitz256, nil
ec, err = curves.ED25519().ToEllipticCurve() // -> nil, "can't convert ed25519"

secp256k1.BitCurve additionally offers Marshal(x, y) []byte / Unmarshal(data) (x, y) and exposes its parameters as public fields (P, N, B, Gx, Gy, BitSize).

core/curves/native — the layer below

native is the constant-time-oriented field and point arithmetic that the modern Point/Scalar implementations sit on. It is a building block, and almost nothing outside core/curves should import it.

Fields are represented as four 64-bit limbs in the Montgomery domain:

const (
	FieldBytes     = 32 // canonical byte width
	FieldLimbs     = 4  // uint64 limbs
	WideFieldBytes = 64 // width for bias-free reduction
	MaxDstLen      = 255
)

type Field struct {
	Value      [FieldLimbs]uint64
	Params     *FieldParams   // R, R2, R3, Modulus, BiModulus
	Arithmetic FieldArithmetic // per-curve limb routines
}

Field provides Add, Sub, Mul, Square, Double, Neg, Exp, Invert, Sqrt, CMove, Equal, Cmp, plus SetBytes/SetBytesWide/SetBigInt/SetLimbs/SetRaw and their Bytes/BigInt/Raw inverses. EllipticPoint provides Weierstrass point arithmetic in Jacobian coordinates (Add, Double, Generator, Hash, Equal, BigInt, GetX, GetY).

Which fields and groups are actually implemented:

Package Contents
native/bls12381 G1, G2, Gt, the pairing Engine, Fq, Bls12381FqNew()
native/k256 K256PointNew(); subpackages k256/fp (base field) and k256/fq (scalar field)
native/p256 P256PointNew(); subpackages p256/fp and p256/fq
native/pasta Pallas/Vesta point code; subpackages pasta/fp and pasta/fq

Hash-to-curve hashers

EllipticPointHasher bundles a hash function with its expansion mode. It is what Point.Hash uses internally, and the only reason to construct one yourself is if you are calling native.ExpandMsgXmd / native.ExpandMsgXof or EllipticPoint.Hash directly.

Constructor Name() Type()
EllipticPointHasherSha256() SHA-256 XMD
EllipticPointHasherSha512() SHA-512 XMD
EllipticPointHasherSha3256() SHA3-256 XMD
EllipticPointHasherSha3384() SHA3-384 XMD
EllipticPointHasherSha3512() SHA3-512 XMD
EllipticPointHasherBlake2b() BLAKE2b XMD
EllipticPointHasherShake128() SHAKE-128 XOF
EllipticPointHasherShake256() SHAKE-256 XOF

ExpandMsgXmd and ExpandMsgXof implement §5.4.1 and §5.4.2 of the CFRG hash-to-curve draft (the source links to draft-irtf-cfrg-hash-to-curve-13). Domain separation tags longer than MaxDstLen are hashed down using the OversizeDstSalt prefix H2C-OVERSIZE-DST-.

Legacy curve types

For completeness, since they show up in go doc next to everything above. These belong to the older API described on the foundations overview and are used by sharing/v1, dkg/gennaro, and ted25519 keygen.

  • EcPoint{Curve elliptic.Curve; X, Y *big.Int} with NewScalarBaseMult, PointFromBytesUncompressed, Add, Neg, ScalarMult, Bytes, Equals, IsOnCurve, IsIdentity, IsBasePoint, IsValid, and binary/JSON marshalling (plus EcPointJSON as the wire shape).
  • Field/Element — generic big.Int modular arithmetic over an explicit modulus, with ElementJSON for serialization.
  • EcScalar — a strategy interface (Add, Sub, Neg, Mul, Div, Hash, Random, IsValid, Bytes) implemented by NewK256Scalar(), NewP256Scalar(), NewEd25519Scalar(), NewBls12381Scalar(), and NewPallasScalar().
  • EcdsaSignature, EcdsaVerify, and VerifyEcdsa(pk *EcPoint, hash []byte, sig *EcdsaSignature) bool — the verification hook used by threshold ECDSA. See ECDSA.
  • Ed25519Order() *big.Int — the Ed25519 group order as a big.Int.

Last updated on September 2, 2026

Was this page helpful?