https://github.com/lovesh/coconut-rust
Coconut: Threshold Issuance Selective Disclosure Credentials with Applications to Distributed Ledgers
https://github.com/lovesh/coconut-rust
anonymous-credentials threshold-cryptography
Last synced: 11 months ago
JSON representation
Coconut: Threshold Issuance Selective Disclosure Credentials with Applications to Distributed Ledgers
- Host: GitHub
- URL: https://github.com/lovesh/coconut-rust
- Owner: lovesh
- License: apache-2.0
- Created: 2019-11-25T19:33:18.000Z (over 6 years ago)
- Default Branch: master
- Last Pushed: 2020-01-16T13:02:37.000Z (over 6 years ago)
- Last Synced: 2025-06-28T20:54:06.522Z (12 months ago)
- Topics: anonymous-credentials, threshold-cryptography
- Language: Rust
- Homepage:
- Size: 44.9 KB
- Stars: 14
- Watchers: 4
- Forks: 2
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
# Coconut: Threshold Issuance Selective Disclosure Credentials with Applications to Distributed Ledgers
Based on the Coconut paper, [arxiv link](https://arxiv.org/pdf/1802.07344.pdf), [NDSS submission](https://www.ndss-symposium.org/wp-content/uploads/2019/02/ndss2019_06A-1_Sonnino_paper.pdf). Can use Shamir secret sharing
or Pedersen verifiable secret sharing (centalized and decentralized versions available) for key generation.
Centralized keygen is done by a trusted third party. This trusted party's role ends at key generation.
The decentralized version of Pedersen's secret sharing can be used to avoid the trusted third party.
## API
1. Generate system parameters.
```rust
let threshold = 3; // threshold number of participants
let total = 5; // total number of participants
let msg_count = 6; // total attributes in credential
let count_hidden = 2; // number of attributes hidden from issuers.
let params = Params::new(msg_count, "test-label".as_bytes());
```
1. Keygen for issuer. This could be a distributed keygen procedure or something done by a
trusted third party. For prototyping, the code used the latter.
```rust
// Below is an example of keys generated with Shamir secret sharing
// signers is a vector of struct `Signer` which corresponds to a single signer and contains a signer id, a signing and a
// verification key
pub struct Signer {
pub id: usize,
pub sigkey: Sigkey,
pub verkey: Verkey,
}
let (_, _, signers: Vec) = trusted_party_SSS_keygen(threshold, total, ¶ms);
// Below is an example of Pedersen verifiable secret sharing
let (g, h) = PedersenVSS::gens("testPVSS-label".as_bytes());
// `secret_x` and `secret_y` are the combined secrets and should never be given away. Only use for testing.
// `x_shares` an `y_shares` are shares of the secrets x and y (vector)
// `comm_coeff_x` and `comm_coeff_y` are commitments to coefficients of polynomial used to share `secret_x` and `secret_y`
// `signers` is a vector of struct `Signer` like above
let (
secret_x,
secret_y,
signers,
_,
comm_coeff_x,
x_shares,
x_t_shares,
_,
comm_coeff_y,
y_shares,
y_t_shares,
) = trusted_party_PVSS_keygen(threshold, total, ¶ms, &g, &h);
// Each participant can verify its share as
PedersenVSS::verify_share(
threshold,
participant_id,
(&x_shares[&i], &x_t_shares[&i]),
&comm_coeff_x,
&g,
&h
)
PedersenVSS::verify_share(
threshold,
participant_id,
(&y_shares[j][&i], &y_t_shares[j][&i]),
&comm_coeff_y[j],
&g,
&h
)
```
Also provided a decentralized (no trusted third party) verifiable secret sharing which
can be used for keygen. Use `PedersenDVSSParticipant`. Look at tests `test_Pedersen_DVSS`, `test_keygen_reconstruction_decentralized_verifiable_secret_sharing`,
`test_sign_verify_decentralized_verifiable_secret_sharing_keygen` for examples of secret sharing, key generation and signing respectively
1. User takes his attributes, generates an Elgamal keypair and creates a signature request
to be sent to Signers (Issuers)
```rust
let msgs = FieldElementVector::random(msg_count);
let (elg_sk, elg_pk) = elgamal_keygen!(¶ms.g1);
// sig_req is the signature request. randomness will be used to create proof of knowledge of
// various elements in the signature request
let (sig_req, randomness) = SignatureRequest::new(&msgs, count_hidden, &elg_pk, ¶ms);
```
1. Create a proof of knowledge of hidden messages, elgamal secret key and others.
```rust
// Initiate proof of knowledge of various items of Signature request
let sig_req_pok = SignatureRequestPoK::init(&sig_req, &elg_pk, ¶ms);
// The challenge can include other things also (if proving other predicates)
let challenge = FieldElement::from_msg_hash(&sig_req_pok.to_bytes());
// Create proof once the challenge is finalized
let hidden_msgs: FieldElementVector = msgs
.iter()
.take(count_hidden)
.map(|m| m.clone())
.collect::>()
.into();
let sig_req_proof = sig_req_pok
.gen_proof(&hidden_msgs, randomness, &elg_sk, &challenge)
.unwrap();
```
1. Each signer will verify the proof and create a blind signature which is sent back to user.
```rust
assert!(sig_req_proof.verify(&sig_req, &elg_pk, &challenge, ¶ms));
let blinded_sig = BlindSignature::new(&sig_req, &sig_key);
```
1. User unblinds the signature and verifies correctness of signature
```rust
let unblinded_sig = blinded_sig.unblind(&elg_sk);
unblinded_sig.verify(&msgs, &verkey, ¶ms);
```
1. User aggregates the unblinded signatures and verifies correctness of the
aggregated signature
```rust
let aggr_sig = Signature::aggregate(threshold, unblinded_sigs);
// keys is a vector of tuples containing signer id and verification key (usize, Verkey)
let aggr_vk = Verkey::aggregate(
threshold,
keys
);
assert!(aggr_sig.verify(&msgs, &aggr_vk, ¶ms));
```
1. To prove knowledge of signature, transform the verkey and signature to
an appropriate structure and then use the Schnorr protocol similar to above
```rust
let ps_verkey = transform_to_PS_verkey(&aggr_vk, ¶ms);
let ps_sig = transform_to_PS_sig(&aggr_sig);
// Empty HashSet indicates that no message is being revealed, only knowledge of signature is proved
let pok =
PoKOfSignature::init(&ps_sig, &ps_verkey, msgs.as_slice(), HashSet::new()).unwrap();
let chal = FieldElement::from_msg_hash(&pok.to_bytes());
let proof = pok.gen_proof(&chal).unwrap();
// The verifier verifies the proof. Empty HashMap indicates the no message was revealed
assert!(proof.verify(&ps_verkey, HashMap::new(), &chal).unwrap());
```
1. To prove knowledge of signature and reveal some of the messages, the prover specifies
the indices of the messages being revealed to `PoKOfSignature`.
```rust
let ps_verkey = transform_to_PS_verkey(&aggr_vk, ¶ms);
let ps_sig = transform_to_PS_sig(&aggr_sig);
// Reveal the following messages to the verifier
let mut revealed_msg_indices = HashSet::new();
revealed_msg_indices.insert(3);
revealed_msg_indices.insert(5);
let pok =
PoKOfSignature::init(&ps_sig, &ps_verkey, msgs.as_slice(), revealed_msg_indices.clone()).unwrap();
let chal = FieldElement::from_msg_hash(&pok.to_bytes());
let proof = pok.gen_proof(&chal).unwrap();
// The prover reveals these messages
let mut revealed_msgs = HashMap::new();
for i in &revealed_msg_indices {
revealed_msgs.insert(i.clone(), msgs[*i].clone());
}
// The verifier verifies the proof, passing the revealed messages
assert!(proof.verify(&ps_verkey, revealed_msgs.clone(), &chal).unwrap());
```
## Pending
1. Error handling. Start with asserts in non-test code.
1. Documentation
1. Benchmarking