Skip to content
This repository has been archived by the owner on Apr 9, 2024. It is now read-only.

feat: Add Log Directive #61

Merged
merged 12 commits into from
Feb 4, 2023
25 changes: 25 additions & 0 deletions acir/src/circuit/directives.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,8 @@ pub enum Directive {
b: Vec<Witness>,
radix: u32,
},

Log(LogInfo),
}

impl Directive {
Expand All @@ -58,6 +60,7 @@ impl Directive {
Directive::Truncate { .. } => "truncate",
Directive::OddRange { .. } => "odd_range",
Directive::ToRadix { .. } => "to_radix",
Directive::Log { .. } => "log",
}
}
fn to_u16(&self) -> u16 {
Expand All @@ -67,6 +70,7 @@ impl Directive {
Directive::Truncate { .. } => 2,
Directive::OddRange { .. } => 3,
Directive::ToRadix { .. } => 4,
Directive::Log { .. } => 5,
}
}

Expand Down Expand Up @@ -116,6 +120,17 @@ impl Directive {
}
write_u32(&mut writer, *radix)?;
}
Directive::Log(info) => match info {
LogInfo::FinalizedOutput(output_string) => {
write_bytes(&mut writer, output_string.as_bytes())?;
}
LogInfo::WitnessOutput(witnesses) => {
write_u32(&mut writer, witnesses.len() as u32)?;
for w in witnesses {
write_u32(&mut writer, w.witness_index())?;
}
}
},
};

Ok(())
Expand Down Expand Up @@ -184,6 +199,16 @@ impl Directive {
}
}

#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
// If values are compile time and/or known during
// evaluation, we can form an output string during ACIR generation.
// Otherwise, we must store witnesses whose values will
// be fetched during the PWG stage.
pub enum LogInfo {
FinalizedOutput(String),
WitnessOutput(Vec<Witness>),
}

#[test]
fn serialisation_roundtrip() {
fn read_write(directive: Directive) -> (Directive, Directive) {
Expand Down
11 changes: 10 additions & 1 deletion acir/src/circuit/opcodes.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use std::io::{Read, Write};

use super::directives::Directive;
use super::directives::{Directive, LogInfo};
use crate::native_types::{Expression, Witness};
use crate::serialisation::{read_n, read_u16, read_u32, write_bytes, write_u16, write_u32};
use crate::BlackBoxFunc;
Expand Down Expand Up @@ -164,6 +164,15 @@ impl std::fmt::Display for Opcode {
b.last().unwrap().witness_index(),
)
}
Opcode::Directive(Directive::Log(info)) => match info {
LogInfo::FinalizedOutput(output_string) => write!(f, "Log: {output_string}"),
LogInfo::WitnessOutput(witnesses) => write!(
f,
"Log: _{}..._{}",
witnesses.first().unwrap().witness_index(),
witnesses.last().unwrap().witness_index()
),
},
}
}
}
Expand Down
5 changes: 1 addition & 4 deletions acvm/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -211,10 +211,7 @@ pub fn default_is_blackbox_supported(
// attempt to transform into supported gates. If these are also not available
// then a compiler error will be emitted.
fn plonk_is_supported(opcode: &BlackBoxFunc) -> bool {
match opcode {
BlackBoxFunc::AES => false,
_ => true,
}
!matches!(opcode, BlackBoxFunc::AES)
}

match language {
Expand Down
43 changes: 42 additions & 1 deletion acvm/src/pwg/directives.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
use std::collections::BTreeMap;

use acir::{circuit::directives::Directive, native_types::Witness, FieldElement};
use acir::{
circuit::directives::{Directive, LogInfo},
native_types::Witness,
FieldElement,
};
use num_bigint::BigUint;
use num_traits::{One, Zero};

Expand Down Expand Up @@ -108,6 +112,43 @@ pub fn solve_directives(
initial_witness.insert(*b, FieldElement::from_be_bytes_reduce(&int_b.to_bytes_be()));
initial_witness.insert(*r, FieldElement::from_be_bytes_reduce(&int_r.to_bytes_be()));

Ok(())
}
Directive::Log(info) => {
let witnesses = match info {
LogInfo::FinalizedOutput(output_string) => {
println!("{output_string}");
return Ok(());
}
LogInfo::WitnessOutput(witnesses) => witnesses,
};

if witnesses.len() == 1 {
let witness = &witnesses[0];
let log_value = witness_to_value(initial_witness, *witness)?;
println!("{}", log_value.to_hex());

return Ok(());
}

// If multiple witnesses are to be fetched for a log directive,
// it assumed that an array is meant to be printed to standard output
//
// Collect all field element values corresponding to the given witness indices
// and convert them to hex strings.
let mut elements_as_hex = Vec::with_capacity(witnesses.len());
for witness in witnesses {
let element = witness_to_value(initial_witness, *witness)?;
elements_as_hex.push(element.to_hex());
}

// Join all of the hex strings using a comma
let comma_separated_elements = elements_as_hex.join(",");

let output_witnesses_string = "[".to_owned() + &comma_separated_elements + "]";

println!("{output_witnesses_string}");

Ok(())
}
}
Expand Down