Skip to content

Commit

Permalink
add tests
Browse files Browse the repository at this point in the history
Signed-off-by: bytemare <[email protected]>
  • Loading branch information
bytemare committed Dec 25, 2023
1 parent 6bf944e commit 248432a
Show file tree
Hide file tree
Showing 16 changed files with 484 additions and 196 deletions.
2 changes: 1 addition & 1 deletion .github/licence-header.tmpl
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
SPDX-License-Identifier: MIT

Copyright (C) 2021 Daniel Bourdrez. All Rights Reserved.
Copyright (C) 2024 Daniel Bourdrez. All Rights Reserved.

This source code is licensed under the MIT license found in the
LICENSE file in the root directory of this source tree or at
Expand Down
2 changes: 1 addition & 1 deletion client.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: MIT
//
// Copyright (C) 2021 Daniel Bourdrez. All Rights Reserved.
// Copyright (C) 2024 Daniel Bourdrez. All Rights Reserved.
//
// This source code is licensed under the MIT license found in the
// LICENSE file in the root directory of this source tree or at
Expand Down
16 changes: 8 additions & 8 deletions client_state.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: MIT
//
// Copyright (C) 2021 Daniel Bourdrez. All Rights Reserved.
// Copyright (C) 2024 Daniel Bourdrez. All Rights Reserved.
//
// This source code is licensed under the MIT license found in the
// LICENSE file in the root directory of this source tree or at
Expand All @@ -16,13 +16,13 @@ import (

// State represents a client's state, allowing internal values to be exported and imported to resume a session.
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"`
Identifier Ciphersuite `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"`
}

// Export extracts the client's internal values that can be imported in another client for session resumption.
Expand Down
2 changes: 1 addition & 1 deletion doc.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: MIT
//
// Copyright (C) 2021 Daniel Bourdrez. All Rights Reserved.
// Copyright (C) 2024 Daniel Bourdrez. All Rights Reserved.
//
// This source code is licensed under the MIT license found in the
// LICENSE file in the root directory of this source tree or at
Expand Down
4 changes: 2 additions & 2 deletions errors.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: MIT
//
// Copyright (C) 2021 Daniel Bourdrez. All Rights Reserved.
// Copyright (C) 2024 Daniel Bourdrez. All Rights Reserved.
//
// This source code is licensed under the MIT license found in the
// LICENSE file in the root directory of this source tree or at
Expand All @@ -12,7 +12,7 @@ import "errors"

var (
errParamInvalidMode = errors.New("invalid OPRF mode")
errParamInvalidID = errors.New("invalid Identifier")
errParamInvalidID = errors.New("invalid Ciphersuite")
errParamFinalizeLen = errors.New("invalid number of elements in evaluation")
errParamInputEqualLen = errors.New("input lengths are not equal")
errParamNoPubKey = errors.New("missing public key")
Expand Down
2 changes: 1 addition & 1 deletion evaluation.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: MIT
//
// Copyright (C) 2021 Daniel Bourdrez. All Rights Reserved.
// Copyright (C) 2024 Daniel Bourdrez. All Rights Reserved.
//
// This source code is licensed under the MIT license found in the
// LICENSE file in the root directory of this source tree or at
Expand Down
2 changes: 1 addition & 1 deletion examples_test.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: MIT
//
// Copyright (C) 2021 Daniel Bourdrez. All Rights Reserved.
// Copyright (C) 2024 Daniel Bourdrez. All Rights Reserved.
//
// This source code is licensed under the MIT license found in the
// LICENSE file in the root directory of this source tree or at
Expand Down
148 changes: 76 additions & 72 deletions oprf.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: MIT
//
// Copyright (C) 2021 Daniel Bourdrez. All Rights Reserved.
// Copyright (C) 2024 Daniel Bourdrez. All Rights Reserved.
//
// This source code is licensed under the MIT license found in the
// LICENSE file in the root directory of this source tree or at
Expand Down Expand Up @@ -29,29 +29,32 @@ const (
POPRF
)

// Identifier of the OPRF compatible cipher suite to be used.
type Identifier string
// Ciphersuite of the OPRF compatible cipher suite to be used.
type Ciphersuite string

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

// Decaf448Sha512 is the OPRF cipher suite of the Decaf448 group and SHA-512.
// decaf448Sha512 Identifier = "decaf448-SHAKE256".
// decaf448Sha512 Ciphersuite = "decaf448-SHAKE256".

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

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

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

nbIDs = 4
// Secp256k1 is the OPRF cipher suite of the SECp256k1 group and SHA-256.
Secp256k1 Ciphersuite = "secp256k1-SHA256"

// version is a string explicitly stating the version name.
version = "OPRFV1"
nbIDs = 5

// Version is a string explicitly stating the Version name.
Version = "OPRFV1"

// deriveKeyPairDST is the DST prefix for the DeriveKeyPair function.
deriveKeyPairDST = "DeriveKeyPair"
Expand All @@ -64,54 +67,54 @@ const (
)

var (
groups = make(map[Identifier]group.Group, nbIDs)
hashes = make(map[Identifier]hash.Hashing, nbIDs)
groups = make(map[Ciphersuite]group.Group, nbIDs)
hashes = make(map[Ciphersuite]hash.Hashing, nbIDs)
)

func (i Identifier) new(mode Mode) *oprf {
func (c Ciphersuite) new(mode Mode) *oprf {
return &oprf{
hash: hashes[i].Get(),
contextString: contextString(mode, i),
id: i,
hash: hashes[c].Get(),
contextString: contextString(mode, c),
id: c,
mode: mode,
group: groups[i],
group: groups[c],
}
}

// Available returns whether the Identifier is registered and available for usage.
func (i Identifier) Available() bool {
// Available returns whether the Ciphersuite is registered and available for usage.
func (c Ciphersuite) Available() bool {
// Check for invalid identifiers
switch i {
case Ristretto255Sha512, P256Sha256, P384Sha384, P521Sha512:
switch c {
case Ristretto255Sha512, P256Sha256, P384Sha384, P521Sha512, Secp256k1:
break
default:
return false
}

// Check for unregistered groups and hashes
if _, ok := groups[i]; !ok {
if _, ok := groups[c]; !ok {
return false
}

if _, ok := hashes[i]; !ok {
if _, ok := hashes[c]; !ok {
return false
}

return true
}

// Group returns the group identifier used in the cipher suite.
func (i Identifier) Group() group.Group {
return groups[i]
func (c Ciphersuite) Group() group.Group {
return groups[c]
}

// Hash returns the hash function identifier used in the cipher suite.
func (i Identifier) Hash() hash.Hashing {
return hashes[i]
func (c Ciphersuite) Hash() hash.Hashing {
return hashes[c]
}

// FromGroup returns a (V)OPRF Identifier given a Group Identifier.
func FromGroup(g group.Group) (Identifier, error) {
// FromGroup returns a (V)OPRF Ciphersuite given a Group Ciphersuite.
func FromGroup(g group.Group) (Ciphersuite, error) {
for k, v := range groups {
if v == g {
return k, nil
Expand All @@ -122,24 +125,44 @@ func FromGroup(g group.Group) (Identifier, error) {
}

// KeyGen returns a fresh KeyPair for the given cipher suite.
func (i Identifier) KeyGen() *KeyPair {
sk := i.Group().NewScalar().Random()
pk := i.Group().Base().Multiply(sk)
func (c Ciphersuite) KeyGen() *KeyPair {
sk := c.Group().NewScalar().Random()
pk := c.Group().Base().Multiply(sk)

return &KeyPair{
ID: i,
ID: c,
PublicKey: pk.Encode(),
SecretKey: sk.Encode(),
}
}

// DeriveKeyPair deterministically generates a private and public key pair from input seed.
func (c Ciphersuite) DeriveKeyPair(mode Mode, seed, info []byte) (*group.Scalar, *group.Element) {
dst := concatenate([]byte(deriveKeyPairDST), contextString(mode, c))
deriveInput := concatenate(seed, lengthPrefixEncode(info))

var counter uint8
var s *group.Scalar

for s == nil || s.IsZero() {
if counter > 255 {
panic("impossible to generate non-zero scalar")
}

s = c.Group().HashToScalar(concatenate(deriveInput, []byte{counter}), dst)
counter++
}

return s, c.Group().Base().Multiply(s)
}

// Client returns a (P|V)OPRF client. For the OPRF mode, serverPublicKey should be nil, and non-nil otherwise.
func (i Identifier) Client(mode Mode, serverPublicKey []byte) (*Client, error) {
func (c Ciphersuite) Client(mode Mode, serverPublicKey []byte) (*Client, error) {
if mode != OPRF && mode != VOPRF && mode != POPRF {
return nil, errParamInvalidMode
}

client := i.client(mode)
client := c.client(mode)

if mode == VOPRF || mode == POPRF {
if serverPublicKey == nil {
Expand All @@ -156,25 +179,25 @@ func (i Identifier) Client(mode Mode, serverPublicKey []byte) (*Client, 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 (i Identifier) Server(mode Mode, privateKey []byte) (*Server, error) {
func (c Ciphersuite) Server(mode Mode, privateKey []byte) (*Server, error) {
if mode != OPRF && mode != VOPRF && mode != POPRF {
return nil, errParamInvalidMode
}

return i.server(mode, privateKey)
return c.server(mode, privateKey)
}

type oprf struct {
hash *hash.Hash
id Identifier
id Ciphersuite
contextString []byte
mode Mode
group group.Group
}

func contextString(mode Mode, id Identifier) []byte {
ctx := make([]byte, 0, len(version)+3+len(id.String()))
ctx = append(ctx, version...)
func contextString(mode Mode, id Ciphersuite) []byte {
ctx := make([]byte, 0, len(Version)+3+len(id.String()))
ctx = append(ctx, Version...)
ctx = append(ctx, "-"...)
ctx = append(ctx, byte(mode))
ctx = append(ctx, "-"...)
Expand All @@ -183,26 +206,6 @@ func contextString(mode Mode, id Identifier) []byte {
return ctx
}

// DeriveKeyPair deterministically generates a private and public key pair from input seed.
func (o *oprf) DeriveKeyPair(seed, info []byte) (*group.Scalar, *group.Element) {
dst := concatenate([]byte(deriveKeyPairDST), o.contextString)
deriveInput := concatenate(seed, lengthPrefixEncode(info))

var counter uint8
var s *group.Scalar

for s == nil || s.IsZero() {
if counter > 255 {
panic("impossible to generate non-zero scalar")
}

s = o.group.HashToScalar(concatenate(deriveInput, []byte{counter}), dst)
counter++
}

return s, o.group.Base().Multiply(s)
}

// HashToGroup maps the input data to an element of the group.
func (o *oprf) HashToGroup(data []byte) *group.Element {
return o.group.HashToGroup(data, dst(hash2groupDSTPrefix, o.contextString))
Expand All @@ -213,11 +216,11 @@ func (o *oprf) HashToScalar(data []byte) *group.Scalar {
return o.group.HashToScalar(data, dst(hash2scalarDSTPrefix, o.contextString))
}

func (i Identifier) client(mode Mode) *Client {
func (c Ciphersuite) client(mode Mode) *Client {
return &Client{
tweakedKey: nil,
serverPublicKey: nil,
oprf: i.new(mode),
oprf: c.new(mode),
input: nil,
blind: nil,
blindedElement: nil,
Expand All @@ -239,11 +242,11 @@ func (c *Client) setServerPublicKey(serverPublicKey []byte) error {
return nil
}

func (i Identifier) server(mode Mode, privateKey []byte) (*Server, error) {
func (c Ciphersuite) server(mode Mode, privateKey []byte) (*Server, error) {
s := &Server{
privateKey: nil,
publicKey: nil,
oprf: i.new(mode),
oprf: c.new(mode),
}

if privateKey == nil {
Expand Down Expand Up @@ -286,15 +289,15 @@ func (o *oprf) hashTranscript(input, info, unblinded []byte) []byte {
return h
}

// String implements the Stringer() interface for the Identifier.
func (i Identifier) String() string {
return string(i)
// String implements the Stringer() interface for the Ciphersuite.
func (c Ciphersuite) String() string {
return string(c)
}

func (i Identifier) register(g group.Group, h hash.Hashing) {
func (c Ciphersuite) register(g group.Group, h hash.Hashing) {
if g.Available() && h.Available() {
groups[i] = g
hashes[i] = h
groups[c] = g
hashes[c] = h
} else {
panic(fmt.Sprintf("OPRF dependencies not available - Group: %v, Hash: %v", g.Available(), h.Available()))
}
Expand All @@ -306,4 +309,5 @@ func init() {
P256Sha256.register(group.P256Sha256, hash.SHA256)
P384Sha384.register(group.P384Sha384, hash.SHA384)
P521Sha512.register(group.P521Sha512, hash.SHA512)
Secp256k1.register(group.Secp256k1, hash.SHA256)
}
6 changes: 3 additions & 3 deletions server.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: MIT
//
// Copyright (C) 2021 Daniel Bourdrez. All Rights Reserved.
// Copyright (C) 2024 Daniel Bourdrez. All Rights Reserved.
//
// This source code is licensed under the MIT license found in the
// LICENSE file in the root directory of this source tree or at
Expand Down Expand Up @@ -180,7 +180,7 @@ func (s *Server) PublicKey() []byte {
return s.publicKey.Encode()
}

// Identifier returns the cipher suite used in s' instance.
func (s *Server) Identifier() Identifier {
// Ciphersuite returns the cipher suite used in the server's instance.
func (s *Server) Ciphersuite() Ciphersuite {
return s.oprf.id
}
Loading

0 comments on commit 248432a

Please sign in to comment.