update bls12_381 dependency
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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>;
|
||||
|
||||
|
||||
@@ -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);
|
||||
@@ -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,
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -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"
|
||||
|
||||
Reference in New Issue
Block a user