---
title: Signatures
description: Choosing between BLS aggregation, BBS+ selective disclosure, ECDSA canonicalization, verifiable random functions, and the chain-specific Schnorr variants.
sidebar:
order: 1
icon: pen-tool
---
Five very different things live under this heading, and they are not interchangeable. Before you
pick one, decide which property you actually need: **aggregation** (many signatures collapse into
one), **selective disclosure** (a holder proves a subset of signed attributes), **determinism and
canonical encoding** (the same message always yields the same bytes), **verifiable randomness** (an
output nobody can predict but everybody can check), or **wire compatibility with a specific
blockchain**.
Every package here is a distinct construction with its own key type. There is no shared `Signer`
interface across them, and keys from one scheme are never valid in another.
## Pick a scheme
| Goal | Package | Page |
| --- | --- | --- |
| Collapse N signatures over N messages into one 96-byte object | `signatures/bls/bls_sig` | [BLS](/signatures/bls) |
| Multi-signature: N signers, one message, one aggregate check | `signatures/bls/bls_sig` (`SigPop`) | [BLS](/signatures/bls) |
| Split a signing key into `t`-of-`n` shares with no interaction | `signatures/bls/bls_sig` | [BLS](/signatures/bls) |
| Sign a vector of attributes; let the holder reveal only some | `signatures/bbs` | [BBS+](/signatures/bbs) |
| Issue a credential over messages the issuer must not see | `signatures/bbs` | [BBS+](/signatures/bbs) |
| Kill ECDSA signature malleability before storing or comparing | `ecdsa` | [ECDSA utilities](/signatures/ecdsa) |
| Sign with ECDSA without depending on runtime entropy | `ecdsa` | [ECDSA utilities](/signatures/ecdsa) |
| Unpredictable-but-verifiable per-message output (leader election, lotteries) | `vrf` | [VRF](/signatures/vrf) |
| Sign a Mina payment or delegation transaction | `signatures/schnorr/mina` | [Chain schemes](/signatures/chain-schemes) |
| Produce a NEM/Symbol Keccak-flavoured Ed25519 signature | `signatures/schnorr/nem` | [Chain schemes](/signatures/chain-schemes) |
Some adjacent things are documented elsewhere:
- The **interactive Schnorr proof of knowledge** (`zkp/schnorr`) is a ZKP, not a signature scheme —
see [zero-knowledge/schnorr](/zero-knowledge/schnorr).
- **Threshold ECDSA** and **threshold Ed25519** (FROST) produce ordinary ECDSA / Ed25519 signatures
from distributed shares — see [threshold ECDSA](/threshold/threshold-ecdsa) and
[threshold Ed25519](/threshold/threshold-ed25519). BLS threshold signing on this page is a
different, much simpler construction: it needs no rounds of interaction.
## What these packages assume about curves
`signatures/bbs` and the Mina scheme are written against the
[`core/curves`](/foundations/curves) `Curve` / `Point` / `Scalar` abstraction — BBS+ specifically
requires a `*curves.PairingCurve` (`curves.BLS12381(...)`). `signatures/bls/bls_sig` bypasses the
abstraction entirely and calls the low-level `core/curves/native/bls12381` backend directly, so it
is hard-wired to BLS12-381. The `ecdsa` package operates on stdlib `crypto/ecdsa` and
`crypto/elliptic` types, and `vrf` on a vendored Edwards25519 implementation.
## The shared proof toolkit: `signatures/common`
`signatures/common` holds the sigma-protocol plumbing that BBS+ (and code composing proofs with
BBS+) builds on. It is a building-block package — you rarely import it alone, but you will import it
to construct BBS+ proof messages.
| Symbol | Kind | Purpose |
| --- | --- | --- |
| `Challenge` | `= curves.Scalar` | Fiat-Shamir challenge value |
| `Commitment` | `= curves.Point` | Pedersen commitment to one or more scalars |
| `Nonce` | `= curves.Scalar` | Freshness / replay protection in a proof |
| `SignatureBlinding` | `= curves.PairingScalar` | Blinding factor for blind signing |
| `HmacDrbg` | struct | HMAC deterministic random bit generator, any hash, auto-reseeding |
| `ProofCommittedBuilder` | struct | Accumulates `(point, scalar)` commitments into Schnorr proofs |
| `ProofMessage` | interface | Classifies a signed message as revealed or hidden |
The four aliases are Go **type aliases**, not defined types: a `common.Nonce` *is* a
`curves.Scalar`, so no conversion is needed and the compiler will not stop you passing a challenge
where a nonce belongs. Treat the names as documentation, not as type safety.
### `ProofMessage` and its three implementations
`ProofMessage` is how a BBS+ prover declares, per message, whether it is disclosed:
```go
type ProofMessage interface {
IsHidden() bool
GetBlinding(reader io.Reader) curves.Scalar
GetMessage() curves.Scalar
}
```
### `ProofCommittedBuilder`
A small accumulator for Schnorr-style proofs of knowledge of a linear combination:
```go
import "github.com/sonr-io/crypto/signatures/common"
builder := common.NewProofCommittedBuilder(curve)
_ = builder.CommitRandom(basePoint, crand.Reader) // blinding for a secret you know
_ = builder.Commit(otherPoint, knownScalar) // fixed scalar
bytes := builder.GetChallengeContribution() // feed into your transcript
proofs, err := builder.GenerateProof(challenge, secrets)
```
`GetChallengeContribution` returns the compressed encoding of `SumOfProducts(points, scalars)` — the
aggregate commitment. `GenerateProof` then returns one response scalar per commitment, computed as
`secret*challenge + blinding`, and errors if `len(secrets)` does not match the number of
commitments. `Get(index)` retrieves the `(point, scalar)` pair at a position, returning `(nil, nil)`
out of range. The builder caps out at roughly 65535 commitments.
### `HmacDrbg`
```go
drbg := common.NewHmacDrbg(entropy, nonce, personalization, sha256.New)
buf := make([]byte, 64)
_, _ = drbg.Read(buf)
drbg.Reseed(moreEntropy)
```
It satisfies `io.Reader`, so it can be handed to any API here that takes a `reader` — which is how
you make an otherwise randomised proof reproducible in a test.
:::warning[These are internal building blocks]
`signatures/common` carries no package-level documentation and no tests of its own; it is exercised
only indirectly through `signatures/bbs`. If you use `ProofCommittedBuilder` to build a *new*
protocol rather than to compose with BBS+, you are on your own for soundness — nothing in this
repository validates that usage.
:::
## Caveats that apply across this section
:::danger[No audit, and no uniform error discipline]
None of these packages has a published security audit. They also differ in how they report failure:
BLS returns `(bool, error)` and you must check **both**; BBS+ `Verify` returns a plain `error`;
`PokSignatureProof.Verify` returns a bare `bool`; the VRF `Verify` returns a bare `bool`. Copying an
error-handling idiom from one page to another will silently drop failures. See
[security notes](/reference/security).
:::
:::note
Serialization is `encoding.BinaryMarshaler` / `BinaryUnmarshaler` throughout, but several types
(BBS+ `Signature`, `PokSignatureProof`, `BlindSignature`, `BlindSignatureContext`) need an
`Init(curve)` call before `UnmarshalBinary`, because the wire format does not name its curve.
:::
## Where to next
Two instantiations, three ciphersuites, aggregation, multi-signatures, and non-interactive
threshold keygen on BLS12-381.
Sign a vector of attributes, then prove possession while revealing only the ones you choose.
Malleability, canonical low-S form, fixed-width codecs, and deterministic nonce derivation.
Verifiable pseudorandom outputs over Edwards25519 with SHAKE256.
Mina Schnorr over Pallas/Poseidon and NEM's Keccak-512 Ed25519 variant.
The `Curve` / `Point` / `Scalar` triple that BBS+ and the Mina scheme are generic over.