From bea8e4a8810b39bc2a8edbcb61bef26fec18a466 Mon Sep 17 00:00:00 2001 From: aniampio Date: Mon, 21 Mar 2022 18:09:05 +0000 Subject: [PATCH] Add initial functions --- .DS_Store | Bin 0 -> 8196 bytes Cargo.toml | 1 + common/nym-compact-ecash/Cargo.toml | 14 +- common/nym-compact-ecash/src/error.rs | 24 +++ common/nym-compact-ecash/src/lib.rs | 8 +- common/nym-compact-ecash/src/main.rs | 3 - common/nym-compact-ecash/src/proofs/mod.rs | 4 + common/nym-compact-ecash/src/scheme/keygen.rs | 171 ++++++++++++++++++ common/nym-compact-ecash/src/scheme/mod.rs | 8 +- common/nym-compact-ecash/src/scheme/setup.rs | 49 ++++- .../src/scheme/withdrawal.rs | 88 +++++++++ common/nym-compact-ecash/src/tests/e2e.rs | 0 common/nym-compact-ecash/src/tests/mod.rs | 1 + common/nym-compact-ecash/src/utils.rs | 77 ++++++++ common/nymcoconut/src/lib.rs | 13 +- common/nymcoconut/src/utils.rs | 18 +- 16 files changed, 462 insertions(+), 17 deletions(-) create mode 100644 .DS_Store create mode 100644 common/nym-compact-ecash/src/error.rs delete mode 100644 common/nym-compact-ecash/src/main.rs create mode 100644 common/nym-compact-ecash/src/proofs/mod.rs create mode 100644 common/nym-compact-ecash/src/tests/e2e.rs create mode 100644 common/nym-compact-ecash/src/tests/mod.rs create mode 100644 common/nym-compact-ecash/src/utils.rs diff --git a/.DS_Store b/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..982829a9ace8c734aa4e322bdb5540432e51b5a1 GIT binary patch literal 8196 zcmeHM+iuf95S>j+;xuVh5J;5}$P%wjNUEwr;w4QRK_xCygWv&BaV{+;t{pi}Lsb>! z9l0 zNd@@+U}Irhi|trhdFwzYrvR|?*ex5@F%OU&JGQmhj+K>EoKwvnL`)U&6hkOFj@t}} zt;Ke%tfG@pbP};=5zkPB^bVda;UsFxn%*d26qr4C_?ov~1cBE&TX$M7-R@{_`Q}#OM~>@vLrHKuT|nNv za{W#)ss}^AGmzY-I$-6k{ND2Ilao?){lWUGy|!LCUA0fDm9>pkd!xE`dYZRx-MjyA zcdzFi`oR~3fF|PmD=n(+^ZqN=5)vFWL*EO0mWereDGx+PayVE|ehNBErEgj)WvQdm z2Nx?$3Mx}b$KKGfREjS}AAC;RG9AxIDg7K4kRPcplQx|6DL9pMd@+rOUk7|QIaa}G zrSozq4hQjfX#{(mM9Z|&(F+(4;zznVh~op|nVw!c$3j8upg9 z7}t!*S=$6JPrHbBleQ62W7-XY^-VBxP_zwwU3i?xNiN(3`nt@gkdAwjw zW#x5l0r-I&ovwc>Dyh59T7&`)t}Ls-xg9`>snsC$*O__b2FK;&YE6Ay$ZMc8P)?>@ zh5~cS$w~pXG5h=fWemmmFbWt2{*eM=e!IC{hx4;{zw|hGu5Dv^hlLyC#>z?xIyoJO tmD6$9^FIu+ZUf4kT5QM4Vh`G-e+W4Ldy-%B>Qqf0^gMOvWqJ{RKR!MDPFr literal 0 HcmV?d00001 diff --git a/Cargo.toml b/Cargo.toml index 4d786023d4..69caaf4b7f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -56,6 +56,7 @@ members = [ "common/node-tester-utils", "common/nonexhaustive-delayqueue", "common/nymcoconut", + "common/nym-compact-ecash", "common/nymsphinx", "common/nymsphinx/acknowledgements", "common/nymsphinx/addressing", diff --git a/common/nym-compact-ecash/Cargo.toml b/common/nym-compact-ecash/Cargo.toml index e678081a14..45df1b19fe 100644 --- a/common/nym-compact-ecash/Cargo.toml +++ b/common/nym-compact-ecash/Cargo.toml @@ -8,6 +8,18 @@ edition = "2021" [dependencies] bls12_381 = { version = "0.5", default-features = false, features = ["pairings", "alloc", "experimental"] } +nymcoconut = { path = "../nymcoconut" } +rand = "0.8" +thiserror = "1.0" +sha2 = "0.9" [dev-dependencies] -criterion = { version = "0.3", features = ["html_reports"] } \ No newline at end of file +criterion = { version = "0.3", features = ["html_reports"] } + +[dependencies.ff] +version = "0.10" +default-features = false + +[dependencies.group] +version = "0.10" +default-features = false \ No newline at end of file diff --git a/common/nym-compact-ecash/src/error.rs b/common/nym-compact-ecash/src/error.rs new file mode 100644 index 0000000000..0ff3c4733a --- /dev/null +++ b/common/nym-compact-ecash/src/error.rs @@ -0,0 +1,24 @@ +use thiserror::Error; + +pub type Result = std::result::Result; + +#[derive(Error, Debug)] +pub enum CompactEcashError { + #[error("Setup error: {0}")] + Setup(String), + + #[error("Withdrawal Request Verification related error: {0}")] + WithdrawalVerification(String), + + #[error("Deserialization error: {0}")] + Deserialization(String), + + #[error("Tried to deserialize {object} with bytes of invalid length. Expected {actual} < {} or {modulus_target} % {modulus} == 0")] + DeserializationInvalidLength { + actual: usize, + target: usize, + modulus_target: usize, + modulus: usize, + object: String, + }, +} \ No newline at end of file diff --git a/common/nym-compact-ecash/src/lib.rs b/common/nym-compact-ecash/src/lib.rs index 3fbbea1744..970a074a42 100644 --- a/common/nym-compact-ecash/src/lib.rs +++ b/common/nym-compact-ecash/src/lib.rs @@ -1,2 +1,8 @@ +pub use nymcoconut::*; + +mod error; mod proofs; -mod scheme; \ No newline at end of file +mod scheme; +mod utils; +#[cfg(test)] +mod tests; \ No newline at end of file diff --git a/common/nym-compact-ecash/src/main.rs b/common/nym-compact-ecash/src/main.rs deleted file mode 100644 index e7a11a969c..0000000000 --- a/common/nym-compact-ecash/src/main.rs +++ /dev/null @@ -1,3 +0,0 @@ -fn main() { - println!("Hello, world!"); -} diff --git a/common/nym-compact-ecash/src/proofs/mod.rs b/common/nym-compact-ecash/src/proofs/mod.rs new file mode 100644 index 0000000000..94fe728571 --- /dev/null +++ b/common/nym-compact-ecash/src/proofs/mod.rs @@ -0,0 +1,4 @@ +/// Instances: +/// Statement: +/// Witnesses: +pub struct WithdrawalProof {} \ No newline at end of file diff --git a/common/nym-compact-ecash/src/scheme/keygen.rs b/common/nym-compact-ecash/src/scheme/keygen.rs index e69de29bb2..849b5eec53 100644 --- a/common/nym-compact-ecash/src/scheme/keygen.rs +++ b/common/nym-compact-ecash/src/scheme/keygen.rs @@ -0,0 +1,171 @@ +use std::convert::TryFrom; +use std::convert::TryInto; + +use bls12_381::{G1Projective, G2Projective, Scalar}; + +use crate::error::{CompactEcashError, Result}; +use crate::scheme::setup::Parameters; +use crate::utils::{try_deserialize_g1_projective, try_deserialize_g2_projective, try_deserialize_scalar, try_deserialize_scalar_vec}; + +pub struct SecretKeyAuth { + pub(crate) x: Scalar, + pub(crate) ys: Vec, +} + +impl TryFrom<&[u8]> for SecretKeyAuth { + type Error = CompactEcashError; + + fn try_from(bytes: &[u8]) -> Result { + // There should be x and at least one y + if bytes.len() < 32 * 2 + 8 || (bytes.len() - 8) % 32 != 0 { + return Err(CompactEcashError::DeserializationInvalidLength { + actual: bytes.len(), + modulus_target: bytes.len() - 8, + target: 32 * 2 + 8, + modulus: 32, + object: "secret key".to_string(), + }); + } + + // this conversion will not fail as we are taking the same length of data + let x_bytes: [u8; 32] = bytes[..32].try_into().unwrap(); + let ys_len = u64::from_le_bytes(bytes[32..40].try_into().unwrap()); + let actual_ys_len = (bytes.len() - 40) / 32; + + if ys_len as usize != actual_ys_len { + return Err(CompactEcashError::Deserialization(format!( + "Tried to deserialize secret key with inconsistent ys len (expected {}, got {})", + ys_len, actual_ys_len + ))); + } + + let x = try_deserialize_scalar( + &x_bytes, + CompactEcashError::Deserialization("Failed to deserialize secret key scalar".to_string()), + )?; + let ys = try_deserialize_scalar_vec( + ys_len, + &bytes[40..], + CompactEcashError::Deserialization("Failed to deserialize secret key scalars".to_string()), + )?; + + Ok(SecretKeyAuth { x, ys }) + } +} + +impl SecretKeyAuth { + pub fn verification_key(&self, params: &Parameters) -> VerificationKeyAuth { + let g1 = params.gen1(); + let g2 = params.gen2(); + VerificationKeyAuth { + alpha: g2 * self.x, + beta_g1: self.ys.iter().map(|y| g1 * y).collect(), + beta_g2: self.ys.iter().map(|y| g2 * y).collect(), + } + } + + pub fn to_bytes(&self) -> Vec { + let ys_len = self.ys.len(); + let mut bytes = Vec::with_capacity(8 + (ys_len + 1) as usize * 32); + bytes.extend_from_slice(&self.x.to_bytes()); + bytes.extend_from_slice(&ys_len.to_le_bytes()); + for y in self.ys.iter() { + bytes.extend_from_slice(&y.to_bytes()) + } + bytes + } + + pub fn from_bytes(bytes: &[u8]) -> Result { + SecretKeyAuth::try_from(bytes) + } +} + +pub struct VerificationKeyAuth { + pub(crate) alpha: G2Projective, + pub(crate) beta_g1: Vec, + pub(crate) beta_g2: Vec, +} + +impl TryFrom<&[u8]> for VerificationKeyAuth { + type Error = CompactEcashError; + + fn try_from(bytes: &[u8]) -> Result { + // There should be at least alpha, one betaG1 and one betaG2 and their length + if bytes.len() < 96 * 2 + 48 + 8 || (bytes.len() - 8 - 96) % (96 + 48) != 0 { + return Err(CompactEcashError::DeserializationInvalidLength { + actual: bytes.len(), + modulus_target: bytes.len() - 8 - 96, + target: 96 * 2 + 48 + 8, + modulus: 96 + 48, + object: "verification key".to_string(), + }); + } + + // this conversion will not fail as we are taking the same length of data + let alpha_bytes: [u8; 96] = bytes[..96].try_into().unwrap(); + let betas_len = u64::from_le_bytes(bytes[96..104].try_into().unwrap()); + + let actual_betas_len = (bytes.len() - 104) / (96 + 48); + + if betas_len as usize != actual_betas_len { + return Err( + CompactEcashError::Deserialization( + format!("Tried to deserialize verification key with inconsistent betas len (expected {}, got {})", + betas_len, actual_betas_len + ))); + } + + let alpha = try_deserialize_g2_projective( + &alpha_bytes, + CompactEcashError::Deserialization( + "Failed to deserialize verification key G2 point (alpha)".to_string(), + ), + )?; + + let mut beta_g1 = Vec::with_capacity(betas_len as usize); + let mut beta_g1_end: u64 = 0; + for i in 0..betas_len { + let start = (104 + i * 48) as usize; + let end = (start + 48) as usize; + let beta_i_bytes = bytes[start..end].try_into().unwrap(); + let beta_i = try_deserialize_g1_projective( + &beta_i_bytes, + CompactEcashError::Deserialization( + "Failed to deserialize verification key G1 point (beta)".to_string(), + ), + )?; + + beta_g1_end = end as u64; + beta_g1.push(beta_i) + } + + let mut beta_g2 = Vec::with_capacity(betas_len as usize); + for i in 0..betas_len { + let start = (beta_g1_end + i * 96) as usize; + let end = (start + 96) as usize; + let beta_i_bytes = bytes[start..end].try_into().unwrap(); + let beta_i = try_deserialize_g2_projective( + &beta_i_bytes, + CompactEcashError::Deserialization( + "Failed to deserialize verification key G2 point (beta)".to_string(), + ), + )?; + + beta_g2.push(beta_i) + } + + Ok(VerificationKeyAuth { + alpha, + beta_g1, + beta_g2, + }) + } +} + +pub struct SecretKeyUser { + pub(crate) sk: Scalar, +} + +pub struct PublicKeyUser { + pub(crate) pk: G1Projective, +} diff --git a/common/nym-compact-ecash/src/scheme/mod.rs b/common/nym-compact-ecash/src/scheme/mod.rs index 240ad88ce8..8710be8388 100644 --- a/common/nym-compact-ecash/src/scheme/mod.rs +++ b/common/nym-compact-ecash/src/scheme/mod.rs @@ -1,5 +1,11 @@ +use bls12_381::G1Projective; + pub mod aggregation; pub mod withdrawal; pub mod keygen; pub mod setup; -pub mod spend; \ No newline at end of file +pub mod spend; + +#[derive(Debug)] +#[cfg_attr(test, derive(PartialEq))] +pub struct BlindedSignature(G1Projective, G1Projective); \ No newline at end of file diff --git a/common/nym-compact-ecash/src/scheme/setup.rs b/common/nym-compact-ecash/src/scheme/setup.rs index 9bc4972db9..7e76df22d2 100644 --- a/common/nym-compact-ecash/src/scheme/setup.rs +++ b/common/nym-compact-ecash/src/scheme/setup.rs @@ -1,4 +1,13 @@ -use bls12_381::{G1Affine, G2Affine}; +use bls12_381::{G1Affine, G2Affine, Scalar}; +use ff::Field; +use group::Curve; +use rand::thread_rng; + +use crate::error::Result; +use crate::utils::hash_g1; + +const ATTRIBUTES_LEN: usize = 3; +const MAX_COIN_VALUE: usize = 32; pub struct Parameters { /// Generator of the G1 group @@ -9,4 +18,42 @@ pub struct Parameters { gammas: Vec, /// Value of wallet L: usize, +} + +impl Parameters { + pub fn new() -> Result { + let gammas = (1..=ATTRIBUTES_LEN) + .map(|i| hash_g1(format!("gamma{}", i)).to_affine()) + .collect(); + Ok(Parameters { + g1: G1Affine::generator(), + g2: G2Affine::generator(), + gammas, + L: MAX_COIN_VALUE, + }) + } + + pub(crate) fn gen1(&self) -> &G1Affine { + &self.g1 + } + + pub(crate) fn gen2(&self) -> &G2Affine { + &self.g2 + } + + pub(crate) fn gammas(&self) -> &Vec { &self.gammas } + + pub fn random_scalar(&self) -> Scalar { + // lazily-initialized thread-local random number generator, seeded by the system + let mut rng = thread_rng(); + Scalar::random(&mut rng) + } + + pub fn n_random_scalars(&self, n: usize) -> Vec { + (0..n).map(|_| self.random_scalar()).collect() + } +} + +pub fn setup() -> Result { + Parameters::new() } \ No newline at end of file diff --git a/common/nym-compact-ecash/src/scheme/withdrawal.rs b/common/nym-compact-ecash/src/scheme/withdrawal.rs index e69de29bb2..b85406e754 100644 --- a/common/nym-compact-ecash/src/scheme/withdrawal.rs +++ b/common/nym-compact-ecash/src/scheme/withdrawal.rs @@ -0,0 +1,88 @@ +use bls12_381::{G1Projective, Scalar}; +use group::{Curve, GroupEncoding}; + +use nymcoconut::utils::hash_g1; + +use crate::error::{CompactEcashError, Result}; +use crate::proofs::WithdrawalProof; +use crate::scheme::BlindedSignature; +use crate::scheme::keygen::{PublicKeyUser, SecretKeyAuth, SecretKeyUser}; +use crate::scheme::setup::Parameters; + +pub struct WithdrawalRequest { + commitment_hash: G1Projective, + attrs_commitment: G1Projective, + pc_commitments: Vec, + zk_proof: WithdrawalProof, +} + +pub struct RequestInfo { + commitment_hash: G1Projective, + attrs_commitment_opening: Scalar, + pc_openings: Vec, + v: Scalar, + t: Scalar, +} + +pub fn withdrawal_request(params: &Parameters, skUser: SecretKeyUser) { + let v = params.random_scalar(); + let t = params.random_scalar(); + + let attributes = [skUser.sk, v, t]; + let gammas = params.gammas(); + let attrs_commitment_opening = params.random_scalar(); + let attribute_commitment = attributes + .iter() + .zip(gammas).map(|(&m, gamma)| gamma * m) + .sum::(); + + let commitment_hash = hash_g1(attribute_commitment.to_bytes()); + + let pc_openings = params.n_random_scalars(attributes.len()); + + // Compute Pedersen commitment for each attribute + let pc_attributes = pc_openings + .iter() + .zip(attributes.iter()) + .map(|(o_j, m_j)| params.gen1() * o_j + commitment_hash * m_j) + .collect::>(); + + // construct a zk proof of knowledge proving possession of m1, m2, m3, o, o1, o2, o3 + + let req_info = RequestInfo { + commitment_hash, + attrs_commitment_opening, + pc_openings, + v, + t, + }; +} + +pub fn issue(params: &Parameters, skAuth: SecretKeyAuth, pkUser: PublicKeyUser, withReq: &WithdrawalRequest) -> Result { + let h = hash_g1(withReq.attrs_commitment.to_bytes()); + if !(h == withReq.commitment_hash) { + return Err(CompactEcashError::WithdrawalVerification( + "Failed to verify the commitment hash".to_string(), + )); + } + + let sig = withReq.pc_commitments + .iter() + .zip(skAuth.ys.iter()) + .map(|(pc, yi)| pc * yi) + .chain(std::iter::once(h * skAuth.x)).sum(); + // verify zk proof + + Ok(BlindedSignature(h, sig)) +} + + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn withdrawal_request() { + let params = Parameters::new().unwrap(); + } +} \ No newline at end of file diff --git a/common/nym-compact-ecash/src/tests/e2e.rs b/common/nym-compact-ecash/src/tests/e2e.rs new file mode 100644 index 0000000000..e69de29bb2 diff --git a/common/nym-compact-ecash/src/tests/mod.rs b/common/nym-compact-ecash/src/tests/mod.rs new file mode 100644 index 0000000000..b6ae44f843 --- /dev/null +++ b/common/nym-compact-ecash/src/tests/mod.rs @@ -0,0 +1 @@ +mod e2e; diff --git a/common/nym-compact-ecash/src/utils.rs b/common/nym-compact-ecash/src/utils.rs new file mode 100644 index 0000000000..2dced059c1 --- /dev/null +++ b/common/nym-compact-ecash/src/utils.rs @@ -0,0 +1,77 @@ +use std::convert::TryInto; + +use bls12_381::{G1Affine, G1Projective, G2Affine, G2Projective, Scalar}; +use bls12_381::hash_to_curve::{ExpandMsgXmd, HashToCurve, HashToField}; + +use crate::error::{CompactEcashError, Result}; + +// A temporary way of hashing particular message into G1. +// Implementation idea was taken from `threshold_crypto`: +// https://github.com/poanetwork/threshold_crypto/blob/7709462f2df487ada3bb3243060504b5881f2628/src/lib.rs#L691 +// Eventually it should get replaced by, most likely, the osswu map +// method once ideally it's implemented inside the pairing crate. + +// https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-hash-to-curve-11#appendix-J.9.1 +const G1_HASH_DOMAIN: &[u8] = b"QUUX-V01-CS02-with-BLS12381G1_XMD:SHA-256_SSWU_RO_"; + +// https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-hash-to-curve-11#appendix-K.1 +const SCALAR_HASH_DOMAIN: &[u8] = b"QUUX-V01-CS02-with-expander"; + +pub fn hash_g1>(msg: M) -> G1Projective { + >>::hash_to_curve(msg, G1_HASH_DOMAIN) +} + +pub fn hash_to_scalar>(msg: M) -> Scalar { + let mut output = vec![Scalar::zero()]; + + Scalar::hash_to_field::>( + msg.as_ref(), + SCALAR_HASH_DOMAIN, + &mut output, + ); + output[0] +} + +pub fn try_deserialize_scalar(bytes: &[u8; 32], err: CompactEcashError) -> Result { + Into::>::into(Scalar::from_bytes(bytes)).ok_or(err) +} + +pub fn try_deserialize_g1_projective( + bytes: &[u8; 48], + err: CompactEcashError, +) -> Result { + Into::>::into(G1Affine::from_compressed(bytes)) + .ok_or(err) + .map(G1Projective::from) +} + +pub fn try_deserialize_g2_projective( + bytes: &[u8; 96], + err: CompactEcashError, +) -> Result { + Into::>::into(G2Affine::from_compressed(bytes)) + .ok_or(err) + .map(G2Projective::from) +} + +pub fn try_deserialize_scalar_vec( + expected_len: u64, + bytes: &[u8], + err: CompactEcashError, +) -> Result> { + if bytes.len() != expected_len as usize * 32 { + return Err(err); + } + + let mut out = Vec::with_capacity(expected_len as usize); + for i in 0..expected_len as usize { + let s_bytes = bytes[i * 32..(i + 1) * 32].try_into().unwrap(); + let s = match Into::>::into(Scalar::from_bytes(&s_bytes)) { + None => return Err(err), + Some(scalar) => scalar, + }; + out.push(s) + } + + Ok(out) +} diff --git a/common/nymcoconut/src/lib.rs b/common/nymcoconut/src/lib.rs index 821b1b3b29..f812c06fd1 100644 --- a/common/nymcoconut/src/lib.rs +++ b/common/nymcoconut/src/lib.rs @@ -27,8 +27,19 @@ pub use scheme::verification::prove_bandwidth_credential; pub use scheme::verification::verify_credential; pub use scheme::verification::Theta; pub use scheme::BlindedSignature; +pub use scheme::issuance::blind_sign; +pub use scheme::issuance::BlindSignRequest; +pub use scheme::issuance::prepare_blind_sign; +pub use scheme::keygen::KeyPair; +pub use scheme::keygen::ttp_keygen; +pub use scheme::keygen::VerificationKey; +pub use scheme::setup::Parameters; +pub use scheme::setup::setup; pub use scheme::Signature; pub use scheme::SignatureShare; +pub use scheme::verification::prove_bandwidth_credential; +pub use scheme::verification::Theta; +pub use scheme::verification::verify_credential; pub use traits::Base58; pub use utils::hash_to_scalar; @@ -39,7 +50,7 @@ mod proofs; mod scheme; pub mod tests; mod traits; -mod utils; +pub mod utils; pub type Attribute = Scalar; pub type PrivateAttribute = Attribute; diff --git a/common/nymcoconut/src/utils.rs b/common/nymcoconut/src/utils.rs index 9fec3b334c..8a9796c5b9 100644 --- a/common/nymcoconut/src/utils.rs +++ b/common/nymcoconut/src/utils.rs @@ -5,8 +5,8 @@ use core::iter::Sum; use core::ops::Mul; use std::convert::TryInto; -use bls12_381::hash_to_curve::{ExpandMsgXmd, HashToCurve, HashToField}; use bls12_381::{G1Affine, G1Projective, G2Affine, G2Projective, Scalar}; +use bls12_381::hash_to_curve::{ExpandMsgXmd, HashToCurve, HashToField}; use ff::Field; use crate::error::{CoconutError, Result}; @@ -81,9 +81,9 @@ pub(crate) fn perform_lagrangian_interpolation_at_origin( points: &[SignerIndex], values: &[T], ) -> Result -where - T: Sum, - for<'a> &'a T: Mul, + where + T: Sum, + for<'a> &'a T: Mul, { if points.is_empty() || values.is_empty() { return Err(CoconutError::Interpolation( @@ -122,7 +122,7 @@ const G1_HASH_DOMAIN: &[u8] = b"QUUX-V01-CS02-with-BLS12381G1_XMD:SHA-256_SSWU_R // https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-hash-to-curve-11#appendix-K.1 const SCALAR_HASH_DOMAIN: &[u8] = b"QUUX-V01-CS02-with-expander"; -pub(crate) fn hash_g1>(msg: M) -> G1Projective { +pub fn hash_g1>(msg: M) -> G1Projective { >>::hash_to_curve(msg, G1_HASH_DOMAIN) } @@ -137,7 +137,7 @@ pub fn hash_to_scalar>(msg: M) -> Scalar { output[0] } -pub(crate) fn try_deserialize_scalar_vec( +pub fn try_deserialize_scalar_vec( expected_len: u64, bytes: &[u8], err: CoconutError, @@ -159,11 +159,11 @@ pub(crate) fn try_deserialize_scalar_vec( Ok(out) } -pub(crate) fn try_deserialize_scalar(bytes: &[u8; 32], err: CoconutError) -> Result { +pub fn try_deserialize_scalar(bytes: &[u8; 32], err: CoconutError) -> Result { Into::>::into(Scalar::from_bytes(bytes)).ok_or(err) } -pub(crate) fn try_deserialize_g1_projective( +pub fn try_deserialize_g1_projective( bytes: &[u8; 48], err: CoconutError, ) -> Result { @@ -172,7 +172,7 @@ pub(crate) fn try_deserialize_g1_projective( .map(G1Projective::from) } -pub(crate) fn try_deserialize_g2_projective( +pub fn try_deserialize_g2_projective( bytes: &[u8; 96], err: CoconutError, ) -> Result {