Transcript crate with both a merlin backend and a basic label len value backend

Moves binding factor/seeded RNGs over to the transcripts.
This commit is contained in:
Luke Parker
2022-05-03 07:20:24 -04:00
parent 87f38cafe4
commit bf257b3a1f
19 changed files with 282 additions and 129 deletions

View File

@@ -0,0 +1,18 @@
[package]
name = "transcript"
version = "0.1.0"
description = "A simple transcript definition"
license = "MIT"
authors = ["Luke Parker <lukeparker5132@gmail.com>"]
edition = "2021"
[dependencies]
rand_core = "0.6"
rand_chacha = "0.3"
digest = "0.10"
merlin = { version = "3", optional = true }
[features]
merlin = ["dep:merlin"]

21
crypto/transcript/LICENSE Normal file
View File

@@ -0,0 +1,21 @@
MIT License
Copyright (c) 2022 Luke Parker
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@@ -0,0 +1,62 @@
use core::{marker::PhantomData, fmt::Debug};
#[cfg(features = "merlin")]
mod merlin;
#[cfg(features = "merlin")]
pub use merlin::MerlinTranscript;
use rand_core::{RngCore, CryptoRng, SeedableRng};
use rand_chacha::ChaCha12Rng;
use digest::Digest;
pub trait Transcript {
type SeededRng: RngCore + CryptoRng;
fn new(label: &'static [u8]) -> Self;
fn append_message(&mut self, label: &'static [u8], message: &[u8]);
fn challenge(&mut self, label: &'static [u8], len: usize) -> Vec<u8>;
fn seeded_rng(&self, label: &'static [u8], additional_entropy: Option<[u8; 32]>) -> Self::SeededRng;
}
#[derive(Clone, Debug)]
pub struct DigestTranscript<D: Digest>(Vec<u8>, PhantomData<D>);
impl<D: Digest> Transcript for DigestTranscript<D> {
// Uses ChaCha12 as even ChaCha8 should be secure yet 12 is considered a sane middleground
type SeededRng = ChaCha12Rng;
fn new(label: &'static [u8]) -> Self {
DigestTranscript(label.to_vec(), PhantomData)
}
fn append_message(&mut self, label: &'static [u8], message: &[u8]) {
self.0.extend(label);
// Assumes messages don't exceed 16 exabytes
self.0.extend(u64::try_from(message.len()).unwrap().to_le_bytes());
self.0.extend(message);
}
fn challenge(&mut self, label: &'static [u8], len: usize) -> Vec<u8> {
self.0.extend(label);
let mut challenge = Vec::with_capacity(len);
challenge.extend(&D::new().chain_update(&self.0).chain_update(&0u64.to_le_bytes()).finalize());
for i in 0 .. (len / challenge.len()) {
challenge.extend(&D::new().chain_update(&self.0).chain_update(&u64::try_from(i).unwrap().to_le_bytes()).finalize());
}
challenge.truncate(len);
challenge
}
fn seeded_rng(&self, label: &'static [u8], additional_entropy: Option<[u8; 32]>) -> Self::SeededRng {
let mut transcript = DigestTranscript::<D>(self.0.clone(), PhantomData);
if additional_entropy.is_some() {
transcript.append_message(b"additional_entropy", &additional_entropy.unwrap());
}
transcript.0.extend(label);
let mut seed = [0; 32];
seed.copy_from_slice(&D::digest(&transcript.0)[0 .. 32]);
ChaCha12Rng::from_seed(seed)
}
}

View File

@@ -0,0 +1,42 @@
use core::{marker::PhantomData, fmt::{Debug, Formatter}};
use rand_core::{RngCore, CryptoRng, SeedableRng};
use rand_chacha::ChaCha12Rng;
use digest::Digest;
#[derive(Clone)]
pub struct MerlinTranscript(merlin::Transcript);
// Merlin doesn't implement Debug so provide a stub which won't panic
impl Debug for MerlinTranscript {
fn fmt(&self, _: &mut Formatter<'_>) -> Result<(), std::fmt::Error> { Ok(()) }
}
impl Transcript for MerlinTranscript {
type SeededRng = ChaCha12Rng;
fn new(label: &'static [u8]) -> Self {
MerlinTranscript(merlin::Transcript::new(label))
}
fn append_message(&mut self, label: &'static [u8], message: &[u8]) {
self.0.append_message(label, message);
}
fn challenge(&mut self, label: &'static [u8], len: usize) -> Vec<u8> {
let mut challenge = vec![];
challenge.resize(len, 0);
self.0.challenge_bytes(label, &mut challenge);
challenge
}
fn seeded_rng(&self, label: &'static [u8], additional_entropy: Option<[u8; 32]>) -> ChaCha12Rng {
let mut transcript = self.0.clone();
if additional_entropy.is_some() {
transcript.append_message(b"additional_entropy", &additional_entropy.unwrap());
}
let mut seed = [0; 32];
transcript.challenge_bytes(label, &mut seed);
ChaCha12Rng::from_seed(seed)
}
}