Skip to content

Commit

Permalink
circl: Update to 3977848c88c641772e447c63a0ec29c8f4085e58
Browse files Browse the repository at this point in the history
This change upgrades CIRCL's implementation of draft-irtf-cfrg-hpke-07
to 08. This breaks unit tests for ECH in crypto/tls, which currently
expects HPKE-07. It also modifies the implementation of OPRF.

Manually removed Ristretto code, which includes external dependencies
that break ./all.bash.
  • Loading branch information
cjpatton committed Mar 19, 2021
1 parent 33dbd35 commit 76b537c
Show file tree
Hide file tree
Showing 8 changed files with 111 additions and 86 deletions.
2 changes: 1 addition & 1 deletion src/circl/hpke/hpke.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ import (
"circl/kem"
)

const versionLabel = "HPKE-07"
const versionLabel = "HPKE-v1"

// Context defines the capabilities of an HPKE context.
type Context interface {
Expand Down

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions src/circl/hpke/vectors_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@ import (

func TestVectors(t *testing.T) {
// Test vectors from
// https://github.com/cfrg/draft-irtf-cfrg-hpke/blob/draft-irtf-cfrg-hpke-07/test-vectors.json
vectors := readFile(t, "testdata/vectors_v07.json")
// https://github.com/cfrg/draft-irtf-cfrg-hpke/blob/master/test-vectors.json
vectors := readFile(t, "testdata/vectors_v08_779d028.json")
for i, v := range vectors {
t.Run(fmt.Sprintf("v%v", i), v.verify)
}
Expand Down
72 changes: 45 additions & 27 deletions src/circl/oprf/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ package oprf
import (
"crypto/rand"
"errors"

"circl/group"
)

// Client is a representation of a OPRF client during protocol execution.
Expand All @@ -13,9 +15,22 @@ type Client struct {

// ClientRequest is a structure to encapsulate the output of a Request call.
type ClientRequest struct {
inputs [][]byte
blinds []Blind
BlindedElements []Blinded
inputs [][]byte
blinds []Blind
elements []group.Element
}

// BlindedElements returns the serialized blinded elements produced for the client request.
func (r ClientRequest) BlindedElements() [][]byte {
var err error
serializedBlinds := make([][]byte, len(r.elements))
for i := range r.elements {
serializedBlinds[i], err = r.elements[i].MarshalBinaryCompress()
if err != nil {
return nil
}
}
return serializedBlinds
}

// NewClient creates a client in base mode.
Expand Down Expand Up @@ -58,14 +73,11 @@ func (c *Client) Request(inputs [][]byte) (*ClientRequest, error) {
}

func (c *Client) blind(inputs [][]byte, blinds []Blind) (*ClientRequest, error) {
var err error
blindedElements := make([]Blinded, len(inputs))
blindedElements := make([]group.Element, len(inputs))
for i := range inputs {
p := c.suite.Group.HashToElement(inputs[i], c.suite.getDST(hashToGroupDST))
blindedElements[i], err = c.scalarMult(p, blinds[i])
if err != nil {
return nil, err
}
blindedElements[i] = c.suite.Group.NewElement()
blindedElements[i].Mul(p, blinds[i])
}
return &ClientRequest{inputs, blinds, blindedElements}, nil
}
Expand All @@ -75,17 +87,27 @@ func (c *Client) blind(inputs [][]byte, blinds []Blind) (*ClientRequest, error)
// to verify the proof in verifiable mode.
func (c *Client) Finalize(r *ClientRequest, e *Evaluation) ([][]byte, error) {
l := len(r.blinds)
if len(r.BlindedElements) != l || len(e.Elements) != l {
if len(r.elements) != l || len(e.Elements) != l {
return nil, errors.New("mismatch number of elements")
}

var err error
evals := make([]group.Element, len(e.Elements))
for i := range e.Elements {
evals[i] = c.suite.Group.NewElement()
err = evals[i].UnmarshalBinary(e.Elements[i])
if err != nil {
return nil, err
}
}

if c.Mode == VerifiableMode {
if !c.verifyProof(r.BlindedElements, e) {
if !c.verifyProof(r.elements, evals, *e.Proof) {
return nil, errors.New("invalid proof")
}
}

unblindedElements, err := c.unblind(e.Elements, r.blinds)
unblindedElements, err := c.unblind(evals, r.blinds)
if err != nil {
return nil, err
}
Expand All @@ -96,37 +118,37 @@ func (c *Client) Finalize(r *ClientRequest, e *Evaluation) ([][]byte, error) {
return outputs, nil
}

func (c *Client) verifyProof(blinds []Blinded, e *Evaluation) bool {
func (c *Client) verifyProof(blinds []group.Element, elements []group.Element, proof Proof) bool {
pkSm, err := c.pkS.Serialize()
if err != nil {
return false
}
a0, a1, err := c.computeComposites(pkSm, blinds, e.Elements, nil)

M, Z, err := c.computeComposites(nil, c.pkS.e, blinds, elements)
if err != nil {
return false
}
M := c.suite.Group.NewElement()
err = M.UnmarshalBinary(a0)

a0, err := M.MarshalBinaryCompress()
if err != nil {
return false
}
Z := c.suite.Group.NewElement()
err = Z.UnmarshalBinary(a1)
a1, err := Z.MarshalBinaryCompress()
if err != nil {
return false
}

sG := c.suite.Group.NewElement()
ss := c.suite.Group.NewScalar()
err = ss.UnmarshalBinary(e.Proof.S)
err = ss.UnmarshalBinary(proof.S)
if err != nil {
return false
}
sG.MulGen(ss)

cP := c.suite.Group.NewElement()
cc := c.suite.Group.NewScalar()
err = cc.UnmarshalBinary(e.Proof.C)
err = cc.UnmarshalBinary(proof.C)
if err != nil {
return false
}
Expand All @@ -151,17 +173,13 @@ func (c *Client) verifyProof(blinds []Blinded, e *Evaluation) bool {
return gotC.IsEqual(cc)
}

func (c *Client) unblind(e []SerializedElement, blinds []Blind) ([][]byte, error) {
func (c *Client) unblind(e []group.Element, blinds []Blind) ([][]byte, error) {
var err error
unblindedElements := make([][]byte, len(e))
p := c.Group.NewElement()
invBlind := c.Group.NewScalar()
for i := range e {
err := p.UnmarshalBinary(e[i])
if err != nil {
return nil, err
}
invBlind.Inv(blinds[i])
unblindedElements[i], err = c.scalarMult(p, invBlind)
unblindedElements[i], err = c.scalarMult(e[i], invBlind)
if err != nil {
return nil, err
}
Expand Down
73 changes: 35 additions & 38 deletions src/circl/oprf/oprf.go
Original file line number Diff line number Diff line change
Expand Up @@ -151,18 +151,22 @@ func mustWrite(h io.Writer, bytes []byte) {
}

func (s *suite) computeComposites(
pkSm []byte,
b []Blinded,
eval []SerializedElement,
skS group.Scalar,
) ([]byte, []byte, error) {
lenBuf := []byte{0, 0}
k group.Scalar,
B group.Element,
Cs []group.Element,
Ds []group.Element,
) (group.Element, group.Element, error) {
Bm, err := B.MarshalBinaryCompress()
if err != nil {
return nil, nil, err
}

lenBuf := []byte{0, 0}
H := s.New()

binary.BigEndian.PutUint16(lenBuf, uint16(len(pkSm)))
binary.BigEndian.PutUint16(lenBuf, uint16(len(Bm)))
mustWrite(H, lenBuf)
mustWrite(H, pkSm)
mustWrite(H, Bm)

dst := s.getDST(seedDST)
binary.BigEndian.PutUint16(lenBuf, uint16(len(dst)))
Expand All @@ -173,60 +177,53 @@ func (s *suite) computeComposites(

M := s.Group.Identity()
Z := s.Group.Identity()
Mi := s.Group.NewElement()
Zi := s.Group.NewElement()
h2sDST := s.getDST(hashToScalarDST)
for i := range b {
for i := range Cs {
h2Input := []byte{}

Ci, err := Cs[i].MarshalBinaryCompress()
if err != nil {
return nil, nil, err
}

Di, err := Ds[i].MarshalBinaryCompress()
if err != nil {
return nil, nil, err
}

binary.BigEndian.PutUint16(lenBuf, uint16(len(seed)))
h2Input = append(append(h2Input, lenBuf...), seed...)

binary.BigEndian.PutUint16(lenBuf, uint16(i))
h2Input = append(h2Input, lenBuf...)

binary.BigEndian.PutUint16(lenBuf, uint16(len(b[i])))
h2Input = append(append(h2Input, lenBuf...), b[i]...)
binary.BigEndian.PutUint16(lenBuf, uint16(len(Ci)))
h2Input = append(append(h2Input, lenBuf...), Ci...)

binary.BigEndian.PutUint16(lenBuf, uint16(len(eval[i])))
h2Input = append(append(h2Input, lenBuf...), eval[i]...)
binary.BigEndian.PutUint16(lenBuf, uint16(len(Di)))
h2Input = append(append(h2Input, lenBuf...), Di...)

dst := s.getDST(compositeDST)
binary.BigEndian.PutUint16(lenBuf, uint16(len(dst)))
h2Input = append(append(h2Input, lenBuf...), dst...)

di := s.Group.HashToScalar(h2Input, h2sDST)
err := Mi.UnmarshalBinary(b[i])
if err != nil {
return nil, nil, err
}
Mi.Mul(Mi, di)
Mi := s.Group.NewElement()
Mi.Mul(Cs[i], di)
M.Add(M, Mi)

if skS == nil {
err = Zi.UnmarshalBinary(eval[i])
if err != nil {
return nil, nil, err
}
Zi.Mul(Zi, di)
if k == nil {
Zi := s.Group.NewElement()
Zi.Mul(Ds[i], di)
Z.Add(Z, Zi)
}
}

if skS != nil {
Z.Mul(M, skS)
}

serM, err := M.MarshalBinaryCompress()
if err != nil {
return nil, nil, err
}
serZ, err := Z.MarshalBinaryCompress()
if err != nil {
return nil, nil, err
if k != nil {
Z.Mul(M, k)
}

return serM, serZ, nil
return M, Z, nil
}

func (s *suite) doChallenge(a [5][]byte) group.Scalar {
Expand Down
2 changes: 1 addition & 1 deletion src/circl/oprf/oprf_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ func testAPI(t *testing.T, suite oprf.SuiteID, mode oprf.Mode) {
t.Fatal("invalid blinding of client: " + err.Error())
}

eval, err := server.Evaluate(cr.BlindedElements)
eval, err := server.Evaluate(cr.BlindedElements())
if err != nil {
t.Fatal("invalid evaluation of server: " + err.Error())
}
Expand Down
38 changes: 24 additions & 14 deletions src/circl/oprf/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ func newServer(id SuiteID, m Mode, skS *PrivateKey) (*Server, error) {
return &Server{*suite, *skS}, nil
}

// GetPublicKey returns the public key corresponding to the server.
func (s *Server) GetPublicKey() *PublicKey { return s.privateKey.Public() }

// Evaluate evaluates a set of blinded inputs from the client.
Expand All @@ -57,29 +58,36 @@ func (s *Server) evaluateWithProofScalar(blindedElements []Blinded, proofScalar
}

var err error
eval := make([]SerializedElement, l)
p := s.suite.NewElement()
input := make([]group.Element, l)
eval := make([]group.Element, l)
out := make([]SerializedElement, l)

for i := range blindedElements {
err = p.UnmarshalBinary(blindedElements[i])
input[i] = s.suite.NewElement()
err = input[i].UnmarshalBinary(blindedElements[i])
if err != nil {
return nil, err
}
eval[i], err = s.scalarMult(p, s.privateKey.k)

eval[i] = s.Group.NewElement()
eval[i].Mul(input[i], s.privateKey.k)

e, err := eval[i].MarshalBinaryCompress()
if err != nil {
return nil, err
}
out[i] = e
}

var proof *Proof
if s.Mode == VerifiableMode {
proof, err = s.generateProofWithRandomScalar(blindedElements, eval, proofScalar)
proof, err = s.generateProofWithRandomScalar(s.privateKey.k, s.Generator(), s.privateKey.Public().e, input, eval, proofScalar)
if err != nil {
return nil, err
}
}

return &Evaluation{eval, proof}, nil
return &Evaluation{out, proof}, nil
}

// FullEvaluate performs a full OPRF protocol at server-side.
Expand All @@ -104,26 +112,28 @@ func (s *Server) VerifyFinalize(input, expectedOutput []byte) bool {
return subtle.ConstantTimeCompare(gotOutput, expectedOutput) == 1
}

func (s *Server) generateProofWithRandomScalar(b []Blinded, eval []SerializedElement, rr group.Scalar) (*Proof, error) {
pkS := s.privateKey.Public()
pkSm, err := pkS.Serialize()
func (s *Server) generateProofWithRandomScalar(k group.Scalar, A, B group.Element, Cs []group.Element, Ds []group.Element, rr group.Scalar) (*Proof, error) {
M, Z, err := s.computeComposites(k, B, Cs, Ds)
if err != nil {
return nil, err
}

a0, a1, err := s.computeComposites(pkSm, b, eval, s.privateKey.k)
Bm, err := B.MarshalBinaryCompress()
if err != nil {
return nil, err
}

M := s.Group.NewElement()
err = M.UnmarshalBinary(a0)
a0, err := M.MarshalBinaryCompress()
if err != nil {
return nil, err
}
a1, err := Z.MarshalBinaryCompress()
if err != nil {
return nil, err
}

a2e := s.Group.NewElement()
a2e.MulGen(rr)
a2e.Mul(A, rr)
a2, err := a2e.MarshalBinaryCompress()
if err != nil {
return nil, err
Expand All @@ -136,7 +146,7 @@ func (s *Server) generateProofWithRandomScalar(b []Blinded, eval []SerializedEle
return nil, err
}

cc := s.doChallenge([5][]byte{pkSm, a0, a1, a2, a3})
cc := s.doChallenge([5][]byte{Bm, a0, a1, a2, a3})
ss := s.suite.Group.NewScalar()
ss.Mul(cc, s.privateKey.k)
ss.Sub(rr, ss)
Expand Down
Loading

0 comments on commit 76b537c

Please sign in to comment.