Skip to content

Commit

Permalink
Abstract out sinsemilla::message module
Browse files Browse the repository at this point in the history
  • Loading branch information
therealyingtong committed Jun 4, 2021
1 parent 2d39432 commit 44dd0eb
Show file tree
Hide file tree
Showing 4 changed files with 424 additions and 323 deletions.
56 changes: 25 additions & 31 deletions src/circuit/gadget/sinsemilla.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,18 @@ use halo2::{arithmetic::CurveAffine, circuit::Layouter, plonk::Error};
use std::fmt::Debug;

pub mod chip;
mod message;

pub use chip::{SinsemillaChip, SinsemillaConfig};

/// The set of circuit instructions required to use the [`Sinsemilla`](https://zcash.github.io/halo2/design/gadgets/sinsemilla.html) gadget.
/// This trait is bounded on two constant parameters: `K`, the number of bits
/// in each word accepted by the Sinsemilla hash, and `MAX_WORDS`, the maximum
/// number of words that a single hash instance can process.
pub trait SinsemillaInstructions<C: CurveAffine, const K: usize, const MAX_WORDS: usize> {
/// A message composed of [`MessagePiece`]s.
type Message: From<Vec<Self::MessagePiece>>;

/// A piece in a message containing a number of `K`-bit words.
/// A [`MessagePiece`] fits in a single base field element,
/// which means it can only contain up to `N` words, where
Expand All @@ -20,9 +25,6 @@ pub trait SinsemillaInstructions<C: CurveAffine, const K: usize, const MAX_WORDS
/// up to `N = 25` words in a single base field element.
type MessagePiece;

/// A cell in the circuit with an optional assigned value.
type CellValue;

/// The x-coordinate of a point output of [`hash_to_point`].
type X;
/// A point output of [`hash_to_point`].
Expand Down Expand Up @@ -51,7 +53,7 @@ pub trait SinsemillaInstructions<C: CurveAffine, const K: usize, const MAX_WORDS
layouter: impl Layouter<C::Base>,
message: Vec<Option<bool>>,
num_words: usize,
) -> Result<Vec<Self::MessagePiece>, Error>;
) -> Result<Self::Message, Error>;

/// Witness a message piece given a bitstring. Returns a [`MessagePiece`]
/// encoding the given message.
Expand Down Expand Up @@ -84,17 +86,13 @@ pub trait SinsemillaInstructions<C: CurveAffine, const K: usize, const MAX_WORDS
num_words: usize,
) -> Result<Self::MessagePiece, Error>;

/// Prepare a message piece given a [`CellValue`] and the number of words
/// encoded in the contained base field element.
fn prepare_message_piece(cell: &Self::CellValue, num_words: usize) -> Self::MessagePiece;

/// Hashes a message to an ECC curve point.
#[allow(non_snake_case)]
fn hash_to_point(
&self,
layouter: impl Layouter<C::Base>,
Q: C,
message: Vec<Self::MessagePiece>,
message: Self::Message,
) -> Result<Self::Point, Error>;

/// Extracts the x-coordinate of the output of a Sinsemilla hash.
Expand All @@ -110,7 +108,7 @@ where
SinsemillaChip: SinsemillaInstructions<C, K, MAX_WORDS> + Clone + Debug + Eq,
{
chip: SinsemillaChip,
inner: Vec<SinsemillaChip::MessagePiece>,
inner: SinsemillaChip::Message,
}

impl<C: CurveAffine, SinsemillaChip, const K: usize, const MAX_WORDS: usize>
Expand All @@ -132,24 +130,9 @@ where
fn from_pieces(chip: SinsemillaChip, pieces: Vec<SinsemillaChip::MessagePiece>) -> Self {
Self {
chip,
inner: pieces,
inner: pieces.into(),
}
}

/// Return the `MessagePiece`s contained in this `Message`.
fn pieces(&self) -> &[SinsemillaChip::MessagePiece] {
&self.inner
}

/// Construct a `MessagePiece` given a vector of `CellValue`s and the
/// number of words encoded in the contained base field elements.
fn new_piece(
_chip: SinsemillaChip,
cell: &SinsemillaChip::CellValue,
num_words: usize,
) -> SinsemillaChip::MessagePiece {
SinsemillaChip::prepare_message_piece(cell, num_words)
}
}

#[allow(non_snake_case)]
Expand Down Expand Up @@ -337,9 +320,12 @@ mod tests {
SinsemillaInstructions,
};

use crate::circuit::gadget::ecc::{
chip::{EccChip, EccConfig},
ScalarFixed,
use crate::circuit::gadget::{
ecc::{
chip::{EccChip, EccConfig},
ScalarFixed,
},
utilities::Var,
};

use std::convert::TryInto;
Expand Down Expand Up @@ -432,7 +418,11 @@ mod tests {
)?;
let left = merkle_crh.hash_to_point(layouter.namespace(|| "left"), left)?;
let left = left.extract_p();
Message::new_piece(chip1.clone(), left.inner(), 25)
chip1.witness_message_piece_field(
layouter.namespace(|| "witness left piece"),
left.inner().value(),
25,
)?
};

// Right leaf
Expand All @@ -447,7 +437,11 @@ mod tests {
)?;
let right = merkle_crh.hash_to_point(layouter.namespace(|| "right"), right)?;
let right = right.extract_p();
Message::new_piece(chip1.clone(), right.inner(), 25)
chip1.witness_message_piece_field(
layouter.namespace(|| "witness left piece"),
right.inner().value(),
25,
)?
};

// Layer 0
Expand Down
71 changes: 20 additions & 51 deletions src/circuit/gadget/sinsemilla/chip.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
use super::super::ecc::chip::{CellValue, EccPoint};
use super::{CommitDomains, HashDomains, SinsemillaInstructions};
use super::{
message::{Message, MessagePiece},
CommitDomains, HashDomains, SinsemillaInstructions,
};
use crate::circuit::gadget::{
ecc::chip::EccPoint,
utilities::{CellValue, Var},
};

use crate::constants::OrchardFixedBasesFull;
use crate::primitives::sinsemilla::{
Expand All @@ -23,27 +29,6 @@ use generator_table::{GeneratorTableChip, GeneratorTableConfig};

mod hash_to_point;

/// A [`MessagePiece`] of some bitlength.
///
/// The piece must fit within a cell, which means its length cannot exceed
/// the base field's `NUM_BITS`.
#[derive(Clone, Debug)]
pub struct MessagePiece<F: FieldExt> {
cell: CellValue<F>,
// The number of K-bit words in this message piece.
num_words: usize,
}

impl<F: FieldExt> MessagePiece<F> {
fn new(cell: CellValue<F>, num_words: usize) -> Self {
Self { cell, num_words }
}

fn num_words(&self) -> usize {
self.num_words
}
}

/// TODO: Configuration for the Sinsemilla hash chip
#[derive(Clone, Debug)]
pub struct SinsemillaConfig {
Expand Down Expand Up @@ -199,8 +184,8 @@ impl<C: CurveAffine, const K: usize, const MAX_WORDS: usize> SinsemillaChip<C, K
impl<C: CurveAffine, const K: usize, const MAX_WORDS: usize> SinsemillaInstructions<C, K, MAX_WORDS>
for SinsemillaChip<C, K, MAX_WORDS>
{
type MessagePiece = MessagePiece<C::Base>;
type CellValue = CellValue<C::Base>;
type Message = Message<C::Base, K, MAX_WORDS>;
type MessagePiece = MessagePiece<C::Base, K>;

type X = CellValue<C::Base>;
type Point = EccPoint<C>;
Expand All @@ -215,7 +200,7 @@ impl<C: CurveAffine, const K: usize, const MAX_WORDS: usize> SinsemillaInstructi
mut layouter: impl Layouter<C::Base>,
message: Vec<Option<bool>>,
num_words: usize,
) -> Result<Vec<Self::MessagePiece>, Error> {
) -> Result<Self::Message, Error> {
// Message must have at most `MAX_WORDS` words.
assert!(num_words <= MAX_WORDS);

Expand All @@ -224,17 +209,19 @@ impl<C: CurveAffine, const K: usize, const MAX_WORDS: usize> SinsemillaInstructi

// Message piece must be at most `ceil(C::Base::NUM_BITS / 10)` bits
let piece_num_words = C::Base::NUM_BITS as usize / K;
message
let pieces: Result<Vec<_>, _> = message
.chunks(piece_num_words * K)
.map(|piece| {
.map(|piece| -> Result<Self::MessagePiece, Error> {
let num_words = (piece.len() + K - 1) / K;
self.witness_message_piece_bitstring(
layouter.namespace(|| "message piece"),
piece.to_vec(),
num_words,
)
})
.collect()
.collect();

pieces.map(|pieces| pieces.into())
}

#[allow(non_snake_case)]
Expand Down Expand Up @@ -282,10 +269,7 @@ impl<C: CurveAffine, const K: usize, const MAX_WORDS: usize> SinsemillaInstructi
0,
|| piece_value.ok_or(Error::SynthesisError),
)?;
Ok(MessagePiece::new(
CellValue::new(cell, piece_value),
num_words,
))
Ok(MessagePiece::new(cell, piece_value, num_words))
},
)
}
Expand All @@ -309,34 +293,19 @@ impl<C: CurveAffine, const K: usize, const MAX_WORDS: usize> SinsemillaInstructi
)
},
)?;
Ok(Self::prepare_message_piece(
&CellValue::new(cell, value),
num_words,
))
}

fn prepare_message_piece(cell: &Self::CellValue, length: usize) -> Self::MessagePiece {
MessagePiece::new(cell.clone(), length)
Ok(MessagePiece::new(cell, value, num_words))
}

#[allow(non_snake_case)]
fn hash_to_point(
&self,
mut layouter: impl Layouter<C::Base>,
Q: C,
message: Vec<Self::MessagePiece>,
message: Self::Message,
) -> Result<Self::Point, Error> {
let config = self.config();
layouter.assign_region(
|| "hash_to_point",
|mut region| {
hash_to_point::hash_message::<C, K, MAX_WORDS>(
&mut region,
config.clone(),
Q,
&message,
)
},
|mut region| self.hash_message(&mut region, Q, &message),
)
}

Expand Down
Loading

0 comments on commit 44dd0eb

Please sign in to comment.