-
Notifications
You must be signed in to change notification settings - Fork 31
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Signed-off-by: lovesh <[email protected]>
- Loading branch information
Showing
17 changed files
with
1,236 additions
and
6 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
Implements KVAC from [Improved Algebraic MACs and Practical Keyed-Verification Anonymous Credentials](https://link.springer.com/chapter/10.1007/978-3-319-69453-5_20) | ||
|
||
An alternate implementation of proof of knowledge of MAC is added which is adapted from the protocol to prove knowledge of | ||
BBS+ signatures described in section 4.5 of the paper [Anonymous Attestation Using the Strong Diffie Hellman Assumption Revisited](https://eprint.iacr.org/2016/663) | ||
|
||
In addition, it supports generating proof of validity or invalidity of keyed-proofs, i.e. the proof verifying which requires the knowledge of | ||
secret key. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
BBS# as described [here](https://github.com/user-attachments/files/15905230/BBS_Sharp_Short_TR.pdf) | ||
|
||
This assumes that the messages/attributes have already been prepared before signing, i.e. attributes are hashed | ||
with public salts, etc and whats called `H_i` in the paper is already created. | ||
|
||
Assumes that a Schnorr Signature will be generated by the user's secure hardware. | ||
|
||
Implements both the offline and half-offline (HOL) mode. | ||
In the former, the verifier is either the signer (has the secret key) or can ask the signer to verify the proof without revealing any user-specific info. | ||
In the latter, the user needs to communicate with the signer before creating a proof and get "some helper data" | ||
to create a proof which the verifier can check without needing the secret key or interacting with the issuer. | ||
For efficiency and avoiding correlation (when signer and verifier collude), the user gets a batch of | ||
"helper data" to let him create several proofs. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,210 @@ | ||
use crate::{ | ||
bbs_sharp::setup::{MACParams, PublicKey, SecretKey}, | ||
error::KVACError, | ||
}; | ||
use ark_ec::{AffineRepr, CurveGroup}; | ||
use ark_ff::{Field, Zero}; | ||
use ark_serialize::{CanonicalDeserialize, CanonicalSerialize}; | ||
use ark_std::{ops::Neg, rand::RngCore, vec, vec::Vec, UniformRand}; | ||
use digest::Digest; | ||
use dock_crypto_utils::{ | ||
expect_equality, serde_utils::ArkObjectBytes, signature::MultiMessageSignatureParams, | ||
}; | ||
use schnorr_pok::{ | ||
compute_random_oracle_challenge, | ||
discrete_log::{PokDiscreteLog, PokDiscreteLogProtocol}, | ||
}; | ||
use serde::{Deserialize, Serialize}; | ||
use serde_with::serde_as; | ||
use zeroize::{Zeroize, ZeroizeOnDrop}; | ||
|
||
#[serde_as] | ||
#[derive( | ||
Clone, | ||
PartialEq, | ||
Eq, | ||
Debug, | ||
CanonicalSerialize, | ||
CanonicalDeserialize, | ||
Serialize, | ||
Deserialize, | ||
Zeroize, | ||
ZeroizeOnDrop, | ||
)] | ||
pub struct MAC<G: AffineRepr> { | ||
#[serde_as(as = "ArkObjectBytes")] | ||
pub A: G, | ||
#[serde_as(as = "ArkObjectBytes")] | ||
pub e: G::ScalarField, | ||
} | ||
|
||
/// A proof corresponding to a MAC that it is correctly created, i.e. can be verified successfully by someone possessing | ||
/// the secret key. Verifying the proof does not require the secret key. | ||
/// Consists of 2 protocols for discrete log relations, and both have the same discrete log | ||
/// | ||
#[serde_as] | ||
#[derive( | ||
Clone, PartialEq, Eq, Debug, CanonicalSerialize, CanonicalDeserialize, Serialize, Deserialize, | ||
)] | ||
pub struct ProofOfValidityOfMAC<G: AffineRepr> { | ||
/// For proving `B = A * sk` where `sk` is the secret key and `B = g_0 + signer_pk + g_1 * m_1 + g_2 * m_2 + ... g_n * m_n` | ||
pub sc_B: PokDiscreteLog<G>, | ||
/// For proving knowledge of secret key, i.e. `pk = g * sk` | ||
pub sc_pk: PokDiscreteLog<G>, | ||
} | ||
|
||
impl<G: AffineRepr> MAC<G> { | ||
pub fn new<R: RngCore>( | ||
rng: &mut R, | ||
messages: &[G::ScalarField], | ||
user_public_key: &PublicKey<G>, | ||
signer_secret_key: &SecretKey<G::ScalarField>, | ||
params: impl AsRef<MACParams<G>>, | ||
) -> Result<Self, KVACError> { | ||
if messages.is_empty() { | ||
return Err(KVACError::NoMessageGiven); | ||
} | ||
let params = params.as_ref(); | ||
expect_equality!( | ||
messages.len(), | ||
params.supported_message_count(), | ||
KVACError::MessageCountIncompatibleWithMACParams | ||
); | ||
let mut e = G::ScalarField::rand(rng); | ||
while (e + signer_secret_key.0).is_zero() { | ||
e = G::ScalarField::rand(rng) | ||
} | ||
// 1/(e+x) | ||
let e_plus_x_inv = (e + signer_secret_key.0).inverse().unwrap(); | ||
let A = params.b(messages.iter().enumerate(), user_public_key)? * e_plus_x_inv; | ||
Ok(Self { | ||
A: A.into_affine(), | ||
e, | ||
}) | ||
} | ||
|
||
pub fn verify( | ||
&self, | ||
messages: &[G::ScalarField], | ||
user_public_key: &PublicKey<G>, | ||
sk: impl AsRef<G::ScalarField>, | ||
params: impl AsRef<MACParams<G>>, | ||
) -> Result<(), KVACError> { | ||
if messages.is_empty() { | ||
return Err(KVACError::NoMessageGiven); | ||
} | ||
let params = params.as_ref(); | ||
expect_equality!( | ||
messages.len(), | ||
params.supported_message_count(), | ||
KVACError::MessageCountIncompatibleWithMACParams | ||
); | ||
let b = params.b(messages.iter().enumerate(), user_public_key)?; | ||
let e_plus_x_inv = (self.e + sk.as_ref()) | ||
.inverse() | ||
.ok_or(KVACError::CannotInvert0)?; | ||
if (b * e_plus_x_inv).into_affine() != self.A { | ||
return Err(KVACError::InvalidMAC); | ||
} | ||
Ok(()) | ||
} | ||
} | ||
|
||
impl<G: AffineRepr> ProofOfValidityOfMAC<G> { | ||
pub fn new<R: RngCore, D: Digest>( | ||
rng: &mut R, | ||
mac: &MAC<G>, | ||
secret_key: &SecretKey<G::ScalarField>, | ||
public_key: &PublicKey<G>, | ||
params: impl AsRef<MACParams<G>>, | ||
) -> Self { | ||
let witness = secret_key.0; | ||
let blinding = G::ScalarField::rand(rng); | ||
let B = (mac.A * witness).into_affine(); | ||
let params = params.as_ref(); | ||
let mut challenge_bytes = vec![]; | ||
// As witness has to be proven same in both protocols. | ||
let p1 = PokDiscreteLogProtocol::init(witness, blinding, &mac.A); | ||
let p2 = PokDiscreteLogProtocol::init(witness, blinding, ¶ms.g); | ||
p1.challenge_contribution(&mac.A, &B, &mut challenge_bytes) | ||
.unwrap(); | ||
p2.challenge_contribution(¶ms.g, &public_key.0, &mut challenge_bytes) | ||
.unwrap(); | ||
let challenge = compute_random_oracle_challenge::<G::ScalarField, D>(&challenge_bytes); | ||
Self { | ||
sc_B: p1.gen_proof(&challenge), | ||
sc_pk: p2.gen_proof(&challenge), | ||
} | ||
} | ||
|
||
pub fn verify<D: Digest>( | ||
&self, | ||
mac: &MAC<G>, | ||
messages: &[G::ScalarField], | ||
user_public_key: &PublicKey<G>, | ||
signer_public_key: &PublicKey<G>, | ||
params: impl AsRef<MACParams<G>>, | ||
) -> Result<(), KVACError> { | ||
if self.sc_B.response != self.sc_pk.response { | ||
return Err(KVACError::InvalidMACProof); | ||
} | ||
let params = params.as_ref(); | ||
// B = g_0 + user_pk + g_1 * m_1 + g_2 * m_2 + ... g_n * m_n - A * e | ||
let B = (params.b(messages.iter().enumerate(), user_public_key)? + mac.A * mac.e.neg()) | ||
.into_affine(); | ||
|
||
let mut challenge_bytes = vec![]; | ||
self.sc_B | ||
.challenge_contribution(&mac.A, &B, &mut challenge_bytes) | ||
.unwrap(); | ||
self.sc_pk | ||
.challenge_contribution(¶ms.g, &signer_public_key.0, &mut challenge_bytes) | ||
.unwrap(); | ||
let challenge = compute_random_oracle_challenge::<G::ScalarField, D>(&challenge_bytes); | ||
if !self.sc_B.verify(&B, &mac.A, &challenge) { | ||
return Err(KVACError::InvalidMACProof); | ||
} | ||
if !self | ||
.sc_pk | ||
.verify(&signer_public_key.0, ¶ms.g, &challenge) | ||
{ | ||
return Err(KVACError::InvalidMACProof); | ||
} | ||
Ok(()) | ||
} | ||
} | ||
|
||
#[cfg(test)] | ||
mod tests { | ||
use super::*; | ||
use ark_secp256r1::{Affine, Fr}; | ||
use ark_std::rand::{prelude::StdRng, SeedableRng}; | ||
use sha2::Sha256; | ||
|
||
#[test] | ||
fn mac_verification() { | ||
let mut rng = StdRng::seed_from_u64(0u64); | ||
let message_count = 10; | ||
let messages = (0..message_count) | ||
.map(|_| Fr::rand(&mut rng)) | ||
.collect::<Vec<_>>(); | ||
let params = MACParams::<Affine>::new::<Sha256>(b"test", message_count); | ||
let signer_sk = SecretKey::new(&mut rng); | ||
let signer_pk = PublicKey::new(&signer_sk, ¶ms.g); | ||
|
||
let user_sk = SecretKey::new(&mut rng); | ||
let user_pk = PublicKey::new(&user_sk, ¶ms.g); | ||
|
||
// Signer sends the following 2 items to the user | ||
let mac = MAC::new(&mut rng, &messages, &user_pk, &signer_sk, ¶ms).unwrap(); | ||
let proof = | ||
ProofOfValidityOfMAC::new::<_, Sha256>(&mut rng, &mac, &signer_sk, &signer_pk, ¶ms); | ||
|
||
// User verifies both | ||
mac.verify(&messages, &user_pk, &signer_sk, ¶ms) | ||
.unwrap(); | ||
proof | ||
.verify::<Sha256>(&mac, &messages, &user_pk, &signer_pk, params) | ||
.unwrap(); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
//! BBS# as described [here](https://github.com/user-attachments/files/15905230/BBS_Sharp_Short_TR.pdf) | ||
//! | ||
//! This assumes that the messages/attributes have already been prepared before signing, i.e. attributes are hashed | ||
//! with public salts, etc and whats called `H_i` in the paper is already created. | ||
//! | ||
//! Assumes that a Schnorr Signature will be generated by the user's secure hardware. | ||
//! | ||
//! Implements both the offline and half-offline (HOL) mode. In the former, the verifier is either the | ||
//! signer (has the secret key) or can ask the signer to verify the proof without revealing any user-specific info | ||
//! In the latter, the user needs to communicate with the signer before creating a proof and get "some helper data" | ||
//! to create a proof which the verifier can check without needing the secret key or interacting with the issuer. | ||
//! For efficiency and avoiding correlation (when signer and verifier collude), the user gets a batch of | ||
//! "helper data" to let him create several proofs. | ||
pub mod mac; | ||
pub mod proof; | ||
pub mod setup; |
Oops, something went wrong.