update bls12_381 dependency

This commit is contained in:
Simon Wicky
2023-10-18 14:17:16 +02:00
committed by durch
parent 954f76e241
commit dd323ce493
18 changed files with 512 additions and 75 deletions
@@ -0,0 +1,14 @@
/*
* Copyright 2023 - Nym Technologies SA <contact@nymtech.net>
* SPDX-License-Identifier: Apache-2.0
*/
CREATE TABLE ecash_credentials
(
id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
voucher_value TEXT NOT NULL,
voucher_info TEXT NOT NULL,
wallet TEXT NOT NULL UNIQUE,
epoch_id TEXT NOT NULL,
consumed BOOLEAN NOT NULL
);
@@ -1,13 +1,14 @@
// Copyright 2023 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use crate::models::CoconutCredential;
use crate::models::{CoconutCredential, EcashCredential};
use std::sync::Arc;
use tokio::sync::RwLock;
#[derive(Clone)]
pub struct CoconutCredentialManager {
inner: Arc<RwLock<Vec<CoconutCredential>>>,
ecash: Arc<RwLock<Vec<EcashCredential>>>,
}
impl CoconutCredentialManager {
@@ -15,6 +16,7 @@ impl CoconutCredentialManager {
pub fn new() -> Self {
CoconutCredentialManager {
inner: Arc::new(RwLock::new(Vec::new())),
ecash: Arc::new(RwLock::new(Vec::new())),
}
}
@@ -50,6 +52,34 @@ impl CoconutCredentialManager {
});
}
/// Inserts provided signature into the database.
///
/// # Arguments
///
/// * `voucher_value`: Plaintext bandwidth value of the credential.
/// * `voucher_info`: Plaintext information of the credential.
/// * `serial_number`: Base58 representation of the serial number attribute.
/// * `binding_number`: Base58 representation of the binding number attribute.
/// * `signature`: Coconut credential in the form of a signature.
pub async fn insert_ecash_credential(
&self,
voucher_value: String,
voucher_info: String,
wallet: String,
epoch_id: String,
) {
let mut creds = self.ecash.write().await;
let id = creds.len() as i64;
creds.push(EcashCredential {
id,
voucher_value,
voucher_info,
wallet,
epoch_id,
consumed: false,
});
}
/// Tries to retrieve one of the stored, unused credentials.
pub async fn get_next_coconut_credential(&self) -> Option<CoconutCredential> {
let creds = self.inner.read().await;
@@ -45,6 +45,29 @@ impl CoconutCredentialManager {
Ok(())
}
/// Inserts provided signature into the database.
///
/// # Arguments
///
/// * `voucher_value`: Plaintext bandwidth value of the credential.
/// * `voucher_info`: Plaintext information of the credential.
/// * `signature`: Coconut credential in the form of a signature.
pub async fn insert_ecash_credential(
&self,
voucher_value: String,
voucher_info: String,
wallet: String,
epoch_id: String,
) -> Result<(), sqlx::Error> {
sqlx::query!(
"INSERT INTO ecash_credentials(voucher_value, voucher_info, wallet, epoch_id, consumed) VALUES (?, ?, ?, ?, ?)",
voucher_value, voucher_info, wallet, epoch_id, false
)
.execute(&self.connection_pool)
.await?;
Ok(())
}
/// Tries to retrieve one of the stored, unused credentials.
pub async fn get_next_coconut_credential(
&self,
@@ -50,6 +50,20 @@ impl Storage for EphemeralStorage {
Ok(())
}
async fn insert_ecash_credential(
&self,
voucher_value: String,
voucher_info: String,
wallet: String,
epoch_id: String,
) -> Result<(), StorageError> {
self.coconut_credential_manager
.insert_ecash_credential(voucher_value, voucher_info, wallet, epoch_id)
.await;
Ok(())
}
async fn get_next_coconut_credential(&self) -> Result<CoconutCredential, StorageError> {
let credential = self
.coconut_credential_manager
+11
View File
@@ -13,3 +13,14 @@ pub struct CoconutCredential {
pub epoch_id: String,
pub consumed: bool,
}
#[derive(Clone)]
pub struct EcashCredential {
#[allow(dead_code)]
pub id: i64,
pub voucher_value: String,
pub voucher_info: String,
pub wallet: String,
pub epoch_id: String,
pub consumed: bool,
}
@@ -81,6 +81,20 @@ impl Storage for PersistentStorage {
Ok(())
}
async fn insert_ecash_credential(
&self,
voucher_value: String,
voucher_info: String,
wallet: String,
epoch_id: String,
) -> Result<(), StorageError> {
self.coconut_credential_manager
.insert_ecash_credential(voucher_value, voucher_info, wallet, epoch_id)
.await?;
Ok(())
}
async fn get_next_coconut_credential(&self) -> Result<CoconutCredential, StorageError> {
let credential = self
.coconut_credential_manager
+16
View File
@@ -29,6 +29,22 @@ pub trait Storage: Send + Sync {
epoch_id: String,
) -> Result<(), Self::StorageError>;
/// Inserts provided wallet into the database.
///
/// # Arguments
///
/// * `voucher_value`: How much bandwidth is in the credential.
/// * `voucher_info`: What type of credential it is.
/// * `signature`: Ecash wallet credential in the form of a wallet.
/// * `epoch_id`: The epoch when it was signed.
async fn insert_ecash_credential(
&self,
voucher_value: String,
voucher_info: String,
signature: String,
epoch_id: String,
) -> Result<(), Self::StorageError>;
/// Tries to retrieve one of the stored, unused credentials.
async fn get_next_coconut_credential(&self) -> Result<CoconutCredential, Self::StorageError>;
+2 -1
View File
@@ -8,13 +8,14 @@ edition = "2021"
[dependencies]
#bls12_381 = { version = "0.5", default-features = false, features = ["pairings", "alloc", "experimental"] }
bls12_381 = { path = "/Users/ania/Documents/Git/andrew_bls12_381", default-features = false, features = ["alloc", "pairings", "experimental", "zeroize"] }
bls12_381 = { path = "/Users/simon/Documents/Nym/github/andrew_bls12_381", default-features = false, features = ["alloc", "pairings", "experimental", "zeroize"] }
itertools = "0.10"
digest = "0.9"
rand = "0.8"
thiserror = "1.0"
sha2 = "0.9"
bs58 = "0.4.0"
serde = "1.0.189"
[dev-dependencies]
criterion = { version = "0.3", features = ["html_reports"] }
@@ -31,10 +31,13 @@ pub enum CompactEcashError {
#[error("Identify Verification related error: {0}")]
Identify(String),
#[error("Could not decode base 58 string - {0}")]
MalformedString(#[from] bs58::decode::Error),
#[error(
"Deserailization error, expected at least {} bytes, got {}",
min,
actual
"Deserailization error, expected at least {} bytes, got {}",
min,
actual
)]
DeserializationMinLength { min: usize, actual: usize },
@@ -0,0 +1,14 @@
use crate::scheme::withdrawal::WithdrawalRequest;
use crate::traits::Bytable;
macro_rules! impl_clone {
($struct:ident) => {
impl Clone for $struct {
fn clone(&self) -> Self {
Self::try_from_byte_slice(&self.to_byte_vec()).unwrap()
}
}
};
}
impl_clone!(WithdrawalRequest);
@@ -0,0 +1,2 @@
mod clone;
mod serde;
@@ -0,0 +1,47 @@
use crate::traits::Base58;
use serde::de::Unexpected;
use serde::{de::Error, de::Visitor, Deserialize, Deserializer, Serialize, Serializer};
use std::fmt;
use crate::scheme::withdrawal::WithdrawalRequest;
macro_rules! impl_serde {
($struct:ident, $visitor:ident) => {
pub struct $visitor {}
impl Serialize for $struct {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
serializer.serialize_str(&self.to_bs58())
}
}
impl<'de> Visitor<'de> for $visitor {
type Value = $struct;
fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(formatter, "A base58 encoded struct")
}
fn visit_str<E: Error>(self, s: &str) -> Result<Self::Value, E> {
match $struct::try_from_bs58(s) {
Ok(x) => Ok(x),
Err(_) => Err(Error::invalid_value(Unexpected::Str(s), &self)),
}
}
}
impl<'de> Deserialize<'de> for $struct {
fn deserialize<D>(deserializer: D) -> Result<$struct, D::Error>
where
D: Deserializer<'de>,
{
deserializer.deserialize_str($visitor {})
}
}
};
}
impl_serde!(WithdrawalRequest, V1);
+7 -6
View File
@@ -5,27 +5,28 @@ use bls12_381::Scalar;
pub use scheme::aggregation::aggregate_verification_keys;
pub use scheme::aggregation::aggregate_wallets;
pub use scheme::identify;
pub use scheme::keygen::{PublicKeyUser, SecretKeyUser, VerificationKeyAuth};
pub use scheme::keygen::generate_keypair_user;
pub use scheme::keygen::ttp_keygen;
pub use scheme::PartialWallet;
pub use scheme::PayInfo;
pub use scheme::keygen::{PublicKeyUser, SecretKeyUser, VerificationKeyAuth};
pub use scheme::setup;
pub use scheme::withdrawal::issue_verify;
pub use scheme::withdrawal::issue_wallet;
pub use scheme::withdrawal::withdrawal_request;
pub use scheme::PartialWallet;
pub use scheme::PayInfo;
pub use traits::Base58;
use crate::error::CompactEcashError;
use crate::traits::Bytable;
mod error;
pub mod error;
mod impls;
mod proofs;
mod scheme;
pub mod scheme;
#[cfg(test)]
mod tests;
mod traits;
mod utils;
pub mod utils;
pub type Attribute = Scalar;
@@ -5,17 +5,18 @@ use std::convert::TryFrom;
use std::convert::TryInto;
use bls12_381::{G1Projective, G2Projective, Scalar};
use group::Curve;
use group::{Curve, GroupEncoding};
use crate::error::{CompactEcashError, Result};
use crate::scheme::aggregation::aggregate_verification_keys;
use crate::scheme::setup::GroupParameters;
use crate::scheme::SignerIndex;
use crate::traits::Bytable;
use crate::utils::Polynomial;
use crate::utils::{
try_deserialize_g1_projective, try_deserialize_g2_projective, try_deserialize_scalar,
try_deserialize_scalar_vec,
};
use crate::utils::Polynomial;
#[derive(Debug, PartialEq, Clone)]
pub struct SecretKeyAuth {
@@ -242,13 +243,13 @@ impl<'a> Mul<Scalar> for &'a VerificationKeyAuth {
}
impl<T> Sum<T> for VerificationKeyAuth
where
T: Borrow<VerificationKeyAuth>,
where
T: Borrow<VerificationKeyAuth>,
{
#[inline]
fn sum<I>(iter: I) -> Self
where
I: Iterator<Item=T>,
where
I: Iterator<Item = T>,
{
let mut peekable = iter.peekable();
let head_attributes = match peekable.peek() {
@@ -330,6 +331,15 @@ impl SecretKeyUser {
pk: params.gen1() * self.sk,
}
}
pub fn to_bytes(&self) -> Vec<u8> {
self.sk.to_bytes().to_vec()
}
pub fn from_bytes(bytes: &[u8]) -> Result<Self> {
let sk = Scalar::try_from_byte_slice(bytes)?;
Ok(SecretKeyUser { sk })
}
}
#[derive(Debug, Eq, PartialEq, Clone, Hash)]
@@ -337,6 +347,39 @@ pub struct PublicKeyUser {
pub(crate) pk: G1Projective,
}
impl PublicKeyUser {
pub fn to_base58_string(&self) -> String {
bs58::encode(&self.pk.to_bytes()).into_string()
}
pub fn from_base58_string<I: AsRef<[u8]>>(val: I) -> Result<Self> {
let bytes = bs58::decode(val)
.into_vec()
.map_err(|source| CompactEcashError::Deserialization(source.to_string()))?;
Self::from_bytes(&bytes)
}
pub fn to_bytes(&self) -> Vec<u8> {
self.pk.to_affine().to_compressed().to_vec()
}
pub fn from_bytes(bytes: &[u8]) -> Result<Self> {
if bytes.len() != 48 {
return Err(CompactEcashError::Deserialization(
"Failed to deserialize : Invalid length".to_string(),
));
}
let pk_bytes: &[u8; 48] = bytes[..48].try_into().unwrap();
let pk = try_deserialize_g1_projective(
pk_bytes,
CompactEcashError::Deserialization(
"Failed to deserialize verification key G1 point".to_string(),
),
)?;
Ok(PublicKeyUser { pk })
}
}
pub struct KeyPairAuth {
secret_key: SecretKeyAuth,
verification_key: VerificationKeyAuth,
@@ -345,6 +388,17 @@ pub struct KeyPairAuth {
}
impl KeyPairAuth {
pub fn new(
sk: SecretKeyAuth,
vk: VerificationKeyAuth,
index: Option<SignerIndex>,
) -> KeyPairAuth {
KeyPairAuth {
secret_key: sk,
verification_key: vk,
index,
}
}
pub fn secret_key(&self) -> SecretKeyAuth {
self.secret_key.clone()
}
@@ -367,6 +421,24 @@ impl KeyPairUser {
pub fn public_key(&self) -> PublicKeyUser {
self.public_key.clone()
}
pub fn to_bytes(&self) -> Vec<u8> {
[self.secret_key.to_bytes(), self.public_key.to_bytes()].concat()
}
pub fn from_bytes(bytes: &[u8]) -> Result<Self> {
if bytes.len() != 32 + 48 {
return Err(CompactEcashError::Deserialization(
"Failed to deserialize keypair : Invalid length".to_string(),
));
}
let sk = SecretKeyUser::from_bytes(&bytes[..32])?;
let pk = PublicKeyUser::from_bytes(&bytes[32..32 + 48])?;
Ok(KeyPairUser {
secret_key: sk,
public_key: pk,
})
}
}
pub fn generate_keypair_user(params: &GroupParameters) -> KeyPairUser {
@@ -3,15 +3,16 @@ use std::cell::Cell;
use bls12_381::{G1Projective, G2Prepared, G2Projective, Scalar};
use group::Curve;
use crate::Attribute;
use crate::error::{CompactEcashError, Result};
use crate::proofs::proof_spend::{SpendInstance, SpendProof, SpendWitness};
use crate::scheme::keygen::{SecretKeyUser, VerificationKeyAuth};
use crate::scheme::setup::{GroupParameters, Parameters};
use crate::traits::Bytable;
use crate::utils::{
check_bilinear_pairing, hash_to_scalar, Signature, SignerIndex,
try_deserialize_g1_projective, try_deserialize_scalar, try_deserialize_g2_projective,
check_bilinear_pairing, hash_to_scalar, try_deserialize_g1_projective,
try_deserialize_g2_projective, try_deserialize_scalar, Signature, SignerIndex,
};
use crate::{Attribute, Base58};
pub mod aggregation;
pub mod identify;
@@ -36,7 +37,7 @@ impl PartialWallet {
pub fn index(&self) -> Option<SignerIndex> {
self.idx
}
pub fn to_bytes(&self) -> [u8; 136]{
pub fn to_bytes(&self) -> [u8; 136] {
let mut bytes = [0u8; 136];
bytes[0..96].copy_from_slice(&self.sig.to_bytes());
bytes[96..128].copy_from_slice(&self.v.to_bytes());
@@ -66,15 +67,11 @@ impl TryFrom<&[u8]> for PartialWallet {
let sig = Signature::try_from(sig_bytes.as_slice()).unwrap();
let v = Scalar::from_bytes(&v_bytes).unwrap();
let idx = None;
if !idx_bytes.iter().all(|&x| x == 0){
if !idx_bytes.iter().all(|&x| x == 0) {
let idx = Some(u64::from_le_bytes(*idx_bytes));
}
Ok(PartialWallet{
sig,
v,
idx,
})
Ok(PartialWallet { sig, v, idx })
}
}
@@ -98,7 +95,7 @@ impl Wallet {
self.l.get()
}
pub fn to_bytes(&self) -> [u8; 136]{
pub fn to_bytes(&self) -> [u8; 136] {
let mut bytes = [0u8; 136];
bytes[0..96].copy_from_slice(&self.sig.to_bytes());
bytes[96..128].copy_from_slice(&self.v.to_bytes());
@@ -109,7 +106,6 @@ impl Wallet {
self.l.set(self.l.get() + 1);
}
pub fn spend(
&self,
params: &Parameters,
@@ -144,7 +140,6 @@ impl Wallet {
// compute commitments C
let cc = grparams.gen1() * o_c + grparams.gamma1() * self.v();
let mut aa: Vec<G1Projective> = Default::default();
let mut ss: Vec<G1Projective> = Default::default();
let mut tt: Vec<G1Projective> = Default::default();
@@ -172,8 +167,8 @@ impl Wallet {
// evaluate the pseudorandom functions
let ss_k = pseudorandom_f_delta_v(&grparams, self.v(), self.l() + k);
ss.push(ss_k);
let tt_k =
grparams.gen1() * sk_user.sk + pseudorandom_f_g_v(&grparams, self.v(), self.l() + k) * rr_k;
let tt_k = grparams.gen1() * sk_user.sk
+ pseudorandom_f_g_v(&grparams, self.v(), self.l() + k) * rr_k;
tt.push(tt_k);
// compute values mu, o_mu, lambda, o_lambda
@@ -198,7 +193,6 @@ impl Wallet {
kappa_k_vec.push(kappa_k);
}
// construct the zkp proof
let spend_instance = SpendInstance {
kappa,
@@ -274,14 +268,22 @@ impl TryFrom<&[u8]> for Wallet {
let v = Scalar::from_bytes(&v_bytes).unwrap();
let l = Cell::new(u64::from_le_bytes(*l_bytes));
Ok(Wallet{
sig,
v,
l
})
Ok(Wallet { sig, v, l })
}
}
impl Bytable for Wallet {
fn to_byte_vec(&self) -> Vec<u8> {
self.to_bytes().to_vec()
}
fn try_from_byte_slice(slice: &[u8]) -> std::result::Result<Self, CompactEcashError> {
Wallet::try_from(slice)
}
}
impl Base58 for Wallet {}
pub fn pseudorandom_f_delta_v(params: &GroupParameters, v: Scalar, l: u64) -> G1Projective {
let pow = (v + Scalar::from(l) + Scalar::from(1)).invert().unwrap();
params.delta() * pow
@@ -301,10 +303,10 @@ pub fn compute_kappa(
params.gen2() * blinding_factor
+ verification_key.alpha
+ attributes
.iter()
.zip(verification_key.beta_g2.iter())
.map(|(priv_attr, beta_i)| beta_i * priv_attr)
.sum::<G2Projective>()
.iter()
.zip(verification_key.beta_g2.iter())
.map(|(priv_attr, beta_i)| beta_i * priv_attr)
.sum::<G2Projective>()
}
#[derive(PartialEq, Eq, Debug, Clone)]
@@ -405,25 +407,38 @@ impl Payment {
let sig_bytes = self.sig.to_bytes();
let cc_bytes = self.cc.to_affine().to_compressed();
let vv_bytes: [u8; 8] = self.vv.to_le_bytes();
let ss_len = self.ss.len() as u64;
let tt_len = self.tt.len() as u64;
let aa_len = self.aa.len() as u64;
let rr_len = self.rr.len() as u64;
let ss_len = self.ss.len() as u64;
let tt_len = self.tt.len() as u64;
let aa_len = self.aa.len() as u64;
let rr_len = self.rr.len() as u64;
let kappa_k_len = self.kappa_k.len() as u64;
let sig_lk_len = self.sig_lk.len() as u64;
let zk_proof_bytes = self.zk_proof.to_bytes();
let zk_proof_bytes_len = self.zk_proof.to_bytes().len() as u64;
let mut bytes: Vec<u8> = Vec::with_capacity(
(96 + 96 + 48 + 8 + ss_len * 48 + 8 + tt_len * 48 + 8 + aa_len * 48 + 8 + rr_len * 32 + 8 + kappa_k_len * 96 + 8 + sig_lk_len * 96 + zk_proof_bytes_len) as usize);
(96 + 96
+ 48
+ 8
+ ss_len * 48
+ 8
+ tt_len * 48
+ 8
+ aa_len * 48
+ 8
+ rr_len * 32
+ 8
+ kappa_k_len * 96
+ 8
+ sig_lk_len * 96
+ zk_proof_bytes_len) as usize,
);
bytes.extend_from_slice(&kappa_bytes);
bytes.extend_from_slice(&sig_bytes);
bytes.extend_from_slice(&cc_bytes);
bytes.extend_from_slice(&vv_bytes);
let ss_len_bytes = ss_len.to_le_bytes();
bytes.extend_from_slice(&ss_len_bytes);
for s in &self.ss {
@@ -506,7 +521,7 @@ impl TryFrom<&[u8]> for Payment {
idx += 48;
}
let tt_len = u64::from_le_bytes(bytes[idx..idx+8].try_into().unwrap()) as usize;
let tt_len = u64::from_le_bytes(bytes[idx..idx + 8].try_into().unwrap()) as usize;
idx += 8;
let mut tt = Vec::with_capacity(tt_len);
for _ in 0..tt_len {
@@ -519,7 +534,7 @@ impl TryFrom<&[u8]> for Payment {
idx += 48;
}
let aa_len = u64::from_le_bytes(bytes[idx..idx+8].try_into().unwrap()) as usize;
let aa_len = u64::from_le_bytes(bytes[idx..idx + 8].try_into().unwrap()) as usize;
idx += 8;
let mut aa = Vec::with_capacity(aa_len);
for _ in 0..aa_len {
@@ -532,7 +547,7 @@ impl TryFrom<&[u8]> for Payment {
idx += 48;
}
let rr_len = u64::from_le_bytes(bytes[idx..idx+8].try_into().unwrap()) as usize;
let rr_len = u64::from_le_bytes(bytes[idx..idx + 8].try_into().unwrap()) as usize;
idx += 8;
let mut rr = Vec::with_capacity(rr_len);
for _ in 0..rr_len {
@@ -545,21 +560,23 @@ impl TryFrom<&[u8]> for Payment {
idx += 32;
}
let kappa_k_len = u64::from_le_bytes(bytes[idx..idx+8].try_into().unwrap()) as usize;
let kappa_k_len = u64::from_le_bytes(bytes[idx..idx + 8].try_into().unwrap()) as usize;
idx += 8;
let mut kappa_k = Vec::with_capacity(kappa_k_len);
for _ in 0..kappa_k_len {
let kappa_k_bytes: [u8; 96] = bytes[idx..idx + 96].try_into().unwrap();
let kappa_k_elem = try_deserialize_g2_projective(
&kappa_k_bytes,
CompactEcashError::Deserialization("Failed to deserialize kappa_k element".to_string()),
CompactEcashError::Deserialization(
"Failed to deserialize kappa_k element".to_string(),
),
)?;
kappa_k.push(kappa_k_elem);
idx += 96;
}
// sig_lk
let sig_lk_len = u64::from_le_bytes(bytes[idx..idx+8].try_into().unwrap()) as usize;
let sig_lk_len = u64::from_le_bytes(bytes[idx..idx + 8].try_into().unwrap()) as usize;
idx += 8;
let mut sig_lk = Vec::with_capacity(sig_lk_len);
for _ in 0..sig_lk_len {
@@ -590,4 +607,4 @@ impl TryFrom<&[u8]> for Payment {
Ok(payment)
}
}
}
@@ -6,10 +6,14 @@ use crate::proofs::proof_withdrawal::{
WithdrawalReqInstance, WithdrawalReqProof, WithdrawalReqWitness,
};
use crate::scheme::keygen::{PublicKeyUser, SecretKeyAuth, SecretKeyUser, VerificationKeyAuth};
use crate::scheme::PartialWallet;
use crate::scheme::setup::GroupParameters;
use crate::utils::{check_bilinear_pairing, hash_g1, try_deserialize_g1_projective};
use crate::scheme::PartialWallet;
use crate::traits::Bytable;
use crate::utils::{
check_bilinear_pairing, hash_g1, try_deserialize_g1_projective, try_deserialize_scalar,
};
use crate::utils::{BlindedSignature, Signature};
use crate::Base58;
#[derive(Debug, PartialEq)]
pub struct WithdrawalRequest {
@@ -20,13 +24,14 @@ pub struct WithdrawalRequest {
}
impl WithdrawalRequest {
pub fn to_bytes(&self) -> Vec<u8>{
pub fn to_bytes(&self) -> Vec<u8> {
let com_hash_bytes = self.com_hash.to_affine().to_compressed();
let com_bytes = self.com.to_affine().to_compressed();
let pr_coms_len = self.pc_coms.len() as u64;
let zk_proof_bytes = self.zk_proof.to_bytes();
let mut bytes = Vec::with_capacity(48 + 48 + 8 + pr_coms_len as usize * 48 + zk_proof_bytes.len());
let mut bytes =
Vec::with_capacity(48 + 48 + 8 + pr_coms_len as usize * 48 + zk_proof_bytes.len());
bytes.extend_from_slice(&com_hash_bytes);
bytes.extend_from_slice(&com_bytes);
bytes.extend_from_slice(&pr_coms_len.to_le_bytes());
@@ -37,7 +42,6 @@ impl WithdrawalRequest {
bytes.extend_from_slice(&zk_proof_bytes);
bytes
}
}
@@ -45,7 +49,7 @@ impl TryFrom<&[u8]> for WithdrawalRequest {
type Error = CompactEcashError;
fn try_from(bytes: &[u8]) -> Result<WithdrawalRequest> {
if bytes.len() < 48 + 48 + 8 + 48{
if bytes.len() < 48 + 48 + 8 + 48 {
return Err(CompactEcashError::DeserializationMinLength {
min: 48 + 48 + 8 + 48,
actual: bytes.len(),
@@ -100,7 +104,7 @@ impl TryFrom<&[u8]> for WithdrawalRequest {
let zk_proof = WithdrawalReqProof::try_from(&bytes[j + pc_len as usize * 48..])?;
Ok(WithdrawalRequest{
Ok(WithdrawalRequest {
com_hash,
com,
pc_coms,
@@ -109,6 +113,18 @@ impl TryFrom<&[u8]> for WithdrawalRequest {
}
}
impl Bytable for WithdrawalRequest {
fn to_byte_vec(&self) -> Vec<u8> {
self.to_bytes()
}
fn try_from_byte_slice(slice: &[u8]) -> Result<Self> {
WithdrawalRequest::try_from(slice)
}
}
impl Base58 for WithdrawalRequest {}
pub struct RequestInfo {
com_hash: G1Projective,
com_opening: Scalar,
@@ -129,6 +145,104 @@ impl RequestInfo {
pub fn get_v(&self) -> Scalar {
self.v
}
pub fn to_bytes(&self) -> Vec<u8> {
let com_hash_bytes = self.com_hash.to_affine().to_compressed();
let com_opening_bytes = self.com_opening.to_bytes();
let pr_coms_openings_len = self.pc_coms_openings.len() as u64;
let v_bytes = self.v.to_bytes();
let mut bytes = Vec::with_capacity(48 + 32 + 8 + pr_coms_openings_len as usize * 32 + 32);
bytes.extend_from_slice(&com_hash_bytes);
bytes.extend_from_slice(&com_opening_bytes);
bytes.extend_from_slice(&pr_coms_openings_len.to_le_bytes());
for c in &self.pc_coms_openings {
bytes.extend_from_slice(&c.to_bytes());
}
bytes.extend_from_slice(&v_bytes);
bytes
}
}
impl TryFrom<&[u8]> for RequestInfo {
type Error = CompactEcashError;
fn try_from(bytes: &[u8]) -> Result<RequestInfo> {
if bytes.len() < 48 + 32 + 8 + 32 {
return Err(CompactEcashError::DeserializationMinLength {
min: 48 + 32 + 8 + 32,
actual: bytes.len(),
});
}
let mut j = 0;
let commitment_hash_bytes_len = 48;
let com_hash_bytes = bytes[j..j + commitment_hash_bytes_len].try_into().unwrap();
let com_hash = try_deserialize_g1_projective(
&com_hash_bytes,
CompactEcashError::Deserialization(
"Failed to deserialize compressed commitment hash".to_string(),
),
)?;
j += commitment_hash_bytes_len;
let com_opening_bytes_len = 32;
let com_opening_bytes = bytes[j..j + com_opening_bytes_len].try_into().unwrap();
let com_opening = try_deserialize_scalar(
&com_opening_bytes,
CompactEcashError::Deserialization(
"Failed to deserialize commitment opening".to_string(),
),
)?;
j += com_opening_bytes_len;
let pc_coms_openings_len = u64::from_le_bytes(bytes[j..j + 8].try_into().unwrap());
j += 8;
if bytes[j..].len() < pc_coms_openings_len as usize * 32 {
return Err(CompactEcashError::DeserializationMinLength {
min: pc_coms_openings_len as usize * 32,
actual: bytes[j..].len(),
});
}
let mut pc_coms_openings = Vec::with_capacity(pc_coms_openings_len as usize);
for i in 0..pc_coms_openings_len as usize {
let start = j + i * 32;
let end = start + 32;
let pc_com_opening_bytes = bytes[start..end].try_into().unwrap();
let pc_com_opening = try_deserialize_scalar(
&pc_com_opening_bytes,
CompactEcashError::Deserialization(
"Failed to deserialize compressed Pedersen commitment opening".to_string(),
),
)?;
pc_coms_openings.push(pc_com_opening)
}
j += pc_coms_openings_len as usize * 32;
let v_len = 32;
if bytes[j..].len() != v_len {
return Err(CompactEcashError::DeserializationMinLength {
min: v_len,
actual: bytes[j..].len(),
});
}
let v_bytes = bytes[j..j + v_len].try_into().unwrap();
let v = try_deserialize_scalar(
v_bytes,
CompactEcashError::Deserialization("Failed to deserialize v".to_string()),
)?;
Ok(RequestInfo {
com_hash,
com_opening,
pc_coms_openings,
v,
})
}
}
pub fn withdrawal_request(
@@ -142,10 +256,10 @@ pub fn withdrawal_request(
let com_opening = params.random_scalar();
let com = params.gen1() * com_opening
+ attributes
.iter()
.zip(gammas)
.map(|(&m, gamma)| gamma * m)
.sum::<G1Projective>();
.iter()
.zip(gammas)
.map(|(&m, gamma)| gamma * m)
.sum::<G1Projective>();
// Value h in the paper
let com_hash = hash_g1(com.to_bytes());
@@ -286,4 +400,3 @@ pub fn issue_verify(
idx: None,
})
}
+51 -6
View File
@@ -6,10 +6,10 @@ use core::ops::Mul;
use std::convert::{TryFrom, TryInto};
use std::ops::Neg;
use bls12_381::{
G1Affine, G1Projective, G2Affine, G2Prepared, G2Projective, multi_miller_loop, Scalar,
};
use bls12_381::hash_to_curve::{ExpandMsgXmd, HashToCurve, HashToField};
use bls12_381::{
multi_miller_loop, G1Affine, G1Projective, G2Affine, G2Prepared, G2Projective, Scalar,
};
use ff::Field;
use group::{Curve, Group};
@@ -85,9 +85,9 @@ pub(crate) fn perform_lagrangian_interpolation_at_origin<T>(
points: &[SignerIndex],
values: &[T],
) -> Result<T>
where
T: Sum,
for<'a> &'a T: Mul<Scalar, Output=T>,
where
T: Sum,
for<'a> &'a T: Mul<Scalar, Output = T>,
{
if points.is_empty() || values.is_empty() {
return Err(CompactEcashError::Interpolation(
@@ -276,6 +276,51 @@ impl Bytable for Signature {
#[cfg_attr(test, derive(PartialEq))]
pub struct BlindedSignature(pub(crate) G1Projective, pub(crate) G1Projective);
impl TryFrom<&[u8]> for BlindedSignature {
type Error = CompactEcashError;
fn try_from(bytes: &[u8]) -> Result<BlindedSignature> {
if bytes.len() != 96 {
return Err(CompactEcashError::Deserialization(format!(
"BlindedSignature must be exactly 96 bytes, got {}",
bytes.len()
)));
}
let bsig1_bytes: &[u8; 48] = &bytes[..48].try_into().expect("Slice size != 48");
let bsig2_bytes: &[u8; 48] = &bytes[48..].try_into().expect("Slice size != 48");
let bsig1 = try_deserialize_g1_projective(
bsig1_bytes,
CompactEcashError::Deserialization(
"Failed to deserialize compressed bsig1".to_string(),
),
)?;
let bsig2 = try_deserialize_g1_projective(
bsig2_bytes,
CompactEcashError::Deserialization(
"Failed to deserialize compressed bsig2".to_string(),
),
)?;
Ok(BlindedSignature(bsig1, bsig2))
}
}
impl BlindedSignature {
pub fn to_bytes(&self) -> [u8; 96] {
let mut bytes = [0u8; 96];
bytes[..48].copy_from_slice(&self.0.to_affine().to_compressed());
bytes[48..].copy_from_slice(&self.1.to_affine().to_compressed());
bytes
}
pub fn from_bytes(bytes: &[u8]) -> Result<BlindedSignature> {
BlindedSignature::try_from(bytes)
}
}
pub struct SignatureShare {
signature: Signature,
index: SignerIndex,
@@ -8,7 +8,7 @@ edition = "2021"
[dependencies]
#bls12_381 = { git = "https://github.com/jstuczyn/bls12_381", branch = "gt-serialisation", default-features = false, features = ["alloc", "pairings", "experimental", "zeroize"] }
bls12_381 = { path = "/Users/ania/Documents/Git/andrew_bls12_381", default-features = false, features = ["alloc", "pairings", "experimental", "zeroize"] }
bls12_381 = { path = "/Users/simon/Documents/Nym/github/andrew_bls12_381", default-features = false, features = ["alloc", "pairings", "experimental", "zeroize"] }
itertools = "0.10"
digest = "0.9"
rand = "0.8"