Documentation
¶
Overview ¶
Example (SignAndVerify) ¶
Example_signAndVerify shows the default signing path.
Sign/Verify are CONSENSUS-SAFE: they perform a fixed amount of work independent of any cache or call history, so their cost is deterministic across nodes. Use this path on-chain / in gas-metered code.
package main
import (
"fmt"
ring "github.com/pokt-network/ring-go"
"golang.org/x/crypto/sha3"
)
func main() {
curve := ring.Secp256k1()
privKey := curve.NewRandomScalar()
// ring of 16 keys; ours sits at secret index 7.
keyring, err := ring.NewKeyRing(curve, 16, privKey, 7)
if err != nil {
panic(err)
}
msg := sha3.Sum256([]byte("hello"))
sig, err := keyring.Sign(msg, privKey)
if err != nil {
panic(err)
}
fmt.Println(sig.Verify(msg))
}
Output: true
Index ¶
- func Ed25519() types.Curve
- func Link(sigA, sigB *RingSig) bool
- func Secp256k1() types.Curve
- type Curve
- type Ring
- func NewFixedKeyRingFromPublicKeys(curve types.Curve, pubkeys []types.Point) (*Ring, error)
- func NewKeyRing(curve types.Curve, size int, privKey types.Scalar, idx int) (*Ring, error)
- func NewKeyRingFromPublicKeys(curve types.Curve, pubkeys []types.Point, privKey types.Scalar, idx int) (*Ring, error)
- func (r *Ring) Equals(other *Ring) bool
- func (r *Ring) NewSignerContext(privKey types.Scalar) (*SignerContext, error)
- func (r *Ring) Sign(m [32]byte, privKey types.Scalar) (*RingSig, error)
- func (r *Ring) SignWithContext(m [32]byte, privKey types.Scalar, ctx *SignerContext) (*RingSig, error)
- func (r *Ring) Size() int
- type RingSig
- type SignerContext
Examples ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
Types ¶
type Ring ¶
type Ring struct {
// contains filtered or unexported fields
}
Ring represents a group of public keys such that one of the group created a signature.
func NewFixedKeyRingFromPublicKeys ¶
NewFixedKeyRingFromPublicKeys takes public keys and a curve to create a ring
func NewKeyRing ¶
NewKeyRing creates a ring with size specified by `size` and places the public key corresponding to `privKey` in index idx of the ring. It returns a ring of public keys of length `size`.
func NewKeyRingFromPublicKeys ¶
func NewKeyRingFromPublicKeys(curve types.Curve, pubkeys []types.Point, privKey types.Scalar, idx int) (*Ring, error)
NewKeyRingFromPublicKeys takes public key ring and places the public key corresponding to `privKey` in index idx of the ring. It returns a ring of public keys of length `len(ring)+1`.
func (*Ring) Equals ¶
Equals checks whether the supplied ring is equal to the current ring. The ring's public keys must be in the same order for the rings to be equal
func (*Ring) NewSignerContext ¶ added in v0.2.0
func (r *Ring) NewSignerContext(privKey types.Scalar) (*SignerContext, error)
NewSignerContext pre-computes, for privKey (which must correspond to one of the ring's public keys), the signer's public key, key image, index, and the hash-to-curve of every ring member. The private key is used only to derive these public values and is NOT stored on the returned context. All state lives on the context; the shared Ring is not mutated.
func (*Ring) Sign ¶
Sign creates a ring signature on the given message using the public key ring and a private key of one of the members of the ring.
func (*Ring) SignWithContext ¶ added in v0.2.0
func (r *Ring) SignWithContext(m [32]byte, privKey types.Scalar, ctx *SignerContext) (*RingSig, error)
SignWithContext creates a ring signature using the values pre-computed in ctx, avoiding the per-signer and per-member setup that Sign repeats each call. The private key is supplied here (not stored on the context) and must be the same key the context was built for; otherwise the resulting signature is invalid (and rejected by the closing self-check unless ctx.SkipSelfCheck is set). It is an off-chain optimization; see SignerContext for the determinism caveat.
Example ¶
ExampleRing_SignWithContext shows the off-chain fast path: build a SignerContext once (which pre-computes the signer's key image and the hash-to-curve of every ring member), then reuse it to sign many messages without redoing that work.
WARNING: this path does less work than Sign, so its cost is not identical across calls/nodes. Do NOT use it on consensus-critical or gas-metered paths — use Sign there. Verification is unchanged.
package main
import (
"fmt"
ring "github.com/pokt-network/ring-go"
"golang.org/x/crypto/sha3"
)
func main() {
curve := ring.Secp256k1()
privKey := curve.NewRandomScalar()
keyring, err := ring.NewKeyRing(curve, 16, privKey, 7)
if err != nil {
panic(err)
}
// Pre-compute once.
ctx, err := keyring.NewSignerContext(privKey)
if err != nil {
panic(err)
}
ctx.SkipSelfCheck = true // optional extra speed, off-chain only
// Reuse across many messages.
allVerified := true
for i := 0; i < 3; i++ {
msg := sha3.Sum256([]byte(fmt.Sprintf("message-%d", i)))
sig, err := keyring.SignWithContext(msg, privKey, ctx)
if err != nil {
panic(err)
}
allVerified = allVerified && sig.Verify(msg)
}
fmt.Println(allVerified)
}
Output: true
type RingSig ¶
type RingSig struct {
// contains filtered or unexported fields
}
RingSig represents a ring signature.
func Sign ¶
Sign creates a ring signature on the given message using the provided private key and ring of public keys.
func (*RingSig) Deserialize ¶
Deserialize converts the byteified signature into a *RingSig.
func (*RingSig) PublicKeys ¶
PublicKeys returns a copy of the ring signature's public keys.
type SignerContext ¶ added in v0.2.0
type SignerContext struct {
// SkipSelfCheck, when true, omits the ~4-scalar-mul closing self-checks in
// SignWithContext. Off-chain speed opt-in only; the signature is still fully
// verifiable via RingSig.Verify. Leave false unless you trust the backend
// and have measured the win. NOTE: the self-checks are also what catch a
// privKey that does not match this context; with them skipped, a mismatched
// key silently produces an invalid (not forged) signature.
SkipSelfCheck bool
// contains filtered or unexported fields
}
SignerContext holds values that are constant across messages for a given (private key, ring): the signer's public key, hash-to-curve point, key image, index, and the hash-to-curve of every ring member. Pre-computing them once lets repeated signing skip all per-signer and per-member setup.
ctx, err := ring.NewSignerContext(privKey) sig1, _ := ring.SignWithContext(msg1, privKey, ctx) sig2, _ := ring.SignWithContext(msg2, privKey, ctx) // reuses ctx precompute
A SignerContext holds NO secret material: every field is derived from public data (the key image and public key are already published in signatures). The private key is not retained — it is supplied per call to SignWithContext, exactly as with Sign — so a context is safe to hold, reuse, and pass around. It is tied to the ring it was created from; do not use it with a different ring or a different private key than the one it was built for.
IMPORTANT: this is an OFF-CHAIN optimization. The precomputed member hashes mean SignWithContext performs less work than Sign for the same signature, so its cost is not identical to the plain path. Do NOT use SignerContext on consensus-critical / gas-metered paths where the amount of work performed must be deterministic across nodes — use Sign there.