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

feat(stdlib): Add fallback implementation of SHA256 black box function #407

Merged
merged 45 commits into from
Jul 11, 2023
Merged
Show file tree
Hide file tree
Changes from 14 commits
Commits
Show all changes
45 commits
Select commit Hold shift + click to select a range
db1433a
initial
Ethan-000 Jun 22, 2023
b97e105
impl padding
Ethan-000 Jun 22, 2023
ed1596b
fix bytes
Ethan-000 Jun 24, 2023
fbba92b
padding
Ethan-000 Jun 28, 2023
2f01ea2
sha256u32
Ethan-000 Jun 29, 2023
32612da
unfinished
Ethan-000 Jul 1, 2023
c574ad1
.
Ethan-000 Jul 2, 2023
4c4e1df
Merge branch 'master' into sha256_fallback
Ethan-000 Jul 2, 2023
52ca59d
clippy
Ethan-000 Jul 2, 2023
868832b
.
Ethan-000 Jul 2, 2023
6b79031
.
Ethan-000 Jul 2, 2023
810b73b
.
Ethan-000 Jul 3, 2023
e24cbfc
.
Ethan-000 Jul 4, 2023
49b6b45
.
Ethan-000 Jul 4, 2023
1d51cf3
Merge branch 'master' into sha256_fallback
Ethan-000 Jul 4, 2023
895941d
cleanup
Ethan-000 Jul 5, 2023
9bc1fbd
Merge branch 'master' into sha256_fallback
Ethan-000 Jul 5, 2023
528e746
.
Ethan-000 Jul 5, 2023
ec66851
.
Ethan-000 Jul 5, 2023
4c011ac
.
Ethan-000 Jul 5, 2023
4ad60f1
.
Ethan-000 Jul 5, 2023
b6a7759
.
Ethan-000 Jul 5, 2023
79cbec1
.
Ethan-000 Jul 5, 2023
bba8196
.
Ethan-000 Jul 5, 2023
75ea62c
.
Ethan-000 Jul 5, 2023
eba6e5b
.
Ethan-000 Jul 5, 2023
09d59da
Merge branch 'noir-lang:master' into sha256_fallback
Ethan-000 Jul 8, 2023
0b1097e
Merge branch 'master' into sha256_fallback
Ethan-000 Jul 9, 2023
adf7a61
.
Ethan-000 Jul 9, 2023
6ccc6ca
change wu32 -> uint32
Ethan-000 Jul 10, 2023
0eef099
change visibility
Ethan-000 Jul 10, 2023
d35c79c
move logic fallbacks to blackbox_fallbacks folder
Ethan-000 Jul 10, 2023
a8253d9
remove split & add Copy to uint32
Ethan-000 Jul 10, 2023
cb92432
.
Ethan-000 Jul 10, 2023
1a90301
fix based on review
Ethan-000 Jul 10, 2023
e57e9ce
move bit_decomposition
Ethan-000 Jul 10, 2023
48f571c
.
Ethan-000 Jul 10, 2023
122816c
.
Ethan-000 Jul 10, 2023
4843037
.
Ethan-000 Jul 10, 2023
2a37f28
.
Ethan-000 Jul 10, 2023
87179b9
sha256 test
Ethan-000 Jul 10, 2023
682cdbf
remove genetated file
Ethan-000 Jul 10, 2023
acdcbc9
Merge branch 'master' into sha256_fallback
kevaundray Jul 11, 2023
22ae2f3
Merge branch 'master' into sha256_fallback
Ethan-000 Jul 11, 2023
e339999
update with master
Ethan-000 Jul 11, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions acvm/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -32,3 +32,4 @@ bls12_381 = ["acir/bls12_381", "stdlib/bls12_381"]

[dev-dependencies]
rand = "0.8.5"
proptest = "1.0.0"
5 changes: 2 additions & 3 deletions acvm/src/compiler/optimizers/simplify.rs
Original file line number Diff line number Diff line change
Expand Up @@ -432,7 +432,7 @@ impl CircuitSimplifier {
#[cfg(test)]
mod tests {
use acir::{
circuit::{Circuit, Opcode},
circuit::Opcode,
native_types::{Expression, Witness},
FieldElement,
};
Expand Down Expand Up @@ -475,8 +475,7 @@ mod tests {
assert_eq!(circuit.len(), 3);
assert_eq!(simplifier.solved_gates.len(), 1);
let support_all = |_opcode: &Opcode| true;
let mut acir = Circuit::default();
acir.opcodes = circuit;
let acir = acir::circuit::Circuit { opcodes: circuit, ..Default::default() };
let acir = FallbackTransformer::transform(acir, support_all, &simplifier).unwrap();
assert_eq!(acir.opcodes.len(), 2);
}
Expand Down
13 changes: 13 additions & 0 deletions acvm/src/compiler/transformers/fallback.rs
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,19 @@ impl FallbackTransformer {
current_witness_idx,
)
}
BlackBoxFuncCall::SHA256 { inputs, outputs } => {
kevaundray marked this conversation as resolved.
Show resolved Hide resolved
let mut sha256_inputs = Vec::new();
for input in inputs.iter() {
let witness_index = Expression::from(input.witness);
let num_bits = input.num_bits;
sha256_inputs.push((witness_index, num_bits));
}
stdlib::blackbox_fallbacks::sha256::sha256(
sha256_inputs,
outputs.to_vec(),
current_witness_idx,
)
}
_ => {
return Err(CompileError::UnsupportedBlackBox(gc.get_black_box_func()));
}
Expand Down
1 change: 1 addition & 0 deletions acvm/src/pwg/directives/sorting.rs
Original file line number Diff line number Diff line change
Expand Up @@ -247,6 +247,7 @@ pub(super) fn route(inputs: Vec<FieldElement>, outputs: Vec<FieldElement>) -> Ve
mod tests {
use super::route;
use acir::FieldElement;
use proptest as _;
TomAFrench marked this conversation as resolved.
Show resolved Hide resolved
use rand::prelude::*;

fn execute_network(config: Vec<bool>, inputs: Vec<FieldElement>) -> Vec<FieldElement> {
Expand Down
2 changes: 1 addition & 1 deletion acvm/tests/solver.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ use acvm::{
BlackBoxFunctionSolver,
};

struct StubbedBackend;
pub(crate) struct StubbedBackend;

impl BlackBoxFunctionSolver for StubbedBackend {
fn schnorr_verify(
Expand Down
154 changes: 154 additions & 0 deletions acvm/tests/stdlib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,154 @@
mod solver;
use acir::{native_types::Witness, FieldElement};
use acvm::pwg::{PartialWitnessGeneratorStatus, ACVM};
use proptest::prelude::*;
use std::collections::BTreeMap;
use stdlib::blackbox_fallbacks::sha256::Sha256U32;

use crate::solver::StubbedBackend;

proptest! {
#![proptest_config(ProptestConfig {
cases: 99, .. ProptestConfig::default()
})]

#[test]
fn test_sha256_u32_ror(x in 0..u32::MAX, y in 0..32_u32) {
let fe = FieldElement::from(x as u128);
let w = Witness(1);
let result = x.rotate_right(y);

let sha256_u32 = Sha256U32::new(w);

let (w, extra_gates, _) = sha256_u32.ror(y, 2);


let witness_assignments = BTreeMap::from([(Witness(1), fe)]).into();
let mut acvm = ACVM::new(StubbedBackend, extra_gates, witness_assignments);
let solver_status = acvm.solve().expect("should succeed");

prop_assert_eq!(acvm.witness_map().get(&w.inner).unwrap(), &FieldElement::from(result as u128));
prop_assert_eq!(solver_status, PartialWitnessGeneratorStatus::Solved, "should be fully solved");
}

#[test]
fn test_sha256_u32_euclidean_division(x in 0..u32::MAX, y in 0..u32::MAX) {
let lhs = FieldElement::from(x as u128);
let rhs = FieldElement::from(y as u128);
let w1 = Witness(1);
let w2 = Witness(2);
let q = x.div_euclid(y);
let r = x.rem_euclid(y);

let u32_1 = Sha256U32::new(w1);
let u32_2 = Sha256U32::new(w2);

let (q_w, r_w, extra_gates, _) = Sha256U32::euclidean_division(&u32_1, &u32_2, 3);

let witness_assignments = BTreeMap::from([(Witness(1), lhs),(Witness(2), rhs)]).into();
let mut acvm = ACVM::new(StubbedBackend, extra_gates, witness_assignments);
let solver_status = acvm.solve().expect("should succeed");

prop_assert_eq!(acvm.witness_map().get(&q_w.inner).unwrap(), &FieldElement::from(q as u128));
prop_assert_eq!(acvm.witness_map().get(&r_w.inner).unwrap(), &FieldElement::from(r as u128));
prop_assert_eq!(solver_status, PartialWitnessGeneratorStatus::Solved, "should be fully solved");
}

#[test]
fn test_sha256_u32_add(x in 0..u32::MAX, y in 0..u32::MAX, z in 0..u32::MAX) {
let lhs = FieldElement::from(x as u128);
let rhs = FieldElement::from(y as u128);
let rhs_z = FieldElement::from(z as u128);
let result = FieldElement::from(((x as u128).wrapping_add(y as u128) % (1_u128 << 32)).wrapping_add(z as u128) % (1_u128 << 32));
let w1 = Witness(1);
let w2 = Witness(2);
let w3 = Witness(3);

let u32_1 = Sha256U32::new(w1);
let u32_2 = Sha256U32::new(w2);
let u32_3 = Sha256U32::new(w3);

let mut gates = Vec::new();

let (w, extra_gates, num_witness) = u32_1.add(u32_2, 4);
gates.extend(extra_gates);
let (w2, extra_gates, _) = w.add(u32_3, num_witness);
gates.extend(extra_gates);


let witness_assignments = BTreeMap::from([(Witness(1), lhs), (Witness(2), rhs), (Witness(3), rhs_z)]).into();
let mut acvm = ACVM::new(StubbedBackend, gates, witness_assignments);
let solver_status = acvm.solve().expect("should succeed");

prop_assert_eq!(acvm.witness_map().get(&w2.inner).unwrap(), &result);
prop_assert_eq!(solver_status, PartialWitnessGeneratorStatus::Solved, "should be fully solved");
}

#[test]
fn test_sha256_u32_sub(x in 0..u32::MAX, y in 0..u32::MAX, z in 0..u32::MAX) {
let lhs = FieldElement::from(x as u128);
let rhs = FieldElement::from(y as u128);
let rhs_z = FieldElement::from(z as u128);
let result = FieldElement::from(((x as u128).wrapping_sub(y as u128) % (1_u128 << 32)).wrapping_sub(z as u128) % (1_u128 << 32));
let w1 = Witness(1);
let w2 = Witness(2);
let w3 = Witness(3);

let u32_1 = Sha256U32::new(w1);
let u32_2 = Sha256U32::new(w2);
let u32_3 = Sha256U32::new(w3);

let mut gates = Vec::new();

let (w, extra_gates, num_witness) = u32_1.sub(u32_2, 4);
gates.extend(extra_gates);
let (w2, extra_gates, _) = w.sub(u32_3, num_witness);
gates.extend(extra_gates);


let witness_assignments = BTreeMap::from([(Witness(1), lhs), (Witness(2), rhs), (Witness(3), rhs_z)]).into();
let mut acvm = ACVM::new(StubbedBackend, gates, witness_assignments);
let solver_status = acvm.solve().expect("should succeed");

prop_assert_eq!(acvm.witness_map().get(&w2.inner).unwrap(), &result);
prop_assert_eq!(solver_status, PartialWitnessGeneratorStatus::Solved, "should be fully solved");
}

#[test]
fn test_sha256_u32_left_shift(x in 0..u32::MAX, y in 0..32_u32) {
let lhs = FieldElement::from(x as u128);
let w1 = Witness(1);
let result = x.overflowing_shl(y).0;

let u32_1 = Sha256U32::new(w1);

let (w, extra_gates, _) = u32_1.leftshift(y, 2);


let witness_assignments = BTreeMap::from([(Witness(1), lhs)]).into();
let mut acvm = ACVM::new(StubbedBackend, extra_gates, witness_assignments);
let solver_status = acvm.solve().expect("should succeed");

prop_assert_eq!(acvm.witness_map().get(&w.inner).unwrap(), &FieldElement::from(result as u128));
prop_assert_eq!(solver_status, PartialWitnessGeneratorStatus::Solved, "should be fully solved");
}

#[test]
fn test_sha256_u32_right_shift(x in 0..u32::MAX, y in 0..32_u32) {
let lhs = FieldElement::from(x as u128);
let w1 = Witness(1);
let result = x.overflowing_shr(y).0;

let u32_1 = Sha256U32::new(w1);

let (w, extra_gates, _) = u32_1.rightshift(y, 2);


let witness_assignments = BTreeMap::from([(Witness(1), lhs)]).into();
let mut acvm = ACVM::new(StubbedBackend, extra_gates, witness_assignments);
let solver_status = acvm.solve().expect("should succeed");

prop_assert_eq!(acvm.witness_map().get(&w.inner).unwrap(), &FieldElement::from(result as u128));
prop_assert_eq!(solver_status, PartialWitnessGeneratorStatus::Solved, "should be fully solved");
}
}
3 changes: 3 additions & 0 deletions stdlib/src/blackbox_fallbacks/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
pub mod sha256;
mod sha256_u32;
pub mod utils;
Loading