{"id":22303538,"url":"https://github.com/lovesh/coconut-rust","last_synced_at":"2025-07-29T04:31:04.838Z","repository":{"id":57607305,"uuid":"224026048","full_name":"lovesh/coconut-rust","owner":"lovesh","description":"Coconut: Threshold Issuance Selective Disclosure Credentials with Applications to Distributed Ledgers","archived":false,"fork":false,"pushed_at":"2020-01-16T13:02:37.000Z","size":46,"stargazers_count":14,"open_issues_count":0,"forks_count":2,"subscribers_count":4,"default_branch":"master","last_synced_at":"2025-06-28T20:54:06.522Z","etag":null,"topics":["anonymous-credentials","threshold-cryptography"],"latest_commit_sha":null,"homepage":"","language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/lovesh.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2019-11-25T19:33:18.000Z","updated_at":"2025-04-07T00:20:00.000Z","dependencies_parsed_at":"2022-08-30T08:51:32.985Z","dependency_job_id":null,"html_url":"https://github.com/lovesh/coconut-rust","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/lovesh/coconut-rust","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lovesh%2Fcoconut-rust","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lovesh%2Fcoconut-rust/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lovesh%2Fcoconut-rust/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lovesh%2Fcoconut-rust/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/lovesh","download_url":"https://codeload.github.com/lovesh/coconut-rust/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lovesh%2Fcoconut-rust/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":267601208,"owners_count":24113927,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-07-28T02:00:09.689Z","response_time":68,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["anonymous-credentials","threshold-cryptography"],"created_at":"2024-12-03T18:44:09.075Z","updated_at":"2025-07-29T04:31:04.538Z","avatar_url":"https://github.com/lovesh.png","language":"Rust","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Coconut: Threshold Issuance Selective Disclosure Credentials with Applications to Distributed Ledgers\n\nBased 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 \nor Pedersen verifiable secret sharing (centalized and decentralized versions available) for key generation. \nCentralized keygen is done by a trusted third party. This trusted party's role ends at key generation. \nThe decentralized version of Pedersen's secret sharing can be used to avoid the trusted third party.\n\n## API\n1. Generate system parameters.\n    ```rust\n    let threshold = 3;     // threshold number of participants\n    let total = 5;         // total number of participants\n    let msg_count = 6;     // total attributes in credential\n    let count_hidden = 2;  // number of attributes hidden from issuers.\n    let params = Params::new(msg_count, \"test-label\".as_bytes());\n    ```\n\n1. Keygen for issuer. This could be a distributed keygen procedure or something done by a \ntrusted third party. For prototyping, the code used the latter.\n    ```rust\n       // Below is an example of keys generated with Shamir secret sharing\n       // signers is a vector of struct `Signer` which corresponds to a single signer and contains a signer id, a signing and a \n       // verification key\n        pub struct Signer {\n             pub id: usize,\n             pub sigkey: Sigkey,\n             pub verkey: Verkey,\n        }\n        let (_, _, signers: Vec\u003cSigner\u003e) = trusted_party_SSS_keygen(threshold, total, \u0026params);\n       \n       // Below is an example of Pedersen verifiable secret sharing\n       let (g, h) = PedersenVSS::gens(\"testPVSS-label\".as_bytes());\n       // `secret_x` and `secret_y` are the combined secrets and should never be given away. Only use for testing.\n       // `x_shares` an `y_shares` are shares of the secrets x and y (vector)\n       // `comm_coeff_x` and `comm_coeff_y` are commitments to coefficients of polynomial used to share `secret_x` and `secret_y`\n       // `signers` is a vector of struct `Signer` like above\n       let (\n           secret_x,\n           secret_y,\n           signers,\n           _,\n           comm_coeff_x,\n           x_shares,\n           x_t_shares,\n           _,\n           comm_coeff_y,\n           y_shares,\n           y_t_shares,\n       ) = trusted_party_PVSS_keygen(threshold, total, \u0026params, \u0026g, \u0026h);\n       \n       // Each participant can verify its share as\n       PedersenVSS::verify_share(\n           threshold,\n           participant_id,\n           (\u0026x_shares[\u0026i], \u0026x_t_shares[\u0026i]),\n           \u0026comm_coeff_x,\n           \u0026g,\n           \u0026h\n       )\n       \n       PedersenVSS::verify_share(\n           threshold,\n           participant_id,\n           (\u0026y_shares[j][\u0026i], \u0026y_t_shares[j][\u0026i]),\n           \u0026comm_coeff_y[j],\n           \u0026g,\n           \u0026h\n       ) \n    ```\n    Also provided a decentralized (no trusted third party) verifiable secret sharing which \n    can be used for keygen. Use `PedersenDVSSParticipant`. Look at tests `test_Pedersen_DVSS`, `test_keygen_reconstruction_decentralized_verifiable_secret_sharing`,\n    `test_sign_verify_decentralized_verifiable_secret_sharing_keygen` for examples of secret sharing, key generation and signing respectively\n           \n1. User takes his attributes, generates an Elgamal keypair and creates a signature request \nto be sent to Signers (Issuers)\n    ```rust\n   let msgs = FieldElementVector::random(msg_count);\n   let (elg_sk, elg_pk) = elgamal_keygen!(\u0026params.g1);\n   // sig_req is the signature request. randomness will be used to create proof of knowledge of \n   // various elements in the signature request \n   let (sig_req, randomness) = SignatureRequest::new(\u0026msgs, count_hidden, \u0026elg_pk, \u0026params);\n    ```\n\n1. Create a proof of knowledge of hidden messages, elgamal secret key and others.\n    ```rust\n   // Initiate proof of knowledge of various items of Signature request\n   let sig_req_pok = SignatureRequestPoK::init(\u0026sig_req, \u0026elg_pk, \u0026params);\n\n   // The challenge can include other things also (if proving other predicates)\n   let challenge = FieldElement::from_msg_hash(\u0026sig_req_pok.to_bytes());\n\n   // Create proof once the challenge is finalized\n   let hidden_msgs: FieldElementVector = msgs\n       .iter()\n       .take(count_hidden)\n       .map(|m| m.clone())\n       .collect::\u003cVec\u003cFieldElement\u003e\u003e()\n       .into();\n   let sig_req_proof = sig_req_pok\n       .gen_proof(\u0026hidden_msgs, randomness, \u0026elg_sk, \u0026challenge)\n       .unwrap();\n    ```\n\n1. Each signer will verify the proof and create a blind signature which is sent back to user.\n    ```rust\n   assert!(sig_req_proof.verify(\u0026sig_req, \u0026elg_pk, \u0026challenge, \u0026params));\n   let blinded_sig = BlindSignature::new(\u0026sig_req, \u0026sig_key);\n    ```\n   \n1. User unblinds the signature and verifies correctness of signature\n    ```rust\n    let unblinded_sig = blinded_sig.unblind(\u0026elg_sk);\n    unblinded_sig.verify(\u0026msgs, \u0026verkey, \u0026params);\n    ```\n\n1.  User aggregates the unblinded signatures and verifies correctness of the \n    aggregated signature\n    ```rust\n    let aggr_sig = Signature::aggregate(threshold, unblinded_sigs);\n    // keys is a vector of tuples containing signer id and verification key (usize, Verkey)\n    let aggr_vk = Verkey::aggregate(\n                threshold,\n                keys\n            );\n    assert!(aggr_sig.verify(\u0026msgs, \u0026aggr_vk, \u0026params));\n    ```\n\n1. To prove knowledge of signature, transform the verkey and signature to \nan appropriate structure and then use the Schnorr protocol similar to above\n    ```rust\n   let ps_verkey = transform_to_PS_verkey(\u0026aggr_vk, \u0026params);\n   let ps_sig = transform_to_PS_sig(\u0026aggr_sig);\n   \n   // Empty HashSet indicates that no message is being revealed, only knowledge of signature is proved\n   let pok =\n       PoKOfSignature::init(\u0026ps_sig, \u0026ps_verkey, msgs.as_slice(), HashSet::new()).unwrap();\n   \n   let chal = FieldElement::from_msg_hash(\u0026pok.to_bytes());\n   \n   let proof = pok.gen_proof(\u0026chal).unwrap();\n   \n   // The verifier verifies the proof. Empty HashMap indicates the no message was revealed\n   assert!(proof.verify(\u0026ps_verkey, HashMap::new(), \u0026chal).unwrap());\n    ```\n\n1. To prove knowledge of signature and reveal some of the messages, the prover specifies \nthe indices of the messages being revealed to `PoKOfSignature`.\n    ```rust\n       let ps_verkey = transform_to_PS_verkey(\u0026aggr_vk, \u0026params);\n       let ps_sig = transform_to_PS_sig(\u0026aggr_sig);\n       \n       // Reveal the following messages to the verifier\n       let mut revealed_msg_indices = HashSet::new();\n       revealed_msg_indices.insert(3);\n       revealed_msg_indices.insert(5);\n       \n       let pok =\n           PoKOfSignature::init(\u0026ps_sig, \u0026ps_verkey, msgs.as_slice(), revealed_msg_indices.clone()).unwrap();\n   \n       let chal = FieldElement::from_msg_hash(\u0026pok.to_bytes());\n   \n       let proof = pok.gen_proof(\u0026chal).unwrap();\n       \n       // The prover reveals these messages\n       let mut revealed_msgs = HashMap::new();\n       for i in \u0026revealed_msg_indices {\n           revealed_msgs.insert(i.clone(), msgs[*i].clone());\n       }\n       \n       // The verifier verifies the proof, passing the revealed messages\n       assert!(proof.verify(\u0026ps_verkey, revealed_msgs.clone(), \u0026chal).unwrap());\n    ```\n\n## Pending\n1. Error handling. Start with asserts in non-test code.\n1. Documentation\n1. Benchmarking\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flovesh%2Fcoconut-rust","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Flovesh%2Fcoconut-rust","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flovesh%2Fcoconut-rust/lists"}