github.com/cloudflare/circl@v1.5.0/oprf/client.go (about)

     1  package oprf
     2  
     3  import (
     4  	"crypto/rand"
     5  
     6  	"github.com/cloudflare/circl/group"
     7  	"github.com/cloudflare/circl/zk/dleq"
     8  )
     9  
    10  type client struct{ params }
    11  
    12  type Client struct {
    13  	client
    14  }
    15  
    16  type VerifiableClient struct {
    17  	client
    18  	pkS *PublicKey
    19  }
    20  
    21  type PartialObliviousClient struct {
    22  	client
    23  	pkS *PublicKey
    24  }
    25  
    26  func (c client) Blind(inputs [][]byte) (*FinalizeData, *EvaluationRequest, error) {
    27  	if len(inputs) == 0 {
    28  		return nil, nil, ErrInvalidInput
    29  	}
    30  
    31  	blinds := make([]Blind, len(inputs))
    32  	for i := range inputs {
    33  		blinds[i] = c.params.group.RandomScalar(rand.Reader)
    34  	}
    35  
    36  	return c.blind(inputs, blinds)
    37  }
    38  
    39  func (c client) DeterministicBlind(inputs [][]byte, blinds []Blind) (*FinalizeData, *EvaluationRequest, error) {
    40  	if len(inputs) == 0 {
    41  		return nil, nil, ErrInvalidInput
    42  	}
    43  	if len(inputs) != len(blinds) {
    44  		return nil, nil, ErrInvalidInput
    45  	}
    46  
    47  	return c.blind(inputs, blinds)
    48  }
    49  
    50  func (c client) blind(inputs [][]byte, blinds []Blind) (*FinalizeData, *EvaluationRequest, error) {
    51  	blindedElements := make([]Blinded, len(inputs))
    52  	dst := c.params.getDST(hashToGroupDST)
    53  	for i := range inputs {
    54  		point := c.params.group.HashToElement(inputs[i], dst)
    55  		if point.IsIdentity() {
    56  			return nil, nil, ErrInvalidInput
    57  		}
    58  		blindedElements[i] = c.params.group.NewElement().Mul(point, blinds[i])
    59  	}
    60  
    61  	evalReq := &EvaluationRequest{blindedElements}
    62  	finData := &FinalizeData{inputs, blinds, evalReq}
    63  
    64  	return finData, evalReq, nil
    65  }
    66  
    67  func (c client) unblind(serUnblindeds [][]byte, blindeds []group.Element, blind []Blind) (err error) {
    68  	invBlind := c.params.group.NewScalar()
    69  	U := c.params.group.NewElement()
    70  
    71  	for i := range blindeds {
    72  		invBlind.Inv(blind[i])
    73  		U.Mul(blindeds[i], invBlind)
    74  		serUnblindeds[i], err = U.MarshalBinaryCompress()
    75  		if err != nil {
    76  			return err
    77  		}
    78  	}
    79  
    80  	return nil
    81  }
    82  
    83  func (c client) validate(f *FinalizeData, e *Evaluation) (err error) {
    84  	if l := len(f.blinds); len(f.evalReq.Elements) != l || len(e.Elements) != l {
    85  		err = ErrInvalidInput
    86  	}
    87  
    88  	return
    89  }
    90  
    91  func (c client) finalize(f *FinalizeData, e *Evaluation, info []byte) ([][]byte, error) {
    92  	unblindedElements := make([][]byte, len(f.blinds))
    93  	err := c.unblind(unblindedElements, e.Elements, f.blinds)
    94  	if err != nil {
    95  		return nil, err
    96  	}
    97  
    98  	h := c.params.hash.New()
    99  	outputs := make([][]byte, len(f.inputs))
   100  	for i := range f.inputs {
   101  		outputs[i] = c.params.finalizeHash(h, f.inputs[i], info, unblindedElements[i])
   102  	}
   103  
   104  	return outputs, nil
   105  }
   106  
   107  func (c Client) Finalize(f *FinalizeData, e *Evaluation) (outputs [][]byte, err error) {
   108  	if err = c.validate(f, e); err != nil {
   109  		return nil, err
   110  	}
   111  
   112  	return c.client.finalize(f, e, nil)
   113  }
   114  
   115  func (c VerifiableClient) Finalize(f *FinalizeData, e *Evaluation) (outputs [][]byte, err error) {
   116  	if err := c.validate(f, e); err != nil {
   117  		return nil, err
   118  	}
   119  
   120  	if !(dleq.Verifier{Params: c.getDLEQParams()}).VerifyBatch(
   121  		c.params.group.Generator(),
   122  		c.pkS.e,
   123  		f.evalReq.Elements,
   124  		e.Elements,
   125  		e.Proof,
   126  	) {
   127  		return nil, ErrInvalidProof
   128  	}
   129  
   130  	return c.client.finalize(f, e, nil)
   131  }
   132  
   133  func (c PartialObliviousClient) Finalize(f *FinalizeData, e *Evaluation, info []byte) (outputs [][]byte, err error) {
   134  	if err = c.validate(f, e); err != nil {
   135  		return nil, err
   136  	}
   137  
   138  	tweakedKey, err := c.pointFromInfo(info)
   139  	if err != nil {
   140  		return nil, err
   141  	}
   142  
   143  	if !(dleq.Verifier{Params: c.getDLEQParams()}).VerifyBatch(
   144  		c.params.group.Generator(),
   145  		tweakedKey,
   146  		e.Elements,
   147  		f.evalReq.Elements,
   148  		e.Proof,
   149  	) {
   150  		return nil, ErrInvalidProof
   151  	}
   152  
   153  	return c.client.finalize(f, e, info)
   154  }
   155  
   156  func (c PartialObliviousClient) pointFromInfo(info []byte) (group.Element, error) {
   157  	m, err := c.params.scalarFromInfo(info)
   158  	if err != nil {
   159  		return nil, err
   160  	}
   161  
   162  	T := c.params.group.NewElement().MulGen(m)
   163  	tweakedKey := c.params.group.NewElement().Add(T, c.pkS.e)
   164  	if tweakedKey.IsIdentity() {
   165  		return nil, ErrInvalidInfo
   166  	}
   167  
   168  	return tweakedKey, nil
   169  }