Skip to content

Commit

Permalink
progress
Browse files Browse the repository at this point in the history
  • Loading branch information
rw0x0 committed Sep 13, 2024
1 parent d3d79a0 commit 48ba00a
Show file tree
Hide file tree
Showing 6 changed files with 144 additions and 60 deletions.
1 change: 1 addition & 0 deletions co-noir/ultrahonk/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ rust-version.workspace = true
ark-ec.workspace = true
ark-ff.workspace = true
ark-serialize.workspace = true
ark-bn254.workspace = true
eyre.workspace = true
itertools.workspace = true
lazy_static = "1.5"
Expand Down
49 changes: 49 additions & 0 deletions co-noir/ultrahonk/src/field_convert.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
use ark_ff::{One, PrimeField};
use num_bigint::BigUint;

pub trait ConvertField<Des: PrimeField>: PrimeField {
fn convert_field(&self) -> Vec<Des>;
}

impl ConvertField<ark_bn254::Fr> for ark_bn254::Fr {
fn convert_field(&self) -> Vec<ark_bn254::Fr> {
vec![self.to_owned()]
}
}

/**
* @brief Converts grumpkin::fr to 2 bb::fr elements
* @details First, this function must return 2 bb::fr elements because the grumpkin::fr field has a larger modulus than
* the bb::fr field, so we choose to send 1 grumpkin::fr element to 2 bb::fr elements to maintain injectivity.
* This function the reverse of convert_from_bn254_frs(std::span<const bb::fr> fr_vec, grumpkin::fr*) by merging the two
* pairs of limbs back into the 2 bb::fr elements. For the implementation, we want to minimize the number of constraints
* created by the circuit form, which happens to use 68 bit limbs to represent a grumpkin::fr (as a bigfield).
* Therefore, our mapping will split a grumpkin::fr into a 136 bit chunk for the lower two bigfield limbs and the upper
* chunk for the upper two limbs. The upper chunk ends up being 254 - 2*68 = 118 bits as a result. We manipulate the
* value using bitwise masks and shifts to obtain our two chunks.
* @param input
* @return std::array<bb::fr, 2>
*/
impl ConvertField<ark_bn254::Fr> for ark_bn254::Fq {
fn convert_field(&self) -> Vec<ark_bn254::Fr> {
// Goal is to slice up the 64 bit limbs of grumpkin::fr/uint256_t to mirror the 68 bit limbs of bigfield
// We accomplish this by dividing the grumpkin::fr's value into two 68*2=136 bit pieces.
const NUM_LIMB_BITS: u32 = 68;
const LOWER_BITS: u32 = 2 * NUM_LIMB_BITS;
const TOTAL_BITS: u32 = 254;
let lower_mask = (BigUint::one() << LOWER_BITS) - BigUint::one();
let value = BigUint::from(self.0);

debug_assert!(value < (BigUint::one() << TOTAL_BITS));

let res0 = value.to_owned() & lower_mask;
let res1 = value >> LOWER_BITS;

debug_assert!(res1 < (BigUint::one() << (TOTAL_BITS - LOWER_BITS)));

let res0 = ark_bn254::Fr::from(res0);
let res1 = ark_bn254::Fr::from(res1);

vec![res0, res1]
}
}
3 changes: 3 additions & 0 deletions co-noir/ultrahonk/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
pub(crate) mod decider;
pub mod field_convert;
pub(crate) mod oink;
pub mod prover;
mod transcript;
Expand All @@ -10,6 +11,8 @@ use ark_ff::PrimeField;
use prover::{HonkProofError, HonkProofResult};
use types::ProverCrs;

pub(crate) type TranscriptFieldType = ark_bn254::Fr;

// from http://supertech.csail.mit.edu/papers/debruijn.pdf
pub(crate) fn get_msb(inp: u32) -> u8 {
const MULTIPLY_DE_BRUIJNI_BIT_POSIITION: [u8; 32] = [
Expand Down
59 changes: 27 additions & 32 deletions co-noir/ultrahonk/src/oink/prover.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,12 @@
use super::types::ProverMemory;
use crate::{
batch_invert,
field_convert::ConvertField,
prover::{HonkProofError, HonkProofResult},
transcript::Keccak256Transcript,
transcript::{Keccak256Transcript, TranscriptFieldType},
types::ProvingKey,
};
use ark_ec::pairing::Pairing;
use ark_ec::{pairing::Pairing, AffineRepr};
use ark_ff::{One, Zero};
use itertools::izip;
use std::marker::PhantomData;
Expand All @@ -34,13 +35,21 @@ pub struct Oink<P: Pairing> {
phantom_data: PhantomData<P>,
}

impl<P: Pairing> Default for Oink<P> {
impl<P: Pairing> Default for Oink<P>
where
<P::G1Affine as AffineRepr>::BaseField: ConvertField<TranscriptFieldType>,
P::ScalarField: ConvertField<TranscriptFieldType>,
{
fn default() -> Self {
Self::new()
}
}

impl<P: Pairing> Oink<P> {
impl<P: Pairing> Oink<P>
where
<P::G1Affine as AffineRepr>::BaseField: ConvertField<TranscriptFieldType>,
P::ScalarField: ConvertField<TranscriptFieldType>,
{
pub fn new() -> Self {
Self {
memory: ProverMemory::default(),
Expand Down Expand Up @@ -316,7 +325,7 @@ impl<P: Pairing> Oink<P> {
}

// Generate relation separators alphas for sumcheck/combiner computation
fn generate_alphas_round(&mut self, transcript: Keccak256Transcript<P>) {
fn generate_alphas_round(&mut self, transcript: Keccak256Transcript) {
tracing::trace!("generate alpha round");

self.memory.challenges.alphas[0] = transcript.get_challenge();
Expand All @@ -329,7 +338,7 @@ impl<P: Pairing> Oink<P> {

// Add circuit size public input size and public inputs to transcript
fn execute_preamble_round(
transcript: &mut Keccak256Transcript<P>,
transcript: &mut Keccak256Transcript,
proving_key: &ProvingKey<P>,
public_inputs: &[P::ScalarField],
) -> HonkProofResult<()> {
Expand Down Expand Up @@ -360,7 +369,7 @@ impl<P: Pairing> Oink<P> {
// Compute first three wire commitments
fn execute_wire_commitments_round(
&mut self,
transcript: &mut Keccak256Transcript<P>,
transcript: &mut Keccak256Transcript,
proving_key: &ProvingKey<P>,
) -> HonkProofResult<()> {
tracing::trace!("executing wire commitments round");
Expand All @@ -372,9 +381,9 @@ impl<P: Pairing> Oink<P> {
let w_r = crate::commit(proving_key.polynomials.witness.w_r(), &proving_key.crs)?;
let w_o = crate::commit(proving_key.polynomials.witness.w_o(), &proving_key.crs)?;

transcript.add_point(w_l.into());
transcript.add_point(w_r.into());
transcript.add_point(w_o.into());
transcript.send_point_to_verifier("W_L".to_string(), w_l.into());
transcript.send_point_to_verifier("W_R".to_string(), w_r.into());
transcript.send_point_to_verifier("W_O".to_string(), w_o.into());

// Round is done since ultra_honk is no goblin flavor
Ok(())
Expand All @@ -383,27 +392,14 @@ impl<P: Pairing> Oink<P> {
// Compute sorted list accumulator and commitment
fn execute_sorted_list_accumulator_round(
&mut self,
transcript_inout: &mut Keccak256Transcript<P>,
transcript: &mut Keccak256Transcript,
proving_key: &ProvingKey<P>,
) -> HonkProofResult<()> {
tracing::trace!("executing sorted list accumulator round");

// Get the challenges and refresh the transcript
let mut transcript = Keccak256Transcript::<P>::default();
std::mem::swap(&mut transcript, transcript_inout);

self.memory.challenges.eta_1 = transcript.get_challenge();

let mut transcript = Keccak256Transcript::<P>::default();
transcript.add_scalar(self.memory.challenges.eta_1);
self.memory.challenges.eta_2 = transcript.get_challenge();

let mut transcript = Keccak256Transcript::<P>::default();
transcript.add_scalar(self.memory.challenges.eta_2);
self.memory.challenges.eta_3 = transcript.get_challenge();

transcript_inout.add_scalar(self.memory.challenges.eta_3);

self.compute_w4(proving_key);

// Commit to lookup argument polynomials and the finalized (i.e. with memory records) fourth wire polynomial
Expand All @@ -417,17 +413,17 @@ impl<P: Pairing> Oink<P> {
)?;
let w_4 = crate::commit(&self.memory.w_4, &proving_key.crs)?;

transcript_inout.add_point(lookup_read_counts.into());
transcript_inout.add_point(lookup_read_tags.into());
transcript_inout.add_point(w_4.into());
transcript.add_point(lookup_read_counts.into());
transcript.add_point(lookup_read_tags.into());
transcript.add_point(w_4.into());

Ok(())
}

// Fiat-Shamir: beta & gamma
fn execute_log_derivative_inverse_round(
&mut self,
transcript_inout: &mut Keccak256Transcript<P>,
transcript_inout: &mut Keccak256Transcript,
proving_key: &ProvingKey<P>,
) -> HonkProofResult<()> {
tracing::trace!("executing log derivative inverse round");
Expand Down Expand Up @@ -457,7 +453,7 @@ impl<P: Pairing> Oink<P> {
// Compute grand product(s) and commitments.
fn execute_grand_product_computation_round(
&mut self,
transcript: &mut Keccak256Transcript<P>,
transcript: &mut Keccak256Transcript,
proving_key: &ProvingKey<P>,
public_inputs: &[P::ScalarField],
) -> HonkProofResult<()> {
Expand All @@ -477,13 +473,12 @@ impl<P: Pairing> Oink<P> {
mut self,
proving_key: &ProvingKey<P>,
public_inputs: &[P::ScalarField],
transcript: &mut Keccak256Transcript,
) -> HonkProofResult<ProverMemory<P>> {
tracing::trace!("Oink prove");

let mut transcript = Keccak256Transcript::default();

// Add circuit size public input size and public inputs to transcript
Self::execute_preamble_round(&mut transcript, proving_key, public_inputs)?;
Self::execute_preamble_round(transcript, proving_key, public_inputs)?;
// Compute first three wire commitments
self.execute_wire_commitments_round(&mut transcript, proving_key)?;
// Compute sorted list accumulator and commitment
Expand Down
9 changes: 6 additions & 3 deletions co-noir/ultrahonk/src/prover.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use crate::{
decider::{prover::Decider, types::ProverMemory},
get_msb,
oink::prover::Oink,
transcript::Keccak256Transcript,
transcript::{self, Keccak256Transcript},
types::ProvingKey,
NUM_ALPHAS,
};
Expand Down Expand Up @@ -47,7 +47,7 @@ impl<P: Pairing> UltraHonk<P> {
let challenge_size = get_msb(proving_key.circuit_size) as usize;
let mut gate_challenges = Vec::with_capacity(challenge_size);

let mut transcript = Keccak256Transcript::<P>::default();
let mut transcript = Keccak256Transcript::<ark_bn254::Fr>::default();
transcript.add_scalar(memory.relation_parameters.alphas[NUM_ALPHAS - 1]);

gate_challenges.push(transcript.get_challenge());
Expand All @@ -66,8 +66,11 @@ impl<P: Pairing> UltraHonk<P> {
) -> HonkProofResult<()> {
tracing::trace!("UltraHonk prove");

let mut transcript = Keccak256Transcript::default();

let oink = Oink::<P>::default();
let mut memory = ProverMemory::from(oink.prove(proving_key, public_inputs)?);
let mut memory =
ProverMemory::from(oink.prove(proving_key, public_inputs, &mut transcript)?);
self.generate_gate_challenges(&mut memory, proving_key);

let decider = Decider::new(memory);
Expand Down
Loading

0 comments on commit 48ba00a

Please sign in to comment.