Add missing blinded serial number value and update accordingly the code

This commit is contained in:
aniampio
2021-10-20 16:06:30 +01:00
parent b068dde7c7
commit 2e8a0e9a72
9 changed files with 145 additions and 90 deletions
+1
View File
@@ -194,6 +194,7 @@ impl NymClient {
prepare_for_spending(
&self.key_manager.identity_keypair().public_key().to_bytes(),
&bandwidth_credential,
&bandwidth_credential_attributes,
&verification_key,
)
.expect("could not prepare out bandwidth credential for spending")
+1 -1
View File
@@ -79,7 +79,7 @@ async fn prepare_temporary_credential(validators: &[Url], raw_identity: &[u8]) -
.await
.expect("could not obtain bandwidth credential");
prepare_for_spending(raw_identity, &bandwidth_credential, &verification_key)
prepare_for_spending(raw_identity, &bandwidth_credential, &bandwidth_credential_attributes, &verification_key)
.expect("could not prepare out bandwidth credential for spending")
}
+1
View File
@@ -182,6 +182,7 @@ impl NymClient {
prepare_for_spending(
&self.key_manager.identity_keypair().public_key().to_bytes(),
&bandwidth_credential,
&bandwidth_credential_attributes,
&verification_key,
)
.expect("could not prepare out bandwidth credential for spending")
+1 -1
View File
@@ -79,7 +79,7 @@ async fn prepare_temporary_credential(validators: &[Url], raw_identity: &[u8]) -
.await
.expect("could not obtain bandwidth credential");
prepare_for_spending(raw_identity, &bandwidth_credential, &verification_key)
prepare_for_spending(raw_identity, &bandwidth_credential, &bandwidth_credential_attributes, &verification_key)
.expect("could not prepare out bandwidth credential for spending")
}
+5 -4
View File
@@ -32,14 +32,14 @@ pub struct BandwidthVoucherAttributes {
impl BandwidthVoucherAttributes {
fn get_public_attributes(&self) -> Vec<PublicAttribute> {
pub fn get_public_attributes(&self) -> Vec<PublicAttribute> {
let mut pub_attributes = Vec::with_capacity(PUBLIC_ATTRIBUTES as usize);
pub_attributes.push(self.voucher_value);
pub_attributes.push(self.voucher_info);
pub_attributes
}
fn get_private_attributes(&self) -> Vec<PrivateAttribute> {
pub fn get_private_attributes(&self) -> Vec<PrivateAttribute> {
let mut priv_attributes = Vec::with_capacity(PRIVATE_ATTRIBUTES as usize);
priv_attributes.push(self.serial_number);
priv_attributes.push(self.binding_number);
@@ -62,17 +62,18 @@ pub async fn obtain_signature(attributes: &BandwidthVoucherAttributes, validator
pub fn prepare_for_spending(
raw_identity: &[u8],
signature: &Signature,
attributes: &BandwidthVoucherAttributes,
verification_key: &VerificationKey,
) -> Result<Credential, Error> {
let public_attributes = vec![BANDWIDTH_VALUE.to_be_bytes().to_vec()];
let private_attributes = vec![raw_identity.to_vec()];
let params = Parameters::new(TOTAL_ATTRIBUTES)?;
prepare_credential_for_spending(
&params,
public_attributes,
private_attributes,
attributes.serial_number,
attributes.binding_number,
signature,
verification_key,
)
+5 -7
View File
@@ -134,18 +134,16 @@ pub async fn obtain_aggregate_signature(
pub fn prepare_credential_for_spending(
params: &Parameters,
public_attributes: Vec<Vec<u8>>,
private_attributes: Vec<Vec<u8>>,
serial_number: Attribute,
binding_number: Attribute,
signature: &Signature,
verification_key: &VerificationKey,
) -> Result<Credential, Error> {
let private_attributes = private_attributes
.iter()
.map(hash_to_scalar)
.collect::<Vec<Attribute>>();
let theta = prove_credential(params, verification_key, signature, &private_attributes)?;
let theta = prove_credential(params, verification_key, signature, serial_number, binding_number)?;
Ok(Credential::new(
(public_attributes.len() + private_attributes.len()) as u32,
(public_attributes.len() + 2) as u32,
theta,
public_attributes,
signature,
+77 -42
View File
@@ -76,7 +76,8 @@ fn compute_challenge<D, I, B>(iter: I) -> Scalar
Scalar::from_bytes_wide(&bytes)
}
fn produce_response(witness: &Scalar, challenge: &Scalar, secret: &Scalar) -> Scalar {
fn produce_response(witness: &Scalar, challenge: &Scalar, secret: &Scalar) -> Scalar
{
witness - challenge * secret
}
@@ -380,11 +381,9 @@ pub struct ProofKappaNu {
// c
challenge: Scalar,
// rm
response_attributes: Vec<Scalar>,
// TODO NAMING: blinder or blinding factor?
// rt
// responses
response_serial_number: Scalar,
response_binding_number: Scalar,
response_blinder: Scalar,
}
@@ -392,13 +391,17 @@ impl ProofKappaNu {
pub(crate) fn construct(
params: &Parameters,
verification_key: &VerificationKey,
private_attributes: &[Attribute],
serial_number: &Attribute,
binding_number: &Attribute,
blinding_factor: &Scalar,
blinded_message: &G2Projective,
blinded_serial_number: &G2Projective,
) -> Self {
// create the witnesses
let witness_blinder = params.random_scalar();
let witness_attributes = params.n_random_scalars(private_attributes.len());
let witness_serial_number = params.random_scalar();
let witness_binding_number = params.random_scalar();
let witness_attributes = vec![witness_serial_number, witness_blinder];
let beta_bytes = verification_key
.beta
@@ -416,28 +419,33 @@ impl ProofKappaNu {
.map(|(wm_i, beta_i)| beta_i * wm_i)
.sum::<G2Projective>();
// zeta is the public value associated with the serial number
let commitment_zeta = params.gen2() * witness_serial_number;
let challenge = compute_challenge::<ChallengeDigest, _, _>(
std::iter::once(params.gen2().to_bytes().as_ref())
.chain(std::iter::once(blinded_message.to_bytes().as_ref())) //kappa
.chain(std::iter::once(verification_key.alpha.to_bytes().as_ref()))
.chain(beta_bytes.iter().map(|b| b.as_ref()))
.chain(std::iter::once(commitment_kappa.to_bytes().as_ref())),
.chain(std::iter::once(commitment_kappa.to_bytes().as_ref()))
.chain(std::iter::once(commitment_zeta.to_bytes().as_ref())),
);
// responses
let response_blinder = produce_response(&witness_blinder, &challenge, &blinding_factor);
let response_attributes =
produce_responses(&witness_attributes, &challenge, private_attributes);
let response_serial_number = produce_response(&witness_serial_number, &challenge, &serial_number);
let response_binding_number = produce_response(&witness_binding_number, &challenge, &binding_number);
ProofKappaNu {
challenge,
response_attributes,
response_serial_number,
response_binding_number,
response_blinder,
}
}
pub(crate) fn private_attributes(&self) -> usize {
self.response_attributes.len()
2
}
pub(crate) fn verify(
@@ -445,6 +453,7 @@ impl ProofKappaNu {
params: &Parameters,
verification_key: &VerificationKey,
kappa: &G2Projective,
zeta: &G2Projective,
) -> bool {
let beta_bytes = verification_key
.beta
@@ -452,20 +461,22 @@ impl ProofKappaNu {
.map(|beta_i| beta_i.to_bytes())
.collect::<Vec<_>>();
let response_attributes = [self.response_serial_number, self.response_binding_number];
// re-compute witnesses commitments
// Aw = (c * kappa) + (rt * g2) + ((1 - c) * alpha) + (rm[0] * beta[0]) + ... + (rm[i] * beta[i])
let commitment_kappa = kappa * self.challenge
+ params.gen2() * self.response_blinder
+ verification_key.alpha * (Scalar::one() - self.challenge)
+ self
.response_attributes
+ response_attributes
.iter()
.zip(verification_key.beta.iter())
.map(|(priv_attr, beta_i)| beta_i * priv_attr)
.sum::<G2Projective>();
// Bw = (c * nu) + (rt * h)
// let commitment_blinder = nu * self.challenge + signature.sig1() * self.response_blinder;
// zeta is the public value associated with the serial number
let commitment_zeta = zeta * self.challenge
+ params.gen2() * self.response_serial_number;
// compute the challenge
let challenge = compute_challenge::<ChallengeDigest, _, _>(
@@ -473,7 +484,8 @@ impl ProofKappaNu {
.chain(std::iter::once(kappa.to_bytes().as_ref())) //kappa
.chain(std::iter::once(verification_key.alpha.to_bytes().as_ref()))
.chain(beta_bytes.iter().map(|b| b.as_ref()))
.chain(std::iter::once(commitment_kappa.to_bytes().as_ref())),
.chain(std::iter::once(commitment_kappa.to_bytes().as_ref()))
.chain(std::iter::once(commitment_zeta.to_bytes().as_ref())),
);
challenge == self.challenge
@@ -481,16 +493,19 @@ impl ProofKappaNu {
// challenge || rm.len() || rm || rt
pub(crate) fn to_bytes(&self) -> Vec<u8> {
let attributes_len = self.response_attributes.len() as u64;
let mut bytes = Vec::with_capacity(8 + (attributes_len + 1) as usize * 32);
//let attributes_len = self.response_attributes.len() as u64;
let attributes_len = 2;
let mut bytes = Vec::with_capacity((attributes_len + 1) as usize * 32);
bytes.extend_from_slice(&self.challenge.to_bytes());
bytes.extend_from_slice(&self.response_serial_number.to_bytes());
bytes.extend_from_slice(&self.response_binding_number.to_bytes());
bytes.extend_from_slice(&attributes_len.to_le_bytes());
for rm in &self.response_attributes {
bytes.extend_from_slice(&rm.to_bytes());
}
// bytes.extend_from_slice(&attributes_len.to_le_bytes());
// for rm in &self.response_attributes {
// bytes.extend_from_slice(&rm.to_bytes());
// }
bytes.extend_from_slice(&self.response_blinder.to_bytes());
@@ -499,12 +514,12 @@ impl ProofKappaNu {
pub(crate) fn from_bytes(bytes: &[u8]) -> Result<Self> {
// at the very minimum there must be a single attribute being proven
if bytes.len() < 32 * 3 + 8 || (bytes.len() - 8) % 32 != 0 {
if bytes.len() < 32 * 3 || (bytes.len()) % 32 != 0 {
return Err(CoconutError::DeserializationInvalidLength {
actual: bytes.len(),
modulus_target: bytes.len() - 8,
modulus_target: bytes.len(),
modulus: 32,
object: "kappa and nu".to_string(),
object: "kappa and zeta".to_string(),
target: 32 * 3 + 8,
});
}
@@ -515,23 +530,34 @@ impl ProofKappaNu {
CoconutError::Deserialization("Failed to deserialize challenge".to_string()),
)?;
let rm_len = u64::from_le_bytes(bytes[32..40].try_into().unwrap());
if bytes[40..].len() != (rm_len + 1) as usize * 32 {
// let rm_len = u64::from_le_bytes(bytes[32..40].try_into().unwrap());
if bytes[32..].len() != (2 + 1) as usize * 32 {
return Err(
CoconutError::Deserialization(
format!("Tried to deserialize proof of kappa and nu with insufficient number of bytes provided, expected {} got {}.", (rm_len + 1) as usize * 32, bytes[40..].len())
format!("Tried to deserialize proof of kappa and zeta with insufficient number of bytes provided, expected {} got {}.", (2 + 1) as usize * 32, bytes[32..].len())
)
);
}
let rm_end = 40 + rm_len as usize * 32;
let response_attributes = try_deserialize_scalar_vec(
rm_len,
&bytes[40..rm_end],
CoconutError::Deserialization("Failed to deserialize attributes response".to_string()),
let serial_number_bytes = &bytes[32..64].try_into().unwrap();
let response_serial_number = try_deserialize_scalar(
&serial_number_bytes,
CoconutError::Deserialization("failed to deserialize the serial number".to_string()),
)?;
let blinder_bytes = bytes[rm_end..].try_into().unwrap();
let binding_number_bytes = &bytes[64..96].try_into().unwrap();
let response_binding_number = try_deserialize_scalar(
&binding_number_bytes,
CoconutError::Deserialization("failed to deserialize the binding number".to_string()),
)?;
// let rm_end = 40 + rm_len as usize * 32;
// let response_attributes = try_deserialize_scalar_vec(
// rm_len,
// &bytes[40..rm_end],
// CoconutError::Deserialization("Failed to deserialize attributes response".to_string()),
// )?;
let blinder_bytes = bytes[96..].try_into().unwrap();
let response_blinder = try_deserialize_scalar(
&blinder_bytes,
CoconutError::Deserialization("failed to deserialize the blinder".to_string()),
@@ -539,7 +565,8 @@ impl ProofKappaNu {
Ok(ProofKappaNu {
challenge,
response_attributes,
response_serial_number,
response_binding_number,
response_blinder,
})
}
@@ -558,7 +585,7 @@ mod tests {
use crate::scheme::issuance::{compute_attribute_encryption, compute_commitment_hash};
use crate::scheme::keygen::keygen;
use crate::scheme::setup::setup;
use crate::scheme::verification::compute_kappa;
use crate::scheme::verification::{compute_kappa, compute_zeta};
use super::*;
@@ -628,17 +655,21 @@ mod tests {
// we don't care about 'correctness' of the proof. only whether we can correctly recover it from bytes
let signature = Signature(params.gen1() * r, params.gen1() * s);
let private_attributes = params.n_random_scalars(1);
let serial_number = params.random_scalar();
let binding_number = params.random_scalar();
let r = params.random_scalar();
let kappa = compute_kappa(&params, &keypair.verification_key(), &private_attributes, r);
let zeta = compute_zeta(&params, serial_number);
// 0 public 1 private
// 0 public 2 private
let pi_v = ProofKappaNu::construct(
&mut params,
&keypair.verification_key(),
&private_attributes,
&binding_number,
&r,
&kappa,
&zeta
);
let bytes = pi_v.to_bytes();
@@ -648,13 +679,17 @@ mod tests {
let mut params = setup(4).unwrap();
let keypair = keygen(&mut params);
let private_attributes = params.n_random_scalars(2);
let serial_number = params.random_scalar();
let binding_number = params.random_scalar();
let pi_v = ProofKappaNu::construct(
&mut params,
&keypair.verification_key(),
&private_attributes,
&serial_number,
&binding_number,
&r,
&kappa,
&zeta
);
let bytes = pi_v.to_bytes();
+53 -35
View File
@@ -35,6 +35,8 @@ use crate::utils::{try_deserialize_g1_projective, try_deserialize_g2_projective}
pub struct Theta {
// blinded_message (kappa)
pub blinded_message: G2Projective,
// blinded serial number (zeta)
pub blinded_serial_number : G2Projective,
// sigma
pub credential: Signature,
// pi_v
@@ -45,7 +47,7 @@ impl TryFrom<&[u8]> for Theta {
type Error = CoconutError;
fn try_from(bytes: &[u8]) -> Result<Theta> {
if bytes.len() < 192 {
if bytes.len() < 288 {
return Err(
CoconutError::Deserialization(
format!("Tried to deserialize theta with insufficient number of bytes, expected >= 240, got {}", bytes.len()),
@@ -58,12 +60,18 @@ impl TryFrom<&[u8]> for Theta {
CoconutError::Deserialization("failed to deserialize kappa".to_string()),
)?;
let credential = Signature::try_from(&bytes[96..192])?;
let blinded_serial_number_bytes = bytes[96..192].try_into().unwrap();
let blinded_serial_number = try_deserialize_g2_projective(
&blinded_serial_number_bytes,
CoconutError::Deserialization("failed to deserialize zeta".to_string()),
)?;
let credential = Signature::try_from(&bytes[192..288])?;
let pi_v = ProofKappaNu::from_bytes(&bytes[192..])?;
let pi_v = ProofKappaNu::from_bytes(&bytes[288..])?;
Ok(Theta {
blinded_message,
blinded_serial_number,
credential,
pi_v,
})
@@ -76,6 +84,7 @@ impl Theta {
params,
verification_key,
&self.blinded_message,
&self.blinded_serial_number,
)
}
@@ -85,11 +94,13 @@ impl Theta {
// kappa || nu || credential || pi_v
pub fn to_bytes(&self) -> Vec<u8> {
let blinded_message_bytes = self.blinded_message.to_affine().to_compressed();
let blinded_serial_number_bytes = self.blinded_serial_number.to_affine().to_compressed();
let credential_bytes = self.credential.to_bytes();
let proof_bytes = self.pi_v.to_bytes();
let mut bytes = Vec::with_capacity(192 + proof_bytes.len());
let mut bytes = Vec::with_capacity(288 + proof_bytes.len());
bytes.extend_from_slice(&blinded_message_bytes);
bytes.extend_from_slice(&blinded_serial_number_bytes);
bytes.extend_from_slice(&credential_bytes);
bytes.extend_from_slice(&proof_bytes);
@@ -128,24 +139,23 @@ pub fn compute_kappa(
.sum::<G2Projective>()
}
pub fn compute_zeta(params: &Parameters, serial_number: Attribute) -> G2Projective {
params.gen2() * serial_number
}
pub fn prove_credential(
params: &Parameters,
verification_key: &VerificationKey,
signature: &Signature,
private_attributes: &[Attribute],
serial_number: Attribute,
binding_number: Attribute,
) -> Result<Theta> {
if private_attributes.is_empty() {
return Err(CoconutError::Verification(
"Tried to prove a credential with an empty set of private attributes".to_string(),
));
}
if private_attributes.len() > verification_key.beta.len() {
if verification_key.beta.len() < 2{
return Err(
CoconutError::Verification(
format!("Tried to prove a credential for higher than supported by the provided verification key number of attributes (max: {}, requested: {})",
verification_key.beta.len(),
private_attributes.len()
format!("Tried to prove a credential for higher than supported by the provided verification key number of attributes (max: {}, requested: 2)",
verification_key.beta.len()
)));
}
@@ -154,24 +164,30 @@ pub fn prove_credential(
// blinded_message : kappa in the paper.
// Value kappa is needed since we want to show a signature sigma'.
// In order to verify sigma' we need both the varification key vk and the message m.
// In order to verify sigma' we need both the verification key vk and the message m.
// However, we do not want to reveal m to whomever we are showing the signature.
// Thus, we need kappa which allows us to verify sigma'. In particular,
// kappa is computed on m as input, but thanks to the use or random value r,
// it does not reveal any information about m.
let blinded_message = compute_kappa(params, verification_key, private_attributes, sign_blinding_factor);
let private_attributes = vec![serial_number, binding_number];
let blinded_message = compute_kappa(params, verification_key, &private_attributes, sign_blinding_factor);
// zeta is a commitment to the serial number (i.e., a public value associated with the serial number)
let blinded_serial_number = compute_zeta(params, serial_number);
let pi_v = ProofKappaNu::construct(
params,
verification_key,
private_attributes,
&serial_number,
&binding_number,
&sign_blinding_factor,
&blinded_message,
&blinded_serial_number,
);
Ok(Theta {
blinded_message,
blinded_serial_number,
credential: signature_prime,
pi_v,
})
@@ -262,40 +278,42 @@ mod tests {
#[test]
fn theta_bytes_roundtrip() {
let mut params = setup(1).unwrap();
let mut params = setup(2).unwrap();
let keypair = keygen(&mut params);
let r = params.random_scalar();
let s = params.random_scalar();
let signature = Signature(params.gen1() * r, params.gen1() * s);
let private_attributes = params.n_random_scalars(1);
let serial_number = params.random_scalar();
let binding_number = params.random_scalar();
let theta = prove_credential(
&mut params,
&keypair.verification_key(),
&signature,
&private_attributes,
serial_number,
binding_number,
)
.unwrap();
let bytes = theta.to_bytes();
assert_eq!(Theta::try_from(bytes.as_slice()).unwrap(), theta);
let mut params = setup(4).unwrap();
let keypair = keygen(&mut params);
let private_attributes = params.n_random_scalars(2);
let theta = prove_credential(
&mut params,
&keypair.verification_key(),
&signature,
&private_attributes,
)
.unwrap();
let bytes = theta.to_bytes();
assert_eq!(Theta::try_from(bytes.as_slice()).unwrap(), theta);
// let mut params = setup(4).unwrap();
//
// let keypair = keygen(&mut params);
// let private_attributes = params.n_random_scalars(2);
//
// let theta = prove_credential(
// &mut params,
// &keypair.verification_key(),
// &signature,
// &private_attributes,
// )
// .unwrap();
//
// let bytes = theta.to_bytes();
// assert_eq!(Theta::try_from(bytes.as_slice()).unwrap(), theta);
}
}
+1
View File
@@ -191,6 +191,7 @@ async fn TEMPORARY_obtain_bandwidth_credential(
prepare_for_spending(
&identity.to_bytes(),
&bandwidth_credential,
&bandwidth_credential_attributes,
&verification_key,
)
.expect("failed to prepare bandwidth credential for spending!")