Skip to content

Commit

Permalink
Implement witness_message() APIs
Browse files Browse the repository at this point in the history
  • Loading branch information
therealyingtong committed Jun 2, 2021
1 parent 5b07764 commit 773d143
Showing 1 changed file with 106 additions and 3 deletions.
109 changes: 106 additions & 3 deletions src/circuit/gadget/sinsemilla/chip.rs
Original file line number Diff line number Diff line change
Expand Up @@ -210,7 +210,35 @@ impl<C: CurveAffine> SinsemillaInstructions<C> for SinsemillaChip<C> {
message: Vec<Option<bool>>,
num_words: usize,
) -> Result<Vec<Self::MessagePiece>, Error> {
todo!()
// Message must have at most SinsemillaC words.
assert!(num_words <= SinsemillaC);

let message = if message.len() < num_words * K {
// If message is shorter than the number of words specified, pad it to the
// correct length.
let pad_len = num_words * K - message.len();
let mut message = message.clone();
message.extend_from_slice(&vec![None; pad_len]);
message
} else {
// If message is longer than the number of words specified, truncate it
// to the correct length.
message[..(num_words * K)].to_vec()
};

// Number of words that can be contained in a piece
let piece_num_words = C::Base::NUM_BITS as usize / K;
message
.chunks(piece_num_words * K)
.map(|piece| {
let num_words = (piece.len() + K - 1) / K;
self.witness_message_piece_bitstring(
layouter.namespace(|| "message piece"),
piece.to_vec(),
num_words,
)
})
.collect()
}

#[allow(non_snake_case)]
Expand All @@ -220,7 +248,66 @@ impl<C: CurveAffine> SinsemillaInstructions<C> for SinsemillaChip<C> {
message: Vec<Option<bool>>,
num_words: usize,
) -> Result<Self::MessagePiece, Error> {
todo!()
println!("num_words: {}", num_words);
assert_eq!(message.len(), num_words * 10);
// Message piece must be at most `ceil(C::Base::NUM_BITS / 10)` bits
let max_len = C::Base::NUM_BITS / 10;
assert!(num_words <= max_len as usize);

// A `K`-bit bitstring.
struct Word([Option<bool>; K]);

// Chunk message into `K`-bit words.
let message: Vec<Word> = message
.chunks_exact(K)
.map(|word| Word(word.try_into().unwrap()))
.collect();

// Closure to parse a vector of K-bit words into a base field element.
let to_base_field = |words: &[Word]| -> Option<C::Base> {
let bits = words
.into_iter()
.map(|word| word.0.to_vec())
.flatten()
.collect::<Vec<Option<bool>>>();
let bytearray: Vec<Option<u8>> = bits
.chunks(8)
.map(|byte| {
byte.iter().rev().fold(Some(0u8), |acc, bit| {
acc.zip(*bit).map(|(acc, bit)| acc * 2 + bit as u8)
})
})
.collect();

// Pad to 32 bytes
let pad_len = 32 - bytearray.len();
let bytearray: Option<Vec<u8>> = bytearray.into_iter().collect();
let bytearray: Option<Vec<u8>> = bytearray.map(|mut bytearray| {
bytearray.extend_from_slice(&vec![0; pad_len]);
bytearray
});

bytearray.map(|bytearray| C::Base::from_bytes(&bytearray.try_into().unwrap()).unwrap())
};

let config = self.config().clone();

layouter.assign_region(
|| "message",
|mut region: Region<'_, C::Base>| {
let piece_value = to_base_field(&message);
let cell = region.assign_advice(
|| "message piece",
config.bits,
0,
|| piece_value.ok_or(Error::SynthesisError),
)?;
Ok(MessagePiece::new(
CellValue::new(cell, piece_value),
message.len(),
))
},
)
}

fn witness_message_piece_field(
Expand All @@ -229,7 +316,23 @@ impl<C: CurveAffine> SinsemillaInstructions<C> for SinsemillaChip<C> {
value: Option<C::Base>,
num_words: usize,
) -> Result<Self::MessagePiece, Error> {
todo!()
let config = self.config().clone();

let cell = layouter.assign_region(
|| "witness message piece",
|mut region| {
region.assign_advice(
|| "witness message piece",
config.bits,
0,
|| value.ok_or(Error::SynthesisError),
)
},
)?;
Ok(Self::prepare_message_piece(
&CellValue::new(cell, value),
num_words,
))
}

fn prepare_message_piece(cell: &Self::CellValue, length: usize) -> Self::MessagePiece {
Expand Down

0 comments on commit 773d143

Please sign in to comment.