use std::cell::RefCell;
use rand::prelude::*;
use merlin::{Transcript};
use curve25519_dalek::digest::{Input,FixedOutput,ExtendableOutput,XofReader};
use curve25519_dalek::digest::generic_array::typenum::{U32,U64};
use curve25519_dalek::ristretto::{CompressedRistretto}; use curve25519_dalek::scalar::Scalar;
pub trait SigningTranscript {
fn commit_bytes(&mut self, label: &'static [u8], bytes: &[u8]);
fn proto_name(&mut self, label: &'static [u8]) {
self.commit_bytes(b"proto-name", label);
}
fn commit_point(&mut self, label: &'static [u8], compressed: &CompressedRistretto) {
self.commit_bytes(label, compressed.as_bytes());
}
fn challenge_bytes(&mut self, label: &'static [u8], dest: &mut [u8]);
fn challenge_scalar(&mut self, label: &'static [u8]) -> Scalar {
let mut buf = [0; 64];
self.challenge_bytes(label, &mut buf);
Scalar::from_bytes_mod_order_wide(&buf)
}
fn witness_scalar(&self, nonce_seeds: &[&[u8]]) -> Scalar {
let mut scalar_bytes = [0u8; 64];
self.witness_bytes(&mut scalar_bytes, nonce_seeds);
Scalar::from_bytes_mod_order_wide(&scalar_bytes)
}
fn witness_bytes(&self, dest: &mut [u8], nonce_seeds: &[&[u8]]) {
self.witness_bytes_rng(dest, nonce_seeds, thread_rng())
}
fn witness_bytes_rng<R>(&self, dest: &mut [u8], nonce_seeds: &[&[u8]], rng: R)
where R: Rng+CryptoRng;
}
impl<T> SigningTranscript for &mut T
where T: SigningTranscript + ?Sized
{
#[inline(always)]
fn commit_bytes(&mut self, label: &'static [u8], bytes: &[u8])
{ (**self).commit_bytes(label,bytes) }
#[inline(always)]
fn proto_name(&mut self, label: &'static [u8])
{ (**self).proto_name(label) }
#[inline(always)]
fn commit_point(&mut self, label: &'static [u8], compressed: &CompressedRistretto)
{ (**self).commit_point(label, compressed) }
#[inline(always)]
fn challenge_bytes(&mut self, label: &'static [u8], dest: &mut [u8])
{ (**self).challenge_bytes(label,dest) }
#[inline(always)]
fn challenge_scalar(&mut self, label: &'static [u8]) -> Scalar
{ (**self).challenge_scalar(label) }
#[inline(always)]
fn witness_scalar(&self, nonce_seeds: &[&[u8]]) -> Scalar
{ (**self).witness_scalar(nonce_seeds) }
#[inline(always)]
fn witness_bytes(&self, dest: &mut [u8], nonce_seeds: &[&[u8]])
{ (**self).witness_bytes(dest,nonce_seeds) }
#[inline(always)]
fn witness_bytes_rng<R>(&self, dest: &mut [u8], nonce_seeds: &[&[u8]], rng: R)
where R: Rng+CryptoRng
{ (**self).witness_bytes_rng(dest,nonce_seeds,rng) }
}
impl SigningTranscript for Transcript {
fn commit_bytes(&mut self, label: &'static [u8], bytes: &[u8]) {
Transcript::commit_bytes(self, label, bytes)
}
fn challenge_bytes(&mut self, label: &'static [u8], dest: &mut [u8]) {
Transcript::challenge_bytes(self, label, dest)
}
fn witness_bytes_rng<R>(&self, dest: &mut [u8], nonce_seeds: &[&[u8]], mut rng: R)
where R: Rng+CryptoRng
{
let mut br = self.build_rng();
for ns in nonce_seeds {
br = br.commit_witness_bytes(b"", ns);
}
let mut r = br.finalize(&mut rng);
r.fill_bytes(dest)
}
}
#[derive(Clone)] pub struct SigningContext(Transcript);
pub fn signing_context(context : &'static [u8]) -> SigningContext {
SigningContext::new(context)
}
impl SigningContext {
pub fn new(context : &'static [u8]) -> SigningContext {
SigningContext(Transcript::new(context))
}
pub fn bytes(&self, bytes: &[u8]) -> Transcript {
let mut t = self.0.clone();
t.commit_bytes(b"sign-bytes", bytes);
t
}
pub fn xof<D: ExtendableOutput>(&self, h: D) -> Transcript {
let mut prehash = [0u8; 32];
h.xof_result().read(&mut prehash);
let mut t = self.0.clone();
t.commit_bytes(b"sign-XoF", &prehash);
t
}
pub fn hash256<D: FixedOutput<OutputSize=U32>>(&self, h: D) -> Transcript {
let mut prehash = [0u8; 32];
prehash.copy_from_slice(h.fixed_result().as_slice());
let mut t = self.0.clone();
t.commit_bytes(b"sign-256", &prehash);
t
}
pub fn hash512<D: FixedOutput<OutputSize=U64>>(&self, h: D) -> Transcript {
let mut prehash = [0u8; 64];
prehash.copy_from_slice(h.fixed_result().as_slice());
let mut t = self.0.clone();
t.commit_bytes(b"sign-256", &prehash);
t
}
}
pub struct SimpleTranscript<H>(pub H)
where H: Input + ExtendableOutput + Clone;
fn input_bytes<H: Input>(h: &mut H, bytes: &[u8]) {
let l = bytes.len() as u64;
h.input(l.to_le_bytes());
h.input(bytes);
}
impl<H> SigningTranscript for SimpleTranscript<H>
where H: Input + ExtendableOutput + Clone
{
fn commit_bytes(&mut self, label: &'static [u8], bytes: &[u8]) {
self.0.input(b"co");
input_bytes(&mut self.0, label);
input_bytes(&mut self.0, bytes);
}
fn challenge_bytes(&mut self, label: &'static [u8], dest: &mut [u8]) {
self.0.input(b"ch");
input_bytes(&mut self.0, label);
let l = dest.len() as u64;
self.0.input(l.to_le_bytes());
self.0.clone().chain(b"xof").xof_result().read(dest);
}
fn witness_bytes_rng<R>(&self, dest: &mut [u8], nonce_seeds: &[&[u8]], mut rng: R)
where R: Rng+CryptoRng
{
let mut h = self.0.clone().chain(b"wb");
for ns in nonce_seeds {
input_bytes(&mut h, ns);
}
let l = dest.len() as u64;
h.input(l.to_le_bytes());
let mut r = [0u8; 32];
rng.fill_bytes(&mut r);
h.input(&r);
h.xof_result().read(dest);
}
}
pub struct SigningTranscriptWithRng<T,R>
where T: SigningTranscript, R: Rng+CryptoRng
{
t: T,
rng: RefCell<R>,
}
impl<T,R> SigningTranscript for SigningTranscriptWithRng<T,R>
where T: SigningTranscript, R: Rng+CryptoRng
{
fn commit_bytes(&mut self, label: &'static [u8], bytes: &[u8])
{ self.t.commit_bytes(label, bytes) }
fn challenge_bytes(&mut self, label: &'static [u8], dest: &mut [u8])
{ self.t.challenge_bytes(label, dest) }
fn witness_bytes(&self, dest: &mut [u8], nonce_seeds: &[&[u8]])
{ self.witness_bytes_rng(dest, nonce_seeds, &mut *self.rng.borrow_mut()) }
fn witness_bytes_rng<RR>(&self, dest: &mut [u8], nonce_seeds: &[&[u8]], rng: RR)
where RR: Rng+CryptoRng
{ self.t.witness_bytes_rng(dest,nonce_seeds,rng) }
}
pub fn attach_rng<T,R>(t: T, rng: R) -> SigningTranscriptWithRng<T,R>
where T: SigningTranscript, R: Rng+CryptoRng
{
SigningTranscriptWithRng {
t, rng: RefCell::new(rng)
}
}