Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Verifier #173

Closed
wants to merge 23 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 26 additions & 0 deletions transcript-core/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
[package]
name = "transcript-core"
version = "0.1.0"
edition = "2021"

[dependencies]
p256 = { version = "0.10", features = ["ecdsa"]}
thiserror = "1"
rs_merkle = "1.2.0"
serde = { version = "1.0", features = ["derive"] }
bincode = "1.3.3"

[features]
# This feature allows other crates to modify private fields of some types for testing purposes
expose_setters_for_testing = []

[dev-dependencies]
tlsn-mpc-core = { path = "../mpc/mpc-core" }
tlsn-mpc-circuits = { path = "../mpc/mpc-circuits" }
tlsn-tls-circuits = { path = "../tls/tls-circuits" }
hex = "0.4"
rstest = "0.12"
rand_chacha = "0.3"
rand = "0.8"
rand_core = "0.6"

209 changes: 209 additions & 0 deletions transcript-core/src/commitment.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,209 @@
use super::{error::Error, HashCommitment, LabelSeed};
use serde::Serialize;

/// A User's commitment to a portion of the notarized data
#[derive(Serialize, Clone, Default)]
pub struct Commitment {
/// This commitment's index in `commitments` of [crate::document::Document]
id: u32,
typ: CommitmentType,
direction: Direction,
/// The index of this commitment in the Merkle tree of commitments
merkle_tree_index: u32,
/// The actual commitment
commitment: HashCommitment,
/// The absolute byte ranges within the notarized data. The committed data
/// is located in those ranges. Ranges do not overlap.
ranges: Vec<TranscriptRange>,
}

impl Commitment {
pub fn new(
id: u32,
typ: CommitmentType,
direction: Direction,
commitment: HashCommitment,
ranges: Vec<TranscriptRange>,
merkle_tree_index: u32,
) -> Self {
Self {
id,
typ,
direction,
commitment,
ranges,
merkle_tree_index,
}
}

pub fn id(&self) -> u32 {
self.id
}

pub fn typ(&self) -> &CommitmentType {
&self.typ
}

pub fn direction(&self) -> &Direction {
&self.direction
}

pub fn merkle_tree_index(&self) -> u32 {
self.merkle_tree_index
}

pub fn commitment(&self) -> [u8; 32] {
self.commitment
}

pub fn ranges(&self) -> &Vec<TranscriptRange> {
&self.ranges
}

#[cfg(test)]
pub fn set_id(&mut self, id: u32) {
self.id = id;
}

#[cfg(test)]
pub fn set_typ(&mut self, typ: CommitmentType) {
self.typ = typ;
}

#[cfg(any(feature = "expose_setters_for_testing", test))]
pub fn set_ranges(&mut self, ranges: Vec<TranscriptRange>) {
self.ranges = ranges;
}

#[cfg(test)]
pub fn set_merkle_tree_index(&mut self, merkle_tree_index: u32) {
self.merkle_tree_index = merkle_tree_index;
}

#[cfg(test)]
pub fn set_commitment(&mut self, commitment: [u8; 32]) {
self.commitment = commitment;
}
}

#[derive(Clone, PartialEq, Serialize, Default)]
#[allow(non_camel_case_types)]
th4s marked this conversation as resolved.
Show resolved Hide resolved
pub enum CommitmentType {
#[default]
// A blake3 digest of the garbled circuit's active labels. The labels are generated from a PRG seed.
// For more details on the protocol used to generate this commitment, see
// https://github.com/tlsnotary/docs-mdbook/blob/main/src/protocol/notarization/public_data_commitment.md
labels_blake3,
}

/// Various supported types of commitment opening
#[derive(Serialize, Clone)]
pub enum CommitmentOpening {
LabelsBlake3(LabelsBlake3Opening),
}

/// A validated opening for the commitment type [CommitmentType::labels_blake3]
#[derive(Serialize, Clone, Default)]
pub struct LabelsBlake3Opening {
/// This commitment opening's index in `commitment_openings` of [crate::document::Document].
/// The [Commitment] corresponding to this opening has the same id.
id: u32,
/// The actual opening of the commitment
opening: Vec<u8>,
/// All our commitments are `salt`ed by appending 16 random bytes
salt: Vec<u8>,
/// A PRG seeds from which to generate garbled circuit active labels, see
/// [crate::commitment::CommitmentType::labels_blake3].
/// It must match `label_seed` in [crate::document::Document].
label_seed: LabelSeed,
}

impl LabelsBlake3Opening {
pub fn new(id: u32, opening: Vec<u8>, salt: Vec<u8>, label_seed: LabelSeed) -> Self {
Self {
id,
opening,
salt,
label_seed,
}
}

pub fn id(&self) -> u32 {
self.id
}
pub fn opening(&self) -> &Vec<u8> {
&self.opening
}

pub fn salt(&self) -> &Vec<u8> {
&self.salt
}

pub fn label_seed(&self) -> &LabelSeed {
&self.label_seed
}

#[cfg(any(feature = "expose_setters_for_testing", test))]
pub fn set_id(&mut self, id: u32) {
self.id = id;
}

pub fn set_opening(&mut self, opening: Vec<u8>) {
self.opening = opening;
}

#[cfg(any(feature = "expose_setters_for_testing", test))]
pub fn set_label_seed(&mut self, label_seed: LabelSeed) {
self.label_seed = label_seed;
}

#[cfg(any(feature = "expose_setters_for_testing", test))]
pub fn set_salt(&mut self, salt: Vec<u8>) {
self.salt = salt;
}
}

#[derive(Serialize, Clone, PartialEq, Default, Debug)]
/// A TLS transcript consists of a stream of bytes which were `Sent` to the server
/// and a stream of bytes which were `Received` from the server . The User creates
/// separate commitments to bytes in each direction.
pub enum Direction {
#[default]
Sent,
Received,
}

#[derive(Serialize, Clone, Debug, PartialEq)]
/// A non-empty half-open range [start, end). Range bounds are ascending i.e. start < end
pub struct TranscriptRange {
start: u32,
end: u32,
}

impl TranscriptRange {
pub fn new(start: u32, end: u32) -> Result<Self, Error> {
// empty ranges are not allowed
if start >= end {
return Err(Error::RangeInvalid);
}
Ok(Self { start, end })
}

pub fn start(&self) -> u32 {
self.start
}

pub fn end(&self) -> u32 {
self.end
}

#[cfg(test)]
pub fn len(&self) -> u32 {
self.end - self.start
}

#[cfg(any(feature = "expose_setters_for_testing", test))]
pub fn new_unchecked(start: u32, end: u32) -> Self {
Self { start, end }
}
}
105 changes: 105 additions & 0 deletions transcript-core/src/document.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
use crate::{
commitment::{Commitment, CommitmentOpening},
merkle::MerkleProof,
tls_handshake::TLSHandshake,
LabelSeed,
};
use serde::Serialize;

/// Notarization document. This is the form in which the document is received
/// by the Verifier from the User.
#[derive(Serialize, Clone)]
pub struct Document {
version: u8,
tls_handshake: TLSHandshake,
/// Notary's signature over the [crate::signed::Signed] portion of this doc
signature: Option<Vec<u8>>,

/// A PRG seeds from which to generate garbled circuit active labels, see
/// [crate::commitment::CommitmentType::labels_blake3]
label_seed: LabelSeed,

/// The root of the Merkle tree of all the commitments. The User must prove that each one of the
/// `commitments` is included in the Merkle tree.
/// This approach allows the User to hide from the Notary the exact amount of commitments thus
/// increasing User privacy against the Notary.
/// The root was made known to the Notary before the Notary opened his garbled circuits
/// to the User.
merkle_root: [u8; 32],

/// The total leaf count in the Merkle tree of commitments. Provided by the User to the Verifier
/// to enable merkle proof verification.
merkle_tree_leaf_count: u32,

/// A proof that all [commitments] are the leaves of the Merkle tree
merkle_multi_proof: MerkleProof,

/// User's commitments to various portions of the notarized data, sorted ascendingly by id
commitments: Vec<Commitment>,

/// Openings for the commitments, sorted ascendingly by id
commitment_openings: Vec<CommitmentOpening>,
}

impl Document {
/// Creates a new document
pub fn new(
version: u8,
tls_handshake: TLSHandshake,
signature: Option<Vec<u8>>,
label_seed: LabelSeed,
merkle_root: [u8; 32],
merkle_tree_leaf_count: u32,
merkle_multi_proof: MerkleProof,
commitments: Vec<Commitment>,
commitment_openings: Vec<CommitmentOpening>,
) -> Self {
Self {
version,
tls_handshake,
signature,
label_seed,
merkle_root,
merkle_tree_leaf_count,
merkle_multi_proof,
commitments,
commitment_openings,
}
}

pub fn version(&self) -> u8 {
self.version
}

pub fn tls_handshake(&self) -> &TLSHandshake {
&self.tls_handshake
}

pub fn signature(&self) -> &Option<Vec<u8>> {
&self.signature
}

pub fn label_seed(&self) -> &LabelSeed {
&self.label_seed
}

pub fn merkle_root(&self) -> &[u8; 32] {
&self.merkle_root
}

pub fn merkle_tree_leaf_count(&self) -> u32 {
self.merkle_tree_leaf_count
}

pub fn merkle_multi_proof(&self) -> &MerkleProof {
&self.merkle_multi_proof
}

pub fn commitments(&self) -> &Vec<Commitment> {
&self.commitments
}

pub fn commitment_openings(&self) -> &Vec<CommitmentOpening> {
&self.commitment_openings
}
}
11 changes: 11 additions & 0 deletions transcript-core/src/error.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
#[derive(Debug, thiserror::Error, PartialEq)]
pub enum Error {
#[error("An internal error occured")]
InternalError,
#[error("An internal error during serialization or deserialization")]
SerializationError,
#[error("Error during signature verification")]
SignatureVerificationError,
#[error("Attempted to create an invalid range")]
RangeInvalid,
}
15 changes: 15 additions & 0 deletions transcript-core/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
//! This crate contains types associated with the notarized transcript

pub mod commitment;
pub mod document;
pub mod error;
pub mod merkle;
pub mod pubkey;
pub mod signed;
pub mod tls_handshake;

pub type HashCommitment = [u8; 32];

/// A PRG seeds from which to generate garbled circuit active labels, see
/// [crate::commitment::CommitmentType::labels_blake3]
pub type LabelSeed = [u8; 32];
Loading