Change:
Since metadata can be bound to tokens via TokenChallenge.redemptioncontext, and the origin is ultimately the one who determines what metadata is supported, there's no more real need for the issuer_ to supply this metadata. So let's go with the simpler VOPRF protocol instead! Test vectors generated from the code here: URL cc NAME NAME NAME
LGTM

Discussion:
this might be provided by the redemption protocol in HTTP- Authentication. <del> Both Client and Issuer also share a common public string called "info". </del> Given this configuration and these inputs, the two messages exchanged in this protocol are described below.  This section uses notation described in OPRF, Section 4, including SerializeElement and

The Client first creates a context as follows: Here, 0x0004 is the two-octet identifier corresponding to the <del> OPRF(P-384, SHA-384) ciphersuite in OPRF.  SetupPOPRFClient is </del> <ins> OPRF(P-384, SHA-384) ciphersuite in OPRF.  SetupVOPRFClient is </ins> defined in OPRF, Section 3.2. The Client then creates an issuance request message for a random value "nonce" using the input challenge and Issuer key identifier as follows: <del> The Blind function is defined in OPRF, Section 3.3.3.  If the Blind </del> <ins> The Blind function is defined in OPRF, Section 3.3.2.  If the Blind </ins> function fails, the Client aborts the protocol.  Otherwise, the Client then creates a TokenRequest structured as follows:

"token_key_id" is the least significant byte of the "key_id". <del> "blinded_request" is the Ne-octet blinded message defined above, computed as "SerializeElement(blinded_msg)".  Ne is as defined in OPRF, Section 4. </del> <ins> "blinded_msg" is the Ne-octet blinded message defined above, computed as "SerializeElement(blinded_element)".  Ne is as defined in OPRF, Section 4. </ins> <del> The value "tweaked_key" is stored locally and used later as described in finalization.  The Client then generates an HTTP POST request to send to the Issuer, with the TokenRequest as the body.  The media type for this request is "message/token-request".  An example request is shown below. </del> <ins> The values "token_input" and "blinded_element" are stored locally and used later as described in finalization.  The Client then generates an HTTP POST request to send to the Issuer, with the TokenRequest as the body.  The media type for this request is "message/token- request".  An example request is shown below. </ins> Upon receipt of the request, the Issuer validates the following conditions:

The TokenRequest.token_key_id corresponds to a key ID of a Public Key owned by the issuer. <del> The TokenRequest.blinded_msg is of the correct size. </del> <ins> The TokenRequest.blinded_request is of the correct size. </ins> If any of these conditions is not met, the Issuer MUST return an HTTP <del> 400 error to the Client, which will forward the error to the client. </del> <ins> 400 error to the client. </ins> 5.2. <del> If the Issuer is willing to produce a token token to the Client, the Issuer completes the issuance flow by computing a blinded response as follows: </del> <ins> Upon receipt of a TokenRequest, the Issuer tries to deseralize TokenRequest.blinded_msg using DeserializeElement from Section 2.1 of OPRF, yielding "blinded_element".  If this fails, the Issuer MUST return an HTTP 400 error to the client.  Otherwise, if the Issuer is willing to produce a token token to the Client, the Issuer completes the issuance flow by computing a blinded response as follows: </ins> <del> SetupPOPRFServer is in OPRF, Section 3.2 and Evaluate is defined in OPRF, Section 3.3.3.  The Issuer then creates a TokenResponse </del> <ins> SetupVOPRFServer is in OPRF, Section 3.2 and Evaluate is defined in OPRF, Section 3.3.2.  The Issuer then creates a TokenResponse </ins> structured as follows: The structure fields are defined as follows: <del> "evaluate_response" is the Ne-octet evaluated messaged, computed as "SerializeElement(evaluated_msg)". </del> <ins> "evaluate_msg" is the Ne-octet evaluated messaged, computed as "SerializeElement(evaluate_element)". </ins> "evaluate_proof" is the (Ns+Ns)-octet serialized proof, which is a pair of Scalar values, computed as

Upon receipt, the Client handles the response and, if successful, deserializes the body values TokenResponse.evaluate_response and <del> TokenResponse.evaluate_proof.  If deserialization of any value fails, the Client aborts the protocol.  Otherwise, when deserialization yields "evaluated_msg" and "proof", the Client processes the response as follows: </del> <ins> TokenResponse.evaluate_proof, yielding "evaluated_element" and "proof".  If deserialization of either value fails, the Client aborts the protocol.  Otherwise, the Client processes the response as follows: </ins> <del> The Finalize function is defined in OPRF, Section 3.3.3.  If this </del> <ins> The Finalize function is defined in OPRF, Section 3.3.2.  If this </ins> succeeds, the Client then constructs a Token as follows: Otherwise, the Client aborts the protocol.