Skip to content

fix(stdlib): Only compute the garbage embedded_curve_result result if we know we will need it#10077

Merged
aakoshh merged 3 commits intomasterfrom
af/9923-embedded-curve-add
Oct 6, 2025
Merged

fix(stdlib): Only compute the garbage embedded_curve_result result if we know we will need it#10077
aakoshh merged 3 commits intomasterfrom
af/9923-embedded-curve-add

Conversation

@aakoshh
Copy link
Contributor

@aakoshh aakoshh commented Oct 3, 2025

Description

Problem*

Resolves #9923

Summary*

Changes embedded_curve_add in the stdlib to only compute the result on the points which are artificially guaranteed to be different if we know that we are doubling the input. Otherwise this is an operation that is guaranteed to fail as x+1 for abscissae is not on the curve, and then the circuit only succeeds when DIE removes the unused instruction.

Brillig never failed because it doesn't use this method, going straight to embedded_curve_add_unsafe.

This will be part of integration tests once #9912 is merged, where any Err observed in interpret will have caused the command to fail.

Additional Context

Here's the SSA before and after it "heals". As we can see v7-v20 are unused and eliminated, but embedded_curve_add(v7, v2, ... will fail because v7 is add v1, Field 1 which is not on the curve, while embedded_curve_add(v1, v2, ... works.

After Mem2Reg (step 9):
acir(inline) predicate_pure fn main f0 {
  b0(v0: Field, v1: Field, v2: Field):
    v7 = add v1, Field 1
    v11 = call embedded_curve_add(v7, v2, u1 0, v1, v2, u1 0, u1 1) -> [(Field, Field, u1); 1]
    v13 = array_get v11, index u32 0 -> Field
    v15 = array_get v11, index u32 1 -> Field
    v17 = array_get v11, index u32 2 -> u1
    v18 = allocate -> &mut Field
    v19 = allocate -> &mut Field
    v20 = allocate -> &mut u1
    v21 = call embedded_curve_add(v1, v2, u1 0, v1, v2, u1 0, u1 1) -> [(Field, Field, u1); 1]
    v22 = array_get v21, index u32 0 -> Field
    v23 = array_get v21, index u32 1 -> Field
    v24 = array_get v21, index u32 2 -> u1
    jmp b1()
  b1():
    jmp b2(v22, v23, v24)
  b2(v3: Field, v4: Field, v5: u1):
    jmp b3()
  b3():
    jmp b4()
  b4():
    return v3, v4, u1 0
}

--- Interpreter result after Mem2Reg (step 9):
Err(Failed to solve blackbox function embedded_curve_add: Point (0000000000000000000000000000000000000000000000000000000000000002, 0000000000000002cf135e7506a45d632d270d45f1181294833fc48d823f272c) is not on curve)
---
After Dead Instruction Elimination (step 10):
acir(inline) predicate_pure fn main f0 {
  b0(v0: Field, v1: Field, v2: Field):
    v8 = call embedded_curve_add(v1, v2, u1 0, v1, v2, u1 0, u1 1) -> [(Field, Field, u1); 1]
    v10 = array_get v8, index u32 0 -> Field
    v12 = array_get v8, index u32 1 -> Field
    jmp b1()
  b1():
    jmp b2(v10, v12)
  b2(v3: Field, v4: Field):
    jmp b3()
  b3():
    jmp b4()
  b4():
    return v3, v4, u1 0
}

--- Interpreter result after Dead Instruction Elimination (step 10):
Ok(Field 3078034153852398078128400807926804309327113743808504829582559963737223069694, Field -9191351987198133172789796342745422989482268917117950487758512501574271532885, u1 0)
---

Documentation*

Check one:

  • No documentation needed.
  • Documentation included in this PR.
  • [For Experimental Features] Documentation to be submitted in a separate PR.

PR Checklist*

  • I have tested the changes locally.
  • I have formatted the changes with Prettier and/or cargo fmt on default settings.

@aakoshh aakoshh requested a review from a team October 3, 2025 15:19
Copy link
Contributor

@github-actions github-actions bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Performance Alert ⚠️

Possible performance regression was detected for benchmark 'Test Suite Duration'.
Benchmark result of this commit is worse than the previous benchmark result exceeding threshold 1.20.

Benchmark suite Current: 97961f7 Previous: 1ffaa3b Ratio
test_report_zkpassport_noir-ecdsa_ 3 s 2 s 1.50

This comment was automatically generated by workflow using github-action-benchmark.

CC: @TomAFrench

Copy link
Contributor

@github-actions github-actions bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Performance Alert ⚠️

Possible performance regression was detected for benchmark 'Execution Time'.
Benchmark result of this commit is worse than the previous benchmark result exceeding threshold 1.20.

Benchmark suite Current: 97961f7 Previous: 1ffaa3b Ratio
rollup-block-root-single-tx 0.003 s 0.002 s 1.50
rollup-checkpoint-merge 0.004 s 0.003 s 1.33
sha512-100-bytes 0.095 s 0.075 s 1.27

This comment was automatically generated by workflow using github-action-benchmark.

CC: @TomAFrench

Copy link
Contributor

@vezenovm vezenovm left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

Some snaps need updating it looks like

@aakoshh aakoshh enabled auto-merge October 6, 2025 08:21
@aakoshh aakoshh added this pull request to the merge queue Oct 6, 2025
Merged via the queue into master with commit e5acaf6 Oct 6, 2025
132 checks passed
@aakoshh aakoshh deleted the af/9923-embedded-curve-add branch October 6, 2025 09:08
AztecBot added a commit to AztecProtocol/aztec-packages that referenced this pull request Oct 8, 2025
Automated pull of nightly from the [noir](https://github.com/noir-lang/noir) programming language, a dependency of Aztec.
BEGIN_COMMIT_OVERRIDE
chore: Remove unnecessary allocation in `expr_with` (noir-lang/noir#10103)
chore(ACIR): inline `maybe_eq_predicate` (noir-lang/noir#10095)
chore: use `u64` over `Field` in template program (noir-lang/noir#10096)
chore: disallow slice arguments to blackbox functions (noir-lang/noir#10090)
chore(brillig_vm): Separate fuzzing module (noir-lang/noir#10091)
chore: ConstrainNotEqual requires acir predicate (noir-lang/noir#10062)
chore: bump version of bb used in tests (noir-lang/noir#10093)
chore: wrapping arithmetic tests (noir-lang/noir#9714)
chore(brillig_vm): Foreign call module and test re-org (noir-lang/noir#10089)
chore: add extra constraint folding pass (noir-lang/noir#9766)
chore: refactor brillig_blocks (noir-lang/noir#10088)
chore: add regression test for #9986 (noir-lang/noir#10087)
chore: Release Noir(1.0.0-beta.14) (noir-lang/noir#9942)
fix(tag_attr): keep whitespace tokens when parsing (noir-lang/noir#9981)
fix: hoist and then deduplicate (noir-lang/noir#10047)
chore: typos and some refactors in `acvm/src/pwg` (noir-lang/noir#10086)
chore: add in hack for `public_dispatch` (noir-lang/noir#10084)
fix(ssa): Avoid going through `i128` when casting signed to `u128` (noir-lang/noir#10045)
chore: avoid zero bits range-checks (noir-lang/noir#10083)
chore: bump external pinned commits (noir-lang/noir#10082)
fix(stdlib): Only compute the garbage `embedded_curve_result` result if we know we will need it (noir-lang/noir#10077)
fix(ssa): Keep defaults for values returned in the databus (noir-lang/noir#10042)
chore: remove unused predicate from mem-op solver (noir-lang/noir#10079)
chore(ACIR): snapshot tests for each instruction (noir-lang/noir#10071)
fix: remove generic length from ECDSA message hash in stdlib (noir-lang/noir#10043)
chore: validate that no jumps to function entry block exist (noir-lang/noir#10076)
feat(brillig): Centralize memory layout policy and reorganize memory regions (noir-lang/noir#9985)
chore(ci): fix permissions about publishing rustdoc (noir-lang/noir#10075)
chore(ACVM): use Vec instead of Hash for memory blocks (noir-lang/noir#10072)
feat(ssa): `constant_folding` with loop (noir-lang/noir#10019)
chore: take truncate into account for bit size (noir-lang/noir#10059)
chore: update check for `u128` overflow in `check_u128_mul_overflow` (noir-lang/noir#9998)
chore: update check for field overflow in `check_u128_mul_overflow` (noir-lang/noir#9968)
chore(ACIR): binary instructions snapshots (noir-lang/noir#10054)
chore(acir): SliceRemove refactor (noir-lang/noir#10058)
fix(fuzzer): Mark DivisionByZero with different types as equivalent (noir-lang/noir#10066)
chore(fuzz): Remove `is_frontend_friendly` from the AST fuzzer (noir-lang/noir#10046)
chore: use new ACIR syntax in docs, and some tests (noir-lang/noir#10057)
fix(ssa): SSA interpreter to use the 2nd arg in `slice_refcount` (noir-lang/noir#10034)
fix(ssa): SSA interpreter to return 0 for `Intrinsic::*RefCount` when constrained (noir-lang/noir#10033)
chore(ssa_fuzzer): fix array get/set  (noir-lang/noir#10031)
fix(acir): Extend slice on dynamic insertion and compilation panic when flattening (noir-lang/noir#10051)
chore(ACIR): extract convert_constrain_error helper (noir-lang/noir#10050)
chore(ACIR): expand signed lt, div and mod in SSA (noir-lang/noir#10036)
chore(ACIR): more consistent syntax and with less noise (noir-lang/noir#10014)
chore(acir): Code gen tests for slice intrinsics (noir-lang/noir#10017)
feat: parse and display SSA databus (noir-lang/noir#9991)
fix(ssa): Handle partially removed `ArrayGet` groups of complex type during OOB checks (noir-lang/noir#10027)
chore(acir): binary operations always have the same operand types (noir-lang/noir#10028)
feat: Add Module::parent and Module::child_modules (noir-lang/noir#10005)
chore: green light for ACVM optimisation (noir-lang/noir#10002)
chore: unit test for brillig solver (greenlight ACVM execution) (noir-lang/noir#9967)
chore(acir): avoid duplication when invoking brillig stdlib call (noir-lang/noir#10025)
chore: Use 8 partitions for rust tests (noir-lang/noir#10026)
chore: green light for ACVM execution audit (noir-lang/noir#9982)
chore: greenlight for ACVM execution (PWG) (noir-lang/noir#9961)
feat: optimize out noop casts on constants (noir-lang/noir#10024)
fix(mem2reg): consider call return aliases (noir-lang/noir#10016)
chore: bump external pinned commits (noir-lang/noir#10022)
fix(parser): enforce left brace after match expression (noir-lang/noir#10018)
chore(acir): Intrinsics and slice_ops modules as well as slice_ops doc comments (noir-lang/noir#10012)
fix: signed division by -1 can overflow (noir-lang/noir#9976)
chore(ci): fix external checks (noir-lang/noir#10009)
chore(ci): add provenance attestations to npm packages (noir-lang/noir#10011)
chore(ACIR): show all expressions as polynomials (noir-lang/noir#10007)
chore: remove unused feature flag (noir-lang/noir#9993)
chore(ci): fix docs breaking JS releases (noir-lang/noir#10010)
chore(ssa_fuzzer): add external coverage registration  (noir-lang/noir#9974)
END_COMMIT_OVERRIDE

Co-authored-by: Tom French <15848336+TomAFrench@users.noreply.github.com>
github-merge-queue bot pushed a commit to AztecProtocol/aztec-packages that referenced this pull request Oct 8, 2025
Automated pull of nightly from the
[noir](https://github.com/noir-lang/noir) programming language, a
dependency of Aztec.
BEGIN_COMMIT_OVERRIDE
chore: Remove unnecessary allocation in `expr_with`
(noir-lang/noir#10103)
chore(ACIR): inline `maybe_eq_predicate`
(noir-lang/noir#10095)
chore: use `u64` over `Field` in template program
(noir-lang/noir#10096)
chore: disallow slice arguments to blackbox functions
(noir-lang/noir#10090)
chore(brillig_vm): Separate fuzzing module
(noir-lang/noir#10091)
chore: ConstrainNotEqual requires acir predicate
(noir-lang/noir#10062)
chore: bump version of bb used in tests
(noir-lang/noir#10093)
chore: wrapping arithmetic tests
(noir-lang/noir#9714)
chore(brillig_vm): Foreign call module and test re-org
(noir-lang/noir#10089)
chore: add extra constraint folding pass
(noir-lang/noir#9766)
chore: refactor brillig_blocks
(noir-lang/noir#10088)
chore: add regression test for #9986
(noir-lang/noir#10087)
chore: Release Noir(1.0.0-beta.14)
(noir-lang/noir#9942)
fix(tag_attr): keep whitespace tokens when parsing
(noir-lang/noir#9981)
fix: hoist and then deduplicate
(noir-lang/noir#10047)
chore: typos and some refactors in `acvm/src/pwg`
(noir-lang/noir#10086)
chore: add in hack for `public_dispatch`
(noir-lang/noir#10084)
fix(ssa): Avoid going through `i128` when casting signed to `u128`
(noir-lang/noir#10045)
chore: avoid zero bits range-checks
(noir-lang/noir#10083)
chore: bump external pinned commits
(noir-lang/noir#10082)
fix(stdlib): Only compute the garbage `embedded_curve_result` result if
we know we will need it (noir-lang/noir#10077)
fix(ssa): Keep defaults for values returned in the databus
(noir-lang/noir#10042)
chore: remove unused predicate from mem-op solver
(noir-lang/noir#10079)
chore(ACIR): snapshot tests for each instruction
(noir-lang/noir#10071)
fix: remove generic length from ECDSA message hash in stdlib
(noir-lang/noir#10043)
chore: validate that no jumps to function entry block exist
(noir-lang/noir#10076)
feat(brillig): Centralize memory layout policy and reorganize memory
regions (noir-lang/noir#9985)
chore(ci): fix permissions about publishing rustdoc
(noir-lang/noir#10075)
chore(ACVM): use Vec instead of Hash for memory blocks
(noir-lang/noir#10072)
feat(ssa): `constant_folding` with loop
(noir-lang/noir#10019)
chore: take truncate into account for bit size
(noir-lang/noir#10059)
chore: update check for `u128` overflow in `check_u128_mul_overflow`
(noir-lang/noir#9998)
chore: update check for field overflow in `check_u128_mul_overflow`
(noir-lang/noir#9968)
chore(ACIR): binary instructions snapshots
(noir-lang/noir#10054)
chore(acir): SliceRemove refactor
(noir-lang/noir#10058)
fix(fuzzer): Mark DivisionByZero with different types as equivalent
(noir-lang/noir#10066)
chore(fuzz): Remove `is_frontend_friendly` from the AST fuzzer
(noir-lang/noir#10046)
chore: use new ACIR syntax in docs, and some tests
(noir-lang/noir#10057)
fix(ssa): SSA interpreter to use the 2nd arg in `slice_refcount`
(noir-lang/noir#10034)
fix(ssa): SSA interpreter to return 0 for `Intrinsic::*RefCount` when
constrained (noir-lang/noir#10033)
chore(ssa_fuzzer): fix array get/set
(noir-lang/noir#10031)
fix(acir): Extend slice on dynamic insertion and compilation panic when
flattening (noir-lang/noir#10051)
chore(ACIR): extract convert_constrain_error helper
(noir-lang/noir#10050)
chore(ACIR): expand signed lt, div and mod in SSA
(noir-lang/noir#10036)
chore(ACIR): more consistent syntax and with less noise
(noir-lang/noir#10014)
chore(acir): Code gen tests for slice intrinsics
(noir-lang/noir#10017)
feat: parse and display SSA databus
(noir-lang/noir#9991)
fix(ssa): Handle partially removed `ArrayGet` groups of complex type
during OOB checks (noir-lang/noir#10027)
chore(acir): binary operations always have the same operand types
(noir-lang/noir#10028)
feat: Add Module::parent and Module::child_modules
(noir-lang/noir#10005)
chore: green light for ACVM optimisation
(noir-lang/noir#10002)
chore: unit test for brillig solver (greenlight ACVM execution)
(noir-lang/noir#9967)
chore(acir): avoid duplication when invoking brillig stdlib call
(noir-lang/noir#10025)
chore: Use 8 partitions for rust tests
(noir-lang/noir#10026)
chore: green light for ACVM execution audit
(noir-lang/noir#9982)
chore: greenlight for ACVM execution (PWG)
(noir-lang/noir#9961)
feat: optimize out noop casts on constants
(noir-lang/noir#10024)
fix(mem2reg): consider call return aliases
(noir-lang/noir#10016)
chore: bump external pinned commits
(noir-lang/noir#10022)
fix(parser): enforce left brace after match expression
(noir-lang/noir#10018)
chore(acir): Intrinsics and slice_ops modules as well as slice_ops doc
comments (noir-lang/noir#10012)
fix: signed division by -1 can overflow
(noir-lang/noir#9976)
chore(ci): fix external checks
(noir-lang/noir#10009)
chore(ci): add provenance attestations to npm packages
(noir-lang/noir#10011)
chore(ACIR): show all expressions as polynomials
(noir-lang/noir#10007)
chore: remove unused feature flag
(noir-lang/noir#9993)
chore(ci): fix docs breaking JS releases
(noir-lang/noir#10010)
chore(ssa_fuzzer): add external coverage registration
(noir-lang/noir#9974)
END_COMMIT_OVERRIDE
mralj pushed a commit to AztecProtocol/aztec-packages that referenced this pull request Oct 13, 2025
Automated pull of nightly from the [noir](https://github.com/noir-lang/noir) programming language, a dependency of Aztec.
BEGIN_COMMIT_OVERRIDE
chore: Remove unnecessary allocation in `expr_with` (noir-lang/noir#10103)
chore(ACIR): inline `maybe_eq_predicate` (noir-lang/noir#10095)
chore: use `u64` over `Field` in template program (noir-lang/noir#10096)
chore: disallow slice arguments to blackbox functions (noir-lang/noir#10090)
chore(brillig_vm): Separate fuzzing module (noir-lang/noir#10091)
chore: ConstrainNotEqual requires acir predicate (noir-lang/noir#10062)
chore: bump version of bb used in tests (noir-lang/noir#10093)
chore: wrapping arithmetic tests (noir-lang/noir#9714)
chore(brillig_vm): Foreign call module and test re-org (noir-lang/noir#10089)
chore: add extra constraint folding pass (noir-lang/noir#9766)
chore: refactor brillig_blocks (noir-lang/noir#10088)
chore: add regression test for #9986 (noir-lang/noir#10087)
chore: Release Noir(1.0.0-beta.14) (noir-lang/noir#9942)
fix(tag_attr): keep whitespace tokens when parsing (noir-lang/noir#9981)
fix: hoist and then deduplicate (noir-lang/noir#10047)
chore: typos and some refactors in `acvm/src/pwg` (noir-lang/noir#10086)
chore: add in hack for `public_dispatch` (noir-lang/noir#10084)
fix(ssa): Avoid going through `i128` when casting signed to `u128` (noir-lang/noir#10045)
chore: avoid zero bits range-checks (noir-lang/noir#10083)
chore: bump external pinned commits (noir-lang/noir#10082)
fix(stdlib): Only compute the garbage `embedded_curve_result` result if we know we will need it (noir-lang/noir#10077)
fix(ssa): Keep defaults for values returned in the databus (noir-lang/noir#10042)
chore: remove unused predicate from mem-op solver (noir-lang/noir#10079)
chore(ACIR): snapshot tests for each instruction (noir-lang/noir#10071)
fix: remove generic length from ECDSA message hash in stdlib (noir-lang/noir#10043)
chore: validate that no jumps to function entry block exist (noir-lang/noir#10076)
feat(brillig): Centralize memory layout policy and reorganize memory regions (noir-lang/noir#9985)
chore(ci): fix permissions about publishing rustdoc (noir-lang/noir#10075)
chore(ACVM): use Vec instead of Hash for memory blocks (noir-lang/noir#10072)
feat(ssa): `constant_folding` with loop (noir-lang/noir#10019)
chore: take truncate into account for bit size (noir-lang/noir#10059)
chore: update check for `u128` overflow in `check_u128_mul_overflow` (noir-lang/noir#9998)
chore: update check for field overflow in `check_u128_mul_overflow` (noir-lang/noir#9968)
chore(ACIR): binary instructions snapshots (noir-lang/noir#10054)
chore(acir): SliceRemove refactor (noir-lang/noir#10058)
fix(fuzzer): Mark DivisionByZero with different types as equivalent (noir-lang/noir#10066)
chore(fuzz): Remove `is_frontend_friendly` from the AST fuzzer (noir-lang/noir#10046)
chore: use new ACIR syntax in docs, and some tests (noir-lang/noir#10057)
fix(ssa): SSA interpreter to use the 2nd arg in `slice_refcount` (noir-lang/noir#10034)
fix(ssa): SSA interpreter to return 0 for `Intrinsic::*RefCount` when constrained (noir-lang/noir#10033)
chore(ssa_fuzzer): fix array get/set  (noir-lang/noir#10031)
fix(acir): Extend slice on dynamic insertion and compilation panic when flattening (noir-lang/noir#10051)
chore(ACIR): extract convert_constrain_error helper (noir-lang/noir#10050)
chore(ACIR): expand signed lt, div and mod in SSA (noir-lang/noir#10036)
chore(ACIR): more consistent syntax and with less noise (noir-lang/noir#10014)
chore(acir): Code gen tests for slice intrinsics (noir-lang/noir#10017)
feat: parse and display SSA databus (noir-lang/noir#9991)
fix(ssa): Handle partially removed `ArrayGet` groups of complex type during OOB checks (noir-lang/noir#10027)
chore(acir): binary operations always have the same operand types (noir-lang/noir#10028)
feat: Add Module::parent and Module::child_modules (noir-lang/noir#10005)
chore: green light for ACVM optimisation (noir-lang/noir#10002)
chore: unit test for brillig solver (greenlight ACVM execution) (noir-lang/noir#9967)
chore(acir): avoid duplication when invoking brillig stdlib call (noir-lang/noir#10025)
chore: Use 8 partitions for rust tests (noir-lang/noir#10026)
chore: green light for ACVM execution audit (noir-lang/noir#9982)
chore: greenlight for ACVM execution (PWG) (noir-lang/noir#9961)
feat: optimize out noop casts on constants (noir-lang/noir#10024)
fix(mem2reg): consider call return aliases (noir-lang/noir#10016)
chore: bump external pinned commits (noir-lang/noir#10022)
fix(parser): enforce left brace after match expression (noir-lang/noir#10018)
chore(acir): Intrinsics and slice_ops modules as well as slice_ops doc comments (noir-lang/noir#10012)
fix: signed division by -1 can overflow (noir-lang/noir#9976)
chore(ci): fix external checks (noir-lang/noir#10009)
chore(ci): add provenance attestations to npm packages (noir-lang/noir#10011)
chore(ACIR): show all expressions as polynomials (noir-lang/noir#10007)
chore: remove unused feature flag (noir-lang/noir#9993)
chore(ci): fix docs breaking JS releases (noir-lang/noir#10010)
chore(ssa_fuzzer): add external coverage registration  (noir-lang/noir#9974)
END_COMMIT_OVERRIDE

Co-authored-by: Tom French <15848336+TomAFrench@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

SSA interpreter fails on test: embedded_curve_ops

2 participants