From f90a3d99b53396894fa7c9708a474c7dbe6f1672 Mon Sep 17 00:00:00 2001 From: guipublic Date: Fri, 27 Jun 2025 14:10:50 +0000 Subject: [PATCH 1/3] check both coordinates for point doubling --- .../src/ssa/opt/flatten_cfg.rs | 3 +- .../embedded_curve_ops/src/main.nr | 54 ++++++++++++++++++- 2 files changed, 55 insertions(+), 2 deletions(-) diff --git a/compiler/noirc_evaluator/src/ssa/opt/flatten_cfg.rs b/compiler/noirc_evaluator/src/ssa/opt/flatten_cfg.rs index e5da1714c01..0027d6a819e 100644 --- a/compiler/noirc_evaluator/src/ssa/opt/flatten_cfg.rs +++ b/compiler/noirc_evaluator/src/ssa/opt/flatten_cfg.rs @@ -1073,7 +1073,8 @@ impl<'f> Context<'f> { call_stack: CallStackId, ) -> (ValueId, ValueId) { let index = !abscissa as usize; - if inputs[3 + index] == inputs[index] { + if inputs[3] == inputs[0] && inputs[4] == inputs[1] { + // Point doubling let predicated_value = self.var_or(inputs[index], condition, generators[index], call_stack); (predicated_value, predicated_value) diff --git a/test_programs/execution_success/embedded_curve_ops/src/main.nr b/test_programs/execution_success/embedded_curve_ops/src/main.nr index b2f6b68ca92..d9e8b64646a 100644 --- a/test_programs/execution_success/embedded_curve_ops/src/main.nr +++ b/test_programs/execution_success/embedded_curve_ops/src/main.nr @@ -1,4 +1,4 @@ -use std::ops::Add; +use std::{embedded_curve_ops::embedded_curve_add_unsafe, ops::Add}; fn main(priv_key: Field, pub_x: pub Field, pub_y: pub Field) { let g1 = std::embedded_curve_ops::EmbeddedCurvePoint::generator(); @@ -39,4 +39,56 @@ fn main(priv_key: Field, pub_x: pub Field, pub_y: pub Field) { [scalar, const_zero, scalar], ); assert(partial_mul == g1); + + // Additional tests for validating embedded_curve_add_unsafe under a conditional + if pub_x == pub_y { + let a1 = std::embedded_curve_ops::EmbeddedCurvePoint { x: 1, y: 2, is_infinite: false }; + let a2 = std::embedded_curve_ops::EmbeddedCurvePoint { x: 1, y: 3, is_infinite: false }; + let doubling = a1.double(); + assert(doubling.x == 1); + let res = embedded_curve_add_unsafe(a1, a2); + assert(res.x == 1); + + let a1 = std::embedded_curve_ops::EmbeddedCurvePoint { + x: pub_x + 1, + y: pub_y, + is_infinite: false, + }; + let a2 = std::embedded_curve_ops::EmbeddedCurvePoint { + x: pub_x + 1, + y: pub_y + 1, + is_infinite: false, + }; + let doubling = a1.double(); + assert(doubling.x == 1); + let res = embedded_curve_add_unsafe(a1, a2); + assert(res.x == 1); + + let a1 = std::embedded_curve_ops::EmbeddedCurvePoint { x: 2, y: 3, is_infinite: false }; + let a2 = std::embedded_curve_ops::EmbeddedCurvePoint { + x: pub_x, + y: pub_y + 1 as Field, + is_infinite: false, + }; + let res = embedded_curve_add_unsafe(a1, a2); + assert(res.x == 1); + + let a1 = std::embedded_curve_ops::EmbeddedCurvePoint { x: 2, y: 3, is_infinite: false }; + let a2 = std::embedded_curve_ops::EmbeddedCurvePoint { x: 2, y: 4, is_infinite: false }; + let res = embedded_curve_add_unsafe(a1, a2); + assert(res.x == 1); + + let a1 = std::embedded_curve_ops::EmbeddedCurvePoint { x: 2, y: 3, is_infinite: false }; + let a2 = std::embedded_curve_ops::EmbeddedCurvePoint { x: 2, y: 3, is_infinite: false }; + let res = embedded_curve_add_unsafe(a1, a2); + assert(res.x == 1); + let a1 = std::embedded_curve_ops::EmbeddedCurvePoint { x: 1, y: 3, is_infinite: false }; + let a2 = std::embedded_curve_ops::EmbeddedCurvePoint { x: 1, y: 3, is_infinite: false }; + let res = embedded_curve_add_unsafe(a1, a2); + assert(res.x == 1); + let a1 = std::embedded_curve_ops::EmbeddedCurvePoint { x: pub_x, y: 3, is_infinite: false }; + let a2 = std::embedded_curve_ops::EmbeddedCurvePoint { x: pub_x, y: 2, is_infinite: false }; + let res = embedded_curve_add_unsafe(a1, a2); + assert(res.x == 1); + } } From 24ac223a21a54659100bbdc4306b261642d8ac70 Mon Sep 17 00:00:00 2001 From: guipublic Date: Fri, 27 Jun 2025 14:50:52 +0000 Subject: [PATCH 2/3] snapshots --- .../execute__tests__expanded.snap | 92 ++++++++++++++++++- ...ig_false_inliner_-9223372036854775808.snap | 69 +++++++++++--- ..._tests__force_brillig_false_inliner_0.snap | 69 +++++++++++--- ...lig_false_inliner_9223372036854775807.snap | 69 +++++++++++--- ...lig_true_inliner_-9223372036854775808.snap | 6 +- ...__tests__force_brillig_true_inliner_0.snap | 6 +- ...llig_true_inliner_9223372036854775807.snap | 6 +- 7 files changed, 262 insertions(+), 55 deletions(-) diff --git a/tooling/nargo_cli/tests/snapshots/execution_success/embedded_curve_ops/execute__tests__expanded.snap b/tooling/nargo_cli/tests/snapshots/execution_success/embedded_curve_ops/execute__tests__expanded.snap index eb00575b82a..8074a34e40d 100644 --- a/tooling/nargo_cli/tests/snapshots/execution_success/embedded_curve_ops/execute__tests__expanded.snap +++ b/tooling/nargo_cli/tests/snapshots/execution_success/embedded_curve_ops/execute__tests__expanded.snap @@ -2,7 +2,7 @@ source: tooling/nargo_cli/tests/execute.rs expression: expanded_code --- -use std::ops::Add; +use std::{embedded_curve_ops::embedded_curve_add_unsafe, ops::Add}; fn main(priv_key: Field, pub_x: pub Field, pub_y: pub Field) { let g1: std::embedded_curve_ops::EmbeddedCurvePoint = @@ -44,4 +44,94 @@ fn main(priv_key: Field, pub_x: pub Field, pub_y: pub Field) { [scalar, const_zero, scalar], ); assert(partial_mul == g1); + if pub_x == pub_y { + let a1: std::embedded_curve_ops::EmbeddedCurvePoint = std::embedded_curve_ops::EmbeddedCurvePoint { + x: 1_Field, + y: 2_Field, + is_infinite: false, + }; + let a2: std::embedded_curve_ops::EmbeddedCurvePoint = std::embedded_curve_ops::EmbeddedCurvePoint { + x: 1_Field, + y: 3_Field, + is_infinite: false, + }; + let doubling: std::embedded_curve_ops::EmbeddedCurvePoint = a1.double(); + assert(doubling.x == 1_Field); + let res: std::embedded_curve_ops::EmbeddedCurvePoint = embedded_curve_add_unsafe(a1, a2); + assert(res.x == 1_Field); + let a1: std::embedded_curve_ops::EmbeddedCurvePoint = std::embedded_curve_ops::EmbeddedCurvePoint { + x: pub_x + 1_Field, + y: pub_y, + is_infinite: false, + }; + let a2: std::embedded_curve_ops::EmbeddedCurvePoint = std::embedded_curve_ops::EmbeddedCurvePoint { + x: pub_x + 1_Field, + y: pub_y + 1_Field, + is_infinite: false, + }; + let doubling: std::embedded_curve_ops::EmbeddedCurvePoint = a1.double(); + assert(doubling.x == 1_Field); + let res: std::embedded_curve_ops::EmbeddedCurvePoint = embedded_curve_add_unsafe(a1, a2); + assert(res.x == 1_Field); + let a1: std::embedded_curve_ops::EmbeddedCurvePoint = std::embedded_curve_ops::EmbeddedCurvePoint { + x: 2_Field, + y: 3_Field, + is_infinite: false, + }; + let a2: std::embedded_curve_ops::EmbeddedCurvePoint = std::embedded_curve_ops::EmbeddedCurvePoint { + x: pub_x, + y: pub_y + (1_Field as Field), + is_infinite: false, + }; + let res: std::embedded_curve_ops::EmbeddedCurvePoint = embedded_curve_add_unsafe(a1, a2); + assert(res.x == 1_Field); + let a1: std::embedded_curve_ops::EmbeddedCurvePoint = std::embedded_curve_ops::EmbeddedCurvePoint { + x: 2_Field, + y: 3_Field, + is_infinite: false, + }; + let a2: std::embedded_curve_ops::EmbeddedCurvePoint = std::embedded_curve_ops::EmbeddedCurvePoint { + x: 2_Field, + y: 4_Field, + is_infinite: false, + }; + let res: std::embedded_curve_ops::EmbeddedCurvePoint = embedded_curve_add_unsafe(a1, a2); + assert(res.x == 1_Field); + let a1: std::embedded_curve_ops::EmbeddedCurvePoint = std::embedded_curve_ops::EmbeddedCurvePoint { + x: 2_Field, + y: 3_Field, + is_infinite: false, + }; + let a2: std::embedded_curve_ops::EmbeddedCurvePoint = std::embedded_curve_ops::EmbeddedCurvePoint { + x: 2_Field, + y: 3_Field, + is_infinite: false, + }; + let res: std::embedded_curve_ops::EmbeddedCurvePoint = embedded_curve_add_unsafe(a1, a2); + assert(res.x == 1_Field); + let a1: std::embedded_curve_ops::EmbeddedCurvePoint = std::embedded_curve_ops::EmbeddedCurvePoint { + x: 1_Field, + y: 3_Field, + is_infinite: false, + }; + let a2: std::embedded_curve_ops::EmbeddedCurvePoint = std::embedded_curve_ops::EmbeddedCurvePoint { + x: 1_Field, + y: 3_Field, + is_infinite: false, + }; + let res: std::embedded_curve_ops::EmbeddedCurvePoint = embedded_curve_add_unsafe(a1, a2); + assert(res.x == 1_Field); + let a1: std::embedded_curve_ops::EmbeddedCurvePoint = std::embedded_curve_ops::EmbeddedCurvePoint { + x: pub_x, + y: 3_Field, + is_infinite: false, + }; + let a2: std::embedded_curve_ops::EmbeddedCurvePoint = std::embedded_curve_ops::EmbeddedCurvePoint { + x: pub_x, + y: 2_Field, + is_infinite: false, + }; + let res: std::embedded_curve_ops::EmbeddedCurvePoint = embedded_curve_add_unsafe(a1, a2); + assert(res.x == 1_Field); + } } diff --git a/tooling/nargo_cli/tests/snapshots/execution_success/embedded_curve_ops/execute__tests__force_brillig_false_inliner_-9223372036854775808.snap b/tooling/nargo_cli/tests/snapshots/execution_success/embedded_curve_ops/execute__tests__force_brillig_false_inliner_-9223372036854775808.snap index 95e9276a19b..12800efb646 100644 --- a/tooling/nargo_cli/tests/snapshots/execution_success/embedded_curve_ops/execute__tests__force_brillig_false_inliner_-9223372036854775808.snap +++ b/tooling/nargo_cli/tests/snapshots/execution_success/embedded_curve_ops/execute__tests__force_brillig_false_inliner_-9223372036854775808.snap @@ -34,38 +34,77 @@ expression: artifact }, "bytecode": [ "func 0", - "current witness index : _18", + "current witness index : _61", "private parameters indices : [_0]", "public parameters indices : [_1, _2]", "return value indices : []", "BLACKBOX::MULTI_SCALAR_MUL [(1, 254), (17631683881184975370165255887551781615748388533673675138860, 254), (0, 1), (_0, 254), (0, 254)] [_3, _4, _5]", "EXPR [ (-1, _1) (1, _3) 0 ]", "EXPR [ (-1, _2) (1, _4) 0 ]", - "EXPR [ (-1, _6) 0 ]", - "BLACKBOX::EMBEDDED_CURVE_ADD [(_1, 254), (_2, 254), (_6, 1), (_1, 254), (_2, 254), (_6, 1)] [_7, _8, _9]", - "EXPR [ (-1, _7) 3078034153852398078128400807926804309327113743808504829582559963737223069694 ]", - "BLACKBOX::MULTI_SCALAR_MUL [(1, 254), (17631683881184975370165255887551781615748388533673675138860, 254), (0, 1), (1, 254), (17631683881184975370165255887551781615748388533673675138860, 254), (0, 1), (_0, 254), (0, 254), (_0, 254), (0, 254)] [_10, _11, _12]", - "EXPR [ (-1, _10) 3078034153852398078128400807926804309327113743808504829582559963737223069694 ]", - "BLACKBOX::MULTI_SCALAR_MUL [(1, 254), (17631683881184975370165255887551781615748388533673675138860, 254), (0, 1), (_1, 254), (_2, 254), (0, 1), (11179562631109628533987091031692370366552561688588090155835439555627259799605, 254), (3443719903172018228650470536370404288991794296383447657609081676265727805364, 254), (0, 1), (_0, 254), (0, 254), (_0, 254), (0, 254), (1, 254), (0, 254)] [_13, _14, _15]", - "EXPR [ (1, _13) 7349266043899242844836273743257843180744506495159104166319746739537754653274 ]", - "BLACKBOX::MULTI_SCALAR_MUL [(1, 254), (17631683881184975370165255887551781615748388533673675138860, 254), (0, 1), (_0, 254), (0, 254)] [_16, _17, _18]", - "EXPR [ (1, _18) 0 ]", - "EXPR [ (1, _16) -1 ]", - "EXPR [ (1, _17) -17631683881184975370165255887551781615748388533673675138860 ]" + "BLACKBOX::EMBEDDED_CURVE_ADD [(_1, 254), (_2, 254), (0, 1), (_1, 254), (_2, 254), (0, 1)] [_6, _7, _8]", + "EXPR [ (-1, _6) 3078034153852398078128400807926804309327113743808504829582559963737223069694 ]", + "BLACKBOX::MULTI_SCALAR_MUL [(1, 254), (17631683881184975370165255887551781615748388533673675138860, 254), (0, 1), (1, 254), (17631683881184975370165255887551781615748388533673675138860, 254), (0, 1), (_0, 254), (0, 254), (_0, 254), (0, 254)] [_9, _10, _11]", + "EXPR [ (-1, _9) 3078034153852398078128400807926804309327113743808504829582559963737223069694 ]", + "BLACKBOX::MULTI_SCALAR_MUL [(1, 254), (17631683881184975370165255887551781615748388533673675138860, 254), (0, 1), (_1, 254), (_2, 254), (0, 1), (11179562631109628533987091031692370366552561688588090155835439555627259799605, 254), (3443719903172018228650470536370404288991794296383447657609081676265727805364, 254), (0, 1), (_0, 254), (0, 254), (_0, 254), (0, 254), (1, 254), (0, 254)] [_12, _13, _14]", + "EXPR [ (1, _12) 7349266043899242844836273743257843180744506495159104166319746739537754653274 ]", + "BLACKBOX::MULTI_SCALAR_MUL [(1, 254), (17631683881184975370165255887551781615748388533673675138860, 254), (0, 1), (_0, 254), (0, 254)] [_15, _16, _17]", + "EXPR [ (1, _17) 0 ]", + "EXPR [ (1, _15) -1 ]", + "EXPR [ (1, _16) -17631683881184975370165255887551781615748388533673675138860 ]", + "EXPR [ (1, _1) (-1, _2) (-1, _18) 0 ]", + "BRILLIG CALL func 0: inputs: [Single(Expression { mul_terms: [], linear_combinations: [(1, Witness(18))], q_c: 0 })], outputs: [Simple(Witness(19))]", + "EXPR [ (1, _18, _19) (1, _20) -1 ]", + "EXPR [ (1, _18, _20) 0 ]", + "EXPR [ (-17631683881184975370165255887551781615748388533673675138858, _20) (-1, _21) 17631683881184975370165255887551781615748388533673675138860 ]", + "BLACKBOX::EMBEDDED_CURVE_ADD [(1, 254), (_21, 254), (0, 1), (1, 254), (_21, 254), (0, 1)] [_22, _23, _24]", + "EXPR [ (1, _20, _22) (-1, _20) 0 ]", + "EXPR [ (-3078034153852398078128400807926804309327113743808504829582559963737223069693, _20) (-1, _25) 3078034153852398078128400807926804309327113743808504829582559963737223069694 ]", + "EXPR [ (9191351987198133172789796342745422989482268917117950487758512501574271532888, _20) (-1, _26) -9191351987198133172789796342745422989482268917117950487758512501574271532885 ]", + "BLACKBOX::EMBEDDED_CURVE_ADD [(1, 254), (_21, 254), (0, 1), (_25, 254), (_26, 254), (0, 1)] [_27, _28, _29]", + "EXPR [ (1, _20, _27) (-1, _20) 0 ]", + "EXPR [ (1, _1, _20) (-1, _30) 1 ]", + "EXPR [ (1, _2, _20) (-17631683881184975370165255887551781615748388533673675138860, _20) (-1, _31) 17631683881184975370165255887551781615748388533673675138860 ]", + "BLACKBOX::EMBEDDED_CURVE_ADD [(_30, 254), (_31, 254), (0, 1), (_30, 254), (_31, 254), (0, 1)] [_32, _33, _34]", + "EXPR [ (1, _20, _32) (-1, _20) 0 ]", + "EXPR [ (1, _1, _20) (-3078034153852398078128400807926804309327113743808504829582559963737223069693, _20) (-1, _35) 3078034153852398078128400807926804309327113743808504829582559963737223069694 ]", + "EXPR [ (1, _2, _20) (9191351987198133172789796342745422989482268917117950487758512501574271532886, _20) (-1, _36) -9191351987198133172789796342745422989482268917117950487758512501574271532885 ]", + "BLACKBOX::EMBEDDED_CURVE_ADD [(_30, 254), (_31, 254), (0, 1), (_35, 254), (_36, 254), (0, 1)] [_37, _38, _39]", + "EXPR [ (1, _20, _37) (-1, _20) 0 ]", + "EXPR [ (1, _20) (-1, _40) 1 ]", + "EXPR [ (-17631683881184975370165255887551781615748388533673675138857, _20) (-1, _41) 17631683881184975370165255887551781615748388533673675138860 ]", + "EXPR [ (1, _1, _20) (-3078034153852398078128400807926804309327113743808504829582559963737223069694, _20) (-1, _42) 3078034153852398078128400807926804309327113743808504829582559963737223069694 ]", + "BLACKBOX::EMBEDDED_CURVE_ADD [(_40, 254), (_41, 254), (0, 1), (_42, 254), (_36, 254), (0, 1)] [_43, _44, _45]", + "EXPR [ (1, _20, _43) (-1, _20) 0 ]", + "EXPR [ (-3078034153852398078128400807926804309327113743808504829582559963737223069692, _20) (-1, _46) 3078034153852398078128400807926804309327113743808504829582559963737223069694 ]", + "EXPR [ (9191351987198133172789796342745422989482268917117950487758512501574271532889, _20) (-1, _47) -9191351987198133172789796342745422989482268917117950487758512501574271532885 ]", + "BLACKBOX::EMBEDDED_CURVE_ADD [(_40, 254), (_41, 254), (0, 1), (_46, 254), (_47, 254), (0, 1)] [_48, _49, _50]", + "EXPR [ (1, _20, _48) (-1, _20) 0 ]", + "BLACKBOX::EMBEDDED_CURVE_ADD [(_40, 254), (_41, 254), (0, 1), (_40, 254), (_41, 254), (0, 1)] [_51, _52, _53]", + "EXPR [ (1, _20, _51) (-1, _20) 0 ]", + "BLACKBOX::EMBEDDED_CURVE_ADD [(1, 254), (_41, 254), (0, 1), (1, 254), (_41, 254), (0, 1)] [_54, _55, _56]", + "EXPR [ (1, _20, _54) (-1, _20) 0 ]", + "EXPR [ (1, _1, _20) (-1, _20) (-1, _57) 1 ]", + "EXPR [ (9191351987198133172789796342745422989482268917117950487758512501574271532887, _20) (-1, _58) -9191351987198133172789796342745422989482268917117950487758512501574271532885 ]", + "BLACKBOX::EMBEDDED_CURVE_ADD [(_57, 254), (_41, 254), (0, 1), (_42, 254), (_58, 254), (0, 1)] [_59, _60, _61]", + "EXPR [ (1, _20, _59) (-1, _20) 0 ]", + "unconstrained func 0", + "[Const { destination: Direct(21), bit_size: Integer(U32), value: 1 }, Const { destination: Direct(20), bit_size: Integer(U32), value: 0 }, CalldataCopy { destination_address: Direct(0), size_address: Direct(21), offset_address: Direct(20) }, Const { destination: Direct(2), bit_size: Field, value: 0 }, BinaryFieldOp { destination: Direct(3), op: Equals, lhs: Direct(0), rhs: Direct(2) }, JumpIf { condition: Direct(3), location: 8 }, Const { destination: Direct(1), bit_size: Field, value: 1 }, BinaryFieldOp { destination: Direct(0), op: Div, lhs: Direct(1), rhs: Direct(0) }, Stop { return_data: HeapVector { pointer: Direct(20), size: Direct(21) } }]" ], - "debug_symbols": "tVXbbsIwDP2XPOchzj37lWlCpQRUKWqr0E6aEP8+hzUFHoJQGE9u4pwj+9i1T2Tnt/Nh0/X74Ug+Pk9kG7sQusMmDG0zdUOPt6czJfm4maL3eEVu/Igam+j7iXz0cwiUfDdhvjw6jk1/sVMT0cso8f0OLRLuu+DT15le0awM5UIvYC7MCldP4wXnC14YV8LzMl4qJxcCqeU1AdB1DKLE8CgHl3OQTFdoIHkugBSyAq9lroHWvIQ3D/AcMl5BKX9bxlvBMoEVkpcYXJkBgDOzUOC3kv/AYSoqaVYGw2sqYSF3grVQwoN4uZ2fp6jpZ7cSAAOokAEEXxmkLQoJ5nUhzDuFAOnWjlKW1ShhucoMTqrigIPXJxy8VQmn7JqHuc/jC09N28W71UQYzkVKAJ9QwnGyUCJSP1Ei/4xCgz+LTipTYlIwlNikGCUO08EngBxpPQCypIYCvliR7DlFG7tmG/yyC/dz396sxulnzJ68PMc4tH43R59ivfgw+l8=", + "debug_symbols": "tVjLbuMwDPwXnX0QX3rsrywWRZq6RQDDCdxkgUXRf1+qlez0oKBV7NMksTkhR+TY0pt56h8vLw+H8fn4an79fjOP02EYDi8Pw3G/Ox+Oo/769t6Z8vXhPPW9/mSurmvUaTf149n8Gi/D0Jm/u+HycdPraTd+4Hk36VXbmX58UlTC58PQp0/v3RJt66EYJAdjcHO4fDuePOR4xlCLx3o8S+RC4HgpAFwbA9UYbtTAPNcg0qABu1jiAzXEu1jWwAPU4v2NeCz5O4Fa/aEe71GwJICRGhgC2ZJCIMYaA9wQAQCtzxz6WXgNEt/QDV5cEcO3rGZwRYpIthYPfPdIfJ+iZSbAMhUhrbMNOgD5mUGoqiSE+5UImyohXBoCHMYWJYIvOUCMXHXJFWxyU59EOw8XWuQGJVDnszAANTGQlCqQXLWr8F67xFtuZ2e/DDZWPQbjCm6H97suwQp5/ISkxXWRAs7reqXpDzqDkw98MrBUn6Mka6ghG6vBbqnFhxY1PM+T5rnFtTDAPO0Bq++GbO+cNIa7J41xhTW9mcf3Jo15jTx4494KfPXKb5s6IxQ1MELVxTmsoUbYWI1ISy0MLTsgxPKeQyjVOZE1evQnJC1qEPqllqa9DHEsmyESwqoabg013MZqCC+1SIuHkvdl1ijYqo+7NfZFbuN9kT6gl1qoaZ9spTyT2Na7y63hom5jF2Wwcy0ALS7KRGXWmFzVN9waLuo2dlHWjphriV9X9o9+2+0P05eTL2O1izoDektnUBPsDKW/7wynnWNnJG28OuMUNDmfdk6dCWnb0JmY3hE1WDlSSwJkxIzKhEoInFEyuow+uZtiyBiTbWkaKSe9jpARM1LqeEVOmyhFyegyKh9rkqh8yTAwfiLZjKlKTZuUTzRvooycUTIqnygfKZ8oH4WM8RNZ+UT5WPnSGQMn3TSOKb1fKSqfS/dJOlJSdBl9xpAOmN7TKk6H3ePQ5yPI58u4vzqRPP87lSvlzPI0Hff902Xq0xp+XNNV/Q8=", "file_map": { "16": { "source": "use crate::cmp::Eq;\nuse crate::hash::Hash;\nuse crate::ops::arith::{Add, Neg, Sub};\n\n/// A point on the embedded elliptic curve\n/// By definition, the base field of the embedded curve is the scalar field of the proof system curve, i.e the Noir Field.\n/// x and y denotes the Weierstrass coordinates of the point, if is_infinite is false.\npub struct EmbeddedCurvePoint {\n pub x: Field,\n pub y: Field,\n pub is_infinite: bool,\n}\n\nimpl EmbeddedCurvePoint {\n /// Elliptic curve point doubling operation\n /// returns the doubled point of a point P, i.e P+P\n pub fn double(self) -> EmbeddedCurvePoint {\n embedded_curve_add(self, self)\n }\n\n /// Returns the null element of the curve; 'the point at infinity'\n pub fn point_at_infinity() -> EmbeddedCurvePoint {\n EmbeddedCurvePoint { x: 0, y: 0, is_infinite: true }\n }\n\n /// Returns the curve's generator point.\n pub fn generator() -> EmbeddedCurvePoint {\n // Generator point for the grumpkin curve (y^2 = x^3 - 17)\n EmbeddedCurvePoint {\n x: 1,\n y: 17631683881184975370165255887551781615748388533673675138860, // sqrt(-16)\n is_infinite: false,\n }\n }\n}\n\nimpl Add for EmbeddedCurvePoint {\n /// Adds two points P+Q, using the curve addition formula, and also handles point at infinity\n fn add(self, other: EmbeddedCurvePoint) -> EmbeddedCurvePoint {\n embedded_curve_add(self, other)\n }\n}\n\nimpl Sub for EmbeddedCurvePoint {\n /// Points subtraction operation, using addition and negation\n fn sub(self, other: EmbeddedCurvePoint) -> EmbeddedCurvePoint {\n self + other.neg()\n }\n}\n\nimpl Neg for EmbeddedCurvePoint {\n /// Negates a point P, i.e returns -P, by negating the y coordinate.\n /// If the point is at infinity, then the result is also at infinity.\n fn neg(self) -> EmbeddedCurvePoint {\n EmbeddedCurvePoint { x: self.x, y: -self.y, is_infinite: self.is_infinite }\n }\n}\n\nimpl Eq for EmbeddedCurvePoint {\n /// Checks whether two points are equal\n fn eq(self: Self, b: EmbeddedCurvePoint) -> bool {\n (self.is_infinite & b.is_infinite)\n | ((self.is_infinite == b.is_infinite) & (self.x == b.x) & (self.y == b.y))\n }\n}\n\nimpl Hash for EmbeddedCurvePoint {\n fn hash(self, state: &mut H)\n where\n H: crate::hash::Hasher,\n {\n if self.is_infinite {\n self.is_infinite.hash(state);\n } else {\n self.x.hash(state);\n self.y.hash(state);\n }\n }\n}\n\n/// Scalar for the embedded curve represented as low and high limbs\n/// By definition, the scalar field of the embedded curve is base field of the proving system curve.\n/// It may not fit into a Field element, so it is represented with two Field elements; its low and high limbs.\npub struct EmbeddedCurveScalar {\n pub lo: Field,\n pub hi: Field,\n}\n\nimpl EmbeddedCurveScalar {\n pub fn new(lo: Field, hi: Field) -> Self {\n EmbeddedCurveScalar { lo, hi }\n }\n\n #[field(bn254)]\n pub fn from_field(scalar: Field) -> EmbeddedCurveScalar {\n let (a, b) = crate::field::bn254::decompose(scalar);\n EmbeddedCurveScalar { lo: a, hi: b }\n }\n\n //Bytes to scalar: take the first (after the specified offset) 16 bytes of the input as the lo value, and the next 16 bytes as the hi value\n #[field(bn254)]\n pub(crate) fn from_bytes(bytes: [u8; 64], offset: u32) -> EmbeddedCurveScalar {\n let mut v = 1;\n let mut lo = 0 as Field;\n let mut hi = 0 as Field;\n for i in 0..16 {\n lo = lo + (bytes[offset + 31 - i] as Field) * v;\n hi = hi + (bytes[offset + 15 - i] as Field) * v;\n v = v * 256;\n }\n let sig_s = crate::embedded_curve_ops::EmbeddedCurveScalar { lo, hi };\n sig_s\n }\n}\n\nimpl Eq for EmbeddedCurveScalar {\n fn eq(self, other: Self) -> bool {\n (other.hi == self.hi) & (other.lo == self.lo)\n }\n}\n\nimpl Hash for EmbeddedCurveScalar {\n fn hash(self, state: &mut H)\n where\n H: crate::hash::Hasher,\n {\n self.hi.hash(state);\n self.lo.hash(state);\n }\n}\n\n// Computes a multi scalar multiplication over the embedded curve.\n// For bn254, We have Grumpkin and Baby JubJub.\n// For bls12-381, we have JubJub and Bandersnatch.\n//\n// The embedded curve being used is decided by the\n// underlying proof system.\n// docs:start:multi_scalar_mul\npub fn multi_scalar_mul(\n points: [EmbeddedCurvePoint; N],\n scalars: [EmbeddedCurveScalar; N],\n) -> EmbeddedCurvePoint\n// docs:end:multi_scalar_mul\n{\n multi_scalar_mul_array_return(points, scalars)[0]\n}\n\n#[foreign(multi_scalar_mul)]\npub(crate) fn multi_scalar_mul_array_return(\n points: [EmbeddedCurvePoint; N],\n scalars: [EmbeddedCurveScalar; N],\n) -> [EmbeddedCurvePoint; 1] {}\n\n// docs:start:fixed_base_scalar_mul\npub fn fixed_base_scalar_mul(scalar: EmbeddedCurveScalar) -> EmbeddedCurvePoint\n// docs:end:fixed_base_scalar_mul\n{\n multi_scalar_mul([EmbeddedCurvePoint::generator()], [scalar])\n}\n\n/// This function only assumes that the points are on the curve\n/// It handles corner cases around the infinity point causing some overhead compared to embedded_curve_add_not_nul and embedded_curve_add_unsafe\n// docs:start:embedded_curve_add\npub fn embedded_curve_add(\n point1: EmbeddedCurvePoint,\n point2: EmbeddedCurvePoint,\n) -> EmbeddedCurvePoint {\n // docs:end:embedded_curve_add\n if crate::runtime::is_unconstrained() {\n // `embedded_curve_add_unsafe` requires the inputs not to be the infinity point, so we check it here.\n // This is because `embedded_curve_add_unsafe` uses the `embedded_curve_add` opcode.\n // For efficiency, the backend does not check the inputs for the infinity point, but it assumes that they are not the infinity point\n // so that it can apply the ec addition formula directly.\n if point1.is_infinite {\n point2\n } else if point2.is_infinite {\n point1\n } else {\n embedded_curve_add_unsafe(point1, point2)\n }\n } else {\n // In a constrained context, we also need to check the inputs are not the infinity point because we also use `embedded_curve_add_unsafe`\n // However we also need to identify the case where the two inputs are the same, because then\n // the addition formula does not work and we need to use the doubling formula instead.\n // In unconstrained context, we can check directly if the input values are the same when solving the opcode, so it is not an issue.\n\n // x_coordinates_match is true if both abscissae are the same\n let x_coordinates_match = point1.x == point2.x;\n // y_coordinates_match is true if both ordinates are the same\n let y_coordinates_match = point1.y == point2.y;\n // double_predicate is true if both abscissae and ordinates are the same\n let double_predicate = (x_coordinates_match & y_coordinates_match);\n // If the abscissae are the same, but not the ordinates, then one point is the opposite of the other\n let infinity_predicate = (x_coordinates_match & !y_coordinates_match);\n let point1_1 = EmbeddedCurvePoint {\n x: point1.x + (x_coordinates_match as Field),\n y: point1.y,\n is_infinite: false,\n };\n let point2_1 = EmbeddedCurvePoint { x: point2.x, y: point2.y, is_infinite: false };\n // point1_1 is guaranteed to have a different abscissa than point2:\n // - if x_coordinates_match is 0, that means point1.x != point2.x, and point1_1.x = point1.x + 0\n // - if x_coordinates_match is 1, that means point1.x = point2.x, but point1_1.x = point1.x + 1 in this case\n // Because the abscissa is different, the addition formula is guaranteed to succeed, so we can safely use `embedded_curve_add_unsafe`\n // Note that this computation may be garbage: if x_coordinates_match is 1, or if one of the input is the point at infinity.\n let mut result = embedded_curve_add_unsafe(point1_1, point2_1);\n\n // `embedded_curve_add_unsafe` is doing a doubling if the input is the same variable, because in this case it is guaranteed (at 'compile time') that the input is the same.\n let double = embedded_curve_add_unsafe(point1, point1);\n // `embedded_curve_add_unsafe` would not perform doubling, even if the inputs point1 and point2 are the same, because it cannot know this without adding some logic (and some constraints)\n // However we did this logic when we computed `double_predicate`, so we set the result to 2*point1 if point1 and point2 are the same\n result = if double_predicate { double } else { result };\n\n // Same logic as above for unconstrained context, we set the proper result when one of the inputs is the infinity point\n if point1.is_infinite {\n result = point2;\n }\n if point2.is_infinite {\n result = point1;\n }\n\n // Finally, we set the is_infinity flag of the result:\n // Opposite points should sum into the infinity point, however, if one of them is point at infinity, their coordinates are not meaningful\n // so we should not use the fact that the inputs are opposite in this case:\n let mut result_is_infinity =\n infinity_predicate & (!point1.is_infinite & !point2.is_infinite);\n // However, if both of them are at infinity, then the result is also at infinity\n result.is_infinite = result_is_infinity | (point1.is_infinite & point2.is_infinite);\n result\n }\n}\n\n#[foreign(embedded_curve_add)]\nfn embedded_curve_add_array_return(\n _point1: EmbeddedCurvePoint,\n _point2: EmbeddedCurvePoint,\n) -> [EmbeddedCurvePoint; 1] {}\n\n/// This function assumes that:\n/// The points are on the curve, and\n/// The points don't share an x-coordinate, and\n/// Neither point is the infinity point.\n/// If it is used with correct input, the function ensures the correct non-zero result is returned.\n/// Except for points on the curve, the other assumptions are checked by the function. It will cause assertion failure if they are not respected.\npub fn embedded_curve_add_not_nul(\n point1: EmbeddedCurvePoint,\n point2: EmbeddedCurvePoint,\n) -> EmbeddedCurvePoint {\n assert(point1.x != point2.x);\n assert(!point1.is_infinite);\n assert(!point2.is_infinite);\n // Ensure is_infinite is comptime\n let point1_1 = EmbeddedCurvePoint { x: point1.x, y: point1.y, is_infinite: false };\n let point2_1 = EmbeddedCurvePoint { x: point2.x, y: point2.y, is_infinite: false };\n embedded_curve_add_unsafe(point1_1, point2_1)\n}\n\n/// Unsafe ec addition\n/// If the inputs are the same, it will perform a doubling, but only if point1 and point2 are the same variable.\n/// If they have the same value but are different variables, the result will be incorrect because in this case\n/// it assumes (but does not check) that the points' x-coordinates are not equal.\n/// It also assumes neither point is the infinity point.\npub fn embedded_curve_add_unsafe(\n point1: EmbeddedCurvePoint,\n point2: EmbeddedCurvePoint,\n) -> EmbeddedCurvePoint {\n embedded_curve_add_array_return(point1, point2)[0]\n}\n", "path": "std/embedded_curve_ops.nr" }, "50": { - "source": "use std::ops::Add;\n\nfn main(priv_key: Field, pub_x: pub Field, pub_y: pub Field) {\n let g1 = std::embedded_curve_ops::EmbeddedCurvePoint::generator();\n let scalar = std::embedded_curve_ops::EmbeddedCurveScalar { lo: priv_key, hi: 0 };\n // Test that multi_scalar_mul correctly derives the public key\n let res = std::embedded_curve_ops::multi_scalar_mul([g1], [scalar]);\n assert(res.x == pub_x);\n assert(res.y == pub_y);\n\n // Test that double function calling embedded_curve_add works as expected\n let pub_point =\n std::embedded_curve_ops::EmbeddedCurvePoint { x: pub_x, y: pub_y, is_infinite: false };\n let res = pub_point.double();\n let double = g1.add(g1);\n\n assert(double.x == res.x);\n\n // Test calling multi_scalar_mul with multiple points and scalars\n let res = std::embedded_curve_ops::multi_scalar_mul([g1, g1], [scalar, scalar]);\n\n // The results should be double the g1 point because the scalars are 1 and we pass in g1 twice\n assert(double.x == res.x);\n\n // Tests for #6549\n let const_scalar1 = std::embedded_curve_ops::EmbeddedCurveScalar { lo: 23, hi: 0 };\n let const_scalar2 = std::embedded_curve_ops::EmbeddedCurveScalar { lo: 0, hi: 23 };\n let const_scalar3 = std::embedded_curve_ops::EmbeddedCurveScalar { lo: 13, hi: 4 };\n let partial_mul = std::embedded_curve_ops::multi_scalar_mul(\n [g1, double, pub_point, g1, g1],\n [scalar, const_scalar1, scalar, const_scalar2, const_scalar3],\n );\n assert(partial_mul.x == 0x2024c4eebfbc8a20018f8c95c7aab77c6f34f10cf785a6f04e97452d8708fda7);\n // Check simplification by zero\n let zero_point = std::embedded_curve_ops::EmbeddedCurvePoint { x: 0, y: 0, is_infinite: true };\n let const_zero = std::embedded_curve_ops::EmbeddedCurveScalar { lo: 0, hi: 0 };\n let partial_mul = std::embedded_curve_ops::multi_scalar_mul(\n [zero_point, double, g1],\n [scalar, const_zero, scalar],\n );\n assert(partial_mul == g1);\n}\n", + "source": "use std::{embedded_curve_ops::embedded_curve_add_unsafe, ops::Add};\n\nfn main(priv_key: Field, pub_x: pub Field, pub_y: pub Field) {\n let g1 = std::embedded_curve_ops::EmbeddedCurvePoint::generator();\n let scalar = std::embedded_curve_ops::EmbeddedCurveScalar { lo: priv_key, hi: 0 };\n // Test that multi_scalar_mul correctly derives the public key\n let res = std::embedded_curve_ops::multi_scalar_mul([g1], [scalar]);\n assert(res.x == pub_x);\n assert(res.y == pub_y);\n\n // Test that double function calling embedded_curve_add works as expected\n let pub_point =\n std::embedded_curve_ops::EmbeddedCurvePoint { x: pub_x, y: pub_y, is_infinite: false };\n let res = pub_point.double();\n let double = g1.add(g1);\n\n assert(double.x == res.x);\n\n // Test calling multi_scalar_mul with multiple points and scalars\n let res = std::embedded_curve_ops::multi_scalar_mul([g1, g1], [scalar, scalar]);\n\n // The results should be double the g1 point because the scalars are 1 and we pass in g1 twice\n assert(double.x == res.x);\n\n // Tests for #6549\n let const_scalar1 = std::embedded_curve_ops::EmbeddedCurveScalar { lo: 23, hi: 0 };\n let const_scalar2 = std::embedded_curve_ops::EmbeddedCurveScalar { lo: 0, hi: 23 };\n let const_scalar3 = std::embedded_curve_ops::EmbeddedCurveScalar { lo: 13, hi: 4 };\n let partial_mul = std::embedded_curve_ops::multi_scalar_mul(\n [g1, double, pub_point, g1, g1],\n [scalar, const_scalar1, scalar, const_scalar2, const_scalar3],\n );\n assert(partial_mul.x == 0x2024c4eebfbc8a20018f8c95c7aab77c6f34f10cf785a6f04e97452d8708fda7);\n // Check simplification by zero\n let zero_point = std::embedded_curve_ops::EmbeddedCurvePoint { x: 0, y: 0, is_infinite: true };\n let const_zero = std::embedded_curve_ops::EmbeddedCurveScalar { lo: 0, hi: 0 };\n let partial_mul = std::embedded_curve_ops::multi_scalar_mul(\n [zero_point, double, g1],\n [scalar, const_zero, scalar],\n );\n assert(partial_mul == g1);\n\n // Additional tests for validating embedded_curve_add_unsafe under a conditional\n if pub_x == pub_y {\n let a1 = std::embedded_curve_ops::EmbeddedCurvePoint { x: 1, y: 2, is_infinite: false };\n let a2 = std::embedded_curve_ops::EmbeddedCurvePoint { x: 1, y: 3, is_infinite: false };\n let doubling = a1.double();\n assert(doubling.x == 1);\n let res = embedded_curve_add_unsafe(a1, a2);\n assert(res.x == 1);\n\n let a1 = std::embedded_curve_ops::EmbeddedCurvePoint {\n x: pub_x + 1,\n y: pub_y,\n is_infinite: false,\n };\n let a2 = std::embedded_curve_ops::EmbeddedCurvePoint {\n x: pub_x + 1,\n y: pub_y + 1,\n is_infinite: false,\n };\n let doubling = a1.double();\n assert(doubling.x == 1);\n let res = embedded_curve_add_unsafe(a1, a2);\n assert(res.x == 1);\n\n let a1 = std::embedded_curve_ops::EmbeddedCurvePoint { x: 2, y: 3, is_infinite: false };\n let a2 = std::embedded_curve_ops::EmbeddedCurvePoint {\n x: pub_x,\n y: pub_y + 1 as Field,\n is_infinite: false,\n };\n let res = embedded_curve_add_unsafe(a1, a2);\n assert(res.x == 1);\n\n let a1 = std::embedded_curve_ops::EmbeddedCurvePoint { x: 2, y: 3, is_infinite: false };\n let a2 = std::embedded_curve_ops::EmbeddedCurvePoint { x: 2, y: 4, is_infinite: false };\n let res = embedded_curve_add_unsafe(a1, a2);\n assert(res.x == 1);\n\n let a1 = std::embedded_curve_ops::EmbeddedCurvePoint { x: 2, y: 3, is_infinite: false };\n let a2 = std::embedded_curve_ops::EmbeddedCurvePoint { x: 2, y: 3, is_infinite: false };\n let res = embedded_curve_add_unsafe(a1, a2);\n assert(res.x == 1);\n let a1 = std::embedded_curve_ops::EmbeddedCurvePoint { x: 1, y: 3, is_infinite: false };\n let a2 = std::embedded_curve_ops::EmbeddedCurvePoint { x: 1, y: 3, is_infinite: false };\n let res = embedded_curve_add_unsafe(a1, a2);\n assert(res.x == 1);\n let a1 = std::embedded_curve_ops::EmbeddedCurvePoint { x: pub_x, y: 3, is_infinite: false };\n let a2 = std::embedded_curve_ops::EmbeddedCurvePoint { x: pub_x, y: 2, is_infinite: false };\n let res = embedded_curve_add_unsafe(a1, a2);\n assert(res.x == 1);\n }\n}\n", "path": "" } }, "names": [ "main" ], - "brillig_names": [] + "brillig_names": [ + "directive_invert" + ] } diff --git a/tooling/nargo_cli/tests/snapshots/execution_success/embedded_curve_ops/execute__tests__force_brillig_false_inliner_0.snap b/tooling/nargo_cli/tests/snapshots/execution_success/embedded_curve_ops/execute__tests__force_brillig_false_inliner_0.snap index 95e9276a19b..12800efb646 100644 --- a/tooling/nargo_cli/tests/snapshots/execution_success/embedded_curve_ops/execute__tests__force_brillig_false_inliner_0.snap +++ b/tooling/nargo_cli/tests/snapshots/execution_success/embedded_curve_ops/execute__tests__force_brillig_false_inliner_0.snap @@ -34,38 +34,77 @@ expression: artifact }, "bytecode": [ "func 0", - "current witness index : _18", + "current witness index : _61", "private parameters indices : [_0]", "public parameters indices : [_1, _2]", "return value indices : []", "BLACKBOX::MULTI_SCALAR_MUL [(1, 254), (17631683881184975370165255887551781615748388533673675138860, 254), (0, 1), (_0, 254), (0, 254)] [_3, _4, _5]", "EXPR [ (-1, _1) (1, _3) 0 ]", "EXPR [ (-1, _2) (1, _4) 0 ]", - "EXPR [ (-1, _6) 0 ]", - "BLACKBOX::EMBEDDED_CURVE_ADD [(_1, 254), (_2, 254), (_6, 1), (_1, 254), (_2, 254), (_6, 1)] [_7, _8, _9]", - "EXPR [ (-1, _7) 3078034153852398078128400807926804309327113743808504829582559963737223069694 ]", - "BLACKBOX::MULTI_SCALAR_MUL [(1, 254), (17631683881184975370165255887551781615748388533673675138860, 254), (0, 1), (1, 254), (17631683881184975370165255887551781615748388533673675138860, 254), (0, 1), (_0, 254), (0, 254), (_0, 254), (0, 254)] [_10, _11, _12]", - "EXPR [ (-1, _10) 3078034153852398078128400807926804309327113743808504829582559963737223069694 ]", - "BLACKBOX::MULTI_SCALAR_MUL [(1, 254), (17631683881184975370165255887551781615748388533673675138860, 254), (0, 1), (_1, 254), (_2, 254), (0, 1), (11179562631109628533987091031692370366552561688588090155835439555627259799605, 254), (3443719903172018228650470536370404288991794296383447657609081676265727805364, 254), (0, 1), (_0, 254), (0, 254), (_0, 254), (0, 254), (1, 254), (0, 254)] [_13, _14, _15]", - "EXPR [ (1, _13) 7349266043899242844836273743257843180744506495159104166319746739537754653274 ]", - "BLACKBOX::MULTI_SCALAR_MUL [(1, 254), (17631683881184975370165255887551781615748388533673675138860, 254), (0, 1), (_0, 254), (0, 254)] [_16, _17, _18]", - "EXPR [ (1, _18) 0 ]", - "EXPR [ (1, _16) -1 ]", - "EXPR [ (1, _17) -17631683881184975370165255887551781615748388533673675138860 ]" + "BLACKBOX::EMBEDDED_CURVE_ADD [(_1, 254), (_2, 254), (0, 1), (_1, 254), (_2, 254), (0, 1)] [_6, _7, _8]", + "EXPR [ (-1, _6) 3078034153852398078128400807926804309327113743808504829582559963737223069694 ]", + "BLACKBOX::MULTI_SCALAR_MUL [(1, 254), (17631683881184975370165255887551781615748388533673675138860, 254), (0, 1), (1, 254), (17631683881184975370165255887551781615748388533673675138860, 254), (0, 1), (_0, 254), (0, 254), (_0, 254), (0, 254)] [_9, _10, _11]", + "EXPR [ (-1, _9) 3078034153852398078128400807926804309327113743808504829582559963737223069694 ]", + "BLACKBOX::MULTI_SCALAR_MUL [(1, 254), (17631683881184975370165255887551781615748388533673675138860, 254), (0, 1), (_1, 254), (_2, 254), (0, 1), (11179562631109628533987091031692370366552561688588090155835439555627259799605, 254), (3443719903172018228650470536370404288991794296383447657609081676265727805364, 254), (0, 1), (_0, 254), (0, 254), (_0, 254), (0, 254), (1, 254), (0, 254)] [_12, _13, _14]", + "EXPR [ (1, _12) 7349266043899242844836273743257843180744506495159104166319746739537754653274 ]", + "BLACKBOX::MULTI_SCALAR_MUL [(1, 254), (17631683881184975370165255887551781615748388533673675138860, 254), (0, 1), (_0, 254), (0, 254)] [_15, _16, _17]", + "EXPR [ (1, _17) 0 ]", + "EXPR [ (1, _15) -1 ]", + "EXPR [ (1, _16) -17631683881184975370165255887551781615748388533673675138860 ]", + "EXPR [ (1, _1) (-1, _2) (-1, _18) 0 ]", + "BRILLIG CALL func 0: inputs: [Single(Expression { mul_terms: [], linear_combinations: [(1, Witness(18))], q_c: 0 })], outputs: [Simple(Witness(19))]", + "EXPR [ (1, _18, _19) (1, _20) -1 ]", + "EXPR [ (1, _18, _20) 0 ]", + "EXPR [ (-17631683881184975370165255887551781615748388533673675138858, _20) (-1, _21) 17631683881184975370165255887551781615748388533673675138860 ]", + "BLACKBOX::EMBEDDED_CURVE_ADD [(1, 254), (_21, 254), (0, 1), (1, 254), (_21, 254), (0, 1)] [_22, _23, _24]", + "EXPR [ (1, _20, _22) (-1, _20) 0 ]", + "EXPR [ (-3078034153852398078128400807926804309327113743808504829582559963737223069693, _20) (-1, _25) 3078034153852398078128400807926804309327113743808504829582559963737223069694 ]", + "EXPR [ (9191351987198133172789796342745422989482268917117950487758512501574271532888, _20) (-1, _26) -9191351987198133172789796342745422989482268917117950487758512501574271532885 ]", + "BLACKBOX::EMBEDDED_CURVE_ADD [(1, 254), (_21, 254), (0, 1), (_25, 254), (_26, 254), (0, 1)] [_27, _28, _29]", + "EXPR [ (1, _20, _27) (-1, _20) 0 ]", + "EXPR [ (1, _1, _20) (-1, _30) 1 ]", + "EXPR [ (1, _2, _20) (-17631683881184975370165255887551781615748388533673675138860, _20) (-1, _31) 17631683881184975370165255887551781615748388533673675138860 ]", + "BLACKBOX::EMBEDDED_CURVE_ADD [(_30, 254), (_31, 254), (0, 1), (_30, 254), (_31, 254), (0, 1)] [_32, _33, _34]", + "EXPR [ (1, _20, _32) (-1, _20) 0 ]", + "EXPR [ (1, _1, _20) (-3078034153852398078128400807926804309327113743808504829582559963737223069693, _20) (-1, _35) 3078034153852398078128400807926804309327113743808504829582559963737223069694 ]", + "EXPR [ (1, _2, _20) (9191351987198133172789796342745422989482268917117950487758512501574271532886, _20) (-1, _36) -9191351987198133172789796342745422989482268917117950487758512501574271532885 ]", + "BLACKBOX::EMBEDDED_CURVE_ADD [(_30, 254), (_31, 254), (0, 1), (_35, 254), (_36, 254), (0, 1)] [_37, _38, _39]", + "EXPR [ (1, _20, _37) (-1, _20) 0 ]", + "EXPR [ (1, _20) (-1, _40) 1 ]", + "EXPR [ (-17631683881184975370165255887551781615748388533673675138857, _20) (-1, _41) 17631683881184975370165255887551781615748388533673675138860 ]", + "EXPR [ (1, _1, _20) (-3078034153852398078128400807926804309327113743808504829582559963737223069694, _20) (-1, _42) 3078034153852398078128400807926804309327113743808504829582559963737223069694 ]", + "BLACKBOX::EMBEDDED_CURVE_ADD [(_40, 254), (_41, 254), (0, 1), (_42, 254), (_36, 254), (0, 1)] [_43, _44, _45]", + "EXPR [ (1, _20, _43) (-1, _20) 0 ]", + "EXPR [ (-3078034153852398078128400807926804309327113743808504829582559963737223069692, _20) (-1, _46) 3078034153852398078128400807926804309327113743808504829582559963737223069694 ]", + "EXPR [ (9191351987198133172789796342745422989482268917117950487758512501574271532889, _20) (-1, _47) -9191351987198133172789796342745422989482268917117950487758512501574271532885 ]", + "BLACKBOX::EMBEDDED_CURVE_ADD [(_40, 254), (_41, 254), (0, 1), (_46, 254), (_47, 254), (0, 1)] [_48, _49, _50]", + "EXPR [ (1, _20, _48) (-1, _20) 0 ]", + "BLACKBOX::EMBEDDED_CURVE_ADD [(_40, 254), (_41, 254), (0, 1), (_40, 254), (_41, 254), (0, 1)] [_51, _52, _53]", + "EXPR [ (1, _20, _51) (-1, _20) 0 ]", + "BLACKBOX::EMBEDDED_CURVE_ADD [(1, 254), (_41, 254), (0, 1), (1, 254), (_41, 254), (0, 1)] [_54, _55, _56]", + "EXPR [ (1, _20, _54) (-1, _20) 0 ]", + "EXPR [ (1, _1, _20) (-1, _20) (-1, _57) 1 ]", + "EXPR [ (9191351987198133172789796342745422989482268917117950487758512501574271532887, _20) (-1, _58) -9191351987198133172789796342745422989482268917117950487758512501574271532885 ]", + "BLACKBOX::EMBEDDED_CURVE_ADD [(_57, 254), (_41, 254), (0, 1), (_42, 254), (_58, 254), (0, 1)] [_59, _60, _61]", + "EXPR [ (1, _20, _59) (-1, _20) 0 ]", + "unconstrained func 0", + "[Const { destination: Direct(21), bit_size: Integer(U32), value: 1 }, Const { destination: Direct(20), bit_size: Integer(U32), value: 0 }, CalldataCopy { destination_address: Direct(0), size_address: Direct(21), offset_address: Direct(20) }, Const { destination: Direct(2), bit_size: Field, value: 0 }, BinaryFieldOp { destination: Direct(3), op: Equals, lhs: Direct(0), rhs: Direct(2) }, JumpIf { condition: Direct(3), location: 8 }, Const { destination: Direct(1), bit_size: Field, value: 1 }, BinaryFieldOp { destination: Direct(0), op: Div, lhs: Direct(1), rhs: Direct(0) }, Stop { return_data: HeapVector { pointer: Direct(20), size: Direct(21) } }]" ], - "debug_symbols": "tVXbbsIwDP2XPOchzj37lWlCpQRUKWqr0E6aEP8+hzUFHoJQGE9u4pwj+9i1T2Tnt/Nh0/X74Ug+Pk9kG7sQusMmDG0zdUOPt6czJfm4maL3eEVu/Igam+j7iXz0cwiUfDdhvjw6jk1/sVMT0cso8f0OLRLuu+DT15le0awM5UIvYC7MCldP4wXnC14YV8LzMl4qJxcCqeU1AdB1DKLE8CgHl3OQTFdoIHkugBSyAq9lroHWvIQ3D/AcMl5BKX9bxlvBMoEVkpcYXJkBgDOzUOC3kv/AYSoqaVYGw2sqYSF3grVQwoN4uZ2fp6jpZ7cSAAOokAEEXxmkLQoJ5nUhzDuFAOnWjlKW1ShhucoMTqrigIPXJxy8VQmn7JqHuc/jC09N28W71UQYzkVKAJ9QwnGyUCJSP1Ei/4xCgz+LTipTYlIwlNikGCUO08EngBxpPQCypIYCvliR7DlFG7tmG/yyC/dz396sxulnzJ68PMc4tH43R59ivfgw+l8=", + "debug_symbols": "tVjLbuMwDPwXnX0QX3rsrywWRZq6RQDDCdxkgUXRf1+qlez0oKBV7NMksTkhR+TY0pt56h8vLw+H8fn4an79fjOP02EYDi8Pw3G/Ox+Oo/769t6Z8vXhPPW9/mSurmvUaTf149n8Gi/D0Jm/u+HycdPraTd+4Hk36VXbmX58UlTC58PQp0/v3RJt66EYJAdjcHO4fDuePOR4xlCLx3o8S+RC4HgpAFwbA9UYbtTAPNcg0qABu1jiAzXEu1jWwAPU4v2NeCz5O4Fa/aEe71GwJICRGhgC2ZJCIMYaA9wQAQCtzxz6WXgNEt/QDV5cEcO3rGZwRYpIthYPfPdIfJ+iZSbAMhUhrbMNOgD5mUGoqiSE+5UImyohXBoCHMYWJYIvOUCMXHXJFWxyU59EOw8XWuQGJVDnszAANTGQlCqQXLWr8F67xFtuZ2e/DDZWPQbjCm6H97suwQp5/ISkxXWRAs7reqXpDzqDkw98MrBUn6Mka6ghG6vBbqnFhxY1PM+T5rnFtTDAPO0Bq++GbO+cNIa7J41xhTW9mcf3Jo15jTx4494KfPXKb5s6IxQ1MELVxTmsoUbYWI1ISy0MLTsgxPKeQyjVOZE1evQnJC1qEPqllqa9DHEsmyESwqoabg013MZqCC+1SIuHkvdl1ijYqo+7NfZFbuN9kT6gl1qoaZ9spTyT2Na7y63hom5jF2Wwcy0ALS7KRGXWmFzVN9waLuo2dlHWjphriV9X9o9+2+0P05eTL2O1izoDektnUBPsDKW/7wynnWNnJG28OuMUNDmfdk6dCWnb0JmY3hE1WDlSSwJkxIzKhEoInFEyuow+uZtiyBiTbWkaKSe9jpARM1LqeEVOmyhFyegyKh9rkqh8yTAwfiLZjKlKTZuUTzRvooycUTIqnygfKZ8oH4WM8RNZ+UT5WPnSGQMn3TSOKb1fKSqfS/dJOlJSdBl9xpAOmN7TKk6H3ePQ5yPI58u4vzqRPP87lSvlzPI0Hff902Xq0xp+XNNV/Q8=", "file_map": { "16": { "source": "use crate::cmp::Eq;\nuse crate::hash::Hash;\nuse crate::ops::arith::{Add, Neg, Sub};\n\n/// A point on the embedded elliptic curve\n/// By definition, the base field of the embedded curve is the scalar field of the proof system curve, i.e the Noir Field.\n/// x and y denotes the Weierstrass coordinates of the point, if is_infinite is false.\npub struct EmbeddedCurvePoint {\n pub x: Field,\n pub y: Field,\n pub is_infinite: bool,\n}\n\nimpl EmbeddedCurvePoint {\n /// Elliptic curve point doubling operation\n /// returns the doubled point of a point P, i.e P+P\n pub fn double(self) -> EmbeddedCurvePoint {\n embedded_curve_add(self, self)\n }\n\n /// Returns the null element of the curve; 'the point at infinity'\n pub fn point_at_infinity() -> EmbeddedCurvePoint {\n EmbeddedCurvePoint { x: 0, y: 0, is_infinite: true }\n }\n\n /// Returns the curve's generator point.\n pub fn generator() -> EmbeddedCurvePoint {\n // Generator point for the grumpkin curve (y^2 = x^3 - 17)\n EmbeddedCurvePoint {\n x: 1,\n y: 17631683881184975370165255887551781615748388533673675138860, // sqrt(-16)\n is_infinite: false,\n }\n }\n}\n\nimpl Add for EmbeddedCurvePoint {\n /// Adds two points P+Q, using the curve addition formula, and also handles point at infinity\n fn add(self, other: EmbeddedCurvePoint) -> EmbeddedCurvePoint {\n embedded_curve_add(self, other)\n }\n}\n\nimpl Sub for EmbeddedCurvePoint {\n /// Points subtraction operation, using addition and negation\n fn sub(self, other: EmbeddedCurvePoint) -> EmbeddedCurvePoint {\n self + other.neg()\n }\n}\n\nimpl Neg for EmbeddedCurvePoint {\n /// Negates a point P, i.e returns -P, by negating the y coordinate.\n /// If the point is at infinity, then the result is also at infinity.\n fn neg(self) -> EmbeddedCurvePoint {\n EmbeddedCurvePoint { x: self.x, y: -self.y, is_infinite: self.is_infinite }\n }\n}\n\nimpl Eq for EmbeddedCurvePoint {\n /// Checks whether two points are equal\n fn eq(self: Self, b: EmbeddedCurvePoint) -> bool {\n (self.is_infinite & b.is_infinite)\n | ((self.is_infinite == b.is_infinite) & (self.x == b.x) & (self.y == b.y))\n }\n}\n\nimpl Hash for EmbeddedCurvePoint {\n fn hash(self, state: &mut H)\n where\n H: crate::hash::Hasher,\n {\n if self.is_infinite {\n self.is_infinite.hash(state);\n } else {\n self.x.hash(state);\n self.y.hash(state);\n }\n }\n}\n\n/// Scalar for the embedded curve represented as low and high limbs\n/// By definition, the scalar field of the embedded curve is base field of the proving system curve.\n/// It may not fit into a Field element, so it is represented with two Field elements; its low and high limbs.\npub struct EmbeddedCurveScalar {\n pub lo: Field,\n pub hi: Field,\n}\n\nimpl EmbeddedCurveScalar {\n pub fn new(lo: Field, hi: Field) -> Self {\n EmbeddedCurveScalar { lo, hi }\n }\n\n #[field(bn254)]\n pub fn from_field(scalar: Field) -> EmbeddedCurveScalar {\n let (a, b) = crate::field::bn254::decompose(scalar);\n EmbeddedCurveScalar { lo: a, hi: b }\n }\n\n //Bytes to scalar: take the first (after the specified offset) 16 bytes of the input as the lo value, and the next 16 bytes as the hi value\n #[field(bn254)]\n pub(crate) fn from_bytes(bytes: [u8; 64], offset: u32) -> EmbeddedCurveScalar {\n let mut v = 1;\n let mut lo = 0 as Field;\n let mut hi = 0 as Field;\n for i in 0..16 {\n lo = lo + (bytes[offset + 31 - i] as Field) * v;\n hi = hi + (bytes[offset + 15 - i] as Field) * v;\n v = v * 256;\n }\n let sig_s = crate::embedded_curve_ops::EmbeddedCurveScalar { lo, hi };\n sig_s\n }\n}\n\nimpl Eq for EmbeddedCurveScalar {\n fn eq(self, other: Self) -> bool {\n (other.hi == self.hi) & (other.lo == self.lo)\n }\n}\n\nimpl Hash for EmbeddedCurveScalar {\n fn hash(self, state: &mut H)\n where\n H: crate::hash::Hasher,\n {\n self.hi.hash(state);\n self.lo.hash(state);\n }\n}\n\n// Computes a multi scalar multiplication over the embedded curve.\n// For bn254, We have Grumpkin and Baby JubJub.\n// For bls12-381, we have JubJub and Bandersnatch.\n//\n// The embedded curve being used is decided by the\n// underlying proof system.\n// docs:start:multi_scalar_mul\npub fn multi_scalar_mul(\n points: [EmbeddedCurvePoint; N],\n scalars: [EmbeddedCurveScalar; N],\n) -> EmbeddedCurvePoint\n// docs:end:multi_scalar_mul\n{\n multi_scalar_mul_array_return(points, scalars)[0]\n}\n\n#[foreign(multi_scalar_mul)]\npub(crate) fn multi_scalar_mul_array_return(\n points: [EmbeddedCurvePoint; N],\n scalars: [EmbeddedCurveScalar; N],\n) -> [EmbeddedCurvePoint; 1] {}\n\n// docs:start:fixed_base_scalar_mul\npub fn fixed_base_scalar_mul(scalar: EmbeddedCurveScalar) -> EmbeddedCurvePoint\n// docs:end:fixed_base_scalar_mul\n{\n multi_scalar_mul([EmbeddedCurvePoint::generator()], [scalar])\n}\n\n/// This function only assumes that the points are on the curve\n/// It handles corner cases around the infinity point causing some overhead compared to embedded_curve_add_not_nul and embedded_curve_add_unsafe\n// docs:start:embedded_curve_add\npub fn embedded_curve_add(\n point1: EmbeddedCurvePoint,\n point2: EmbeddedCurvePoint,\n) -> EmbeddedCurvePoint {\n // docs:end:embedded_curve_add\n if crate::runtime::is_unconstrained() {\n // `embedded_curve_add_unsafe` requires the inputs not to be the infinity point, so we check it here.\n // This is because `embedded_curve_add_unsafe` uses the `embedded_curve_add` opcode.\n // For efficiency, the backend does not check the inputs for the infinity point, but it assumes that they are not the infinity point\n // so that it can apply the ec addition formula directly.\n if point1.is_infinite {\n point2\n } else if point2.is_infinite {\n point1\n } else {\n embedded_curve_add_unsafe(point1, point2)\n }\n } else {\n // In a constrained context, we also need to check the inputs are not the infinity point because we also use `embedded_curve_add_unsafe`\n // However we also need to identify the case where the two inputs are the same, because then\n // the addition formula does not work and we need to use the doubling formula instead.\n // In unconstrained context, we can check directly if the input values are the same when solving the opcode, so it is not an issue.\n\n // x_coordinates_match is true if both abscissae are the same\n let x_coordinates_match = point1.x == point2.x;\n // y_coordinates_match is true if both ordinates are the same\n let y_coordinates_match = point1.y == point2.y;\n // double_predicate is true if both abscissae and ordinates are the same\n let double_predicate = (x_coordinates_match & y_coordinates_match);\n // If the abscissae are the same, but not the ordinates, then one point is the opposite of the other\n let infinity_predicate = (x_coordinates_match & !y_coordinates_match);\n let point1_1 = EmbeddedCurvePoint {\n x: point1.x + (x_coordinates_match as Field),\n y: point1.y,\n is_infinite: false,\n };\n let point2_1 = EmbeddedCurvePoint { x: point2.x, y: point2.y, is_infinite: false };\n // point1_1 is guaranteed to have a different abscissa than point2:\n // - if x_coordinates_match is 0, that means point1.x != point2.x, and point1_1.x = point1.x + 0\n // - if x_coordinates_match is 1, that means point1.x = point2.x, but point1_1.x = point1.x + 1 in this case\n // Because the abscissa is different, the addition formula is guaranteed to succeed, so we can safely use `embedded_curve_add_unsafe`\n // Note that this computation may be garbage: if x_coordinates_match is 1, or if one of the input is the point at infinity.\n let mut result = embedded_curve_add_unsafe(point1_1, point2_1);\n\n // `embedded_curve_add_unsafe` is doing a doubling if the input is the same variable, because in this case it is guaranteed (at 'compile time') that the input is the same.\n let double = embedded_curve_add_unsafe(point1, point1);\n // `embedded_curve_add_unsafe` would not perform doubling, even if the inputs point1 and point2 are the same, because it cannot know this without adding some logic (and some constraints)\n // However we did this logic when we computed `double_predicate`, so we set the result to 2*point1 if point1 and point2 are the same\n result = if double_predicate { double } else { result };\n\n // Same logic as above for unconstrained context, we set the proper result when one of the inputs is the infinity point\n if point1.is_infinite {\n result = point2;\n }\n if point2.is_infinite {\n result = point1;\n }\n\n // Finally, we set the is_infinity flag of the result:\n // Opposite points should sum into the infinity point, however, if one of them is point at infinity, their coordinates are not meaningful\n // so we should not use the fact that the inputs are opposite in this case:\n let mut result_is_infinity =\n infinity_predicate & (!point1.is_infinite & !point2.is_infinite);\n // However, if both of them are at infinity, then the result is also at infinity\n result.is_infinite = result_is_infinity | (point1.is_infinite & point2.is_infinite);\n result\n }\n}\n\n#[foreign(embedded_curve_add)]\nfn embedded_curve_add_array_return(\n _point1: EmbeddedCurvePoint,\n _point2: EmbeddedCurvePoint,\n) -> [EmbeddedCurvePoint; 1] {}\n\n/// This function assumes that:\n/// The points are on the curve, and\n/// The points don't share an x-coordinate, and\n/// Neither point is the infinity point.\n/// If it is used with correct input, the function ensures the correct non-zero result is returned.\n/// Except for points on the curve, the other assumptions are checked by the function. It will cause assertion failure if they are not respected.\npub fn embedded_curve_add_not_nul(\n point1: EmbeddedCurvePoint,\n point2: EmbeddedCurvePoint,\n) -> EmbeddedCurvePoint {\n assert(point1.x != point2.x);\n assert(!point1.is_infinite);\n assert(!point2.is_infinite);\n // Ensure is_infinite is comptime\n let point1_1 = EmbeddedCurvePoint { x: point1.x, y: point1.y, is_infinite: false };\n let point2_1 = EmbeddedCurvePoint { x: point2.x, y: point2.y, is_infinite: false };\n embedded_curve_add_unsafe(point1_1, point2_1)\n}\n\n/// Unsafe ec addition\n/// If the inputs are the same, it will perform a doubling, but only if point1 and point2 are the same variable.\n/// If they have the same value but are different variables, the result will be incorrect because in this case\n/// it assumes (but does not check) that the points' x-coordinates are not equal.\n/// It also assumes neither point is the infinity point.\npub fn embedded_curve_add_unsafe(\n point1: EmbeddedCurvePoint,\n point2: EmbeddedCurvePoint,\n) -> EmbeddedCurvePoint {\n embedded_curve_add_array_return(point1, point2)[0]\n}\n", "path": "std/embedded_curve_ops.nr" }, "50": { - "source": "use std::ops::Add;\n\nfn main(priv_key: Field, pub_x: pub Field, pub_y: pub Field) {\n let g1 = std::embedded_curve_ops::EmbeddedCurvePoint::generator();\n let scalar = std::embedded_curve_ops::EmbeddedCurveScalar { lo: priv_key, hi: 0 };\n // Test that multi_scalar_mul correctly derives the public key\n let res = std::embedded_curve_ops::multi_scalar_mul([g1], [scalar]);\n assert(res.x == pub_x);\n assert(res.y == pub_y);\n\n // Test that double function calling embedded_curve_add works as expected\n let pub_point =\n std::embedded_curve_ops::EmbeddedCurvePoint { x: pub_x, y: pub_y, is_infinite: false };\n let res = pub_point.double();\n let double = g1.add(g1);\n\n assert(double.x == res.x);\n\n // Test calling multi_scalar_mul with multiple points and scalars\n let res = std::embedded_curve_ops::multi_scalar_mul([g1, g1], [scalar, scalar]);\n\n // The results should be double the g1 point because the scalars are 1 and we pass in g1 twice\n assert(double.x == res.x);\n\n // Tests for #6549\n let const_scalar1 = std::embedded_curve_ops::EmbeddedCurveScalar { lo: 23, hi: 0 };\n let const_scalar2 = std::embedded_curve_ops::EmbeddedCurveScalar { lo: 0, hi: 23 };\n let const_scalar3 = std::embedded_curve_ops::EmbeddedCurveScalar { lo: 13, hi: 4 };\n let partial_mul = std::embedded_curve_ops::multi_scalar_mul(\n [g1, double, pub_point, g1, g1],\n [scalar, const_scalar1, scalar, const_scalar2, const_scalar3],\n );\n assert(partial_mul.x == 0x2024c4eebfbc8a20018f8c95c7aab77c6f34f10cf785a6f04e97452d8708fda7);\n // Check simplification by zero\n let zero_point = std::embedded_curve_ops::EmbeddedCurvePoint { x: 0, y: 0, is_infinite: true };\n let const_zero = std::embedded_curve_ops::EmbeddedCurveScalar { lo: 0, hi: 0 };\n let partial_mul = std::embedded_curve_ops::multi_scalar_mul(\n [zero_point, double, g1],\n [scalar, const_zero, scalar],\n );\n assert(partial_mul == g1);\n}\n", + "source": "use std::{embedded_curve_ops::embedded_curve_add_unsafe, ops::Add};\n\nfn main(priv_key: Field, pub_x: pub Field, pub_y: pub Field) {\n let g1 = std::embedded_curve_ops::EmbeddedCurvePoint::generator();\n let scalar = std::embedded_curve_ops::EmbeddedCurveScalar { lo: priv_key, hi: 0 };\n // Test that multi_scalar_mul correctly derives the public key\n let res = std::embedded_curve_ops::multi_scalar_mul([g1], [scalar]);\n assert(res.x == pub_x);\n assert(res.y == pub_y);\n\n // Test that double function calling embedded_curve_add works as expected\n let pub_point =\n std::embedded_curve_ops::EmbeddedCurvePoint { x: pub_x, y: pub_y, is_infinite: false };\n let res = pub_point.double();\n let double = g1.add(g1);\n\n assert(double.x == res.x);\n\n // Test calling multi_scalar_mul with multiple points and scalars\n let res = std::embedded_curve_ops::multi_scalar_mul([g1, g1], [scalar, scalar]);\n\n // The results should be double the g1 point because the scalars are 1 and we pass in g1 twice\n assert(double.x == res.x);\n\n // Tests for #6549\n let const_scalar1 = std::embedded_curve_ops::EmbeddedCurveScalar { lo: 23, hi: 0 };\n let const_scalar2 = std::embedded_curve_ops::EmbeddedCurveScalar { lo: 0, hi: 23 };\n let const_scalar3 = std::embedded_curve_ops::EmbeddedCurveScalar { lo: 13, hi: 4 };\n let partial_mul = std::embedded_curve_ops::multi_scalar_mul(\n [g1, double, pub_point, g1, g1],\n [scalar, const_scalar1, scalar, const_scalar2, const_scalar3],\n );\n assert(partial_mul.x == 0x2024c4eebfbc8a20018f8c95c7aab77c6f34f10cf785a6f04e97452d8708fda7);\n // Check simplification by zero\n let zero_point = std::embedded_curve_ops::EmbeddedCurvePoint { x: 0, y: 0, is_infinite: true };\n let const_zero = std::embedded_curve_ops::EmbeddedCurveScalar { lo: 0, hi: 0 };\n let partial_mul = std::embedded_curve_ops::multi_scalar_mul(\n [zero_point, double, g1],\n [scalar, const_zero, scalar],\n );\n assert(partial_mul == g1);\n\n // Additional tests for validating embedded_curve_add_unsafe under a conditional\n if pub_x == pub_y {\n let a1 = std::embedded_curve_ops::EmbeddedCurvePoint { x: 1, y: 2, is_infinite: false };\n let a2 = std::embedded_curve_ops::EmbeddedCurvePoint { x: 1, y: 3, is_infinite: false };\n let doubling = a1.double();\n assert(doubling.x == 1);\n let res = embedded_curve_add_unsafe(a1, a2);\n assert(res.x == 1);\n\n let a1 = std::embedded_curve_ops::EmbeddedCurvePoint {\n x: pub_x + 1,\n y: pub_y,\n is_infinite: false,\n };\n let a2 = std::embedded_curve_ops::EmbeddedCurvePoint {\n x: pub_x + 1,\n y: pub_y + 1,\n is_infinite: false,\n };\n let doubling = a1.double();\n assert(doubling.x == 1);\n let res = embedded_curve_add_unsafe(a1, a2);\n assert(res.x == 1);\n\n let a1 = std::embedded_curve_ops::EmbeddedCurvePoint { x: 2, y: 3, is_infinite: false };\n let a2 = std::embedded_curve_ops::EmbeddedCurvePoint {\n x: pub_x,\n y: pub_y + 1 as Field,\n is_infinite: false,\n };\n let res = embedded_curve_add_unsafe(a1, a2);\n assert(res.x == 1);\n\n let a1 = std::embedded_curve_ops::EmbeddedCurvePoint { x: 2, y: 3, is_infinite: false };\n let a2 = std::embedded_curve_ops::EmbeddedCurvePoint { x: 2, y: 4, is_infinite: false };\n let res = embedded_curve_add_unsafe(a1, a2);\n assert(res.x == 1);\n\n let a1 = std::embedded_curve_ops::EmbeddedCurvePoint { x: 2, y: 3, is_infinite: false };\n let a2 = std::embedded_curve_ops::EmbeddedCurvePoint { x: 2, y: 3, is_infinite: false };\n let res = embedded_curve_add_unsafe(a1, a2);\n assert(res.x == 1);\n let a1 = std::embedded_curve_ops::EmbeddedCurvePoint { x: 1, y: 3, is_infinite: false };\n let a2 = std::embedded_curve_ops::EmbeddedCurvePoint { x: 1, y: 3, is_infinite: false };\n let res = embedded_curve_add_unsafe(a1, a2);\n assert(res.x == 1);\n let a1 = std::embedded_curve_ops::EmbeddedCurvePoint { x: pub_x, y: 3, is_infinite: false };\n let a2 = std::embedded_curve_ops::EmbeddedCurvePoint { x: pub_x, y: 2, is_infinite: false };\n let res = embedded_curve_add_unsafe(a1, a2);\n assert(res.x == 1);\n }\n}\n", "path": "" } }, "names": [ "main" ], - "brillig_names": [] + "brillig_names": [ + "directive_invert" + ] } diff --git a/tooling/nargo_cli/tests/snapshots/execution_success/embedded_curve_ops/execute__tests__force_brillig_false_inliner_9223372036854775807.snap b/tooling/nargo_cli/tests/snapshots/execution_success/embedded_curve_ops/execute__tests__force_brillig_false_inliner_9223372036854775807.snap index 95e9276a19b..12800efb646 100644 --- a/tooling/nargo_cli/tests/snapshots/execution_success/embedded_curve_ops/execute__tests__force_brillig_false_inliner_9223372036854775807.snap +++ b/tooling/nargo_cli/tests/snapshots/execution_success/embedded_curve_ops/execute__tests__force_brillig_false_inliner_9223372036854775807.snap @@ -34,38 +34,77 @@ expression: artifact }, "bytecode": [ "func 0", - "current witness index : _18", + "current witness index : _61", "private parameters indices : [_0]", "public parameters indices : [_1, _2]", "return value indices : []", "BLACKBOX::MULTI_SCALAR_MUL [(1, 254), (17631683881184975370165255887551781615748388533673675138860, 254), (0, 1), (_0, 254), (0, 254)] [_3, _4, _5]", "EXPR [ (-1, _1) (1, _3) 0 ]", "EXPR [ (-1, _2) (1, _4) 0 ]", - "EXPR [ (-1, _6) 0 ]", - "BLACKBOX::EMBEDDED_CURVE_ADD [(_1, 254), (_2, 254), (_6, 1), (_1, 254), (_2, 254), (_6, 1)] [_7, _8, _9]", - "EXPR [ (-1, _7) 3078034153852398078128400807926804309327113743808504829582559963737223069694 ]", - "BLACKBOX::MULTI_SCALAR_MUL [(1, 254), (17631683881184975370165255887551781615748388533673675138860, 254), (0, 1), (1, 254), (17631683881184975370165255887551781615748388533673675138860, 254), (0, 1), (_0, 254), (0, 254), (_0, 254), (0, 254)] [_10, _11, _12]", - "EXPR [ (-1, _10) 3078034153852398078128400807926804309327113743808504829582559963737223069694 ]", - "BLACKBOX::MULTI_SCALAR_MUL [(1, 254), (17631683881184975370165255887551781615748388533673675138860, 254), (0, 1), (_1, 254), (_2, 254), (0, 1), (11179562631109628533987091031692370366552561688588090155835439555627259799605, 254), (3443719903172018228650470536370404288991794296383447657609081676265727805364, 254), (0, 1), (_0, 254), (0, 254), (_0, 254), (0, 254), (1, 254), (0, 254)] [_13, _14, _15]", - "EXPR [ (1, _13) 7349266043899242844836273743257843180744506495159104166319746739537754653274 ]", - "BLACKBOX::MULTI_SCALAR_MUL [(1, 254), (17631683881184975370165255887551781615748388533673675138860, 254), (0, 1), (_0, 254), (0, 254)] [_16, _17, _18]", - "EXPR [ (1, _18) 0 ]", - "EXPR [ (1, _16) -1 ]", - "EXPR [ (1, _17) -17631683881184975370165255887551781615748388533673675138860 ]" + "BLACKBOX::EMBEDDED_CURVE_ADD [(_1, 254), (_2, 254), (0, 1), (_1, 254), (_2, 254), (0, 1)] [_6, _7, _8]", + "EXPR [ (-1, _6) 3078034153852398078128400807926804309327113743808504829582559963737223069694 ]", + "BLACKBOX::MULTI_SCALAR_MUL [(1, 254), (17631683881184975370165255887551781615748388533673675138860, 254), (0, 1), (1, 254), (17631683881184975370165255887551781615748388533673675138860, 254), (0, 1), (_0, 254), (0, 254), (_0, 254), (0, 254)] [_9, _10, _11]", + "EXPR [ (-1, _9) 3078034153852398078128400807926804309327113743808504829582559963737223069694 ]", + "BLACKBOX::MULTI_SCALAR_MUL [(1, 254), (17631683881184975370165255887551781615748388533673675138860, 254), (0, 1), (_1, 254), (_2, 254), (0, 1), (11179562631109628533987091031692370366552561688588090155835439555627259799605, 254), (3443719903172018228650470536370404288991794296383447657609081676265727805364, 254), (0, 1), (_0, 254), (0, 254), (_0, 254), (0, 254), (1, 254), (0, 254)] [_12, _13, _14]", + "EXPR [ (1, _12) 7349266043899242844836273743257843180744506495159104166319746739537754653274 ]", + "BLACKBOX::MULTI_SCALAR_MUL [(1, 254), (17631683881184975370165255887551781615748388533673675138860, 254), (0, 1), (_0, 254), (0, 254)] [_15, _16, _17]", + "EXPR [ (1, _17) 0 ]", + "EXPR [ (1, _15) -1 ]", + "EXPR [ (1, _16) -17631683881184975370165255887551781615748388533673675138860 ]", + "EXPR [ (1, _1) (-1, _2) (-1, _18) 0 ]", + "BRILLIG CALL func 0: inputs: [Single(Expression { mul_terms: [], linear_combinations: [(1, Witness(18))], q_c: 0 })], outputs: [Simple(Witness(19))]", + "EXPR [ (1, _18, _19) (1, _20) -1 ]", + "EXPR [ (1, _18, _20) 0 ]", + "EXPR [ (-17631683881184975370165255887551781615748388533673675138858, _20) (-1, _21) 17631683881184975370165255887551781615748388533673675138860 ]", + "BLACKBOX::EMBEDDED_CURVE_ADD [(1, 254), (_21, 254), (0, 1), (1, 254), (_21, 254), (0, 1)] [_22, _23, _24]", + "EXPR [ (1, _20, _22) (-1, _20) 0 ]", + "EXPR [ (-3078034153852398078128400807926804309327113743808504829582559963737223069693, _20) (-1, _25) 3078034153852398078128400807926804309327113743808504829582559963737223069694 ]", + "EXPR [ (9191351987198133172789796342745422989482268917117950487758512501574271532888, _20) (-1, _26) -9191351987198133172789796342745422989482268917117950487758512501574271532885 ]", + "BLACKBOX::EMBEDDED_CURVE_ADD [(1, 254), (_21, 254), (0, 1), (_25, 254), (_26, 254), (0, 1)] [_27, _28, _29]", + "EXPR [ (1, _20, _27) (-1, _20) 0 ]", + "EXPR [ (1, _1, _20) (-1, _30) 1 ]", + "EXPR [ (1, _2, _20) (-17631683881184975370165255887551781615748388533673675138860, _20) (-1, _31) 17631683881184975370165255887551781615748388533673675138860 ]", + "BLACKBOX::EMBEDDED_CURVE_ADD [(_30, 254), (_31, 254), (0, 1), (_30, 254), (_31, 254), (0, 1)] [_32, _33, _34]", + "EXPR [ (1, _20, _32) (-1, _20) 0 ]", + "EXPR [ (1, _1, _20) (-3078034153852398078128400807926804309327113743808504829582559963737223069693, _20) (-1, _35) 3078034153852398078128400807926804309327113743808504829582559963737223069694 ]", + "EXPR [ (1, _2, _20) (9191351987198133172789796342745422989482268917117950487758512501574271532886, _20) (-1, _36) -9191351987198133172789796342745422989482268917117950487758512501574271532885 ]", + "BLACKBOX::EMBEDDED_CURVE_ADD [(_30, 254), (_31, 254), (0, 1), (_35, 254), (_36, 254), (0, 1)] [_37, _38, _39]", + "EXPR [ (1, _20, _37) (-1, _20) 0 ]", + "EXPR [ (1, _20) (-1, _40) 1 ]", + "EXPR [ (-17631683881184975370165255887551781615748388533673675138857, _20) (-1, _41) 17631683881184975370165255887551781615748388533673675138860 ]", + "EXPR [ (1, _1, _20) (-3078034153852398078128400807926804309327113743808504829582559963737223069694, _20) (-1, _42) 3078034153852398078128400807926804309327113743808504829582559963737223069694 ]", + "BLACKBOX::EMBEDDED_CURVE_ADD [(_40, 254), (_41, 254), (0, 1), (_42, 254), (_36, 254), (0, 1)] [_43, _44, _45]", + "EXPR [ (1, _20, _43) (-1, _20) 0 ]", + "EXPR [ (-3078034153852398078128400807926804309327113743808504829582559963737223069692, _20) (-1, _46) 3078034153852398078128400807926804309327113743808504829582559963737223069694 ]", + "EXPR [ (9191351987198133172789796342745422989482268917117950487758512501574271532889, _20) (-1, _47) -9191351987198133172789796342745422989482268917117950487758512501574271532885 ]", + "BLACKBOX::EMBEDDED_CURVE_ADD [(_40, 254), (_41, 254), (0, 1), (_46, 254), (_47, 254), (0, 1)] [_48, _49, _50]", + "EXPR [ (1, _20, _48) (-1, _20) 0 ]", + "BLACKBOX::EMBEDDED_CURVE_ADD [(_40, 254), (_41, 254), (0, 1), (_40, 254), (_41, 254), (0, 1)] [_51, _52, _53]", + "EXPR [ (1, _20, _51) (-1, _20) 0 ]", + "BLACKBOX::EMBEDDED_CURVE_ADD [(1, 254), (_41, 254), (0, 1), (1, 254), (_41, 254), (0, 1)] [_54, _55, _56]", + "EXPR [ (1, _20, _54) (-1, _20) 0 ]", + "EXPR [ (1, _1, _20) (-1, _20) (-1, _57) 1 ]", + "EXPR [ (9191351987198133172789796342745422989482268917117950487758512501574271532887, _20) (-1, _58) -9191351987198133172789796342745422989482268917117950487758512501574271532885 ]", + "BLACKBOX::EMBEDDED_CURVE_ADD [(_57, 254), (_41, 254), (0, 1), (_42, 254), (_58, 254), (0, 1)] [_59, _60, _61]", + "EXPR [ (1, _20, _59) (-1, _20) 0 ]", + "unconstrained func 0", + "[Const { destination: Direct(21), bit_size: Integer(U32), value: 1 }, Const { destination: Direct(20), bit_size: Integer(U32), value: 0 }, CalldataCopy { destination_address: Direct(0), size_address: Direct(21), offset_address: Direct(20) }, Const { destination: Direct(2), bit_size: Field, value: 0 }, BinaryFieldOp { destination: Direct(3), op: Equals, lhs: Direct(0), rhs: Direct(2) }, JumpIf { condition: Direct(3), location: 8 }, Const { destination: Direct(1), bit_size: Field, value: 1 }, BinaryFieldOp { destination: Direct(0), op: Div, lhs: Direct(1), rhs: Direct(0) }, Stop { return_data: HeapVector { pointer: Direct(20), size: Direct(21) } }]" ], - "debug_symbols": "tVXbbsIwDP2XPOchzj37lWlCpQRUKWqr0E6aEP8+hzUFHoJQGE9u4pwj+9i1T2Tnt/Nh0/X74Ug+Pk9kG7sQusMmDG0zdUOPt6czJfm4maL3eEVu/Igam+j7iXz0cwiUfDdhvjw6jk1/sVMT0cso8f0OLRLuu+DT15le0awM5UIvYC7MCldP4wXnC14YV8LzMl4qJxcCqeU1AdB1DKLE8CgHl3OQTFdoIHkugBSyAq9lroHWvIQ3D/AcMl5BKX9bxlvBMoEVkpcYXJkBgDOzUOC3kv/AYSoqaVYGw2sqYSF3grVQwoN4uZ2fp6jpZ7cSAAOokAEEXxmkLQoJ5nUhzDuFAOnWjlKW1ShhucoMTqrigIPXJxy8VQmn7JqHuc/jC09N28W71UQYzkVKAJ9QwnGyUCJSP1Ei/4xCgz+LTipTYlIwlNikGCUO08EngBxpPQCypIYCvliR7DlFG7tmG/yyC/dz396sxulnzJ68PMc4tH43R59ivfgw+l8=", + "debug_symbols": "tVjLbuMwDPwXnX0QX3rsrywWRZq6RQDDCdxkgUXRf1+qlez0oKBV7NMksTkhR+TY0pt56h8vLw+H8fn4an79fjOP02EYDi8Pw3G/Ox+Oo/769t6Z8vXhPPW9/mSurmvUaTf149n8Gi/D0Jm/u+HycdPraTd+4Hk36VXbmX58UlTC58PQp0/v3RJt66EYJAdjcHO4fDuePOR4xlCLx3o8S+RC4HgpAFwbA9UYbtTAPNcg0qABu1jiAzXEu1jWwAPU4v2NeCz5O4Fa/aEe71GwJICRGhgC2ZJCIMYaA9wQAQCtzxz6WXgNEt/QDV5cEcO3rGZwRYpIthYPfPdIfJ+iZSbAMhUhrbMNOgD5mUGoqiSE+5UImyohXBoCHMYWJYIvOUCMXHXJFWxyU59EOw8XWuQGJVDnszAANTGQlCqQXLWr8F67xFtuZ2e/DDZWPQbjCm6H97suwQp5/ISkxXWRAs7reqXpDzqDkw98MrBUn6Mka6ghG6vBbqnFhxY1PM+T5rnFtTDAPO0Bq++GbO+cNIa7J41xhTW9mcf3Jo15jTx4494KfPXKb5s6IxQ1MELVxTmsoUbYWI1ISy0MLTsgxPKeQyjVOZE1evQnJC1qEPqllqa9DHEsmyESwqoabg013MZqCC+1SIuHkvdl1ijYqo+7NfZFbuN9kT6gl1qoaZ9spTyT2Na7y63hom5jF2Wwcy0ALS7KRGXWmFzVN9waLuo2dlHWjphriV9X9o9+2+0P05eTL2O1izoDektnUBPsDKW/7wynnWNnJG28OuMUNDmfdk6dCWnb0JmY3hE1WDlSSwJkxIzKhEoInFEyuow+uZtiyBiTbWkaKSe9jpARM1LqeEVOmyhFyegyKh9rkqh8yTAwfiLZjKlKTZuUTzRvooycUTIqnygfKZ8oH4WM8RNZ+UT5WPnSGQMn3TSOKb1fKSqfS/dJOlJSdBl9xpAOmN7TKk6H3ePQ5yPI58u4vzqRPP87lSvlzPI0Hff902Xq0xp+XNNV/Q8=", "file_map": { "16": { "source": "use crate::cmp::Eq;\nuse crate::hash::Hash;\nuse crate::ops::arith::{Add, Neg, Sub};\n\n/// A point on the embedded elliptic curve\n/// By definition, the base field of the embedded curve is the scalar field of the proof system curve, i.e the Noir Field.\n/// x and y denotes the Weierstrass coordinates of the point, if is_infinite is false.\npub struct EmbeddedCurvePoint {\n pub x: Field,\n pub y: Field,\n pub is_infinite: bool,\n}\n\nimpl EmbeddedCurvePoint {\n /// Elliptic curve point doubling operation\n /// returns the doubled point of a point P, i.e P+P\n pub fn double(self) -> EmbeddedCurvePoint {\n embedded_curve_add(self, self)\n }\n\n /// Returns the null element of the curve; 'the point at infinity'\n pub fn point_at_infinity() -> EmbeddedCurvePoint {\n EmbeddedCurvePoint { x: 0, y: 0, is_infinite: true }\n }\n\n /// Returns the curve's generator point.\n pub fn generator() -> EmbeddedCurvePoint {\n // Generator point for the grumpkin curve (y^2 = x^3 - 17)\n EmbeddedCurvePoint {\n x: 1,\n y: 17631683881184975370165255887551781615748388533673675138860, // sqrt(-16)\n is_infinite: false,\n }\n }\n}\n\nimpl Add for EmbeddedCurvePoint {\n /// Adds two points P+Q, using the curve addition formula, and also handles point at infinity\n fn add(self, other: EmbeddedCurvePoint) -> EmbeddedCurvePoint {\n embedded_curve_add(self, other)\n }\n}\n\nimpl Sub for EmbeddedCurvePoint {\n /// Points subtraction operation, using addition and negation\n fn sub(self, other: EmbeddedCurvePoint) -> EmbeddedCurvePoint {\n self + other.neg()\n }\n}\n\nimpl Neg for EmbeddedCurvePoint {\n /// Negates a point P, i.e returns -P, by negating the y coordinate.\n /// If the point is at infinity, then the result is also at infinity.\n fn neg(self) -> EmbeddedCurvePoint {\n EmbeddedCurvePoint { x: self.x, y: -self.y, is_infinite: self.is_infinite }\n }\n}\n\nimpl Eq for EmbeddedCurvePoint {\n /// Checks whether two points are equal\n fn eq(self: Self, b: EmbeddedCurvePoint) -> bool {\n (self.is_infinite & b.is_infinite)\n | ((self.is_infinite == b.is_infinite) & (self.x == b.x) & (self.y == b.y))\n }\n}\n\nimpl Hash for EmbeddedCurvePoint {\n fn hash(self, state: &mut H)\n where\n H: crate::hash::Hasher,\n {\n if self.is_infinite {\n self.is_infinite.hash(state);\n } else {\n self.x.hash(state);\n self.y.hash(state);\n }\n }\n}\n\n/// Scalar for the embedded curve represented as low and high limbs\n/// By definition, the scalar field of the embedded curve is base field of the proving system curve.\n/// It may not fit into a Field element, so it is represented with two Field elements; its low and high limbs.\npub struct EmbeddedCurveScalar {\n pub lo: Field,\n pub hi: Field,\n}\n\nimpl EmbeddedCurveScalar {\n pub fn new(lo: Field, hi: Field) -> Self {\n EmbeddedCurveScalar { lo, hi }\n }\n\n #[field(bn254)]\n pub fn from_field(scalar: Field) -> EmbeddedCurveScalar {\n let (a, b) = crate::field::bn254::decompose(scalar);\n EmbeddedCurveScalar { lo: a, hi: b }\n }\n\n //Bytes to scalar: take the first (after the specified offset) 16 bytes of the input as the lo value, and the next 16 bytes as the hi value\n #[field(bn254)]\n pub(crate) fn from_bytes(bytes: [u8; 64], offset: u32) -> EmbeddedCurveScalar {\n let mut v = 1;\n let mut lo = 0 as Field;\n let mut hi = 0 as Field;\n for i in 0..16 {\n lo = lo + (bytes[offset + 31 - i] as Field) * v;\n hi = hi + (bytes[offset + 15 - i] as Field) * v;\n v = v * 256;\n }\n let sig_s = crate::embedded_curve_ops::EmbeddedCurveScalar { lo, hi };\n sig_s\n }\n}\n\nimpl Eq for EmbeddedCurveScalar {\n fn eq(self, other: Self) -> bool {\n (other.hi == self.hi) & (other.lo == self.lo)\n }\n}\n\nimpl Hash for EmbeddedCurveScalar {\n fn hash(self, state: &mut H)\n where\n H: crate::hash::Hasher,\n {\n self.hi.hash(state);\n self.lo.hash(state);\n }\n}\n\n// Computes a multi scalar multiplication over the embedded curve.\n// For bn254, We have Grumpkin and Baby JubJub.\n// For bls12-381, we have JubJub and Bandersnatch.\n//\n// The embedded curve being used is decided by the\n// underlying proof system.\n// docs:start:multi_scalar_mul\npub fn multi_scalar_mul(\n points: [EmbeddedCurvePoint; N],\n scalars: [EmbeddedCurveScalar; N],\n) -> EmbeddedCurvePoint\n// docs:end:multi_scalar_mul\n{\n multi_scalar_mul_array_return(points, scalars)[0]\n}\n\n#[foreign(multi_scalar_mul)]\npub(crate) fn multi_scalar_mul_array_return(\n points: [EmbeddedCurvePoint; N],\n scalars: [EmbeddedCurveScalar; N],\n) -> [EmbeddedCurvePoint; 1] {}\n\n// docs:start:fixed_base_scalar_mul\npub fn fixed_base_scalar_mul(scalar: EmbeddedCurveScalar) -> EmbeddedCurvePoint\n// docs:end:fixed_base_scalar_mul\n{\n multi_scalar_mul([EmbeddedCurvePoint::generator()], [scalar])\n}\n\n/// This function only assumes that the points are on the curve\n/// It handles corner cases around the infinity point causing some overhead compared to embedded_curve_add_not_nul and embedded_curve_add_unsafe\n// docs:start:embedded_curve_add\npub fn embedded_curve_add(\n point1: EmbeddedCurvePoint,\n point2: EmbeddedCurvePoint,\n) -> EmbeddedCurvePoint {\n // docs:end:embedded_curve_add\n if crate::runtime::is_unconstrained() {\n // `embedded_curve_add_unsafe` requires the inputs not to be the infinity point, so we check it here.\n // This is because `embedded_curve_add_unsafe` uses the `embedded_curve_add` opcode.\n // For efficiency, the backend does not check the inputs for the infinity point, but it assumes that they are not the infinity point\n // so that it can apply the ec addition formula directly.\n if point1.is_infinite {\n point2\n } else if point2.is_infinite {\n point1\n } else {\n embedded_curve_add_unsafe(point1, point2)\n }\n } else {\n // In a constrained context, we also need to check the inputs are not the infinity point because we also use `embedded_curve_add_unsafe`\n // However we also need to identify the case where the two inputs are the same, because then\n // the addition formula does not work and we need to use the doubling formula instead.\n // In unconstrained context, we can check directly if the input values are the same when solving the opcode, so it is not an issue.\n\n // x_coordinates_match is true if both abscissae are the same\n let x_coordinates_match = point1.x == point2.x;\n // y_coordinates_match is true if both ordinates are the same\n let y_coordinates_match = point1.y == point2.y;\n // double_predicate is true if both abscissae and ordinates are the same\n let double_predicate = (x_coordinates_match & y_coordinates_match);\n // If the abscissae are the same, but not the ordinates, then one point is the opposite of the other\n let infinity_predicate = (x_coordinates_match & !y_coordinates_match);\n let point1_1 = EmbeddedCurvePoint {\n x: point1.x + (x_coordinates_match as Field),\n y: point1.y,\n is_infinite: false,\n };\n let point2_1 = EmbeddedCurvePoint { x: point2.x, y: point2.y, is_infinite: false };\n // point1_1 is guaranteed to have a different abscissa than point2:\n // - if x_coordinates_match is 0, that means point1.x != point2.x, and point1_1.x = point1.x + 0\n // - if x_coordinates_match is 1, that means point1.x = point2.x, but point1_1.x = point1.x + 1 in this case\n // Because the abscissa is different, the addition formula is guaranteed to succeed, so we can safely use `embedded_curve_add_unsafe`\n // Note that this computation may be garbage: if x_coordinates_match is 1, or if one of the input is the point at infinity.\n let mut result = embedded_curve_add_unsafe(point1_1, point2_1);\n\n // `embedded_curve_add_unsafe` is doing a doubling if the input is the same variable, because in this case it is guaranteed (at 'compile time') that the input is the same.\n let double = embedded_curve_add_unsafe(point1, point1);\n // `embedded_curve_add_unsafe` would not perform doubling, even if the inputs point1 and point2 are the same, because it cannot know this without adding some logic (and some constraints)\n // However we did this logic when we computed `double_predicate`, so we set the result to 2*point1 if point1 and point2 are the same\n result = if double_predicate { double } else { result };\n\n // Same logic as above for unconstrained context, we set the proper result when one of the inputs is the infinity point\n if point1.is_infinite {\n result = point2;\n }\n if point2.is_infinite {\n result = point1;\n }\n\n // Finally, we set the is_infinity flag of the result:\n // Opposite points should sum into the infinity point, however, if one of them is point at infinity, their coordinates are not meaningful\n // so we should not use the fact that the inputs are opposite in this case:\n let mut result_is_infinity =\n infinity_predicate & (!point1.is_infinite & !point2.is_infinite);\n // However, if both of them are at infinity, then the result is also at infinity\n result.is_infinite = result_is_infinity | (point1.is_infinite & point2.is_infinite);\n result\n }\n}\n\n#[foreign(embedded_curve_add)]\nfn embedded_curve_add_array_return(\n _point1: EmbeddedCurvePoint,\n _point2: EmbeddedCurvePoint,\n) -> [EmbeddedCurvePoint; 1] {}\n\n/// This function assumes that:\n/// The points are on the curve, and\n/// The points don't share an x-coordinate, and\n/// Neither point is the infinity point.\n/// If it is used with correct input, the function ensures the correct non-zero result is returned.\n/// Except for points on the curve, the other assumptions are checked by the function. It will cause assertion failure if they are not respected.\npub fn embedded_curve_add_not_nul(\n point1: EmbeddedCurvePoint,\n point2: EmbeddedCurvePoint,\n) -> EmbeddedCurvePoint {\n assert(point1.x != point2.x);\n assert(!point1.is_infinite);\n assert(!point2.is_infinite);\n // Ensure is_infinite is comptime\n let point1_1 = EmbeddedCurvePoint { x: point1.x, y: point1.y, is_infinite: false };\n let point2_1 = EmbeddedCurvePoint { x: point2.x, y: point2.y, is_infinite: false };\n embedded_curve_add_unsafe(point1_1, point2_1)\n}\n\n/// Unsafe ec addition\n/// If the inputs are the same, it will perform a doubling, but only if point1 and point2 are the same variable.\n/// If they have the same value but are different variables, the result will be incorrect because in this case\n/// it assumes (but does not check) that the points' x-coordinates are not equal.\n/// It also assumes neither point is the infinity point.\npub fn embedded_curve_add_unsafe(\n point1: EmbeddedCurvePoint,\n point2: EmbeddedCurvePoint,\n) -> EmbeddedCurvePoint {\n embedded_curve_add_array_return(point1, point2)[0]\n}\n", "path": "std/embedded_curve_ops.nr" }, "50": { - "source": "use std::ops::Add;\n\nfn main(priv_key: Field, pub_x: pub Field, pub_y: pub Field) {\n let g1 = std::embedded_curve_ops::EmbeddedCurvePoint::generator();\n let scalar = std::embedded_curve_ops::EmbeddedCurveScalar { lo: priv_key, hi: 0 };\n // Test that multi_scalar_mul correctly derives the public key\n let res = std::embedded_curve_ops::multi_scalar_mul([g1], [scalar]);\n assert(res.x == pub_x);\n assert(res.y == pub_y);\n\n // Test that double function calling embedded_curve_add works as expected\n let pub_point =\n std::embedded_curve_ops::EmbeddedCurvePoint { x: pub_x, y: pub_y, is_infinite: false };\n let res = pub_point.double();\n let double = g1.add(g1);\n\n assert(double.x == res.x);\n\n // Test calling multi_scalar_mul with multiple points and scalars\n let res = std::embedded_curve_ops::multi_scalar_mul([g1, g1], [scalar, scalar]);\n\n // The results should be double the g1 point because the scalars are 1 and we pass in g1 twice\n assert(double.x == res.x);\n\n // Tests for #6549\n let const_scalar1 = std::embedded_curve_ops::EmbeddedCurveScalar { lo: 23, hi: 0 };\n let const_scalar2 = std::embedded_curve_ops::EmbeddedCurveScalar { lo: 0, hi: 23 };\n let const_scalar3 = std::embedded_curve_ops::EmbeddedCurveScalar { lo: 13, hi: 4 };\n let partial_mul = std::embedded_curve_ops::multi_scalar_mul(\n [g1, double, pub_point, g1, g1],\n [scalar, const_scalar1, scalar, const_scalar2, const_scalar3],\n );\n assert(partial_mul.x == 0x2024c4eebfbc8a20018f8c95c7aab77c6f34f10cf785a6f04e97452d8708fda7);\n // Check simplification by zero\n let zero_point = std::embedded_curve_ops::EmbeddedCurvePoint { x: 0, y: 0, is_infinite: true };\n let const_zero = std::embedded_curve_ops::EmbeddedCurveScalar { lo: 0, hi: 0 };\n let partial_mul = std::embedded_curve_ops::multi_scalar_mul(\n [zero_point, double, g1],\n [scalar, const_zero, scalar],\n );\n assert(partial_mul == g1);\n}\n", + "source": "use std::{embedded_curve_ops::embedded_curve_add_unsafe, ops::Add};\n\nfn main(priv_key: Field, pub_x: pub Field, pub_y: pub Field) {\n let g1 = std::embedded_curve_ops::EmbeddedCurvePoint::generator();\n let scalar = std::embedded_curve_ops::EmbeddedCurveScalar { lo: priv_key, hi: 0 };\n // Test that multi_scalar_mul correctly derives the public key\n let res = std::embedded_curve_ops::multi_scalar_mul([g1], [scalar]);\n assert(res.x == pub_x);\n assert(res.y == pub_y);\n\n // Test that double function calling embedded_curve_add works as expected\n let pub_point =\n std::embedded_curve_ops::EmbeddedCurvePoint { x: pub_x, y: pub_y, is_infinite: false };\n let res = pub_point.double();\n let double = g1.add(g1);\n\n assert(double.x == res.x);\n\n // Test calling multi_scalar_mul with multiple points and scalars\n let res = std::embedded_curve_ops::multi_scalar_mul([g1, g1], [scalar, scalar]);\n\n // The results should be double the g1 point because the scalars are 1 and we pass in g1 twice\n assert(double.x == res.x);\n\n // Tests for #6549\n let const_scalar1 = std::embedded_curve_ops::EmbeddedCurveScalar { lo: 23, hi: 0 };\n let const_scalar2 = std::embedded_curve_ops::EmbeddedCurveScalar { lo: 0, hi: 23 };\n let const_scalar3 = std::embedded_curve_ops::EmbeddedCurveScalar { lo: 13, hi: 4 };\n let partial_mul = std::embedded_curve_ops::multi_scalar_mul(\n [g1, double, pub_point, g1, g1],\n [scalar, const_scalar1, scalar, const_scalar2, const_scalar3],\n );\n assert(partial_mul.x == 0x2024c4eebfbc8a20018f8c95c7aab77c6f34f10cf785a6f04e97452d8708fda7);\n // Check simplification by zero\n let zero_point = std::embedded_curve_ops::EmbeddedCurvePoint { x: 0, y: 0, is_infinite: true };\n let const_zero = std::embedded_curve_ops::EmbeddedCurveScalar { lo: 0, hi: 0 };\n let partial_mul = std::embedded_curve_ops::multi_scalar_mul(\n [zero_point, double, g1],\n [scalar, const_zero, scalar],\n );\n assert(partial_mul == g1);\n\n // Additional tests for validating embedded_curve_add_unsafe under a conditional\n if pub_x == pub_y {\n let a1 = std::embedded_curve_ops::EmbeddedCurvePoint { x: 1, y: 2, is_infinite: false };\n let a2 = std::embedded_curve_ops::EmbeddedCurvePoint { x: 1, y: 3, is_infinite: false };\n let doubling = a1.double();\n assert(doubling.x == 1);\n let res = embedded_curve_add_unsafe(a1, a2);\n assert(res.x == 1);\n\n let a1 = std::embedded_curve_ops::EmbeddedCurvePoint {\n x: pub_x + 1,\n y: pub_y,\n is_infinite: false,\n };\n let a2 = std::embedded_curve_ops::EmbeddedCurvePoint {\n x: pub_x + 1,\n y: pub_y + 1,\n is_infinite: false,\n };\n let doubling = a1.double();\n assert(doubling.x == 1);\n let res = embedded_curve_add_unsafe(a1, a2);\n assert(res.x == 1);\n\n let a1 = std::embedded_curve_ops::EmbeddedCurvePoint { x: 2, y: 3, is_infinite: false };\n let a2 = std::embedded_curve_ops::EmbeddedCurvePoint {\n x: pub_x,\n y: pub_y + 1 as Field,\n is_infinite: false,\n };\n let res = embedded_curve_add_unsafe(a1, a2);\n assert(res.x == 1);\n\n let a1 = std::embedded_curve_ops::EmbeddedCurvePoint { x: 2, y: 3, is_infinite: false };\n let a2 = std::embedded_curve_ops::EmbeddedCurvePoint { x: 2, y: 4, is_infinite: false };\n let res = embedded_curve_add_unsafe(a1, a2);\n assert(res.x == 1);\n\n let a1 = std::embedded_curve_ops::EmbeddedCurvePoint { x: 2, y: 3, is_infinite: false };\n let a2 = std::embedded_curve_ops::EmbeddedCurvePoint { x: 2, y: 3, is_infinite: false };\n let res = embedded_curve_add_unsafe(a1, a2);\n assert(res.x == 1);\n let a1 = std::embedded_curve_ops::EmbeddedCurvePoint { x: 1, y: 3, is_infinite: false };\n let a2 = std::embedded_curve_ops::EmbeddedCurvePoint { x: 1, y: 3, is_infinite: false };\n let res = embedded_curve_add_unsafe(a1, a2);\n assert(res.x == 1);\n let a1 = std::embedded_curve_ops::EmbeddedCurvePoint { x: pub_x, y: 3, is_infinite: false };\n let a2 = std::embedded_curve_ops::EmbeddedCurvePoint { x: pub_x, y: 2, is_infinite: false };\n let res = embedded_curve_add_unsafe(a1, a2);\n assert(res.x == 1);\n }\n}\n", "path": "" } }, "names": [ "main" ], - "brillig_names": [] + "brillig_names": [ + "directive_invert" + ] } diff --git a/tooling/nargo_cli/tests/snapshots/execution_success/embedded_curve_ops/execute__tests__force_brillig_true_inliner_-9223372036854775808.snap b/tooling/nargo_cli/tests/snapshots/execution_success/embedded_curve_ops/execute__tests__force_brillig_true_inliner_-9223372036854775808.snap index 4ee9067548c..4e4ecc82ff4 100644 --- a/tooling/nargo_cli/tests/snapshots/execution_success/embedded_curve_ops/execute__tests__force_brillig_true_inliner_-9223372036854775808.snap +++ b/tooling/nargo_cli/tests/snapshots/execution_success/embedded_curve_ops/execute__tests__force_brillig_true_inliner_-9223372036854775808.snap @@ -45,16 +45,16 @@ expression: artifact "return value indices : []", "BRILLIG CALL func 0: inputs: [Single(Expression { mul_terms: [], linear_combinations: [(1, Witness(0))], q_c: 0 }), Single(Expression { mul_terms: [], linear_combinations: [(1, Witness(1))], q_c: 0 }), Single(Expression { mul_terms: [], linear_combinations: [(1, Witness(2))], q_c: 0 })], outputs: []", "unconstrained func 0", - "[Const { destination: Direct(2), bit_size: Integer(U32), value: 1 }, Const { destination: Direct(1), bit_size: Integer(U32), value: 32841 }, Const { destination: Direct(0), bit_size: Integer(U32), value: 3 }, Const { destination: Relative(4), bit_size: Integer(U32), value: 3 }, Const { destination: Relative(5), bit_size: Integer(U32), value: 0 }, CalldataCopy { destination_address: Direct(32838), size_address: Relative(4), offset_address: Relative(5) }, Mov { destination: Relative(1), source: Direct(32838) }, Mov { destination: Relative(2), source: Direct(32839) }, Mov { destination: Relative(3), source: Direct(32840) }, Call { location: 14 }, Call { location: 18 }, Const { destination: Relative(1), bit_size: Integer(U32), value: 32841 }, Const { destination: Relative(2), bit_size: Integer(U32), value: 0 }, Stop { return_data: HeapVector { pointer: Relative(1), size: Relative(2) } }, Const { destination: Direct(32835), bit_size: Integer(U32), value: 1 }, Const { destination: Direct(32836), bit_size: Integer(U32), value: 2 }, Const { destination: Direct(32837), bit_size: Integer(U32), value: 3 }, Return, Call { location: 262 }, Const { destination: Relative(4), bit_size: Field, value: 1 }, Const { destination: Relative(5), bit_size: Field, value: 17631683881184975370165255887551781615748388533673675138860 }, Const { destination: Relative(6), bit_size: Integer(U1), value: 0 }, Mov { destination: Relative(7), source: Direct(1) }, Const { destination: Relative(8), bit_size: Integer(U32), value: 4 }, BinaryIntOp { destination: Direct(1), op: Add, bit_size: U32, lhs: Direct(1), rhs: Relative(8) }, IndirectConst { destination_pointer: Relative(7), bit_size: Integer(U32), value: 1 }, BinaryIntOp { destination: Relative(8), op: Add, bit_size: U32, lhs: Relative(7), rhs: Direct(2) }, Mov { destination: Relative(9), source: Relative(8) }, Store { destination_pointer: Relative(9), source: Relative(4) }, BinaryIntOp { destination: Relative(9), op: Add, bit_size: U32, lhs: Relative(9), rhs: Direct(2) }, Store { destination_pointer: Relative(9), source: Relative(5) }, BinaryIntOp { destination: Relative(9), op: Add, bit_size: U32, lhs: Relative(9), rhs: Direct(2) }, Store { destination_pointer: Relative(9), source: Relative(6) }, Const { destination: Relative(8), bit_size: Field, value: 0 }, Mov { destination: Relative(9), source: Direct(1) }, Const { destination: Relative(10), bit_size: Integer(U32), value: 3 }, BinaryIntOp { destination: Direct(1), op: Add, bit_size: U32, lhs: Direct(1), rhs: Relative(10) }, IndirectConst { destination_pointer: Relative(9), bit_size: Integer(U32), value: 1 }, BinaryIntOp { destination: Relative(10), op: Add, bit_size: U32, lhs: Relative(9), rhs: Direct(2) }, Mov { destination: Relative(11), source: Relative(10) }, Store { destination_pointer: Relative(11), source: Relative(1) }, BinaryIntOp { destination: Relative(11), op: Add, bit_size: U32, lhs: Relative(11), rhs: Direct(2) }, Store { destination_pointer: Relative(11), source: Relative(8) }, Mov { destination: Relative(10), source: Direct(1) }, Const { destination: Relative(11), bit_size: Integer(U32), value: 4 }, BinaryIntOp { destination: Direct(1), op: Add, bit_size: U32, lhs: Direct(1), rhs: Relative(11) }, IndirectConst { destination_pointer: Relative(10), bit_size: Integer(U32), value: 1 }, BinaryIntOp { destination: Relative(11), op: Add, bit_size: U32, lhs: Relative(7), rhs: Direct(2) }, Const { destination: Relative(12), bit_size: Integer(U32), value: 3 }, BinaryIntOp { destination: Relative(13), op: Add, bit_size: U32, lhs: Relative(9), rhs: Direct(2) }, Const { destination: Relative(14), bit_size: Integer(U32), value: 2 }, BinaryIntOp { destination: Relative(15), op: Add, bit_size: U32, lhs: Relative(10), rhs: Direct(2) }, BlackBox(MultiScalarMul { points: HeapVector { pointer: Relative(11), size: Relative(12) }, scalars: HeapVector { pointer: Relative(13), size: Relative(14) }, outputs: HeapArray { pointer: Relative(15), size: 3 } }), BinaryIntOp { destination: Relative(9), op: Add, bit_size: U32, lhs: Relative(10), rhs: Direct(32835) }, Load { destination: Relative(7), source_pointer: Relative(9) }, BinaryIntOp { destination: Relative(11), op: Add, bit_size: U32, lhs: Relative(10), rhs: Direct(32836) }, Load { destination: Relative(9), source_pointer: Relative(11) }, BinaryFieldOp { destination: Relative(10), op: Equals, lhs: Relative(7), rhs: Relative(2) }, JumpIf { condition: Relative(10), location: 61 }, Const { destination: Relative(11), bit_size: Integer(U32), value: 0 }, Trap { revert_data: HeapVector { pointer: Direct(1), size: Relative(11) } }, BinaryFieldOp { destination: Relative(7), op: Equals, lhs: Relative(9), rhs: Relative(3) }, JumpIf { condition: Relative(7), location: 65 }, Const { destination: Relative(10), bit_size: Integer(U32), value: 0 }, Trap { revert_data: HeapVector { pointer: Direct(1), size: Relative(10) } }, Const { destination: Relative(11), bit_size: Integer(U32), value: 12 }, Mov { destination: Relative(12), source: Direct(0) }, Mov { destination: Relative(13), source: Relative(2) }, Mov { destination: Relative(14), source: Relative(3) }, Mov { destination: Relative(15), source: Relative(6) }, Mov { destination: Relative(16), source: Relative(2) }, Mov { destination: Relative(17), source: Relative(3) }, Mov { destination: Relative(18), source: Relative(6) }, BinaryIntOp { destination: Direct(0), op: Add, bit_size: U32, lhs: Direct(0), rhs: Relative(11) }, Call { location: 268 }, Mov { destination: Direct(0), source: Relative(0) }, Mov { destination: Relative(7), source: Relative(13) }, Mov { destination: Relative(9), source: Relative(14) }, Mov { destination: Relative(10), source: Relative(15) }, Const { destination: Relative(14), bit_size: Integer(U32), value: 15 }, Mov { destination: Relative(15), source: Direct(0) }, Mov { destination: Relative(16), source: Relative(4) }, Mov { destination: Relative(17), source: Relative(5) }, Mov { destination: Relative(18), source: Relative(6) }, Mov { destination: Relative(19), source: Relative(4) }, Mov { destination: Relative(20), source: Relative(5) }, Mov { destination: Relative(21), source: Relative(6) }, BinaryIntOp { destination: Direct(0), op: Add, bit_size: U32, lhs: Direct(0), rhs: Relative(14) }, Call { location: 268 }, Mov { destination: Direct(0), source: Relative(0) }, Mov { destination: Relative(11), source: Relative(16) }, Mov { destination: Relative(12), source: Relative(17) }, Mov { destination: Relative(13), source: Relative(18) }, BinaryFieldOp { destination: Relative(14), op: Equals, lhs: Relative(11), rhs: Relative(7) }, JumpIf { condition: Relative(14), location: 97 }, Const { destination: Relative(15), bit_size: Integer(U32), value: 0 }, Trap { revert_data: HeapVector { pointer: Direct(1), size: Relative(15) } }, Mov { destination: Relative(7), source: Direct(1) }, Const { destination: Relative(14), bit_size: Integer(U32), value: 7 }, BinaryIntOp { destination: Direct(1), op: Add, bit_size: U32, lhs: Direct(1), rhs: Relative(14) }, IndirectConst { destination_pointer: Relative(7), bit_size: Integer(U32), value: 1 }, BinaryIntOp { destination: Relative(14), op: Add, bit_size: U32, lhs: Relative(7), rhs: Direct(2) }, Mov { destination: Relative(15), source: Relative(14) }, Store { destination_pointer: Relative(15), source: Relative(4) }, BinaryIntOp { destination: Relative(15), op: Add, bit_size: U32, lhs: Relative(15), rhs: Direct(2) }, Store { destination_pointer: Relative(15), source: Relative(5) }, BinaryIntOp { destination: Relative(15), op: Add, bit_size: U32, lhs: Relative(15), rhs: Direct(2) }, Store { destination_pointer: Relative(15), source: Relative(6) }, BinaryIntOp { destination: Relative(15), op: Add, bit_size: U32, lhs: Relative(15), rhs: Direct(2) }, Store { destination_pointer: Relative(15), source: Relative(4) }, BinaryIntOp { destination: Relative(15), op: Add, bit_size: U32, lhs: Relative(15), rhs: Direct(2) }, Store { destination_pointer: Relative(15), source: Relative(5) }, BinaryIntOp { destination: Relative(15), op: Add, bit_size: U32, lhs: Relative(15), rhs: Direct(2) }, Store { destination_pointer: Relative(15), source: Relative(6) }, Mov { destination: Relative(14), source: Direct(1) }, Const { destination: Relative(15), bit_size: Integer(U32), value: 5 }, BinaryIntOp { destination: Direct(1), op: Add, bit_size: U32, lhs: Direct(1), rhs: Relative(15) }, IndirectConst { destination_pointer: Relative(14), bit_size: Integer(U32), value: 1 }, BinaryIntOp { destination: Relative(15), op: Add, bit_size: U32, lhs: Relative(14), rhs: Direct(2) }, Mov { destination: Relative(16), source: Relative(15) }, Store { destination_pointer: Relative(16), source: Relative(1) }, BinaryIntOp { destination: Relative(16), op: Add, bit_size: U32, lhs: Relative(16), rhs: Direct(2) }, Store { destination_pointer: Relative(16), source: Relative(8) }, BinaryIntOp { destination: Relative(16), op: Add, bit_size: U32, lhs: Relative(16), rhs: Direct(2) }, Store { destination_pointer: Relative(16), source: Relative(1) }, BinaryIntOp { destination: Relative(16), op: Add, bit_size: U32, lhs: Relative(16), rhs: Direct(2) }, Store { destination_pointer: Relative(16), source: Relative(8) }, Mov { destination: Relative(15), source: Direct(1) }, Const { destination: Relative(16), bit_size: Integer(U32), value: 4 }, BinaryIntOp { destination: Direct(1), op: Add, bit_size: U32, lhs: Direct(1), rhs: Relative(16) }, IndirectConst { destination_pointer: Relative(15), bit_size: Integer(U32), value: 1 }, BinaryIntOp { destination: Relative(16), op: Add, bit_size: U32, lhs: Relative(7), rhs: Direct(2) }, Const { destination: Relative(17), bit_size: Integer(U32), value: 6 }, BinaryIntOp { destination: Relative(18), op: Add, bit_size: U32, lhs: Relative(14), rhs: Direct(2) }, Const { destination: Relative(19), bit_size: Integer(U32), value: 4 }, BinaryIntOp { destination: Relative(20), op: Add, bit_size: U32, lhs: Relative(15), rhs: Direct(2) }, BlackBox(MultiScalarMul { points: HeapVector { pointer: Relative(16), size: Relative(17) }, scalars: HeapVector { pointer: Relative(18), size: Relative(19) }, outputs: HeapArray { pointer: Relative(20), size: 3 } }), BinaryIntOp { destination: Relative(14), op: Add, bit_size: U32, lhs: Relative(15), rhs: Direct(32835) }, Load { destination: Relative(7), source_pointer: Relative(14) }, BinaryFieldOp { destination: Relative(14), op: Equals, lhs: Relative(11), rhs: Relative(7) }, JumpIf { condition: Relative(14), location: 143 }, Const { destination: Relative(15), bit_size: Integer(U32), value: 0 }, Trap { revert_data: HeapVector { pointer: Direct(1), size: Relative(15) } }, Const { destination: Relative(7), bit_size: Field, value: 23 }, Mov { destination: Relative(14), source: Direct(1) }, Const { destination: Relative(15), bit_size: Integer(U32), value: 9 }, BinaryIntOp { destination: Direct(1), op: Add, bit_size: U32, lhs: Direct(1), rhs: Relative(15) }, IndirectConst { destination_pointer: Relative(14), bit_size: Integer(U32), value: 1 }, BinaryIntOp { destination: Relative(15), op: Add, bit_size: U32, lhs: Relative(14), rhs: Direct(2) }, Mov { destination: Relative(16), source: Relative(15) }, Store { destination_pointer: Relative(16), source: Relative(1) }, BinaryIntOp { destination: Relative(16), op: Add, bit_size: U32, lhs: Relative(16), rhs: Direct(2) }, Store { destination_pointer: Relative(16), source: Relative(8) }, BinaryIntOp { destination: Relative(16), op: Add, bit_size: U32, lhs: Relative(16), rhs: Direct(2) }, Store { destination_pointer: Relative(16), source: Relative(7) }, BinaryIntOp { destination: Relative(16), op: Add, bit_size: U32, lhs: Relative(16), rhs: Direct(2) }, Store { destination_pointer: Relative(16), source: Relative(8) }, BinaryIntOp { destination: Relative(16), op: Add, bit_size: U32, lhs: Relative(16), rhs: Direct(2) }, Store { destination_pointer: Relative(16), source: Relative(1) }, BinaryIntOp { destination: Relative(16), op: Add, bit_size: U32, lhs: Relative(16), rhs: Direct(2) }, Store { destination_pointer: Relative(16), source: Relative(8) }, BinaryIntOp { destination: Relative(16), op: Add, bit_size: U32, lhs: Relative(16), rhs: Direct(2) }, Store { destination_pointer: Relative(16), source: Relative(4) }, BinaryIntOp { destination: Relative(16), op: Add, bit_size: U32, lhs: Relative(16), rhs: Direct(2) }, Store { destination_pointer: Relative(16), source: Relative(8) }, Const { destination: Relative(7), bit_size: Field, value: 10456889356757736161582760391335869408742580538510966583040563008531594628700 }, Const { destination: Relative(15), bit_size: Field, value: 4714263418031017792755226781102360879566029698463912436805212494059649164343 }, Mov { destination: Relative(16), source: Direct(1) }, Const { destination: Relative(17), bit_size: Integer(U32), value: 13 }, BinaryIntOp { destination: Direct(1), op: Add, bit_size: U32, lhs: Direct(1), rhs: Relative(17) }, IndirectConst { destination_pointer: Relative(16), bit_size: Integer(U32), value: 1 }, BinaryIntOp { destination: Relative(17), op: Add, bit_size: U32, lhs: Relative(16), rhs: Direct(2) }, Mov { destination: Relative(18), source: Relative(17) }, Store { destination_pointer: Relative(18), source: Relative(4) }, BinaryIntOp { destination: Relative(18), op: Add, bit_size: U32, lhs: Relative(18), rhs: Direct(2) }, Store { destination_pointer: Relative(18), source: Relative(5) }, BinaryIntOp { destination: Relative(18), op: Add, bit_size: U32, lhs: Relative(18), rhs: Direct(2) }, Store { destination_pointer: Relative(18), source: Relative(6) }, BinaryIntOp { destination: Relative(18), op: Add, bit_size: U32, lhs: Relative(18), rhs: Direct(2) }, Store { destination_pointer: Relative(18), source: Relative(11) }, BinaryIntOp { destination: Relative(18), op: Add, bit_size: U32, lhs: Relative(18), rhs: Direct(2) }, Store { destination_pointer: Relative(18), source: Relative(12) }, BinaryIntOp { destination: Relative(18), op: Add, bit_size: U32, lhs: Relative(18), rhs: Direct(2) }, Store { destination_pointer: Relative(18), source: Relative(13) }, BinaryIntOp { destination: Relative(18), op: Add, bit_size: U32, lhs: Relative(18), rhs: Direct(2) }, Store { destination_pointer: Relative(18), source: Relative(2) }, BinaryIntOp { destination: Relative(18), op: Add, bit_size: U32, lhs: Relative(18), rhs: Direct(2) }, Store { destination_pointer: Relative(18), source: Relative(3) }, BinaryIntOp { destination: Relative(18), op: Add, bit_size: U32, lhs: Relative(18), rhs: Direct(2) }, Store { destination_pointer: Relative(18), source: Relative(6) }, BinaryIntOp { destination: Relative(18), op: Add, bit_size: U32, lhs: Relative(18), rhs: Direct(2) }, Store { destination_pointer: Relative(18), source: Relative(7) }, BinaryIntOp { destination: Relative(18), op: Add, bit_size: U32, lhs: Relative(18), rhs: Direct(2) }, Store { destination_pointer: Relative(18), source: Relative(15) }, BinaryIntOp { destination: Relative(18), op: Add, bit_size: U32, lhs: Relative(18), rhs: Direct(2) }, Store { destination_pointer: Relative(18), source: Relative(6) }, Mov { destination: Relative(2), source: Direct(1) }, Const { destination: Relative(3), bit_size: Integer(U32), value: 4 }, BinaryIntOp { destination: Direct(1), op: Add, bit_size: U32, lhs: Direct(1), rhs: Relative(3) }, IndirectConst { destination_pointer: Relative(2), bit_size: Integer(U32), value: 1 }, BinaryIntOp { destination: Relative(3), op: Add, bit_size: U32, lhs: Relative(16), rhs: Direct(2) }, Const { destination: Relative(7), bit_size: Integer(U32), value: 12 }, BinaryIntOp { destination: Relative(11), op: Add, bit_size: U32, lhs: Relative(14), rhs: Direct(2) }, Const { destination: Relative(12), bit_size: Integer(U32), value: 8 }, BinaryIntOp { destination: Relative(13), op: Add, bit_size: U32, lhs: Relative(2), rhs: Direct(2) }, BlackBox(MultiScalarMul { points: HeapVector { pointer: Relative(3), size: Relative(7) }, scalars: HeapVector { pointer: Relative(11), size: Relative(12) }, outputs: HeapArray { pointer: Relative(13), size: 3 } }), BinaryIntOp { destination: Relative(7), op: Add, bit_size: U32, lhs: Relative(2), rhs: Direct(32835) }, Load { destination: Relative(3), source_pointer: Relative(7) }, Const { destination: Relative(2), bit_size: Field, value: -7349266043899242844836273743257843180744506495159104166319746739537754653274 }, BinaryFieldOp { destination: Relative(7), op: Equals, lhs: Relative(3), rhs: Relative(2) }, JumpIf { condition: Relative(7), location: 213 }, Const { destination: Relative(11), bit_size: Integer(U32), value: 0 }, Trap { revert_data: HeapVector { pointer: Direct(1), size: Relative(11) } }, Mov { destination: Relative(2), source: Direct(1) }, Const { destination: Relative(3), bit_size: Integer(U32), value: 3 }, BinaryIntOp { destination: Direct(1), op: Add, bit_size: U32, lhs: Direct(1), rhs: Relative(3) }, IndirectConst { destination_pointer: Relative(2), bit_size: Integer(U32), value: 1 }, BinaryIntOp { destination: Relative(3), op: Add, bit_size: U32, lhs: Relative(2), rhs: Direct(2) }, Mov { destination: Relative(7), source: Relative(3) }, Store { destination_pointer: Relative(7), source: Relative(1) }, BinaryIntOp { destination: Relative(7), op: Add, bit_size: U32, lhs: Relative(7), rhs: Direct(2) }, Store { destination_pointer: Relative(7), source: Relative(8) }, Mov { destination: Relative(1), source: Direct(1) }, Const { destination: Relative(3), bit_size: Integer(U32), value: 4 }, BinaryIntOp { destination: Direct(1), op: Add, bit_size: U32, lhs: Direct(1), rhs: Relative(3) }, IndirectConst { destination_pointer: Relative(1), bit_size: Integer(U32), value: 1 }, BinaryIntOp { destination: Relative(3), op: Add, bit_size: U32, lhs: Relative(1), rhs: Direct(2) }, Mov { destination: Relative(7), source: Relative(3) }, Store { destination_pointer: Relative(7), source: Relative(4) }, BinaryIntOp { destination: Relative(7), op: Add, bit_size: U32, lhs: Relative(7), rhs: Direct(2) }, Store { destination_pointer: Relative(7), source: Relative(5) }, BinaryIntOp { destination: Relative(7), op: Add, bit_size: U32, lhs: Relative(7), rhs: Direct(2) }, Store { destination_pointer: Relative(7), source: Relative(6) }, Mov { destination: Relative(3), source: Direct(1) }, Const { destination: Relative(7), bit_size: Integer(U32), value: 4 }, BinaryIntOp { destination: Direct(1), op: Add, bit_size: U32, lhs: Direct(1), rhs: Relative(7) }, IndirectConst { destination_pointer: Relative(3), bit_size: Integer(U32), value: 1 }, BinaryIntOp { destination: Relative(7), op: Add, bit_size: U32, lhs: Relative(1), rhs: Direct(2) }, Const { destination: Relative(8), bit_size: Integer(U32), value: 3 }, BinaryIntOp { destination: Relative(11), op: Add, bit_size: U32, lhs: Relative(2), rhs: Direct(2) }, Const { destination: Relative(12), bit_size: Integer(U32), value: 2 }, BinaryIntOp { destination: Relative(13), op: Add, bit_size: U32, lhs: Relative(3), rhs: Direct(2) }, BlackBox(MultiScalarMul { points: HeapVector { pointer: Relative(7), size: Relative(8) }, scalars: HeapVector { pointer: Relative(11), size: Relative(12) }, outputs: HeapArray { pointer: Relative(13), size: 3 } }), BinaryIntOp { destination: Relative(2), op: Add, bit_size: U32, lhs: Relative(3), rhs: Direct(32835) }, Load { destination: Relative(1), source_pointer: Relative(2) }, BinaryIntOp { destination: Relative(7), op: Add, bit_size: U32, lhs: Relative(3), rhs: Direct(32836) }, Load { destination: Relative(2), source_pointer: Relative(7) }, BinaryIntOp { destination: Relative(8), op: Add, bit_size: U32, lhs: Relative(3), rhs: Direct(32837) }, Load { destination: Relative(7), source_pointer: Relative(8) }, BinaryIntOp { destination: Relative(3), op: Equals, bit_size: U1, lhs: Relative(7), rhs: Relative(6) }, JumpIf { condition: Relative(3), location: 253 }, Const { destination: Relative(8), bit_size: Integer(U32), value: 0 }, Trap { revert_data: HeapVector { pointer: Direct(1), size: Relative(8) } }, BinaryFieldOp { destination: Relative(3), op: Equals, lhs: Relative(1), rhs: Relative(4) }, JumpIf { condition: Relative(3), location: 257 }, Const { destination: Relative(6), bit_size: Integer(U32), value: 0 }, Trap { revert_data: HeapVector { pointer: Direct(1), size: Relative(6) } }, BinaryFieldOp { destination: Relative(1), op: Equals, lhs: Relative(2), rhs: Relative(5) }, JumpIf { condition: Relative(1), location: 261 }, Const { destination: Relative(3), bit_size: Integer(U32), value: 0 }, Trap { revert_data: HeapVector { pointer: Direct(1), size: Relative(3) } }, Return, Const { destination: Direct(32772), bit_size: Integer(U32), value: 30720 }, BinaryIntOp { destination: Direct(32771), op: LessThan, bit_size: U32, lhs: Direct(0), rhs: Direct(32772) }, JumpIf { condition: Direct(32771), location: 267 }, IndirectConst { destination_pointer: Direct(1), bit_size: Integer(U64), value: 17843811134343075018 }, Trap { revert_data: HeapVector { pointer: Direct(1), size: Direct(2) } }, Return, Call { location: 262 }, JumpIf { condition: Relative(3), location: 297 }, Jump { location: 271 }, JumpIf { condition: Relative(6), location: 289 }, Jump { location: 273 }, Mov { destination: Relative(13), source: Direct(1) }, Const { destination: Relative(14), bit_size: Integer(U32), value: 4 }, BinaryIntOp { destination: Direct(1), op: Add, bit_size: U32, lhs: Direct(1), rhs: Relative(14) }, IndirectConst { destination_pointer: Relative(13), bit_size: Integer(U32), value: 1 }, BinaryIntOp { destination: Relative(14), op: Add, bit_size: U32, lhs: Relative(13), rhs: Direct(2) }, BlackBox(EmbeddedCurveAdd { input1_x: Relative(1), input1_y: Relative(2), input1_infinite: Relative(3), input2_x: Relative(4), input2_y: Relative(5), input2_infinite: Relative(6), result: HeapArray { pointer: Relative(14), size: 3 } }), BinaryIntOp { destination: Relative(2), op: Add, bit_size: U32, lhs: Relative(13), rhs: Direct(32835) }, Load { destination: Relative(1), source_pointer: Relative(2) }, BinaryIntOp { destination: Relative(3), op: Add, bit_size: U32, lhs: Relative(13), rhs: Direct(32836) }, Load { destination: Relative(2), source_pointer: Relative(3) }, BinaryIntOp { destination: Relative(4), op: Add, bit_size: U32, lhs: Relative(13), rhs: Direct(32837) }, Load { destination: Relative(3), source_pointer: Relative(4) }, Mov { destination: Relative(10), source: Relative(1) }, Mov { destination: Relative(11), source: Relative(2) }, Mov { destination: Relative(12), source: Relative(3) }, Jump { location: 293 }, Mov { destination: Relative(10), source: Relative(1) }, Mov { destination: Relative(11), source: Relative(2) }, Mov { destination: Relative(12), source: Relative(3) }, Jump { location: 293 }, Mov { destination: Relative(7), source: Relative(10) }, Mov { destination: Relative(8), source: Relative(11) }, Mov { destination: Relative(9), source: Relative(12) }, Jump { location: 301 }, Mov { destination: Relative(7), source: Relative(4) }, Mov { destination: Relative(8), source: Relative(5) }, Mov { destination: Relative(9), source: Relative(6) }, Jump { location: 301 }, Mov { destination: Relative(1), source: Relative(7) }, Mov { destination: Relative(2), source: Relative(8) }, Mov { destination: Relative(3), source: Relative(9) }, Return]" + "[Const { destination: Direct(2), bit_size: Integer(U32), value: 1 }, Const { destination: Direct(1), bit_size: Integer(U32), value: 32841 }, Const { destination: Direct(0), bit_size: Integer(U32), value: 3 }, Const { destination: Relative(4), bit_size: Integer(U32), value: 3 }, Const { destination: Relative(5), bit_size: Integer(U32), value: 0 }, CalldataCopy { destination_address: Direct(32838), size_address: Relative(4), offset_address: Relative(5) }, Mov { destination: Relative(1), source: Direct(32838) }, Mov { destination: Relative(2), source: Direct(32839) }, Mov { destination: Relative(3), source: Direct(32840) }, Call { location: 14 }, Call { location: 18 }, Const { destination: Relative(1), bit_size: Integer(U32), value: 32841 }, Const { destination: Relative(2), bit_size: Integer(U32), value: 0 }, Stop { return_data: HeapVector { pointer: Relative(1), size: Relative(2) } }, Const { destination: Direct(32835), bit_size: Integer(U32), value: 1 }, Const { destination: Direct(32836), bit_size: Integer(U32), value: 2 }, Const { destination: Direct(32837), bit_size: Integer(U32), value: 3 }, Return, Call { location: 391 }, Const { destination: Relative(4), bit_size: Field, value: 1 }, Const { destination: Relative(5), bit_size: Field, value: 17631683881184975370165255887551781615748388533673675138860 }, Const { destination: Relative(6), bit_size: Integer(U1), value: 0 }, Mov { destination: Relative(7), source: Direct(1) }, Const { destination: Relative(8), bit_size: Integer(U32), value: 4 }, BinaryIntOp { destination: Direct(1), op: Add, bit_size: U32, lhs: Direct(1), rhs: Relative(8) }, IndirectConst { destination_pointer: Relative(7), bit_size: Integer(U32), value: 1 }, BinaryIntOp { destination: Relative(8), op: Add, bit_size: U32, lhs: Relative(7), rhs: Direct(2) }, Mov { destination: Relative(9), source: Relative(8) }, Store { destination_pointer: Relative(9), source: Relative(4) }, BinaryIntOp { destination: Relative(9), op: Add, bit_size: U32, lhs: Relative(9), rhs: Direct(2) }, Store { destination_pointer: Relative(9), source: Relative(5) }, BinaryIntOp { destination: Relative(9), op: Add, bit_size: U32, lhs: Relative(9), rhs: Direct(2) }, Store { destination_pointer: Relative(9), source: Relative(6) }, Const { destination: Relative(8), bit_size: Field, value: 0 }, Mov { destination: Relative(9), source: Direct(1) }, Const { destination: Relative(10), bit_size: Integer(U32), value: 3 }, BinaryIntOp { destination: Direct(1), op: Add, bit_size: U32, lhs: Direct(1), rhs: Relative(10) }, IndirectConst { destination_pointer: Relative(9), bit_size: Integer(U32), value: 1 }, BinaryIntOp { destination: Relative(10), op: Add, bit_size: U32, lhs: Relative(9), rhs: Direct(2) }, Mov { destination: Relative(11), source: Relative(10) }, Store { destination_pointer: Relative(11), source: Relative(1) }, BinaryIntOp { destination: Relative(11), op: Add, bit_size: U32, lhs: Relative(11), rhs: Direct(2) }, Store { destination_pointer: Relative(11), source: Relative(8) }, Mov { destination: Relative(10), source: Direct(1) }, Const { destination: Relative(11), bit_size: Integer(U32), value: 4 }, BinaryIntOp { destination: Direct(1), op: Add, bit_size: U32, lhs: Direct(1), rhs: Relative(11) }, IndirectConst { destination_pointer: Relative(10), bit_size: Integer(U32), value: 1 }, BinaryIntOp { destination: Relative(11), op: Add, bit_size: U32, lhs: Relative(7), rhs: Direct(2) }, Const { destination: Relative(12), bit_size: Integer(U32), value: 3 }, BinaryIntOp { destination: Relative(13), op: Add, bit_size: U32, lhs: Relative(9), rhs: Direct(2) }, Const { destination: Relative(14), bit_size: Integer(U32), value: 2 }, BinaryIntOp { destination: Relative(15), op: Add, bit_size: U32, lhs: Relative(10), rhs: Direct(2) }, BlackBox(MultiScalarMul { points: HeapVector { pointer: Relative(11), size: Relative(12) }, scalars: HeapVector { pointer: Relative(13), size: Relative(14) }, outputs: HeapArray { pointer: Relative(15), size: 3 } }), BinaryIntOp { destination: Relative(9), op: Add, bit_size: U32, lhs: Relative(10), rhs: Direct(32835) }, Load { destination: Relative(7), source_pointer: Relative(9) }, BinaryIntOp { destination: Relative(11), op: Add, bit_size: U32, lhs: Relative(10), rhs: Direct(32836) }, Load { destination: Relative(9), source_pointer: Relative(11) }, BinaryFieldOp { destination: Relative(10), op: Equals, lhs: Relative(7), rhs: Relative(2) }, JumpIf { condition: Relative(10), location: 61 }, Const { destination: Relative(11), bit_size: Integer(U32), value: 0 }, Trap { revert_data: HeapVector { pointer: Direct(1), size: Relative(11) } }, BinaryFieldOp { destination: Relative(7), op: Equals, lhs: Relative(9), rhs: Relative(3) }, JumpIf { condition: Relative(7), location: 65 }, Const { destination: Relative(10), bit_size: Integer(U32), value: 0 }, Trap { revert_data: HeapVector { pointer: Direct(1), size: Relative(10) } }, Const { destination: Relative(11), bit_size: Integer(U32), value: 12 }, Mov { destination: Relative(12), source: Direct(0) }, Mov { destination: Relative(13), source: Relative(2) }, Mov { destination: Relative(14), source: Relative(3) }, Mov { destination: Relative(15), source: Relative(6) }, Mov { destination: Relative(16), source: Relative(2) }, Mov { destination: Relative(17), source: Relative(3) }, Mov { destination: Relative(18), source: Relative(6) }, BinaryIntOp { destination: Direct(0), op: Add, bit_size: U32, lhs: Direct(0), rhs: Relative(11) }, Call { location: 397 }, Mov { destination: Direct(0), source: Relative(0) }, Mov { destination: Relative(7), source: Relative(13) }, Mov { destination: Relative(9), source: Relative(14) }, Mov { destination: Relative(10), source: Relative(15) }, Const { destination: Relative(14), bit_size: Integer(U32), value: 15 }, Mov { destination: Relative(15), source: Direct(0) }, Mov { destination: Relative(16), source: Relative(4) }, Mov { destination: Relative(17), source: Relative(5) }, Mov { destination: Relative(18), source: Relative(6) }, Mov { destination: Relative(19), source: Relative(4) }, Mov { destination: Relative(20), source: Relative(5) }, Mov { destination: Relative(21), source: Relative(6) }, BinaryIntOp { destination: Direct(0), op: Add, bit_size: U32, lhs: Direct(0), rhs: Relative(14) }, Call { location: 397 }, Mov { destination: Direct(0), source: Relative(0) }, Mov { destination: Relative(11), source: Relative(16) }, Mov { destination: Relative(12), source: Relative(17) }, Mov { destination: Relative(13), source: Relative(18) }, BinaryFieldOp { destination: Relative(14), op: Equals, lhs: Relative(11), rhs: Relative(7) }, JumpIf { condition: Relative(14), location: 97 }, Const { destination: Relative(15), bit_size: Integer(U32), value: 0 }, Trap { revert_data: HeapVector { pointer: Direct(1), size: Relative(15) } }, Mov { destination: Relative(7), source: Direct(1) }, Const { destination: Relative(14), bit_size: Integer(U32), value: 7 }, BinaryIntOp { destination: Direct(1), op: Add, bit_size: U32, lhs: Direct(1), rhs: Relative(14) }, IndirectConst { destination_pointer: Relative(7), bit_size: Integer(U32), value: 1 }, BinaryIntOp { destination: Relative(14), op: Add, bit_size: U32, lhs: Relative(7), rhs: Direct(2) }, Mov { destination: Relative(15), source: Relative(14) }, Store { destination_pointer: Relative(15), source: Relative(4) }, BinaryIntOp { destination: Relative(15), op: Add, bit_size: U32, lhs: Relative(15), rhs: Direct(2) }, Store { destination_pointer: Relative(15), source: Relative(5) }, BinaryIntOp { destination: Relative(15), op: Add, bit_size: U32, lhs: Relative(15), rhs: Direct(2) }, Store { destination_pointer: Relative(15), source: Relative(6) }, BinaryIntOp { destination: Relative(15), op: Add, bit_size: U32, lhs: Relative(15), rhs: Direct(2) }, Store { destination_pointer: Relative(15), source: Relative(4) }, BinaryIntOp { destination: Relative(15), op: Add, bit_size: U32, lhs: Relative(15), rhs: Direct(2) }, Store { destination_pointer: Relative(15), source: Relative(5) }, BinaryIntOp { destination: Relative(15), op: Add, bit_size: U32, lhs: Relative(15), rhs: Direct(2) }, Store { destination_pointer: Relative(15), source: Relative(6) }, Mov { destination: Relative(14), source: Direct(1) }, Const { destination: Relative(15), bit_size: Integer(U32), value: 5 }, BinaryIntOp { destination: Direct(1), op: Add, bit_size: U32, lhs: Direct(1), rhs: Relative(15) }, IndirectConst { destination_pointer: Relative(14), bit_size: Integer(U32), value: 1 }, BinaryIntOp { destination: Relative(15), op: Add, bit_size: U32, lhs: Relative(14), rhs: Direct(2) }, Mov { destination: Relative(16), source: Relative(15) }, Store { destination_pointer: Relative(16), source: Relative(1) }, BinaryIntOp { destination: Relative(16), op: Add, bit_size: U32, lhs: Relative(16), rhs: Direct(2) }, Store { destination_pointer: Relative(16), source: Relative(8) }, BinaryIntOp { destination: Relative(16), op: Add, bit_size: U32, lhs: Relative(16), rhs: Direct(2) }, Store { destination_pointer: Relative(16), source: Relative(1) }, BinaryIntOp { destination: Relative(16), op: Add, bit_size: U32, lhs: Relative(16), rhs: Direct(2) }, Store { destination_pointer: Relative(16), source: Relative(8) }, Mov { destination: Relative(15), source: Direct(1) }, Const { destination: Relative(16), bit_size: Integer(U32), value: 4 }, BinaryIntOp { destination: Direct(1), op: Add, bit_size: U32, lhs: Direct(1), rhs: Relative(16) }, IndirectConst { destination_pointer: Relative(15), bit_size: Integer(U32), value: 1 }, BinaryIntOp { destination: Relative(16), op: Add, bit_size: U32, lhs: Relative(7), rhs: Direct(2) }, Const { destination: Relative(17), bit_size: Integer(U32), value: 6 }, BinaryIntOp { destination: Relative(18), op: Add, bit_size: U32, lhs: Relative(14), rhs: Direct(2) }, Const { destination: Relative(19), bit_size: Integer(U32), value: 4 }, BinaryIntOp { destination: Relative(20), op: Add, bit_size: U32, lhs: Relative(15), rhs: Direct(2) }, BlackBox(MultiScalarMul { points: HeapVector { pointer: Relative(16), size: Relative(17) }, scalars: HeapVector { pointer: Relative(18), size: Relative(19) }, outputs: HeapArray { pointer: Relative(20), size: 3 } }), BinaryIntOp { destination: Relative(14), op: Add, bit_size: U32, lhs: Relative(15), rhs: Direct(32835) }, Load { destination: Relative(7), source_pointer: Relative(14) }, BinaryFieldOp { destination: Relative(14), op: Equals, lhs: Relative(11), rhs: Relative(7) }, JumpIf { condition: Relative(14), location: 143 }, Const { destination: Relative(15), bit_size: Integer(U32), value: 0 }, Trap { revert_data: HeapVector { pointer: Direct(1), size: Relative(15) } }, Const { destination: Relative(7), bit_size: Field, value: 23 }, Mov { destination: Relative(14), source: Direct(1) }, Const { destination: Relative(15), bit_size: Integer(U32), value: 9 }, BinaryIntOp { destination: Direct(1), op: Add, bit_size: U32, lhs: Direct(1), rhs: Relative(15) }, IndirectConst { destination_pointer: Relative(14), bit_size: Integer(U32), value: 1 }, BinaryIntOp { destination: Relative(15), op: Add, bit_size: U32, lhs: Relative(14), rhs: Direct(2) }, Mov { destination: Relative(16), source: Relative(15) }, Store { destination_pointer: Relative(16), source: Relative(1) }, BinaryIntOp { destination: Relative(16), op: Add, bit_size: U32, lhs: Relative(16), rhs: Direct(2) }, Store { destination_pointer: Relative(16), source: Relative(8) }, BinaryIntOp { destination: Relative(16), op: Add, bit_size: U32, lhs: Relative(16), rhs: Direct(2) }, Store { destination_pointer: Relative(16), source: Relative(7) }, BinaryIntOp { destination: Relative(16), op: Add, bit_size: U32, lhs: Relative(16), rhs: Direct(2) }, Store { destination_pointer: Relative(16), source: Relative(8) }, BinaryIntOp { destination: Relative(16), op: Add, bit_size: U32, lhs: Relative(16), rhs: Direct(2) }, Store { destination_pointer: Relative(16), source: Relative(1) }, BinaryIntOp { destination: Relative(16), op: Add, bit_size: U32, lhs: Relative(16), rhs: Direct(2) }, Store { destination_pointer: Relative(16), source: Relative(8) }, BinaryIntOp { destination: Relative(16), op: Add, bit_size: U32, lhs: Relative(16), rhs: Direct(2) }, Store { destination_pointer: Relative(16), source: Relative(4) }, BinaryIntOp { destination: Relative(16), op: Add, bit_size: U32, lhs: Relative(16), rhs: Direct(2) }, Store { destination_pointer: Relative(16), source: Relative(8) }, Const { destination: Relative(7), bit_size: Field, value: 10456889356757736161582760391335869408742580538510966583040563008531594628700 }, Const { destination: Relative(15), bit_size: Field, value: 4714263418031017792755226781102360879566029698463912436805212494059649164343 }, Mov { destination: Relative(16), source: Direct(1) }, Const { destination: Relative(17), bit_size: Integer(U32), value: 13 }, BinaryIntOp { destination: Direct(1), op: Add, bit_size: U32, lhs: Direct(1), rhs: Relative(17) }, IndirectConst { destination_pointer: Relative(16), bit_size: Integer(U32), value: 1 }, BinaryIntOp { destination: Relative(17), op: Add, bit_size: U32, lhs: Relative(16), rhs: Direct(2) }, Mov { destination: Relative(18), source: Relative(17) }, Store { destination_pointer: Relative(18), source: Relative(4) }, BinaryIntOp { destination: Relative(18), op: Add, bit_size: U32, lhs: Relative(18), rhs: Direct(2) }, Store { destination_pointer: Relative(18), source: Relative(5) }, BinaryIntOp { destination: Relative(18), op: Add, bit_size: U32, lhs: Relative(18), rhs: Direct(2) }, Store { destination_pointer: Relative(18), source: Relative(6) }, BinaryIntOp { destination: Relative(18), op: Add, bit_size: U32, lhs: Relative(18), rhs: Direct(2) }, Store { destination_pointer: Relative(18), source: Relative(11) }, BinaryIntOp { destination: Relative(18), op: Add, bit_size: U32, lhs: Relative(18), rhs: Direct(2) }, Store { destination_pointer: Relative(18), source: Relative(12) }, BinaryIntOp { destination: Relative(18), op: Add, bit_size: U32, lhs: Relative(18), rhs: Direct(2) }, Store { destination_pointer: Relative(18), source: Relative(13) }, BinaryIntOp { destination: Relative(18), op: Add, bit_size: U32, lhs: Relative(18), rhs: Direct(2) }, Store { destination_pointer: Relative(18), source: Relative(2) }, BinaryIntOp { destination: Relative(18), op: Add, bit_size: U32, lhs: Relative(18), rhs: Direct(2) }, Store { destination_pointer: Relative(18), source: Relative(3) }, BinaryIntOp { destination: Relative(18), op: Add, bit_size: U32, lhs: Relative(18), rhs: Direct(2) }, Store { destination_pointer: Relative(18), source: Relative(6) }, BinaryIntOp { destination: Relative(18), op: Add, bit_size: U32, lhs: Relative(18), rhs: Direct(2) }, Store { destination_pointer: Relative(18), source: Relative(7) }, BinaryIntOp { destination: Relative(18), op: Add, bit_size: U32, lhs: Relative(18), rhs: Direct(2) }, Store { destination_pointer: Relative(18), source: Relative(15) }, BinaryIntOp { destination: Relative(18), op: Add, bit_size: U32, lhs: Relative(18), rhs: Direct(2) }, Store { destination_pointer: Relative(18), source: Relative(6) }, Mov { destination: Relative(7), source: Direct(1) }, Const { destination: Relative(11), bit_size: Integer(U32), value: 4 }, BinaryIntOp { destination: Direct(1), op: Add, bit_size: U32, lhs: Direct(1), rhs: Relative(11) }, IndirectConst { destination_pointer: Relative(7), bit_size: Integer(U32), value: 1 }, BinaryIntOp { destination: Relative(11), op: Add, bit_size: U32, lhs: Relative(16), rhs: Direct(2) }, Const { destination: Relative(12), bit_size: Integer(U32), value: 12 }, BinaryIntOp { destination: Relative(13), op: Add, bit_size: U32, lhs: Relative(14), rhs: Direct(2) }, Const { destination: Relative(15), bit_size: Integer(U32), value: 8 }, BinaryIntOp { destination: Relative(17), op: Add, bit_size: U32, lhs: Relative(7), rhs: Direct(2) }, BlackBox(MultiScalarMul { points: HeapVector { pointer: Relative(11), size: Relative(12) }, scalars: HeapVector { pointer: Relative(13), size: Relative(15) }, outputs: HeapArray { pointer: Relative(17), size: 3 } }), BinaryIntOp { destination: Relative(12), op: Add, bit_size: U32, lhs: Relative(7), rhs: Direct(32835) }, Load { destination: Relative(11), source_pointer: Relative(12) }, Const { destination: Relative(7), bit_size: Field, value: -7349266043899242844836273743257843180744506495159104166319746739537754653274 }, BinaryFieldOp { destination: Relative(12), op: Equals, lhs: Relative(11), rhs: Relative(7) }, JumpIf { condition: Relative(12), location: 213 }, Const { destination: Relative(13), bit_size: Integer(U32), value: 0 }, Trap { revert_data: HeapVector { pointer: Direct(1), size: Relative(13) } }, Mov { destination: Relative(7), source: Direct(1) }, Const { destination: Relative(11), bit_size: Integer(U32), value: 3 }, BinaryIntOp { destination: Direct(1), op: Add, bit_size: U32, lhs: Direct(1), rhs: Relative(11) }, IndirectConst { destination_pointer: Relative(7), bit_size: Integer(U32), value: 1 }, BinaryIntOp { destination: Relative(11), op: Add, bit_size: U32, lhs: Relative(7), rhs: Direct(2) }, Mov { destination: Relative(12), source: Relative(11) }, Store { destination_pointer: Relative(12), source: Relative(1) }, BinaryIntOp { destination: Relative(12), op: Add, bit_size: U32, lhs: Relative(12), rhs: Direct(2) }, Store { destination_pointer: Relative(12), source: Relative(8) }, Mov { destination: Relative(1), source: Direct(1) }, Const { destination: Relative(8), bit_size: Integer(U32), value: 4 }, BinaryIntOp { destination: Direct(1), op: Add, bit_size: U32, lhs: Direct(1), rhs: Relative(8) }, IndirectConst { destination_pointer: Relative(1), bit_size: Integer(U32), value: 1 }, BinaryIntOp { destination: Relative(8), op: Add, bit_size: U32, lhs: Relative(1), rhs: Direct(2) }, Mov { destination: Relative(11), source: Relative(8) }, Store { destination_pointer: Relative(11), source: Relative(4) }, BinaryIntOp { destination: Relative(11), op: Add, bit_size: U32, lhs: Relative(11), rhs: Direct(2) }, Store { destination_pointer: Relative(11), source: Relative(5) }, BinaryIntOp { destination: Relative(11), op: Add, bit_size: U32, lhs: Relative(11), rhs: Direct(2) }, Store { destination_pointer: Relative(11), source: Relative(6) }, Mov { destination: Relative(8), source: Direct(1) }, Const { destination: Relative(11), bit_size: Integer(U32), value: 4 }, BinaryIntOp { destination: Direct(1), op: Add, bit_size: U32, lhs: Direct(1), rhs: Relative(11) }, IndirectConst { destination_pointer: Relative(8), bit_size: Integer(U32), value: 1 }, BinaryIntOp { destination: Relative(11), op: Add, bit_size: U32, lhs: Relative(1), rhs: Direct(2) }, Const { destination: Relative(12), bit_size: Integer(U32), value: 3 }, BinaryIntOp { destination: Relative(13), op: Add, bit_size: U32, lhs: Relative(7), rhs: Direct(2) }, Const { destination: Relative(14), bit_size: Integer(U32), value: 2 }, BinaryIntOp { destination: Relative(15), op: Add, bit_size: U32, lhs: Relative(8), rhs: Direct(2) }, BlackBox(MultiScalarMul { points: HeapVector { pointer: Relative(11), size: Relative(12) }, scalars: HeapVector { pointer: Relative(13), size: Relative(14) }, outputs: HeapArray { pointer: Relative(15), size: 3 } }), BinaryIntOp { destination: Relative(7), op: Add, bit_size: U32, lhs: Relative(8), rhs: Direct(32835) }, Load { destination: Relative(1), source_pointer: Relative(7) }, BinaryIntOp { destination: Relative(11), op: Add, bit_size: U32, lhs: Relative(8), rhs: Direct(32836) }, Load { destination: Relative(7), source_pointer: Relative(11) }, BinaryIntOp { destination: Relative(12), op: Add, bit_size: U32, lhs: Relative(8), rhs: Direct(32837) }, Load { destination: Relative(11), source_pointer: Relative(12) }, BinaryIntOp { destination: Relative(8), op: Equals, bit_size: U1, lhs: Relative(11), rhs: Relative(6) }, JumpIf { condition: Relative(8), location: 253 }, Const { destination: Relative(12), bit_size: Integer(U32), value: 0 }, Trap { revert_data: HeapVector { pointer: Direct(1), size: Relative(12) } }, BinaryFieldOp { destination: Relative(8), op: Equals, lhs: Relative(1), rhs: Relative(4) }, JumpIf { condition: Relative(8), location: 257 }, Const { destination: Relative(11), bit_size: Integer(U32), value: 0 }, Trap { revert_data: HeapVector { pointer: Direct(1), size: Relative(11) } }, BinaryFieldOp { destination: Relative(1), op: Equals, lhs: Relative(7), rhs: Relative(5) }, JumpIf { condition: Relative(1), location: 261 }, Const { destination: Relative(8), bit_size: Integer(U32), value: 0 }, Trap { revert_data: HeapVector { pointer: Direct(1), size: Relative(8) } }, BinaryFieldOp { destination: Relative(1), op: Equals, lhs: Relative(2), rhs: Relative(3) }, JumpIf { condition: Relative(1), location: 264 }, Jump { location: 390 }, Const { destination: Relative(1), bit_size: Field, value: 2 }, Const { destination: Relative(9), bit_size: Integer(U32), value: 10 }, Mov { destination: Relative(10), source: Direct(0) }, Mov { destination: Relative(11), source: Relative(4) }, Mov { destination: Relative(12), source: Relative(1) }, Mov { destination: Relative(13), source: Relative(6) }, Mov { destination: Relative(14), source: Relative(4) }, Mov { destination: Relative(15), source: Relative(1) }, Mov { destination: Relative(16), source: Relative(6) }, BinaryIntOp { destination: Direct(0), op: Add, bit_size: U32, lhs: Direct(0), rhs: Relative(9) }, Call { location: 397 }, Mov { destination: Direct(0), source: Relative(0) }, Mov { destination: Relative(5), source: Relative(11) }, Mov { destination: Relative(7), source: Relative(12) }, Mov { destination: Relative(8), source: Relative(13) }, BinaryFieldOp { destination: Relative(9), op: Equals, lhs: Relative(5), rhs: Relative(4) }, JumpIf { condition: Relative(9), location: 283 }, Const { destination: Relative(10), bit_size: Integer(U32), value: 0 }, Trap { revert_data: HeapVector { pointer: Direct(1), size: Relative(10) } }, Const { destination: Relative(5), bit_size: Field, value: 3 }, Mov { destination: Relative(9), source: Direct(1) }, Const { destination: Relative(10), bit_size: Integer(U32), value: 4 }, BinaryIntOp { destination: Direct(1), op: Add, bit_size: U32, lhs: Direct(1), rhs: Relative(10) }, IndirectConst { destination_pointer: Relative(9), bit_size: Integer(U32), value: 1 }, BinaryIntOp { destination: Relative(10), op: Add, bit_size: U32, lhs: Relative(9), rhs: Direct(2) }, BlackBox(EmbeddedCurveAdd { input1_x: Relative(4), input1_y: Relative(1), input1_infinite: Relative(6), input2_x: Relative(4), input2_y: Relative(5), input2_infinite: Relative(6), result: HeapArray { pointer: Relative(10), size: 3 } }), BinaryIntOp { destination: Relative(11), op: Add, bit_size: U32, lhs: Relative(9), rhs: Direct(32835) }, Load { destination: Relative(10), source_pointer: Relative(11) }, BinaryFieldOp { destination: Relative(9), op: Equals, lhs: Relative(10), rhs: Relative(4) }, JumpIf { condition: Relative(9), location: 296 }, Const { destination: Relative(11), bit_size: Integer(U32), value: 0 }, Trap { revert_data: HeapVector { pointer: Direct(1), size: Relative(11) } }, BinaryFieldOp { destination: Relative(9), op: Add, lhs: Relative(2), rhs: Relative(4) }, BinaryFieldOp { destination: Relative(10), op: Add, lhs: Relative(3), rhs: Relative(4) }, Const { destination: Relative(14), bit_size: Integer(U32), value: 15 }, Mov { destination: Relative(15), source: Direct(0) }, Mov { destination: Relative(16), source: Relative(9) }, Mov { destination: Relative(17), source: Relative(3) }, Mov { destination: Relative(18), source: Relative(6) }, Mov { destination: Relative(19), source: Relative(9) }, Mov { destination: Relative(20), source: Relative(3) }, Mov { destination: Relative(21), source: Relative(6) }, BinaryIntOp { destination: Direct(0), op: Add, bit_size: U32, lhs: Direct(0), rhs: Relative(14) }, Call { location: 397 }, Mov { destination: Direct(0), source: Relative(0) }, Mov { destination: Relative(11), source: Relative(16) }, Mov { destination: Relative(12), source: Relative(17) }, Mov { destination: Relative(13), source: Relative(18) }, BinaryFieldOp { destination: Relative(14), op: Equals, lhs: Relative(11), rhs: Relative(4) }, JumpIf { condition: Relative(14), location: 316 }, Const { destination: Relative(15), bit_size: Integer(U32), value: 0 }, Trap { revert_data: HeapVector { pointer: Direct(1), size: Relative(15) } }, Mov { destination: Relative(11), source: Direct(1) }, Const { destination: Relative(14), bit_size: Integer(U32), value: 4 }, BinaryIntOp { destination: Direct(1), op: Add, bit_size: U32, lhs: Direct(1), rhs: Relative(14) }, IndirectConst { destination_pointer: Relative(11), bit_size: Integer(U32), value: 1 }, BinaryIntOp { destination: Relative(14), op: Add, bit_size: U32, lhs: Relative(11), rhs: Direct(2) }, BlackBox(EmbeddedCurveAdd { input1_x: Relative(9), input1_y: Relative(3), input1_infinite: Relative(6), input2_x: Relative(9), input2_y: Relative(10), input2_infinite: Relative(6), result: HeapArray { pointer: Relative(14), size: 3 } }), BinaryIntOp { destination: Relative(9), op: Add, bit_size: U32, lhs: Relative(11), rhs: Direct(32835) }, Load { destination: Relative(3), source_pointer: Relative(9) }, BinaryFieldOp { destination: Relative(9), op: Equals, lhs: Relative(3), rhs: Relative(4) }, JumpIf { condition: Relative(9), location: 328 }, Const { destination: Relative(11), bit_size: Integer(U32), value: 0 }, Trap { revert_data: HeapVector { pointer: Direct(1), size: Relative(11) } }, Mov { destination: Relative(3), source: Direct(1) }, Const { destination: Relative(9), bit_size: Integer(U32), value: 4 }, BinaryIntOp { destination: Direct(1), op: Add, bit_size: U32, lhs: Direct(1), rhs: Relative(9) }, IndirectConst { destination_pointer: Relative(3), bit_size: Integer(U32), value: 1 }, BinaryIntOp { destination: Relative(9), op: Add, bit_size: U32, lhs: Relative(3), rhs: Direct(2) }, BlackBox(EmbeddedCurveAdd { input1_x: Relative(1), input1_y: Relative(5), input1_infinite: Relative(6), input2_x: Relative(2), input2_y: Relative(10), input2_infinite: Relative(6), result: HeapArray { pointer: Relative(9), size: 3 } }), BinaryIntOp { destination: Relative(10), op: Add, bit_size: U32, lhs: Relative(3), rhs: Direct(32835) }, Load { destination: Relative(9), source_pointer: Relative(10) }, BinaryFieldOp { destination: Relative(3), op: Equals, lhs: Relative(9), rhs: Relative(4) }, JumpIf { condition: Relative(3), location: 340 }, Const { destination: Relative(10), bit_size: Integer(U32), value: 0 }, Trap { revert_data: HeapVector { pointer: Direct(1), size: Relative(10) } }, Const { destination: Relative(3), bit_size: Field, value: 4 }, Mov { destination: Relative(9), source: Direct(1) }, Const { destination: Relative(10), bit_size: Integer(U32), value: 4 }, BinaryIntOp { destination: Direct(1), op: Add, bit_size: U32, lhs: Direct(1), rhs: Relative(10) }, IndirectConst { destination_pointer: Relative(9), bit_size: Integer(U32), value: 1 }, BinaryIntOp { destination: Relative(10), op: Add, bit_size: U32, lhs: Relative(9), rhs: Direct(2) }, BlackBox(EmbeddedCurveAdd { input1_x: Relative(1), input1_y: Relative(5), input1_infinite: Relative(6), input2_x: Relative(1), input2_y: Relative(3), input2_infinite: Relative(6), result: HeapArray { pointer: Relative(10), size: 3 } }), BinaryIntOp { destination: Relative(10), op: Add, bit_size: U32, lhs: Relative(9), rhs: Direct(32835) }, Load { destination: Relative(3), source_pointer: Relative(10) }, BinaryFieldOp { destination: Relative(9), op: Equals, lhs: Relative(3), rhs: Relative(4) }, JumpIf { condition: Relative(9), location: 353 }, Const { destination: Relative(10), bit_size: Integer(U32), value: 0 }, Trap { revert_data: HeapVector { pointer: Direct(1), size: Relative(10) } }, Mov { destination: Relative(3), source: Direct(1) }, Const { destination: Relative(9), bit_size: Integer(U32), value: 4 }, BinaryIntOp { destination: Direct(1), op: Add, bit_size: U32, lhs: Direct(1), rhs: Relative(9) }, IndirectConst { destination_pointer: Relative(3), bit_size: Integer(U32), value: 1 }, BinaryIntOp { destination: Relative(9), op: Add, bit_size: U32, lhs: Relative(3), rhs: Direct(2) }, BlackBox(EmbeddedCurveAdd { input1_x: Relative(1), input1_y: Relative(5), input1_infinite: Relative(6), input2_x: Relative(1), input2_y: Relative(5), input2_infinite: Relative(6), result: HeapArray { pointer: Relative(9), size: 3 } }), BinaryIntOp { destination: Relative(10), op: Add, bit_size: U32, lhs: Relative(3), rhs: Direct(32835) }, Load { destination: Relative(9), source_pointer: Relative(10) }, BinaryFieldOp { destination: Relative(3), op: Equals, lhs: Relative(9), rhs: Relative(4) }, JumpIf { condition: Relative(3), location: 365 }, Const { destination: Relative(10), bit_size: Integer(U32), value: 0 }, Trap { revert_data: HeapVector { pointer: Direct(1), size: Relative(10) } }, Mov { destination: Relative(3), source: Direct(1) }, Const { destination: Relative(9), bit_size: Integer(U32), value: 4 }, BinaryIntOp { destination: Direct(1), op: Add, bit_size: U32, lhs: Direct(1), rhs: Relative(9) }, IndirectConst { destination_pointer: Relative(3), bit_size: Integer(U32), value: 1 }, BinaryIntOp { destination: Relative(9), op: Add, bit_size: U32, lhs: Relative(3), rhs: Direct(2) }, BlackBox(EmbeddedCurveAdd { input1_x: Relative(4), input1_y: Relative(5), input1_infinite: Relative(6), input2_x: Relative(4), input2_y: Relative(5), input2_infinite: Relative(6), result: HeapArray { pointer: Relative(9), size: 3 } }), BinaryIntOp { destination: Relative(10), op: Add, bit_size: U32, lhs: Relative(3), rhs: Direct(32835) }, Load { destination: Relative(9), source_pointer: Relative(10) }, BinaryFieldOp { destination: Relative(3), op: Equals, lhs: Relative(9), rhs: Relative(4) }, JumpIf { condition: Relative(3), location: 377 }, Const { destination: Relative(10), bit_size: Integer(U32), value: 0 }, Trap { revert_data: HeapVector { pointer: Direct(1), size: Relative(10) } }, Mov { destination: Relative(3), source: Direct(1) }, Const { destination: Relative(9), bit_size: Integer(U32), value: 4 }, BinaryIntOp { destination: Direct(1), op: Add, bit_size: U32, lhs: Direct(1), rhs: Relative(9) }, IndirectConst { destination_pointer: Relative(3), bit_size: Integer(U32), value: 1 }, BinaryIntOp { destination: Relative(9), op: Add, bit_size: U32, lhs: Relative(3), rhs: Direct(2) }, BlackBox(EmbeddedCurveAdd { input1_x: Relative(2), input1_y: Relative(5), input1_infinite: Relative(6), input2_x: Relative(2), input2_y: Relative(1), input2_infinite: Relative(6), result: HeapArray { pointer: Relative(9), size: 3 } }), BinaryIntOp { destination: Relative(2), op: Add, bit_size: U32, lhs: Relative(3), rhs: Direct(32835) }, Load { destination: Relative(1), source_pointer: Relative(2) }, BinaryFieldOp { destination: Relative(2), op: Equals, lhs: Relative(1), rhs: Relative(4) }, JumpIf { condition: Relative(2), location: 389 }, Const { destination: Relative(3), bit_size: Integer(U32), value: 0 }, Trap { revert_data: HeapVector { pointer: Direct(1), size: Relative(3) } }, Jump { location: 390 }, Return, Const { destination: Direct(32772), bit_size: Integer(U32), value: 30720 }, BinaryIntOp { destination: Direct(32771), op: LessThan, bit_size: U32, lhs: Direct(0), rhs: Direct(32772) }, JumpIf { condition: Direct(32771), location: 396 }, IndirectConst { destination_pointer: Direct(1), bit_size: Integer(U64), value: 17843811134343075018 }, Trap { revert_data: HeapVector { pointer: Direct(1), size: Direct(2) } }, Return, Call { location: 391 }, JumpIf { condition: Relative(3), location: 426 }, Jump { location: 400 }, JumpIf { condition: Relative(6), location: 418 }, Jump { location: 402 }, Mov { destination: Relative(13), source: Direct(1) }, Const { destination: Relative(14), bit_size: Integer(U32), value: 4 }, BinaryIntOp { destination: Direct(1), op: Add, bit_size: U32, lhs: Direct(1), rhs: Relative(14) }, IndirectConst { destination_pointer: Relative(13), bit_size: Integer(U32), value: 1 }, BinaryIntOp { destination: Relative(14), op: Add, bit_size: U32, lhs: Relative(13), rhs: Direct(2) }, BlackBox(EmbeddedCurveAdd { input1_x: Relative(1), input1_y: Relative(2), input1_infinite: Relative(3), input2_x: Relative(4), input2_y: Relative(5), input2_infinite: Relative(6), result: HeapArray { pointer: Relative(14), size: 3 } }), BinaryIntOp { destination: Relative(2), op: Add, bit_size: U32, lhs: Relative(13), rhs: Direct(32835) }, Load { destination: Relative(1), source_pointer: Relative(2) }, BinaryIntOp { destination: Relative(3), op: Add, bit_size: U32, lhs: Relative(13), rhs: Direct(32836) }, Load { destination: Relative(2), source_pointer: Relative(3) }, BinaryIntOp { destination: Relative(4), op: Add, bit_size: U32, lhs: Relative(13), rhs: Direct(32837) }, Load { destination: Relative(3), source_pointer: Relative(4) }, Mov { destination: Relative(10), source: Relative(1) }, Mov { destination: Relative(11), source: Relative(2) }, Mov { destination: Relative(12), source: Relative(3) }, Jump { location: 422 }, Mov { destination: Relative(10), source: Relative(1) }, Mov { destination: Relative(11), source: Relative(2) }, Mov { destination: Relative(12), source: Relative(3) }, Jump { location: 422 }, Mov { destination: Relative(7), source: Relative(10) }, Mov { destination: Relative(8), source: Relative(11) }, Mov { destination: Relative(9), source: Relative(12) }, Jump { location: 430 }, Mov { destination: Relative(7), source: Relative(4) }, Mov { destination: Relative(8), source: Relative(5) }, Mov { destination: Relative(9), source: Relative(6) }, Jump { location: 430 }, Mov { destination: Relative(1), source: Relative(7) }, Mov { destination: Relative(2), source: Relative(8) }, Mov { destination: Relative(3), source: Relative(9) }, Return]" ], - "debug_symbols": "tZfBThs7FED/ZdZZ2Nf2tc2vVBUKEKpIUUBp8qQnlH+vPdcnpYtB1VA2nBOCDxlPPON5m552D5cf9/vj88vP6e7b2/Rw2h8O+x/3h5fH7Xn/cmy/fZtc/+HrdOc3kziDN4ghGKIhGdSQDcVglWCVYJVglWCVYJVglWCVYJVglWCVaJVolWiV2CqhIRqSQQ3ZUAx1RnIGbxBDq8SGaEgGNbRKaiiGOkOdoVW0QQzBEA2tUhrUkA3FUGdkZ/AGMQRDNFglWyVbJVsl93lxm6m4QT8og2EwDqZBHcyDZXD06ujV0aujV3uvzXmNg2lQB/NgGaxG7xziEUECEpGEKJKRglD2lD1lT9lT9pQ9ZU/ZU/aUPWWhLJSFslAWykJZKM/rIHQpSB0yr4ZZPCJIQCKSEEV6OXYpSC+3b6OfV8gsHhGkl3OXiCREkYwUpA7pq8bEI4JQTpQT5UQ5UU6UE2WlrJSVslJWykpZKStlpayUM+VMOVPOlDPlTDlTzpQz5Uy5UC6UC+VCuVAulAvlQrlQLpQr5Uq5Uq6UK+VKuVKulCvlOsriHOIRQQISkYT0cumSkV6uXeqQeQ3O4hFBWlnm+0dEEqJIRgpSh/Q1aOIRQSgLZaEslIWyUBbKgXKgHCgHyoFyoBwoB8qBcqAcKUfKkXJfgyJdIpIQRTJSkF4O/T7rEI8IEpCIJESRjBSEslLu60JSl4gkRJGMFKR3tN/0HeIRQQLSy3q9biY2Hffn027X9xzvdiFtb/K6Pe2O5+nueDkcNtN/28Nl/qOfr9vjzPP21N5tt6Xd8amxBZ/3h1236+b3aLc8tJ3OMbidz9vw9NfjQz898/iQ69J4WR4fU40jEDX+PgCv6wphqfDRMVSOITpdMQdROAExxBXjNXIOVGVpfP5gfF9YNj75FcevJTC+LJ7Dujy+3XLzCLRbbFnxCfItkGXNDBbPGSzFL433n/8a+i/9HtZboO0R/YppaHuoWyGWxYn0+vmJ0K+ciLblun2hUnFrZqL0i7IVakyLFyb3+SuT+9KZqKncjiOnNRcXFyur29Xlw4gffIj2HHA7H22bH/9FJP8R+d5ebR/3pz8ewq+9dtpvHw678fL5cnx89+75/1fe4SH+9fTyuHu6nHa99O5Jvv38Jiob0fz92v/fLw==", + "debug_symbols": "tZndTls7EEbfJddcbHv821epqiqFUEWKAkrhSEeIdz8ze7wSzsVGZUNu+BalXmw7HsdDXjZ3u1/Pv3/uj/cPfzbfvr9sfp32h8P+98/Dw+32af9w1H992Uz2JfTNt3CziZNH8Ige4pE8skfxqB7Nwy3iFnGLuEXcIm4Rt4hbxC3iFnFLcktyS3JLUotoJI/sUTyqR/Poc+TJI3hED7UkjeSRPYqHWrJG8+hzlMlDLUUjeohH8lBL0yge1aN59Dnq5BE8ood4JA+3VLdUt1S3VFuX6WbTppFhZBwpI9PIPLKMrCPbyOHrw9eHrw9fN5+ueU8j88gyso5sI7tnmCYgABEQIAEZKEAFGoA5YA6YA+aAOWAOmAPmgDlgDpgj5og5Yo6YI+aIOWKe60AMGtAHzNUwQwAiIEACMlAAMyeDBphZd2OYK2SGAETAzNUgARkoQAUa0AdY1TgEIAKYM+aMOWPOmDPmjLlgLpgL5oK5YC6YC+aCuWAumCvmirlirpgr5oq5Yq6YK+aKuWFumBvmhrlhbpgb5oa5YW6YO+aOuWPumDvmjrlj7pg75j7McZqAAERAgARkwMzNoAJm7gZ9wFyDMwQgAmqO8/tHAjJQgAo0oA+wGnQIQAQwR8wRc8QcMUfMEbNgFsyCWTALZsEsmAWzYBbMCXPCnDBbDcZokIAMFKACDTCz2PvsBAQgAgIkIAMFqEADMBfMVoMxGZinGGSgABVoQB9gFecQgAgIgLlirpgr5orZKi7aPrSKcwhABMxsm80qziEDBahAA/oAqziZDAJgd4L58iJAAjJgNwx7dazixJbOKk6yQXcQqziHAERAgARkoAAVaADmgDlgtoqTYiBAAjJg5mZQgQb0AVZxDgEwczcQwG5Jk0EGClABNado0AdYxTkEIAICmFkMMmDmZFCBBvQBVnHJJmgV5xABARKQgQKYuRo0wMw2d6s4hwBEQM3ZZmoV55CBAlSgAXZ7nK+5E6DmbHO3dz0HARJgZpup1aBDBRrQB1gNOpjZ9obVoIOZbcpWgw4ZKICZbYJWgw59gNWgQwAiYGbbG1aDDmouNmWrQYcKNIdk5VCigQAJyEABKmDD7T5v5TCDlYNDACJgZnl9vdnQ4vx8Ou121uG86Xm0E3rcnnbHp8234/PhcLP5Z3t4nv/Tn8ftcc6n7Ul/qk+9O95pqvB+f9gZvd5cRk/LQ/VUGoP1WDoPz389Xl/PMT7FtjQ+Lo9PuScEJV0mEMo6gywZ3plDSuc55LxiDVLpjG+yYnzpvAY1hKXx9Z3xkecvOayYf7W3DP/9svga9uXxesGvQ6AX+rbmCazI/QnqmhVshRXoMi2ND5/fhuGq+1CbTWEdpzKtWAftws6GLIsrGcrnV6JcdSVyYkNo39XXrESrPIM2G2nxZJo+fzRN11wJbZCoLe2M0oqV0LaH9wdtfFYZJDML7TUWd1XM1zuitKOJ50fodc0kkvWJbkh58ZiN7Z09pSt5Puj0jytpcUt8QFLXrEYql7nUtmY1cjlvilzWFJh2TGdDTasMLZy3douLlw9JV9xWLb25/kyrJtF4BG3VFqtL6hdsq49IVm2rLpe5pLDmNhgj7z/ahi2+pHbf+vRqfESyZjW0a7zMZdW9Tjs2LobamMXF1chfsRr5yquR02UueU25aw9HrWnPtnhopf4Vq9GvvBotXuYiq3qGKXN8auu4uLuyfMFqfESyZjW00z3PRT/6WLMaItRa0j8nLK7GV5yi+cqnqHZAl7n0Vf3gdK61MvXFi2f5ilO0rD5Ff+h329v96X+f0r6a7bTf/jrsxrf3z8fbNz99+veRn/Ap7+Pp4XZ393zamenNR7369bv0cCO9/Hi13/cf", "file_map": { "16": { "source": "use crate::cmp::Eq;\nuse crate::hash::Hash;\nuse crate::ops::arith::{Add, Neg, Sub};\n\n/// A point on the embedded elliptic curve\n/// By definition, the base field of the embedded curve is the scalar field of the proof system curve, i.e the Noir Field.\n/// x and y denotes the Weierstrass coordinates of the point, if is_infinite is false.\npub struct EmbeddedCurvePoint {\n pub x: Field,\n pub y: Field,\n pub is_infinite: bool,\n}\n\nimpl EmbeddedCurvePoint {\n /// Elliptic curve point doubling operation\n /// returns the doubled point of a point P, i.e P+P\n pub fn double(self) -> EmbeddedCurvePoint {\n embedded_curve_add(self, self)\n }\n\n /// Returns the null element of the curve; 'the point at infinity'\n pub fn point_at_infinity() -> EmbeddedCurvePoint {\n EmbeddedCurvePoint { x: 0, y: 0, is_infinite: true }\n }\n\n /// Returns the curve's generator point.\n pub fn generator() -> EmbeddedCurvePoint {\n // Generator point for the grumpkin curve (y^2 = x^3 - 17)\n EmbeddedCurvePoint {\n x: 1,\n y: 17631683881184975370165255887551781615748388533673675138860, // sqrt(-16)\n is_infinite: false,\n }\n }\n}\n\nimpl Add for EmbeddedCurvePoint {\n /// Adds two points P+Q, using the curve addition formula, and also handles point at infinity\n fn add(self, other: EmbeddedCurvePoint) -> EmbeddedCurvePoint {\n embedded_curve_add(self, other)\n }\n}\n\nimpl Sub for EmbeddedCurvePoint {\n /// Points subtraction operation, using addition and negation\n fn sub(self, other: EmbeddedCurvePoint) -> EmbeddedCurvePoint {\n self + other.neg()\n }\n}\n\nimpl Neg for EmbeddedCurvePoint {\n /// Negates a point P, i.e returns -P, by negating the y coordinate.\n /// If the point is at infinity, then the result is also at infinity.\n fn neg(self) -> EmbeddedCurvePoint {\n EmbeddedCurvePoint { x: self.x, y: -self.y, is_infinite: self.is_infinite }\n }\n}\n\nimpl Eq for EmbeddedCurvePoint {\n /// Checks whether two points are equal\n fn eq(self: Self, b: EmbeddedCurvePoint) -> bool {\n (self.is_infinite & b.is_infinite)\n | ((self.is_infinite == b.is_infinite) & (self.x == b.x) & (self.y == b.y))\n }\n}\n\nimpl Hash for EmbeddedCurvePoint {\n fn hash(self, state: &mut H)\n where\n H: crate::hash::Hasher,\n {\n if self.is_infinite {\n self.is_infinite.hash(state);\n } else {\n self.x.hash(state);\n self.y.hash(state);\n }\n }\n}\n\n/// Scalar for the embedded curve represented as low and high limbs\n/// By definition, the scalar field of the embedded curve is base field of the proving system curve.\n/// It may not fit into a Field element, so it is represented with two Field elements; its low and high limbs.\npub struct EmbeddedCurveScalar {\n pub lo: Field,\n pub hi: Field,\n}\n\nimpl EmbeddedCurveScalar {\n pub fn new(lo: Field, hi: Field) -> Self {\n EmbeddedCurveScalar { lo, hi }\n }\n\n #[field(bn254)]\n pub fn from_field(scalar: Field) -> EmbeddedCurveScalar {\n let (a, b) = crate::field::bn254::decompose(scalar);\n EmbeddedCurveScalar { lo: a, hi: b }\n }\n\n //Bytes to scalar: take the first (after the specified offset) 16 bytes of the input as the lo value, and the next 16 bytes as the hi value\n #[field(bn254)]\n pub(crate) fn from_bytes(bytes: [u8; 64], offset: u32) -> EmbeddedCurveScalar {\n let mut v = 1;\n let mut lo = 0 as Field;\n let mut hi = 0 as Field;\n for i in 0..16 {\n lo = lo + (bytes[offset + 31 - i] as Field) * v;\n hi = hi + (bytes[offset + 15 - i] as Field) * v;\n v = v * 256;\n }\n let sig_s = crate::embedded_curve_ops::EmbeddedCurveScalar { lo, hi };\n sig_s\n }\n}\n\nimpl Eq for EmbeddedCurveScalar {\n fn eq(self, other: Self) -> bool {\n (other.hi == self.hi) & (other.lo == self.lo)\n }\n}\n\nimpl Hash for EmbeddedCurveScalar {\n fn hash(self, state: &mut H)\n where\n H: crate::hash::Hasher,\n {\n self.hi.hash(state);\n self.lo.hash(state);\n }\n}\n\n// Computes a multi scalar multiplication over the embedded curve.\n// For bn254, We have Grumpkin and Baby JubJub.\n// For bls12-381, we have JubJub and Bandersnatch.\n//\n// The embedded curve being used is decided by the\n// underlying proof system.\n// docs:start:multi_scalar_mul\npub fn multi_scalar_mul(\n points: [EmbeddedCurvePoint; N],\n scalars: [EmbeddedCurveScalar; N],\n) -> EmbeddedCurvePoint\n// docs:end:multi_scalar_mul\n{\n multi_scalar_mul_array_return(points, scalars)[0]\n}\n\n#[foreign(multi_scalar_mul)]\npub(crate) fn multi_scalar_mul_array_return(\n points: [EmbeddedCurvePoint; N],\n scalars: [EmbeddedCurveScalar; N],\n) -> [EmbeddedCurvePoint; 1] {}\n\n// docs:start:fixed_base_scalar_mul\npub fn fixed_base_scalar_mul(scalar: EmbeddedCurveScalar) -> EmbeddedCurvePoint\n// docs:end:fixed_base_scalar_mul\n{\n multi_scalar_mul([EmbeddedCurvePoint::generator()], [scalar])\n}\n\n/// This function only assumes that the points are on the curve\n/// It handles corner cases around the infinity point causing some overhead compared to embedded_curve_add_not_nul and embedded_curve_add_unsafe\n// docs:start:embedded_curve_add\npub fn embedded_curve_add(\n point1: EmbeddedCurvePoint,\n point2: EmbeddedCurvePoint,\n) -> EmbeddedCurvePoint {\n // docs:end:embedded_curve_add\n if crate::runtime::is_unconstrained() {\n // `embedded_curve_add_unsafe` requires the inputs not to be the infinity point, so we check it here.\n // This is because `embedded_curve_add_unsafe` uses the `embedded_curve_add` opcode.\n // For efficiency, the backend does not check the inputs for the infinity point, but it assumes that they are not the infinity point\n // so that it can apply the ec addition formula directly.\n if point1.is_infinite {\n point2\n } else if point2.is_infinite {\n point1\n } else {\n embedded_curve_add_unsafe(point1, point2)\n }\n } else {\n // In a constrained context, we also need to check the inputs are not the infinity point because we also use `embedded_curve_add_unsafe`\n // However we also need to identify the case where the two inputs are the same, because then\n // the addition formula does not work and we need to use the doubling formula instead.\n // In unconstrained context, we can check directly if the input values are the same when solving the opcode, so it is not an issue.\n\n // x_coordinates_match is true if both abscissae are the same\n let x_coordinates_match = point1.x == point2.x;\n // y_coordinates_match is true if both ordinates are the same\n let y_coordinates_match = point1.y == point2.y;\n // double_predicate is true if both abscissae and ordinates are the same\n let double_predicate = (x_coordinates_match & y_coordinates_match);\n // If the abscissae are the same, but not the ordinates, then one point is the opposite of the other\n let infinity_predicate = (x_coordinates_match & !y_coordinates_match);\n let point1_1 = EmbeddedCurvePoint {\n x: point1.x + (x_coordinates_match as Field),\n y: point1.y,\n is_infinite: false,\n };\n let point2_1 = EmbeddedCurvePoint { x: point2.x, y: point2.y, is_infinite: false };\n // point1_1 is guaranteed to have a different abscissa than point2:\n // - if x_coordinates_match is 0, that means point1.x != point2.x, and point1_1.x = point1.x + 0\n // - if x_coordinates_match is 1, that means point1.x = point2.x, but point1_1.x = point1.x + 1 in this case\n // Because the abscissa is different, the addition formula is guaranteed to succeed, so we can safely use `embedded_curve_add_unsafe`\n // Note that this computation may be garbage: if x_coordinates_match is 1, or if one of the input is the point at infinity.\n let mut result = embedded_curve_add_unsafe(point1_1, point2_1);\n\n // `embedded_curve_add_unsafe` is doing a doubling if the input is the same variable, because in this case it is guaranteed (at 'compile time') that the input is the same.\n let double = embedded_curve_add_unsafe(point1, point1);\n // `embedded_curve_add_unsafe` would not perform doubling, even if the inputs point1 and point2 are the same, because it cannot know this without adding some logic (and some constraints)\n // However we did this logic when we computed `double_predicate`, so we set the result to 2*point1 if point1 and point2 are the same\n result = if double_predicate { double } else { result };\n\n // Same logic as above for unconstrained context, we set the proper result when one of the inputs is the infinity point\n if point1.is_infinite {\n result = point2;\n }\n if point2.is_infinite {\n result = point1;\n }\n\n // Finally, we set the is_infinity flag of the result:\n // Opposite points should sum into the infinity point, however, if one of them is point at infinity, their coordinates are not meaningful\n // so we should not use the fact that the inputs are opposite in this case:\n let mut result_is_infinity =\n infinity_predicate & (!point1.is_infinite & !point2.is_infinite);\n // However, if both of them are at infinity, then the result is also at infinity\n result.is_infinite = result_is_infinity | (point1.is_infinite & point2.is_infinite);\n result\n }\n}\n\n#[foreign(embedded_curve_add)]\nfn embedded_curve_add_array_return(\n _point1: EmbeddedCurvePoint,\n _point2: EmbeddedCurvePoint,\n) -> [EmbeddedCurvePoint; 1] {}\n\n/// This function assumes that:\n/// The points are on the curve, and\n/// The points don't share an x-coordinate, and\n/// Neither point is the infinity point.\n/// If it is used with correct input, the function ensures the correct non-zero result is returned.\n/// Except for points on the curve, the other assumptions are checked by the function. It will cause assertion failure if they are not respected.\npub fn embedded_curve_add_not_nul(\n point1: EmbeddedCurvePoint,\n point2: EmbeddedCurvePoint,\n) -> EmbeddedCurvePoint {\n assert(point1.x != point2.x);\n assert(!point1.is_infinite);\n assert(!point2.is_infinite);\n // Ensure is_infinite is comptime\n let point1_1 = EmbeddedCurvePoint { x: point1.x, y: point1.y, is_infinite: false };\n let point2_1 = EmbeddedCurvePoint { x: point2.x, y: point2.y, is_infinite: false };\n embedded_curve_add_unsafe(point1_1, point2_1)\n}\n\n/// Unsafe ec addition\n/// If the inputs are the same, it will perform a doubling, but only if point1 and point2 are the same variable.\n/// If they have the same value but are different variables, the result will be incorrect because in this case\n/// it assumes (but does not check) that the points' x-coordinates are not equal.\n/// It also assumes neither point is the infinity point.\npub fn embedded_curve_add_unsafe(\n point1: EmbeddedCurvePoint,\n point2: EmbeddedCurvePoint,\n) -> EmbeddedCurvePoint {\n embedded_curve_add_array_return(point1, point2)[0]\n}\n", "path": "std/embedded_curve_ops.nr" }, "50": { - "source": "use std::ops::Add;\n\nfn main(priv_key: Field, pub_x: pub Field, pub_y: pub Field) {\n let g1 = std::embedded_curve_ops::EmbeddedCurvePoint::generator();\n let scalar = std::embedded_curve_ops::EmbeddedCurveScalar { lo: priv_key, hi: 0 };\n // Test that multi_scalar_mul correctly derives the public key\n let res = std::embedded_curve_ops::multi_scalar_mul([g1], [scalar]);\n assert(res.x == pub_x);\n assert(res.y == pub_y);\n\n // Test that double function calling embedded_curve_add works as expected\n let pub_point =\n std::embedded_curve_ops::EmbeddedCurvePoint { x: pub_x, y: pub_y, is_infinite: false };\n let res = pub_point.double();\n let double = g1.add(g1);\n\n assert(double.x == res.x);\n\n // Test calling multi_scalar_mul with multiple points and scalars\n let res = std::embedded_curve_ops::multi_scalar_mul([g1, g1], [scalar, scalar]);\n\n // The results should be double the g1 point because the scalars are 1 and we pass in g1 twice\n assert(double.x == res.x);\n\n // Tests for #6549\n let const_scalar1 = std::embedded_curve_ops::EmbeddedCurveScalar { lo: 23, hi: 0 };\n let const_scalar2 = std::embedded_curve_ops::EmbeddedCurveScalar { lo: 0, hi: 23 };\n let const_scalar3 = std::embedded_curve_ops::EmbeddedCurveScalar { lo: 13, hi: 4 };\n let partial_mul = std::embedded_curve_ops::multi_scalar_mul(\n [g1, double, pub_point, g1, g1],\n [scalar, const_scalar1, scalar, const_scalar2, const_scalar3],\n );\n assert(partial_mul.x == 0x2024c4eebfbc8a20018f8c95c7aab77c6f34f10cf785a6f04e97452d8708fda7);\n // Check simplification by zero\n let zero_point = std::embedded_curve_ops::EmbeddedCurvePoint { x: 0, y: 0, is_infinite: true };\n let const_zero = std::embedded_curve_ops::EmbeddedCurveScalar { lo: 0, hi: 0 };\n let partial_mul = std::embedded_curve_ops::multi_scalar_mul(\n [zero_point, double, g1],\n [scalar, const_zero, scalar],\n );\n assert(partial_mul == g1);\n}\n", + "source": "use std::{embedded_curve_ops::embedded_curve_add_unsafe, ops::Add};\n\nfn main(priv_key: Field, pub_x: pub Field, pub_y: pub Field) {\n let g1 = std::embedded_curve_ops::EmbeddedCurvePoint::generator();\n let scalar = std::embedded_curve_ops::EmbeddedCurveScalar { lo: priv_key, hi: 0 };\n // Test that multi_scalar_mul correctly derives the public key\n let res = std::embedded_curve_ops::multi_scalar_mul([g1], [scalar]);\n assert(res.x == pub_x);\n assert(res.y == pub_y);\n\n // Test that double function calling embedded_curve_add works as expected\n let pub_point =\n std::embedded_curve_ops::EmbeddedCurvePoint { x: pub_x, y: pub_y, is_infinite: false };\n let res = pub_point.double();\n let double = g1.add(g1);\n\n assert(double.x == res.x);\n\n // Test calling multi_scalar_mul with multiple points and scalars\n let res = std::embedded_curve_ops::multi_scalar_mul([g1, g1], [scalar, scalar]);\n\n // The results should be double the g1 point because the scalars are 1 and we pass in g1 twice\n assert(double.x == res.x);\n\n // Tests for #6549\n let const_scalar1 = std::embedded_curve_ops::EmbeddedCurveScalar { lo: 23, hi: 0 };\n let const_scalar2 = std::embedded_curve_ops::EmbeddedCurveScalar { lo: 0, hi: 23 };\n let const_scalar3 = std::embedded_curve_ops::EmbeddedCurveScalar { lo: 13, hi: 4 };\n let partial_mul = std::embedded_curve_ops::multi_scalar_mul(\n [g1, double, pub_point, g1, g1],\n [scalar, const_scalar1, scalar, const_scalar2, const_scalar3],\n );\n assert(partial_mul.x == 0x2024c4eebfbc8a20018f8c95c7aab77c6f34f10cf785a6f04e97452d8708fda7);\n // Check simplification by zero\n let zero_point = std::embedded_curve_ops::EmbeddedCurvePoint { x: 0, y: 0, is_infinite: true };\n let const_zero = std::embedded_curve_ops::EmbeddedCurveScalar { lo: 0, hi: 0 };\n let partial_mul = std::embedded_curve_ops::multi_scalar_mul(\n [zero_point, double, g1],\n [scalar, const_zero, scalar],\n );\n assert(partial_mul == g1);\n\n // Additional tests for validating embedded_curve_add_unsafe under a conditional\n if pub_x == pub_y {\n let a1 = std::embedded_curve_ops::EmbeddedCurvePoint { x: 1, y: 2, is_infinite: false };\n let a2 = std::embedded_curve_ops::EmbeddedCurvePoint { x: 1, y: 3, is_infinite: false };\n let doubling = a1.double();\n assert(doubling.x == 1);\n let res = embedded_curve_add_unsafe(a1, a2);\n assert(res.x == 1);\n\n let a1 = std::embedded_curve_ops::EmbeddedCurvePoint {\n x: pub_x + 1,\n y: pub_y,\n is_infinite: false,\n };\n let a2 = std::embedded_curve_ops::EmbeddedCurvePoint {\n x: pub_x + 1,\n y: pub_y + 1,\n is_infinite: false,\n };\n let doubling = a1.double();\n assert(doubling.x == 1);\n let res = embedded_curve_add_unsafe(a1, a2);\n assert(res.x == 1);\n\n let a1 = std::embedded_curve_ops::EmbeddedCurvePoint { x: 2, y: 3, is_infinite: false };\n let a2 = std::embedded_curve_ops::EmbeddedCurvePoint {\n x: pub_x,\n y: pub_y + 1 as Field,\n is_infinite: false,\n };\n let res = embedded_curve_add_unsafe(a1, a2);\n assert(res.x == 1);\n\n let a1 = std::embedded_curve_ops::EmbeddedCurvePoint { x: 2, y: 3, is_infinite: false };\n let a2 = std::embedded_curve_ops::EmbeddedCurvePoint { x: 2, y: 4, is_infinite: false };\n let res = embedded_curve_add_unsafe(a1, a2);\n assert(res.x == 1);\n\n let a1 = std::embedded_curve_ops::EmbeddedCurvePoint { x: 2, y: 3, is_infinite: false };\n let a2 = std::embedded_curve_ops::EmbeddedCurvePoint { x: 2, y: 3, is_infinite: false };\n let res = embedded_curve_add_unsafe(a1, a2);\n assert(res.x == 1);\n let a1 = std::embedded_curve_ops::EmbeddedCurvePoint { x: 1, y: 3, is_infinite: false };\n let a2 = std::embedded_curve_ops::EmbeddedCurvePoint { x: 1, y: 3, is_infinite: false };\n let res = embedded_curve_add_unsafe(a1, a2);\n assert(res.x == 1);\n let a1 = std::embedded_curve_ops::EmbeddedCurvePoint { x: pub_x, y: 3, is_infinite: false };\n let a2 = std::embedded_curve_ops::EmbeddedCurvePoint { x: pub_x, y: 2, is_infinite: false };\n let res = embedded_curve_add_unsafe(a1, a2);\n assert(res.x == 1);\n }\n}\n", "path": "" } }, diff --git a/tooling/nargo_cli/tests/snapshots/execution_success/embedded_curve_ops/execute__tests__force_brillig_true_inliner_0.snap b/tooling/nargo_cli/tests/snapshots/execution_success/embedded_curve_ops/execute__tests__force_brillig_true_inliner_0.snap index e1cc05ccb59..3ebd817e856 100644 --- a/tooling/nargo_cli/tests/snapshots/execution_success/embedded_curve_ops/execute__tests__force_brillig_true_inliner_0.snap +++ b/tooling/nargo_cli/tests/snapshots/execution_success/embedded_curve_ops/execute__tests__force_brillig_true_inliner_0.snap @@ -45,16 +45,16 @@ expression: artifact "return value indices : []", "BRILLIG CALL func 0: inputs: [Single(Expression { mul_terms: [], linear_combinations: [(1, Witness(0))], q_c: 0 }), Single(Expression { mul_terms: [], linear_combinations: [(1, Witness(1))], q_c: 0 }), Single(Expression { mul_terms: [], linear_combinations: [(1, Witness(2))], q_c: 0 })], outputs: []", "unconstrained func 0", - "[Const { destination: Direct(2), bit_size: Integer(U32), value: 1 }, Const { destination: Direct(1), bit_size: Integer(U32), value: 32839 }, Const { destination: Direct(0), bit_size: Integer(U32), value: 3 }, Const { destination: Relative(4), bit_size: Integer(U32), value: 3 }, Const { destination: Relative(5), bit_size: Integer(U32), value: 0 }, CalldataCopy { destination_address: Direct(32836), size_address: Relative(4), offset_address: Relative(5) }, Mov { destination: Relative(1), source: Direct(32836) }, Mov { destination: Relative(2), source: Direct(32837) }, Mov { destination: Relative(3), source: Direct(32838) }, Call { location: 14 }, Call { location: 15 }, Const { destination: Relative(1), bit_size: Integer(U32), value: 32839 }, Const { destination: Relative(2), bit_size: Integer(U32), value: 0 }, Stop { return_data: HeapVector { pointer: Relative(1), size: Relative(2) } }, Return, Call { location: 232 }, Const { destination: Relative(4), bit_size: Field, value: 1 }, Const { destination: Relative(5), bit_size: Field, value: 17631683881184975370165255887551781615748388533673675138860 }, Const { destination: Relative(6), bit_size: Integer(U1), value: 0 }, Mov { destination: Relative(7), source: Direct(1) }, Const { destination: Relative(8), bit_size: Integer(U32), value: 4 }, BinaryIntOp { destination: Direct(1), op: Add, bit_size: U32, lhs: Direct(1), rhs: Relative(8) }, IndirectConst { destination_pointer: Relative(7), bit_size: Integer(U32), value: 1 }, BinaryIntOp { destination: Relative(8), op: Add, bit_size: U32, lhs: Relative(7), rhs: Direct(2) }, Mov { destination: Relative(9), source: Relative(8) }, Store { destination_pointer: Relative(9), source: Relative(4) }, BinaryIntOp { destination: Relative(9), op: Add, bit_size: U32, lhs: Relative(9), rhs: Direct(2) }, Store { destination_pointer: Relative(9), source: Relative(5) }, BinaryIntOp { destination: Relative(9), op: Add, bit_size: U32, lhs: Relative(9), rhs: Direct(2) }, Store { destination_pointer: Relative(9), source: Relative(6) }, Const { destination: Relative(8), bit_size: Field, value: 0 }, Mov { destination: Relative(9), source: Direct(1) }, Const { destination: Relative(10), bit_size: Integer(U32), value: 3 }, BinaryIntOp { destination: Direct(1), op: Add, bit_size: U32, lhs: Direct(1), rhs: Relative(10) }, IndirectConst { destination_pointer: Relative(9), bit_size: Integer(U32), value: 1 }, BinaryIntOp { destination: Relative(10), op: Add, bit_size: U32, lhs: Relative(9), rhs: Direct(2) }, Mov { destination: Relative(11), source: Relative(10) }, Store { destination_pointer: Relative(11), source: Relative(1) }, BinaryIntOp { destination: Relative(11), op: Add, bit_size: U32, lhs: Relative(11), rhs: Direct(2) }, Store { destination_pointer: Relative(11), source: Relative(8) }, Mov { destination: Relative(10), source: Direct(1) }, Const { destination: Relative(11), bit_size: Integer(U32), value: 4 }, BinaryIntOp { destination: Direct(1), op: Add, bit_size: U32, lhs: Direct(1), rhs: Relative(11) }, IndirectConst { destination_pointer: Relative(10), bit_size: Integer(U32), value: 1 }, BinaryIntOp { destination: Relative(11), op: Add, bit_size: U32, lhs: Relative(7), rhs: Direct(2) }, Const { destination: Relative(12), bit_size: Integer(U32), value: 3 }, BinaryIntOp { destination: Relative(13), op: Add, bit_size: U32, lhs: Relative(9), rhs: Direct(2) }, Const { destination: Relative(14), bit_size: Integer(U32), value: 2 }, BinaryIntOp { destination: Relative(15), op: Add, bit_size: U32, lhs: Relative(10), rhs: Direct(2) }, BlackBox(MultiScalarMul { points: HeapVector { pointer: Relative(11), size: Relative(12) }, scalars: HeapVector { pointer: Relative(13), size: Relative(14) }, outputs: HeapArray { pointer: Relative(15), size: 3 } }), Const { destination: Relative(7), bit_size: Integer(U32), value: 1 }, BinaryIntOp { destination: Relative(11), op: Add, bit_size: U32, lhs: Relative(10), rhs: Relative(7) }, Load { destination: Relative(9), source_pointer: Relative(11) }, Const { destination: Relative(11), bit_size: Integer(U32), value: 2 }, BinaryIntOp { destination: Relative(13), op: Add, bit_size: U32, lhs: Relative(10), rhs: Relative(11) }, Load { destination: Relative(12), source_pointer: Relative(13) }, BinaryFieldOp { destination: Relative(10), op: Equals, lhs: Relative(9), rhs: Relative(2) }, JumpIf { condition: Relative(10), location: 60 }, Const { destination: Relative(13), bit_size: Integer(U32), value: 0 }, Trap { revert_data: HeapVector { pointer: Direct(1), size: Relative(13) } }, BinaryFieldOp { destination: Relative(9), op: Equals, lhs: Relative(12), rhs: Relative(3) }, JumpIf { condition: Relative(9), location: 64 }, Const { destination: Relative(10), bit_size: Integer(U32), value: 0 }, Trap { revert_data: HeapVector { pointer: Direct(1), size: Relative(10) } }, Mov { destination: Relative(9), source: Direct(1) }, Const { destination: Relative(10), bit_size: Integer(U32), value: 4 }, BinaryIntOp { destination: Direct(1), op: Add, bit_size: U32, lhs: Direct(1), rhs: Relative(10) }, IndirectConst { destination_pointer: Relative(9), bit_size: Integer(U32), value: 1 }, BinaryIntOp { destination: Relative(10), op: Add, bit_size: U32, lhs: Relative(9), rhs: Direct(2) }, BlackBox(EmbeddedCurveAdd { input1_x: Relative(2), input1_y: Relative(3), input1_infinite: Relative(6), input2_x: Relative(2), input2_y: Relative(3), input2_infinite: Relative(6), result: HeapArray { pointer: Relative(10), size: 3 } }), BinaryIntOp { destination: Relative(12), op: Add, bit_size: U32, lhs: Relative(9), rhs: Relative(7) }, Load { destination: Relative(10), source_pointer: Relative(12) }, Const { destination: Relative(9), bit_size: Field, value: 3078034153852398078128400807926804309327113743808504829582559963737223069694 }, BinaryFieldOp { destination: Relative(12), op: Equals, lhs: Relative(9), rhs: Relative(10) }, JumpIf { condition: Relative(12), location: 77 }, Const { destination: Relative(13), bit_size: Integer(U32), value: 0 }, Trap { revert_data: HeapVector { pointer: Direct(1), size: Relative(13) } }, Mov { destination: Relative(10), source: Direct(1) }, Const { destination: Relative(12), bit_size: Integer(U32), value: 7 }, BinaryIntOp { destination: Direct(1), op: Add, bit_size: U32, lhs: Direct(1), rhs: Relative(12) }, IndirectConst { destination_pointer: Relative(10), bit_size: Integer(U32), value: 1 }, BinaryIntOp { destination: Relative(12), op: Add, bit_size: U32, lhs: Relative(10), rhs: Direct(2) }, Mov { destination: Relative(13), source: Relative(12) }, Store { destination_pointer: Relative(13), source: Relative(4) }, BinaryIntOp { destination: Relative(13), op: Add, bit_size: U32, lhs: Relative(13), rhs: Direct(2) }, Store { destination_pointer: Relative(13), source: Relative(5) }, BinaryIntOp { destination: Relative(13), op: Add, bit_size: U32, lhs: Relative(13), rhs: Direct(2) }, Store { destination_pointer: Relative(13), source: Relative(6) }, BinaryIntOp { destination: Relative(13), op: Add, bit_size: U32, lhs: Relative(13), rhs: Direct(2) }, Store { destination_pointer: Relative(13), source: Relative(4) }, BinaryIntOp { destination: Relative(13), op: Add, bit_size: U32, lhs: Relative(13), rhs: Direct(2) }, Store { destination_pointer: Relative(13), source: Relative(5) }, BinaryIntOp { destination: Relative(13), op: Add, bit_size: U32, lhs: Relative(13), rhs: Direct(2) }, Store { destination_pointer: Relative(13), source: Relative(6) }, Mov { destination: Relative(12), source: Direct(1) }, Const { destination: Relative(13), bit_size: Integer(U32), value: 5 }, BinaryIntOp { destination: Direct(1), op: Add, bit_size: U32, lhs: Direct(1), rhs: Relative(13) }, IndirectConst { destination_pointer: Relative(12), bit_size: Integer(U32), value: 1 }, BinaryIntOp { destination: Relative(13), op: Add, bit_size: U32, lhs: Relative(12), rhs: Direct(2) }, Mov { destination: Relative(14), source: Relative(13) }, Store { destination_pointer: Relative(14), source: Relative(1) }, BinaryIntOp { destination: Relative(14), op: Add, bit_size: U32, lhs: Relative(14), rhs: Direct(2) }, Store { destination_pointer: Relative(14), source: Relative(8) }, BinaryIntOp { destination: Relative(14), op: Add, bit_size: U32, lhs: Relative(14), rhs: Direct(2) }, Store { destination_pointer: Relative(14), source: Relative(1) }, BinaryIntOp { destination: Relative(14), op: Add, bit_size: U32, lhs: Relative(14), rhs: Direct(2) }, Store { destination_pointer: Relative(14), source: Relative(8) }, Mov { destination: Relative(13), source: Direct(1) }, Const { destination: Relative(14), bit_size: Integer(U32), value: 4 }, BinaryIntOp { destination: Direct(1), op: Add, bit_size: U32, lhs: Direct(1), rhs: Relative(14) }, IndirectConst { destination_pointer: Relative(13), bit_size: Integer(U32), value: 1 }, BinaryIntOp { destination: Relative(14), op: Add, bit_size: U32, lhs: Relative(10), rhs: Direct(2) }, Const { destination: Relative(15), bit_size: Integer(U32), value: 6 }, BinaryIntOp { destination: Relative(16), op: Add, bit_size: U32, lhs: Relative(12), rhs: Direct(2) }, Const { destination: Relative(17), bit_size: Integer(U32), value: 4 }, BinaryIntOp { destination: Relative(18), op: Add, bit_size: U32, lhs: Relative(13), rhs: Direct(2) }, BlackBox(MultiScalarMul { points: HeapVector { pointer: Relative(14), size: Relative(15) }, scalars: HeapVector { pointer: Relative(16), size: Relative(17) }, outputs: HeapArray { pointer: Relative(18), size: 3 } }), BinaryIntOp { destination: Relative(12), op: Add, bit_size: U32, lhs: Relative(13), rhs: Relative(7) }, Load { destination: Relative(10), source_pointer: Relative(12) }, BinaryFieldOp { destination: Relative(12), op: Equals, lhs: Relative(9), rhs: Relative(10) }, JumpIf { condition: Relative(12), location: 123 }, Const { destination: Relative(13), bit_size: Integer(U32), value: 0 }, Trap { revert_data: HeapVector { pointer: Direct(1), size: Relative(13) } }, Mov { destination: Relative(9), source: Direct(1) }, Const { destination: Relative(10), bit_size: Integer(U32), value: 7 }, BinaryIntOp { destination: Direct(1), op: Add, bit_size: U32, lhs: Direct(1), rhs: Relative(10) }, IndirectConst { destination_pointer: Relative(9), bit_size: Integer(U32), value: 1 }, BinaryIntOp { destination: Relative(10), op: Add, bit_size: U32, lhs: Relative(9), rhs: Direct(2) }, Mov { destination: Relative(12), source: Relative(10) }, Store { destination_pointer: Relative(12), source: Relative(1) }, BinaryIntOp { destination: Relative(12), op: Add, bit_size: U32, lhs: Relative(12), rhs: Direct(2) }, Store { destination_pointer: Relative(12), source: Relative(8) }, BinaryIntOp { destination: Relative(12), op: Add, bit_size: U32, lhs: Relative(12), rhs: Direct(2) }, Store { destination_pointer: Relative(12), source: Relative(1) }, BinaryIntOp { destination: Relative(12), op: Add, bit_size: U32, lhs: Relative(12), rhs: Direct(2) }, Store { destination_pointer: Relative(12), source: Relative(8) }, BinaryIntOp { destination: Relative(12), op: Add, bit_size: U32, lhs: Relative(12), rhs: Direct(2) }, Store { destination_pointer: Relative(12), source: Relative(4) }, BinaryIntOp { destination: Relative(12), op: Add, bit_size: U32, lhs: Relative(12), rhs: Direct(2) }, Store { destination_pointer: Relative(12), source: Relative(8) }, Const { destination: Relative(10), bit_size: Field, value: 11179562631109628533987091031692370366552561688588090155835439555627259799605 }, Const { destination: Relative(12), bit_size: Field, value: 3443719903172018228650470536370404288991794296383447657609081676265727805364 }, Mov { destination: Relative(13), source: Direct(1) }, Const { destination: Relative(14), bit_size: Integer(U32), value: 10 }, BinaryIntOp { destination: Direct(1), op: Add, bit_size: U32, lhs: Direct(1), rhs: Relative(14) }, IndirectConst { destination_pointer: Relative(13), bit_size: Integer(U32), value: 1 }, BinaryIntOp { destination: Relative(14), op: Add, bit_size: U32, lhs: Relative(13), rhs: Direct(2) }, Mov { destination: Relative(15), source: Relative(14) }, Store { destination_pointer: Relative(15), source: Relative(4) }, BinaryIntOp { destination: Relative(15), op: Add, bit_size: U32, lhs: Relative(15), rhs: Direct(2) }, Store { destination_pointer: Relative(15), source: Relative(5) }, BinaryIntOp { destination: Relative(15), op: Add, bit_size: U32, lhs: Relative(15), rhs: Direct(2) }, Store { destination_pointer: Relative(15), source: Relative(6) }, BinaryIntOp { destination: Relative(15), op: Add, bit_size: U32, lhs: Relative(15), rhs: Direct(2) }, Store { destination_pointer: Relative(15), source: Relative(2) }, BinaryIntOp { destination: Relative(15), op: Add, bit_size: U32, lhs: Relative(15), rhs: Direct(2) }, Store { destination_pointer: Relative(15), source: Relative(3) }, BinaryIntOp { destination: Relative(15), op: Add, bit_size: U32, lhs: Relative(15), rhs: Direct(2) }, Store { destination_pointer: Relative(15), source: Relative(6) }, BinaryIntOp { destination: Relative(15), op: Add, bit_size: U32, lhs: Relative(15), rhs: Direct(2) }, Store { destination_pointer: Relative(15), source: Relative(10) }, BinaryIntOp { destination: Relative(15), op: Add, bit_size: U32, lhs: Relative(15), rhs: Direct(2) }, Store { destination_pointer: Relative(15), source: Relative(12) }, BinaryIntOp { destination: Relative(15), op: Add, bit_size: U32, lhs: Relative(15), rhs: Direct(2) }, Store { destination_pointer: Relative(15), source: Relative(6) }, Mov { destination: Relative(2), source: Direct(1) }, Const { destination: Relative(3), bit_size: Integer(U32), value: 4 }, BinaryIntOp { destination: Direct(1), op: Add, bit_size: U32, lhs: Direct(1), rhs: Relative(3) }, IndirectConst { destination_pointer: Relative(2), bit_size: Integer(U32), value: 1 }, BinaryIntOp { destination: Relative(3), op: Add, bit_size: U32, lhs: Relative(13), rhs: Direct(2) }, Const { destination: Relative(10), bit_size: Integer(U32), value: 9 }, BinaryIntOp { destination: Relative(12), op: Add, bit_size: U32, lhs: Relative(9), rhs: Direct(2) }, Const { destination: Relative(14), bit_size: Integer(U32), value: 6 }, BinaryIntOp { destination: Relative(15), op: Add, bit_size: U32, lhs: Relative(2), rhs: Direct(2) }, BlackBox(MultiScalarMul { points: HeapVector { pointer: Relative(3), size: Relative(10) }, scalars: HeapVector { pointer: Relative(12), size: Relative(14) }, outputs: HeapArray { pointer: Relative(15), size: 3 } }), BinaryIntOp { destination: Relative(9), op: Add, bit_size: U32, lhs: Relative(2), rhs: Relative(7) }, Load { destination: Relative(3), source_pointer: Relative(9) }, Const { destination: Relative(2), bit_size: Field, value: -7349266043899242844836273743257843180744506495159104166319746739537754653274 }, BinaryFieldOp { destination: Relative(9), op: Equals, lhs: Relative(3), rhs: Relative(2) }, JumpIf { condition: Relative(9), location: 182 }, Const { destination: Relative(10), bit_size: Integer(U32), value: 0 }, Trap { revert_data: HeapVector { pointer: Direct(1), size: Relative(10) } }, Mov { destination: Relative(2), source: Direct(1) }, Const { destination: Relative(3), bit_size: Integer(U32), value: 3 }, BinaryIntOp { destination: Direct(1), op: Add, bit_size: U32, lhs: Direct(1), rhs: Relative(3) }, IndirectConst { destination_pointer: Relative(2), bit_size: Integer(U32), value: 1 }, BinaryIntOp { destination: Relative(3), op: Add, bit_size: U32, lhs: Relative(2), rhs: Direct(2) }, Mov { destination: Relative(9), source: Relative(3) }, Store { destination_pointer: Relative(9), source: Relative(1) }, BinaryIntOp { destination: Relative(9), op: Add, bit_size: U32, lhs: Relative(9), rhs: Direct(2) }, Store { destination_pointer: Relative(9), source: Relative(8) }, Mov { destination: Relative(1), source: Direct(1) }, Const { destination: Relative(3), bit_size: Integer(U32), value: 4 }, BinaryIntOp { destination: Direct(1), op: Add, bit_size: U32, lhs: Direct(1), rhs: Relative(3) }, IndirectConst { destination_pointer: Relative(1), bit_size: Integer(U32), value: 1 }, BinaryIntOp { destination: Relative(3), op: Add, bit_size: U32, lhs: Relative(1), rhs: Direct(2) }, Mov { destination: Relative(8), source: Relative(3) }, Store { destination_pointer: Relative(8), source: Relative(4) }, BinaryIntOp { destination: Relative(8), op: Add, bit_size: U32, lhs: Relative(8), rhs: Direct(2) }, Store { destination_pointer: Relative(8), source: Relative(5) }, BinaryIntOp { destination: Relative(8), op: Add, bit_size: U32, lhs: Relative(8), rhs: Direct(2) }, Store { destination_pointer: Relative(8), source: Relative(6) }, Mov { destination: Relative(3), source: Direct(1) }, Const { destination: Relative(8), bit_size: Integer(U32), value: 4 }, BinaryIntOp { destination: Direct(1), op: Add, bit_size: U32, lhs: Direct(1), rhs: Relative(8) }, IndirectConst { destination_pointer: Relative(3), bit_size: Integer(U32), value: 1 }, BinaryIntOp { destination: Relative(8), op: Add, bit_size: U32, lhs: Relative(1), rhs: Direct(2) }, Const { destination: Relative(9), bit_size: Integer(U32), value: 3 }, BinaryIntOp { destination: Relative(10), op: Add, bit_size: U32, lhs: Relative(2), rhs: Direct(2) }, Const { destination: Relative(12), bit_size: Integer(U32), value: 2 }, BinaryIntOp { destination: Relative(13), op: Add, bit_size: U32, lhs: Relative(3), rhs: Direct(2) }, BlackBox(MultiScalarMul { points: HeapVector { pointer: Relative(8), size: Relative(9) }, scalars: HeapVector { pointer: Relative(10), size: Relative(12) }, outputs: HeapArray { pointer: Relative(13), size: 3 } }), BinaryIntOp { destination: Relative(2), op: Add, bit_size: U32, lhs: Relative(3), rhs: Relative(7) }, Load { destination: Relative(1), source_pointer: Relative(2) }, BinaryIntOp { destination: Relative(7), op: Add, bit_size: U32, lhs: Relative(3), rhs: Relative(11) }, Load { destination: Relative(2), source_pointer: Relative(7) }, Const { destination: Relative(7), bit_size: Integer(U32), value: 3 }, BinaryIntOp { destination: Relative(9), op: Add, bit_size: U32, lhs: Relative(3), rhs: Relative(7) }, Load { destination: Relative(8), source_pointer: Relative(9) }, BinaryIntOp { destination: Relative(3), op: Equals, bit_size: U1, lhs: Relative(8), rhs: Relative(6) }, JumpIf { condition: Relative(3), location: 223 }, Const { destination: Relative(7), bit_size: Integer(U32), value: 0 }, Trap { revert_data: HeapVector { pointer: Direct(1), size: Relative(7) } }, BinaryFieldOp { destination: Relative(3), op: Equals, lhs: Relative(1), rhs: Relative(4) }, JumpIf { condition: Relative(3), location: 227 }, Const { destination: Relative(6), bit_size: Integer(U32), value: 0 }, Trap { revert_data: HeapVector { pointer: Direct(1), size: Relative(6) } }, BinaryFieldOp { destination: Relative(1), op: Equals, lhs: Relative(2), rhs: Relative(5) }, JumpIf { condition: Relative(1), location: 231 }, Const { destination: Relative(3), bit_size: Integer(U32), value: 0 }, Trap { revert_data: HeapVector { pointer: Direct(1), size: Relative(3) } }, Return, Const { destination: Direct(32772), bit_size: Integer(U32), value: 30720 }, BinaryIntOp { destination: Direct(32771), op: LessThan, bit_size: U32, lhs: Direct(0), rhs: Direct(32772) }, JumpIf { condition: Direct(32771), location: 237 }, IndirectConst { destination_pointer: Direct(1), bit_size: Integer(U64), value: 17843811134343075018 }, Trap { revert_data: HeapVector { pointer: Direct(1), size: Direct(2) } }, Return]" + "[Const { destination: Direct(2), bit_size: Integer(U32), value: 1 }, Const { destination: Direct(1), bit_size: Integer(U32), value: 32839 }, Const { destination: Direct(0), bit_size: Integer(U32), value: 3 }, Const { destination: Relative(4), bit_size: Integer(U32), value: 3 }, Const { destination: Relative(5), bit_size: Integer(U32), value: 0 }, CalldataCopy { destination_address: Direct(32836), size_address: Relative(4), offset_address: Relative(5) }, Mov { destination: Relative(1), source: Direct(32836) }, Mov { destination: Relative(2), source: Direct(32837) }, Mov { destination: Relative(3), source: Direct(32838) }, Call { location: 14 }, Call { location: 15 }, Const { destination: Relative(1), bit_size: Integer(U32), value: 32839 }, Const { destination: Relative(2), bit_size: Integer(U32), value: 0 }, Stop { return_data: HeapVector { pointer: Relative(1), size: Relative(2) } }, Return, Call { location: 349 }, Const { destination: Relative(4), bit_size: Field, value: 1 }, Const { destination: Relative(5), bit_size: Field, value: 17631683881184975370165255887551781615748388533673675138860 }, Const { destination: Relative(6), bit_size: Integer(U1), value: 0 }, Mov { destination: Relative(7), source: Direct(1) }, Const { destination: Relative(8), bit_size: Integer(U32), value: 4 }, BinaryIntOp { destination: Direct(1), op: Add, bit_size: U32, lhs: Direct(1), rhs: Relative(8) }, IndirectConst { destination_pointer: Relative(7), bit_size: Integer(U32), value: 1 }, BinaryIntOp { destination: Relative(8), op: Add, bit_size: U32, lhs: Relative(7), rhs: Direct(2) }, Mov { destination: Relative(9), source: Relative(8) }, Store { destination_pointer: Relative(9), source: Relative(4) }, BinaryIntOp { destination: Relative(9), op: Add, bit_size: U32, lhs: Relative(9), rhs: Direct(2) }, Store { destination_pointer: Relative(9), source: Relative(5) }, BinaryIntOp { destination: Relative(9), op: Add, bit_size: U32, lhs: Relative(9), rhs: Direct(2) }, Store { destination_pointer: Relative(9), source: Relative(6) }, Const { destination: Relative(8), bit_size: Field, value: 0 }, Mov { destination: Relative(9), source: Direct(1) }, Const { destination: Relative(10), bit_size: Integer(U32), value: 3 }, BinaryIntOp { destination: Direct(1), op: Add, bit_size: U32, lhs: Direct(1), rhs: Relative(10) }, IndirectConst { destination_pointer: Relative(9), bit_size: Integer(U32), value: 1 }, BinaryIntOp { destination: Relative(10), op: Add, bit_size: U32, lhs: Relative(9), rhs: Direct(2) }, Mov { destination: Relative(11), source: Relative(10) }, Store { destination_pointer: Relative(11), source: Relative(1) }, BinaryIntOp { destination: Relative(11), op: Add, bit_size: U32, lhs: Relative(11), rhs: Direct(2) }, Store { destination_pointer: Relative(11), source: Relative(8) }, Mov { destination: Relative(10), source: Direct(1) }, Const { destination: Relative(11), bit_size: Integer(U32), value: 4 }, BinaryIntOp { destination: Direct(1), op: Add, bit_size: U32, lhs: Direct(1), rhs: Relative(11) }, IndirectConst { destination_pointer: Relative(10), bit_size: Integer(U32), value: 1 }, BinaryIntOp { destination: Relative(11), op: Add, bit_size: U32, lhs: Relative(7), rhs: Direct(2) }, Const { destination: Relative(12), bit_size: Integer(U32), value: 3 }, BinaryIntOp { destination: Relative(13), op: Add, bit_size: U32, lhs: Relative(9), rhs: Direct(2) }, Const { destination: Relative(14), bit_size: Integer(U32), value: 2 }, BinaryIntOp { destination: Relative(15), op: Add, bit_size: U32, lhs: Relative(10), rhs: Direct(2) }, BlackBox(MultiScalarMul { points: HeapVector { pointer: Relative(11), size: Relative(12) }, scalars: HeapVector { pointer: Relative(13), size: Relative(14) }, outputs: HeapArray { pointer: Relative(15), size: 3 } }), Const { destination: Relative(7), bit_size: Integer(U32), value: 1 }, BinaryIntOp { destination: Relative(11), op: Add, bit_size: U32, lhs: Relative(10), rhs: Relative(7) }, Load { destination: Relative(9), source_pointer: Relative(11) }, Const { destination: Relative(11), bit_size: Integer(U32), value: 2 }, BinaryIntOp { destination: Relative(13), op: Add, bit_size: U32, lhs: Relative(10), rhs: Relative(11) }, Load { destination: Relative(12), source_pointer: Relative(13) }, BinaryFieldOp { destination: Relative(10), op: Equals, lhs: Relative(9), rhs: Relative(2) }, JumpIf { condition: Relative(10), location: 60 }, Const { destination: Relative(13), bit_size: Integer(U32), value: 0 }, Trap { revert_data: HeapVector { pointer: Direct(1), size: Relative(13) } }, BinaryFieldOp { destination: Relative(9), op: Equals, lhs: Relative(12), rhs: Relative(3) }, JumpIf { condition: Relative(9), location: 64 }, Const { destination: Relative(10), bit_size: Integer(U32), value: 0 }, Trap { revert_data: HeapVector { pointer: Direct(1), size: Relative(10) } }, Mov { destination: Relative(9), source: Direct(1) }, Const { destination: Relative(10), bit_size: Integer(U32), value: 4 }, BinaryIntOp { destination: Direct(1), op: Add, bit_size: U32, lhs: Direct(1), rhs: Relative(10) }, IndirectConst { destination_pointer: Relative(9), bit_size: Integer(U32), value: 1 }, BinaryIntOp { destination: Relative(10), op: Add, bit_size: U32, lhs: Relative(9), rhs: Direct(2) }, BlackBox(EmbeddedCurveAdd { input1_x: Relative(2), input1_y: Relative(3), input1_infinite: Relative(6), input2_x: Relative(2), input2_y: Relative(3), input2_infinite: Relative(6), result: HeapArray { pointer: Relative(10), size: 3 } }), BinaryIntOp { destination: Relative(12), op: Add, bit_size: U32, lhs: Relative(9), rhs: Relative(7) }, Load { destination: Relative(10), source_pointer: Relative(12) }, Const { destination: Relative(9), bit_size: Field, value: 3078034153852398078128400807926804309327113743808504829582559963737223069694 }, BinaryFieldOp { destination: Relative(12), op: Equals, lhs: Relative(9), rhs: Relative(10) }, JumpIf { condition: Relative(12), location: 77 }, Const { destination: Relative(13), bit_size: Integer(U32), value: 0 }, Trap { revert_data: HeapVector { pointer: Direct(1), size: Relative(13) } }, Mov { destination: Relative(10), source: Direct(1) }, Const { destination: Relative(12), bit_size: Integer(U32), value: 7 }, BinaryIntOp { destination: Direct(1), op: Add, bit_size: U32, lhs: Direct(1), rhs: Relative(12) }, IndirectConst { destination_pointer: Relative(10), bit_size: Integer(U32), value: 1 }, BinaryIntOp { destination: Relative(12), op: Add, bit_size: U32, lhs: Relative(10), rhs: Direct(2) }, Mov { destination: Relative(13), source: Relative(12) }, Store { destination_pointer: Relative(13), source: Relative(4) }, BinaryIntOp { destination: Relative(13), op: Add, bit_size: U32, lhs: Relative(13), rhs: Direct(2) }, Store { destination_pointer: Relative(13), source: Relative(5) }, BinaryIntOp { destination: Relative(13), op: Add, bit_size: U32, lhs: Relative(13), rhs: Direct(2) }, Store { destination_pointer: Relative(13), source: Relative(6) }, BinaryIntOp { destination: Relative(13), op: Add, bit_size: U32, lhs: Relative(13), rhs: Direct(2) }, Store { destination_pointer: Relative(13), source: Relative(4) }, BinaryIntOp { destination: Relative(13), op: Add, bit_size: U32, lhs: Relative(13), rhs: Direct(2) }, Store { destination_pointer: Relative(13), source: Relative(5) }, BinaryIntOp { destination: Relative(13), op: Add, bit_size: U32, lhs: Relative(13), rhs: Direct(2) }, Store { destination_pointer: Relative(13), source: Relative(6) }, Mov { destination: Relative(12), source: Direct(1) }, Const { destination: Relative(13), bit_size: Integer(U32), value: 5 }, BinaryIntOp { destination: Direct(1), op: Add, bit_size: U32, lhs: Direct(1), rhs: Relative(13) }, IndirectConst { destination_pointer: Relative(12), bit_size: Integer(U32), value: 1 }, BinaryIntOp { destination: Relative(13), op: Add, bit_size: U32, lhs: Relative(12), rhs: Direct(2) }, Mov { destination: Relative(14), source: Relative(13) }, Store { destination_pointer: Relative(14), source: Relative(1) }, BinaryIntOp { destination: Relative(14), op: Add, bit_size: U32, lhs: Relative(14), rhs: Direct(2) }, Store { destination_pointer: Relative(14), source: Relative(8) }, BinaryIntOp { destination: Relative(14), op: Add, bit_size: U32, lhs: Relative(14), rhs: Direct(2) }, Store { destination_pointer: Relative(14), source: Relative(1) }, BinaryIntOp { destination: Relative(14), op: Add, bit_size: U32, lhs: Relative(14), rhs: Direct(2) }, Store { destination_pointer: Relative(14), source: Relative(8) }, Mov { destination: Relative(13), source: Direct(1) }, Const { destination: Relative(14), bit_size: Integer(U32), value: 4 }, BinaryIntOp { destination: Direct(1), op: Add, bit_size: U32, lhs: Direct(1), rhs: Relative(14) }, IndirectConst { destination_pointer: Relative(13), bit_size: Integer(U32), value: 1 }, BinaryIntOp { destination: Relative(14), op: Add, bit_size: U32, lhs: Relative(10), rhs: Direct(2) }, Const { destination: Relative(15), bit_size: Integer(U32), value: 6 }, BinaryIntOp { destination: Relative(16), op: Add, bit_size: U32, lhs: Relative(12), rhs: Direct(2) }, Const { destination: Relative(17), bit_size: Integer(U32), value: 4 }, BinaryIntOp { destination: Relative(18), op: Add, bit_size: U32, lhs: Relative(13), rhs: Direct(2) }, BlackBox(MultiScalarMul { points: HeapVector { pointer: Relative(14), size: Relative(15) }, scalars: HeapVector { pointer: Relative(16), size: Relative(17) }, outputs: HeapArray { pointer: Relative(18), size: 3 } }), BinaryIntOp { destination: Relative(12), op: Add, bit_size: U32, lhs: Relative(13), rhs: Relative(7) }, Load { destination: Relative(10), source_pointer: Relative(12) }, BinaryFieldOp { destination: Relative(12), op: Equals, lhs: Relative(9), rhs: Relative(10) }, JumpIf { condition: Relative(12), location: 123 }, Const { destination: Relative(13), bit_size: Integer(U32), value: 0 }, Trap { revert_data: HeapVector { pointer: Direct(1), size: Relative(13) } }, Mov { destination: Relative(9), source: Direct(1) }, Const { destination: Relative(10), bit_size: Integer(U32), value: 7 }, BinaryIntOp { destination: Direct(1), op: Add, bit_size: U32, lhs: Direct(1), rhs: Relative(10) }, IndirectConst { destination_pointer: Relative(9), bit_size: Integer(U32), value: 1 }, BinaryIntOp { destination: Relative(10), op: Add, bit_size: U32, lhs: Relative(9), rhs: Direct(2) }, Mov { destination: Relative(12), source: Relative(10) }, Store { destination_pointer: Relative(12), source: Relative(1) }, BinaryIntOp { destination: Relative(12), op: Add, bit_size: U32, lhs: Relative(12), rhs: Direct(2) }, Store { destination_pointer: Relative(12), source: Relative(8) }, BinaryIntOp { destination: Relative(12), op: Add, bit_size: U32, lhs: Relative(12), rhs: Direct(2) }, Store { destination_pointer: Relative(12), source: Relative(1) }, BinaryIntOp { destination: Relative(12), op: Add, bit_size: U32, lhs: Relative(12), rhs: Direct(2) }, Store { destination_pointer: Relative(12), source: Relative(8) }, BinaryIntOp { destination: Relative(12), op: Add, bit_size: U32, lhs: Relative(12), rhs: Direct(2) }, Store { destination_pointer: Relative(12), source: Relative(4) }, BinaryIntOp { destination: Relative(12), op: Add, bit_size: U32, lhs: Relative(12), rhs: Direct(2) }, Store { destination_pointer: Relative(12), source: Relative(8) }, Const { destination: Relative(10), bit_size: Field, value: 11179562631109628533987091031692370366552561688588090155835439555627259799605 }, Const { destination: Relative(12), bit_size: Field, value: 3443719903172018228650470536370404288991794296383447657609081676265727805364 }, Mov { destination: Relative(13), source: Direct(1) }, Const { destination: Relative(14), bit_size: Integer(U32), value: 10 }, BinaryIntOp { destination: Direct(1), op: Add, bit_size: U32, lhs: Direct(1), rhs: Relative(14) }, IndirectConst { destination_pointer: Relative(13), bit_size: Integer(U32), value: 1 }, BinaryIntOp { destination: Relative(14), op: Add, bit_size: U32, lhs: Relative(13), rhs: Direct(2) }, Mov { destination: Relative(15), source: Relative(14) }, Store { destination_pointer: Relative(15), source: Relative(4) }, BinaryIntOp { destination: Relative(15), op: Add, bit_size: U32, lhs: Relative(15), rhs: Direct(2) }, Store { destination_pointer: Relative(15), source: Relative(5) }, BinaryIntOp { destination: Relative(15), op: Add, bit_size: U32, lhs: Relative(15), rhs: Direct(2) }, Store { destination_pointer: Relative(15), source: Relative(6) }, BinaryIntOp { destination: Relative(15), op: Add, bit_size: U32, lhs: Relative(15), rhs: Direct(2) }, Store { destination_pointer: Relative(15), source: Relative(2) }, BinaryIntOp { destination: Relative(15), op: Add, bit_size: U32, lhs: Relative(15), rhs: Direct(2) }, Store { destination_pointer: Relative(15), source: Relative(3) }, BinaryIntOp { destination: Relative(15), op: Add, bit_size: U32, lhs: Relative(15), rhs: Direct(2) }, Store { destination_pointer: Relative(15), source: Relative(6) }, BinaryIntOp { destination: Relative(15), op: Add, bit_size: U32, lhs: Relative(15), rhs: Direct(2) }, Store { destination_pointer: Relative(15), source: Relative(10) }, BinaryIntOp { destination: Relative(15), op: Add, bit_size: U32, lhs: Relative(15), rhs: Direct(2) }, Store { destination_pointer: Relative(15), source: Relative(12) }, BinaryIntOp { destination: Relative(15), op: Add, bit_size: U32, lhs: Relative(15), rhs: Direct(2) }, Store { destination_pointer: Relative(15), source: Relative(6) }, Mov { destination: Relative(10), source: Direct(1) }, Const { destination: Relative(12), bit_size: Integer(U32), value: 4 }, BinaryIntOp { destination: Direct(1), op: Add, bit_size: U32, lhs: Direct(1), rhs: Relative(12) }, IndirectConst { destination_pointer: Relative(10), bit_size: Integer(U32), value: 1 }, BinaryIntOp { destination: Relative(12), op: Add, bit_size: U32, lhs: Relative(13), rhs: Direct(2) }, Const { destination: Relative(14), bit_size: Integer(U32), value: 9 }, BinaryIntOp { destination: Relative(15), op: Add, bit_size: U32, lhs: Relative(9), rhs: Direct(2) }, Const { destination: Relative(16), bit_size: Integer(U32), value: 6 }, BinaryIntOp { destination: Relative(17), op: Add, bit_size: U32, lhs: Relative(10), rhs: Direct(2) }, BlackBox(MultiScalarMul { points: HeapVector { pointer: Relative(12), size: Relative(14) }, scalars: HeapVector { pointer: Relative(15), size: Relative(16) }, outputs: HeapArray { pointer: Relative(17), size: 3 } }), BinaryIntOp { destination: Relative(12), op: Add, bit_size: U32, lhs: Relative(10), rhs: Relative(7) }, Load { destination: Relative(9), source_pointer: Relative(12) }, Const { destination: Relative(10), bit_size: Field, value: -7349266043899242844836273743257843180744506495159104166319746739537754653274 }, BinaryFieldOp { destination: Relative(12), op: Equals, lhs: Relative(9), rhs: Relative(10) }, JumpIf { condition: Relative(12), location: 182 }, Const { destination: Relative(13), bit_size: Integer(U32), value: 0 }, Trap { revert_data: HeapVector { pointer: Direct(1), size: Relative(13) } }, Mov { destination: Relative(9), source: Direct(1) }, Const { destination: Relative(10), bit_size: Integer(U32), value: 3 }, BinaryIntOp { destination: Direct(1), op: Add, bit_size: U32, lhs: Direct(1), rhs: Relative(10) }, IndirectConst { destination_pointer: Relative(9), bit_size: Integer(U32), value: 1 }, BinaryIntOp { destination: Relative(10), op: Add, bit_size: U32, lhs: Relative(9), rhs: Direct(2) }, Mov { destination: Relative(12), source: Relative(10) }, Store { destination_pointer: Relative(12), source: Relative(1) }, BinaryIntOp { destination: Relative(12), op: Add, bit_size: U32, lhs: Relative(12), rhs: Direct(2) }, Store { destination_pointer: Relative(12), source: Relative(8) }, Mov { destination: Relative(1), source: Direct(1) }, Const { destination: Relative(8), bit_size: Integer(U32), value: 4 }, BinaryIntOp { destination: Direct(1), op: Add, bit_size: U32, lhs: Direct(1), rhs: Relative(8) }, IndirectConst { destination_pointer: Relative(1), bit_size: Integer(U32), value: 1 }, BinaryIntOp { destination: Relative(8), op: Add, bit_size: U32, lhs: Relative(1), rhs: Direct(2) }, Mov { destination: Relative(10), source: Relative(8) }, Store { destination_pointer: Relative(10), source: Relative(4) }, BinaryIntOp { destination: Relative(10), op: Add, bit_size: U32, lhs: Relative(10), rhs: Direct(2) }, Store { destination_pointer: Relative(10), source: Relative(5) }, BinaryIntOp { destination: Relative(10), op: Add, bit_size: U32, lhs: Relative(10), rhs: Direct(2) }, Store { destination_pointer: Relative(10), source: Relative(6) }, Mov { destination: Relative(8), source: Direct(1) }, Const { destination: Relative(10), bit_size: Integer(U32), value: 4 }, BinaryIntOp { destination: Direct(1), op: Add, bit_size: U32, lhs: Direct(1), rhs: Relative(10) }, IndirectConst { destination_pointer: Relative(8), bit_size: Integer(U32), value: 1 }, BinaryIntOp { destination: Relative(10), op: Add, bit_size: U32, lhs: Relative(1), rhs: Direct(2) }, Const { destination: Relative(12), bit_size: Integer(U32), value: 3 }, BinaryIntOp { destination: Relative(13), op: Add, bit_size: U32, lhs: Relative(9), rhs: Direct(2) }, Const { destination: Relative(14), bit_size: Integer(U32), value: 2 }, BinaryIntOp { destination: Relative(15), op: Add, bit_size: U32, lhs: Relative(8), rhs: Direct(2) }, BlackBox(MultiScalarMul { points: HeapVector { pointer: Relative(10), size: Relative(12) }, scalars: HeapVector { pointer: Relative(13), size: Relative(14) }, outputs: HeapArray { pointer: Relative(15), size: 3 } }), BinaryIntOp { destination: Relative(9), op: Add, bit_size: U32, lhs: Relative(8), rhs: Relative(7) }, Load { destination: Relative(1), source_pointer: Relative(9) }, BinaryIntOp { destination: Relative(10), op: Add, bit_size: U32, lhs: Relative(8), rhs: Relative(11) }, Load { destination: Relative(9), source_pointer: Relative(10) }, Const { destination: Relative(10), bit_size: Integer(U32), value: 3 }, BinaryIntOp { destination: Relative(12), op: Add, bit_size: U32, lhs: Relative(8), rhs: Relative(10) }, Load { destination: Relative(11), source_pointer: Relative(12) }, BinaryIntOp { destination: Relative(8), op: Equals, bit_size: U1, lhs: Relative(11), rhs: Relative(6) }, JumpIf { condition: Relative(8), location: 223 }, Const { destination: Relative(10), bit_size: Integer(U32), value: 0 }, Trap { revert_data: HeapVector { pointer: Direct(1), size: Relative(10) } }, BinaryFieldOp { destination: Relative(8), op: Equals, lhs: Relative(1), rhs: Relative(4) }, JumpIf { condition: Relative(8), location: 227 }, Const { destination: Relative(10), bit_size: Integer(U32), value: 0 }, Trap { revert_data: HeapVector { pointer: Direct(1), size: Relative(10) } }, BinaryFieldOp { destination: Relative(1), op: Equals, lhs: Relative(9), rhs: Relative(5) }, JumpIf { condition: Relative(1), location: 231 }, Const { destination: Relative(8), bit_size: Integer(U32), value: 0 }, Trap { revert_data: HeapVector { pointer: Direct(1), size: Relative(8) } }, BinaryFieldOp { destination: Relative(1), op: Equals, lhs: Relative(2), rhs: Relative(3) }, JumpIf { condition: Relative(1), location: 234 }, Jump { location: 348 }, Const { destination: Relative(1), bit_size: Field, value: 2 }, Mov { destination: Relative(5), source: Direct(1) }, Const { destination: Relative(8), bit_size: Integer(U32), value: 4 }, BinaryIntOp { destination: Direct(1), op: Add, bit_size: U32, lhs: Direct(1), rhs: Relative(8) }, IndirectConst { destination_pointer: Relative(5), bit_size: Integer(U32), value: 1 }, BinaryIntOp { destination: Relative(8), op: Add, bit_size: U32, lhs: Relative(5), rhs: Direct(2) }, BlackBox(EmbeddedCurveAdd { input1_x: Relative(4), input1_y: Relative(1), input1_infinite: Relative(6), input2_x: Relative(4), input2_y: Relative(1), input2_infinite: Relative(6), result: HeapArray { pointer: Relative(8), size: 3 } }), BinaryIntOp { destination: Relative(9), op: Add, bit_size: U32, lhs: Relative(5), rhs: Relative(7) }, Load { destination: Relative(8), source_pointer: Relative(9) }, BinaryFieldOp { destination: Relative(5), op: Equals, lhs: Relative(8), rhs: Relative(4) }, JumpIf { condition: Relative(5), location: 247 }, Const { destination: Relative(9), bit_size: Integer(U32), value: 0 }, Trap { revert_data: HeapVector { pointer: Direct(1), size: Relative(9) } }, Const { destination: Relative(5), bit_size: Field, value: 3 }, Mov { destination: Relative(8), source: Direct(1) }, Const { destination: Relative(9), bit_size: Integer(U32), value: 4 }, BinaryIntOp { destination: Direct(1), op: Add, bit_size: U32, lhs: Direct(1), rhs: Relative(9) }, IndirectConst { destination_pointer: Relative(8), bit_size: Integer(U32), value: 1 }, BinaryIntOp { destination: Relative(9), op: Add, bit_size: U32, lhs: Relative(8), rhs: Direct(2) }, BlackBox(EmbeddedCurveAdd { input1_x: Relative(4), input1_y: Relative(1), input1_infinite: Relative(6), input2_x: Relative(4), input2_y: Relative(5), input2_infinite: Relative(6), result: HeapArray { pointer: Relative(9), size: 3 } }), BinaryIntOp { destination: Relative(10), op: Add, bit_size: U32, lhs: Relative(8), rhs: Relative(7) }, Load { destination: Relative(9), source_pointer: Relative(10) }, BinaryFieldOp { destination: Relative(8), op: Equals, lhs: Relative(9), rhs: Relative(4) }, JumpIf { condition: Relative(8), location: 260 }, Const { destination: Relative(10), bit_size: Integer(U32), value: 0 }, Trap { revert_data: HeapVector { pointer: Direct(1), size: Relative(10) } }, BinaryFieldOp { destination: Relative(8), op: Add, lhs: Relative(2), rhs: Relative(4) }, BinaryFieldOp { destination: Relative(9), op: Add, lhs: Relative(3), rhs: Relative(4) }, Mov { destination: Relative(10), source: Direct(1) }, Const { destination: Relative(11), bit_size: Integer(U32), value: 4 }, BinaryIntOp { destination: Direct(1), op: Add, bit_size: U32, lhs: Direct(1), rhs: Relative(11) }, IndirectConst { destination_pointer: Relative(10), bit_size: Integer(U32), value: 1 }, BinaryIntOp { destination: Relative(11), op: Add, bit_size: U32, lhs: Relative(10), rhs: Direct(2) }, BlackBox(EmbeddedCurveAdd { input1_x: Relative(8), input1_y: Relative(3), input1_infinite: Relative(6), input2_x: Relative(8), input2_y: Relative(3), input2_infinite: Relative(6), result: HeapArray { pointer: Relative(11), size: 3 } }), BinaryIntOp { destination: Relative(12), op: Add, bit_size: U32, lhs: Relative(10), rhs: Relative(7) }, Load { destination: Relative(11), source_pointer: Relative(12) }, BinaryFieldOp { destination: Relative(10), op: Equals, lhs: Relative(11), rhs: Relative(4) }, JumpIf { condition: Relative(10), location: 274 }, Const { destination: Relative(12), bit_size: Integer(U32), value: 0 }, Trap { revert_data: HeapVector { pointer: Direct(1), size: Relative(12) } }, Mov { destination: Relative(10), source: Direct(1) }, Const { destination: Relative(11), bit_size: Integer(U32), value: 4 }, BinaryIntOp { destination: Direct(1), op: Add, bit_size: U32, lhs: Direct(1), rhs: Relative(11) }, IndirectConst { destination_pointer: Relative(10), bit_size: Integer(U32), value: 1 }, BinaryIntOp { destination: Relative(11), op: Add, bit_size: U32, lhs: Relative(10), rhs: Direct(2) }, BlackBox(EmbeddedCurveAdd { input1_x: Relative(8), input1_y: Relative(3), input1_infinite: Relative(6), input2_x: Relative(8), input2_y: Relative(9), input2_infinite: Relative(6), result: HeapArray { pointer: Relative(11), size: 3 } }), BinaryIntOp { destination: Relative(8), op: Add, bit_size: U32, lhs: Relative(10), rhs: Relative(7) }, Load { destination: Relative(3), source_pointer: Relative(8) }, BinaryFieldOp { destination: Relative(8), op: Equals, lhs: Relative(3), rhs: Relative(4) }, JumpIf { condition: Relative(8), location: 286 }, Const { destination: Relative(10), bit_size: Integer(U32), value: 0 }, Trap { revert_data: HeapVector { pointer: Direct(1), size: Relative(10) } }, Mov { destination: Relative(3), source: Direct(1) }, Const { destination: Relative(8), bit_size: Integer(U32), value: 4 }, BinaryIntOp { destination: Direct(1), op: Add, bit_size: U32, lhs: Direct(1), rhs: Relative(8) }, IndirectConst { destination_pointer: Relative(3), bit_size: Integer(U32), value: 1 }, BinaryIntOp { destination: Relative(8), op: Add, bit_size: U32, lhs: Relative(3), rhs: Direct(2) }, BlackBox(EmbeddedCurveAdd { input1_x: Relative(1), input1_y: Relative(5), input1_infinite: Relative(6), input2_x: Relative(2), input2_y: Relative(9), input2_infinite: Relative(6), result: HeapArray { pointer: Relative(8), size: 3 } }), BinaryIntOp { destination: Relative(9), op: Add, bit_size: U32, lhs: Relative(3), rhs: Relative(7) }, Load { destination: Relative(8), source_pointer: Relative(9) }, BinaryFieldOp { destination: Relative(3), op: Equals, lhs: Relative(8), rhs: Relative(4) }, JumpIf { condition: Relative(3), location: 298 }, Const { destination: Relative(9), bit_size: Integer(U32), value: 0 }, Trap { revert_data: HeapVector { pointer: Direct(1), size: Relative(9) } }, Const { destination: Relative(3), bit_size: Field, value: 4 }, Mov { destination: Relative(8), source: Direct(1) }, Const { destination: Relative(9), bit_size: Integer(U32), value: 4 }, BinaryIntOp { destination: Direct(1), op: Add, bit_size: U32, lhs: Direct(1), rhs: Relative(9) }, IndirectConst { destination_pointer: Relative(8), bit_size: Integer(U32), value: 1 }, BinaryIntOp { destination: Relative(9), op: Add, bit_size: U32, lhs: Relative(8), rhs: Direct(2) }, BlackBox(EmbeddedCurveAdd { input1_x: Relative(1), input1_y: Relative(5), input1_infinite: Relative(6), input2_x: Relative(1), input2_y: Relative(3), input2_infinite: Relative(6), result: HeapArray { pointer: Relative(9), size: 3 } }), BinaryIntOp { destination: Relative(9), op: Add, bit_size: U32, lhs: Relative(8), rhs: Relative(7) }, Load { destination: Relative(3), source_pointer: Relative(9) }, BinaryFieldOp { destination: Relative(8), op: Equals, lhs: Relative(3), rhs: Relative(4) }, JumpIf { condition: Relative(8), location: 311 }, Const { destination: Relative(9), bit_size: Integer(U32), value: 0 }, Trap { revert_data: HeapVector { pointer: Direct(1), size: Relative(9) } }, Mov { destination: Relative(3), source: Direct(1) }, Const { destination: Relative(8), bit_size: Integer(U32), value: 4 }, BinaryIntOp { destination: Direct(1), op: Add, bit_size: U32, lhs: Direct(1), rhs: Relative(8) }, IndirectConst { destination_pointer: Relative(3), bit_size: Integer(U32), value: 1 }, BinaryIntOp { destination: Relative(8), op: Add, bit_size: U32, lhs: Relative(3), rhs: Direct(2) }, BlackBox(EmbeddedCurveAdd { input1_x: Relative(1), input1_y: Relative(5), input1_infinite: Relative(6), input2_x: Relative(1), input2_y: Relative(5), input2_infinite: Relative(6), result: HeapArray { pointer: Relative(8), size: 3 } }), BinaryIntOp { destination: Relative(9), op: Add, bit_size: U32, lhs: Relative(3), rhs: Relative(7) }, Load { destination: Relative(8), source_pointer: Relative(9) }, BinaryFieldOp { destination: Relative(3), op: Equals, lhs: Relative(8), rhs: Relative(4) }, JumpIf { condition: Relative(3), location: 323 }, Const { destination: Relative(9), bit_size: Integer(U32), value: 0 }, Trap { revert_data: HeapVector { pointer: Direct(1), size: Relative(9) } }, Mov { destination: Relative(3), source: Direct(1) }, Const { destination: Relative(8), bit_size: Integer(U32), value: 4 }, BinaryIntOp { destination: Direct(1), op: Add, bit_size: U32, lhs: Direct(1), rhs: Relative(8) }, IndirectConst { destination_pointer: Relative(3), bit_size: Integer(U32), value: 1 }, BinaryIntOp { destination: Relative(8), op: Add, bit_size: U32, lhs: Relative(3), rhs: Direct(2) }, BlackBox(EmbeddedCurveAdd { input1_x: Relative(4), input1_y: Relative(5), input1_infinite: Relative(6), input2_x: Relative(4), input2_y: Relative(5), input2_infinite: Relative(6), result: HeapArray { pointer: Relative(8), size: 3 } }), BinaryIntOp { destination: Relative(9), op: Add, bit_size: U32, lhs: Relative(3), rhs: Relative(7) }, Load { destination: Relative(8), source_pointer: Relative(9) }, BinaryFieldOp { destination: Relative(3), op: Equals, lhs: Relative(8), rhs: Relative(4) }, JumpIf { condition: Relative(3), location: 335 }, Const { destination: Relative(9), bit_size: Integer(U32), value: 0 }, Trap { revert_data: HeapVector { pointer: Direct(1), size: Relative(9) } }, Mov { destination: Relative(3), source: Direct(1) }, Const { destination: Relative(8), bit_size: Integer(U32), value: 4 }, BinaryIntOp { destination: Direct(1), op: Add, bit_size: U32, lhs: Direct(1), rhs: Relative(8) }, IndirectConst { destination_pointer: Relative(3), bit_size: Integer(U32), value: 1 }, BinaryIntOp { destination: Relative(8), op: Add, bit_size: U32, lhs: Relative(3), rhs: Direct(2) }, BlackBox(EmbeddedCurveAdd { input1_x: Relative(2), input1_y: Relative(5), input1_infinite: Relative(6), input2_x: Relative(2), input2_y: Relative(1), input2_infinite: Relative(6), result: HeapArray { pointer: Relative(8), size: 3 } }), BinaryIntOp { destination: Relative(2), op: Add, bit_size: U32, lhs: Relative(3), rhs: Relative(7) }, Load { destination: Relative(1), source_pointer: Relative(2) }, BinaryFieldOp { destination: Relative(2), op: Equals, lhs: Relative(1), rhs: Relative(4) }, JumpIf { condition: Relative(2), location: 347 }, Const { destination: Relative(3), bit_size: Integer(U32), value: 0 }, Trap { revert_data: HeapVector { pointer: Direct(1), size: Relative(3) } }, Jump { location: 348 }, Return, Const { destination: Direct(32772), bit_size: Integer(U32), value: 30720 }, BinaryIntOp { destination: Direct(32771), op: LessThan, bit_size: U32, lhs: Direct(0), rhs: Direct(32772) }, JumpIf { condition: Direct(32771), location: 354 }, IndirectConst { destination_pointer: Direct(1), bit_size: Integer(U64), value: 17843811134343075018 }, Trap { revert_data: HeapVector { pointer: Direct(1), size: Direct(2) } }, Return]" ], - "debug_symbols": "tZfRTioxEIbfZa+5aDszbcdXMcagroaEAEE4yYnh3U+7Mz/qxRqzHm/4PsR+pN0thbfhaXw4v9xvds/71+Hm9m14OG62283L/Xb/uD5t9rv217ch9IeYh5u4GmIxVINOSMEQDclABjaIwSrJKskqySpkFbIKWYWsQlYhq5BVyCpkFbIKtwo1REMykIENYsiGYqgGnSCtwg3RkAxkYIMYWkUaiqEadEJuldwQDclAhj6j0CjO7CzO6lRj6avT5leis69PaiQnO8WZncVZnWqswRmd3qveq96r3qveq96r3qveU++p99R76j31nnpPvafeU++p92IIkAhJEIIwRCAZ0rvcpULUJQZIhCQIQRgikAzpZelSIb3crmmcNsIkEZIgvVy7MEQgGVIgFaIu0+aYJEISBGVCmVAmlAllQplQZpQZZUaZUWaUGWVGmVFmlBllQVlQFpQFZUFZUBaUBWVBWVDOKGeUM8oZ5YxyRjmjnFHOKGeUC8oF5YJyQbmgPO017ZIhrZxClwpRl77hTCKklVO/V/ueM2GIQDKkQCpEXfrWM4kQlBVlRVlRVpQVZUVZvZxCgERIghCEIQLJkAKpEJQjyhHlvgcTdSEIQwSSIQVSIb3M/fQJkAhJEIIwRCAZUiAVgjJN5ctlNeB4vD8dx7Gfjh/Oy3aKHtbHcXcabnbn7XY1/Flvz9M/vR7Wu4mn9bG92m6BcffU2ILPm+3Y7bJ6Hx3mhybKPjhRuQ6Xb4+nvuLTeCo6Nz7Nj2dR9gBnfp9AzMsKNFf4ag6KOXDIC9aAEy4AEy8YnxnXIOc0N758MT5FjJc4N//6xfjAikDQ2Wug84V27IXiiebC/6FRFlzJci2UtORK1Ig7odY4Nz7Sj2/n7yeW3M96DbRvPHHBMrRvBNcC19mFjOXnC1F+cyHaF4jrHSU1LFmJmgQFZZn9gIs//4SLv7oSKvU6j/J5Hnft2fpxc/z0U+3SW8fN+mE7+tPn8+7xw6unvwe8gp96h+P+cXw6H8de+vB7rz3eJkqrdsLcXfr7/QM=", + "debug_symbols": "tZndThs9EIbvJccc2J4f29xKVaEAoYoUBZTCJ31C3Htndvwm9GBR2SQnfR9K/TT2euxZ5X31uLl/+3W33T89/17d/nhf3R+2u932193u+WH9un3e29++r5L/kXV1m29WuUa0iD5FSRE5okRQBEdIRFhKWEpYSlgoLBQWCguFhcJCYaGwUFgoLBQWNgtZ5IgSQREcIREaUSNaRJ9CzMIWOaJEUARHSIRZxKJGtIg+hZpFLXJEiaAIn1GylJE6so5sI3tk9dWx+dU80tenWNJIHikjdWQd2Ub2yJZG5pHD14avDV8bvjZ8bfja8LXh68PXh68PXx++Pnx9+Prw9eHrw9eHL6cEyIACIAADBKAA97JDA/QBOQEyoAAIwAABKMDN4tAAbrZnmqdCmCADCsDNzYEBAlBABTRAHzAVxwQZUAAwE8wEM8FMMBPMBDPDzDAzzAwzw8wwM8wMM8PMMAvMArPALDALzAKzwCwwC8wCs8KsMCvMCrPCrDArzAqzwqwwV5grzBXmCnOFeaq17qAAM5fk0AB9gBdcQAaYufhe9ZoLYIAAFFABDdAHeOkFZADMHeYOc4e5w9xh7jD3YS4pATKgAAjAAAEooAIaAOYMc4bZa7CQAwEYIAAFVEADuJn99kmADCgAAjBAAAqogAaAmWD2Gizi4J7uIAAFVEAD9AFecQF+SSWHAvCLaro1GSAABfiF5VOerqwJ+gCvuIAMKAACuNln4RUX4GafjldcQAP0AV5xpA5urg5+KU5XOgEYIAAFVICZ2R+3V9wEXnHsH8wrLqAACOBm/xhecQEKqIAG6AO84tg/s1dcgJv9w3vFBTBAAG72p+MVF9AAfYBXXEAGmFn8CXrFBZhZpu5GAAqoAG8XfIJecQ7kFReQAQVAAAa4mR0U4GZxaIA+wCsuwM3VoQAIwAABKMDNzaEB3Ny9U0uADCgAb3ambo4BAlBABTSAmbV485cA3kL5lP3WCyAAA9zsE/QaDKiABugDvAYD3KwOBeBmn7LXYIAA3Fw/Pm5WaJDvXg+bjffHnzpm66Nf1ofN/nV1u3/b7W5W/613b9M/+v2y3k/5uj7Yb22bbPaPliZ82u42Th83p9Fpfqjt1zHYNuxxuPzzeKp5jOfS5saX+fEsnSFQPk0g6zIDzRm+mAPzcQ4iC9aAtWN8owXjteMZ1Jznxtcvxhd8fpU8N//2xfjEmICmPvsM+rzBGt9Uh8JY+AKOuuBJVlGsZF3yJJpiJTulufGZzt7O/65Ysp/tdYawkEnTgnWwPv9oEJpdyVzPX4l61ZUQxoawzr4vWYlW8RmsneXZEy6ff8Tla66EteAoLuu9ecFKWGONe8Za60UGEszC+tvZXVX0zKOu1LPPutIucNh9R7LktLNXgnJcz16XPBH2988wsMzePVQusBrfkSxaDdbTXGpbshqixx0uuuS0sBeMo6HyIkPLxzptZbYjo3ZmjVA/u0Y4XWBXfEeyaFc0/tTgpkVPpGE97TVt9txjvsRq8JVXo9NpLpyX9PuloDOwV7DZ/cmXOD/5yuenvTGe5rKocyfuqBQSKnMGucT5KVc+P+1yPs1FlpxdVCtqjVqaPYFFL7EaeuXVaOU0F1r0VpgEdwGn+d2llzhF9cqnKNu3KJiLfe2xZDWIUGtMOntu6CVOUb3yKcq2I45z6X8/2Z/20/phe/jrm88Pdx226/vdZvz49LZ/+PTb1/9f8Bt8c/pyeH7YPL4dNm769PWp/fnDjp0bK9efH/7//QE=", "file_map": { "16": { "source": "use crate::cmp::Eq;\nuse crate::hash::Hash;\nuse crate::ops::arith::{Add, Neg, Sub};\n\n/// A point on the embedded elliptic curve\n/// By definition, the base field of the embedded curve is the scalar field of the proof system curve, i.e the Noir Field.\n/// x and y denotes the Weierstrass coordinates of the point, if is_infinite is false.\npub struct EmbeddedCurvePoint {\n pub x: Field,\n pub y: Field,\n pub is_infinite: bool,\n}\n\nimpl EmbeddedCurvePoint {\n /// Elliptic curve point doubling operation\n /// returns the doubled point of a point P, i.e P+P\n pub fn double(self) -> EmbeddedCurvePoint {\n embedded_curve_add(self, self)\n }\n\n /// Returns the null element of the curve; 'the point at infinity'\n pub fn point_at_infinity() -> EmbeddedCurvePoint {\n EmbeddedCurvePoint { x: 0, y: 0, is_infinite: true }\n }\n\n /// Returns the curve's generator point.\n pub fn generator() -> EmbeddedCurvePoint {\n // Generator point for the grumpkin curve (y^2 = x^3 - 17)\n EmbeddedCurvePoint {\n x: 1,\n y: 17631683881184975370165255887551781615748388533673675138860, // sqrt(-16)\n is_infinite: false,\n }\n }\n}\n\nimpl Add for EmbeddedCurvePoint {\n /// Adds two points P+Q, using the curve addition formula, and also handles point at infinity\n fn add(self, other: EmbeddedCurvePoint) -> EmbeddedCurvePoint {\n embedded_curve_add(self, other)\n }\n}\n\nimpl Sub for EmbeddedCurvePoint {\n /// Points subtraction operation, using addition and negation\n fn sub(self, other: EmbeddedCurvePoint) -> EmbeddedCurvePoint {\n self + other.neg()\n }\n}\n\nimpl Neg for EmbeddedCurvePoint {\n /// Negates a point P, i.e returns -P, by negating the y coordinate.\n /// If the point is at infinity, then the result is also at infinity.\n fn neg(self) -> EmbeddedCurvePoint {\n EmbeddedCurvePoint { x: self.x, y: -self.y, is_infinite: self.is_infinite }\n }\n}\n\nimpl Eq for EmbeddedCurvePoint {\n /// Checks whether two points are equal\n fn eq(self: Self, b: EmbeddedCurvePoint) -> bool {\n (self.is_infinite & b.is_infinite)\n | ((self.is_infinite == b.is_infinite) & (self.x == b.x) & (self.y == b.y))\n }\n}\n\nimpl Hash for EmbeddedCurvePoint {\n fn hash(self, state: &mut H)\n where\n H: crate::hash::Hasher,\n {\n if self.is_infinite {\n self.is_infinite.hash(state);\n } else {\n self.x.hash(state);\n self.y.hash(state);\n }\n }\n}\n\n/// Scalar for the embedded curve represented as low and high limbs\n/// By definition, the scalar field of the embedded curve is base field of the proving system curve.\n/// It may not fit into a Field element, so it is represented with two Field elements; its low and high limbs.\npub struct EmbeddedCurveScalar {\n pub lo: Field,\n pub hi: Field,\n}\n\nimpl EmbeddedCurveScalar {\n pub fn new(lo: Field, hi: Field) -> Self {\n EmbeddedCurveScalar { lo, hi }\n }\n\n #[field(bn254)]\n pub fn from_field(scalar: Field) -> EmbeddedCurveScalar {\n let (a, b) = crate::field::bn254::decompose(scalar);\n EmbeddedCurveScalar { lo: a, hi: b }\n }\n\n //Bytes to scalar: take the first (after the specified offset) 16 bytes of the input as the lo value, and the next 16 bytes as the hi value\n #[field(bn254)]\n pub(crate) fn from_bytes(bytes: [u8; 64], offset: u32) -> EmbeddedCurveScalar {\n let mut v = 1;\n let mut lo = 0 as Field;\n let mut hi = 0 as Field;\n for i in 0..16 {\n lo = lo + (bytes[offset + 31 - i] as Field) * v;\n hi = hi + (bytes[offset + 15 - i] as Field) * v;\n v = v * 256;\n }\n let sig_s = crate::embedded_curve_ops::EmbeddedCurveScalar { lo, hi };\n sig_s\n }\n}\n\nimpl Eq for EmbeddedCurveScalar {\n fn eq(self, other: Self) -> bool {\n (other.hi == self.hi) & (other.lo == self.lo)\n }\n}\n\nimpl Hash for EmbeddedCurveScalar {\n fn hash(self, state: &mut H)\n where\n H: crate::hash::Hasher,\n {\n self.hi.hash(state);\n self.lo.hash(state);\n }\n}\n\n// Computes a multi scalar multiplication over the embedded curve.\n// For bn254, We have Grumpkin and Baby JubJub.\n// For bls12-381, we have JubJub and Bandersnatch.\n//\n// The embedded curve being used is decided by the\n// underlying proof system.\n// docs:start:multi_scalar_mul\npub fn multi_scalar_mul(\n points: [EmbeddedCurvePoint; N],\n scalars: [EmbeddedCurveScalar; N],\n) -> EmbeddedCurvePoint\n// docs:end:multi_scalar_mul\n{\n multi_scalar_mul_array_return(points, scalars)[0]\n}\n\n#[foreign(multi_scalar_mul)]\npub(crate) fn multi_scalar_mul_array_return(\n points: [EmbeddedCurvePoint; N],\n scalars: [EmbeddedCurveScalar; N],\n) -> [EmbeddedCurvePoint; 1] {}\n\n// docs:start:fixed_base_scalar_mul\npub fn fixed_base_scalar_mul(scalar: EmbeddedCurveScalar) -> EmbeddedCurvePoint\n// docs:end:fixed_base_scalar_mul\n{\n multi_scalar_mul([EmbeddedCurvePoint::generator()], [scalar])\n}\n\n/// This function only assumes that the points are on the curve\n/// It handles corner cases around the infinity point causing some overhead compared to embedded_curve_add_not_nul and embedded_curve_add_unsafe\n// docs:start:embedded_curve_add\npub fn embedded_curve_add(\n point1: EmbeddedCurvePoint,\n point2: EmbeddedCurvePoint,\n) -> EmbeddedCurvePoint {\n // docs:end:embedded_curve_add\n if crate::runtime::is_unconstrained() {\n // `embedded_curve_add_unsafe` requires the inputs not to be the infinity point, so we check it here.\n // This is because `embedded_curve_add_unsafe` uses the `embedded_curve_add` opcode.\n // For efficiency, the backend does not check the inputs for the infinity point, but it assumes that they are not the infinity point\n // so that it can apply the ec addition formula directly.\n if point1.is_infinite {\n point2\n } else if point2.is_infinite {\n point1\n } else {\n embedded_curve_add_unsafe(point1, point2)\n }\n } else {\n // In a constrained context, we also need to check the inputs are not the infinity point because we also use `embedded_curve_add_unsafe`\n // However we also need to identify the case where the two inputs are the same, because then\n // the addition formula does not work and we need to use the doubling formula instead.\n // In unconstrained context, we can check directly if the input values are the same when solving the opcode, so it is not an issue.\n\n // x_coordinates_match is true if both abscissae are the same\n let x_coordinates_match = point1.x == point2.x;\n // y_coordinates_match is true if both ordinates are the same\n let y_coordinates_match = point1.y == point2.y;\n // double_predicate is true if both abscissae and ordinates are the same\n let double_predicate = (x_coordinates_match & y_coordinates_match);\n // If the abscissae are the same, but not the ordinates, then one point is the opposite of the other\n let infinity_predicate = (x_coordinates_match & !y_coordinates_match);\n let point1_1 = EmbeddedCurvePoint {\n x: point1.x + (x_coordinates_match as Field),\n y: point1.y,\n is_infinite: false,\n };\n let point2_1 = EmbeddedCurvePoint { x: point2.x, y: point2.y, is_infinite: false };\n // point1_1 is guaranteed to have a different abscissa than point2:\n // - if x_coordinates_match is 0, that means point1.x != point2.x, and point1_1.x = point1.x + 0\n // - if x_coordinates_match is 1, that means point1.x = point2.x, but point1_1.x = point1.x + 1 in this case\n // Because the abscissa is different, the addition formula is guaranteed to succeed, so we can safely use `embedded_curve_add_unsafe`\n // Note that this computation may be garbage: if x_coordinates_match is 1, or if one of the input is the point at infinity.\n let mut result = embedded_curve_add_unsafe(point1_1, point2_1);\n\n // `embedded_curve_add_unsafe` is doing a doubling if the input is the same variable, because in this case it is guaranteed (at 'compile time') that the input is the same.\n let double = embedded_curve_add_unsafe(point1, point1);\n // `embedded_curve_add_unsafe` would not perform doubling, even if the inputs point1 and point2 are the same, because it cannot know this without adding some logic (and some constraints)\n // However we did this logic when we computed `double_predicate`, so we set the result to 2*point1 if point1 and point2 are the same\n result = if double_predicate { double } else { result };\n\n // Same logic as above for unconstrained context, we set the proper result when one of the inputs is the infinity point\n if point1.is_infinite {\n result = point2;\n }\n if point2.is_infinite {\n result = point1;\n }\n\n // Finally, we set the is_infinity flag of the result:\n // Opposite points should sum into the infinity point, however, if one of them is point at infinity, their coordinates are not meaningful\n // so we should not use the fact that the inputs are opposite in this case:\n let mut result_is_infinity =\n infinity_predicate & (!point1.is_infinite & !point2.is_infinite);\n // However, if both of them are at infinity, then the result is also at infinity\n result.is_infinite = result_is_infinity | (point1.is_infinite & point2.is_infinite);\n result\n }\n}\n\n#[foreign(embedded_curve_add)]\nfn embedded_curve_add_array_return(\n _point1: EmbeddedCurvePoint,\n _point2: EmbeddedCurvePoint,\n) -> [EmbeddedCurvePoint; 1] {}\n\n/// This function assumes that:\n/// The points are on the curve, and\n/// The points don't share an x-coordinate, and\n/// Neither point is the infinity point.\n/// If it is used with correct input, the function ensures the correct non-zero result is returned.\n/// Except for points on the curve, the other assumptions are checked by the function. It will cause assertion failure if they are not respected.\npub fn embedded_curve_add_not_nul(\n point1: EmbeddedCurvePoint,\n point2: EmbeddedCurvePoint,\n) -> EmbeddedCurvePoint {\n assert(point1.x != point2.x);\n assert(!point1.is_infinite);\n assert(!point2.is_infinite);\n // Ensure is_infinite is comptime\n let point1_1 = EmbeddedCurvePoint { x: point1.x, y: point1.y, is_infinite: false };\n let point2_1 = EmbeddedCurvePoint { x: point2.x, y: point2.y, is_infinite: false };\n embedded_curve_add_unsafe(point1_1, point2_1)\n}\n\n/// Unsafe ec addition\n/// If the inputs are the same, it will perform a doubling, but only if point1 and point2 are the same variable.\n/// If they have the same value but are different variables, the result will be incorrect because in this case\n/// it assumes (but does not check) that the points' x-coordinates are not equal.\n/// It also assumes neither point is the infinity point.\npub fn embedded_curve_add_unsafe(\n point1: EmbeddedCurvePoint,\n point2: EmbeddedCurvePoint,\n) -> EmbeddedCurvePoint {\n embedded_curve_add_array_return(point1, point2)[0]\n}\n", "path": "std/embedded_curve_ops.nr" }, "50": { - "source": "use std::ops::Add;\n\nfn main(priv_key: Field, pub_x: pub Field, pub_y: pub Field) {\n let g1 = std::embedded_curve_ops::EmbeddedCurvePoint::generator();\n let scalar = std::embedded_curve_ops::EmbeddedCurveScalar { lo: priv_key, hi: 0 };\n // Test that multi_scalar_mul correctly derives the public key\n let res = std::embedded_curve_ops::multi_scalar_mul([g1], [scalar]);\n assert(res.x == pub_x);\n assert(res.y == pub_y);\n\n // Test that double function calling embedded_curve_add works as expected\n let pub_point =\n std::embedded_curve_ops::EmbeddedCurvePoint { x: pub_x, y: pub_y, is_infinite: false };\n let res = pub_point.double();\n let double = g1.add(g1);\n\n assert(double.x == res.x);\n\n // Test calling multi_scalar_mul with multiple points and scalars\n let res = std::embedded_curve_ops::multi_scalar_mul([g1, g1], [scalar, scalar]);\n\n // The results should be double the g1 point because the scalars are 1 and we pass in g1 twice\n assert(double.x == res.x);\n\n // Tests for #6549\n let const_scalar1 = std::embedded_curve_ops::EmbeddedCurveScalar { lo: 23, hi: 0 };\n let const_scalar2 = std::embedded_curve_ops::EmbeddedCurveScalar { lo: 0, hi: 23 };\n let const_scalar3 = std::embedded_curve_ops::EmbeddedCurveScalar { lo: 13, hi: 4 };\n let partial_mul = std::embedded_curve_ops::multi_scalar_mul(\n [g1, double, pub_point, g1, g1],\n [scalar, const_scalar1, scalar, const_scalar2, const_scalar3],\n );\n assert(partial_mul.x == 0x2024c4eebfbc8a20018f8c95c7aab77c6f34f10cf785a6f04e97452d8708fda7);\n // Check simplification by zero\n let zero_point = std::embedded_curve_ops::EmbeddedCurvePoint { x: 0, y: 0, is_infinite: true };\n let const_zero = std::embedded_curve_ops::EmbeddedCurveScalar { lo: 0, hi: 0 };\n let partial_mul = std::embedded_curve_ops::multi_scalar_mul(\n [zero_point, double, g1],\n [scalar, const_zero, scalar],\n );\n assert(partial_mul == g1);\n}\n", + "source": "use std::{embedded_curve_ops::embedded_curve_add_unsafe, ops::Add};\n\nfn main(priv_key: Field, pub_x: pub Field, pub_y: pub Field) {\n let g1 = std::embedded_curve_ops::EmbeddedCurvePoint::generator();\n let scalar = std::embedded_curve_ops::EmbeddedCurveScalar { lo: priv_key, hi: 0 };\n // Test that multi_scalar_mul correctly derives the public key\n let res = std::embedded_curve_ops::multi_scalar_mul([g1], [scalar]);\n assert(res.x == pub_x);\n assert(res.y == pub_y);\n\n // Test that double function calling embedded_curve_add works as expected\n let pub_point =\n std::embedded_curve_ops::EmbeddedCurvePoint { x: pub_x, y: pub_y, is_infinite: false };\n let res = pub_point.double();\n let double = g1.add(g1);\n\n assert(double.x == res.x);\n\n // Test calling multi_scalar_mul with multiple points and scalars\n let res = std::embedded_curve_ops::multi_scalar_mul([g1, g1], [scalar, scalar]);\n\n // The results should be double the g1 point because the scalars are 1 and we pass in g1 twice\n assert(double.x == res.x);\n\n // Tests for #6549\n let const_scalar1 = std::embedded_curve_ops::EmbeddedCurveScalar { lo: 23, hi: 0 };\n let const_scalar2 = std::embedded_curve_ops::EmbeddedCurveScalar { lo: 0, hi: 23 };\n let const_scalar3 = std::embedded_curve_ops::EmbeddedCurveScalar { lo: 13, hi: 4 };\n let partial_mul = std::embedded_curve_ops::multi_scalar_mul(\n [g1, double, pub_point, g1, g1],\n [scalar, const_scalar1, scalar, const_scalar2, const_scalar3],\n );\n assert(partial_mul.x == 0x2024c4eebfbc8a20018f8c95c7aab77c6f34f10cf785a6f04e97452d8708fda7);\n // Check simplification by zero\n let zero_point = std::embedded_curve_ops::EmbeddedCurvePoint { x: 0, y: 0, is_infinite: true };\n let const_zero = std::embedded_curve_ops::EmbeddedCurveScalar { lo: 0, hi: 0 };\n let partial_mul = std::embedded_curve_ops::multi_scalar_mul(\n [zero_point, double, g1],\n [scalar, const_zero, scalar],\n );\n assert(partial_mul == g1);\n\n // Additional tests for validating embedded_curve_add_unsafe under a conditional\n if pub_x == pub_y {\n let a1 = std::embedded_curve_ops::EmbeddedCurvePoint { x: 1, y: 2, is_infinite: false };\n let a2 = std::embedded_curve_ops::EmbeddedCurvePoint { x: 1, y: 3, is_infinite: false };\n let doubling = a1.double();\n assert(doubling.x == 1);\n let res = embedded_curve_add_unsafe(a1, a2);\n assert(res.x == 1);\n\n let a1 = std::embedded_curve_ops::EmbeddedCurvePoint {\n x: pub_x + 1,\n y: pub_y,\n is_infinite: false,\n };\n let a2 = std::embedded_curve_ops::EmbeddedCurvePoint {\n x: pub_x + 1,\n y: pub_y + 1,\n is_infinite: false,\n };\n let doubling = a1.double();\n assert(doubling.x == 1);\n let res = embedded_curve_add_unsafe(a1, a2);\n assert(res.x == 1);\n\n let a1 = std::embedded_curve_ops::EmbeddedCurvePoint { x: 2, y: 3, is_infinite: false };\n let a2 = std::embedded_curve_ops::EmbeddedCurvePoint {\n x: pub_x,\n y: pub_y + 1 as Field,\n is_infinite: false,\n };\n let res = embedded_curve_add_unsafe(a1, a2);\n assert(res.x == 1);\n\n let a1 = std::embedded_curve_ops::EmbeddedCurvePoint { x: 2, y: 3, is_infinite: false };\n let a2 = std::embedded_curve_ops::EmbeddedCurvePoint { x: 2, y: 4, is_infinite: false };\n let res = embedded_curve_add_unsafe(a1, a2);\n assert(res.x == 1);\n\n let a1 = std::embedded_curve_ops::EmbeddedCurvePoint { x: 2, y: 3, is_infinite: false };\n let a2 = std::embedded_curve_ops::EmbeddedCurvePoint { x: 2, y: 3, is_infinite: false };\n let res = embedded_curve_add_unsafe(a1, a2);\n assert(res.x == 1);\n let a1 = std::embedded_curve_ops::EmbeddedCurvePoint { x: 1, y: 3, is_infinite: false };\n let a2 = std::embedded_curve_ops::EmbeddedCurvePoint { x: 1, y: 3, is_infinite: false };\n let res = embedded_curve_add_unsafe(a1, a2);\n assert(res.x == 1);\n let a1 = std::embedded_curve_ops::EmbeddedCurvePoint { x: pub_x, y: 3, is_infinite: false };\n let a2 = std::embedded_curve_ops::EmbeddedCurvePoint { x: pub_x, y: 2, is_infinite: false };\n let res = embedded_curve_add_unsafe(a1, a2);\n assert(res.x == 1);\n }\n}\n", "path": "" } }, diff --git a/tooling/nargo_cli/tests/snapshots/execution_success/embedded_curve_ops/execute__tests__force_brillig_true_inliner_9223372036854775807.snap b/tooling/nargo_cli/tests/snapshots/execution_success/embedded_curve_ops/execute__tests__force_brillig_true_inliner_9223372036854775807.snap index e1cc05ccb59..3ebd817e856 100644 --- a/tooling/nargo_cli/tests/snapshots/execution_success/embedded_curve_ops/execute__tests__force_brillig_true_inliner_9223372036854775807.snap +++ b/tooling/nargo_cli/tests/snapshots/execution_success/embedded_curve_ops/execute__tests__force_brillig_true_inliner_9223372036854775807.snap @@ -45,16 +45,16 @@ expression: artifact "return value indices : []", "BRILLIG CALL func 0: inputs: [Single(Expression { mul_terms: [], linear_combinations: [(1, Witness(0))], q_c: 0 }), Single(Expression { mul_terms: [], linear_combinations: [(1, Witness(1))], q_c: 0 }), Single(Expression { mul_terms: [], linear_combinations: [(1, Witness(2))], q_c: 0 })], outputs: []", "unconstrained func 0", - "[Const { destination: Direct(2), bit_size: Integer(U32), value: 1 }, Const { destination: Direct(1), bit_size: Integer(U32), value: 32839 }, Const { destination: Direct(0), bit_size: Integer(U32), value: 3 }, Const { destination: Relative(4), bit_size: Integer(U32), value: 3 }, Const { destination: Relative(5), bit_size: Integer(U32), value: 0 }, CalldataCopy { destination_address: Direct(32836), size_address: Relative(4), offset_address: Relative(5) }, Mov { destination: Relative(1), source: Direct(32836) }, Mov { destination: Relative(2), source: Direct(32837) }, Mov { destination: Relative(3), source: Direct(32838) }, Call { location: 14 }, Call { location: 15 }, Const { destination: Relative(1), bit_size: Integer(U32), value: 32839 }, Const { destination: Relative(2), bit_size: Integer(U32), value: 0 }, Stop { return_data: HeapVector { pointer: Relative(1), size: Relative(2) } }, Return, Call { location: 232 }, Const { destination: Relative(4), bit_size: Field, value: 1 }, Const { destination: Relative(5), bit_size: Field, value: 17631683881184975370165255887551781615748388533673675138860 }, Const { destination: Relative(6), bit_size: Integer(U1), value: 0 }, Mov { destination: Relative(7), source: Direct(1) }, Const { destination: Relative(8), bit_size: Integer(U32), value: 4 }, BinaryIntOp { destination: Direct(1), op: Add, bit_size: U32, lhs: Direct(1), rhs: Relative(8) }, IndirectConst { destination_pointer: Relative(7), bit_size: Integer(U32), value: 1 }, BinaryIntOp { destination: Relative(8), op: Add, bit_size: U32, lhs: Relative(7), rhs: Direct(2) }, Mov { destination: Relative(9), source: Relative(8) }, Store { destination_pointer: Relative(9), source: Relative(4) }, BinaryIntOp { destination: Relative(9), op: Add, bit_size: U32, lhs: Relative(9), rhs: Direct(2) }, Store { destination_pointer: Relative(9), source: Relative(5) }, BinaryIntOp { destination: Relative(9), op: Add, bit_size: U32, lhs: Relative(9), rhs: Direct(2) }, Store { destination_pointer: Relative(9), source: Relative(6) }, Const { destination: Relative(8), bit_size: Field, value: 0 }, Mov { destination: Relative(9), source: Direct(1) }, Const { destination: Relative(10), bit_size: Integer(U32), value: 3 }, BinaryIntOp { destination: Direct(1), op: Add, bit_size: U32, lhs: Direct(1), rhs: Relative(10) }, IndirectConst { destination_pointer: Relative(9), bit_size: Integer(U32), value: 1 }, BinaryIntOp { destination: Relative(10), op: Add, bit_size: U32, lhs: Relative(9), rhs: Direct(2) }, Mov { destination: Relative(11), source: Relative(10) }, Store { destination_pointer: Relative(11), source: Relative(1) }, BinaryIntOp { destination: Relative(11), op: Add, bit_size: U32, lhs: Relative(11), rhs: Direct(2) }, Store { destination_pointer: Relative(11), source: Relative(8) }, Mov { destination: Relative(10), source: Direct(1) }, Const { destination: Relative(11), bit_size: Integer(U32), value: 4 }, BinaryIntOp { destination: Direct(1), op: Add, bit_size: U32, lhs: Direct(1), rhs: Relative(11) }, IndirectConst { destination_pointer: Relative(10), bit_size: Integer(U32), value: 1 }, BinaryIntOp { destination: Relative(11), op: Add, bit_size: U32, lhs: Relative(7), rhs: Direct(2) }, Const { destination: Relative(12), bit_size: Integer(U32), value: 3 }, BinaryIntOp { destination: Relative(13), op: Add, bit_size: U32, lhs: Relative(9), rhs: Direct(2) }, Const { destination: Relative(14), bit_size: Integer(U32), value: 2 }, BinaryIntOp { destination: Relative(15), op: Add, bit_size: U32, lhs: Relative(10), rhs: Direct(2) }, BlackBox(MultiScalarMul { points: HeapVector { pointer: Relative(11), size: Relative(12) }, scalars: HeapVector { pointer: Relative(13), size: Relative(14) }, outputs: HeapArray { pointer: Relative(15), size: 3 } }), Const { destination: Relative(7), bit_size: Integer(U32), value: 1 }, BinaryIntOp { destination: Relative(11), op: Add, bit_size: U32, lhs: Relative(10), rhs: Relative(7) }, Load { destination: Relative(9), source_pointer: Relative(11) }, Const { destination: Relative(11), bit_size: Integer(U32), value: 2 }, BinaryIntOp { destination: Relative(13), op: Add, bit_size: U32, lhs: Relative(10), rhs: Relative(11) }, Load { destination: Relative(12), source_pointer: Relative(13) }, BinaryFieldOp { destination: Relative(10), op: Equals, lhs: Relative(9), rhs: Relative(2) }, JumpIf { condition: Relative(10), location: 60 }, Const { destination: Relative(13), bit_size: Integer(U32), value: 0 }, Trap { revert_data: HeapVector { pointer: Direct(1), size: Relative(13) } }, BinaryFieldOp { destination: Relative(9), op: Equals, lhs: Relative(12), rhs: Relative(3) }, JumpIf { condition: Relative(9), location: 64 }, Const { destination: Relative(10), bit_size: Integer(U32), value: 0 }, Trap { revert_data: HeapVector { pointer: Direct(1), size: Relative(10) } }, Mov { destination: Relative(9), source: Direct(1) }, Const { destination: Relative(10), bit_size: Integer(U32), value: 4 }, BinaryIntOp { destination: Direct(1), op: Add, bit_size: U32, lhs: Direct(1), rhs: Relative(10) }, IndirectConst { destination_pointer: Relative(9), bit_size: Integer(U32), value: 1 }, BinaryIntOp { destination: Relative(10), op: Add, bit_size: U32, lhs: Relative(9), rhs: Direct(2) }, BlackBox(EmbeddedCurveAdd { input1_x: Relative(2), input1_y: Relative(3), input1_infinite: Relative(6), input2_x: Relative(2), input2_y: Relative(3), input2_infinite: Relative(6), result: HeapArray { pointer: Relative(10), size: 3 } }), BinaryIntOp { destination: Relative(12), op: Add, bit_size: U32, lhs: Relative(9), rhs: Relative(7) }, Load { destination: Relative(10), source_pointer: Relative(12) }, Const { destination: Relative(9), bit_size: Field, value: 3078034153852398078128400807926804309327113743808504829582559963737223069694 }, BinaryFieldOp { destination: Relative(12), op: Equals, lhs: Relative(9), rhs: Relative(10) }, JumpIf { condition: Relative(12), location: 77 }, Const { destination: Relative(13), bit_size: Integer(U32), value: 0 }, Trap { revert_data: HeapVector { pointer: Direct(1), size: Relative(13) } }, Mov { destination: Relative(10), source: Direct(1) }, Const { destination: Relative(12), bit_size: Integer(U32), value: 7 }, BinaryIntOp { destination: Direct(1), op: Add, bit_size: U32, lhs: Direct(1), rhs: Relative(12) }, IndirectConst { destination_pointer: Relative(10), bit_size: Integer(U32), value: 1 }, BinaryIntOp { destination: Relative(12), op: Add, bit_size: U32, lhs: Relative(10), rhs: Direct(2) }, Mov { destination: Relative(13), source: Relative(12) }, Store { destination_pointer: Relative(13), source: Relative(4) }, BinaryIntOp { destination: Relative(13), op: Add, bit_size: U32, lhs: Relative(13), rhs: Direct(2) }, Store { destination_pointer: Relative(13), source: Relative(5) }, BinaryIntOp { destination: Relative(13), op: Add, bit_size: U32, lhs: Relative(13), rhs: Direct(2) }, Store { destination_pointer: Relative(13), source: Relative(6) }, BinaryIntOp { destination: Relative(13), op: Add, bit_size: U32, lhs: Relative(13), rhs: Direct(2) }, Store { destination_pointer: Relative(13), source: Relative(4) }, BinaryIntOp { destination: Relative(13), op: Add, bit_size: U32, lhs: Relative(13), rhs: Direct(2) }, Store { destination_pointer: Relative(13), source: Relative(5) }, BinaryIntOp { destination: Relative(13), op: Add, bit_size: U32, lhs: Relative(13), rhs: Direct(2) }, Store { destination_pointer: Relative(13), source: Relative(6) }, Mov { destination: Relative(12), source: Direct(1) }, Const { destination: Relative(13), bit_size: Integer(U32), value: 5 }, BinaryIntOp { destination: Direct(1), op: Add, bit_size: U32, lhs: Direct(1), rhs: Relative(13) }, IndirectConst { destination_pointer: Relative(12), bit_size: Integer(U32), value: 1 }, BinaryIntOp { destination: Relative(13), op: Add, bit_size: U32, lhs: Relative(12), rhs: Direct(2) }, Mov { destination: Relative(14), source: Relative(13) }, Store { destination_pointer: Relative(14), source: Relative(1) }, BinaryIntOp { destination: Relative(14), op: Add, bit_size: U32, lhs: Relative(14), rhs: Direct(2) }, Store { destination_pointer: Relative(14), source: Relative(8) }, BinaryIntOp { destination: Relative(14), op: Add, bit_size: U32, lhs: Relative(14), rhs: Direct(2) }, Store { destination_pointer: Relative(14), source: Relative(1) }, BinaryIntOp { destination: Relative(14), op: Add, bit_size: U32, lhs: Relative(14), rhs: Direct(2) }, Store { destination_pointer: Relative(14), source: Relative(8) }, Mov { destination: Relative(13), source: Direct(1) }, Const { destination: Relative(14), bit_size: Integer(U32), value: 4 }, BinaryIntOp { destination: Direct(1), op: Add, bit_size: U32, lhs: Direct(1), rhs: Relative(14) }, IndirectConst { destination_pointer: Relative(13), bit_size: Integer(U32), value: 1 }, BinaryIntOp { destination: Relative(14), op: Add, bit_size: U32, lhs: Relative(10), rhs: Direct(2) }, Const { destination: Relative(15), bit_size: Integer(U32), value: 6 }, BinaryIntOp { destination: Relative(16), op: Add, bit_size: U32, lhs: Relative(12), rhs: Direct(2) }, Const { destination: Relative(17), bit_size: Integer(U32), value: 4 }, BinaryIntOp { destination: Relative(18), op: Add, bit_size: U32, lhs: Relative(13), rhs: Direct(2) }, BlackBox(MultiScalarMul { points: HeapVector { pointer: Relative(14), size: Relative(15) }, scalars: HeapVector { pointer: Relative(16), size: Relative(17) }, outputs: HeapArray { pointer: Relative(18), size: 3 } }), BinaryIntOp { destination: Relative(12), op: Add, bit_size: U32, lhs: Relative(13), rhs: Relative(7) }, Load { destination: Relative(10), source_pointer: Relative(12) }, BinaryFieldOp { destination: Relative(12), op: Equals, lhs: Relative(9), rhs: Relative(10) }, JumpIf { condition: Relative(12), location: 123 }, Const { destination: Relative(13), bit_size: Integer(U32), value: 0 }, Trap { revert_data: HeapVector { pointer: Direct(1), size: Relative(13) } }, Mov { destination: Relative(9), source: Direct(1) }, Const { destination: Relative(10), bit_size: Integer(U32), value: 7 }, BinaryIntOp { destination: Direct(1), op: Add, bit_size: U32, lhs: Direct(1), rhs: Relative(10) }, IndirectConst { destination_pointer: Relative(9), bit_size: Integer(U32), value: 1 }, BinaryIntOp { destination: Relative(10), op: Add, bit_size: U32, lhs: Relative(9), rhs: Direct(2) }, Mov { destination: Relative(12), source: Relative(10) }, Store { destination_pointer: Relative(12), source: Relative(1) }, BinaryIntOp { destination: Relative(12), op: Add, bit_size: U32, lhs: Relative(12), rhs: Direct(2) }, Store { destination_pointer: Relative(12), source: Relative(8) }, BinaryIntOp { destination: Relative(12), op: Add, bit_size: U32, lhs: Relative(12), rhs: Direct(2) }, Store { destination_pointer: Relative(12), source: Relative(1) }, BinaryIntOp { destination: Relative(12), op: Add, bit_size: U32, lhs: Relative(12), rhs: Direct(2) }, Store { destination_pointer: Relative(12), source: Relative(8) }, BinaryIntOp { destination: Relative(12), op: Add, bit_size: U32, lhs: Relative(12), rhs: Direct(2) }, Store { destination_pointer: Relative(12), source: Relative(4) }, BinaryIntOp { destination: Relative(12), op: Add, bit_size: U32, lhs: Relative(12), rhs: Direct(2) }, Store { destination_pointer: Relative(12), source: Relative(8) }, Const { destination: Relative(10), bit_size: Field, value: 11179562631109628533987091031692370366552561688588090155835439555627259799605 }, Const { destination: Relative(12), bit_size: Field, value: 3443719903172018228650470536370404288991794296383447657609081676265727805364 }, Mov { destination: Relative(13), source: Direct(1) }, Const { destination: Relative(14), bit_size: Integer(U32), value: 10 }, BinaryIntOp { destination: Direct(1), op: Add, bit_size: U32, lhs: Direct(1), rhs: Relative(14) }, IndirectConst { destination_pointer: Relative(13), bit_size: Integer(U32), value: 1 }, BinaryIntOp { destination: Relative(14), op: Add, bit_size: U32, lhs: Relative(13), rhs: Direct(2) }, Mov { destination: Relative(15), source: Relative(14) }, Store { destination_pointer: Relative(15), source: Relative(4) }, BinaryIntOp { destination: Relative(15), op: Add, bit_size: U32, lhs: Relative(15), rhs: Direct(2) }, Store { destination_pointer: Relative(15), source: Relative(5) }, BinaryIntOp { destination: Relative(15), op: Add, bit_size: U32, lhs: Relative(15), rhs: Direct(2) }, Store { destination_pointer: Relative(15), source: Relative(6) }, BinaryIntOp { destination: Relative(15), op: Add, bit_size: U32, lhs: Relative(15), rhs: Direct(2) }, Store { destination_pointer: Relative(15), source: Relative(2) }, BinaryIntOp { destination: Relative(15), op: Add, bit_size: U32, lhs: Relative(15), rhs: Direct(2) }, Store { destination_pointer: Relative(15), source: Relative(3) }, BinaryIntOp { destination: Relative(15), op: Add, bit_size: U32, lhs: Relative(15), rhs: Direct(2) }, Store { destination_pointer: Relative(15), source: Relative(6) }, BinaryIntOp { destination: Relative(15), op: Add, bit_size: U32, lhs: Relative(15), rhs: Direct(2) }, Store { destination_pointer: Relative(15), source: Relative(10) }, BinaryIntOp { destination: Relative(15), op: Add, bit_size: U32, lhs: Relative(15), rhs: Direct(2) }, Store { destination_pointer: Relative(15), source: Relative(12) }, BinaryIntOp { destination: Relative(15), op: Add, bit_size: U32, lhs: Relative(15), rhs: Direct(2) }, Store { destination_pointer: Relative(15), source: Relative(6) }, Mov { destination: Relative(2), source: Direct(1) }, Const { destination: Relative(3), bit_size: Integer(U32), value: 4 }, BinaryIntOp { destination: Direct(1), op: Add, bit_size: U32, lhs: Direct(1), rhs: Relative(3) }, IndirectConst { destination_pointer: Relative(2), bit_size: Integer(U32), value: 1 }, BinaryIntOp { destination: Relative(3), op: Add, bit_size: U32, lhs: Relative(13), rhs: Direct(2) }, Const { destination: Relative(10), bit_size: Integer(U32), value: 9 }, BinaryIntOp { destination: Relative(12), op: Add, bit_size: U32, lhs: Relative(9), rhs: Direct(2) }, Const { destination: Relative(14), bit_size: Integer(U32), value: 6 }, BinaryIntOp { destination: Relative(15), op: Add, bit_size: U32, lhs: Relative(2), rhs: Direct(2) }, BlackBox(MultiScalarMul { points: HeapVector { pointer: Relative(3), size: Relative(10) }, scalars: HeapVector { pointer: Relative(12), size: Relative(14) }, outputs: HeapArray { pointer: Relative(15), size: 3 } }), BinaryIntOp { destination: Relative(9), op: Add, bit_size: U32, lhs: Relative(2), rhs: Relative(7) }, Load { destination: Relative(3), source_pointer: Relative(9) }, Const { destination: Relative(2), bit_size: Field, value: -7349266043899242844836273743257843180744506495159104166319746739537754653274 }, BinaryFieldOp { destination: Relative(9), op: Equals, lhs: Relative(3), rhs: Relative(2) }, JumpIf { condition: Relative(9), location: 182 }, Const { destination: Relative(10), bit_size: Integer(U32), value: 0 }, Trap { revert_data: HeapVector { pointer: Direct(1), size: Relative(10) } }, Mov { destination: Relative(2), source: Direct(1) }, Const { destination: Relative(3), bit_size: Integer(U32), value: 3 }, BinaryIntOp { destination: Direct(1), op: Add, bit_size: U32, lhs: Direct(1), rhs: Relative(3) }, IndirectConst { destination_pointer: Relative(2), bit_size: Integer(U32), value: 1 }, BinaryIntOp { destination: Relative(3), op: Add, bit_size: U32, lhs: Relative(2), rhs: Direct(2) }, Mov { destination: Relative(9), source: Relative(3) }, Store { destination_pointer: Relative(9), source: Relative(1) }, BinaryIntOp { destination: Relative(9), op: Add, bit_size: U32, lhs: Relative(9), rhs: Direct(2) }, Store { destination_pointer: Relative(9), source: Relative(8) }, Mov { destination: Relative(1), source: Direct(1) }, Const { destination: Relative(3), bit_size: Integer(U32), value: 4 }, BinaryIntOp { destination: Direct(1), op: Add, bit_size: U32, lhs: Direct(1), rhs: Relative(3) }, IndirectConst { destination_pointer: Relative(1), bit_size: Integer(U32), value: 1 }, BinaryIntOp { destination: Relative(3), op: Add, bit_size: U32, lhs: Relative(1), rhs: Direct(2) }, Mov { destination: Relative(8), source: Relative(3) }, Store { destination_pointer: Relative(8), source: Relative(4) }, BinaryIntOp { destination: Relative(8), op: Add, bit_size: U32, lhs: Relative(8), rhs: Direct(2) }, Store { destination_pointer: Relative(8), source: Relative(5) }, BinaryIntOp { destination: Relative(8), op: Add, bit_size: U32, lhs: Relative(8), rhs: Direct(2) }, Store { destination_pointer: Relative(8), source: Relative(6) }, Mov { destination: Relative(3), source: Direct(1) }, Const { destination: Relative(8), bit_size: Integer(U32), value: 4 }, BinaryIntOp { destination: Direct(1), op: Add, bit_size: U32, lhs: Direct(1), rhs: Relative(8) }, IndirectConst { destination_pointer: Relative(3), bit_size: Integer(U32), value: 1 }, BinaryIntOp { destination: Relative(8), op: Add, bit_size: U32, lhs: Relative(1), rhs: Direct(2) }, Const { destination: Relative(9), bit_size: Integer(U32), value: 3 }, BinaryIntOp { destination: Relative(10), op: Add, bit_size: U32, lhs: Relative(2), rhs: Direct(2) }, Const { destination: Relative(12), bit_size: Integer(U32), value: 2 }, BinaryIntOp { destination: Relative(13), op: Add, bit_size: U32, lhs: Relative(3), rhs: Direct(2) }, BlackBox(MultiScalarMul { points: HeapVector { pointer: Relative(8), size: Relative(9) }, scalars: HeapVector { pointer: Relative(10), size: Relative(12) }, outputs: HeapArray { pointer: Relative(13), size: 3 } }), BinaryIntOp { destination: Relative(2), op: Add, bit_size: U32, lhs: Relative(3), rhs: Relative(7) }, Load { destination: Relative(1), source_pointer: Relative(2) }, BinaryIntOp { destination: Relative(7), op: Add, bit_size: U32, lhs: Relative(3), rhs: Relative(11) }, Load { destination: Relative(2), source_pointer: Relative(7) }, Const { destination: Relative(7), bit_size: Integer(U32), value: 3 }, BinaryIntOp { destination: Relative(9), op: Add, bit_size: U32, lhs: Relative(3), rhs: Relative(7) }, Load { destination: Relative(8), source_pointer: Relative(9) }, BinaryIntOp { destination: Relative(3), op: Equals, bit_size: U1, lhs: Relative(8), rhs: Relative(6) }, JumpIf { condition: Relative(3), location: 223 }, Const { destination: Relative(7), bit_size: Integer(U32), value: 0 }, Trap { revert_data: HeapVector { pointer: Direct(1), size: Relative(7) } }, BinaryFieldOp { destination: Relative(3), op: Equals, lhs: Relative(1), rhs: Relative(4) }, JumpIf { condition: Relative(3), location: 227 }, Const { destination: Relative(6), bit_size: Integer(U32), value: 0 }, Trap { revert_data: HeapVector { pointer: Direct(1), size: Relative(6) } }, BinaryFieldOp { destination: Relative(1), op: Equals, lhs: Relative(2), rhs: Relative(5) }, JumpIf { condition: Relative(1), location: 231 }, Const { destination: Relative(3), bit_size: Integer(U32), value: 0 }, Trap { revert_data: HeapVector { pointer: Direct(1), size: Relative(3) } }, Return, Const { destination: Direct(32772), bit_size: Integer(U32), value: 30720 }, BinaryIntOp { destination: Direct(32771), op: LessThan, bit_size: U32, lhs: Direct(0), rhs: Direct(32772) }, JumpIf { condition: Direct(32771), location: 237 }, IndirectConst { destination_pointer: Direct(1), bit_size: Integer(U64), value: 17843811134343075018 }, Trap { revert_data: HeapVector { pointer: Direct(1), size: Direct(2) } }, Return]" + "[Const { destination: Direct(2), bit_size: Integer(U32), value: 1 }, Const { destination: Direct(1), bit_size: Integer(U32), value: 32839 }, Const { destination: Direct(0), bit_size: Integer(U32), value: 3 }, Const { destination: Relative(4), bit_size: Integer(U32), value: 3 }, Const { destination: Relative(5), bit_size: Integer(U32), value: 0 }, CalldataCopy { destination_address: Direct(32836), size_address: Relative(4), offset_address: Relative(5) }, Mov { destination: Relative(1), source: Direct(32836) }, Mov { destination: Relative(2), source: Direct(32837) }, Mov { destination: Relative(3), source: Direct(32838) }, Call { location: 14 }, Call { location: 15 }, Const { destination: Relative(1), bit_size: Integer(U32), value: 32839 }, Const { destination: Relative(2), bit_size: Integer(U32), value: 0 }, Stop { return_data: HeapVector { pointer: Relative(1), size: Relative(2) } }, Return, Call { location: 349 }, Const { destination: Relative(4), bit_size: Field, value: 1 }, Const { destination: Relative(5), bit_size: Field, value: 17631683881184975370165255887551781615748388533673675138860 }, Const { destination: Relative(6), bit_size: Integer(U1), value: 0 }, Mov { destination: Relative(7), source: Direct(1) }, Const { destination: Relative(8), bit_size: Integer(U32), value: 4 }, BinaryIntOp { destination: Direct(1), op: Add, bit_size: U32, lhs: Direct(1), rhs: Relative(8) }, IndirectConst { destination_pointer: Relative(7), bit_size: Integer(U32), value: 1 }, BinaryIntOp { destination: Relative(8), op: Add, bit_size: U32, lhs: Relative(7), rhs: Direct(2) }, Mov { destination: Relative(9), source: Relative(8) }, Store { destination_pointer: Relative(9), source: Relative(4) }, BinaryIntOp { destination: Relative(9), op: Add, bit_size: U32, lhs: Relative(9), rhs: Direct(2) }, Store { destination_pointer: Relative(9), source: Relative(5) }, BinaryIntOp { destination: Relative(9), op: Add, bit_size: U32, lhs: Relative(9), rhs: Direct(2) }, Store { destination_pointer: Relative(9), source: Relative(6) }, Const { destination: Relative(8), bit_size: Field, value: 0 }, Mov { destination: Relative(9), source: Direct(1) }, Const { destination: Relative(10), bit_size: Integer(U32), value: 3 }, BinaryIntOp { destination: Direct(1), op: Add, bit_size: U32, lhs: Direct(1), rhs: Relative(10) }, IndirectConst { destination_pointer: Relative(9), bit_size: Integer(U32), value: 1 }, BinaryIntOp { destination: Relative(10), op: Add, bit_size: U32, lhs: Relative(9), rhs: Direct(2) }, Mov { destination: Relative(11), source: Relative(10) }, Store { destination_pointer: Relative(11), source: Relative(1) }, BinaryIntOp { destination: Relative(11), op: Add, bit_size: U32, lhs: Relative(11), rhs: Direct(2) }, Store { destination_pointer: Relative(11), source: Relative(8) }, Mov { destination: Relative(10), source: Direct(1) }, Const { destination: Relative(11), bit_size: Integer(U32), value: 4 }, BinaryIntOp { destination: Direct(1), op: Add, bit_size: U32, lhs: Direct(1), rhs: Relative(11) }, IndirectConst { destination_pointer: Relative(10), bit_size: Integer(U32), value: 1 }, BinaryIntOp { destination: Relative(11), op: Add, bit_size: U32, lhs: Relative(7), rhs: Direct(2) }, Const { destination: Relative(12), bit_size: Integer(U32), value: 3 }, BinaryIntOp { destination: Relative(13), op: Add, bit_size: U32, lhs: Relative(9), rhs: Direct(2) }, Const { destination: Relative(14), bit_size: Integer(U32), value: 2 }, BinaryIntOp { destination: Relative(15), op: Add, bit_size: U32, lhs: Relative(10), rhs: Direct(2) }, BlackBox(MultiScalarMul { points: HeapVector { pointer: Relative(11), size: Relative(12) }, scalars: HeapVector { pointer: Relative(13), size: Relative(14) }, outputs: HeapArray { pointer: Relative(15), size: 3 } }), Const { destination: Relative(7), bit_size: Integer(U32), value: 1 }, BinaryIntOp { destination: Relative(11), op: Add, bit_size: U32, lhs: Relative(10), rhs: Relative(7) }, Load { destination: Relative(9), source_pointer: Relative(11) }, Const { destination: Relative(11), bit_size: Integer(U32), value: 2 }, BinaryIntOp { destination: Relative(13), op: Add, bit_size: U32, lhs: Relative(10), rhs: Relative(11) }, Load { destination: Relative(12), source_pointer: Relative(13) }, BinaryFieldOp { destination: Relative(10), op: Equals, lhs: Relative(9), rhs: Relative(2) }, JumpIf { condition: Relative(10), location: 60 }, Const { destination: Relative(13), bit_size: Integer(U32), value: 0 }, Trap { revert_data: HeapVector { pointer: Direct(1), size: Relative(13) } }, BinaryFieldOp { destination: Relative(9), op: Equals, lhs: Relative(12), rhs: Relative(3) }, JumpIf { condition: Relative(9), location: 64 }, Const { destination: Relative(10), bit_size: Integer(U32), value: 0 }, Trap { revert_data: HeapVector { pointer: Direct(1), size: Relative(10) } }, Mov { destination: Relative(9), source: Direct(1) }, Const { destination: Relative(10), bit_size: Integer(U32), value: 4 }, BinaryIntOp { destination: Direct(1), op: Add, bit_size: U32, lhs: Direct(1), rhs: Relative(10) }, IndirectConst { destination_pointer: Relative(9), bit_size: Integer(U32), value: 1 }, BinaryIntOp { destination: Relative(10), op: Add, bit_size: U32, lhs: Relative(9), rhs: Direct(2) }, BlackBox(EmbeddedCurveAdd { input1_x: Relative(2), input1_y: Relative(3), input1_infinite: Relative(6), input2_x: Relative(2), input2_y: Relative(3), input2_infinite: Relative(6), result: HeapArray { pointer: Relative(10), size: 3 } }), BinaryIntOp { destination: Relative(12), op: Add, bit_size: U32, lhs: Relative(9), rhs: Relative(7) }, Load { destination: Relative(10), source_pointer: Relative(12) }, Const { destination: Relative(9), bit_size: Field, value: 3078034153852398078128400807926804309327113743808504829582559963737223069694 }, BinaryFieldOp { destination: Relative(12), op: Equals, lhs: Relative(9), rhs: Relative(10) }, JumpIf { condition: Relative(12), location: 77 }, Const { destination: Relative(13), bit_size: Integer(U32), value: 0 }, Trap { revert_data: HeapVector { pointer: Direct(1), size: Relative(13) } }, Mov { destination: Relative(10), source: Direct(1) }, Const { destination: Relative(12), bit_size: Integer(U32), value: 7 }, BinaryIntOp { destination: Direct(1), op: Add, bit_size: U32, lhs: Direct(1), rhs: Relative(12) }, IndirectConst { destination_pointer: Relative(10), bit_size: Integer(U32), value: 1 }, BinaryIntOp { destination: Relative(12), op: Add, bit_size: U32, lhs: Relative(10), rhs: Direct(2) }, Mov { destination: Relative(13), source: Relative(12) }, Store { destination_pointer: Relative(13), source: Relative(4) }, BinaryIntOp { destination: Relative(13), op: Add, bit_size: U32, lhs: Relative(13), rhs: Direct(2) }, Store { destination_pointer: Relative(13), source: Relative(5) }, BinaryIntOp { destination: Relative(13), op: Add, bit_size: U32, lhs: Relative(13), rhs: Direct(2) }, Store { destination_pointer: Relative(13), source: Relative(6) }, BinaryIntOp { destination: Relative(13), op: Add, bit_size: U32, lhs: Relative(13), rhs: Direct(2) }, Store { destination_pointer: Relative(13), source: Relative(4) }, BinaryIntOp { destination: Relative(13), op: Add, bit_size: U32, lhs: Relative(13), rhs: Direct(2) }, Store { destination_pointer: Relative(13), source: Relative(5) }, BinaryIntOp { destination: Relative(13), op: Add, bit_size: U32, lhs: Relative(13), rhs: Direct(2) }, Store { destination_pointer: Relative(13), source: Relative(6) }, Mov { destination: Relative(12), source: Direct(1) }, Const { destination: Relative(13), bit_size: Integer(U32), value: 5 }, BinaryIntOp { destination: Direct(1), op: Add, bit_size: U32, lhs: Direct(1), rhs: Relative(13) }, IndirectConst { destination_pointer: Relative(12), bit_size: Integer(U32), value: 1 }, BinaryIntOp { destination: Relative(13), op: Add, bit_size: U32, lhs: Relative(12), rhs: Direct(2) }, Mov { destination: Relative(14), source: Relative(13) }, Store { destination_pointer: Relative(14), source: Relative(1) }, BinaryIntOp { destination: Relative(14), op: Add, bit_size: U32, lhs: Relative(14), rhs: Direct(2) }, Store { destination_pointer: Relative(14), source: Relative(8) }, BinaryIntOp { destination: Relative(14), op: Add, bit_size: U32, lhs: Relative(14), rhs: Direct(2) }, Store { destination_pointer: Relative(14), source: Relative(1) }, BinaryIntOp { destination: Relative(14), op: Add, bit_size: U32, lhs: Relative(14), rhs: Direct(2) }, Store { destination_pointer: Relative(14), source: Relative(8) }, Mov { destination: Relative(13), source: Direct(1) }, Const { destination: Relative(14), bit_size: Integer(U32), value: 4 }, BinaryIntOp { destination: Direct(1), op: Add, bit_size: U32, lhs: Direct(1), rhs: Relative(14) }, IndirectConst { destination_pointer: Relative(13), bit_size: Integer(U32), value: 1 }, BinaryIntOp { destination: Relative(14), op: Add, bit_size: U32, lhs: Relative(10), rhs: Direct(2) }, Const { destination: Relative(15), bit_size: Integer(U32), value: 6 }, BinaryIntOp { destination: Relative(16), op: Add, bit_size: U32, lhs: Relative(12), rhs: Direct(2) }, Const { destination: Relative(17), bit_size: Integer(U32), value: 4 }, BinaryIntOp { destination: Relative(18), op: Add, bit_size: U32, lhs: Relative(13), rhs: Direct(2) }, BlackBox(MultiScalarMul { points: HeapVector { pointer: Relative(14), size: Relative(15) }, scalars: HeapVector { pointer: Relative(16), size: Relative(17) }, outputs: HeapArray { pointer: Relative(18), size: 3 } }), BinaryIntOp { destination: Relative(12), op: Add, bit_size: U32, lhs: Relative(13), rhs: Relative(7) }, Load { destination: Relative(10), source_pointer: Relative(12) }, BinaryFieldOp { destination: Relative(12), op: Equals, lhs: Relative(9), rhs: Relative(10) }, JumpIf { condition: Relative(12), location: 123 }, Const { destination: Relative(13), bit_size: Integer(U32), value: 0 }, Trap { revert_data: HeapVector { pointer: Direct(1), size: Relative(13) } }, Mov { destination: Relative(9), source: Direct(1) }, Const { destination: Relative(10), bit_size: Integer(U32), value: 7 }, BinaryIntOp { destination: Direct(1), op: Add, bit_size: U32, lhs: Direct(1), rhs: Relative(10) }, IndirectConst { destination_pointer: Relative(9), bit_size: Integer(U32), value: 1 }, BinaryIntOp { destination: Relative(10), op: Add, bit_size: U32, lhs: Relative(9), rhs: Direct(2) }, Mov { destination: Relative(12), source: Relative(10) }, Store { destination_pointer: Relative(12), source: Relative(1) }, BinaryIntOp { destination: Relative(12), op: Add, bit_size: U32, lhs: Relative(12), rhs: Direct(2) }, Store { destination_pointer: Relative(12), source: Relative(8) }, BinaryIntOp { destination: Relative(12), op: Add, bit_size: U32, lhs: Relative(12), rhs: Direct(2) }, Store { destination_pointer: Relative(12), source: Relative(1) }, BinaryIntOp { destination: Relative(12), op: Add, bit_size: U32, lhs: Relative(12), rhs: Direct(2) }, Store { destination_pointer: Relative(12), source: Relative(8) }, BinaryIntOp { destination: Relative(12), op: Add, bit_size: U32, lhs: Relative(12), rhs: Direct(2) }, Store { destination_pointer: Relative(12), source: Relative(4) }, BinaryIntOp { destination: Relative(12), op: Add, bit_size: U32, lhs: Relative(12), rhs: Direct(2) }, Store { destination_pointer: Relative(12), source: Relative(8) }, Const { destination: Relative(10), bit_size: Field, value: 11179562631109628533987091031692370366552561688588090155835439555627259799605 }, Const { destination: Relative(12), bit_size: Field, value: 3443719903172018228650470536370404288991794296383447657609081676265727805364 }, Mov { destination: Relative(13), source: Direct(1) }, Const { destination: Relative(14), bit_size: Integer(U32), value: 10 }, BinaryIntOp { destination: Direct(1), op: Add, bit_size: U32, lhs: Direct(1), rhs: Relative(14) }, IndirectConst { destination_pointer: Relative(13), bit_size: Integer(U32), value: 1 }, BinaryIntOp { destination: Relative(14), op: Add, bit_size: U32, lhs: Relative(13), rhs: Direct(2) }, Mov { destination: Relative(15), source: Relative(14) }, Store { destination_pointer: Relative(15), source: Relative(4) }, BinaryIntOp { destination: Relative(15), op: Add, bit_size: U32, lhs: Relative(15), rhs: Direct(2) }, Store { destination_pointer: Relative(15), source: Relative(5) }, BinaryIntOp { destination: Relative(15), op: Add, bit_size: U32, lhs: Relative(15), rhs: Direct(2) }, Store { destination_pointer: Relative(15), source: Relative(6) }, BinaryIntOp { destination: Relative(15), op: Add, bit_size: U32, lhs: Relative(15), rhs: Direct(2) }, Store { destination_pointer: Relative(15), source: Relative(2) }, BinaryIntOp { destination: Relative(15), op: Add, bit_size: U32, lhs: Relative(15), rhs: Direct(2) }, Store { destination_pointer: Relative(15), source: Relative(3) }, BinaryIntOp { destination: Relative(15), op: Add, bit_size: U32, lhs: Relative(15), rhs: Direct(2) }, Store { destination_pointer: Relative(15), source: Relative(6) }, BinaryIntOp { destination: Relative(15), op: Add, bit_size: U32, lhs: Relative(15), rhs: Direct(2) }, Store { destination_pointer: Relative(15), source: Relative(10) }, BinaryIntOp { destination: Relative(15), op: Add, bit_size: U32, lhs: Relative(15), rhs: Direct(2) }, Store { destination_pointer: Relative(15), source: Relative(12) }, BinaryIntOp { destination: Relative(15), op: Add, bit_size: U32, lhs: Relative(15), rhs: Direct(2) }, Store { destination_pointer: Relative(15), source: Relative(6) }, Mov { destination: Relative(10), source: Direct(1) }, Const { destination: Relative(12), bit_size: Integer(U32), value: 4 }, BinaryIntOp { destination: Direct(1), op: Add, bit_size: U32, lhs: Direct(1), rhs: Relative(12) }, IndirectConst { destination_pointer: Relative(10), bit_size: Integer(U32), value: 1 }, BinaryIntOp { destination: Relative(12), op: Add, bit_size: U32, lhs: Relative(13), rhs: Direct(2) }, Const { destination: Relative(14), bit_size: Integer(U32), value: 9 }, BinaryIntOp { destination: Relative(15), op: Add, bit_size: U32, lhs: Relative(9), rhs: Direct(2) }, Const { destination: Relative(16), bit_size: Integer(U32), value: 6 }, BinaryIntOp { destination: Relative(17), op: Add, bit_size: U32, lhs: Relative(10), rhs: Direct(2) }, BlackBox(MultiScalarMul { points: HeapVector { pointer: Relative(12), size: Relative(14) }, scalars: HeapVector { pointer: Relative(15), size: Relative(16) }, outputs: HeapArray { pointer: Relative(17), size: 3 } }), BinaryIntOp { destination: Relative(12), op: Add, bit_size: U32, lhs: Relative(10), rhs: Relative(7) }, Load { destination: Relative(9), source_pointer: Relative(12) }, Const { destination: Relative(10), bit_size: Field, value: -7349266043899242844836273743257843180744506495159104166319746739537754653274 }, BinaryFieldOp { destination: Relative(12), op: Equals, lhs: Relative(9), rhs: Relative(10) }, JumpIf { condition: Relative(12), location: 182 }, Const { destination: Relative(13), bit_size: Integer(U32), value: 0 }, Trap { revert_data: HeapVector { pointer: Direct(1), size: Relative(13) } }, Mov { destination: Relative(9), source: Direct(1) }, Const { destination: Relative(10), bit_size: Integer(U32), value: 3 }, BinaryIntOp { destination: Direct(1), op: Add, bit_size: U32, lhs: Direct(1), rhs: Relative(10) }, IndirectConst { destination_pointer: Relative(9), bit_size: Integer(U32), value: 1 }, BinaryIntOp { destination: Relative(10), op: Add, bit_size: U32, lhs: Relative(9), rhs: Direct(2) }, Mov { destination: Relative(12), source: Relative(10) }, Store { destination_pointer: Relative(12), source: Relative(1) }, BinaryIntOp { destination: Relative(12), op: Add, bit_size: U32, lhs: Relative(12), rhs: Direct(2) }, Store { destination_pointer: Relative(12), source: Relative(8) }, Mov { destination: Relative(1), source: Direct(1) }, Const { destination: Relative(8), bit_size: Integer(U32), value: 4 }, BinaryIntOp { destination: Direct(1), op: Add, bit_size: U32, lhs: Direct(1), rhs: Relative(8) }, IndirectConst { destination_pointer: Relative(1), bit_size: Integer(U32), value: 1 }, BinaryIntOp { destination: Relative(8), op: Add, bit_size: U32, lhs: Relative(1), rhs: Direct(2) }, Mov { destination: Relative(10), source: Relative(8) }, Store { destination_pointer: Relative(10), source: Relative(4) }, BinaryIntOp { destination: Relative(10), op: Add, bit_size: U32, lhs: Relative(10), rhs: Direct(2) }, Store { destination_pointer: Relative(10), source: Relative(5) }, BinaryIntOp { destination: Relative(10), op: Add, bit_size: U32, lhs: Relative(10), rhs: Direct(2) }, Store { destination_pointer: Relative(10), source: Relative(6) }, Mov { destination: Relative(8), source: Direct(1) }, Const { destination: Relative(10), bit_size: Integer(U32), value: 4 }, BinaryIntOp { destination: Direct(1), op: Add, bit_size: U32, lhs: Direct(1), rhs: Relative(10) }, IndirectConst { destination_pointer: Relative(8), bit_size: Integer(U32), value: 1 }, BinaryIntOp { destination: Relative(10), op: Add, bit_size: U32, lhs: Relative(1), rhs: Direct(2) }, Const { destination: Relative(12), bit_size: Integer(U32), value: 3 }, BinaryIntOp { destination: Relative(13), op: Add, bit_size: U32, lhs: Relative(9), rhs: Direct(2) }, Const { destination: Relative(14), bit_size: Integer(U32), value: 2 }, BinaryIntOp { destination: Relative(15), op: Add, bit_size: U32, lhs: Relative(8), rhs: Direct(2) }, BlackBox(MultiScalarMul { points: HeapVector { pointer: Relative(10), size: Relative(12) }, scalars: HeapVector { pointer: Relative(13), size: Relative(14) }, outputs: HeapArray { pointer: Relative(15), size: 3 } }), BinaryIntOp { destination: Relative(9), op: Add, bit_size: U32, lhs: Relative(8), rhs: Relative(7) }, Load { destination: Relative(1), source_pointer: Relative(9) }, BinaryIntOp { destination: Relative(10), op: Add, bit_size: U32, lhs: Relative(8), rhs: Relative(11) }, Load { destination: Relative(9), source_pointer: Relative(10) }, Const { destination: Relative(10), bit_size: Integer(U32), value: 3 }, BinaryIntOp { destination: Relative(12), op: Add, bit_size: U32, lhs: Relative(8), rhs: Relative(10) }, Load { destination: Relative(11), source_pointer: Relative(12) }, BinaryIntOp { destination: Relative(8), op: Equals, bit_size: U1, lhs: Relative(11), rhs: Relative(6) }, JumpIf { condition: Relative(8), location: 223 }, Const { destination: Relative(10), bit_size: Integer(U32), value: 0 }, Trap { revert_data: HeapVector { pointer: Direct(1), size: Relative(10) } }, BinaryFieldOp { destination: Relative(8), op: Equals, lhs: Relative(1), rhs: Relative(4) }, JumpIf { condition: Relative(8), location: 227 }, Const { destination: Relative(10), bit_size: Integer(U32), value: 0 }, Trap { revert_data: HeapVector { pointer: Direct(1), size: Relative(10) } }, BinaryFieldOp { destination: Relative(1), op: Equals, lhs: Relative(9), rhs: Relative(5) }, JumpIf { condition: Relative(1), location: 231 }, Const { destination: Relative(8), bit_size: Integer(U32), value: 0 }, Trap { revert_data: HeapVector { pointer: Direct(1), size: Relative(8) } }, BinaryFieldOp { destination: Relative(1), op: Equals, lhs: Relative(2), rhs: Relative(3) }, JumpIf { condition: Relative(1), location: 234 }, Jump { location: 348 }, Const { destination: Relative(1), bit_size: Field, value: 2 }, Mov { destination: Relative(5), source: Direct(1) }, Const { destination: Relative(8), bit_size: Integer(U32), value: 4 }, BinaryIntOp { destination: Direct(1), op: Add, bit_size: U32, lhs: Direct(1), rhs: Relative(8) }, IndirectConst { destination_pointer: Relative(5), bit_size: Integer(U32), value: 1 }, BinaryIntOp { destination: Relative(8), op: Add, bit_size: U32, lhs: Relative(5), rhs: Direct(2) }, BlackBox(EmbeddedCurveAdd { input1_x: Relative(4), input1_y: Relative(1), input1_infinite: Relative(6), input2_x: Relative(4), input2_y: Relative(1), input2_infinite: Relative(6), result: HeapArray { pointer: Relative(8), size: 3 } }), BinaryIntOp { destination: Relative(9), op: Add, bit_size: U32, lhs: Relative(5), rhs: Relative(7) }, Load { destination: Relative(8), source_pointer: Relative(9) }, BinaryFieldOp { destination: Relative(5), op: Equals, lhs: Relative(8), rhs: Relative(4) }, JumpIf { condition: Relative(5), location: 247 }, Const { destination: Relative(9), bit_size: Integer(U32), value: 0 }, Trap { revert_data: HeapVector { pointer: Direct(1), size: Relative(9) } }, Const { destination: Relative(5), bit_size: Field, value: 3 }, Mov { destination: Relative(8), source: Direct(1) }, Const { destination: Relative(9), bit_size: Integer(U32), value: 4 }, BinaryIntOp { destination: Direct(1), op: Add, bit_size: U32, lhs: Direct(1), rhs: Relative(9) }, IndirectConst { destination_pointer: Relative(8), bit_size: Integer(U32), value: 1 }, BinaryIntOp { destination: Relative(9), op: Add, bit_size: U32, lhs: Relative(8), rhs: Direct(2) }, BlackBox(EmbeddedCurveAdd { input1_x: Relative(4), input1_y: Relative(1), input1_infinite: Relative(6), input2_x: Relative(4), input2_y: Relative(5), input2_infinite: Relative(6), result: HeapArray { pointer: Relative(9), size: 3 } }), BinaryIntOp { destination: Relative(10), op: Add, bit_size: U32, lhs: Relative(8), rhs: Relative(7) }, Load { destination: Relative(9), source_pointer: Relative(10) }, BinaryFieldOp { destination: Relative(8), op: Equals, lhs: Relative(9), rhs: Relative(4) }, JumpIf { condition: Relative(8), location: 260 }, Const { destination: Relative(10), bit_size: Integer(U32), value: 0 }, Trap { revert_data: HeapVector { pointer: Direct(1), size: Relative(10) } }, BinaryFieldOp { destination: Relative(8), op: Add, lhs: Relative(2), rhs: Relative(4) }, BinaryFieldOp { destination: Relative(9), op: Add, lhs: Relative(3), rhs: Relative(4) }, Mov { destination: Relative(10), source: Direct(1) }, Const { destination: Relative(11), bit_size: Integer(U32), value: 4 }, BinaryIntOp { destination: Direct(1), op: Add, bit_size: U32, lhs: Direct(1), rhs: Relative(11) }, IndirectConst { destination_pointer: Relative(10), bit_size: Integer(U32), value: 1 }, BinaryIntOp { destination: Relative(11), op: Add, bit_size: U32, lhs: Relative(10), rhs: Direct(2) }, BlackBox(EmbeddedCurveAdd { input1_x: Relative(8), input1_y: Relative(3), input1_infinite: Relative(6), input2_x: Relative(8), input2_y: Relative(3), input2_infinite: Relative(6), result: HeapArray { pointer: Relative(11), size: 3 } }), BinaryIntOp { destination: Relative(12), op: Add, bit_size: U32, lhs: Relative(10), rhs: Relative(7) }, Load { destination: Relative(11), source_pointer: Relative(12) }, BinaryFieldOp { destination: Relative(10), op: Equals, lhs: Relative(11), rhs: Relative(4) }, JumpIf { condition: Relative(10), location: 274 }, Const { destination: Relative(12), bit_size: Integer(U32), value: 0 }, Trap { revert_data: HeapVector { pointer: Direct(1), size: Relative(12) } }, Mov { destination: Relative(10), source: Direct(1) }, Const { destination: Relative(11), bit_size: Integer(U32), value: 4 }, BinaryIntOp { destination: Direct(1), op: Add, bit_size: U32, lhs: Direct(1), rhs: Relative(11) }, IndirectConst { destination_pointer: Relative(10), bit_size: Integer(U32), value: 1 }, BinaryIntOp { destination: Relative(11), op: Add, bit_size: U32, lhs: Relative(10), rhs: Direct(2) }, BlackBox(EmbeddedCurveAdd { input1_x: Relative(8), input1_y: Relative(3), input1_infinite: Relative(6), input2_x: Relative(8), input2_y: Relative(9), input2_infinite: Relative(6), result: HeapArray { pointer: Relative(11), size: 3 } }), BinaryIntOp { destination: Relative(8), op: Add, bit_size: U32, lhs: Relative(10), rhs: Relative(7) }, Load { destination: Relative(3), source_pointer: Relative(8) }, BinaryFieldOp { destination: Relative(8), op: Equals, lhs: Relative(3), rhs: Relative(4) }, JumpIf { condition: Relative(8), location: 286 }, Const { destination: Relative(10), bit_size: Integer(U32), value: 0 }, Trap { revert_data: HeapVector { pointer: Direct(1), size: Relative(10) } }, Mov { destination: Relative(3), source: Direct(1) }, Const { destination: Relative(8), bit_size: Integer(U32), value: 4 }, BinaryIntOp { destination: Direct(1), op: Add, bit_size: U32, lhs: Direct(1), rhs: Relative(8) }, IndirectConst { destination_pointer: Relative(3), bit_size: Integer(U32), value: 1 }, BinaryIntOp { destination: Relative(8), op: Add, bit_size: U32, lhs: Relative(3), rhs: Direct(2) }, BlackBox(EmbeddedCurveAdd { input1_x: Relative(1), input1_y: Relative(5), input1_infinite: Relative(6), input2_x: Relative(2), input2_y: Relative(9), input2_infinite: Relative(6), result: HeapArray { pointer: Relative(8), size: 3 } }), BinaryIntOp { destination: Relative(9), op: Add, bit_size: U32, lhs: Relative(3), rhs: Relative(7) }, Load { destination: Relative(8), source_pointer: Relative(9) }, BinaryFieldOp { destination: Relative(3), op: Equals, lhs: Relative(8), rhs: Relative(4) }, JumpIf { condition: Relative(3), location: 298 }, Const { destination: Relative(9), bit_size: Integer(U32), value: 0 }, Trap { revert_data: HeapVector { pointer: Direct(1), size: Relative(9) } }, Const { destination: Relative(3), bit_size: Field, value: 4 }, Mov { destination: Relative(8), source: Direct(1) }, Const { destination: Relative(9), bit_size: Integer(U32), value: 4 }, BinaryIntOp { destination: Direct(1), op: Add, bit_size: U32, lhs: Direct(1), rhs: Relative(9) }, IndirectConst { destination_pointer: Relative(8), bit_size: Integer(U32), value: 1 }, BinaryIntOp { destination: Relative(9), op: Add, bit_size: U32, lhs: Relative(8), rhs: Direct(2) }, BlackBox(EmbeddedCurveAdd { input1_x: Relative(1), input1_y: Relative(5), input1_infinite: Relative(6), input2_x: Relative(1), input2_y: Relative(3), input2_infinite: Relative(6), result: HeapArray { pointer: Relative(9), size: 3 } }), BinaryIntOp { destination: Relative(9), op: Add, bit_size: U32, lhs: Relative(8), rhs: Relative(7) }, Load { destination: Relative(3), source_pointer: Relative(9) }, BinaryFieldOp { destination: Relative(8), op: Equals, lhs: Relative(3), rhs: Relative(4) }, JumpIf { condition: Relative(8), location: 311 }, Const { destination: Relative(9), bit_size: Integer(U32), value: 0 }, Trap { revert_data: HeapVector { pointer: Direct(1), size: Relative(9) } }, Mov { destination: Relative(3), source: Direct(1) }, Const { destination: Relative(8), bit_size: Integer(U32), value: 4 }, BinaryIntOp { destination: Direct(1), op: Add, bit_size: U32, lhs: Direct(1), rhs: Relative(8) }, IndirectConst { destination_pointer: Relative(3), bit_size: Integer(U32), value: 1 }, BinaryIntOp { destination: Relative(8), op: Add, bit_size: U32, lhs: Relative(3), rhs: Direct(2) }, BlackBox(EmbeddedCurveAdd { input1_x: Relative(1), input1_y: Relative(5), input1_infinite: Relative(6), input2_x: Relative(1), input2_y: Relative(5), input2_infinite: Relative(6), result: HeapArray { pointer: Relative(8), size: 3 } }), BinaryIntOp { destination: Relative(9), op: Add, bit_size: U32, lhs: Relative(3), rhs: Relative(7) }, Load { destination: Relative(8), source_pointer: Relative(9) }, BinaryFieldOp { destination: Relative(3), op: Equals, lhs: Relative(8), rhs: Relative(4) }, JumpIf { condition: Relative(3), location: 323 }, Const { destination: Relative(9), bit_size: Integer(U32), value: 0 }, Trap { revert_data: HeapVector { pointer: Direct(1), size: Relative(9) } }, Mov { destination: Relative(3), source: Direct(1) }, Const { destination: Relative(8), bit_size: Integer(U32), value: 4 }, BinaryIntOp { destination: Direct(1), op: Add, bit_size: U32, lhs: Direct(1), rhs: Relative(8) }, IndirectConst { destination_pointer: Relative(3), bit_size: Integer(U32), value: 1 }, BinaryIntOp { destination: Relative(8), op: Add, bit_size: U32, lhs: Relative(3), rhs: Direct(2) }, BlackBox(EmbeddedCurveAdd { input1_x: Relative(4), input1_y: Relative(5), input1_infinite: Relative(6), input2_x: Relative(4), input2_y: Relative(5), input2_infinite: Relative(6), result: HeapArray { pointer: Relative(8), size: 3 } }), BinaryIntOp { destination: Relative(9), op: Add, bit_size: U32, lhs: Relative(3), rhs: Relative(7) }, Load { destination: Relative(8), source_pointer: Relative(9) }, BinaryFieldOp { destination: Relative(3), op: Equals, lhs: Relative(8), rhs: Relative(4) }, JumpIf { condition: Relative(3), location: 335 }, Const { destination: Relative(9), bit_size: Integer(U32), value: 0 }, Trap { revert_data: HeapVector { pointer: Direct(1), size: Relative(9) } }, Mov { destination: Relative(3), source: Direct(1) }, Const { destination: Relative(8), bit_size: Integer(U32), value: 4 }, BinaryIntOp { destination: Direct(1), op: Add, bit_size: U32, lhs: Direct(1), rhs: Relative(8) }, IndirectConst { destination_pointer: Relative(3), bit_size: Integer(U32), value: 1 }, BinaryIntOp { destination: Relative(8), op: Add, bit_size: U32, lhs: Relative(3), rhs: Direct(2) }, BlackBox(EmbeddedCurveAdd { input1_x: Relative(2), input1_y: Relative(5), input1_infinite: Relative(6), input2_x: Relative(2), input2_y: Relative(1), input2_infinite: Relative(6), result: HeapArray { pointer: Relative(8), size: 3 } }), BinaryIntOp { destination: Relative(2), op: Add, bit_size: U32, lhs: Relative(3), rhs: Relative(7) }, Load { destination: Relative(1), source_pointer: Relative(2) }, BinaryFieldOp { destination: Relative(2), op: Equals, lhs: Relative(1), rhs: Relative(4) }, JumpIf { condition: Relative(2), location: 347 }, Const { destination: Relative(3), bit_size: Integer(U32), value: 0 }, Trap { revert_data: HeapVector { pointer: Direct(1), size: Relative(3) } }, Jump { location: 348 }, Return, Const { destination: Direct(32772), bit_size: Integer(U32), value: 30720 }, BinaryIntOp { destination: Direct(32771), op: LessThan, bit_size: U32, lhs: Direct(0), rhs: Direct(32772) }, JumpIf { condition: Direct(32771), location: 354 }, IndirectConst { destination_pointer: Direct(1), bit_size: Integer(U64), value: 17843811134343075018 }, Trap { revert_data: HeapVector { pointer: Direct(1), size: Direct(2) } }, Return]" ], - "debug_symbols": "tZfRTioxEIbfZa+5aDszbcdXMcagroaEAEE4yYnh3U+7Mz/qxRqzHm/4PsR+pN0thbfhaXw4v9xvds/71+Hm9m14OG62283L/Xb/uD5t9rv217ch9IeYh5u4GmIxVINOSMEQDclABjaIwSrJKskqySpkFbIKWYWsQlYhq5BVyCpkFbIKtwo1REMykIENYsiGYqgGnSCtwg3RkAxkYIMYWkUaiqEadEJuldwQDclAhj6j0CjO7CzO6lRj6avT5leis69PaiQnO8WZncVZnWqswRmd3qveq96r3qveq96r3qveU++p99R76j31nnpPvafeU++p92IIkAhJEIIwRCAZ0rvcpULUJQZIhCQIQRgikAzpZelSIb3crmmcNsIkEZIgvVy7MEQgGVIgFaIu0+aYJEISBGVCmVAmlAllQplQZpQZZUaZUWaUGWVGmVFmlBllQVlQFpQFZUFZUBaUBWVBWVDOKGeUM8oZ5YxyRjmjnFHOKGeUC8oF5YJyQbmgPO017ZIhrZxClwpRl77hTCKklVO/V/ueM2GIQDKkQCpEXfrWM4kQlBVlRVlRVpQVZUVZvZxCgERIghCEIQLJkAKpEJQjyhHlvgcTdSEIQwSSIQVSIb3M/fQJkAhJEIIwRCAZUiAVgjJN5ctlNeB4vD8dx7Gfjh/Oy3aKHtbHcXcabnbn7XY1/Flvz9M/vR7Wu4mn9bG92m6BcffU2ILPm+3Y7bJ6Hx3mhybKPjhRuQ6Xb4+nvuLTeCo6Nz7Nj2dR9gBnfp9AzMsKNFf4ag6KOXDIC9aAEy4AEy8YnxnXIOc0N758MT5FjJc4N//6xfjAikDQ2Wug84V27IXiiebC/6FRFlzJci2UtORK1Ig7odY4Nz7Sj2/n7yeW3M96DbRvPHHBMrRvBNcC19mFjOXnC1F+cyHaF4jrHSU1LFmJmgQFZZn9gIs//4SLv7oSKvU6j/J5Hnft2fpxc/z0U+3SW8fN+mE7+tPn8+7xw6unvwe8gp96h+P+cXw6H8de+vB7rz3eJkqrdsLcXfr7/QM=", + "debug_symbols": "tZndThs9EIbvJccc2J4f29xKVaEAoYoUBZTCJ31C3Htndvwm9GBR2SQnfR9K/TT2euxZ5X31uLl/+3W33T89/17d/nhf3R+2u932193u+WH9un3e29++r5L/kXV1m29WuUa0iD5FSRE5okRQBEdIRFhKWEpYSlgoLBQWCguFhcJCYaGwUFgoLBQWNgtZ5IgSQREcIREaUSNaRJ9CzMIWOaJEUARHSIRZxKJGtIg+hZpFLXJEiaAIn1GylJE6so5sI3tk9dWx+dU80tenWNJIHikjdWQd2Ub2yJZG5pHD14avDV8bvjZ8bfja8LXh68PXh68PXx++Pnx9+Prw9eHrw9eHL6cEyIACIAADBKAA97JDA/QBOQEyoAAIwAABKMDN4tAAbrZnmqdCmCADCsDNzYEBAlBABTRAHzAVxwQZUAAwE8wEM8FMMBPMBDPDzDAzzAwzw8wwM8wMM8PMMAvMArPALDALzAKzwCwwC8wCs8KsMCvMCrPCrDArzAqzwqwwV5grzBXmCnOFeaq17qAAM5fk0AB9gBdcQAaYufhe9ZoLYIAAFFABDdAHeOkFZADMHeYOc4e5w9xh7jD3YS4pATKgAAjAAAEooAIaAOYMc4bZa7CQAwEYIAAFVEADuJn99kmADCgAAjBAAAqogAaAmWD2Gizi4J7uIAAFVEAD9AFecQF+SSWHAvCLaro1GSAABfiF5VOerqwJ+gCvuIAMKAACuNln4RUX4GafjldcQAP0AV5xpA5urg5+KU5XOgEYIAAFVICZ2R+3V9wEXnHsH8wrLqAACOBm/xhecQEKqIAG6AO84tg/s1dcgJv9w3vFBTBAAG72p+MVF9AAfYBXXEAGmFn8CXrFBZhZpu5GAAqoAG8XfIJecQ7kFReQAQVAAAa4mR0U4GZxaIA+wCsuwM3VoQAIwAABKMDNzaEB3Ny9U0uADCgAb3ambo4BAlBABTSAmbV485cA3kL5lP3WCyAAA9zsE/QaDKiABugDvAYD3KwOBeBmn7LXYIAA3Fw/Pm5WaJDvXg+bjffHnzpm66Nf1ofN/nV1u3/b7W5W/613b9M/+v2y3k/5uj7Yb22bbPaPliZ82u42Th83p9Fpfqjt1zHYNuxxuPzzeKp5jOfS5saX+fEsnSFQPk0g6zIDzRm+mAPzcQ4iC9aAtWN8owXjteMZ1Jznxtcvxhd8fpU8N//2xfjEmICmPvsM+rzBGt9Uh8JY+AKOuuBJVlGsZF3yJJpiJTulufGZzt7O/65Ysp/tdYawkEnTgnWwPv9oEJpdyVzPX4l61ZUQxoawzr4vWYlW8RmsneXZEy6ff8Tla66EteAoLuu9ecFKWGONe8Za60UGEszC+tvZXVX0zKOu1LPPutIucNh9R7LktLNXgnJcz16XPBH2988wsMzePVQusBrfkSxaDdbTXGpbshqixx0uuuS0sBeMo6HyIkPLxzptZbYjo3ZmjVA/u0Y4XWBXfEeyaFc0/tTgpkVPpGE97TVt9txjvsRq8JVXo9NpLpyX9PuloDOwV7DZ/cmXOD/5yuenvTGe5rKocyfuqBQSKnMGucT5KVc+P+1yPs1FlpxdVCtqjVqaPYFFL7EaeuXVaOU0F1r0VpgEdwGn+d2llzhF9cqnKNu3KJiLfe2xZDWIUGtMOntu6CVOUb3yKcq2I45z6X8/2Z/20/phe/jrm88Pdx226/vdZvz49LZ/+PTb1/9f8Bt8c/pyeH7YPL4dNm769PWp/fnDjp0bK9efH/7//QE=", "file_map": { "16": { "source": "use crate::cmp::Eq;\nuse crate::hash::Hash;\nuse crate::ops::arith::{Add, Neg, Sub};\n\n/// A point on the embedded elliptic curve\n/// By definition, the base field of the embedded curve is the scalar field of the proof system curve, i.e the Noir Field.\n/// x and y denotes the Weierstrass coordinates of the point, if is_infinite is false.\npub struct EmbeddedCurvePoint {\n pub x: Field,\n pub y: Field,\n pub is_infinite: bool,\n}\n\nimpl EmbeddedCurvePoint {\n /// Elliptic curve point doubling operation\n /// returns the doubled point of a point P, i.e P+P\n pub fn double(self) -> EmbeddedCurvePoint {\n embedded_curve_add(self, self)\n }\n\n /// Returns the null element of the curve; 'the point at infinity'\n pub fn point_at_infinity() -> EmbeddedCurvePoint {\n EmbeddedCurvePoint { x: 0, y: 0, is_infinite: true }\n }\n\n /// Returns the curve's generator point.\n pub fn generator() -> EmbeddedCurvePoint {\n // Generator point for the grumpkin curve (y^2 = x^3 - 17)\n EmbeddedCurvePoint {\n x: 1,\n y: 17631683881184975370165255887551781615748388533673675138860, // sqrt(-16)\n is_infinite: false,\n }\n }\n}\n\nimpl Add for EmbeddedCurvePoint {\n /// Adds two points P+Q, using the curve addition formula, and also handles point at infinity\n fn add(self, other: EmbeddedCurvePoint) -> EmbeddedCurvePoint {\n embedded_curve_add(self, other)\n }\n}\n\nimpl Sub for EmbeddedCurvePoint {\n /// Points subtraction operation, using addition and negation\n fn sub(self, other: EmbeddedCurvePoint) -> EmbeddedCurvePoint {\n self + other.neg()\n }\n}\n\nimpl Neg for EmbeddedCurvePoint {\n /// Negates a point P, i.e returns -P, by negating the y coordinate.\n /// If the point is at infinity, then the result is also at infinity.\n fn neg(self) -> EmbeddedCurvePoint {\n EmbeddedCurvePoint { x: self.x, y: -self.y, is_infinite: self.is_infinite }\n }\n}\n\nimpl Eq for EmbeddedCurvePoint {\n /// Checks whether two points are equal\n fn eq(self: Self, b: EmbeddedCurvePoint) -> bool {\n (self.is_infinite & b.is_infinite)\n | ((self.is_infinite == b.is_infinite) & (self.x == b.x) & (self.y == b.y))\n }\n}\n\nimpl Hash for EmbeddedCurvePoint {\n fn hash(self, state: &mut H)\n where\n H: crate::hash::Hasher,\n {\n if self.is_infinite {\n self.is_infinite.hash(state);\n } else {\n self.x.hash(state);\n self.y.hash(state);\n }\n }\n}\n\n/// Scalar for the embedded curve represented as low and high limbs\n/// By definition, the scalar field of the embedded curve is base field of the proving system curve.\n/// It may not fit into a Field element, so it is represented with two Field elements; its low and high limbs.\npub struct EmbeddedCurveScalar {\n pub lo: Field,\n pub hi: Field,\n}\n\nimpl EmbeddedCurveScalar {\n pub fn new(lo: Field, hi: Field) -> Self {\n EmbeddedCurveScalar { lo, hi }\n }\n\n #[field(bn254)]\n pub fn from_field(scalar: Field) -> EmbeddedCurveScalar {\n let (a, b) = crate::field::bn254::decompose(scalar);\n EmbeddedCurveScalar { lo: a, hi: b }\n }\n\n //Bytes to scalar: take the first (after the specified offset) 16 bytes of the input as the lo value, and the next 16 bytes as the hi value\n #[field(bn254)]\n pub(crate) fn from_bytes(bytes: [u8; 64], offset: u32) -> EmbeddedCurveScalar {\n let mut v = 1;\n let mut lo = 0 as Field;\n let mut hi = 0 as Field;\n for i in 0..16 {\n lo = lo + (bytes[offset + 31 - i] as Field) * v;\n hi = hi + (bytes[offset + 15 - i] as Field) * v;\n v = v * 256;\n }\n let sig_s = crate::embedded_curve_ops::EmbeddedCurveScalar { lo, hi };\n sig_s\n }\n}\n\nimpl Eq for EmbeddedCurveScalar {\n fn eq(self, other: Self) -> bool {\n (other.hi == self.hi) & (other.lo == self.lo)\n }\n}\n\nimpl Hash for EmbeddedCurveScalar {\n fn hash(self, state: &mut H)\n where\n H: crate::hash::Hasher,\n {\n self.hi.hash(state);\n self.lo.hash(state);\n }\n}\n\n// Computes a multi scalar multiplication over the embedded curve.\n// For bn254, We have Grumpkin and Baby JubJub.\n// For bls12-381, we have JubJub and Bandersnatch.\n//\n// The embedded curve being used is decided by the\n// underlying proof system.\n// docs:start:multi_scalar_mul\npub fn multi_scalar_mul(\n points: [EmbeddedCurvePoint; N],\n scalars: [EmbeddedCurveScalar; N],\n) -> EmbeddedCurvePoint\n// docs:end:multi_scalar_mul\n{\n multi_scalar_mul_array_return(points, scalars)[0]\n}\n\n#[foreign(multi_scalar_mul)]\npub(crate) fn multi_scalar_mul_array_return(\n points: [EmbeddedCurvePoint; N],\n scalars: [EmbeddedCurveScalar; N],\n) -> [EmbeddedCurvePoint; 1] {}\n\n// docs:start:fixed_base_scalar_mul\npub fn fixed_base_scalar_mul(scalar: EmbeddedCurveScalar) -> EmbeddedCurvePoint\n// docs:end:fixed_base_scalar_mul\n{\n multi_scalar_mul([EmbeddedCurvePoint::generator()], [scalar])\n}\n\n/// This function only assumes that the points are on the curve\n/// It handles corner cases around the infinity point causing some overhead compared to embedded_curve_add_not_nul and embedded_curve_add_unsafe\n// docs:start:embedded_curve_add\npub fn embedded_curve_add(\n point1: EmbeddedCurvePoint,\n point2: EmbeddedCurvePoint,\n) -> EmbeddedCurvePoint {\n // docs:end:embedded_curve_add\n if crate::runtime::is_unconstrained() {\n // `embedded_curve_add_unsafe` requires the inputs not to be the infinity point, so we check it here.\n // This is because `embedded_curve_add_unsafe` uses the `embedded_curve_add` opcode.\n // For efficiency, the backend does not check the inputs for the infinity point, but it assumes that they are not the infinity point\n // so that it can apply the ec addition formula directly.\n if point1.is_infinite {\n point2\n } else if point2.is_infinite {\n point1\n } else {\n embedded_curve_add_unsafe(point1, point2)\n }\n } else {\n // In a constrained context, we also need to check the inputs are not the infinity point because we also use `embedded_curve_add_unsafe`\n // However we also need to identify the case where the two inputs are the same, because then\n // the addition formula does not work and we need to use the doubling formula instead.\n // In unconstrained context, we can check directly if the input values are the same when solving the opcode, so it is not an issue.\n\n // x_coordinates_match is true if both abscissae are the same\n let x_coordinates_match = point1.x == point2.x;\n // y_coordinates_match is true if both ordinates are the same\n let y_coordinates_match = point1.y == point2.y;\n // double_predicate is true if both abscissae and ordinates are the same\n let double_predicate = (x_coordinates_match & y_coordinates_match);\n // If the abscissae are the same, but not the ordinates, then one point is the opposite of the other\n let infinity_predicate = (x_coordinates_match & !y_coordinates_match);\n let point1_1 = EmbeddedCurvePoint {\n x: point1.x + (x_coordinates_match as Field),\n y: point1.y,\n is_infinite: false,\n };\n let point2_1 = EmbeddedCurvePoint { x: point2.x, y: point2.y, is_infinite: false };\n // point1_1 is guaranteed to have a different abscissa than point2:\n // - if x_coordinates_match is 0, that means point1.x != point2.x, and point1_1.x = point1.x + 0\n // - if x_coordinates_match is 1, that means point1.x = point2.x, but point1_1.x = point1.x + 1 in this case\n // Because the abscissa is different, the addition formula is guaranteed to succeed, so we can safely use `embedded_curve_add_unsafe`\n // Note that this computation may be garbage: if x_coordinates_match is 1, or if one of the input is the point at infinity.\n let mut result = embedded_curve_add_unsafe(point1_1, point2_1);\n\n // `embedded_curve_add_unsafe` is doing a doubling if the input is the same variable, because in this case it is guaranteed (at 'compile time') that the input is the same.\n let double = embedded_curve_add_unsafe(point1, point1);\n // `embedded_curve_add_unsafe` would not perform doubling, even if the inputs point1 and point2 are the same, because it cannot know this without adding some logic (and some constraints)\n // However we did this logic when we computed `double_predicate`, so we set the result to 2*point1 if point1 and point2 are the same\n result = if double_predicate { double } else { result };\n\n // Same logic as above for unconstrained context, we set the proper result when one of the inputs is the infinity point\n if point1.is_infinite {\n result = point2;\n }\n if point2.is_infinite {\n result = point1;\n }\n\n // Finally, we set the is_infinity flag of the result:\n // Opposite points should sum into the infinity point, however, if one of them is point at infinity, their coordinates are not meaningful\n // so we should not use the fact that the inputs are opposite in this case:\n let mut result_is_infinity =\n infinity_predicate & (!point1.is_infinite & !point2.is_infinite);\n // However, if both of them are at infinity, then the result is also at infinity\n result.is_infinite = result_is_infinity | (point1.is_infinite & point2.is_infinite);\n result\n }\n}\n\n#[foreign(embedded_curve_add)]\nfn embedded_curve_add_array_return(\n _point1: EmbeddedCurvePoint,\n _point2: EmbeddedCurvePoint,\n) -> [EmbeddedCurvePoint; 1] {}\n\n/// This function assumes that:\n/// The points are on the curve, and\n/// The points don't share an x-coordinate, and\n/// Neither point is the infinity point.\n/// If it is used with correct input, the function ensures the correct non-zero result is returned.\n/// Except for points on the curve, the other assumptions are checked by the function. It will cause assertion failure if they are not respected.\npub fn embedded_curve_add_not_nul(\n point1: EmbeddedCurvePoint,\n point2: EmbeddedCurvePoint,\n) -> EmbeddedCurvePoint {\n assert(point1.x != point2.x);\n assert(!point1.is_infinite);\n assert(!point2.is_infinite);\n // Ensure is_infinite is comptime\n let point1_1 = EmbeddedCurvePoint { x: point1.x, y: point1.y, is_infinite: false };\n let point2_1 = EmbeddedCurvePoint { x: point2.x, y: point2.y, is_infinite: false };\n embedded_curve_add_unsafe(point1_1, point2_1)\n}\n\n/// Unsafe ec addition\n/// If the inputs are the same, it will perform a doubling, but only if point1 and point2 are the same variable.\n/// If they have the same value but are different variables, the result will be incorrect because in this case\n/// it assumes (but does not check) that the points' x-coordinates are not equal.\n/// It also assumes neither point is the infinity point.\npub fn embedded_curve_add_unsafe(\n point1: EmbeddedCurvePoint,\n point2: EmbeddedCurvePoint,\n) -> EmbeddedCurvePoint {\n embedded_curve_add_array_return(point1, point2)[0]\n}\n", "path": "std/embedded_curve_ops.nr" }, "50": { - "source": "use std::ops::Add;\n\nfn main(priv_key: Field, pub_x: pub Field, pub_y: pub Field) {\n let g1 = std::embedded_curve_ops::EmbeddedCurvePoint::generator();\n let scalar = std::embedded_curve_ops::EmbeddedCurveScalar { lo: priv_key, hi: 0 };\n // Test that multi_scalar_mul correctly derives the public key\n let res = std::embedded_curve_ops::multi_scalar_mul([g1], [scalar]);\n assert(res.x == pub_x);\n assert(res.y == pub_y);\n\n // Test that double function calling embedded_curve_add works as expected\n let pub_point =\n std::embedded_curve_ops::EmbeddedCurvePoint { x: pub_x, y: pub_y, is_infinite: false };\n let res = pub_point.double();\n let double = g1.add(g1);\n\n assert(double.x == res.x);\n\n // Test calling multi_scalar_mul with multiple points and scalars\n let res = std::embedded_curve_ops::multi_scalar_mul([g1, g1], [scalar, scalar]);\n\n // The results should be double the g1 point because the scalars are 1 and we pass in g1 twice\n assert(double.x == res.x);\n\n // Tests for #6549\n let const_scalar1 = std::embedded_curve_ops::EmbeddedCurveScalar { lo: 23, hi: 0 };\n let const_scalar2 = std::embedded_curve_ops::EmbeddedCurveScalar { lo: 0, hi: 23 };\n let const_scalar3 = std::embedded_curve_ops::EmbeddedCurveScalar { lo: 13, hi: 4 };\n let partial_mul = std::embedded_curve_ops::multi_scalar_mul(\n [g1, double, pub_point, g1, g1],\n [scalar, const_scalar1, scalar, const_scalar2, const_scalar3],\n );\n assert(partial_mul.x == 0x2024c4eebfbc8a20018f8c95c7aab77c6f34f10cf785a6f04e97452d8708fda7);\n // Check simplification by zero\n let zero_point = std::embedded_curve_ops::EmbeddedCurvePoint { x: 0, y: 0, is_infinite: true };\n let const_zero = std::embedded_curve_ops::EmbeddedCurveScalar { lo: 0, hi: 0 };\n let partial_mul = std::embedded_curve_ops::multi_scalar_mul(\n [zero_point, double, g1],\n [scalar, const_zero, scalar],\n );\n assert(partial_mul == g1);\n}\n", + "source": "use std::{embedded_curve_ops::embedded_curve_add_unsafe, ops::Add};\n\nfn main(priv_key: Field, pub_x: pub Field, pub_y: pub Field) {\n let g1 = std::embedded_curve_ops::EmbeddedCurvePoint::generator();\n let scalar = std::embedded_curve_ops::EmbeddedCurveScalar { lo: priv_key, hi: 0 };\n // Test that multi_scalar_mul correctly derives the public key\n let res = std::embedded_curve_ops::multi_scalar_mul([g1], [scalar]);\n assert(res.x == pub_x);\n assert(res.y == pub_y);\n\n // Test that double function calling embedded_curve_add works as expected\n let pub_point =\n std::embedded_curve_ops::EmbeddedCurvePoint { x: pub_x, y: pub_y, is_infinite: false };\n let res = pub_point.double();\n let double = g1.add(g1);\n\n assert(double.x == res.x);\n\n // Test calling multi_scalar_mul with multiple points and scalars\n let res = std::embedded_curve_ops::multi_scalar_mul([g1, g1], [scalar, scalar]);\n\n // The results should be double the g1 point because the scalars are 1 and we pass in g1 twice\n assert(double.x == res.x);\n\n // Tests for #6549\n let const_scalar1 = std::embedded_curve_ops::EmbeddedCurveScalar { lo: 23, hi: 0 };\n let const_scalar2 = std::embedded_curve_ops::EmbeddedCurveScalar { lo: 0, hi: 23 };\n let const_scalar3 = std::embedded_curve_ops::EmbeddedCurveScalar { lo: 13, hi: 4 };\n let partial_mul = std::embedded_curve_ops::multi_scalar_mul(\n [g1, double, pub_point, g1, g1],\n [scalar, const_scalar1, scalar, const_scalar2, const_scalar3],\n );\n assert(partial_mul.x == 0x2024c4eebfbc8a20018f8c95c7aab77c6f34f10cf785a6f04e97452d8708fda7);\n // Check simplification by zero\n let zero_point = std::embedded_curve_ops::EmbeddedCurvePoint { x: 0, y: 0, is_infinite: true };\n let const_zero = std::embedded_curve_ops::EmbeddedCurveScalar { lo: 0, hi: 0 };\n let partial_mul = std::embedded_curve_ops::multi_scalar_mul(\n [zero_point, double, g1],\n [scalar, const_zero, scalar],\n );\n assert(partial_mul == g1);\n\n // Additional tests for validating embedded_curve_add_unsafe under a conditional\n if pub_x == pub_y {\n let a1 = std::embedded_curve_ops::EmbeddedCurvePoint { x: 1, y: 2, is_infinite: false };\n let a2 = std::embedded_curve_ops::EmbeddedCurvePoint { x: 1, y: 3, is_infinite: false };\n let doubling = a1.double();\n assert(doubling.x == 1);\n let res = embedded_curve_add_unsafe(a1, a2);\n assert(res.x == 1);\n\n let a1 = std::embedded_curve_ops::EmbeddedCurvePoint {\n x: pub_x + 1,\n y: pub_y,\n is_infinite: false,\n };\n let a2 = std::embedded_curve_ops::EmbeddedCurvePoint {\n x: pub_x + 1,\n y: pub_y + 1,\n is_infinite: false,\n };\n let doubling = a1.double();\n assert(doubling.x == 1);\n let res = embedded_curve_add_unsafe(a1, a2);\n assert(res.x == 1);\n\n let a1 = std::embedded_curve_ops::EmbeddedCurvePoint { x: 2, y: 3, is_infinite: false };\n let a2 = std::embedded_curve_ops::EmbeddedCurvePoint {\n x: pub_x,\n y: pub_y + 1 as Field,\n is_infinite: false,\n };\n let res = embedded_curve_add_unsafe(a1, a2);\n assert(res.x == 1);\n\n let a1 = std::embedded_curve_ops::EmbeddedCurvePoint { x: 2, y: 3, is_infinite: false };\n let a2 = std::embedded_curve_ops::EmbeddedCurvePoint { x: 2, y: 4, is_infinite: false };\n let res = embedded_curve_add_unsafe(a1, a2);\n assert(res.x == 1);\n\n let a1 = std::embedded_curve_ops::EmbeddedCurvePoint { x: 2, y: 3, is_infinite: false };\n let a2 = std::embedded_curve_ops::EmbeddedCurvePoint { x: 2, y: 3, is_infinite: false };\n let res = embedded_curve_add_unsafe(a1, a2);\n assert(res.x == 1);\n let a1 = std::embedded_curve_ops::EmbeddedCurvePoint { x: 1, y: 3, is_infinite: false };\n let a2 = std::embedded_curve_ops::EmbeddedCurvePoint { x: 1, y: 3, is_infinite: false };\n let res = embedded_curve_add_unsafe(a1, a2);\n assert(res.x == 1);\n let a1 = std::embedded_curve_ops::EmbeddedCurvePoint { x: pub_x, y: 3, is_infinite: false };\n let a2 = std::embedded_curve_ops::EmbeddedCurvePoint { x: pub_x, y: 2, is_infinite: false };\n let res = embedded_curve_add_unsafe(a1, a2);\n assert(res.x == 1);\n }\n}\n", "path": "" } }, From 121844b8e1e5e7a66185979ac669546ec9fa7df3 Mon Sep 17 00:00:00 2001 From: guipublic Date: Fri, 27 Jun 2025 16:55:34 +0000 Subject: [PATCH 3/3] snapshots --- ...ig_false_inliner_-9223372036854775808.snap | 98 ++++++++++--------- ..._tests__force_brillig_false_inliner_0.snap | 98 ++++++++++--------- ...lig_false_inliner_9223372036854775807.snap | 98 ++++++++++--------- 3 files changed, 150 insertions(+), 144 deletions(-) diff --git a/tooling/nargo_cli/tests/snapshots/execution_success/embedded_curve_ops/execute__tests__force_brillig_false_inliner_-9223372036854775808.snap b/tooling/nargo_cli/tests/snapshots/execution_success/embedded_curve_ops/execute__tests__force_brillig_false_inliner_-9223372036854775808.snap index 12800efb646..a134c1bd4f7 100644 --- a/tooling/nargo_cli/tests/snapshots/execution_success/embedded_curve_ops/execute__tests__force_brillig_false_inliner_-9223372036854775808.snap +++ b/tooling/nargo_cli/tests/snapshots/execution_success/embedded_curve_ops/execute__tests__force_brillig_false_inliner_-9223372036854775808.snap @@ -34,63 +34,65 @@ expression: artifact }, "bytecode": [ "func 0", - "current witness index : _61", + "current witness index : _63", "private parameters indices : [_0]", "public parameters indices : [_1, _2]", "return value indices : []", "BLACKBOX::MULTI_SCALAR_MUL [(1, 254), (17631683881184975370165255887551781615748388533673675138860, 254), (0, 1), (_0, 254), (0, 254)] [_3, _4, _5]", "EXPR [ (-1, _1) (1, _3) 0 ]", "EXPR [ (-1, _2) (1, _4) 0 ]", - "BLACKBOX::EMBEDDED_CURVE_ADD [(_1, 254), (_2, 254), (0, 1), (_1, 254), (_2, 254), (0, 1)] [_6, _7, _8]", - "EXPR [ (-1, _6) 3078034153852398078128400807926804309327113743808504829582559963737223069694 ]", - "BLACKBOX::MULTI_SCALAR_MUL [(1, 254), (17631683881184975370165255887551781615748388533673675138860, 254), (0, 1), (1, 254), (17631683881184975370165255887551781615748388533673675138860, 254), (0, 1), (_0, 254), (0, 254), (_0, 254), (0, 254)] [_9, _10, _11]", - "EXPR [ (-1, _9) 3078034153852398078128400807926804309327113743808504829582559963737223069694 ]", - "BLACKBOX::MULTI_SCALAR_MUL [(1, 254), (17631683881184975370165255887551781615748388533673675138860, 254), (0, 1), (_1, 254), (_2, 254), (0, 1), (11179562631109628533987091031692370366552561688588090155835439555627259799605, 254), (3443719903172018228650470536370404288991794296383447657609081676265727805364, 254), (0, 1), (_0, 254), (0, 254), (_0, 254), (0, 254), (1, 254), (0, 254)] [_12, _13, _14]", - "EXPR [ (1, _12) 7349266043899242844836273743257843180744506495159104166319746739537754653274 ]", - "BLACKBOX::MULTI_SCALAR_MUL [(1, 254), (17631683881184975370165255887551781615748388533673675138860, 254), (0, 1), (_0, 254), (0, 254)] [_15, _16, _17]", - "EXPR [ (1, _17) 0 ]", - "EXPR [ (1, _15) -1 ]", - "EXPR [ (1, _16) -17631683881184975370165255887551781615748388533673675138860 ]", - "EXPR [ (1, _1) (-1, _2) (-1, _18) 0 ]", - "BRILLIG CALL func 0: inputs: [Single(Expression { mul_terms: [], linear_combinations: [(1, Witness(18))], q_c: 0 })], outputs: [Simple(Witness(19))]", - "EXPR [ (1, _18, _19) (1, _20) -1 ]", - "EXPR [ (1, _18, _20) 0 ]", - "EXPR [ (-17631683881184975370165255887551781615748388533673675138858, _20) (-1, _21) 17631683881184975370165255887551781615748388533673675138860 ]", - "BLACKBOX::EMBEDDED_CURVE_ADD [(1, 254), (_21, 254), (0, 1), (1, 254), (_21, 254), (0, 1)] [_22, _23, _24]", - "EXPR [ (1, _20, _22) (-1, _20) 0 ]", - "EXPR [ (-3078034153852398078128400807926804309327113743808504829582559963737223069693, _20) (-1, _25) 3078034153852398078128400807926804309327113743808504829582559963737223069694 ]", - "EXPR [ (9191351987198133172789796342745422989482268917117950487758512501574271532888, _20) (-1, _26) -9191351987198133172789796342745422989482268917117950487758512501574271532885 ]", - "BLACKBOX::EMBEDDED_CURVE_ADD [(1, 254), (_21, 254), (0, 1), (_25, 254), (_26, 254), (0, 1)] [_27, _28, _29]", - "EXPR [ (1, _20, _27) (-1, _20) 0 ]", - "EXPR [ (1, _1, _20) (-1, _30) 1 ]", - "EXPR [ (1, _2, _20) (-17631683881184975370165255887551781615748388533673675138860, _20) (-1, _31) 17631683881184975370165255887551781615748388533673675138860 ]", - "BLACKBOX::EMBEDDED_CURVE_ADD [(_30, 254), (_31, 254), (0, 1), (_30, 254), (_31, 254), (0, 1)] [_32, _33, _34]", - "EXPR [ (1, _20, _32) (-1, _20) 0 ]", - "EXPR [ (1, _1, _20) (-3078034153852398078128400807926804309327113743808504829582559963737223069693, _20) (-1, _35) 3078034153852398078128400807926804309327113743808504829582559963737223069694 ]", - "EXPR [ (1, _2, _20) (9191351987198133172789796342745422989482268917117950487758512501574271532886, _20) (-1, _36) -9191351987198133172789796342745422989482268917117950487758512501574271532885 ]", - "BLACKBOX::EMBEDDED_CURVE_ADD [(_30, 254), (_31, 254), (0, 1), (_35, 254), (_36, 254), (0, 1)] [_37, _38, _39]", - "EXPR [ (1, _20, _37) (-1, _20) 0 ]", - "EXPR [ (1, _20) (-1, _40) 1 ]", - "EXPR [ (-17631683881184975370165255887551781615748388533673675138857, _20) (-1, _41) 17631683881184975370165255887551781615748388533673675138860 ]", - "EXPR [ (1, _1, _20) (-3078034153852398078128400807926804309327113743808504829582559963737223069694, _20) (-1, _42) 3078034153852398078128400807926804309327113743808504829582559963737223069694 ]", - "BLACKBOX::EMBEDDED_CURVE_ADD [(_40, 254), (_41, 254), (0, 1), (_42, 254), (_36, 254), (0, 1)] [_43, _44, _45]", - "EXPR [ (1, _20, _43) (-1, _20) 0 ]", - "EXPR [ (-3078034153852398078128400807926804309327113743808504829582559963737223069692, _20) (-1, _46) 3078034153852398078128400807926804309327113743808504829582559963737223069694 ]", - "EXPR [ (9191351987198133172789796342745422989482268917117950487758512501574271532889, _20) (-1, _47) -9191351987198133172789796342745422989482268917117950487758512501574271532885 ]", - "BLACKBOX::EMBEDDED_CURVE_ADD [(_40, 254), (_41, 254), (0, 1), (_46, 254), (_47, 254), (0, 1)] [_48, _49, _50]", - "EXPR [ (1, _20, _48) (-1, _20) 0 ]", - "BLACKBOX::EMBEDDED_CURVE_ADD [(_40, 254), (_41, 254), (0, 1), (_40, 254), (_41, 254), (0, 1)] [_51, _52, _53]", - "EXPR [ (1, _20, _51) (-1, _20) 0 ]", - "BLACKBOX::EMBEDDED_CURVE_ADD [(1, 254), (_41, 254), (0, 1), (1, 254), (_41, 254), (0, 1)] [_54, _55, _56]", - "EXPR [ (1, _20, _54) (-1, _20) 0 ]", - "EXPR [ (1, _1, _20) (-1, _20) (-1, _57) 1 ]", - "EXPR [ (9191351987198133172789796342745422989482268917117950487758512501574271532887, _20) (-1, _58) -9191351987198133172789796342745422989482268917117950487758512501574271532885 ]", - "BLACKBOX::EMBEDDED_CURVE_ADD [(_57, 254), (_41, 254), (0, 1), (_42, 254), (_58, 254), (0, 1)] [_59, _60, _61]", - "EXPR [ (1, _20, _59) (-1, _20) 0 ]", + "EXPR [ (-1, _6) 0 ]", + "BLACKBOX::EMBEDDED_CURVE_ADD [(_1, 254), (_2, 254), (_6, 1), (_1, 254), (_2, 254), (_6, 1)] [_7, _8, _9]", + "EXPR [ (-1, _7) 3078034153852398078128400807926804309327113743808504829582559963737223069694 ]", + "BLACKBOX::MULTI_SCALAR_MUL [(1, 254), (17631683881184975370165255887551781615748388533673675138860, 254), (0, 1), (1, 254), (17631683881184975370165255887551781615748388533673675138860, 254), (0, 1), (_0, 254), (0, 254), (_0, 254), (0, 254)] [_10, _11, _12]", + "EXPR [ (-1, _10) 3078034153852398078128400807926804309327113743808504829582559963737223069694 ]", + "BLACKBOX::MULTI_SCALAR_MUL [(1, 254), (17631683881184975370165255887551781615748388533673675138860, 254), (0, 1), (_1, 254), (_2, 254), (0, 1), (11179562631109628533987091031692370366552561688588090155835439555627259799605, 254), (3443719903172018228650470536370404288991794296383447657609081676265727805364, 254), (0, 1), (_0, 254), (0, 254), (_0, 254), (0, 254), (1, 254), (0, 254)] [_13, _14, _15]", + "EXPR [ (1, _13) 7349266043899242844836273743257843180744506495159104166319746739537754653274 ]", + "BLACKBOX::MULTI_SCALAR_MUL [(1, 254), (17631683881184975370165255887551781615748388533673675138860, 254), (0, 1), (_0, 254), (0, 254)] [_16, _17, _18]", + "EXPR [ (1, _18) 0 ]", + "EXPR [ (1, _16) -1 ]", + "EXPR [ (1, _17) -17631683881184975370165255887551781615748388533673675138860 ]", + "EXPR [ (1, _1) (-1, _2) (-1, _19) 0 ]", + "BRILLIG CALL func 0: inputs: [Single(Expression { mul_terms: [], linear_combinations: [(1, Witness(19))], q_c: 0 })], outputs: [Simple(Witness(20))]", + "EXPR [ (1, _19, _20) (1, _21) -1 ]", + "EXPR [ (1, _19, _21) 0 ]", + "EXPR [ (-17631683881184975370165255887551781615748388533673675138858, _21) (-1, _22) 17631683881184975370165255887551781615748388533673675138860 ]", + "EXPR [ (-1, _23) 1 ]", + "BLACKBOX::EMBEDDED_CURVE_ADD [(_23, 254), (_22, 254), (_6, 1), (_23, 254), (_22, 254), (_6, 1)] [_24, _25, _26]", + "EXPR [ (1, _21, _24) (-1, _21) 0 ]", + "EXPR [ (-3078034153852398078128400807926804309327113743808504829582559963737223069693, _21) (-1, _27) 3078034153852398078128400807926804309327113743808504829582559963737223069694 ]", + "EXPR [ (9191351987198133172789796342745422989482268917117950487758512501574271532888, _21) (-1, _28) -9191351987198133172789796342745422989482268917117950487758512501574271532885 ]", + "BLACKBOX::EMBEDDED_CURVE_ADD [(_23, 254), (_22, 254), (_6, 1), (_27, 254), (_28, 254), (_6, 1)] [_29, _30, _31]", + "EXPR [ (1, _21, _29) (-1, _21) 0 ]", + "EXPR [ (1, _1, _21) (-1, _32) 1 ]", + "EXPR [ (1, _2, _21) (-17631683881184975370165255887551781615748388533673675138860, _21) (-1, _33) 17631683881184975370165255887551781615748388533673675138860 ]", + "BLACKBOX::EMBEDDED_CURVE_ADD [(_32, 254), (_33, 254), (_6, 1), (_32, 254), (_33, 254), (_6, 1)] [_34, _35, _36]", + "EXPR [ (1, _21, _34) (-1, _21) 0 ]", + "EXPR [ (1, _1, _21) (-3078034153852398078128400807926804309327113743808504829582559963737223069693, _21) (-1, _37) 3078034153852398078128400807926804309327113743808504829582559963737223069694 ]", + "EXPR [ (1, _2, _21) (9191351987198133172789796342745422989482268917117950487758512501574271532886, _21) (-1, _38) -9191351987198133172789796342745422989482268917117950487758512501574271532885 ]", + "BLACKBOX::EMBEDDED_CURVE_ADD [(_32, 254), (_33, 254), (_6, 1), (_37, 254), (_38, 254), (_6, 1)] [_39, _40, _41]", + "EXPR [ (1, _21, _39) (-1, _21) 0 ]", + "EXPR [ (1, _21) (-1, _42) 1 ]", + "EXPR [ (-17631683881184975370165255887551781615748388533673675138857, _21) (-1, _43) 17631683881184975370165255887551781615748388533673675138860 ]", + "EXPR [ (1, _1, _21) (-3078034153852398078128400807926804309327113743808504829582559963737223069694, _21) (-1, _44) 3078034153852398078128400807926804309327113743808504829582559963737223069694 ]", + "BLACKBOX::EMBEDDED_CURVE_ADD [(_42, 254), (_43, 254), (_6, 1), (_44, 254), (_38, 254), (_6, 1)] [_45, _46, _47]", + "EXPR [ (1, _21, _45) (-1, _21) 0 ]", + "EXPR [ (-3078034153852398078128400807926804309327113743808504829582559963737223069692, _21) (-1, _48) 3078034153852398078128400807926804309327113743808504829582559963737223069694 ]", + "EXPR [ (9191351987198133172789796342745422989482268917117950487758512501574271532889, _21) (-1, _49) -9191351987198133172789796342745422989482268917117950487758512501574271532885 ]", + "BLACKBOX::EMBEDDED_CURVE_ADD [(_42, 254), (_43, 254), (_6, 1), (_48, 254), (_49, 254), (_6, 1)] [_50, _51, _52]", + "EXPR [ (1, _21, _50) (-1, _21) 0 ]", + "BLACKBOX::EMBEDDED_CURVE_ADD [(_42, 254), (_43, 254), (_6, 1), (_42, 254), (_43, 254), (_6, 1)] [_53, _54, _55]", + "EXPR [ (1, _21, _53) (-1, _21) 0 ]", + "BLACKBOX::EMBEDDED_CURVE_ADD [(_23, 254), (_43, 254), (_6, 1), (_23, 254), (_43, 254), (_6, 1)] [_56, _57, _58]", + "EXPR [ (1, _21, _56) (-1, _21) 0 ]", + "EXPR [ (1, _1, _21) (-1, _21) (-1, _59) 1 ]", + "EXPR [ (9191351987198133172789796342745422989482268917117950487758512501574271532887, _21) (-1, _60) -9191351987198133172789796342745422989482268917117950487758512501574271532885 ]", + "BLACKBOX::EMBEDDED_CURVE_ADD [(_59, 254), (_43, 254), (_6, 1), (_44, 254), (_60, 254), (_6, 1)] [_61, _62, _63]", + "EXPR [ (1, _21, _61) (-1, _21) 0 ]", "unconstrained func 0", "[Const { destination: Direct(21), bit_size: Integer(U32), value: 1 }, Const { destination: Direct(20), bit_size: Integer(U32), value: 0 }, CalldataCopy { destination_address: Direct(0), size_address: Direct(21), offset_address: Direct(20) }, Const { destination: Direct(2), bit_size: Field, value: 0 }, BinaryFieldOp { destination: Direct(3), op: Equals, lhs: Direct(0), rhs: Direct(2) }, JumpIf { condition: Direct(3), location: 8 }, Const { destination: Direct(1), bit_size: Field, value: 1 }, BinaryFieldOp { destination: Direct(0), op: Div, lhs: Direct(1), rhs: Direct(0) }, Stop { return_data: HeapVector { pointer: Direct(20), size: Direct(21) } }]" ], - "debug_symbols": "tVjLbuMwDPwXnX0QX3rsrywWRZq6RQDDCdxkgUXRf1+qlez0oKBV7NMksTkhR+TY0pt56h8vLw+H8fn4an79fjOP02EYDi8Pw3G/Ox+Oo/769t6Z8vXhPPW9/mSurmvUaTf149n8Gi/D0Jm/u+HycdPraTd+4Hk36VXbmX58UlTC58PQp0/v3RJt66EYJAdjcHO4fDuePOR4xlCLx3o8S+RC4HgpAFwbA9UYbtTAPNcg0qABu1jiAzXEu1jWwAPU4v2NeCz5O4Fa/aEe71GwJICRGhgC2ZJCIMYaA9wQAQCtzxz6WXgNEt/QDV5cEcO3rGZwRYpIthYPfPdIfJ+iZSbAMhUhrbMNOgD5mUGoqiSE+5UImyohXBoCHMYWJYIvOUCMXHXJFWxyU59EOw8XWuQGJVDnszAANTGQlCqQXLWr8F67xFtuZ2e/DDZWPQbjCm6H97suwQp5/ISkxXWRAs7reqXpDzqDkw98MrBUn6Mka6ghG6vBbqnFhxY1PM+T5rnFtTDAPO0Bq++GbO+cNIa7J41xhTW9mcf3Jo15jTx4494KfPXKb5s6IxQ1MELVxTmsoUbYWI1ISy0MLTsgxPKeQyjVOZE1evQnJC1qEPqllqa9DHEsmyESwqoabg013MZqCC+1SIuHkvdl1ijYqo+7NfZFbuN9kT6gl1qoaZ9spTyT2Na7y63hom5jF2Wwcy0ALS7KRGXWmFzVN9waLuo2dlHWjphriV9X9o9+2+0P05eTL2O1izoDektnUBPsDKW/7wynnWNnJG28OuMUNDmfdk6dCWnb0JmY3hE1WDlSSwJkxIzKhEoInFEyuow+uZtiyBiTbWkaKSe9jpARM1LqeEVOmyhFyegyKh9rkqh8yTAwfiLZjKlKTZuUTzRvooycUTIqnygfKZ8oH4WM8RNZ+UT5WPnSGQMn3TSOKb1fKSqfS/dJOlJSdBl9xpAOmN7TKk6H3ePQ5yPI58u4vzqRPP87lSvlzPI0Hff902Xq0xp+XNNV/Q8=", + "debug_symbols": "tVjLbuowEP0Xr7PwvPzor1xdVZSmFVIEKIUrXVX9946LndCFUWuS1QGSOcwce04yfjfP/dP59XG3fzm8mYc/7+Zp3A3D7vVxOGw3p91hr7++f3SmfH08jX2vP5mr6xp13Iz9/mQe9udh6My/zXD+uuntuNl/4Wkz6lXbmX7/rKiEL7uhT58+ujna1kMxSA7G4KZw+XE8ecjxjKEWj/V4lsiFwPFcALg2Bqox3KiBeapBpEEDdrHEB2qId7GsgQeoxfsb8VjydwK1+kM93qNgSQAjNTAEsiWFQIw1BrghAgBanzn0s/ASJL5hN3hxRQzfsprBFSki2Vo88N0t8XOKlp4Ay1SEtM426ADkJwahqpIQ7lcirKqEcNkQ4DC2KBF8yQFi5KpLLmCTq/ok2qm50CI3KIHan4UBqImBpFSB5Kq7Cu+1S7zldnbyy2Bj1WMwLuB2eL/rEiyQx29IWlwXKeC0rlea/mJncPKBCwNL9TlKsoQasrIa7OZafGhRw/PUaZ5bXAsDTN0esPpuyPbOTmO4u9MYF1jTm3n8rNOYl8iDV95bga9e+W3TzghFDYxQdXEOS6gRVlYj0lwLQ8sEhFjecwil2ieyxB79DUmLGoR+rqVpliGOZRgiIayq4ZZQw62shvBci7R4KHlfeo2Crfq4W2IucivPRfqAnmuhpjnZSnkmsa3vLreEi7qVXZTBTrUAtLgoE5VeY3JV33BLuKhb2UVZd8RUS/y+sn/122a7G7+dfBmru6gzoLd0BjXBzlD6+87wBSQNkJ1xaf7qjFfQHEMaoDoT0/SgwTa9KyoqS9qagBkpo1KhEoNkdBl9xpBcTjFeEG1GSDamqHyk9yFl5IySOkDRpaFK0WcMGZWPNVtSvmQgBBkxo/KJ5k/KJ5o/SUaX0WdUPlE+Uj5RPrYZIaPyifKx8qUzB1Y+p3Es6X1LUflcus+nIybFkDFeUGw6cPpIqzruNk9Dn48kX8777dUJ5en/sVwpZ5jH8bDtn89jn9b065qu8ic=", "file_map": { "16": { "source": "use crate::cmp::Eq;\nuse crate::hash::Hash;\nuse crate::ops::arith::{Add, Neg, Sub};\n\n/// A point on the embedded elliptic curve\n/// By definition, the base field of the embedded curve is the scalar field of the proof system curve, i.e the Noir Field.\n/// x and y denotes the Weierstrass coordinates of the point, if is_infinite is false.\npub struct EmbeddedCurvePoint {\n pub x: Field,\n pub y: Field,\n pub is_infinite: bool,\n}\n\nimpl EmbeddedCurvePoint {\n /// Elliptic curve point doubling operation\n /// returns the doubled point of a point P, i.e P+P\n pub fn double(self) -> EmbeddedCurvePoint {\n embedded_curve_add(self, self)\n }\n\n /// Returns the null element of the curve; 'the point at infinity'\n pub fn point_at_infinity() -> EmbeddedCurvePoint {\n EmbeddedCurvePoint { x: 0, y: 0, is_infinite: true }\n }\n\n /// Returns the curve's generator point.\n pub fn generator() -> EmbeddedCurvePoint {\n // Generator point for the grumpkin curve (y^2 = x^3 - 17)\n EmbeddedCurvePoint {\n x: 1,\n y: 17631683881184975370165255887551781615748388533673675138860, // sqrt(-16)\n is_infinite: false,\n }\n }\n}\n\nimpl Add for EmbeddedCurvePoint {\n /// Adds two points P+Q, using the curve addition formula, and also handles point at infinity\n fn add(self, other: EmbeddedCurvePoint) -> EmbeddedCurvePoint {\n embedded_curve_add(self, other)\n }\n}\n\nimpl Sub for EmbeddedCurvePoint {\n /// Points subtraction operation, using addition and negation\n fn sub(self, other: EmbeddedCurvePoint) -> EmbeddedCurvePoint {\n self + other.neg()\n }\n}\n\nimpl Neg for EmbeddedCurvePoint {\n /// Negates a point P, i.e returns -P, by negating the y coordinate.\n /// If the point is at infinity, then the result is also at infinity.\n fn neg(self) -> EmbeddedCurvePoint {\n EmbeddedCurvePoint { x: self.x, y: -self.y, is_infinite: self.is_infinite }\n }\n}\n\nimpl Eq for EmbeddedCurvePoint {\n /// Checks whether two points are equal\n fn eq(self: Self, b: EmbeddedCurvePoint) -> bool {\n (self.is_infinite & b.is_infinite)\n | ((self.is_infinite == b.is_infinite) & (self.x == b.x) & (self.y == b.y))\n }\n}\n\nimpl Hash for EmbeddedCurvePoint {\n fn hash(self, state: &mut H)\n where\n H: crate::hash::Hasher,\n {\n if self.is_infinite {\n self.is_infinite.hash(state);\n } else {\n self.x.hash(state);\n self.y.hash(state);\n }\n }\n}\n\n/// Scalar for the embedded curve represented as low and high limbs\n/// By definition, the scalar field of the embedded curve is base field of the proving system curve.\n/// It may not fit into a Field element, so it is represented with two Field elements; its low and high limbs.\npub struct EmbeddedCurveScalar {\n pub lo: Field,\n pub hi: Field,\n}\n\nimpl EmbeddedCurveScalar {\n pub fn new(lo: Field, hi: Field) -> Self {\n EmbeddedCurveScalar { lo, hi }\n }\n\n #[field(bn254)]\n pub fn from_field(scalar: Field) -> EmbeddedCurveScalar {\n let (a, b) = crate::field::bn254::decompose(scalar);\n EmbeddedCurveScalar { lo: a, hi: b }\n }\n\n //Bytes to scalar: take the first (after the specified offset) 16 bytes of the input as the lo value, and the next 16 bytes as the hi value\n #[field(bn254)]\n pub(crate) fn from_bytes(bytes: [u8; 64], offset: u32) -> EmbeddedCurveScalar {\n let mut v = 1;\n let mut lo = 0 as Field;\n let mut hi = 0 as Field;\n for i in 0..16 {\n lo = lo + (bytes[offset + 31 - i] as Field) * v;\n hi = hi + (bytes[offset + 15 - i] as Field) * v;\n v = v * 256;\n }\n let sig_s = crate::embedded_curve_ops::EmbeddedCurveScalar { lo, hi };\n sig_s\n }\n}\n\nimpl Eq for EmbeddedCurveScalar {\n fn eq(self, other: Self) -> bool {\n (other.hi == self.hi) & (other.lo == self.lo)\n }\n}\n\nimpl Hash for EmbeddedCurveScalar {\n fn hash(self, state: &mut H)\n where\n H: crate::hash::Hasher,\n {\n self.hi.hash(state);\n self.lo.hash(state);\n }\n}\n\n// Computes a multi scalar multiplication over the embedded curve.\n// For bn254, We have Grumpkin and Baby JubJub.\n// For bls12-381, we have JubJub and Bandersnatch.\n//\n// The embedded curve being used is decided by the\n// underlying proof system.\n// docs:start:multi_scalar_mul\npub fn multi_scalar_mul(\n points: [EmbeddedCurvePoint; N],\n scalars: [EmbeddedCurveScalar; N],\n) -> EmbeddedCurvePoint\n// docs:end:multi_scalar_mul\n{\n multi_scalar_mul_array_return(points, scalars)[0]\n}\n\n#[foreign(multi_scalar_mul)]\npub(crate) fn multi_scalar_mul_array_return(\n points: [EmbeddedCurvePoint; N],\n scalars: [EmbeddedCurveScalar; N],\n) -> [EmbeddedCurvePoint; 1] {}\n\n// docs:start:fixed_base_scalar_mul\npub fn fixed_base_scalar_mul(scalar: EmbeddedCurveScalar) -> EmbeddedCurvePoint\n// docs:end:fixed_base_scalar_mul\n{\n multi_scalar_mul([EmbeddedCurvePoint::generator()], [scalar])\n}\n\n/// This function only assumes that the points are on the curve\n/// It handles corner cases around the infinity point causing some overhead compared to embedded_curve_add_not_nul and embedded_curve_add_unsafe\n// docs:start:embedded_curve_add\npub fn embedded_curve_add(\n point1: EmbeddedCurvePoint,\n point2: EmbeddedCurvePoint,\n) -> EmbeddedCurvePoint {\n // docs:end:embedded_curve_add\n if crate::runtime::is_unconstrained() {\n // `embedded_curve_add_unsafe` requires the inputs not to be the infinity point, so we check it here.\n // This is because `embedded_curve_add_unsafe` uses the `embedded_curve_add` opcode.\n // For efficiency, the backend does not check the inputs for the infinity point, but it assumes that they are not the infinity point\n // so that it can apply the ec addition formula directly.\n if point1.is_infinite {\n point2\n } else if point2.is_infinite {\n point1\n } else {\n embedded_curve_add_unsafe(point1, point2)\n }\n } else {\n // In a constrained context, we also need to check the inputs are not the infinity point because we also use `embedded_curve_add_unsafe`\n // However we also need to identify the case where the two inputs are the same, because then\n // the addition formula does not work and we need to use the doubling formula instead.\n // In unconstrained context, we can check directly if the input values are the same when solving the opcode, so it is not an issue.\n\n // x_coordinates_match is true if both abscissae are the same\n let x_coordinates_match = point1.x == point2.x;\n // y_coordinates_match is true if both ordinates are the same\n let y_coordinates_match = point1.y == point2.y;\n // double_predicate is true if both abscissae and ordinates are the same\n let double_predicate = (x_coordinates_match & y_coordinates_match);\n // If the abscissae are the same, but not the ordinates, then one point is the opposite of the other\n let infinity_predicate = (x_coordinates_match & !y_coordinates_match);\n let point1_1 = EmbeddedCurvePoint {\n x: point1.x + (x_coordinates_match as Field),\n y: point1.y,\n is_infinite: false,\n };\n let point2_1 = EmbeddedCurvePoint { x: point2.x, y: point2.y, is_infinite: false };\n // point1_1 is guaranteed to have a different abscissa than point2:\n // - if x_coordinates_match is 0, that means point1.x != point2.x, and point1_1.x = point1.x + 0\n // - if x_coordinates_match is 1, that means point1.x = point2.x, but point1_1.x = point1.x + 1 in this case\n // Because the abscissa is different, the addition formula is guaranteed to succeed, so we can safely use `embedded_curve_add_unsafe`\n // Note that this computation may be garbage: if x_coordinates_match is 1, or if one of the input is the point at infinity.\n let mut result = embedded_curve_add_unsafe(point1_1, point2_1);\n\n // `embedded_curve_add_unsafe` is doing a doubling if the input is the same variable, because in this case it is guaranteed (at 'compile time') that the input is the same.\n let double = embedded_curve_add_unsafe(point1, point1);\n // `embedded_curve_add_unsafe` would not perform doubling, even if the inputs point1 and point2 are the same, because it cannot know this without adding some logic (and some constraints)\n // However we did this logic when we computed `double_predicate`, so we set the result to 2*point1 if point1 and point2 are the same\n result = if double_predicate { double } else { result };\n\n // Same logic as above for unconstrained context, we set the proper result when one of the inputs is the infinity point\n if point1.is_infinite {\n result = point2;\n }\n if point2.is_infinite {\n result = point1;\n }\n\n // Finally, we set the is_infinity flag of the result:\n // Opposite points should sum into the infinity point, however, if one of them is point at infinity, their coordinates are not meaningful\n // so we should not use the fact that the inputs are opposite in this case:\n let mut result_is_infinity =\n infinity_predicate & (!point1.is_infinite & !point2.is_infinite);\n // However, if both of them are at infinity, then the result is also at infinity\n result.is_infinite = result_is_infinity | (point1.is_infinite & point2.is_infinite);\n result\n }\n}\n\n#[foreign(embedded_curve_add)]\nfn embedded_curve_add_array_return(\n _point1: EmbeddedCurvePoint,\n _point2: EmbeddedCurvePoint,\n) -> [EmbeddedCurvePoint; 1] {}\n\n/// This function assumes that:\n/// The points are on the curve, and\n/// The points don't share an x-coordinate, and\n/// Neither point is the infinity point.\n/// If it is used with correct input, the function ensures the correct non-zero result is returned.\n/// Except for points on the curve, the other assumptions are checked by the function. It will cause assertion failure if they are not respected.\npub fn embedded_curve_add_not_nul(\n point1: EmbeddedCurvePoint,\n point2: EmbeddedCurvePoint,\n) -> EmbeddedCurvePoint {\n assert(point1.x != point2.x);\n assert(!point1.is_infinite);\n assert(!point2.is_infinite);\n // Ensure is_infinite is comptime\n let point1_1 = EmbeddedCurvePoint { x: point1.x, y: point1.y, is_infinite: false };\n let point2_1 = EmbeddedCurvePoint { x: point2.x, y: point2.y, is_infinite: false };\n embedded_curve_add_unsafe(point1_1, point2_1)\n}\n\n/// Unsafe ec addition\n/// If the inputs are the same, it will perform a doubling, but only if point1 and point2 are the same variable.\n/// If they have the same value but are different variables, the result will be incorrect because in this case\n/// it assumes (but does not check) that the points' x-coordinates are not equal.\n/// It also assumes neither point is the infinity point.\npub fn embedded_curve_add_unsafe(\n point1: EmbeddedCurvePoint,\n point2: EmbeddedCurvePoint,\n) -> EmbeddedCurvePoint {\n embedded_curve_add_array_return(point1, point2)[0]\n}\n", diff --git a/tooling/nargo_cli/tests/snapshots/execution_success/embedded_curve_ops/execute__tests__force_brillig_false_inliner_0.snap b/tooling/nargo_cli/tests/snapshots/execution_success/embedded_curve_ops/execute__tests__force_brillig_false_inliner_0.snap index 12800efb646..a134c1bd4f7 100644 --- a/tooling/nargo_cli/tests/snapshots/execution_success/embedded_curve_ops/execute__tests__force_brillig_false_inliner_0.snap +++ b/tooling/nargo_cli/tests/snapshots/execution_success/embedded_curve_ops/execute__tests__force_brillig_false_inliner_0.snap @@ -34,63 +34,65 @@ expression: artifact }, "bytecode": [ "func 0", - "current witness index : _61", + "current witness index : _63", "private parameters indices : [_0]", "public parameters indices : [_1, _2]", "return value indices : []", "BLACKBOX::MULTI_SCALAR_MUL [(1, 254), (17631683881184975370165255887551781615748388533673675138860, 254), (0, 1), (_0, 254), (0, 254)] [_3, _4, _5]", "EXPR [ (-1, _1) (1, _3) 0 ]", "EXPR [ (-1, _2) (1, _4) 0 ]", - "BLACKBOX::EMBEDDED_CURVE_ADD [(_1, 254), (_2, 254), (0, 1), (_1, 254), (_2, 254), (0, 1)] [_6, _7, _8]", - "EXPR [ (-1, _6) 3078034153852398078128400807926804309327113743808504829582559963737223069694 ]", - "BLACKBOX::MULTI_SCALAR_MUL [(1, 254), (17631683881184975370165255887551781615748388533673675138860, 254), (0, 1), (1, 254), (17631683881184975370165255887551781615748388533673675138860, 254), (0, 1), (_0, 254), (0, 254), (_0, 254), (0, 254)] [_9, _10, _11]", - "EXPR [ (-1, _9) 3078034153852398078128400807926804309327113743808504829582559963737223069694 ]", - "BLACKBOX::MULTI_SCALAR_MUL [(1, 254), (17631683881184975370165255887551781615748388533673675138860, 254), (0, 1), (_1, 254), (_2, 254), (0, 1), (11179562631109628533987091031692370366552561688588090155835439555627259799605, 254), (3443719903172018228650470536370404288991794296383447657609081676265727805364, 254), (0, 1), (_0, 254), (0, 254), (_0, 254), (0, 254), (1, 254), (0, 254)] [_12, _13, _14]", - "EXPR [ (1, _12) 7349266043899242844836273743257843180744506495159104166319746739537754653274 ]", - "BLACKBOX::MULTI_SCALAR_MUL [(1, 254), (17631683881184975370165255887551781615748388533673675138860, 254), (0, 1), (_0, 254), (0, 254)] [_15, _16, _17]", - "EXPR [ (1, _17) 0 ]", - "EXPR [ (1, _15) -1 ]", - "EXPR [ (1, _16) -17631683881184975370165255887551781615748388533673675138860 ]", - "EXPR [ (1, _1) (-1, _2) (-1, _18) 0 ]", - "BRILLIG CALL func 0: inputs: [Single(Expression { mul_terms: [], linear_combinations: [(1, Witness(18))], q_c: 0 })], outputs: [Simple(Witness(19))]", - "EXPR [ (1, _18, _19) (1, _20) -1 ]", - "EXPR [ (1, _18, _20) 0 ]", - "EXPR [ (-17631683881184975370165255887551781615748388533673675138858, _20) (-1, _21) 17631683881184975370165255887551781615748388533673675138860 ]", - "BLACKBOX::EMBEDDED_CURVE_ADD [(1, 254), (_21, 254), (0, 1), (1, 254), (_21, 254), (0, 1)] [_22, _23, _24]", - "EXPR [ (1, _20, _22) (-1, _20) 0 ]", - "EXPR [ (-3078034153852398078128400807926804309327113743808504829582559963737223069693, _20) (-1, _25) 3078034153852398078128400807926804309327113743808504829582559963737223069694 ]", - "EXPR [ (9191351987198133172789796342745422989482268917117950487758512501574271532888, _20) (-1, _26) -9191351987198133172789796342745422989482268917117950487758512501574271532885 ]", - "BLACKBOX::EMBEDDED_CURVE_ADD [(1, 254), (_21, 254), (0, 1), (_25, 254), (_26, 254), (0, 1)] [_27, _28, _29]", - "EXPR [ (1, _20, _27) (-1, _20) 0 ]", - "EXPR [ (1, _1, _20) (-1, _30) 1 ]", - "EXPR [ (1, _2, _20) (-17631683881184975370165255887551781615748388533673675138860, _20) (-1, _31) 17631683881184975370165255887551781615748388533673675138860 ]", - "BLACKBOX::EMBEDDED_CURVE_ADD [(_30, 254), (_31, 254), (0, 1), (_30, 254), (_31, 254), (0, 1)] [_32, _33, _34]", - "EXPR [ (1, _20, _32) (-1, _20) 0 ]", - "EXPR [ (1, _1, _20) (-3078034153852398078128400807926804309327113743808504829582559963737223069693, _20) (-1, _35) 3078034153852398078128400807926804309327113743808504829582559963737223069694 ]", - "EXPR [ (1, _2, _20) (9191351987198133172789796342745422989482268917117950487758512501574271532886, _20) (-1, _36) -9191351987198133172789796342745422989482268917117950487758512501574271532885 ]", - "BLACKBOX::EMBEDDED_CURVE_ADD [(_30, 254), (_31, 254), (0, 1), (_35, 254), (_36, 254), (0, 1)] [_37, _38, _39]", - "EXPR [ (1, _20, _37) (-1, _20) 0 ]", - "EXPR [ (1, _20) (-1, _40) 1 ]", - "EXPR [ (-17631683881184975370165255887551781615748388533673675138857, _20) (-1, _41) 17631683881184975370165255887551781615748388533673675138860 ]", - "EXPR [ (1, _1, _20) (-3078034153852398078128400807926804309327113743808504829582559963737223069694, _20) (-1, _42) 3078034153852398078128400807926804309327113743808504829582559963737223069694 ]", - "BLACKBOX::EMBEDDED_CURVE_ADD [(_40, 254), (_41, 254), (0, 1), (_42, 254), (_36, 254), (0, 1)] [_43, _44, _45]", - "EXPR [ (1, _20, _43) (-1, _20) 0 ]", - "EXPR [ (-3078034153852398078128400807926804309327113743808504829582559963737223069692, _20) (-1, _46) 3078034153852398078128400807926804309327113743808504829582559963737223069694 ]", - "EXPR [ (9191351987198133172789796342745422989482268917117950487758512501574271532889, _20) (-1, _47) -9191351987198133172789796342745422989482268917117950487758512501574271532885 ]", - "BLACKBOX::EMBEDDED_CURVE_ADD [(_40, 254), (_41, 254), (0, 1), (_46, 254), (_47, 254), (0, 1)] [_48, _49, _50]", - "EXPR [ (1, _20, _48) (-1, _20) 0 ]", - "BLACKBOX::EMBEDDED_CURVE_ADD [(_40, 254), (_41, 254), (0, 1), (_40, 254), (_41, 254), (0, 1)] [_51, _52, _53]", - "EXPR [ (1, _20, _51) (-1, _20) 0 ]", - "BLACKBOX::EMBEDDED_CURVE_ADD [(1, 254), (_41, 254), (0, 1), (1, 254), (_41, 254), (0, 1)] [_54, _55, _56]", - "EXPR [ (1, _20, _54) (-1, _20) 0 ]", - "EXPR [ (1, _1, _20) (-1, _20) (-1, _57) 1 ]", - "EXPR [ (9191351987198133172789796342745422989482268917117950487758512501574271532887, _20) (-1, _58) -9191351987198133172789796342745422989482268917117950487758512501574271532885 ]", - "BLACKBOX::EMBEDDED_CURVE_ADD [(_57, 254), (_41, 254), (0, 1), (_42, 254), (_58, 254), (0, 1)] [_59, _60, _61]", - "EXPR [ (1, _20, _59) (-1, _20) 0 ]", + "EXPR [ (-1, _6) 0 ]", + "BLACKBOX::EMBEDDED_CURVE_ADD [(_1, 254), (_2, 254), (_6, 1), (_1, 254), (_2, 254), (_6, 1)] [_7, _8, _9]", + "EXPR [ (-1, _7) 3078034153852398078128400807926804309327113743808504829582559963737223069694 ]", + "BLACKBOX::MULTI_SCALAR_MUL [(1, 254), (17631683881184975370165255887551781615748388533673675138860, 254), (0, 1), (1, 254), (17631683881184975370165255887551781615748388533673675138860, 254), (0, 1), (_0, 254), (0, 254), (_0, 254), (0, 254)] [_10, _11, _12]", + "EXPR [ (-1, _10) 3078034153852398078128400807926804309327113743808504829582559963737223069694 ]", + "BLACKBOX::MULTI_SCALAR_MUL [(1, 254), (17631683881184975370165255887551781615748388533673675138860, 254), (0, 1), (_1, 254), (_2, 254), (0, 1), (11179562631109628533987091031692370366552561688588090155835439555627259799605, 254), (3443719903172018228650470536370404288991794296383447657609081676265727805364, 254), (0, 1), (_0, 254), (0, 254), (_0, 254), (0, 254), (1, 254), (0, 254)] [_13, _14, _15]", + "EXPR [ (1, _13) 7349266043899242844836273743257843180744506495159104166319746739537754653274 ]", + "BLACKBOX::MULTI_SCALAR_MUL [(1, 254), (17631683881184975370165255887551781615748388533673675138860, 254), (0, 1), (_0, 254), (0, 254)] [_16, _17, _18]", + "EXPR [ (1, _18) 0 ]", + "EXPR [ (1, _16) -1 ]", + "EXPR [ (1, _17) -17631683881184975370165255887551781615748388533673675138860 ]", + "EXPR [ (1, _1) (-1, _2) (-1, _19) 0 ]", + "BRILLIG CALL func 0: inputs: [Single(Expression { mul_terms: [], linear_combinations: [(1, Witness(19))], q_c: 0 })], outputs: [Simple(Witness(20))]", + "EXPR [ (1, _19, _20) (1, _21) -1 ]", + "EXPR [ (1, _19, _21) 0 ]", + "EXPR [ (-17631683881184975370165255887551781615748388533673675138858, _21) (-1, _22) 17631683881184975370165255887551781615748388533673675138860 ]", + "EXPR [ (-1, _23) 1 ]", + "BLACKBOX::EMBEDDED_CURVE_ADD [(_23, 254), (_22, 254), (_6, 1), (_23, 254), (_22, 254), (_6, 1)] [_24, _25, _26]", + "EXPR [ (1, _21, _24) (-1, _21) 0 ]", + "EXPR [ (-3078034153852398078128400807926804309327113743808504829582559963737223069693, _21) (-1, _27) 3078034153852398078128400807926804309327113743808504829582559963737223069694 ]", + "EXPR [ (9191351987198133172789796342745422989482268917117950487758512501574271532888, _21) (-1, _28) -9191351987198133172789796342745422989482268917117950487758512501574271532885 ]", + "BLACKBOX::EMBEDDED_CURVE_ADD [(_23, 254), (_22, 254), (_6, 1), (_27, 254), (_28, 254), (_6, 1)] [_29, _30, _31]", + "EXPR [ (1, _21, _29) (-1, _21) 0 ]", + "EXPR [ (1, _1, _21) (-1, _32) 1 ]", + "EXPR [ (1, _2, _21) (-17631683881184975370165255887551781615748388533673675138860, _21) (-1, _33) 17631683881184975370165255887551781615748388533673675138860 ]", + "BLACKBOX::EMBEDDED_CURVE_ADD [(_32, 254), (_33, 254), (_6, 1), (_32, 254), (_33, 254), (_6, 1)] [_34, _35, _36]", + "EXPR [ (1, _21, _34) (-1, _21) 0 ]", + "EXPR [ (1, _1, _21) (-3078034153852398078128400807926804309327113743808504829582559963737223069693, _21) (-1, _37) 3078034153852398078128400807926804309327113743808504829582559963737223069694 ]", + "EXPR [ (1, _2, _21) (9191351987198133172789796342745422989482268917117950487758512501574271532886, _21) (-1, _38) -9191351987198133172789796342745422989482268917117950487758512501574271532885 ]", + "BLACKBOX::EMBEDDED_CURVE_ADD [(_32, 254), (_33, 254), (_6, 1), (_37, 254), (_38, 254), (_6, 1)] [_39, _40, _41]", + "EXPR [ (1, _21, _39) (-1, _21) 0 ]", + "EXPR [ (1, _21) (-1, _42) 1 ]", + "EXPR [ (-17631683881184975370165255887551781615748388533673675138857, _21) (-1, _43) 17631683881184975370165255887551781615748388533673675138860 ]", + "EXPR [ (1, _1, _21) (-3078034153852398078128400807926804309327113743808504829582559963737223069694, _21) (-1, _44) 3078034153852398078128400807926804309327113743808504829582559963737223069694 ]", + "BLACKBOX::EMBEDDED_CURVE_ADD [(_42, 254), (_43, 254), (_6, 1), (_44, 254), (_38, 254), (_6, 1)] [_45, _46, _47]", + "EXPR [ (1, _21, _45) (-1, _21) 0 ]", + "EXPR [ (-3078034153852398078128400807926804309327113743808504829582559963737223069692, _21) (-1, _48) 3078034153852398078128400807926804309327113743808504829582559963737223069694 ]", + "EXPR [ (9191351987198133172789796342745422989482268917117950487758512501574271532889, _21) (-1, _49) -9191351987198133172789796342745422989482268917117950487758512501574271532885 ]", + "BLACKBOX::EMBEDDED_CURVE_ADD [(_42, 254), (_43, 254), (_6, 1), (_48, 254), (_49, 254), (_6, 1)] [_50, _51, _52]", + "EXPR [ (1, _21, _50) (-1, _21) 0 ]", + "BLACKBOX::EMBEDDED_CURVE_ADD [(_42, 254), (_43, 254), (_6, 1), (_42, 254), (_43, 254), (_6, 1)] [_53, _54, _55]", + "EXPR [ (1, _21, _53) (-1, _21) 0 ]", + "BLACKBOX::EMBEDDED_CURVE_ADD [(_23, 254), (_43, 254), (_6, 1), (_23, 254), (_43, 254), (_6, 1)] [_56, _57, _58]", + "EXPR [ (1, _21, _56) (-1, _21) 0 ]", + "EXPR [ (1, _1, _21) (-1, _21) (-1, _59) 1 ]", + "EXPR [ (9191351987198133172789796342745422989482268917117950487758512501574271532887, _21) (-1, _60) -9191351987198133172789796342745422989482268917117950487758512501574271532885 ]", + "BLACKBOX::EMBEDDED_CURVE_ADD [(_59, 254), (_43, 254), (_6, 1), (_44, 254), (_60, 254), (_6, 1)] [_61, _62, _63]", + "EXPR [ (1, _21, _61) (-1, _21) 0 ]", "unconstrained func 0", "[Const { destination: Direct(21), bit_size: Integer(U32), value: 1 }, Const { destination: Direct(20), bit_size: Integer(U32), value: 0 }, CalldataCopy { destination_address: Direct(0), size_address: Direct(21), offset_address: Direct(20) }, Const { destination: Direct(2), bit_size: Field, value: 0 }, BinaryFieldOp { destination: Direct(3), op: Equals, lhs: Direct(0), rhs: Direct(2) }, JumpIf { condition: Direct(3), location: 8 }, Const { destination: Direct(1), bit_size: Field, value: 1 }, BinaryFieldOp { destination: Direct(0), op: Div, lhs: Direct(1), rhs: Direct(0) }, Stop { return_data: HeapVector { pointer: Direct(20), size: Direct(21) } }]" ], - "debug_symbols": "tVjLbuMwDPwXnX0QX3rsrywWRZq6RQDDCdxkgUXRf1+qlez0oKBV7NMksTkhR+TY0pt56h8vLw+H8fn4an79fjOP02EYDi8Pw3G/Ox+Oo/769t6Z8vXhPPW9/mSurmvUaTf149n8Gi/D0Jm/u+HycdPraTd+4Hk36VXbmX58UlTC58PQp0/v3RJt66EYJAdjcHO4fDuePOR4xlCLx3o8S+RC4HgpAFwbA9UYbtTAPNcg0qABu1jiAzXEu1jWwAPU4v2NeCz5O4Fa/aEe71GwJICRGhgC2ZJCIMYaA9wQAQCtzxz6WXgNEt/QDV5cEcO3rGZwRYpIthYPfPdIfJ+iZSbAMhUhrbMNOgD5mUGoqiSE+5UImyohXBoCHMYWJYIvOUCMXHXJFWxyU59EOw8XWuQGJVDnszAANTGQlCqQXLWr8F67xFtuZ2e/DDZWPQbjCm6H97suwQp5/ISkxXWRAs7reqXpDzqDkw98MrBUn6Mka6ghG6vBbqnFhxY1PM+T5rnFtTDAPO0Bq++GbO+cNIa7J41xhTW9mcf3Jo15jTx4494KfPXKb5s6IxQ1MELVxTmsoUbYWI1ISy0MLTsgxPKeQyjVOZE1evQnJC1qEPqllqa9DHEsmyESwqoabg013MZqCC+1SIuHkvdl1ijYqo+7NfZFbuN9kT6gl1qoaZ9spTyT2Na7y63hom5jF2Wwcy0ALS7KRGXWmFzVN9waLuo2dlHWjphriV9X9o9+2+0P05eTL2O1izoDektnUBPsDKW/7wynnWNnJG28OuMUNDmfdk6dCWnb0JmY3hE1WDlSSwJkxIzKhEoInFEyuow+uZtiyBiTbWkaKSe9jpARM1LqeEVOmyhFyegyKh9rkqh8yTAwfiLZjKlKTZuUTzRvooycUTIqnygfKZ8oH4WM8RNZ+UT5WPnSGQMn3TSOKb1fKSqfS/dJOlJSdBl9xpAOmN7TKk6H3ePQ5yPI58u4vzqRPP87lSvlzPI0Hff902Xq0xp+XNNV/Q8=", + "debug_symbols": "tVjLbuowEP0Xr7PwvPzor1xdVZSmFVIEKIUrXVX9946LndCFUWuS1QGSOcwce04yfjfP/dP59XG3fzm8mYc/7+Zp3A3D7vVxOGw3p91hr7++f3SmfH08jX2vP5mr6xp13Iz9/mQe9udh6My/zXD+uuntuNl/4Wkz6lXbmX7/rKiEL7uhT58+ujna1kMxSA7G4KZw+XE8ecjxjKEWj/V4lsiFwPFcALg2Bqox3KiBeapBpEEDdrHEB2qId7GsgQeoxfsb8VjydwK1+kM93qNgSQAjNTAEsiWFQIw1BrghAgBanzn0s/ASJL5hN3hxRQzfsprBFSki2Vo88N0t8XOKlp4Ay1SEtM426ADkJwahqpIQ7lcirKqEcNkQ4DC2KBF8yQFi5KpLLmCTq/ok2qm50CI3KIHan4UBqImBpFSB5Kq7Cu+1S7zldnbyy2Bj1WMwLuB2eL/rEiyQx29IWlwXKeC0rlea/mJncPKBCwNL9TlKsoQasrIa7OZafGhRw/PUaZ5bXAsDTN0esPpuyPbOTmO4u9MYF1jTm3n8rNOYl8iDV95bga9e+W3TzghFDYxQdXEOS6gRVlYj0lwLQ8sEhFjecwil2ieyxB79DUmLGoR+rqVpliGOZRgiIayq4ZZQw62shvBci7R4KHlfeo2Crfq4W2IucivPRfqAnmuhpjnZSnkmsa3vLreEi7qVXZTBTrUAtLgoE5VeY3JV33BLuKhb2UVZd8RUS/y+sn/122a7G7+dfBmru6gzoLd0BjXBzlD6+87wBSQNkJ1xaf7qjFfQHEMaoDoT0/SgwTa9KyoqS9qagBkpo1KhEoNkdBl9xpBcTjFeEG1GSDamqHyk9yFl5IySOkDRpaFK0WcMGZWPNVtSvmQgBBkxo/KJ5k/KJ5o/SUaX0WdUPlE+Uj5RPrYZIaPyifKx8qUzB1Y+p3Es6X1LUflcus+nIybFkDFeUGw6cPpIqzruNk9Dn48kX8777dUJ5en/sVwpZ5jH8bDtn89jn9b065qu8ic=", "file_map": { "16": { "source": "use crate::cmp::Eq;\nuse crate::hash::Hash;\nuse crate::ops::arith::{Add, Neg, Sub};\n\n/// A point on the embedded elliptic curve\n/// By definition, the base field of the embedded curve is the scalar field of the proof system curve, i.e the Noir Field.\n/// x and y denotes the Weierstrass coordinates of the point, if is_infinite is false.\npub struct EmbeddedCurvePoint {\n pub x: Field,\n pub y: Field,\n pub is_infinite: bool,\n}\n\nimpl EmbeddedCurvePoint {\n /// Elliptic curve point doubling operation\n /// returns the doubled point of a point P, i.e P+P\n pub fn double(self) -> EmbeddedCurvePoint {\n embedded_curve_add(self, self)\n }\n\n /// Returns the null element of the curve; 'the point at infinity'\n pub fn point_at_infinity() -> EmbeddedCurvePoint {\n EmbeddedCurvePoint { x: 0, y: 0, is_infinite: true }\n }\n\n /// Returns the curve's generator point.\n pub fn generator() -> EmbeddedCurvePoint {\n // Generator point for the grumpkin curve (y^2 = x^3 - 17)\n EmbeddedCurvePoint {\n x: 1,\n y: 17631683881184975370165255887551781615748388533673675138860, // sqrt(-16)\n is_infinite: false,\n }\n }\n}\n\nimpl Add for EmbeddedCurvePoint {\n /// Adds two points P+Q, using the curve addition formula, and also handles point at infinity\n fn add(self, other: EmbeddedCurvePoint) -> EmbeddedCurvePoint {\n embedded_curve_add(self, other)\n }\n}\n\nimpl Sub for EmbeddedCurvePoint {\n /// Points subtraction operation, using addition and negation\n fn sub(self, other: EmbeddedCurvePoint) -> EmbeddedCurvePoint {\n self + other.neg()\n }\n}\n\nimpl Neg for EmbeddedCurvePoint {\n /// Negates a point P, i.e returns -P, by negating the y coordinate.\n /// If the point is at infinity, then the result is also at infinity.\n fn neg(self) -> EmbeddedCurvePoint {\n EmbeddedCurvePoint { x: self.x, y: -self.y, is_infinite: self.is_infinite }\n }\n}\n\nimpl Eq for EmbeddedCurvePoint {\n /// Checks whether two points are equal\n fn eq(self: Self, b: EmbeddedCurvePoint) -> bool {\n (self.is_infinite & b.is_infinite)\n | ((self.is_infinite == b.is_infinite) & (self.x == b.x) & (self.y == b.y))\n }\n}\n\nimpl Hash for EmbeddedCurvePoint {\n fn hash(self, state: &mut H)\n where\n H: crate::hash::Hasher,\n {\n if self.is_infinite {\n self.is_infinite.hash(state);\n } else {\n self.x.hash(state);\n self.y.hash(state);\n }\n }\n}\n\n/// Scalar for the embedded curve represented as low and high limbs\n/// By definition, the scalar field of the embedded curve is base field of the proving system curve.\n/// It may not fit into a Field element, so it is represented with two Field elements; its low and high limbs.\npub struct EmbeddedCurveScalar {\n pub lo: Field,\n pub hi: Field,\n}\n\nimpl EmbeddedCurveScalar {\n pub fn new(lo: Field, hi: Field) -> Self {\n EmbeddedCurveScalar { lo, hi }\n }\n\n #[field(bn254)]\n pub fn from_field(scalar: Field) -> EmbeddedCurveScalar {\n let (a, b) = crate::field::bn254::decompose(scalar);\n EmbeddedCurveScalar { lo: a, hi: b }\n }\n\n //Bytes to scalar: take the first (after the specified offset) 16 bytes of the input as the lo value, and the next 16 bytes as the hi value\n #[field(bn254)]\n pub(crate) fn from_bytes(bytes: [u8; 64], offset: u32) -> EmbeddedCurveScalar {\n let mut v = 1;\n let mut lo = 0 as Field;\n let mut hi = 0 as Field;\n for i in 0..16 {\n lo = lo + (bytes[offset + 31 - i] as Field) * v;\n hi = hi + (bytes[offset + 15 - i] as Field) * v;\n v = v * 256;\n }\n let sig_s = crate::embedded_curve_ops::EmbeddedCurveScalar { lo, hi };\n sig_s\n }\n}\n\nimpl Eq for EmbeddedCurveScalar {\n fn eq(self, other: Self) -> bool {\n (other.hi == self.hi) & (other.lo == self.lo)\n }\n}\n\nimpl Hash for EmbeddedCurveScalar {\n fn hash(self, state: &mut H)\n where\n H: crate::hash::Hasher,\n {\n self.hi.hash(state);\n self.lo.hash(state);\n }\n}\n\n// Computes a multi scalar multiplication over the embedded curve.\n// For bn254, We have Grumpkin and Baby JubJub.\n// For bls12-381, we have JubJub and Bandersnatch.\n//\n// The embedded curve being used is decided by the\n// underlying proof system.\n// docs:start:multi_scalar_mul\npub fn multi_scalar_mul(\n points: [EmbeddedCurvePoint; N],\n scalars: [EmbeddedCurveScalar; N],\n) -> EmbeddedCurvePoint\n// docs:end:multi_scalar_mul\n{\n multi_scalar_mul_array_return(points, scalars)[0]\n}\n\n#[foreign(multi_scalar_mul)]\npub(crate) fn multi_scalar_mul_array_return(\n points: [EmbeddedCurvePoint; N],\n scalars: [EmbeddedCurveScalar; N],\n) -> [EmbeddedCurvePoint; 1] {}\n\n// docs:start:fixed_base_scalar_mul\npub fn fixed_base_scalar_mul(scalar: EmbeddedCurveScalar) -> EmbeddedCurvePoint\n// docs:end:fixed_base_scalar_mul\n{\n multi_scalar_mul([EmbeddedCurvePoint::generator()], [scalar])\n}\n\n/// This function only assumes that the points are on the curve\n/// It handles corner cases around the infinity point causing some overhead compared to embedded_curve_add_not_nul and embedded_curve_add_unsafe\n// docs:start:embedded_curve_add\npub fn embedded_curve_add(\n point1: EmbeddedCurvePoint,\n point2: EmbeddedCurvePoint,\n) -> EmbeddedCurvePoint {\n // docs:end:embedded_curve_add\n if crate::runtime::is_unconstrained() {\n // `embedded_curve_add_unsafe` requires the inputs not to be the infinity point, so we check it here.\n // This is because `embedded_curve_add_unsafe` uses the `embedded_curve_add` opcode.\n // For efficiency, the backend does not check the inputs for the infinity point, but it assumes that they are not the infinity point\n // so that it can apply the ec addition formula directly.\n if point1.is_infinite {\n point2\n } else if point2.is_infinite {\n point1\n } else {\n embedded_curve_add_unsafe(point1, point2)\n }\n } else {\n // In a constrained context, we also need to check the inputs are not the infinity point because we also use `embedded_curve_add_unsafe`\n // However we also need to identify the case where the two inputs are the same, because then\n // the addition formula does not work and we need to use the doubling formula instead.\n // In unconstrained context, we can check directly if the input values are the same when solving the opcode, so it is not an issue.\n\n // x_coordinates_match is true if both abscissae are the same\n let x_coordinates_match = point1.x == point2.x;\n // y_coordinates_match is true if both ordinates are the same\n let y_coordinates_match = point1.y == point2.y;\n // double_predicate is true if both abscissae and ordinates are the same\n let double_predicate = (x_coordinates_match & y_coordinates_match);\n // If the abscissae are the same, but not the ordinates, then one point is the opposite of the other\n let infinity_predicate = (x_coordinates_match & !y_coordinates_match);\n let point1_1 = EmbeddedCurvePoint {\n x: point1.x + (x_coordinates_match as Field),\n y: point1.y,\n is_infinite: false,\n };\n let point2_1 = EmbeddedCurvePoint { x: point2.x, y: point2.y, is_infinite: false };\n // point1_1 is guaranteed to have a different abscissa than point2:\n // - if x_coordinates_match is 0, that means point1.x != point2.x, and point1_1.x = point1.x + 0\n // - if x_coordinates_match is 1, that means point1.x = point2.x, but point1_1.x = point1.x + 1 in this case\n // Because the abscissa is different, the addition formula is guaranteed to succeed, so we can safely use `embedded_curve_add_unsafe`\n // Note that this computation may be garbage: if x_coordinates_match is 1, or if one of the input is the point at infinity.\n let mut result = embedded_curve_add_unsafe(point1_1, point2_1);\n\n // `embedded_curve_add_unsafe` is doing a doubling if the input is the same variable, because in this case it is guaranteed (at 'compile time') that the input is the same.\n let double = embedded_curve_add_unsafe(point1, point1);\n // `embedded_curve_add_unsafe` would not perform doubling, even if the inputs point1 and point2 are the same, because it cannot know this without adding some logic (and some constraints)\n // However we did this logic when we computed `double_predicate`, so we set the result to 2*point1 if point1 and point2 are the same\n result = if double_predicate { double } else { result };\n\n // Same logic as above for unconstrained context, we set the proper result when one of the inputs is the infinity point\n if point1.is_infinite {\n result = point2;\n }\n if point2.is_infinite {\n result = point1;\n }\n\n // Finally, we set the is_infinity flag of the result:\n // Opposite points should sum into the infinity point, however, if one of them is point at infinity, their coordinates are not meaningful\n // so we should not use the fact that the inputs are opposite in this case:\n let mut result_is_infinity =\n infinity_predicate & (!point1.is_infinite & !point2.is_infinite);\n // However, if both of them are at infinity, then the result is also at infinity\n result.is_infinite = result_is_infinity | (point1.is_infinite & point2.is_infinite);\n result\n }\n}\n\n#[foreign(embedded_curve_add)]\nfn embedded_curve_add_array_return(\n _point1: EmbeddedCurvePoint,\n _point2: EmbeddedCurvePoint,\n) -> [EmbeddedCurvePoint; 1] {}\n\n/// This function assumes that:\n/// The points are on the curve, and\n/// The points don't share an x-coordinate, and\n/// Neither point is the infinity point.\n/// If it is used with correct input, the function ensures the correct non-zero result is returned.\n/// Except for points on the curve, the other assumptions are checked by the function. It will cause assertion failure if they are not respected.\npub fn embedded_curve_add_not_nul(\n point1: EmbeddedCurvePoint,\n point2: EmbeddedCurvePoint,\n) -> EmbeddedCurvePoint {\n assert(point1.x != point2.x);\n assert(!point1.is_infinite);\n assert(!point2.is_infinite);\n // Ensure is_infinite is comptime\n let point1_1 = EmbeddedCurvePoint { x: point1.x, y: point1.y, is_infinite: false };\n let point2_1 = EmbeddedCurvePoint { x: point2.x, y: point2.y, is_infinite: false };\n embedded_curve_add_unsafe(point1_1, point2_1)\n}\n\n/// Unsafe ec addition\n/// If the inputs are the same, it will perform a doubling, but only if point1 and point2 are the same variable.\n/// If they have the same value but are different variables, the result will be incorrect because in this case\n/// it assumes (but does not check) that the points' x-coordinates are not equal.\n/// It also assumes neither point is the infinity point.\npub fn embedded_curve_add_unsafe(\n point1: EmbeddedCurvePoint,\n point2: EmbeddedCurvePoint,\n) -> EmbeddedCurvePoint {\n embedded_curve_add_array_return(point1, point2)[0]\n}\n", diff --git a/tooling/nargo_cli/tests/snapshots/execution_success/embedded_curve_ops/execute__tests__force_brillig_false_inliner_9223372036854775807.snap b/tooling/nargo_cli/tests/snapshots/execution_success/embedded_curve_ops/execute__tests__force_brillig_false_inliner_9223372036854775807.snap index 12800efb646..a134c1bd4f7 100644 --- a/tooling/nargo_cli/tests/snapshots/execution_success/embedded_curve_ops/execute__tests__force_brillig_false_inliner_9223372036854775807.snap +++ b/tooling/nargo_cli/tests/snapshots/execution_success/embedded_curve_ops/execute__tests__force_brillig_false_inliner_9223372036854775807.snap @@ -34,63 +34,65 @@ expression: artifact }, "bytecode": [ "func 0", - "current witness index : _61", + "current witness index : _63", "private parameters indices : [_0]", "public parameters indices : [_1, _2]", "return value indices : []", "BLACKBOX::MULTI_SCALAR_MUL [(1, 254), (17631683881184975370165255887551781615748388533673675138860, 254), (0, 1), (_0, 254), (0, 254)] [_3, _4, _5]", "EXPR [ (-1, _1) (1, _3) 0 ]", "EXPR [ (-1, _2) (1, _4) 0 ]", - "BLACKBOX::EMBEDDED_CURVE_ADD [(_1, 254), (_2, 254), (0, 1), (_1, 254), (_2, 254), (0, 1)] [_6, _7, _8]", - "EXPR [ (-1, _6) 3078034153852398078128400807926804309327113743808504829582559963737223069694 ]", - "BLACKBOX::MULTI_SCALAR_MUL [(1, 254), (17631683881184975370165255887551781615748388533673675138860, 254), (0, 1), (1, 254), (17631683881184975370165255887551781615748388533673675138860, 254), (0, 1), (_0, 254), (0, 254), (_0, 254), (0, 254)] [_9, _10, _11]", - "EXPR [ (-1, _9) 3078034153852398078128400807926804309327113743808504829582559963737223069694 ]", - "BLACKBOX::MULTI_SCALAR_MUL [(1, 254), (17631683881184975370165255887551781615748388533673675138860, 254), (0, 1), (_1, 254), (_2, 254), (0, 1), (11179562631109628533987091031692370366552561688588090155835439555627259799605, 254), (3443719903172018228650470536370404288991794296383447657609081676265727805364, 254), (0, 1), (_0, 254), (0, 254), (_0, 254), (0, 254), (1, 254), (0, 254)] [_12, _13, _14]", - "EXPR [ (1, _12) 7349266043899242844836273743257843180744506495159104166319746739537754653274 ]", - "BLACKBOX::MULTI_SCALAR_MUL [(1, 254), (17631683881184975370165255887551781615748388533673675138860, 254), (0, 1), (_0, 254), (0, 254)] [_15, _16, _17]", - "EXPR [ (1, _17) 0 ]", - "EXPR [ (1, _15) -1 ]", - "EXPR [ (1, _16) -17631683881184975370165255887551781615748388533673675138860 ]", - "EXPR [ (1, _1) (-1, _2) (-1, _18) 0 ]", - "BRILLIG CALL func 0: inputs: [Single(Expression { mul_terms: [], linear_combinations: [(1, Witness(18))], q_c: 0 })], outputs: [Simple(Witness(19))]", - "EXPR [ (1, _18, _19) (1, _20) -1 ]", - "EXPR [ (1, _18, _20) 0 ]", - "EXPR [ (-17631683881184975370165255887551781615748388533673675138858, _20) (-1, _21) 17631683881184975370165255887551781615748388533673675138860 ]", - "BLACKBOX::EMBEDDED_CURVE_ADD [(1, 254), (_21, 254), (0, 1), (1, 254), (_21, 254), (0, 1)] [_22, _23, _24]", - "EXPR [ (1, _20, _22) (-1, _20) 0 ]", - "EXPR [ (-3078034153852398078128400807926804309327113743808504829582559963737223069693, _20) (-1, _25) 3078034153852398078128400807926804309327113743808504829582559963737223069694 ]", - "EXPR [ (9191351987198133172789796342745422989482268917117950487758512501574271532888, _20) (-1, _26) -9191351987198133172789796342745422989482268917117950487758512501574271532885 ]", - "BLACKBOX::EMBEDDED_CURVE_ADD [(1, 254), (_21, 254), (0, 1), (_25, 254), (_26, 254), (0, 1)] [_27, _28, _29]", - "EXPR [ (1, _20, _27) (-1, _20) 0 ]", - "EXPR [ (1, _1, _20) (-1, _30) 1 ]", - "EXPR [ (1, _2, _20) (-17631683881184975370165255887551781615748388533673675138860, _20) (-1, _31) 17631683881184975370165255887551781615748388533673675138860 ]", - "BLACKBOX::EMBEDDED_CURVE_ADD [(_30, 254), (_31, 254), (0, 1), (_30, 254), (_31, 254), (0, 1)] [_32, _33, _34]", - "EXPR [ (1, _20, _32) (-1, _20) 0 ]", - "EXPR [ (1, _1, _20) (-3078034153852398078128400807926804309327113743808504829582559963737223069693, _20) (-1, _35) 3078034153852398078128400807926804309327113743808504829582559963737223069694 ]", - "EXPR [ (1, _2, _20) (9191351987198133172789796342745422989482268917117950487758512501574271532886, _20) (-1, _36) -9191351987198133172789796342745422989482268917117950487758512501574271532885 ]", - "BLACKBOX::EMBEDDED_CURVE_ADD [(_30, 254), (_31, 254), (0, 1), (_35, 254), (_36, 254), (0, 1)] [_37, _38, _39]", - "EXPR [ (1, _20, _37) (-1, _20) 0 ]", - "EXPR [ (1, _20) (-1, _40) 1 ]", - "EXPR [ (-17631683881184975370165255887551781615748388533673675138857, _20) (-1, _41) 17631683881184975370165255887551781615748388533673675138860 ]", - "EXPR [ (1, _1, _20) (-3078034153852398078128400807926804309327113743808504829582559963737223069694, _20) (-1, _42) 3078034153852398078128400807926804309327113743808504829582559963737223069694 ]", - "BLACKBOX::EMBEDDED_CURVE_ADD [(_40, 254), (_41, 254), (0, 1), (_42, 254), (_36, 254), (0, 1)] [_43, _44, _45]", - "EXPR [ (1, _20, _43) (-1, _20) 0 ]", - "EXPR [ (-3078034153852398078128400807926804309327113743808504829582559963737223069692, _20) (-1, _46) 3078034153852398078128400807926804309327113743808504829582559963737223069694 ]", - "EXPR [ (9191351987198133172789796342745422989482268917117950487758512501574271532889, _20) (-1, _47) -9191351987198133172789796342745422989482268917117950487758512501574271532885 ]", - "BLACKBOX::EMBEDDED_CURVE_ADD [(_40, 254), (_41, 254), (0, 1), (_46, 254), (_47, 254), (0, 1)] [_48, _49, _50]", - "EXPR [ (1, _20, _48) (-1, _20) 0 ]", - "BLACKBOX::EMBEDDED_CURVE_ADD [(_40, 254), (_41, 254), (0, 1), (_40, 254), (_41, 254), (0, 1)] [_51, _52, _53]", - "EXPR [ (1, _20, _51) (-1, _20) 0 ]", - "BLACKBOX::EMBEDDED_CURVE_ADD [(1, 254), (_41, 254), (0, 1), (1, 254), (_41, 254), (0, 1)] [_54, _55, _56]", - "EXPR [ (1, _20, _54) (-1, _20) 0 ]", - "EXPR [ (1, _1, _20) (-1, _20) (-1, _57) 1 ]", - "EXPR [ (9191351987198133172789796342745422989482268917117950487758512501574271532887, _20) (-1, _58) -9191351987198133172789796342745422989482268917117950487758512501574271532885 ]", - "BLACKBOX::EMBEDDED_CURVE_ADD [(_57, 254), (_41, 254), (0, 1), (_42, 254), (_58, 254), (0, 1)] [_59, _60, _61]", - "EXPR [ (1, _20, _59) (-1, _20) 0 ]", + "EXPR [ (-1, _6) 0 ]", + "BLACKBOX::EMBEDDED_CURVE_ADD [(_1, 254), (_2, 254), (_6, 1), (_1, 254), (_2, 254), (_6, 1)] [_7, _8, _9]", + "EXPR [ (-1, _7) 3078034153852398078128400807926804309327113743808504829582559963737223069694 ]", + "BLACKBOX::MULTI_SCALAR_MUL [(1, 254), (17631683881184975370165255887551781615748388533673675138860, 254), (0, 1), (1, 254), (17631683881184975370165255887551781615748388533673675138860, 254), (0, 1), (_0, 254), (0, 254), (_0, 254), (0, 254)] [_10, _11, _12]", + "EXPR [ (-1, _10) 3078034153852398078128400807926804309327113743808504829582559963737223069694 ]", + "BLACKBOX::MULTI_SCALAR_MUL [(1, 254), (17631683881184975370165255887551781615748388533673675138860, 254), (0, 1), (_1, 254), (_2, 254), (0, 1), (11179562631109628533987091031692370366552561688588090155835439555627259799605, 254), (3443719903172018228650470536370404288991794296383447657609081676265727805364, 254), (0, 1), (_0, 254), (0, 254), (_0, 254), (0, 254), (1, 254), (0, 254)] [_13, _14, _15]", + "EXPR [ (1, _13) 7349266043899242844836273743257843180744506495159104166319746739537754653274 ]", + "BLACKBOX::MULTI_SCALAR_MUL [(1, 254), (17631683881184975370165255887551781615748388533673675138860, 254), (0, 1), (_0, 254), (0, 254)] [_16, _17, _18]", + "EXPR [ (1, _18) 0 ]", + "EXPR [ (1, _16) -1 ]", + "EXPR [ (1, _17) -17631683881184975370165255887551781615748388533673675138860 ]", + "EXPR [ (1, _1) (-1, _2) (-1, _19) 0 ]", + "BRILLIG CALL func 0: inputs: [Single(Expression { mul_terms: [], linear_combinations: [(1, Witness(19))], q_c: 0 })], outputs: [Simple(Witness(20))]", + "EXPR [ (1, _19, _20) (1, _21) -1 ]", + "EXPR [ (1, _19, _21) 0 ]", + "EXPR [ (-17631683881184975370165255887551781615748388533673675138858, _21) (-1, _22) 17631683881184975370165255887551781615748388533673675138860 ]", + "EXPR [ (-1, _23) 1 ]", + "BLACKBOX::EMBEDDED_CURVE_ADD [(_23, 254), (_22, 254), (_6, 1), (_23, 254), (_22, 254), (_6, 1)] [_24, _25, _26]", + "EXPR [ (1, _21, _24) (-1, _21) 0 ]", + "EXPR [ (-3078034153852398078128400807926804309327113743808504829582559963737223069693, _21) (-1, _27) 3078034153852398078128400807926804309327113743808504829582559963737223069694 ]", + "EXPR [ (9191351987198133172789796342745422989482268917117950487758512501574271532888, _21) (-1, _28) -9191351987198133172789796342745422989482268917117950487758512501574271532885 ]", + "BLACKBOX::EMBEDDED_CURVE_ADD [(_23, 254), (_22, 254), (_6, 1), (_27, 254), (_28, 254), (_6, 1)] [_29, _30, _31]", + "EXPR [ (1, _21, _29) (-1, _21) 0 ]", + "EXPR [ (1, _1, _21) (-1, _32) 1 ]", + "EXPR [ (1, _2, _21) (-17631683881184975370165255887551781615748388533673675138860, _21) (-1, _33) 17631683881184975370165255887551781615748388533673675138860 ]", + "BLACKBOX::EMBEDDED_CURVE_ADD [(_32, 254), (_33, 254), (_6, 1), (_32, 254), (_33, 254), (_6, 1)] [_34, _35, _36]", + "EXPR [ (1, _21, _34) (-1, _21) 0 ]", + "EXPR [ (1, _1, _21) (-3078034153852398078128400807926804309327113743808504829582559963737223069693, _21) (-1, _37) 3078034153852398078128400807926804309327113743808504829582559963737223069694 ]", + "EXPR [ (1, _2, _21) (9191351987198133172789796342745422989482268917117950487758512501574271532886, _21) (-1, _38) -9191351987198133172789796342745422989482268917117950487758512501574271532885 ]", + "BLACKBOX::EMBEDDED_CURVE_ADD [(_32, 254), (_33, 254), (_6, 1), (_37, 254), (_38, 254), (_6, 1)] [_39, _40, _41]", + "EXPR [ (1, _21, _39) (-1, _21) 0 ]", + "EXPR [ (1, _21) (-1, _42) 1 ]", + "EXPR [ (-17631683881184975370165255887551781615748388533673675138857, _21) (-1, _43) 17631683881184975370165255887551781615748388533673675138860 ]", + "EXPR [ (1, _1, _21) (-3078034153852398078128400807926804309327113743808504829582559963737223069694, _21) (-1, _44) 3078034153852398078128400807926804309327113743808504829582559963737223069694 ]", + "BLACKBOX::EMBEDDED_CURVE_ADD [(_42, 254), (_43, 254), (_6, 1), (_44, 254), (_38, 254), (_6, 1)] [_45, _46, _47]", + "EXPR [ (1, _21, _45) (-1, _21) 0 ]", + "EXPR [ (-3078034153852398078128400807926804309327113743808504829582559963737223069692, _21) (-1, _48) 3078034153852398078128400807926804309327113743808504829582559963737223069694 ]", + "EXPR [ (9191351987198133172789796342745422989482268917117950487758512501574271532889, _21) (-1, _49) -9191351987198133172789796342745422989482268917117950487758512501574271532885 ]", + "BLACKBOX::EMBEDDED_CURVE_ADD [(_42, 254), (_43, 254), (_6, 1), (_48, 254), (_49, 254), (_6, 1)] [_50, _51, _52]", + "EXPR [ (1, _21, _50) (-1, _21) 0 ]", + "BLACKBOX::EMBEDDED_CURVE_ADD [(_42, 254), (_43, 254), (_6, 1), (_42, 254), (_43, 254), (_6, 1)] [_53, _54, _55]", + "EXPR [ (1, _21, _53) (-1, _21) 0 ]", + "BLACKBOX::EMBEDDED_CURVE_ADD [(_23, 254), (_43, 254), (_6, 1), (_23, 254), (_43, 254), (_6, 1)] [_56, _57, _58]", + "EXPR [ (1, _21, _56) (-1, _21) 0 ]", + "EXPR [ (1, _1, _21) (-1, _21) (-1, _59) 1 ]", + "EXPR [ (9191351987198133172789796342745422989482268917117950487758512501574271532887, _21) (-1, _60) -9191351987198133172789796342745422989482268917117950487758512501574271532885 ]", + "BLACKBOX::EMBEDDED_CURVE_ADD [(_59, 254), (_43, 254), (_6, 1), (_44, 254), (_60, 254), (_6, 1)] [_61, _62, _63]", + "EXPR [ (1, _21, _61) (-1, _21) 0 ]", "unconstrained func 0", "[Const { destination: Direct(21), bit_size: Integer(U32), value: 1 }, Const { destination: Direct(20), bit_size: Integer(U32), value: 0 }, CalldataCopy { destination_address: Direct(0), size_address: Direct(21), offset_address: Direct(20) }, Const { destination: Direct(2), bit_size: Field, value: 0 }, BinaryFieldOp { destination: Direct(3), op: Equals, lhs: Direct(0), rhs: Direct(2) }, JumpIf { condition: Direct(3), location: 8 }, Const { destination: Direct(1), bit_size: Field, value: 1 }, BinaryFieldOp { destination: Direct(0), op: Div, lhs: Direct(1), rhs: Direct(0) }, Stop { return_data: HeapVector { pointer: Direct(20), size: Direct(21) } }]" ], - "debug_symbols": "tVjLbuMwDPwXnX0QX3rsrywWRZq6RQDDCdxkgUXRf1+qlez0oKBV7NMksTkhR+TY0pt56h8vLw+H8fn4an79fjOP02EYDi8Pw3G/Ox+Oo/769t6Z8vXhPPW9/mSurmvUaTf149n8Gi/D0Jm/u+HycdPraTd+4Hk36VXbmX58UlTC58PQp0/v3RJt66EYJAdjcHO4fDuePOR4xlCLx3o8S+RC4HgpAFwbA9UYbtTAPNcg0qABu1jiAzXEu1jWwAPU4v2NeCz5O4Fa/aEe71GwJICRGhgC2ZJCIMYaA9wQAQCtzxz6WXgNEt/QDV5cEcO3rGZwRYpIthYPfPdIfJ+iZSbAMhUhrbMNOgD5mUGoqiSE+5UImyohXBoCHMYWJYIvOUCMXHXJFWxyU59EOw8XWuQGJVDnszAANTGQlCqQXLWr8F67xFtuZ2e/DDZWPQbjCm6H97suwQp5/ISkxXWRAs7reqXpDzqDkw98MrBUn6Mka6ghG6vBbqnFhxY1PM+T5rnFtTDAPO0Bq++GbO+cNIa7J41xhTW9mcf3Jo15jTx4494KfPXKb5s6IxQ1MELVxTmsoUbYWI1ISy0MLTsgxPKeQyjVOZE1evQnJC1qEPqllqa9DHEsmyESwqoabg013MZqCC+1SIuHkvdl1ijYqo+7NfZFbuN9kT6gl1qoaZ9spTyT2Na7y63hom5jF2Wwcy0ALS7KRGXWmFzVN9waLuo2dlHWjphriV9X9o9+2+0P05eTL2O1izoDektnUBPsDKW/7wynnWNnJG28OuMUNDmfdk6dCWnb0JmY3hE1WDlSSwJkxIzKhEoInFEyuow+uZtiyBiTbWkaKSe9jpARM1LqeEVOmyhFyegyKh9rkqh8yTAwfiLZjKlKTZuUTzRvooycUTIqnygfKZ8oH4WM8RNZ+UT5WPnSGQMn3TSOKb1fKSqfS/dJOlJSdBl9xpAOmN7TKk6H3ePQ5yPI58u4vzqRPP87lSvlzPI0Hff902Xq0xp+XNNV/Q8=", + "debug_symbols": "tVjLbuowEP0Xr7PwvPzor1xdVZSmFVIEKIUrXVX9946LndCFUWuS1QGSOcwce04yfjfP/dP59XG3fzm8mYc/7+Zp3A3D7vVxOGw3p91hr7++f3SmfH08jX2vP5mr6xp13Iz9/mQe9udh6My/zXD+uuntuNl/4Wkz6lXbmX7/rKiEL7uhT58+ujna1kMxSA7G4KZw+XE8ecjxjKEWj/V4lsiFwPFcALg2Bqox3KiBeapBpEEDdrHEB2qId7GsgQeoxfsb8VjydwK1+kM93qNgSQAjNTAEsiWFQIw1BrghAgBanzn0s/ASJL5hN3hxRQzfsprBFSki2Vo88N0t8XOKlp4Ay1SEtM426ADkJwahqpIQ7lcirKqEcNkQ4DC2KBF8yQFi5KpLLmCTq/ok2qm50CI3KIHan4UBqImBpFSB5Kq7Cu+1S7zldnbyy2Bj1WMwLuB2eL/rEiyQx29IWlwXKeC0rlea/mJncPKBCwNL9TlKsoQasrIa7OZafGhRw/PUaZ5bXAsDTN0esPpuyPbOTmO4u9MYF1jTm3n8rNOYl8iDV95bga9e+W3TzghFDYxQdXEOS6gRVlYj0lwLQ8sEhFjecwil2ieyxB79DUmLGoR+rqVpliGOZRgiIayq4ZZQw62shvBci7R4KHlfeo2Crfq4W2IucivPRfqAnmuhpjnZSnkmsa3vLreEi7qVXZTBTrUAtLgoE5VeY3JV33BLuKhb2UVZd8RUS/y+sn/122a7G7+dfBmru6gzoLd0BjXBzlD6+87wBSQNkJ1xaf7qjFfQHEMaoDoT0/SgwTa9KyoqS9qagBkpo1KhEoNkdBl9xpBcTjFeEG1GSDamqHyk9yFl5IySOkDRpaFK0WcMGZWPNVtSvmQgBBkxo/KJ5k/KJ5o/SUaX0WdUPlE+Uj5RPrYZIaPyifKx8qUzB1Y+p3Es6X1LUflcus+nIybFkDFeUGw6cPpIqzruNk9Dn48kX8777dUJ5en/sVwpZ5jH8bDtn89jn9b065qu8ic=", "file_map": { "16": { "source": "use crate::cmp::Eq;\nuse crate::hash::Hash;\nuse crate::ops::arith::{Add, Neg, Sub};\n\n/// A point on the embedded elliptic curve\n/// By definition, the base field of the embedded curve is the scalar field of the proof system curve, i.e the Noir Field.\n/// x and y denotes the Weierstrass coordinates of the point, if is_infinite is false.\npub struct EmbeddedCurvePoint {\n pub x: Field,\n pub y: Field,\n pub is_infinite: bool,\n}\n\nimpl EmbeddedCurvePoint {\n /// Elliptic curve point doubling operation\n /// returns the doubled point of a point P, i.e P+P\n pub fn double(self) -> EmbeddedCurvePoint {\n embedded_curve_add(self, self)\n }\n\n /// Returns the null element of the curve; 'the point at infinity'\n pub fn point_at_infinity() -> EmbeddedCurvePoint {\n EmbeddedCurvePoint { x: 0, y: 0, is_infinite: true }\n }\n\n /// Returns the curve's generator point.\n pub fn generator() -> EmbeddedCurvePoint {\n // Generator point for the grumpkin curve (y^2 = x^3 - 17)\n EmbeddedCurvePoint {\n x: 1,\n y: 17631683881184975370165255887551781615748388533673675138860, // sqrt(-16)\n is_infinite: false,\n }\n }\n}\n\nimpl Add for EmbeddedCurvePoint {\n /// Adds two points P+Q, using the curve addition formula, and also handles point at infinity\n fn add(self, other: EmbeddedCurvePoint) -> EmbeddedCurvePoint {\n embedded_curve_add(self, other)\n }\n}\n\nimpl Sub for EmbeddedCurvePoint {\n /// Points subtraction operation, using addition and negation\n fn sub(self, other: EmbeddedCurvePoint) -> EmbeddedCurvePoint {\n self + other.neg()\n }\n}\n\nimpl Neg for EmbeddedCurvePoint {\n /// Negates a point P, i.e returns -P, by negating the y coordinate.\n /// If the point is at infinity, then the result is also at infinity.\n fn neg(self) -> EmbeddedCurvePoint {\n EmbeddedCurvePoint { x: self.x, y: -self.y, is_infinite: self.is_infinite }\n }\n}\n\nimpl Eq for EmbeddedCurvePoint {\n /// Checks whether two points are equal\n fn eq(self: Self, b: EmbeddedCurvePoint) -> bool {\n (self.is_infinite & b.is_infinite)\n | ((self.is_infinite == b.is_infinite) & (self.x == b.x) & (self.y == b.y))\n }\n}\n\nimpl Hash for EmbeddedCurvePoint {\n fn hash(self, state: &mut H)\n where\n H: crate::hash::Hasher,\n {\n if self.is_infinite {\n self.is_infinite.hash(state);\n } else {\n self.x.hash(state);\n self.y.hash(state);\n }\n }\n}\n\n/// Scalar for the embedded curve represented as low and high limbs\n/// By definition, the scalar field of the embedded curve is base field of the proving system curve.\n/// It may not fit into a Field element, so it is represented with two Field elements; its low and high limbs.\npub struct EmbeddedCurveScalar {\n pub lo: Field,\n pub hi: Field,\n}\n\nimpl EmbeddedCurveScalar {\n pub fn new(lo: Field, hi: Field) -> Self {\n EmbeddedCurveScalar { lo, hi }\n }\n\n #[field(bn254)]\n pub fn from_field(scalar: Field) -> EmbeddedCurveScalar {\n let (a, b) = crate::field::bn254::decompose(scalar);\n EmbeddedCurveScalar { lo: a, hi: b }\n }\n\n //Bytes to scalar: take the first (after the specified offset) 16 bytes of the input as the lo value, and the next 16 bytes as the hi value\n #[field(bn254)]\n pub(crate) fn from_bytes(bytes: [u8; 64], offset: u32) -> EmbeddedCurveScalar {\n let mut v = 1;\n let mut lo = 0 as Field;\n let mut hi = 0 as Field;\n for i in 0..16 {\n lo = lo + (bytes[offset + 31 - i] as Field) * v;\n hi = hi + (bytes[offset + 15 - i] as Field) * v;\n v = v * 256;\n }\n let sig_s = crate::embedded_curve_ops::EmbeddedCurveScalar { lo, hi };\n sig_s\n }\n}\n\nimpl Eq for EmbeddedCurveScalar {\n fn eq(self, other: Self) -> bool {\n (other.hi == self.hi) & (other.lo == self.lo)\n }\n}\n\nimpl Hash for EmbeddedCurveScalar {\n fn hash(self, state: &mut H)\n where\n H: crate::hash::Hasher,\n {\n self.hi.hash(state);\n self.lo.hash(state);\n }\n}\n\n// Computes a multi scalar multiplication over the embedded curve.\n// For bn254, We have Grumpkin and Baby JubJub.\n// For bls12-381, we have JubJub and Bandersnatch.\n//\n// The embedded curve being used is decided by the\n// underlying proof system.\n// docs:start:multi_scalar_mul\npub fn multi_scalar_mul(\n points: [EmbeddedCurvePoint; N],\n scalars: [EmbeddedCurveScalar; N],\n) -> EmbeddedCurvePoint\n// docs:end:multi_scalar_mul\n{\n multi_scalar_mul_array_return(points, scalars)[0]\n}\n\n#[foreign(multi_scalar_mul)]\npub(crate) fn multi_scalar_mul_array_return(\n points: [EmbeddedCurvePoint; N],\n scalars: [EmbeddedCurveScalar; N],\n) -> [EmbeddedCurvePoint; 1] {}\n\n// docs:start:fixed_base_scalar_mul\npub fn fixed_base_scalar_mul(scalar: EmbeddedCurveScalar) -> EmbeddedCurvePoint\n// docs:end:fixed_base_scalar_mul\n{\n multi_scalar_mul([EmbeddedCurvePoint::generator()], [scalar])\n}\n\n/// This function only assumes that the points are on the curve\n/// It handles corner cases around the infinity point causing some overhead compared to embedded_curve_add_not_nul and embedded_curve_add_unsafe\n// docs:start:embedded_curve_add\npub fn embedded_curve_add(\n point1: EmbeddedCurvePoint,\n point2: EmbeddedCurvePoint,\n) -> EmbeddedCurvePoint {\n // docs:end:embedded_curve_add\n if crate::runtime::is_unconstrained() {\n // `embedded_curve_add_unsafe` requires the inputs not to be the infinity point, so we check it here.\n // This is because `embedded_curve_add_unsafe` uses the `embedded_curve_add` opcode.\n // For efficiency, the backend does not check the inputs for the infinity point, but it assumes that they are not the infinity point\n // so that it can apply the ec addition formula directly.\n if point1.is_infinite {\n point2\n } else if point2.is_infinite {\n point1\n } else {\n embedded_curve_add_unsafe(point1, point2)\n }\n } else {\n // In a constrained context, we also need to check the inputs are not the infinity point because we also use `embedded_curve_add_unsafe`\n // However we also need to identify the case where the two inputs are the same, because then\n // the addition formula does not work and we need to use the doubling formula instead.\n // In unconstrained context, we can check directly if the input values are the same when solving the opcode, so it is not an issue.\n\n // x_coordinates_match is true if both abscissae are the same\n let x_coordinates_match = point1.x == point2.x;\n // y_coordinates_match is true if both ordinates are the same\n let y_coordinates_match = point1.y == point2.y;\n // double_predicate is true if both abscissae and ordinates are the same\n let double_predicate = (x_coordinates_match & y_coordinates_match);\n // If the abscissae are the same, but not the ordinates, then one point is the opposite of the other\n let infinity_predicate = (x_coordinates_match & !y_coordinates_match);\n let point1_1 = EmbeddedCurvePoint {\n x: point1.x + (x_coordinates_match as Field),\n y: point1.y,\n is_infinite: false,\n };\n let point2_1 = EmbeddedCurvePoint { x: point2.x, y: point2.y, is_infinite: false };\n // point1_1 is guaranteed to have a different abscissa than point2:\n // - if x_coordinates_match is 0, that means point1.x != point2.x, and point1_1.x = point1.x + 0\n // - if x_coordinates_match is 1, that means point1.x = point2.x, but point1_1.x = point1.x + 1 in this case\n // Because the abscissa is different, the addition formula is guaranteed to succeed, so we can safely use `embedded_curve_add_unsafe`\n // Note that this computation may be garbage: if x_coordinates_match is 1, or if one of the input is the point at infinity.\n let mut result = embedded_curve_add_unsafe(point1_1, point2_1);\n\n // `embedded_curve_add_unsafe` is doing a doubling if the input is the same variable, because in this case it is guaranteed (at 'compile time') that the input is the same.\n let double = embedded_curve_add_unsafe(point1, point1);\n // `embedded_curve_add_unsafe` would not perform doubling, even if the inputs point1 and point2 are the same, because it cannot know this without adding some logic (and some constraints)\n // However we did this logic when we computed `double_predicate`, so we set the result to 2*point1 if point1 and point2 are the same\n result = if double_predicate { double } else { result };\n\n // Same logic as above for unconstrained context, we set the proper result when one of the inputs is the infinity point\n if point1.is_infinite {\n result = point2;\n }\n if point2.is_infinite {\n result = point1;\n }\n\n // Finally, we set the is_infinity flag of the result:\n // Opposite points should sum into the infinity point, however, if one of them is point at infinity, their coordinates are not meaningful\n // so we should not use the fact that the inputs are opposite in this case:\n let mut result_is_infinity =\n infinity_predicate & (!point1.is_infinite & !point2.is_infinite);\n // However, if both of them are at infinity, then the result is also at infinity\n result.is_infinite = result_is_infinity | (point1.is_infinite & point2.is_infinite);\n result\n }\n}\n\n#[foreign(embedded_curve_add)]\nfn embedded_curve_add_array_return(\n _point1: EmbeddedCurvePoint,\n _point2: EmbeddedCurvePoint,\n) -> [EmbeddedCurvePoint; 1] {}\n\n/// This function assumes that:\n/// The points are on the curve, and\n/// The points don't share an x-coordinate, and\n/// Neither point is the infinity point.\n/// If it is used with correct input, the function ensures the correct non-zero result is returned.\n/// Except for points on the curve, the other assumptions are checked by the function. It will cause assertion failure if they are not respected.\npub fn embedded_curve_add_not_nul(\n point1: EmbeddedCurvePoint,\n point2: EmbeddedCurvePoint,\n) -> EmbeddedCurvePoint {\n assert(point1.x != point2.x);\n assert(!point1.is_infinite);\n assert(!point2.is_infinite);\n // Ensure is_infinite is comptime\n let point1_1 = EmbeddedCurvePoint { x: point1.x, y: point1.y, is_infinite: false };\n let point2_1 = EmbeddedCurvePoint { x: point2.x, y: point2.y, is_infinite: false };\n embedded_curve_add_unsafe(point1_1, point2_1)\n}\n\n/// Unsafe ec addition\n/// If the inputs are the same, it will perform a doubling, but only if point1 and point2 are the same variable.\n/// If they have the same value but are different variables, the result will be incorrect because in this case\n/// it assumes (but does not check) that the points' x-coordinates are not equal.\n/// It also assumes neither point is the infinity point.\npub fn embedded_curve_add_unsafe(\n point1: EmbeddedCurvePoint,\n point2: EmbeddedCurvePoint,\n) -> EmbeddedCurvePoint {\n embedded_curve_add_array_return(point1, point2)[0]\n}\n",