3
2
Quellcode durchsuchen

Start the README. Still very incomplete.

Ian Goldberg vor 6 Monaten
Ursprung
Commit
e6d04480e4
1 geänderte Dateien mit 276 neuen und 0 gelöschten Zeilen
  1. 276 0
      README.md

+ 276 - 0
README.md

@@ -0,0 +1,276 @@
+This crate is centred around the concept of _credentials_.  A credential
+contains:
+
+  - A number of _attributes_ (each of a type called `Scalar`)
+  - A _Message Authentication Code (MAC)_, which is two values of type
+    `Point`
+
+Credentials are held by _clients_, and are both issued and validated by
+an _issuer_.  With CMZ credentials (the kind used in this crate), the
+issuer is the only entity that can check whether a given credential is
+valid.  (Checking the credential requires the same secret key as is used
+to create the credential.)
+
+Your application can have multiple different kinds of credentials, each
+with its own set of attributes.  All of the credentials in your
+application should use the _same_ `Scalar` and `Point` types.  You get
+these from a mathematical _group_, which must satisfy the trait
+[group::prime::PrimeGroup](https://docs.rs/group/0.13.0/group/prime/trait.PrimeGroup.html).
+A typical such group would be
+[curve25519\_dalek::ristretto::RistrettoPoint](https://docs.rs/curve25519-dalek/4.1.3/curve25519_dalek/ristretto/struct.RistrettoPoint.html).
+
+To declare a credential type, use the `CMZ!` macro at the top level of
+your crate or module (outside of any function):
+
+```rust
+    CMZ! { Lox<RistrettoPoint> :
+        id,
+        bucket,
+        trust_level,
+        level_since,
+        invites_remaining,
+        blockages
+    }
+```
+
+This declares a _credential type_ called `Lox` using the mathematical
+group `RistrettoPoint`.  The credential has six attributes, with the
+names `id`, `bucket`, etc.
+
+If you omit the `<RistrettoPoint>`, a default of `<G>` will be assumed,
+so you will need to have a group called `G` in scope.  For example:
+
+`use curve25519_dalek::ristretto::RistrettoPoint as G;`
+
+Note that this macro declares a _type_ for a credential.  Your
+application may have any number (zero or more) actual credentials of
+this type.
+
+The attribute fields of this credential are of type `Option<Scalar>`.
+The field values could be `None` if, for example, a credential is
+incomplete (in the process of being issued, and the attributes are not
+fully filled in yet), or if an attribute is being hidden from the issuer
+(in which case the issuer will see a credential with some of the fields
+being `None`).
+
+## CMZ Protocols
+
+A _protocol_ is executed by a client and the issuer, and involves:
+
+  - Proving possession of ("showing") zero or more credentials, which
+    may be of the same or different credential types
+  - Requesting zero or more new credentials to be issued, which may be 
+    of the same or different credential types
+
+Importantly, when a client shows a credential and/or requests for a new
+credential to be issued, the attributes of those credentials _are not
+necessarily revealed to the issuer_.  The protocol defines which
+attributes are revealed, and which are hidden.  (There are also a few
+more options, described below.)  For the attributes that are hidden, the
+client can nonetheless prove that certain facts about them are true,
+using a _zero-knowledge proof_ (which will be automatically created
+and checked by the modules generated by this crate).
+
+### Example
+
+Suppose we have a credential type called `Wallet`, with two attributes
+`randid` (a random id number for the wallet) and `balance` (the amount
+of funds in the wallet). We also have a second credential type called
+`Item`, representing items that can be purchased, with two attributes
+`serialno` (the serial number of the item), and `price` (the price of
+the item):
+
+```rust
+CMZ! { Wallet: randid, balance }
+CMZ! { Item: serialno, price }
+```
+
+Now we want to implement a zero-knowledge protocol by which a client
+who holds a wallet with a given balance can buy an item and be issued a
+new wallet with the remaining balance.  The balance, however, is _not_
+revealed to the issuer.  To avoid double-spending (using an old wallet
+with a larger balance after having spent some of that balance already),
+the random id of the wallet will be revealed in each transaction, and
+the issuer will reject attempts to use the same random id two or more
+times.  The new wallet will be created with a fresh random id that is
+also unknown to the issuer, so that the issuer cannot track clients from
+transaction to transaction.  Items for purchase are represented by
+credentials that anyone can download from the issuer's website.
+
+The primary way to create a protocol is with the `CMZProtocol!` macro.
+
+```rust
+    CMZProtocol! { wallet_spend,
+      [ W: Wallet { randid: R, balance: H },
+        I: Item { serialno: H, price: H } ],
+      N: Wallet { randid: J, balance: H },
+      N.balance >= 0,
+      N.balance + I.price = W.balance
+    }
+```
+
+The parameters to the macro call are:
+
+  - an identifier for the protocol
+  - a list of zero or more specifications for credentials that will be shown
+  - a list of zero or more specifications for credentials that will be issued
+  - zero or more statements relating the attributes in the credentials
+
+Each credential specification list can be:
+
+  - empty
+  - a single credential specification
+  - a square-bracketed list of credential specifications
+
+Each credential specification is:
+
+  - an identifier for the credential
+  - a type for the credential, previously defined with the `CMZ!` macro
+  - a braced list of the attributes of the credential (as defined in
+    the `CMZ!` macro), annotated with the attribute specification
+
+An attribute specification for a credential to be shown is one of:
+
+  - H (hide)
+  - R (reveal)
+  - I (implicit)
+
+An attribute specification for a credential to be issued is one of:
+
+  - H (hide)
+  - R (reveal)
+  - I (implicit)
+  - S (set by issuer)
+  - J (joint creation)
+
+For the attributes:
+
+  - "hide" means that the attribute is not revealed to the issuer (but
+    the statements may still prove things about them).
+  - "reveal" means that the attribute is revealed to the issuer.
+  - "implicit" means that some other part of the overall system means
+    that both the client and the issuer already know what the value of
+    this attribute should be, and so it doesn't need to be sent in the
+    CMZ protocol (saving some space).
+  - "set by issuer", for an attribute in a credential to be issued,
+    means that the issuer will choose the value of this attribute, and
+    send it back to the client with the issued credential.
+  - "joint creation" means that both the client and the issuer will
+    contribute a random component to this attribute; the resulting
+    attribute will be the sum of those components.  The issuer will have
+    no information about the resulting attribute value, and the client
+    will not be able to predict the resulting attribute value before
+    receiving the newly issued credential.
+
+So in the example, we are creating a protocol called `wallet_spend`,
+where the client needs to already have two credentials (their current
+Wallet W and the credential I for the item they wish to purchase).  The
+client will receive back a new Wallet credential N.  (Outside of this
+protocol, the issuer would likely send the item being purchased to the
+client, perhaps using Private Information Retrieval, or something like
+that, since the item's serial number and price are hidden from the
+issuer in this example protocol.)
+
+This macro invocation creates a _module_ called `wallet_spend` that
+contains definitions of three structs and two functions.  The general
+flow is:
+
+  - The client calls the `prepare` function, passing it the two
+    credentials to be shown, as well as a partially constructed
+    credential to be issued
+  - The `prepare` function will output a `Request` struct, and a
+    `ClientState` struct.
+  - The client will send the `Request` struct to the issuer.  (The
+    struct has serialization and deserialization methods.)
+  - The issuer will call the `handle` function, which, if everything
+    checks out, will output the two shown credentials and the newly
+    issued credential, with only the attributes visible to the issuer
+    filled in.  It will also output a `Reply` struct.
+  - The issuer will send the `Reply` struct to the client.  (Again it
+    has serialization and deserialization methods.)
+  - The client will pass the `Reply` struct to the `finalize` method of
+    the `ClientState` struct it held on to.  If everything goes well,
+    the `finalize` method will output the completed newly issued
+    credential.
+
+### API
+
+The generated `wallet_spend::prepare` function (run by the client) has
+the following signature:
+
+```rust
+    pub fn prepare(
+        W: &Wallet,
+        I: &Item,
+        N: Wallet,
+    ) -> Result<(Request, ClientState), CMZError>
+```
+
+You should treat the `Request` and `ClientState` structs as opaque, but
+they are currently not, and have `Debug` implemented, so if you wanted,
+you could look inside with `println!("{:#?}", request)` or similar.
+
+You can serialize and deserialize a `Request` struct with
+`request.as_bytes()` and `wallet_spend::Request::try_from(bytes)`, or
+using `serde` (`Serialize` and `Deserialize` are implemented for
+`Request`.)
+
+The generated `wallet_spend::handle`` function (run by the issuer) has
+the following signature:
+
+```rust
+    pub fn handle(
+        request: Request,
+        fill_creds: F,
+        authorize: A,
+    ) -> Result<(Reply, (Wallet, Item, Wallet)), CMZError>
+    where
+        F: FnOnce(&mut Wallet, &mut Item, &mut Wallet) -> Result<(),CMZError>,
+        A: FnOnce(&Wallet, &Item, &Wallet) -> Result<(),CMZError>
+```
+
+Note that `handle` _consumes_ the `Request`.
+
+The `handle` function takes two callbacks: `fill_creds` and `authorize`.
+The `handle` function will read the request, and use it to fill in
+the revealed attributes from the shown and issued credentials (in this case, 
+just `W.randid`).  The hidden attributes from the credentials will be
+set to `None`, as will the implicit, set by issuer, and joint creation
+attributes.  It is the job of the `fill_creds` callback to:
+
+  - Set the values of the implicit, set by issuer, and the issuer
+    contribution to joint creation attributes (if any) for each shown
+    and issued credential
+  - Set the private keys for each credential
+
+The `handle` function will then check that the credentials shown by the
+client are all valid, and that the statements given in the
+`CMZProtocol!` macro call are all true.  If not, it will return with an
+`Err`.  If so, `handle` will call the `authorize` callback, which can do
+any final application-specific checks on the credentials (and any other
+state it can access in its closure).  If `authorize` returns `Err`, so
+will `handle`.  If `authorize` returns `Ok`, then `handle` will issue
+the credentials to be issued (in this case, the new Wallet credential).
+It will return a `Reply` struct and copies of the shown and issued
+credentials (but the attributes not visible to the issuer will still be
+`None` of course).
+
+The `Reply` struct can be serialized and deserialized in the same way as
+the `Request` struct, so that it can be sent back to the client.
+
+The client will then pass that deserialized `Reply` struct into the
+`finalize` method of the `ClientState` struct that was output by
+`prepare`, above.  The `finalize` method has the following signature:
+
+```rust
+    pub fn finalize(
+        self,
+        reply: Reply,
+    ) -> Result<Wallet, (CMZError, Self)>
+```
+
+Note that `finalize` _consumes_ both the `Reply` and also `self`.  In
+the event of an error (such as a malicious reply impersonating the
+issuer?), `self` is returned so you can possibly try again.  In the
+event of success, the newly issued credentials are returned as a tuple,
+or if as in this case, there's just one, as a single element.