Skip to content
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
2 changes: 2 additions & 0 deletions changelogs/unreleased/th__fix_field_spec_conflict.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
fixed:
- Ensure custom finite field definitions do not conflict with pre-defined fields
37 changes: 19 additions & 18 deletions lib/Util/Field.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -65,44 +65,45 @@ const Field &Field::getField(StringRef fieldName, EmitErrorFn errFn) {
}

void Field::addField(Field &&f, EmitErrorFn errFn) {
auto it = knownFields.find(f.name());
if (it == knownFields.end()) {
// Field does not exist, add it.
knownFields.try_emplace(f.name(), f);
} else if (it->second != f) {
// Use `tryGetField()` to ensure knownFields is initialized before checking for conflicts.
auto existing = Field::tryGetField(f.name());
if (mlir::succeeded(existing)) {
// Field exists and conflicts with existing definition.
std::string msg;
debug::Appender(msg) << "Definition of \"" << f.name()
<< "\" conflicts with prior definition: prior=" << it->second.prime()
<< ", new=" << f.prime();
<< "\" conflicts with prior definition: prior="
<< existing.value().get().prime() << ", new=" << f.prime();
if (errFn) {
errFn().append(msg).report();
} else {
report_fatal_error(msg.c_str());
}
return;
}
// Field exists and does not conflict, so do nothing.
// Field does not exist, add it.
knownFields.try_emplace(f.name(), f);
}

void Field::initKnownFields() {
static constexpr const char BN128[] = "bn128", BN254[] = "bn254", BABYBEAR[] = "babybear",
GOLDILOCKS[] = "goldilocks", MERSENNE31[] = "mersenne31",
KOALABEAR[] = "koalabear";

auto insert = [](const char *name, const char *primeStr) {
knownFields.try_emplace(name, Field(primeStr, name));
};

// bn128/254, default for circom
addField(
Field("21888242871839275222246405745257275088696311157297823662689037894645226208583", BN128)
);
addField(
Field("21888242871839275222246405745257275088696311157297823662689037894645226208583", BN254)
);
insert(BN128, "21888242871839275222246405745257275088696311157297823662689037894645226208583");
insert(BN254, "21888242871839275222246405745257275088696311157297823662689037894645226208583");
// 15 * 2^27 + 1, default for zirgen
addField(Field("2013265921", BABYBEAR));
insert(BABYBEAR, "2013265921");
// 2^64 - 2^32 + 1, used for plonky2
addField(Field("18446744069414584321", GOLDILOCKS));
insert(GOLDILOCKS, "18446744069414584321");
// 2^31 - 1, used for Plonky3
addField(Field("2147483647", MERSENNE31));
insert(MERSENNE31, "2147483647");
// 2^31 - 2^24 + 1, also for Plonky3
addField(Field("2130706433", KOALABEAR));
insert(KOALABEAR, "2130706433");
}

DynamicAPInt Field::reduce(const DynamicAPInt &i) const {
Expand Down
5 changes: 5 additions & 0 deletions test/Dialect/Felt/felt_spec_fail.llzk
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,8 @@ module attributes {llzk.lang, llzk.fields = [#felt.field<"moo">]} {}

// expected-error@+1{{Definition of "moo" conflicts with prior definition: prior=7, new=9}}
module attributes {llzk.lang, llzk.fields = [#felt.field<"moo", 7>, #felt.field<"moo", 9>]} {}

// -----

// expected-error@+1{{Definition of "babybear" conflicts with prior definition: prior=2013265921, new=3}}
module attributes {llzk.lang, llzk.fields = [#felt.field<"babybear", 3>]} {}