|
|
@@ -0,0 +1,148 @@
|
|
|
+Open Invitation Credential
|
|
|
+
|
|
|
+`use super::super::cred;`
|
|
|
+`use super::super::cmz::{IssueType, ShowType};`
|
|
|
+
|
|
|
+```
|
|
|
+#[serde_as]
|
|
|
+#[derive(Serialize, Deserialize)]
|
|
|
+pub struct Request {
|
|
|
+ #[serde_as(as = "[_; OPENINV_LENGTH]")]
|
|
|
+ invite: [u8; OPENINV_LENGTH],
|
|
|
+ // Lox credential with each attribute annotated with the IssueType
|
|
|
+ issue_cred: AnnotatedIssueCredential,
|
|
|
+ // Statement relating the annotated_credentials, in this case: the
|
|
|
+ // commitment to the Lox ID
|
|
|
+ open_issue_statement: Statement,
|
|
|
+}
|
|
|
+```
|
|
|
+
|
|
|
+The client state for this protocol
|
|
|
+```
|
|
|
+#[derive(Debug, Serialize, Deserialize)]
|
|
|
+pub struct State {
|
|
|
+ // Randomized attributes could be stored in annotated credential as
|
|
|
+ // part of the state, that can be used to process the Issued credential
|
|
|
+ // later
|
|
|
+ annotated_cred: AnnotatedIssueCredential,
|
|
|
+ s: Scalar,
|
|
|
+}
|
|
|
+```
|
|
|
+
|
|
|
+The response message for this protocol: (This was copied from the exisiting
|
|
|
+protocol and still needs to be updated)
|
|
|
+
|
|
|
+```
|
|
|
+#[derive(Serialize, Deserialize)]
|
|
|
+pub struct Response {
|
|
|
+ P: RistrettoPoint,
|
|
|
+ BlindLoxQ: RistrettoPoint,
|
|
|
+ server_id: Scalar,
|
|
|
+ bucket: Scalar,
|
|
|
+ level_since: Scalar,
|
|
|
+ piBlindIssue: CompactProof,
|
|
|
+ bridge_line: BridgeLine,
|
|
|
+}
|
|
|
+```
|
|
|
+
|
|
|
+Client Request:
|
|
|
+```
|
|
|
+pub fn request(invite: &[u8; OPENINV_LENGTH], lox_pub: &IssuerPubKey) -> (Request, State) {
|
|
|
+
|
|
|
+// There is no call to "show" for open invitation but the open invite must be verified
|
|
|
+
|
|
|
+let open_invite_cred_directive = HashMap::from([
|
|
|
+ ("id", Scalar::random()),
|
|
|
+ ("bucket", Scalar::ZERO), // Placeholder value
|
|
|
+ ("trust_level", Scalar::ZERO), // Placeholder value
|
|
|
+ ("level_since", Scalar::ZERO), // Placeholder value
|
|
|
+ ("invites_remaining", Scalar::ZERO), // Placeholder value
|
|
|
+ ("blockages", Scalar::ZERO), // Placeholder value
|
|
|
+ ]);
|
|
|
+// Create new Lox credential with mapped fields(String) -> Scalar
|
|
|
+let open_invite_cred = cred.Lox.annotate(open_invite_cred_directive, lox_pub);
|
|
|
+
|
|
|
+// Create the open invitation issue directive
|
|
|
+let open_invite_issue_directive = HashMap::from([
|
|
|
+ ("id", IssueType::Joint),
|
|
|
+ ("bucket", IssueType::Select),
|
|
|
+ ("trust_level", IssueType::Select), // Constant: 0
|
|
|
+ ("level_since", IssueType::Select), // Constant: 0
|
|
|
+ ("invites_remaining", IssueType::Select), // Constant: 0
|
|
|
+ ("blockages", IssueType::Select), // Constant: 0
|
|
|
+ ]);
|
|
|
+
|
|
|
+// Annotate the credential with the IssueType for each attribute, returning the
|
|
|
+// AnnotatedIssueCredential
|
|
|
+let issue_cred = open_invite_cred.issue_annotated_request(open_invite_issue_directive);
|
|
|
+
|
|
|
+// Open Invite doesn't have a statement comparing issue and show annotated
|
|
|
+// credentials, but needs to commit to the joint issue lox id
|
|
|
+let (state, open_invite_issue_statement) =
|
|
|
+open_invite_cred.issue_request(vec![issue_cred], Statement::Empty);
|
|
|
+(
|
|
|
+ Request {
|
|
|
+ invite: *invite,
|
|
|
+ issue_cred:
|
|
|
+ open_invite_issue_statement
|
|
|
+ },
|
|
|
+ state
|
|
|
+ )
|
|
|
+
|
|
|
+}
|
|
|
+```
|
|
|
+
|
|
|
+
|
|
|
+Server Response:
|
|
|
+Receive an open invitation issued by the BridgeDb and if it is
|
|
|
+valid and fresh, issue a Lox credential at trust level 0.
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+```
|
|
|
+impl BridgeAuth {
|
|
|
+
|
|
|
+pub fn issue_response(&self, Option<Vec<AnnotatedShowCredential>>, Vec<AnnotatedIssueCredential>, Statement) -> Statement, Credential;
|
|
|
+
|
|
|
+pub fn handle_open_invite(&mut self, req: Request) -> Result<Response, ProofError> {
|
|
|
+
|
|
|
+ // verify Invite from request: check signature and age are correct
|
|
|
+
|
|
|
+ // Create new Lox credential with mapped fields(String) -> Scalar
|
|
|
+ // Including both the private and public keys
|
|
|
+ let issue_statement, open_invite_issuecred = self.issue_response(None, req.issue_cred,
|
|
|
+ req.open_invite_issue_statement);
|
|
|
+
|
|
|
+ Response {
|
|
|
+ // This still needs work
|
|
|
+ // Yet another annotated credential with all of the attributes
|
|
|
+ // from the server + P and blinded Q
|
|
|
+ // ZKProof
|
|
|
+ // BridgeLine
|
|
|
+ open_invite_issuecred,
|
|
|
+ issue_statement,
|
|
|
+ BridgeLine,
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+}
|
|
|
+```
|
|
|
+
|
|
|
+
|
|
|
+Handle the response to the request, producing the desired Lox
|
|
|
+credential if successful.
|
|
|
+```
|
|
|
+pub fn handle_response(
|
|
|
+ state: State,
|
|
|
+ resp: Response,
|
|
|
+ lox_pub: &IssuerPubKey,
|
|
|
+) -> Result<(cred::Lox, BridgeLine), ProofError> {
|
|
|
+
|
|
|
+// Pass the credential from the response to the annotated credential from the
|
|
|
+// client's state and call handle_response to form the final credential
|
|
|
+let lox_cred = state.annotated_cred.handle_response(resp.BlindedCredential, resp.Statement)
|
|
|
+
|
|
|
+Ok( lox_cred, resp.BridgeLine)
|
|
|
+}
|
|
|
+
|
|
|
+```
|