Skip to content

Commit

Permalink
[1 changes] feat: visibility for type aliases (noir-lang/noir#6058)
Browse files Browse the repository at this point in the history
feat: Sync from aztec-packages (noir-lang/noir#6151)
feat: allow silencing an unused variable defined via `let` (noir-lang/noir#6149)
feat: simplify sha256 implementation (noir-lang/noir#6142)
  • Loading branch information
AztecBot committed Sep 25, 2024
1 parent b0d1bab commit 9c380e8
Show file tree
Hide file tree
Showing 38 changed files with 583 additions and 715 deletions.
2 changes: 1 addition & 1 deletion .noir-sync-commit
Original file line number Diff line number Diff line change
@@ -1 +1 @@
164d29e4d1960d16fdeafe2cc8ea8144a769f7b2
66d2a07f0fedb04422c218cbe8d6fb080efac994
2 changes: 1 addition & 1 deletion noir/noir-repo/acvm-repo/acvm_js/build.sh
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ function run_if_available {
require_command jq
require_command cargo
require_command wasm-bindgen
#require_command wasm-opt
require_command wasm-opt

self_path=$(dirname "$(readlink -f "$0")")
pname=$(cargo read-manifest | jq -r '.name')
Expand Down
5 changes: 4 additions & 1 deletion noir/noir-repo/acvm-repo/bn254_blackbox_solver/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,10 @@ mod schnorr;
use ark_ec::AffineRepr;
pub use embedded_curve_ops::{embedded_curve_add, multi_scalar_mul};
pub use generator::generators::derive_generators;
pub use poseidon2::{field_from_hex, poseidon2_permutation, Poseidon2Config, POSEIDON2_CONFIG};
pub use poseidon2::{
field_from_hex, poseidon2_permutation, poseidon_hash, Poseidon2Config, Poseidon2Sponge,
POSEIDON2_CONFIG,
};

// Temporary hack, this ensure that we always use a bn254 field here
// without polluting the feature flags of the `acir_field` crate.
Expand Down
84 changes: 84 additions & 0 deletions noir/noir-repo/acvm-repo/bn254_blackbox_solver/src/poseidon2.rs
Original file line number Diff line number Diff line change
Expand Up @@ -543,6 +543,75 @@ impl<'a> Poseidon2<'a> {
}
}

/// Performs a poseidon hash with a sponge construction equivalent to the one in poseidon2.nr
pub fn poseidon_hash(inputs: &[FieldElement]) -> Result<FieldElement, BlackBoxResolutionError> {
let two_pow_64 = 18446744073709551616_u128.into();
let iv = FieldElement::from(inputs.len()) * two_pow_64;
let mut sponge = Poseidon2Sponge::new(iv, 3);
for input in inputs.iter() {
sponge.absorb(*input)?;
}
sponge.squeeze()
}

pub struct Poseidon2Sponge<'a> {
rate: usize,
poseidon: Poseidon2<'a>,
squeezed: bool,
cache: Vec<FieldElement>,
state: Vec<FieldElement>,
}

impl<'a> Poseidon2Sponge<'a> {
pub fn new(iv: FieldElement, rate: usize) -> Poseidon2Sponge<'a> {
let mut result = Poseidon2Sponge {
cache: Vec::with_capacity(rate),
state: vec![FieldElement::zero(); rate + 1],
squeezed: false,
rate,
poseidon: Poseidon2::new(),
};
result.state[rate] = iv;
result
}

fn perform_duplex(&mut self) -> Result<(), BlackBoxResolutionError> {
// zero-pad the cache
for _ in self.cache.len()..self.rate {
self.cache.push(FieldElement::zero());
}
// add the cache into sponge state
for i in 0..self.rate {
self.state[i] += self.cache[i];
}
self.state = self.poseidon.permutation(&self.state, 4)?;
Ok(())
}

pub fn absorb(&mut self, input: FieldElement) -> Result<(), BlackBoxResolutionError> {
assert!(!self.squeezed);
if self.cache.len() == self.rate {
// If we're absorbing, and the cache is full, apply the sponge permutation to compress the cache
self.perform_duplex()?;
self.cache = vec![input];
} else {
// If we're absorbing, and the cache is not full, add the input into the cache
self.cache.push(input);
}
Ok(())
}

pub fn squeeze(&mut self) -> Result<FieldElement, BlackBoxResolutionError> {
assert!(!self.squeezed);
// If we're in absorb mode, apply sponge permutation to compress the cache.
self.perform_duplex()?;
self.squeezed = true;

// Pop one item off the top of the permutation and return it.
Ok(self.state[0])
}
}

#[cfg(test)]
mod test {
use acir::AcirField;
Expand All @@ -562,4 +631,19 @@ mod test {
];
assert_eq!(result, expected_result);
}

#[test]
fn hash_smoke_test() {
let fields = [
FieldElement::from(1u128),
FieldElement::from(2u128),
FieldElement::from(3u128),
FieldElement::from(4u128),
];
let result = super::poseidon_hash(&fields).expect("should hash successfully");
assert_eq!(
result,
field_from_hex("130bf204a32cac1f0ace56c78b731aa3809f06df2731ebcf6b3464a15788b1b9"),
);
}
}
5 changes: 4 additions & 1 deletion noir/noir-repo/compiler/noirc_frontend/src/ast/statement.rs
Original file line number Diff line number Diff line change
Expand Up @@ -141,13 +141,14 @@ impl StatementKind {
pattern: Pattern,
r#type: UnresolvedType,
expression: Expression,
attributes: Vec<SecondaryAttribute>,
) -> StatementKind {
StatementKind::Let(LetStatement {
pattern,
r#type,
expression,
comptime: false,
attributes: vec![],
attributes,
})
}

Expand Down Expand Up @@ -814,6 +815,7 @@ impl ForRange {
Pattern::Identifier(array_ident.clone()),
UnresolvedTypeData::Unspecified.with_span(Default::default()),
array,
vec![],
),
span: array_span,
};
Expand Down Expand Up @@ -858,6 +860,7 @@ impl ForRange {
Pattern::Identifier(identifier),
UnresolvedTypeData::Unspecified.with_span(Default::default()),
Expression::new(loop_element, array_span),
vec![],
),
span: array_span,
};
Expand Down
6 changes: 4 additions & 2 deletions noir/noir-repo/compiler/noirc_frontend/src/ast/type_alias.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use super::{Ident, UnresolvedGenerics, UnresolvedType};
use super::{Ident, ItemVisibility, UnresolvedGenerics, UnresolvedType};
use iter_extended::vecmap;
use noirc_errors::Span;
use std::fmt::Display;
Expand All @@ -9,6 +9,7 @@ pub struct NoirTypeAlias {
pub name: Ident,
pub generics: UnresolvedGenerics,
pub typ: UnresolvedType,
pub visibility: ItemVisibility,
pub span: Span,
}

Expand All @@ -17,9 +18,10 @@ impl NoirTypeAlias {
name: Ident,
generics: UnresolvedGenerics,
typ: UnresolvedType,
visibility: ItemVisibility,
span: Span,
) -> NoirTypeAlias {
NoirTypeAlias { name, generics, typ, span }
NoirTypeAlias { name, generics, typ, visibility, span }
}
}

Expand Down
5 changes: 5 additions & 0 deletions noir/noir-repo/compiler/noirc_frontend/src/ast/visitor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ pub enum AttributeTarget {
Struct,
Trait,
Function,
Let,
}

/// Implements the [Visitor pattern](https://en.wikipedia.org/wiki/Visitor_pattern) for Noir's AST.
Expand Down Expand Up @@ -1097,6 +1098,10 @@ impl Statement {

impl LetStatement {
pub fn accept(&self, visitor: &mut impl Visitor) {
for attribute in &self.attributes {
attribute.accept(AttributeTarget::Let, visitor);
}

if visitor.visit_let_statement(self) {
self.accept_children(visitor);
}
Expand Down
3 changes: 3 additions & 0 deletions noir/noir-repo/compiler/noirc_frontend/src/debug/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,7 @@ impl DebugInstrumenter {
ast::Pattern::Identifier(ident("__debug_expr", ret_expr.span)),
ast::UnresolvedTypeData::Unspecified.with_span(Default::default()),
ret_expr.clone(),
vec![],
),
span: ret_expr.span,
};
Expand Down Expand Up @@ -249,6 +250,7 @@ impl DebugInstrumenter {
}),
span: let_stmt.expression.span,
},
vec![],
),
span: *span,
}
Expand All @@ -274,6 +276,7 @@ impl DebugInstrumenter {
ast::Pattern::Identifier(ident("__debug_expr", assign_stmt.expression.span)),
ast::UnresolvedTypeData::Unspecified.with_span(Default::default()),
assign_stmt.expression.clone(),
vec![],
);
let expression_span = assign_stmt.expression.span;
let new_assign_stmt = match &assign_stmt.lvalue {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -790,7 +790,7 @@ impl<'context> Elaborator<'context> {
let parameter = DefinitionKind::Local(None);
let typ = self.resolve_inferred_type(typ);
arg_types.push(typ.clone());
(self.elaborate_pattern(pattern, typ.clone(), parameter), typ)
(self.elaborate_pattern(pattern, typ.clone(), parameter, true), typ)
});

let return_type = self.resolve_inferred_type(lambda.return_type);
Expand Down
102 changes: 100 additions & 2 deletions noir/noir-repo/compiler/noirc_frontend/src/elaborator/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -362,8 +362,12 @@ impl<'context> Elaborator<'context> {
if let Kind::Numeric(typ) = &generic.kind {
let definition = DefinitionKind::GenericType(generic.type_var.clone());
let ident = Ident::new(generic.name.to_string(), generic.span);
let hir_ident =
self.add_variable_decl_inner(ident, false, false, false, definition);
let hir_ident = self.add_variable_decl(
ident, false, // mutable
false, // allow_shadowing
false, // warn_if_unused
definition,
);
self.interner.push_definition_type(hir_ident.id, *typ.clone());
}
}
Expand Down Expand Up @@ -760,6 +764,7 @@ impl<'context> Elaborator<'context> {
typ.clone(),
DefinitionKind::Local(None),
&mut parameter_idents,
true, // warn_if_unused
None,
);

Expand Down Expand Up @@ -1126,13 +1131,106 @@ impl<'context> Elaborator<'context> {
self.file = alias.file_id;
self.local_module = alias.module_id;

let name = &alias.type_alias_def.name;
let visibility = alias.type_alias_def.visibility;
let span = alias.type_alias_def.typ.span;

let generics = self.add_generics(&alias.type_alias_def.generics);
self.current_item = Some(DependencyId::Alias(alias_id));
let typ = self.resolve_type(alias.type_alias_def.typ);

if visibility != ItemVisibility::Private {
self.check_aliased_type_is_not_more_private(name, visibility, &typ, span);
}

self.interner.set_type_alias(alias_id, typ, generics);
self.generics.clear();
}

fn check_aliased_type_is_not_more_private(
&mut self,
name: &Ident,
visibility: ItemVisibility,
typ: &Type,
span: Span,
) {
match typ {
Type::Struct(struct_type, generics) => {
let struct_type = struct_type.borrow();
let struct_module_id = struct_type.id.module_id();

// We only check this in types in the same crate. If it's in a different crate
// then it's either accessible (all good) or it's not, in which case a different
// error will happen somewhere else, but no need to error again here.
if struct_module_id.krate == self.crate_id {
// Go to the struct's parent module
let module_data = self.get_module(struct_module_id);
let parent_local_id =
module_data.parent.expect("Expected struct module parent to exist");
let parent_module_id =
ModuleId { krate: struct_module_id.krate, local_id: parent_local_id };
let parent_module_data = self.get_module(parent_module_id);

// Find the struct in the parent module so we can know its visibility
let per_ns = parent_module_data.find_name(&struct_type.name);
if let Some((_, aliased_visibility, _)) = per_ns.types {
if aliased_visibility < visibility {
self.push_err(ResolverError::TypeIsMorePrivateThenItem {
typ: struct_type.name.to_string(),
item: name.to_string(),
span,
});
}
}
}

for generic in generics {
self.check_aliased_type_is_not_more_private(name, visibility, generic, span);
}
}
Type::Tuple(types) => {
for typ in types {
self.check_aliased_type_is_not_more_private(name, visibility, typ, span);
}
}
Type::Alias(alias_type, generics) => {
self.check_aliased_type_is_not_more_private(
name,
visibility,
&alias_type.borrow().get_type(generics),
span,
);
}
Type::Function(args, return_type, env, _) => {
for arg in args {
self.check_aliased_type_is_not_more_private(name, visibility, arg, span);
}
self.check_aliased_type_is_not_more_private(name, visibility, return_type, span);
self.check_aliased_type_is_not_more_private(name, visibility, env, span);
}
Type::MutableReference(typ) | Type::Array(_, typ) | Type::Slice(typ) => {
self.check_aliased_type_is_not_more_private(name, visibility, typ, span);
}
Type::InfixExpr(left, _op, right) => {
self.check_aliased_type_is_not_more_private(name, visibility, left, span);
self.check_aliased_type_is_not_more_private(name, visibility, right, span);
}
Type::FieldElement
| Type::Integer(..)
| Type::Bool
| Type::String(..)
| Type::FmtString(..)
| Type::Unit
| Type::Quoted(..)
| Type::TypeVariable(..)
| Type::Forall(..)
| Type::TraitAsType(..)
| Type::Constant(..)
| Type::NamedGeneric(..)
| Type::Error => (),
}
}

fn collect_struct_definitions(&mut self, structs: &BTreeMap<StructId, UnresolvedStruct>) {
// This is necessary to avoid cloning the entire struct map
// when adding checks after each struct field is resolved.
Expand Down
Loading

0 comments on commit 9c380e8

Please sign in to comment.