Skip to content

Commit

Permalink
feat!: error on too large integer value (noir-lang#5371)
Browse files Browse the repository at this point in the history
# Description

## Problem

Resolves noir-lang#4631

## Summary

Changes the lexer to error if an integer literal is greater than or
equal to the field element modulus.

## Additional Context

None.

## Documentation\*

Check one:
- [x] No documentation needed.
- [ ] Documentation included in this PR.
- [ ] **[For Experimental Features]** Documentation to be submitted in a
separate PR.

# PR Checklist\*

- [x] I have tested the changes locally.
- [x] I have formatted the changes with [Prettier](https://prettier.io/)
and/or `cargo fmt` on default settings.
  • Loading branch information
asterite committed Jul 1, 2024
1 parent a8928dd commit 0c4fffa
Show file tree
Hide file tree
Showing 5 changed files with 56 additions and 6 deletions.
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 @@ use super::{
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 @@ -19,6 +21,7 @@ pub struct Lexer<'a> {
done: bool,
skip_comments: bool,
skip_whitespaces: bool,
max_integer: BigInt,
}

pub type SpannedTokenResult = Result<SpannedToken, LexerErrorKind>;
Expand Down Expand Up @@ -61,6 +64,8 @@ impl<'a> Lexer<'a> {
done: false,
skip_comments: true,
skip_whitespaces: true,
max_integer: BigInt::from_biguint(num_bigint::Sign::Plus, FieldElement::modulus())
- BigInt::one(),
}
}

Expand Down Expand Up @@ -376,14 +381,28 @@ impl<'a> Lexer<'a> {
// 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 @@ mod tests {
}
}

#[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
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() {
// Define Baby Jubjub (ERC-2494) parameters in affine representation
let bjj_affine = AffineCurve::new(
168700,
Expand Down

0 comments on commit 0c4fffa

Please sign in to comment.