Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat!: error on too large integer value #5371

Merged
merged 3 commits into from
Jul 1, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
8 changes: 8 additions & 0 deletions compiler/noirc_frontend/src/lexer/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ pub enum LexerErrorKind {
NotADoubleChar { span: Span, found: Token },
#[error("Invalid integer literal, {:?} is not a integer", found)]
InvalidIntegerLiteral { span: Span, found: String },
#[error("Integer literal is too large")]
IntegerLiteralTooLarge { span: Span, limit: String },
#[error("{:?} is not a valid attribute", found)]
MalformedFuncAttribute { span: Span, found: String },
#[error("Logical and used instead of bitwise and")]
Expand Down Expand Up @@ -46,6 +48,7 @@ impl LexerErrorKind {
LexerErrorKind::UnexpectedCharacter { span, .. } => *span,
LexerErrorKind::NotADoubleChar { span, .. } => *span,
LexerErrorKind::InvalidIntegerLiteral { span, .. } => *span,
LexerErrorKind::IntegerLiteralTooLarge { span, .. } => *span,
LexerErrorKind::MalformedFuncAttribute { span, .. } => *span,
LexerErrorKind::LogicalAnd { span } => *span,
LexerErrorKind::UnterminatedBlockComment { span } => *span,
Expand Down Expand Up @@ -83,6 +86,11 @@ impl LexerErrorKind {
format!(" {found} is not an integer"),
*span,
),
LexerErrorKind::IntegerLiteralTooLarge { span, limit } => (
"Integer literal is too large".to_string(),
format!("value exceeds limit of {limit}"),
*span,
),
LexerErrorKind::MalformedFuncAttribute { span, found } => (
"Malformed function attribute".to_string(),
format!(" {found} is not a valid attribute"),
Expand Down
42 changes: 37 additions & 5 deletions compiler/noirc_frontend/src/lexer/lexer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,11 @@
token_to_borrowed_token, BorrowedToken, IntType, Keyword, SpannedToken, Token, Tokens,
},
};
use acvm::FieldElement;
use acvm::{AcirField, FieldElement};
use noirc_errors::{Position, Span};
use std::str::CharIndices;
use num_bigint::BigInt;
use num_traits::{Num, One};
use std::str::{CharIndices, FromStr};

/// The job of the lexer is to transform an iterator of characters (`char_iter`)
/// into an iterator of `SpannedToken`. Each `Token` corresponds roughly to 1 word or operator.
Expand All @@ -18,7 +20,8 @@
position: Position,
done: bool,
skip_comments: bool,
skip_whitespaces: bool,

Check warning on line 23 in compiler/noirc_frontend/src/lexer/lexer.rs

View workflow job for this annotation

GitHub Actions / Code

Unknown word (whitespaces)
max_integer: BigInt,
}

pub type SpannedTokenResult = Result<SpannedToken, LexerErrorKind>;
Expand Down Expand Up @@ -60,7 +63,9 @@
position: 0,
done: false,
skip_comments: true,
skip_whitespaces: true,

Check warning on line 66 in compiler/noirc_frontend/src/lexer/lexer.rs

View workflow job for this annotation

GitHub Actions / Code

Unknown word (whitespaces)
max_integer: BigInt::from_biguint(num_bigint::Sign::Plus, FieldElement::modulus())

Check warning on line 67 in compiler/noirc_frontend/src/lexer/lexer.rs

View workflow job for this annotation

GitHub Actions / Code

Unknown word (biguint)
- BigInt::one(),
}
}

Expand All @@ -69,8 +74,8 @@
self
}

pub fn skip_whitespaces(mut self, flag: bool) -> Self {

Check warning on line 77 in compiler/noirc_frontend/src/lexer/lexer.rs

View workflow job for this annotation

GitHub Actions / Code

Unknown word (whitespaces)
self.skip_whitespaces = flag;

Check warning on line 78 in compiler/noirc_frontend/src/lexer/lexer.rs

View workflow job for this annotation

GitHub Actions / Code

Unknown word (whitespaces)
self
}

Expand Down Expand Up @@ -113,7 +118,7 @@
match self.next_char() {
Some(x) if Self::is_code_whitespace(x) => {
let spanned = self.eat_whitespace(x);
if self.skip_whitespaces {

Check warning on line 121 in compiler/noirc_frontend/src/lexer/lexer.rs

View workflow job for this annotation

GitHub Actions / Code

Unknown word (whitespaces)
self.next_token()
} else {
Ok(spanned)
Expand Down Expand Up @@ -376,14 +381,28 @@
// Underscores needs to be stripped out before the literal can be converted to a `FieldElement.
let integer_str = integer_str.replace('_', "");

let integer = match FieldElement::try_from_str(&integer_str) {
None => {
let bigint_result = match integer_str.strip_prefix("0x") {
Some(integer_str) => BigInt::from_str_radix(integer_str, 16),
None => BigInt::from_str(&integer_str),
};

let integer = match bigint_result {
Ok(bigint) => {
if bigint > self.max_integer {
return Err(LexerErrorKind::IntegerLiteralTooLarge {
span: Span::inclusive(start, end),
limit: self.max_integer.to_string(),
});
}
let big_uint = bigint.magnitude();
FieldElement::from_be_bytes_reduce(&big_uint.to_bytes_be())
}
Err(_) => {
return Err(LexerErrorKind::InvalidIntegerLiteral {
span: Span::inclusive(start, end),
found: integer_str,
})
}
Some(integer) => integer,
};

let integer_token = Token::Int(integer);
Expand Down Expand Up @@ -899,6 +918,19 @@
}
}

#[test]
fn test_int_too_large() {
let modulus = FieldElement::modulus();
let input = modulus.to_string();

let mut lexer = Lexer::new(&input);
let token = lexer.next_token();
assert!(
matches!(token, Err(LexerErrorKind::IntegerLiteralTooLarge { .. })),
"expected {input} to throw error"
);
}

#[test]
fn test_arithmetic_sugar() {
let input = "+= -= *= /= %=";
Expand Down Expand Up @@ -1185,7 +1217,7 @@
// (expected_token_discriminator, strings_to_lex)
// expected_token_discriminator matches a given token when
// std::mem::discriminant returns the same discriminant for both.
fn blns_base64_to_statements(base64_str: String) -> Vec<(Option<Token>, Vec<String>)> {

Check warning on line 1220 in compiler/noirc_frontend/src/lexer/lexer.rs

View workflow job for this annotation

GitHub Actions / Code

Unknown word (blns)
use base64::engine::general_purpose;
use std::borrow::Cow;
use std::io::Cursor;
Expand Down Expand Up @@ -1243,7 +1275,7 @@
fn test_big_list_of_naughty_strings() {
use std::mem::discriminant;

let blns_contents = include_str!("./blns/blns.base64.json");

Check warning on line 1278 in compiler/noirc_frontend/src/lexer/lexer.rs

View workflow job for this annotation

GitHub Actions / Code

Unknown word (blns)

Check warning on line 1278 in compiler/noirc_frontend/src/lexer/lexer.rs

View workflow job for this annotation

GitHub Actions / Code

Unknown word (blns)

Check warning on line 1278 in compiler/noirc_frontend/src/lexer/lexer.rs

View workflow job for this annotation

GitHub Actions / Code

Unknown word (blns)
let blns_base64: Vec<String> =
serde_json::from_str(blns_contents).expect("BLNS json invalid");
for blns_base64_str in blns_base64 {
Expand Down
5 changes: 5 additions & 0 deletions test_programs/compile_failure/integer_too_large/Nargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
[package]
name = "integer_too_large"
type = "bin"
authors = [""]
[dependencies]
4 changes: 4 additions & 0 deletions test_programs/compile_failure/integer_too_large/src/main.nr
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
fn main(x: Field) {
let too_large: Field = 233149999999999999999999999999999999999999999999999999999999923314999999999999999999999999999999999999999999999999999999999923314999999999999999999999999999999999999999999999999999999999;
assert(x == too_large);
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,11 @@ use std::ec::swcurve::curvegroup::Point as SWG;

use std::ec::montcurve::affine::Point as MGaffine;
use std::ec::montcurve::curvegroup::Point as MG;
use std::compat;

fn main() {
// This test only makes sense if Field is the right prime field.
if 21888242871839275222246405745257275088548364400416034343698204186575808495617 == 0 {
if compat::is_bn254() {
asterite marked this conversation as resolved.
Show resolved Hide resolved
// Define Baby Jubjub (ERC-2494) parameters in affine representation
let bjj_affine = AffineCurve::new(
168700,
Expand Down
Loading