use bitvec::prelude::*;
use halo2::{
arithmetic::{Coordinates, CurveAffine, CurveExt},
pasta::pallas,
};
use sinsemilla::HashDomain;
pub fn extract_p(point: pallas::Point) -> pallas::Base {
let option: Option<Coordinates<pallas::Affine>> =
pallas::Affine::from(point).coordinates().into();
match option {
Some(coordinates) => *coordinates.x(),
_ => pallas::Base::zero(),
}
}
#[allow(non_snake_case)]
pub fn pallas_group_hash(D: &[u8], M: &[u8]) -> pallas::Point {
let domain_separator = std::str::from_utf8(D).unwrap();
pallas::Point::hash_to_curve(domain_separator)(M)
}
#[allow(non_snake_case)]
pub fn sinsemilla_hash(D: &[u8], M: &BitVec<u8, Lsb0>) -> Option<pallas::Base> {
let domain = std::str::from_utf8(D).expect("must be valid UTF-8");
let hash_domain = HashDomain::new(domain);
hash_domain.hash(M.iter().map(|b| *b.as_ref())).into()
}
#[cfg(test)]
mod tests {
use super::*;
use crate::orchard::tests::vectors;
#[test]
#[allow(non_snake_case)]
fn sinsemilla_hackworks_test_vectors() {
use halo2::pasta::group::ff::PrimeField;
for tv in tests::vectors::SINSEMILLA.iter() {
let D = tv.domain.as_slice();
let M: &BitVec<u8, Lsb0> = &tv.msg.iter().collect();
assert_eq!(
sinsemilla_hash(D, M).expect("should not fail per Theorem 5.4.4"),
pallas::Base::from_repr(tv.hash).unwrap()
)
}
}
#[test]
#[allow(non_snake_case)]
fn sinsemilla_hackworks_group_hash_test_vectors() {
use halo2::pasta::group::GroupEncoding;
for tv in tests::vectors::GROUP_HASHES.iter() {
let D = tv.domain.as_slice();
let M = tv.msg.as_slice();
assert_eq!(
pallas_group_hash(D, M),
pallas::Point::from_bytes(&tv.point).unwrap()
);
}
}
}