#![cfg_attr(not(feature = "std"), no_std)]
#![deny(unsafe_code)]
#![doc = include_str!("../README.md")]
use ark_std::{
UniformRand,
borrow::{Borrow,BorrowMut},
io::{self, Read, Write}, vec::Vec,
rand::{self,RngCore,CryptoRng},
};
use ark_serialize::{CanonicalSerialize};
use ark_ff::{Field,PrimeField};
pub use sha3::{Shake128};
pub use digest;
use digest::{Update,XofReader,ExtendableOutput};
#[cfg(test)]
mod tests;
#[cfg(any(test, debug_assertions))]
pub mod debug;
pub trait AsLabel {
fn as_label(&self) -> &[u8];
}
impl AsLabel for &'static [u8] {
fn as_label(&self) -> &[u8] { &self[..] }
}
impl<const N: usize> AsLabel for &'static [u8; N] {
fn as_label(&self) -> &[u8] { &self[..] }
}
#[derive(Clone,Debug)]
pub struct IsLabel<T>(pub T);
impl<T: Borrow<[u8]>> AsLabel for IsLabel<T> {
fn as_label(&self) -> &[u8] { self.0.borrow() }
}
pub trait IntoTranscript {
type Taken: BorrowMut<Transcript>;
fn into_transcript(self) -> Self::Taken;
}
impl<B: BorrowMut<Transcript>> IntoTranscript for B {
type Taken = B;
fn into_transcript(self) -> B { self }
}
impl<T: Borrow<[u8]>> IntoTranscript for IsLabel<T> {
type Taken = Transcript;
fn into_transcript(self) -> Transcript {
Transcript::new_labeled(self)
}
}
impl<'a> IntoTranscript for &'a [u8] {
type Taken = Transcript;
fn into_transcript(self) -> Transcript {
Transcript::from_accumulation(self)
}
}
impl<'a, const N: usize> IntoTranscript for &'a [u8; N] {
type Taken = Transcript;
fn into_transcript(self) -> Transcript {
Transcript::from_accumulation(self)
}
}
#[derive(Clone)]
enum Mode {
Hash(Shake128),
Accumulate(Vec<u8>),
}
impl Mode {
fn raw_write(&mut self, bytes: &[u8]) {
match self {
Mode::Hash(hasher) => hasher.update(bytes),
Mode::Accumulate(acc) => acc.extend_from_slice(bytes),
}
}
fn raw_reader(self) -> Reader {
#[cfg(feature = "debug-transcript")]
println!("Shake128 {}transcript XoF reader",self.debug_name);
match self {
Mode::Hash(hasher) => Reader(hasher.clone().finalize_xof()),
Mode::Accumulate(acc) => {
let mut t = Transcript::from_accumulation(acc);
t.seperate();
t.mode.raw_reader()
}
}
}
}
#[derive(Clone)]
pub struct Transcript {
length: Option<u32>,
mode: Mode,
#[cfg(feature = "debug-transcript")]
debug_name: &'static str,
}
impl Default for Transcript {
fn default() -> Transcript {
Transcript::new_blank()
}
}
impl Update for Transcript {
fn update(&mut self, bytes: &[u8]) {
self.write_bytes(bytes);
}
}
impl Write for Transcript {
fn write(&mut self, bytes: &[u8]) -> io::Result<usize> {
self.write_bytes(bytes);
Ok(bytes.len())
}
fn flush(&mut self) -> io::Result<()> {
Ok(())
}
}
impl Transcript {
pub fn from_shake128(hasher: Shake128) -> Transcript {
Transcript {
length: None,
mode: Mode::Hash(hasher),
#[cfg(feature = "debug-transcript")]
debug_name: "",
}
}
pub fn from_accumulation(acc: impl AsRef<[u8]>) -> Transcript {
let mut hasher = Shake128::default();
hasher.update(acc.as_ref());
Transcript::from_shake128(hasher)
}
pub fn new_blank() -> Transcript {
#[cfg(feature = "debug-transcript")]
println!("Initial Shake128 transcript..");
Transcript::from_accumulation(&[])
}
pub fn new_labeled(label: impl AsLabel) -> Transcript {
let mut t = Transcript::new_blank();
t.label(label);
t
}
pub fn new_blank_accumulator() -> Transcript {
#[cfg(feature = "debug-transcript")]
println!("Initial Shake128 transcript..");
Transcript {
length: None,
mode: Mode::Accumulate(Vec::new()),
#[cfg(feature = "debug-transcript")]
debug_name: "",
}
}
pub fn accumulator_reserve(&mut self, additional: usize) {
match &mut self.mode {
Mode::Accumulate(acc) => acc.reserve(additional),
_ => {},
}
}
pub fn accumulator_finalize(mut self) -> Vec<u8> {
self.seperate();
match self.mode {
Mode::Hash(_) => panic!("Attempte to accumulator_finalize a hashing Transcript"),
Mode::Accumulate(acc) => acc,
}
}
pub fn seperate(&mut self) {
#[cfg(feature = "debug-transcript")]
println!("Shake128 {}transcript seperator: {}",self.debug_name, self.length);
if let Some(l) = self.length {
self.mode.raw_write( & l.to_be_bytes() );
}
self.length = None;
}
pub fn write_bytes(&mut self, mut bytes: &[u8]) {
const HIGH: u32 = 0x80000000;
loop {
let length = self.length.get_or_insert(0);
let l = ark_std::cmp::min( (HIGH - 1 - *length) as usize, bytes.len() );
#[cfg(feature = "debug-transcript")]
match ark_std::str::from_utf8(bytes) {
Ok(s) => {
println!("Shake128 {}transcript write of {} bytes: b\"{}\"", self.debug_name, l, s);
}
Err(_) => {
println!("Shake128 {}transcript write of {} bytes out of {}", self.debug_name, l, bytes.len());
}
}
self.mode.raw_write( &bytes[0..l] );
bytes = &bytes[l..];
if bytes.len() == 0 {
*length += u32::try_from(l).unwrap();
return;
}
*length |= HIGH;
self.seperate();
}
}
pub fn append_u64(&mut self, v: u64) {
self.seperate();
self.write_bytes(&v.to_be_bytes());
self.seperate();
}
pub fn append<O: CanonicalSerialize+?Sized>(&mut self, itm: &O) {
self.seperate();
itm.serialize_uncompressed(&mut *self)
.expect("ArkTranscript should infaillibly flushed");
self.seperate();
}
pub fn append_slice<O,B>(&mut self, itms: &[B])
where O: CanonicalSerialize+?Sized, B: Borrow<O>,
{
self.seperate();
for itm in itms.iter() {
itm.borrow()
.serialize_uncompressed(&mut *self)
.expect("ArkTranscript should infaillibly flushed");
self.seperate();
}
}
pub fn label(&mut self, label: impl AsLabel) {
self.seperate();
self.write_bytes(label.as_label());
self.seperate();
}
pub fn challenge(&mut self, label: impl AsLabel) -> Reader {
#[cfg(feature = "debug-transcript")]
println!("Shake128 {}transcript challenge",self.debug_name);
self.label(label);
self.write_bytes(b"challenge");
let reader = self.mode.clone().raw_reader();
self.seperate();
reader
}
pub fn fork(&self, label: impl AsLabel) -> Transcript {
let mut fork = self.clone();
#[cfg(feature = "debug-transcript")]
{
fork.debug_name = "witness ";
println!("Shake128 {}transcript forked", self.debug_name);
}
fork.label(label);
fork
}
#[cfg(feature = "debug-transcript")]
pub fn set_debug_name(&mut self, debug_name: &'static str) {
self.debug_name = debug_name;
}
pub fn witness(mut self, rng: &mut (impl RngCore+CryptoRng)) -> Reader {
self.seperate();
let mut rand = [0u8; 32];
rng.fill_bytes(&mut rand);
self.write_bytes(&rand);
self.mode.raw_reader()
}
}
#[repr(transparent)]
pub struct Reader(sha3::Shake128Reader);
impl Reader {
pub fn read_bytes(&mut self, buf: &mut [u8]) {
XofReader::read(&mut self.0, buf);
}
pub fn read_byte_array<const N: usize>(&mut self) -> [u8; N] {
let mut buf = [0u8; N];
self.read_bytes(&mut buf);
buf
}
pub fn read_u128(&mut self) -> u128 {
u128::from_le_bytes(self.read_byte_array())
}
pub fn read_128bit_scalar<F: Field>(&mut self) -> F {
self.read_u128().into()
}
pub fn read_uniform<T: UniformRand>(&mut self) -> T {
<T as UniformRand>::rand(self)
}
pub fn read_reduce<F: PrimeField>(&mut self) -> F {
xof_read_reduced::<F,Self>(self)
}
}
pub fn xof_read_reduced<F: PrimeField,R: XofReader>(xof: &mut R) -> F {
let len_per_base_elem = get_len_per_elem::<F, 128>();
if len_per_base_elem > 256 {
panic!("PrimeField larger than 1913 bits!");
}
let mut alloca = [0u8; 256];
let alloca = &mut alloca[0..len_per_base_elem];
xof.read(alloca);
alloca.reverse(); F::from_le_bytes_mod_order(&alloca)
}
const fn get_len_per_elem<F: Field, const SEC_PARAM: usize>() -> usize {
let base_field_size_in_bits = F::BasePrimeField::MODULUS_BIT_SIZE as usize;
let base_field_size_with_security_padding_in_bits = base_field_size_in_bits + SEC_PARAM;
let bytes_per_base_field_elem =
((base_field_size_with_security_padding_in_bits + 7) / 8) as u64;
bytes_per_base_field_elem as usize
}
impl XofReader for Reader {
fn read(&mut self, dest: &mut [u8]) {
self.read_bytes(dest);
}
}
impl Read for Reader {
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
self.read_bytes(buf);
Ok(buf.len())
}
fn read_exact(&mut self, buf: &mut [u8]) -> io::Result<()> {
self.read_bytes(buf);
Ok(())
}
}
impl RngCore for Reader {
fn next_u32(&mut self) -> u32 {
let mut b = [0u8; 4];
self.read_bytes(&mut b);
u32::from_le_bytes(b)
}
fn next_u64(&mut self) -> u64 {
let mut b = [0u8; 8];
self.read_bytes(&mut b);
u64::from_le_bytes(b)
}
fn fill_bytes(&mut self, dest: &mut [u8]) {
self.read_bytes(dest);
}
fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), rand::Error> {
self.fill_bytes(dest);
Ok(())
}
}
impl CryptoRng for Reader { }