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

Getting started

Install the module, choose a curve, and learn the conventions — constructors, round-based protocols, serialization, and error handling — that every package in this library shares.

Install

go get github.com/sonr-io/crypto

Requires Go 1.24.7 or newer. Every package is imported under the module path github.com/sonr-io/crypto/<package>:

import (
	"github.com/sonr-io/crypto/core/curves"
	"github.com/sonr-io/crypto/sharing"
	"github.com/sonr-io/crypto/mpc"
)

There is no top-level façade package — the module root holds only a cross-package security test suite. Import the specific primitive you need.

Pick a curve first

Most constructors take a *curves.Curve. That single argument determines the group, the scalar field, and the serialization width of everything downstream, so it is the first decision you make:

curve := curves.K256()   // secp256k1 — Bitcoin, Ethereum, Cosmos
curve := curves.P256()   // NIST P-256 — WebAuthn, FIDO2, TLS
curve := curves.ED25519() // Ed25519 — Sonr identity keys

Some primitives need a pairing-friendly curve instead, because they rely on a bilinear map. BBS+ signatures and the accumulator both fall in this group and take a *curves.PairingCurve:

pairingCurve := curves.BLS12381(curves.BLS12381G1().NewGeneratorPoint())

Passing a plain *curves.Curve where a *curves.PairingCurve is required will not compile, which is the intended guardrail. See Curves for the full catalog and interface reference.

Conventions worth knowing

Constructors validate, so check the error

Constructors do real work — parameter validation, generator derivation, table precomputation — and return an error rather than panicking on bad input. A NewShamir with a threshold above its limit fails at construction, not at Split time:

scheme, err := sharing.NewShamir(3, 5, curves.K256())
if err != nil {
	return fmt.Errorf("invalid sharing parameters: %w", err)
}

Two generations of API coexist

The library carries an older, curve-specific API alongside the modern generic one. You will meet both in go doc output, and mixing them does not type-check:

Modern Legacy Used by
curves.Point, curves.Scalar curves.EcPoint, curves.EcScalar sharing/v1, dkg/gennaro
sharing sharing/v1 dkg/gennaro, dkg/gennaro2p
operates on curves.Scalar operates on []byte and curves.Element

Prefer the modern API for new code. Reach for the legacy layer only when a package you depend on forces it. Foundations explains the split in detail.

Multi-party protocols are explicit round objects

Nothing in this library hides the network. A multi-party protocol is a stateful object whose methods are the rounds, and you move the messages between parties yourself. Two shapes appear:

Each round is a distinct method. You call them in order and route the outputs — some broadcast to everyone, some point-to-point to one peer. Used by dkg/frost, dkg/gennaro, and ted25519/frost.

bcast, p2p, err := participant.Round1(secret)
// broadcast `bcast` to all; send p2p[peerID] privately to each peer

The protocol is a protocol.Iterator: you feed it the counterparty’s message and it returns the next one, until it signals completion and you read Result. Used by tecdsa/dklsv1 and, wrapped up entirely, by mpc.

msg, err := alice.Next(bobMsg)

Calling rounds out of order is an error, not undefined behavior — the objects track their own state. See Protocol messages for the iterator contract.

Serialization is per-type, not reflective

Keys, shares, proofs, and signatures implement their own codecs — usually MarshalBinary/UnmarshalBinary, sometimes MarshalJSON/UnmarshalJSON, and in the DKG packages Encode/Decode. Use them rather than reflecting over struct fields with encoding/gob or a generic JSON marshal, because unexported field state and curve identity would be lost.

Unmarshalling frequently needs to know the curve up front, since the wire bytes alone do not identify it. The idiom is to initialize an empty value on the right curve, then unmarshal into it:

sig := new(bbs.Signature).Init(pairingCurve)
if err := sig.UnmarshalBinary(data); err != nil {
	return err
}

Randomness is injected

Anything that consumes entropy takes an io.Reader, so tests can be deterministic and production code is explicit about its source. Pass crypto/rand.Reader unless you have a specific reason not to:

shares, err := scheme.Split(secret, rand.Reader)

Where to next

Last updated on September 2, 2026

Was this page helpful?