use crate::{
helpers::{Constraint, Counter},
prelude::*,
};
use snarkvm_fields::PrimeField;
#[cfg(feature = "save_r1cs_hashes")]
use sha2::{Digest, Sha256};
use std::sync::Arc;
#[cfg(feature = "save_r1cs_hashes")]
use std::{
hash::{Hash, Hasher},
sync::Mutex,
};
#[cfg(feature = "save_r1cs_hashes")]
struct Sha256Hasher(Sha256);
#[cfg(feature = "save_r1cs_hashes")]
impl Hasher for Sha256Hasher {
fn write(&mut self, bytes: &[u8]) {
self.0.update(bytes);
}
fn finish(&self) -> u64 {
unimplemented!("Use Digest::finalize instead to get the full SHA-256 digest");
}
}
#[cfg(feature = "save_r1cs_hashes")]
fn hash_to_sha256<T: Hash>(t: &T) -> [u8; 32] {
let mut hasher = Sha256Hasher(Sha256::new());
t.hash(&mut hasher);
hasher.0.finalize().into()
}
pub type Scope = String;
#[cfg(feature = "save_r1cs_hashes")]
pub static R1CS_HASHES: Mutex<Vec<[u8; 32]>> = Mutex::new(Vec::new());
#[derive(Debug, Hash)]
pub struct R1CS<F: PrimeField> {
constants: Vec<Variable<F>>,
pub(crate) public: Vec<Variable<F>>,
pub(crate) private: Vec<Variable<F>>,
pub(crate) constraints: Vec<Arc<Constraint<F>>>,
counter: Counter<F>,
pub(crate) num_variables: u64,
nonzeros: (u64, u64, u64),
}
impl<F: PrimeField> R1CS<F> {
pub(crate) fn new() -> Self {
Self {
constants: Default::default(),
public: vec![Variable::Public(Arc::new((0u64, F::one())))],
private: Default::default(),
constraints: Default::default(),
counter: Default::default(),
num_variables: 1u64,
nonzeros: (0, 0, 0),
}
}
pub(crate) fn push_scope<S: Into<String>>(&mut self, name: S) -> Result<(), String> {
self.counter.push(name)
}
pub(crate) fn pop_scope<S: Into<String>>(&mut self, name: S) -> Result<(), String> {
self.counter.pop(name)
}
pub(crate) fn new_constant(&mut self, value: F) -> Variable<F> {
let variable = Variable::Constant(Arc::new(value));
self.constants.push(variable.clone());
self.counter.increment_constant();
self.num_variables += 1;
variable
}
pub(crate) fn new_public(&mut self, value: F) -> Variable<F> {
let variable = Variable::Public(Arc::new((self.public.len() as u64, value)));
self.public.push(variable.clone());
self.counter.increment_public();
self.num_variables += 1;
variable
}
pub(crate) fn new_private(&mut self, value: F) -> Variable<F> {
let variable = Variable::Private(Arc::new((self.private.len() as u64, value)));
self.private.push(variable.clone());
self.counter.increment_private();
self.num_variables += 1;
variable
}
pub(crate) fn enforce(&mut self, constraint: Constraint<F>) {
let (a_nonzeros, b_nonzeros, c_nonzeros) = constraint.num_nonzeros();
self.nonzeros.0 += a_nonzeros;
self.nonzeros.1 += b_nonzeros;
self.nonzeros.2 += c_nonzeros;
let constraint = Arc::new(constraint);
self.constraints.push(Arc::clone(&constraint));
self.counter.add_constraint(constraint);
}
pub fn is_satisfied(&self) -> bool {
let constraints_satisfied = self.constraints.iter().all(|constraint| constraint.is_satisfied());
if !constraints_satisfied {
return false;
}
#[cfg(not(debug_assertions))]
return true;
#[cfg(debug_assertions)]
self.constraints.iter().all(|constraint| {
let (a, b, c) = constraint.to_terms();
[a, b, c].into_iter().all(|lc| {
lc.to_terms().iter().all(|(variable, _)| match variable {
Variable::Constant(_value) => false, Variable::Private(private) => {
let (index, value) = private.as_ref();
self.private.get(*index as usize).map_or_else(|| false, |v| v.value() == *value)
}
Variable::Public(public) => {
let (index, value) = public.as_ref();
self.public.get(*index as usize).map_or_else(|| false, |v| v.value() == *value)
}
})
})
})
}
pub(crate) fn is_satisfied_in_scope(&self) -> bool {
self.counter.is_satisfied_in_scope()
}
pub(crate) fn scope(&self) -> Scope {
self.counter.scope()
}
pub fn num_constants(&self) -> u64 {
self.constants.len() as u64
}
pub fn num_public(&self) -> u64 {
self.public.len() as u64
}
pub fn num_private(&self) -> u64 {
self.private.len() as u64
}
pub fn num_variables(&self) -> u64 {
self.num_variables
}
pub fn num_constraints(&self) -> u64 {
self.constraints.len() as u64
}
pub fn num_nonzeros(&self) -> (u64, u64, u64) {
self.nonzeros
}
pub(crate) fn num_constants_in_scope(&self) -> u64 {
self.counter.num_constants_in_scope()
}
pub(crate) fn num_public_in_scope(&self) -> u64 {
self.counter.num_public_in_scope()
}
pub(crate) fn num_private_in_scope(&self) -> u64 {
self.counter.num_private_in_scope()
}
pub(crate) fn num_constraints_in_scope(&self) -> u64 {
self.counter.num_constraints_in_scope()
}
pub(crate) fn num_nonzeros_in_scope(&self) -> (u64, u64, u64) {
self.counter.num_nonzeros_in_scope()
}
pub fn to_public_variables(&self) -> &Vec<Variable<F>> {
&self.public
}
pub fn to_private_variables(&self) -> &Vec<Variable<F>> {
&self.private
}
pub fn to_constraints(&self) -> &Vec<Arc<Constraint<F>>> {
&self.constraints
}
#[cfg(feature = "save_r1cs_hashes")]
pub(crate) fn save_hash(&self) {
let r1cs_hash = hash_to_sha256(self);
R1CS_HASHES.lock().unwrap().push(r1cs_hash);
}
}
impl<F: PrimeField> Display for R1CS<F> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let mut output = String::default();
for constraint in self.to_constraints() {
output += &constraint.to_string();
}
output += "\n";
write!(f, "{output}")
}
}