#[cfg(feature = "bbsplus")]
pub mod bbsplus_message {
use crate::bbsplus::ciphersuites::BbsCiphersuite;
use crate::errors::Error;
use crate::utils::util::bbsplus_utils::hash_to_scalar;
use bls12_381_plus::Scalar;
use elliptic_curve::hash2curve::ExpandMsg;
use serde::{Deserialize, Serialize};
#[derive(Clone, Copy, PartialEq, Eq, Debug, Serialize, Deserialize)]
pub struct BBSplusMessage {
pub value: Scalar,
}
impl BBSplusMessage {
pub fn new(msg: Scalar) -> Self {
Self { value: msg }
}
pub fn messages_to_scalar<CS: BbsCiphersuite>(
messages: &[Vec<u8>],
api_id: &[u8],
) -> Result<Vec<Self>, Error>
where
CS::Expander: for<'a> ExpandMsg<'a>,
{
let map_dst = [api_id, CS::MAP_MSG_SCALAR].concat();
let mut msg_scalars: Vec<Self> = Vec::new();
for m in messages {
let scalar = hash_to_scalar::<CS>(m, &map_dst)?;
msg_scalars.push(Self { value: scalar })
}
Ok(msg_scalars)
}
pub fn map_message_to_scalar_as_hash<CS: BbsCiphersuite>(
data: &[u8],
api_id: &[u8],
) -> Result<Self, Error>
where
CS::Expander: for<'a> ExpandMsg<'a>,
{
let map_dst = [api_id, CS::MAP_MSG_SCALAR].concat();
let scalar = hash_to_scalar::<CS>(data, &map_dst)?;
Ok(Self { value: scalar })
}
pub fn to_bytes_be(&self) -> [u8; Scalar::BYTES] {
self.value.to_be_bytes()
}
pub fn from_bytes_be(bytes: &[u8; Scalar::BYTES]) -> Result<Self, Error> {
let s = Scalar::from_be_bytes(bytes);
if s.is_none().into() {
return Err(Error::Unspecified);
}
Ok(BBSplusMessage { value: s.unwrap() })
}
}
#[cfg(test)]
mod tests {
use crate::bbsplus::ciphersuites::BbsCiphersuite;
use crate::schemes::algorithms::Scheme;
use crate::schemes::algorithms::{BbsBls12381Sha256, BbsBls12381Shake256};
use crate::utils::message::bbsplus_message::BBSplusMessage;
use elliptic_curve::hash2curve::ExpandMsg;
use std::fs;
#[test]
fn map_message_to_scalar_as_hash_sha256() {
map_message_to_scalar_as_hash::<BbsBls12381Sha256>(
"./fixture_data/fixture_data/bls12-381-sha-256/MapMessageToScalarAsHash.json",
);
}
#[test]
fn map_message_to_scalar_as_hash_shake256() {
map_message_to_scalar_as_hash::<BbsBls12381Shake256>(
"./fixture_data/fixture_data/bls12-381-shake-256/MapMessageToScalarAsHash.json",
);
}
#[test]
fn messages_to_scalars_sha256() {
messages_to_scalars::<BbsBls12381Sha256>(
"./fixture_data/fixture_data/bls12-381-sha-256/MapMessageToScalarAsHash.json",
);
}
#[test]
fn messages_to_scalars_shake256() {
messages_to_scalars::<BbsBls12381Shake256>(
"./fixture_data/fixture_data/bls12-381-shake-256/MapMessageToScalarAsHash.json",
);
}
fn map_message_to_scalar_as_hash<S: Scheme>(filename: &str)
where
S::Ciphersuite: BbsCiphersuite,
<S::Ciphersuite as BbsCiphersuite>::Expander: for<'a> ExpandMsg<'a>,
{
let data = fs::read_to_string(filename).expect("Unable to read file");
let json: serde_json::Value = serde_json::from_str(&data).expect("Unable to parse");
eprintln!("{}", json["caseName"]);
let cases = json["cases"].as_array().unwrap();
let mut boolean = true;
for c in cases {
let msg = &c["message"];
let msg_hex = hex::decode(msg.as_str().unwrap()).unwrap();
let out = hex::encode(
BBSplusMessage::map_message_to_scalar_as_hash::<S::Ciphersuite>(
&msg_hex,
<S::Ciphersuite as BbsCiphersuite>::API_ID,
)
.unwrap()
.to_bytes_be(),
);
let out_expected = c["scalar"].as_str().unwrap();
if out != out_expected {
boolean = false;
};
}
assert_eq!(boolean, true);
}
fn messages_to_scalars<S: Scheme>(filename: &str)
where
S::Ciphersuite: BbsCiphersuite,
<S::Ciphersuite as BbsCiphersuite>::Expander: for<'a> ExpandMsg<'a>,
{
let data = fs::read_to_string(filename).expect("Unable to read file");
let json: serde_json::Value = serde_json::from_str(&data).expect("Unable to parse");
eprintln!("{}", json["caseName"]);
let mut messages = Vec::new();
let mut scalars = Vec::new();
json["cases"].as_array().unwrap().iter().for_each(|v| {
let msg = v["message"].as_str().unwrap();
messages.push(hex::decode(msg).unwrap());
let s = v["scalar"].as_str().unwrap();
scalars.push(s.to_string());
});
let message_scalars = BBSplusMessage::messages_to_scalar::<S::Ciphersuite>(
&messages,
<S::Ciphersuite as BbsCiphersuite>::API_ID,
)
.unwrap();
let message_scalars_hex: Vec<String> = message_scalars
.iter()
.map(|s| hex::encode(s.to_bytes_be()))
.collect();
assert_eq!(scalars, message_scalars_hex);
}
}
}
#[cfg(feature = "cl03")]
pub mod cl03_message {
use crate::cl03::ciphersuites::CLCiphersuite;
use digest::Digest;
use rug::{integer::Order, Integer};
use serde::{Deserialize, Serialize};
#[derive(Clone, PartialEq, Eq, Debug, Serialize, Deserialize)]
pub struct CL03Message {
pub value: Integer,
}
impl CL03Message {
pub fn new(msg: Integer) -> Self {
Self { value: msg }
}
pub fn get_value(&self) -> Integer {
self.value.clone()
}
pub fn map_message_to_integer_as_hash<C: CLCiphersuite>(data: &[u8]) -> Self
where
C::HashAlg: Digest,
{
let binding = <C::HashAlg as Digest>::digest(data);
let msg_digest = binding.as_slice();
let msg_integer = Integer::from_digits(msg_digest, Order::MsfBe);
Self { value: msg_integer }
}
}
}