schnorrkel

package module
v0.0.0-...-cee0b2e Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Apr 4, 2022 License: Apache-2.0 Imports: 10 Imported by: 0

README

go-schnorrkel

This repo contains the Go implementation of the sr25519 signature algorithm (schnorr over ristretto25519). The existing Rust implementation is here.

This library is currently able to create sr25519 keys, import sr25519 keys, and sign and verify messages. It is interoperable with the Rust implementation.

The BIP39 implementation in this library is compatible with the rust substrate-bip39 implementation. Note that this is not a standard bip39 implementation.

This library has been audited as of August 2021 and is production-ready. Please see the audit report for the results of the audit.

dependencies

go 1.16

usage

Example: key generation, signing, and verification

package main 

import (
	"fmt"
	
	schnorrkel "github.com/hashprotocol/go-schnorrkel"
)

func main() {
	msg := []byte("hello friends")
	signingCtx := []byte("example")

	signingTranscript := schnorrkel.NewSigningContext(signingCtx, msg)
	verifyTranscript := schnorrkel.NewSigningContext(signingCtx, msg)

	priv, pub, err := schnorrkel.GenerateKeypair()
	if err != nil {
		panic(err)
	}

	sig, err := priv.Sign(signingTranscript)
	if err != nil {
		panic(err)
	}

	ok := pub.Verify(sig, verifyTranscript)
	if !ok {
		fmt.Println("failed to verify signature")
		return
	}

	fmt.Println("verified signature")
}

Please see the godocs for more usage examples.

Documentation

Index

Examples

Constants

View Source
const (
	// MiniSecretKeySize is the length in bytes of a MiniSecretKey
	MiniSecretKeySize = 32

	// SecretKeySize is the length in bytes of a SecretKey
	SecretKeySize = 32

	// PublicKeySize is the length in bytes of a PublicKey
	PublicKeySize = 32
)
View Source
const ChainCodeLength = 32
View Source
const MAX_VRF_BYTES = 64

MAX_VRF_BYTES is the maximum bytes that can be extracted from the VRF via MakeBytes

View Source
const SignatureSize = 64

SignatureSize is the length in bytes of a signature

Variables

View Source
var (
	ErrDeriveHardKeyType = errors.New("cannot derive hard key type, DerivableKey must be of type SecretKey")
)
View Source
var ErrSignatureNotMarkedSchnorrkel = errors.New("signature is not marked as a schnorrkel signature")

ErrSignatureNotMarkedSchnorrkel is returned when attempting to decode a signature that is not marked as schnorrkel

Functions

func GenerateKeypair

func GenerateKeypair() (*SecretKey, *PublicKey, error)

GenerateKeypair generates a new schnorrkel secret key and public key

Example
priv, pub, err := GenerateKeypair()
if err != nil {
	panic(err)
}

fmt.Printf("0x%x\n", priv.Encode())
fmt.Printf("0x%x\n", pub.Encode())
Output:

func HexToBytes

func HexToBytes(in string) ([]byte, error)

HexToBytes turns a 0x prefixed hex string into a byte slice

func MnemonicToEntropy

func MnemonicToEntropy(mnemonic string) ([]byte, error)

MnemonicToEntropy takes a mnemonic string and reverses it to the entropy An error is returned if the mnemonic is invalid.

func NewRandomElement

func NewRandomElement() (*r255.Element, error)

NewRandomElement returns a random ristretto element

func NewRandomScalar

func NewRandomScalar() (*r255.Scalar, error)

NewRandomScalar returns a random ristretto scalar

func NewSigningContext

func NewSigningContext(context, msg []byte) *merlin.Transcript

NewSigningContext returns a new transcript initialized with the context for the signature .see: https://github.com/w3f/schnorrkel/blob/db61369a6e77f8074eb3247f9040ccde55697f20/src/context.rs#L183

func ScalarFromBytes

func ScalarFromBytes(b [32]byte) (*r255.Scalar, error)

ScalarFromBytes returns a ristretto scalar from the input bytes performs input mod l where l is the group order

func SeedFromMnemonic

func SeedFromMnemonic(mnemonic string, password string) ([64]byte, error)

SeedFromMnemonic returns a 64-byte seed from a bip39 mnemonic

func SetKusamaVRF

func SetKusamaVRF(k bool)

SetKusama sets the VRF kusama option. Defaults to true.

func TranscriptWithMalleabilityAddressed

func TranscriptWithMalleabilityAddressed(t *merlin.Transcript, pk *PublicKey) *merlin.Transcript

TranscriptWithMalleabilityAddressed returns the input transcript with the public key commited to it, addressing VRF output malleability.

func VerifyBatch

func VerifyBatch(transcripts []*merlin.Transcript, signatures []*Signature, pubkeys []*PublicKey) (bool, error)

VerifyBatch batch verifies the given signatures

Example
num := 16
transcripts := make([]*merlin.Transcript, num)
sigs := make([]*Signature, num)
pubkeys := make([]*PublicKey, num)

for i := 0; i < num; i++ {
	transcript := merlin.NewTranscript(fmt.Sprintf("hello_%d", i))
	priv, pub, err := GenerateKeypair()
	if err != nil {
		panic(err)
	}

	sigs[i], err = priv.Sign(transcript)
	if err != nil {
		panic(err)
	}

	transcripts[i] = merlin.NewTranscript(fmt.Sprintf("hello_%d", i))
	pubkeys[i] = pub
}

ok, err := VerifyBatch(transcripts, sigs, pubkeys)
if err != nil {
	panic(err)
}

if !ok {
	fmt.Println("failed to batch verify signatures")
	return
}

fmt.Println("batch verified signatures")
Output:

batch verified signatures

Types

type BatchVerifier

type BatchVerifier struct {
	// contains filtered or unexported fields
}
Example
num := 16
v := NewBatchVerifier()

for i := 0; i < num; i++ {
	transcript := merlin.NewTranscript(fmt.Sprintf("hello_%d", i))
	priv, pub, err := GenerateKeypair()
	if err != nil {
		panic(err)
	}

	sig, err := priv.Sign(transcript)
	if err != nil {
		panic(err)
	}

	transcript = merlin.NewTranscript(fmt.Sprintf("hello_%d", i))
	err = v.Add(transcript, sig, pub)
	if err != nil {
		panic(err)
	}
}

ok := v.Verify()
if !ok {
	fmt.Println("failed to batch verify signatures")
	return
}

fmt.Println("batch verified signatures")
Output:

batch verified signatures

func NewBatchVerifier

func NewBatchVerifier() *BatchVerifier

func (*BatchVerifier) Add

func (v *BatchVerifier) Add(t *merlin.Transcript, sig *Signature, pubkey *PublicKey) error

func (*BatchVerifier) Verify

func (v *BatchVerifier) Verify() bool

type DerivableKey

type DerivableKey interface {
	Encode() [32]byte
	Decode([32]byte) error
	DeriveKey(*merlin.Transcript, [ChainCodeLength]byte) (*ExtendedKey, error)
}

DerivableKey implements DeriveKey

type ExtendedKey

type ExtendedKey struct {
	// contains filtered or unexported fields
}

ExtendedKey consists of a DerivableKey which can be a schnorrkel public or private key as well as chain code

func DeriveKeyHard

func DeriveKeyHard(key DerivableKey, i []byte, cc [ChainCodeLength]byte) (*ExtendedKey, error)

DeriveKeyHard derives a Hard subkey identified by the byte array i and chain code

func DeriveKeySimple

func DeriveKeySimple(key DerivableKey, i []byte, cc [ChainCodeLength]byte) (*ExtendedKey, error)

DeriveKeySimple derives a Soft subkey identified by byte array i and chain code.

func DeriveKeySoft

func DeriveKeySoft(key DerivableKey, i []byte, cc [ChainCodeLength]byte) (*ExtendedKey, error)

DerviveKeySoft is an alias for DervieKeySimple() used to derive a Soft subkey identified by the byte array i and chain code

func NewExtendedKey

func NewExtendedKey(k DerivableKey, cc [ChainCodeLength]byte) *ExtendedKey

NewExtendedKey creates an ExtendedKey given a DerivableKey and chain code

func (*ExtendedKey) ChainCode

func (ek *ExtendedKey) ChainCode() [ChainCodeLength]byte

ChainCode returns the chain code underlying the ExtendedKey

func (*ExtendedKey) DeriveKey

func (ek *ExtendedKey) DeriveKey(t *merlin.Transcript) (*ExtendedKey, error)

DeriveKey derives an extended key from an extended key

func (*ExtendedKey) HardDeriveMiniSecretKey

func (ek *ExtendedKey) HardDeriveMiniSecretKey(i []byte) (*ExtendedKey, error)

HardDeriveMiniSecretKey implements BIP-32 like "hard" derivation of a mini secret from an extended key's secret key

func (*ExtendedKey) Key

func (ek *ExtendedKey) Key() DerivableKey

Key returns the schnorrkel key underlying the ExtendedKey

func (*ExtendedKey) Public

func (ek *ExtendedKey) Public() (*PublicKey, error)

Public returns the PublicKey underlying the ExtendedKey

func (*ExtendedKey) Secret

func (ek *ExtendedKey) Secret() (*SecretKey, error)

Secret returns the SecretKey underlying the ExtendedKey if it's not a secret key, it returns an error

type MiniSecretKey

type MiniSecretKey struct {
	// contains filtered or unexported fields
}

MiniSecretKey is a secret scalar

Example
// To create a private-public keypair from a subkey keypair, use `NewMiniSecretKeyFromRaw`
// This example uses the substrate built-in key Alice:
// $ subkey inspect //Alice
priv, err := NewMiniSecretKeyFromHex("0xe5be9a5092b81bca64be81d212e7f2f9eba183bb7a90954f7b76361f6edb5c0a")
if err != nil {
	panic(err)
}

pub := priv.Public()
fmt.Printf("0x%x", pub.Encode())
Output:

0xd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d

func GenerateMiniSecretKey

func GenerateMiniSecretKey() (*MiniSecretKey, error)

GenerateMiniSecretKey generates a mini secret key from random

func MiniSecretKeyFromMnemonic

func MiniSecretKeyFromMnemonic(mnemonic string, password string) (*MiniSecretKey, error)

MiniSecretKeyFromMnemonic returns a go-schnorrkel MiniSecretKey from a bip39 mnemonic

Example
mnemonic := "legal winner thank year wave sausage worth useful legal winner thank yellow"
msk, err := MiniSecretKeyFromMnemonic(mnemonic, "Substrate")
if err != nil {
	panic(err)
}

fmt.Printf("0x%x", msk.Encode())
Output:

0x4313249608fe8ac10fd5886c92c4579007272cb77c21551ee5b8d60b78041685

func NewMiniSecretKey

func NewMiniSecretKey(b [64]byte) *MiniSecretKey

NewMiniSecretKey derives a mini secret key from a seed

func NewMiniSecretKeyFromHex

func NewMiniSecretKeyFromHex(s string) (*MiniSecretKey, error)

NewMiniSecretKeyFromHex returns a new MiniSecretKey from the given hex-encoded string

func NewMiniSecretKeyFromRaw

func NewMiniSecretKeyFromRaw(b [MiniSecretKeySize]byte) (*MiniSecretKey, error)

NewMiniSecretKeyFromRaw derives a mini secret key from little-endian encoded raw bytes.

func (*MiniSecretKey) Decode

func (s *MiniSecretKey) Decode(in [MiniSecretKeySize]byte) error

Decode creates a MiniSecretKey from the given input

func (*MiniSecretKey) DeriveKey

DeriveKey derives an Extended Key from the Mini Secret Key

func (*MiniSecretKey) Encode

func (s *MiniSecretKey) Encode() [MiniSecretKeySize]byte

Encode returns the MiniSecretKey's underlying bytes

func (*MiniSecretKey) ExpandEd25519

func (s *MiniSecretKey) ExpandEd25519() *SecretKey

ExpandEd25519 expands a MiniSecretKey into a SecretKey using ed25519-style bit clamping https://github.com/w3f/schnorrkel/blob/43f7fc00724edd1ef53d5ae13d82d240ed6202d5/src/keys.rs#L196

Example
msg := []byte("hello")
signingCtx := []byte("example")

signingTranscript := NewSigningContext(signingCtx, msg)

msk, err := NewMiniSecretKeyFromHex("0xe5be9a5092b81bca64be81d212e7f2f9eba183bb7a90954f7b76361f6edb5c0a")
if err != nil {
	panic(err)
}

sk := msk.ExpandEd25519()

sig, err := sk.Sign(signingTranscript)
if err != nil {
	panic(err)
}

fmt.Printf("0x%x", sig.Encode())
Output:

func (*MiniSecretKey) ExpandUniform

func (s *MiniSecretKey) ExpandUniform() *SecretKey

ExpandUniform expands a MiniSecretKey into a SecretKey

func (*MiniSecretKey) HardDeriveMiniSecretKey

func (mk *MiniSecretKey) HardDeriveMiniSecretKey(i []byte, cc [ChainCodeLength]byte) (
	*MiniSecretKey, [ChainCodeLength]byte, error)

HardDeriveMiniSecretKey implements BIP-32 like "hard" derivation of a mini secret from a mini secret key

func (*MiniSecretKey) Public

func (s *MiniSecretKey) Public() *PublicKey

Public returns the PublicKey expanded from this MiniSecretKey using ExpandEd25519

type PublicKey

type PublicKey struct {
	// contains filtered or unexported fields
}

PublicKey is a field element

func NewPublicKey

func NewPublicKey(b [PublicKeySize]byte) (*PublicKey, error)

NewPublicKey creates a new public key from input bytes

func NewPublicKeyFromHex

func NewPublicKeyFromHex(s string) (*PublicKey, error)

NewPublicKeyFromHex returns a PublicKey from a hex-encoded string

func (*PublicKey) Decode

func (p *PublicKey) Decode(in [PublicKeySize]byte) error

Decode creates a PublicKey from the given input

func (*PublicKey) DeriveKey

func (pk *PublicKey) DeriveKey(t *merlin.Transcript, cc [ChainCodeLength]byte) (*ExtendedKey, error)

func (*PublicKey) DeriveScalarAndChaincode

func (pk *PublicKey) DeriveScalarAndChaincode(t *merlin.Transcript, cc [ChainCodeLength]byte) (*r255.Scalar, [ChainCodeLength]byte, error)

DeriveScalarAndChaincode derives a new scalar and chain code from an existing public key and chain code

func (*PublicKey) Encode

func (p *PublicKey) Encode() [PublicKeySize]byte

Encode returns the encoded point underlying the public key

func (*PublicKey) Verify

func (p *PublicKey) Verify(s *Signature, t *merlin.Transcript) (bool, error)

Verify verifies a schnorr signature with format: (R, s) where y is the public key 1. k = scalar(transcript.extract_bytes()) 2. R' = -ky + gs 3. return R' == R

Example
pub, err := NewPublicKeyFromHex("0x46ebddef8cd9bb167dc30878d7113b7e168e6f0646beffd77d69d39bad76b47a")
if err != nil {
	panic(err)
}

sig, err := NewSignatureFromHex("0x4e172314444b8f820bb54c22e95076f220ed25373e5c178234aa6c211d29271244b947e3ff3418ff6b45fd1df1140c8cbff69fc58ee6dc96df70936a2bb74b82")
if err != nil {
	panic(err)
}

msg := []byte("this is a message")
transcript := NewSigningContext(SigningContext, msg)
ok, err := pub.Verify(sig, transcript)
if err != nil {
	panic(err)
}

if !ok {
	fmt.Println("failed to verify signature")
	return
}

fmt.Println("verified signature")
Output:

verified signature

func (*PublicKey) VrfVerify

func (pk *PublicKey) VrfVerify(t *merlin.Transcript, out *VrfOutput, proof *VrfProof) (bool, error)

VrfVerify verifies that the proof and output created are valid given the public key and transcript.

type SecretKey

type SecretKey struct {
	// contains filtered or unexported fields
}

SecretKey consists of a secret scalar and a signing nonce

func NewSecretKey

func NewSecretKey(key [SecretKeySize]byte, nonce [32]byte) *SecretKey

NewSecretKey creates a new secret key from input bytes

func (*SecretKey) Decode

func (s *SecretKey) Decode(in [SecretKeySize]byte) error

Decode creates a SecretKey from the given input

func (*SecretKey) DeriveKey

func (sk *SecretKey) DeriveKey(t *merlin.Transcript, cc [ChainCodeLength]byte) (*ExtendedKey, error)

DeriveKey derives a new secret key and chain code from an existing secret key and chain code

func (*SecretKey) Encode

func (s *SecretKey) Encode() [SecretKeySize]byte

Encode returns the SecretKey's underlying bytes

func (*SecretKey) HardDeriveMiniSecretKey

func (sk *SecretKey) HardDeriveMiniSecretKey(i []byte, cc [ChainCodeLength]byte) (
	*MiniSecretKey, [ChainCodeLength]byte, error)

HardDeriveMiniSecretKey implements BIP-32 like "hard" derivation of a mini secret from a secret key

func (*SecretKey) Public

func (s *SecretKey) Public() (*PublicKey, error)

Public gets the public key corresponding to this SecretKey

func (*SecretKey) Sign

func (sk *SecretKey) Sign(t *merlin.Transcript) (*Signature, error)

Sign uses the schnorr signature algorithm to sign a message See the following for the transcript message https://github.com/w3f/schnorrkel/blob/db61369a6e77f8074eb3247f9040ccde55697f20/src/sign.rs#L158 Schnorr w/ transcript, secret key x: 1. choose random r from group 2. R = gr 3. k = scalar(transcript.extract_bytes()) 4. s = kx + r signature: (R, s) public key used for verification: y = g^x

Example
msg := []byte("hello")
signingCtx := []byte("example")

signingTranscript := NewSigningContext(signingCtx, msg)
verifyTranscript := NewSigningContext(signingCtx, msg)

priv, pub, err := GenerateKeypair()
if err != nil {
	panic(err)
}

sig, err := priv.Sign(signingTranscript)
if err != nil {
	panic(err)
}

ok, err := pub.Verify(sig, verifyTranscript)
if err != nil {
	panic(err)
}

if !ok {
	fmt.Println("failed to verify signature")
	return
}

fmt.Println("verified signature")
Output:

verified signature

func (*SecretKey) VrfSign

func (sk *SecretKey) VrfSign(t *merlin.Transcript) (*VrfInOut, *VrfProof, error)

VrfSign returns a vrf output and proof given a secret key and transcript.

Example
priv, pub, err := GenerateKeypair()
if err != nil {
	panic(err)
}

signTranscript := merlin.NewTranscript("vrf-test")
verifyTranscript := merlin.NewTranscript("vrf-test")

inout, proof, err := priv.VrfSign(signTranscript)
if err != nil {
	panic(err)
}

ok, err := pub.VrfVerify(verifyTranscript, inout.Output(), proof)
if err != nil {
	panic(err)
}

if !ok {
	fmt.Println("failed to verify VRF output and proof")
	return
}

fmt.Println("verified VRF output and proof")
Output:

verified VRF output and proof

type Signature

type Signature struct {
	// contains filtered or unexported fields
}

Signature holds a schnorrkel signature

Example
msg := []byte("hello")
signingCtx := []byte("example")

signingTranscript := NewSigningContext(signingCtx, msg)

sk, _, err := GenerateKeypair()
if err != nil {
	panic(err)
}

sig, err := sk.Sign(signingTranscript)
if err != nil {
	panic(err)
}

fmt.Printf("0x%x", sig.Encode())
Output:

func NewSignatureFromHex

func NewSignatureFromHex(s string) (*Signature, error)

NewSignatureFromHex returns a new Signature from the given hex-encoded string

func (*Signature) DecodeNotDistinguishedFromEd25519

func (s *Signature) DecodeNotDistinguishedFromEd25519(in [SignatureSize]byte) error

DecodeNotDistinguishedFromEd25519 sets a signature from bytes, not checking if the signature is explicitly marked as a schnorrkel signature

func (*Signature) Encode

func (s *Signature) Encode() [SignatureSize]byte

Encode turns a signature into a byte array see: https://github.com/w3f/schnorrkel/blob/db61369a6e77f8074eb3247f9040ccde55697f20/src/sign.rs#L77

type VrfInOut

type VrfInOut struct {
	// contains filtered or unexported fields
}

func (*VrfInOut) Encode

func (io *VrfInOut) Encode() []byte

EncodeOutput returns the 64-byte encoding of the input and output concatenated

func (*VrfInOut) MakeBytes

func (io *VrfInOut) MakeBytes(size int, context []byte) ([]byte, error)

MakeBytes returns raw bytes output from the VRF It returns a byte slice of the given size https://github.com/w3f/schnorrkel/blob/master/src/vrf.rs#L343

func (*VrfInOut) Output

func (io *VrfInOut) Output() *VrfOutput

Output returns a VrfOutput from a VrfInOut

type VrfOutput

type VrfOutput struct {
	// contains filtered or unexported fields
}

func NewOutput

func NewOutput(in [32]byte) (*VrfOutput, error)

NewOutput creates a new VRF output from a 64-byte element

func (*VrfOutput) AttachInput

func (out *VrfOutput) AttachInput(pub *PublicKey, t *merlin.Transcript) (*VrfInOut, error)

AttachInput returns a VrfInOut pair from an output https://github.com/w3f/schnorrkel/blob/master/src/vrf.rs#L249

func (*VrfOutput) Decode

func (out *VrfOutput) Decode(in [32]byte) error

Decode sets the VrfOutput to the decoded input

func (*VrfOutput) Encode

func (out *VrfOutput) Encode() [32]byte

Encode returns the 32-byte encoding of the output

type VrfProof

type VrfProof struct {
	// contains filtered or unexported fields
}

func (*VrfProof) Decode

func (p *VrfProof) Decode(in [64]byte) error

Decode sets the VrfProof to the decoded input

func (*VrfProof) Encode

func (p *VrfProof) Encode() [64]byte

Encode returns a 64-byte encoded VrfProof

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL