voprf

package module
v0.21.0 Latest Latest
Warning

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

Go to latest
Published: Mar 20, 2023 License: MIT Imports: 6 Imported by: 0

README

(V)OPRF : (Verifiable) Oblivious Pseudorandom Functions

VOPRF Go Reference codecov

Package voprf provides abstracted access to Oblivious Pseudorandom Functions (OPRF) over elliptic curves.

This implementation supports the OPRF, VOPRF, and POPRF protocols as specified in the latest internet draft.

Versioning

SemVer is used for versioning. For the versions available, see the tags on this repository.

Minor v0.x versions match the corresponding CFRG draft version, the master branch implements the latest changes of the draft development.

Contributing

Please read CONTRIBUTING.md for details on the code of conduct, and the process for submitting pull requests.

License

This project is licensed under the MIT License - see the LICENSE file for details.

Documentation

Overview

Package voprf provides abstracted access to Oblivious Pseudorandom Functions (OPRF) and VOPRF Oblivious Pseudorandom Functions (VOPRF) using Elliptic Curves (EC(V)OPRF).

This work in progress implements https://tools.ietf.org/html/draft-irtf-cfrg-voprf

Integrations can use either base or verifiable mode with additive or multiplicative operations.

Example (BaseServer)
package main

import (
	"encoding/hex"

	"github.com/bytemare/voprf"
)

func main() {
	// We suppose the client sends this blinded element.
	blinded, _ := hex.DecodeString("7eaf3d7cbe43d54637274342ce53578b2aba836f297f4f07997a6e1dced1c058")

	// Set up a new server. A private key is automatically created if none is given.
	server, err := voprf.Ristretto255Sha512.Server(voprf.OPRF, nil)
	if err != nil {
		panic(err)
	}

	// The server evaluates the blinded input.
	evaluation, err := server.Evaluate(blinded, nil)
	if err != nil {
		panic(err)
	}

	// The server encodes the evaluation, and sends it to the client.
	_ = evaluation.Serialize()
}
Output:

Example (VerifiableClient)
package main

import (
	"encoding/hex"

	"github.com/bytemare/voprf"
)

func exchangeWithServer(blinded []byte, verifiable bool) []byte {
	var server *voprf.Server
	var err error
	privateKey, _ := hex.DecodeString("8132542d5ed08594e7522b5eac6bee38bab5868996c25a3fd2a7739be1856b04")

	if verifiable {
		server, err = voprf.Ristretto255Sha512.Server(voprf.VOPRF, privateKey)
		if err != nil {
			panic(err)
		}
	} else {
		server, err = voprf.Ristretto255Sha512.Server(voprf.OPRF, privateKey)
		if err != nil {
			panic(err)
		}
	}

	evaluation, err := server.Evaluate(blinded, nil)
	if err != nil {
		panic(err)
	}

	ev := evaluation.Serialize()

	return ev
}

func main() {
	ciphersuite := voprf.Ristretto255Sha512
	input := []byte("input")
	serverPubKey, _ := hex.DecodeString("066c39841db2ca3c2e83e251e71b619013674149692ca2ab41d1b33a1a4fff38")

	// Instantiate a new client with the preprocessed values.
	client, err := ciphersuite.Client(voprf.VOPRF, serverPubKey)
	if err != nil {
		panic(err)
	}

	// The client blinds the initial input, and sends this to the server.
	blinded := client.Blind(input, nil)

	// Exchange with the server is not covered here. The following call is to mock an exchange with a server.
	ev := exchangeWithServer(blinded, true)

	// The client needs to decode the evaluation to finalize the process.
	eval := new(voprf.Evaluation)
	if err := eval.Deserialize(ev); err != nil {
		panic(err)
	}

	// The client finalizes the protocol execution by reverting the blinding and hashing the protocol transcript.
	// If proof verification fails, an error is returned.
	output, err := client.Finalize(eval, nil)
	if output == nil || err != nil {
		panic(err)
	}
}
Output:

Example (VerifiableServer)
package main

import (
	"encoding/hex"

	"github.com/bytemare/voprf"
)

func main() {
	privateKey, _ := hex.DecodeString("8132542d5ed08594e7522b5eac6bee38bab5868996c25a3fd2a7739be1856b04")

	// We suppose the client sends this blinded element.
	blinded, _ := hex.DecodeString("7eaf3d7cbe43d54637274342ce53578b2aba836f297f4f07997a6e1dced1c058")

	// Set up a new server.
	server, err := voprf.Ristretto255Sha512.Server(voprf.VOPRF, privateKey)
	if err != nil {
		panic(err)
	}

	// The server evaluates the blinded input. Proofs are embedded in the evaluation.
	evaluation, err := server.Evaluate(blinded, nil)
	if err != nil {
		panic(err)
	}

	// The server encodes the evaluation, and sends it to the client.
	_ = evaluation.Serialize()
}
Output:

Index

Examples

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type Client

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

Client represents the Client/Verifier party in a (V)OPRF protocol session, and exposes relevant functions for its execution.

Example
package main

import (
	"encoding/hex"

	"github.com/bytemare/voprf"
)

func exchangeWithServer(blinded []byte, verifiable bool) []byte {
	var server *voprf.Server
	var err error
	privateKey, _ := hex.DecodeString("8132542d5ed08594e7522b5eac6bee38bab5868996c25a3fd2a7739be1856b04")

	if verifiable {
		server, err = voprf.Ristretto255Sha512.Server(voprf.VOPRF, privateKey)
		if err != nil {
			panic(err)
		}
	} else {
		server, err = voprf.Ristretto255Sha512.Server(voprf.OPRF, privateKey)
		if err != nil {
			panic(err)
		}
	}

	evaluation, err := server.Evaluate(blinded, nil)
	if err != nil {
		panic(err)
	}

	ev := evaluation.Serialize()

	return ev
}

func main() {
	input := []byte("input")

	// Set up a new client. Not indicating a server public key indicates we don't use the verifiable mode.
	client, err := voprf.Ristretto255Sha512.Client(voprf.OPRF, nil)
	if err != nil {
		panic(err)
	}

	// The client blinds the initial input, and sends this to the server.
	blinded := client.Blind(input, nil)

	// Exchange with the server is not covered here. The following call is to mock an exchange with a server.
	ev := exchangeWithServer(blinded, false)

	// The client needs to decode the evaluation to finalize the process.
	eval := new(voprf.Evaluation)
	if err := eval.Deserialize(ev); err != nil {
		panic(err)
	}

	// The client finalizes the protocol execution by reverting the blinding and hashing the protocol transcript.
	output, err := client.Finalize(eval, nil)
	if output == nil || err != nil {
		panic(err)
	}
}
Output:

func (*Client) Blind

func (c *Client) Blind(input, info []byte) []byte

Blind blinds, or masks, the input with a preset or new random blinding element.

func (*Client) BlindBatch

func (c *Client) BlindBatch(input [][]byte, info []byte) (blinds, blindedElements [][]byte, err error)

BlindBatch allows blinding of batched input. If internal blinds are not set, new ones are created. In either case, the blinds are returned, and can safely be ignored if not needed externally. Subsequent calls on unblinding functions will automatically use the internal blinds, unless specified otherwise through unblindBatchWithBlinds().

func (*Client) BlindBatchWithBlinds

func (c *Client) BlindBatchWithBlinds(blinds, input [][]byte, info []byte) ([][]byte, error)

BlindBatchWithBlinds enables blinding batches while specifying which blinds to use.

func (Client) DeriveKeyPair

func (o Client) DeriveKeyPair(seed, info []byte) (*group.Scalar, *group.Element)

DeriveKeyPair deterministically generates a private and public key pair from input seed.

func (*Client) Export

func (c *Client) Export() *State

Export extracts the client's internal values that can be imported in another client for session resumption.

func (*Client) Finalize

func (c *Client) Finalize(e *Evaluation, info []byte) ([]byte, error)

Finalize finalizes the protocol execution by verifying the proof if necessary, unblinding the evaluated element, and hashing the transcript.

func (*Client) FinalizeBatch

func (c *Client) FinalizeBatch(e *Evaluation, info []byte) ([][]byte, error)

FinalizeBatch finalizes the protocol execution by verifying the proof if necessary, unblinding the evaluated elements, and hashing the transcript.

func (Client) HashToGroup

func (o Client) HashToGroup(data []byte) *group.Element

HashToGroup maps the input data to an element of the group.

func (Client) HashToScalar

func (o Client) HashToScalar(data []byte) *group.Scalar

HashToScalar maps the input data to a scalar.

func (*Client) SetBlinds

func (c *Client) SetBlinds(blind []*group.Scalar)

SetBlinds sets the inner blinds to those given as input.

type Evaluation

type Evaluation struct {
	// Elements represents the unique serialization of an Elements
	Elements [][]byte `json:"e"`

	// Proofs
	ProofC []byte `json:"c,omitempty"`
	ProofS []byte `json:"s,omitempty"`
}

Evaluation holds the serialized evaluated elements and serialized proof.

func (*Evaluation) Deserialize

func (e *Evaluation) Deserialize(input []byte) error

Deserialize decodes the input into the Evaluation.

func (*Evaluation) Serialize

func (e *Evaluation) Serialize() []byte

Serialize returns a compact encoding of the Evaluation.

type Identifier

type Identifier string

Identifier of the OPRF compatible cipher suite to be used.

const (
	// Ristretto255Sha512 is the OPRF cipher suite of the Ristretto255 group and SHA-512.
	Ristretto255Sha512 Identifier = "ristretto255-SHA512"

	// P256Sha256 is the OPRF cipher suite of the NIST P-256 group and SHA-256.
	P256Sha256 Identifier = "P256-SHA256"

	// P384Sha384 is the OPRF cipher suite of the NIST P-384 group and SHA-384.
	P384Sha384 Identifier = "P384-SHA384"

	// P521Sha512 is the OPRF cipher suite of the NIST P-512 group and SHA-512.
	P521Sha512 Identifier = "P521-SHA512"
)

func FromGroup

func FromGroup(g group.Group) (Identifier, error)

FromGroup returns a (V)OPRF Identifier given a Group Identifier.

func (Identifier) Available

func (i Identifier) Available() bool

Available returns whether the Identifier is registered and available for usage.

func (Identifier) Client

func (i Identifier) Client(mode Mode, serverPublicKey []byte) (*Client, error)

Client returns a (P|V)OPRF client. For the OPRF mode, serverPublicKey should be nil, and non-nil otherwise.

func (Identifier) Group

func (i Identifier) Group() group.Group

Group returns the group identifier used in the cipher suite.

func (Identifier) Hash

func (i Identifier) Hash() hash.Hashing

Hash returns the hash function identifier used in the cipher suite.

func (Identifier) KeyGen

func (i Identifier) KeyGen() *KeyPair

KeyGen returns a fresh KeyPair for the given cipher suite.

func (Identifier) Server

func (i Identifier) Server(mode Mode, privateKey []byte) (*Server, error)

Server returns a (P|V)OPRF server instantiated with the given encoded private key. If privateKey is nil, a new private/public key pair is created.

func (Identifier) String

func (i Identifier) String() string

String implements the Stringer() interface for the Identifier.

type KeyPair

type KeyPair struct {
	ID        Identifier
	PublicKey []byte
	SecretKey []byte
}

KeyPair assembles a VOPRF key pair. The SecretKey can be used as the evaluation key for the group identified by ID.

type Mode

type Mode byte

Mode distinguishes between the OPRF base mode and the VOPRF mode.

const (
	// OPRF identifies the base mode.
	OPRF Mode = iota

	// VOPRF identifies the verifiable mode.
	VOPRF

	// POPRF identifies the partially-oblivious mode.
	POPRF
)

type Server

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

Server holds the (V)OPRF prover data.

func (Server) DeriveKeyPair

func (o Server) DeriveKeyPair(seed, info []byte) (*group.Scalar, *group.Element)

DeriveKeyPair deterministically generates a private and public key pair from input seed.

func (*Server) Evaluate

func (s *Server) Evaluate(blindedElement, info []byte) (*Evaluation, error)

Evaluate the input with the private key.

func (*Server) EvaluateBatch

func (s *Server) EvaluateBatch(blindedElements [][]byte, info []byte) (*Evaluation, error)

EvaluateBatch evaluates the input batch of blindedElements and returns a pointer to the Evaluation. If the server was set to be un VOPRF mode, the proof will be included in the Evaluation.

func (*Server) FullEvaluate

func (s *Server) FullEvaluate(input, info []byte) ([]byte, error)

FullEvaluate reproduces the full PRF but without the blinding operations, using the client's input. This should output the same digest as the client's Finalize() function.

func (Server) HashToGroup

func (o Server) HashToGroup(data []byte) *group.Element

HashToGroup maps the input data to an element of the group.

func (Server) HashToScalar

func (o Server) HashToScalar(data []byte) *group.Scalar

HashToScalar maps the input data to a scalar.

func (*Server) Identifier

func (s *Server) Identifier() Identifier

Identifier returns the cipher suite used in s' instance.

func (*Server) KeyGen

func (s *Server) KeyGen()

KeyGen generates and sets a new private/public key pair.

func (*Server) PrivateKey

func (s *Server) PrivateKey() []byte

PrivateKey returns the server's serialized private key.

func (*Server) PublicKey

func (s *Server) PublicKey() []byte

PublicKey returns the server's serialized public key.

func (*Server) SetProofNonce

func (s *Server) SetProofNonce(r []byte)

SetProofNonce sets the nonce used in the proof generation in the VOPRF and POPRF modes.

func (*Server) VerifyFinalize

func (s *Server) VerifyFinalize(input, info, output []byte) bool

VerifyFinalize takes the client input (the un-blinded element) and the client's finalize() output, and returns whether it can match the client's output.

func (*Server) VerifyFinalizeBatch

func (s *Server) VerifyFinalizeBatch(input, output [][]byte, info []byte) bool

VerifyFinalizeBatch takes the batch of client input (the un-blinded elements) and the client's finalize() outputs, and returns whether it can match the client's outputs.

type State

type State struct {
	Identifier      Identifier `json:"s"`
	TweakedKey      []byte     `json:"t,omitempty"`
	ServerPublicKey []byte     `json:"p,omitempty"`
	Input           [][]byte   `json:"i"`
	Blind           [][]byte   `json:"r"`
	Blinded         [][]byte   `json:"d"`
	Mode            Mode       `json:"m"`
}

State represents a client's state, allowing internal values to be exported and imported to resume a session.

func (*State) RecoverClient

func (s *State) RecoverClient() (*Client, error)

RecoverClient returns a Client recovered form the state, from which a session can be resumed.

Jump to

Keyboard shortcuts

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