Barretenberg
The ZK-SNARK library at the core of Aztec
Loading...
Searching...
No Matches
ecc.cpp
Go to the documentation of this file.
5
6namespace bb::avm2::simulation {
7
8namespace {
9
10class InternalEccException : public std::runtime_error {
11 public:
12 using std::runtime_error::runtime_error; // Inherit the constructor.
13};
14
15} // namespace
16
31{
32 // Check if points are on the curve. These will throw an unexpected exception if they fail.
33 BB_ASSERT(p.on_curve(), "Point p is not on the curve");
34 BB_ASSERT(q.on_curve(), "Point q is not on the curve");
35 // Check if the points are normalized (infinity points must be (0, 0, true)).
36 if (p.is_infinity()) {
37 BB_ASSERT((p.x() == 0) && (p.y() == 0), "Point p is not normalized");
38 }
39 if (q.is_infinity()) {
40 BB_ASSERT((q.x() == 0) && (q.y() == 0), "Point q is not normalized");
41 }
42
43 EmbeddedCurvePoint result = p + q;
44 add_events.emit({ .p = p, .q = q, .result = result });
45 return result;
46}
47
63{
64 // This is bad - the scalar mul circuit assumes that the point is on the curve.
65 // This will throw an unexpected exception if it fails.
66 BB_ASSERT(point.on_curve(), "Point must be on the curve for scalar multiplication");
67
68 // FF bit size == 254.
69 auto intermediate_states = std::vector<ScalarMulIntermediateState>(254);
70 // Emits ToRadixEvent, see #[TO_RADIX] in scalar_mul.pil.
71 auto bits = to_radix.to_le_bits(scalar, 254).first;
72
73 // Normalize input infinity point (infinity points must be (0, 0, true)).
74 EmbeddedCurvePoint point_input = point.is_infinity() ? EmbeddedCurvePoint::infinity() : point;
75
76 // First iteration does conditional assignment instead of addition. Note: in circuit we perform reverse aggregation,
77 // so the corresponding constraints for below are gated by 'end'.
78
79 // See 'Temp Computation' section in scalar_mul.pil.
80 EmbeddedCurvePoint temp = point_input;
81 bool bit = bits[0];
82
83 // See 'Result Computation' section in scalar_mul.pil.
85 intermediate_states[0] = { result, temp, bit };
86
87 for (size_t i = 1; i < 254; i++) {
88 bit = bits[i];
89 // Emits EccAddEvent, see #[DOUBLE] in scalar_mul.pil.
90 temp = add(temp, temp);
91 if (bit) {
92 // Emits EccAddEvent, see #[ADD] in scalar_mul.pil.
93 result = add(result, temp);
94 }
95 intermediate_states[i] = { result, temp, bit };
96 }
97 scalar_mul_events.emit({ .point = point_input,
98 .scalar = scalar,
99 .intermediate_states = std::move(intermediate_states),
100 .result = result });
101 return result;
102}
103
119 const EmbeddedCurvePoint& p,
120 const EmbeddedCurvePoint& q,
122{
123 uint32_t execution_clk = execution_id_manager.get_execution_id();
124 uint16_t space_id = memory.get_space_id();
125
126 try {
127 // The resulting EmbeddedCurvePoint is a triple of (x, y, is_infinity).
128 // The x and y coordinates are stored at dst_address and dst_address + 1 respectively,
129 // and the is_infinity flag is stored at dst_address + 2.
130 // Therefore, the maximum address that needs to be written to is dst_address + 2.
131 uint64_t max_write_address = static_cast<uint64_t>(dst_address) + 2;
132 // Emits GreaterThanEvent, see #[CHECK_DST_ADDR_IN_RANGE] in ecc_mem.pil.
133 if (gt.gt(max_write_address, AVM_HIGHEST_MEM_ADDRESS)) {
134 throw InternalEccException("dst address out of range");
135 }
136
137 if (!p.on_curve() || !q.on_curve()) {
138 throw InternalEccException("One of the points is not on the curve");
139 }
140
141 // Normalize input infinity points.
144
145 // Emits EccAddEvent, see #[INPUT_OUTPUT_ECC_ADD] in ecc_mem.pil.
146 EmbeddedCurvePoint result =
147 add(p_input, q_input); // Cannot throw since we have checked on_curve() and normalized.
148
149 // Emits MemoryEvents, see #[WRITE_MEM_i] for i = 0, 1, 2, in ecc_mem.pil.
150 memory.set(dst_address, MemoryValue::from<FF>(result.x()));
151 memory.set(dst_address + 1, MemoryValue::from<FF>(result.y()));
152 memory.set(dst_address + 2, MemoryValue::from<uint1_t>(result.is_infinity() ? 1 : 0));
153
154 add_memory_events.emit({ .execution_clk = execution_clk,
155 .space_id = space_id,
156 .p = p,
157 .q = q,
158 .result = result,
159 .dst_address = dst_address });
160 } catch (const InternalEccException& e) {
161 // Note this point is not on the curve, but corresponds
162 // to default values the circuit will assign.
163 EmbeddedCurvePoint res = EmbeddedCurvePoint(0, 0, false);
164 add_memory_events.emit({ .execution_clk = execution_clk,
165 .space_id = space_id,
166 .p = p,
167 .q = q,
168 .result = res,
169 .dst_address = dst_address });
170 throw EccException("Add failed: " + std::string(e.what()));
171 }
172}
173
174} // namespace bb::avm2::simulation
#define BB_ASSERT(expression,...)
Definition assert.hpp:70
#define AVM_HIGHEST_MEM_ADDRESS
constexpr bool is_infinity() const noexcept
constexpr const BaseField & x() const noexcept
constexpr const BaseField & y() const noexcept
constexpr bool on_curve() const noexcept
EventEmitterInterface< ScalarMulEvent > & scalar_mul_events
Definition ecc.hpp:40
EmbeddedCurvePoint add(const EmbeddedCurvePoint &p, const EmbeddedCurvePoint &q) override
Adds Grumpkin curve points P and Q and emits an EccAddEvent. Corresponds to the non-memory aware subt...
Definition ecc.cpp:30
EmbeddedCurvePoint scalar_mul(const EmbeddedCurvePoint &point, const FF &scalar) override
Performs scalar multiplication of an FF value with a Grumpkin curve point using the double and add al...
Definition ecc.cpp:62
EventEmitterInterface< EccAddMemoryEvent > & add_memory_events
Definition ecc.hpp:41
ExecutionIdManagerInterface & execution_id_manager
Definition ecc.hpp:44
EventEmitterInterface< EccAddEvent > & add_events
Definition ecc.hpp:39
virtual uint32_t get_execution_id() const =0
AVM range check gadget for witness generation.
AvmFlavorSettings::FF FF
Definition field.hpp:10
StandardAffinePoint< AvmFlavorSettings::EmbeddedCurve::AffineElement > EmbeddedCurvePoint
Definition field.hpp:12
uint32_t MemoryAddress
constexpr decltype(auto) get(::tuplet::tuple< T... > &&t) noexcept
Definition tuple.hpp:13