Barretenberg
The ZK-SNARK library at the core of Aztec
Loading...
Searching...
No Matches
safe_uint.hpp
Go to the documentation of this file.
1// === AUDIT STATUS ===
2// internal: { status: not started, auditors: [], date: YYYY-MM-DD }
3// external_1: { status: not started, auditors: [], date: YYYY-MM-DD }
4// external_2: { status: not started, auditors: [], date: YYYY-MM-DD }
5// =====================
6
7#pragma once
8#include "../bool/bool.hpp"
9#include "../circuit_builders/circuit_builders.hpp"
10#include "../circuit_builders/circuit_builders_fwd.hpp"
11#include "../field/field.hpp"
12#include "../witness/witness.hpp"
14#include <functional>
15
16// The purpose of this class is to enable positive integer operations without a risk of overflow.
17// Despite the name, it is *not* a "safe" version of the uint class - as operations are positive integer
18// operations, and not modulo 2^t for some t, as they are in the uint class.
19
20namespace bb::stdlib {
21
22template <typename Builder> class safe_uint_t {
23 private:
26 // this constructor is private since we only want the operators to be able to define a positive int without a range
27 // check.
28 safe_uint_t(field_ct const& value, const uint256_t& current_max, size_t safety)
29 : value(value)
31 {
32 BB_ASSERT_EQ(safety, IS_UNSAFE);
33 BB_ASSERT_LTE(current_max, MAX_VALUE, "exceeded modulus in safe_uint class");
34 }
35
36 public:
37 // The following constant should be small enough that any thing with this bitnum is smaller than the modulus
38 static constexpr size_t MAX_BIT_NUM = bb::fr::modulus.get_msb();
39 static constexpr uint256_t MAX_VALUE = bb::fr::modulus - 1;
40 static constexpr size_t IS_UNSAFE = 143; // weird constant to make it hard to use accidentally
43
45 : value(0)
46 , current_max(0)
47 {}
48
49 safe_uint_t(field_ct const& value, size_t bit_num, std::string const& description = "unknown")
50 : value(value)
51 {
52 BB_ASSERT_LTE(bit_num, MAX_BIT_NUM);
53 this->value.create_range_constraint(bit_num, format("safe_uint_t range constraint failure: ", description));
54 current_max = ((uint256_t)1 << bit_num) - 1;
55 }
56
57 // When initialzing a constant, we can set the max value to the constant itself (rather than the usually larger
58 // 2^n-1)
59 safe_uint_t(const bb::fr& const_value)
60 : value(const_value)
61 , current_max(const_value)
62 {}
63
64 // When initialzing a constant, we can set the max value to the constant itself (rather than the usually larger
65 // 2^n-1)
66 safe_uint_t(const uint256_t& const_value)
67 : value(bb::fr(const_value))
68 , current_max(bb::fr(const_value))
69 {}
70 safe_uint_t(const unsigned int& const_value)
71 : value(bb::fr(const_value))
72 , current_max(bb::fr(const_value))
73 {}
74
76 : value(other.value)
78 {}
79
81 {
82 // Use witness_t's create_constant_witness which safely handles the assertion
84 auto result = safe_uint_t(value, uint256_t(value), IS_UNSAFE);
85 result.set_free_witness_tag();
86 return result;
87 }
88
89 // We take advantage of the range constraint already being applied in the bool constructor and don't make a
90 // redundant one.
91 safe_uint_t(const bool_ct& other)
92 : value(other)
93 , current_max(1)
94 {}
95
96 explicit operator bool_ct() { return bool_ct(value); }
97 static safe_uint_t from_witness_index(Builder* parent_context, const uint32_t witness_index);
98
99 // Subtraction when you have a pre-determined bound on the difference size
100 safe_uint_t subtract(const safe_uint_t& other,
101 const size_t difference_bit_size,
102 std::string const& description = "") const;
103
104 safe_uint_t operator-(const safe_uint_t& other) const;
105
106 // division when you have a pre-determined bound on the sizes of the quotient and remainder
108 const safe_uint_t& other,
109 const size_t quotient_bit_size,
110 const size_t remainder_bit_size,
111 std::string const& description = "",
112 const std::function<std::pair<uint256_t, uint256_t>(uint256_t, uint256_t)>& get_quotient =
113 [](uint256_t val, uint256_t divisor) {
114 return std::make_pair((uint256_t)(val / (uint256_t)divisor), (uint256_t)(val % (uint256_t)divisor));
115 }) const;
116
117 // Potentially less efficient than divide function - bounds remainder and quotient by max of this
118 safe_uint_t operator/(const safe_uint_t& other) const;
119
120 safe_uint_t add_two(const safe_uint_t& add_a, const safe_uint_t& add_b) const
121 {
122 BB_ASSERT_LTE(current_max + add_a.current_max + add_b.current_max, MAX_VALUE, "Exceeded modulus in add_two");
123 auto new_val = value.add_two(add_a.value, add_b.value);
124 auto new_max = current_max + add_a.current_max + add_b.current_max;
125 return safe_uint_t(new_val, new_max, IS_UNSAFE);
126 }
127
128 safe_uint_t madd(const safe_uint_t& to_mul, const safe_uint_t& to_add) const
129 {
131 MAX_VALUE,
132 "Exceeded modulus in madd");
133 auto new_val = value.madd(to_mul.value, to_add.value);
134 auto new_max = current_max * to_mul.current_max + to_add.current_max;
135 return safe_uint_t(new_val, new_max, IS_UNSAFE);
136 }
137
139 {
140 value = other.value;
141 current_max = other.current_max;
142 return *this;
143 }
144
146 {
147 value = other.value;
148 current_max = other.current_max;
149 return *this;
150 }
151
153 {
154 *this = *this + other;
155 return *this;
156 }
157
159 {
160 *this = *this * other;
161 return *this;
162 }
163
164 std::array<safe_uint_t<Builder>, 3> slice(const uint8_t msb, const uint8_t lsb) const;
165 void set_public() const { value.set_public(); }
166 operator field_ct() { return value; }
167 operator field_ct() const { return value; }
168 safe_uint_t operator+(const safe_uint_t& other) const;
169 safe_uint_t operator*(const safe_uint_t& other) const;
170 bool_ct operator==(const safe_uint_t& other) const;
171 bool_ct operator!=(const safe_uint_t& other) const;
172
180 safe_uint_t normalize() const;
181
182 bb::fr get_value() const;
183
184 Builder* get_context() const { return value.context; }
185
190 bool_ct is_zero() const;
191
192 void assert_equal(const safe_uint_t& rhs, std::string const& msg = "safe_uint_t::assert_equal") const
193 {
194 this->value.assert_equal(rhs.value, msg);
195 }
196 void assert_is_not_zero(std::string const& msg = "safe_uint_t::assert_is_not_zero") const;
197 void assert_is_zero(std::string const& msg = "safe_uint_t::assert_is_zero") const;
198 bool is_constant() const { return value.is_constant(); }
199
200 static safe_uint_t conditional_assign(const bool_ct& predicate, const safe_uint_t& lhs, const safe_uint_t& rhs)
201 {
202 auto new_val = (lhs.value - rhs.value).madd(predicate, rhs.value);
203 auto new_max = lhs.current_max > rhs.current_max ? lhs.current_max : rhs.current_max;
204 return safe_uint_t(new_val, new_max, IS_UNSAFE);
205 }
206
207 uint32_t get_witness_index() const { return value.get_witness_index(); }
209
213};
214
215template <typename Builder> inline std::ostream& operator<<(std::ostream& os, safe_uint_t<Builder> const& v)
216{
217 return os << v.value;
218}
219} // namespace bb::stdlib
#define BB_ASSERT_EQ(actual, expected,...)
Definition assert.hpp:77
#define BB_ASSERT_LTE(left, right,...)
Definition assert.hpp:152
constexpr uint64_t get_msb() const
Implements boolean logic in-circuit.
Definition bool.hpp:59
uint32_t set_public() const
Definition field.hpp:434
void assert_equal(const field_t &rhs, std::string const &msg="field_t::assert_equal") const
Copy constraint: constrain that *this field is equal to rhs element.
Definition field.cpp:930
field_t madd(const field_t &to_mul, const field_t &to_add) const
Definition field.cpp:510
void create_range_constraint(size_t num_bits, std::string const &msg="field_t::range_constraint") const
Let x = *this.normalize(), constrain x.v < 2^{num_bits}.
Definition field.cpp:909
Builder * context
Definition field.hpp:56
void unset_free_witness_tag() const
Unset the free witness flag for the field element's tag.
Definition field.hpp:356
OriginTag get_origin_tag() const
Definition field.hpp:346
bool is_constant() const
Definition field.hpp:429
void set_free_witness_tag()
Set the free witness flag for the field element's tag.
Definition field.hpp:351
void set_origin_tag(const OriginTag &new_tag) const
Definition field.hpp:345
field_t add_two(const field_t &add_b, const field_t &add_c) const
Efficiently compute (this + a + b) using big_mul gate.
Definition field.cpp:575
uint32_t get_witness_index() const
Get the witness index of the current field element.
Definition field.hpp:506
safe_uint_t & operator=(safe_uint_t &&other)
void assert_is_zero(std::string const &msg="safe_uint_t::assert_is_zero") const
safe_uint_t(const unsigned int &const_value)
Definition safe_uint.hpp:70
safe_uint_t subtract(const safe_uint_t &other, const size_t difference_bit_size, std::string const &description="") const
Subtraction when you have a pre-determined bound on the difference size.
Definition safe_uint.cpp:41
bool_t< Builder > bool_ct
Definition safe_uint.hpp:25
safe_uint_t operator/(const safe_uint_t &other) const
Potentially less efficient than divide function - bounds remainder and quotient by max of this.
static constexpr uint256_t MAX_VALUE
Definition safe_uint.hpp:39
safe_uint_t(field_ct const &value, size_t bit_num, std::string const &description="unknown")
Definition safe_uint.hpp:49
safe_uint_t & operator=(const safe_uint_t &other)
static constexpr size_t IS_UNSAFE
Definition safe_uint.hpp:40
static safe_uint_t< Builder > create_constant_witness(Builder *parent_context, bb::fr const &value)
Definition safe_uint.hpp:80
bool_ct is_zero() const
void assert_equal(const safe_uint_t &rhs, std::string const &msg="safe_uint_t::assert_equal") const
safe_uint_t(const safe_uint_t &other)
Definition safe_uint.hpp:75
static safe_uint_t from_witness_index(Builder *parent_context, const uint32_t witness_index)
OriginTag get_origin_tag() const
uint32_t get_witness_index() const
safe_uint_t normalize() const
static constexpr size_t MAX_BIT_NUM
Definition safe_uint.hpp:38
std::array< safe_uint_t< Builder >, 3 > slice(const uint8_t msb, const uint8_t lsb) const
safe_uint_t(const bb::fr &const_value)
Definition safe_uint.hpp:59
bool_ct operator==(const safe_uint_t &other) const
safe_uint_t(const uint256_t &const_value)
Definition safe_uint.hpp:66
safe_uint_t operator-(const safe_uint_t &other) const
Subtraction on two safe_uint_t objects.
Definition safe_uint.cpp:74
void set_origin_tag(OriginTag tag) const
Builder * get_context() const
safe_uint_t(field_ct const &value, const uint256_t &current_max, size_t safety)
Definition safe_uint.hpp:28
safe_uint_t add_two(const safe_uint_t &add_a, const safe_uint_t &add_b) const
static safe_uint_t conditional_assign(const bool_ct &predicate, const safe_uint_t &lhs, const safe_uint_t &rhs)
safe_uint_t(const bool_ct &other)
Definition safe_uint.hpp:91
safe_uint_t operator*(const safe_uint_t &other) const
Definition safe_uint.cpp:22
safe_uint_t operator+(const safe_uint_t &other) const
Definition safe_uint.cpp:17
bool_ct operator!=(const safe_uint_t &other) const
safe_uint_t divide(const safe_uint_t &other, const size_t quotient_bit_size, const size_t remainder_bit_size, std::string const &description="", const std::function< std::pair< uint256_t, uint256_t >(uint256_t, uint256_t)> &get_quotient=[](uint256_t val, uint256_t divisor) { return std::make_pair((uint256_t)(val/(uint256_t) divisor),(uint256_t)(val %(uint256_t) divisor));}) const
division when you have a pre-determined bound on the sizes of the quotient and remainder
safe_uint_t operator*=(const safe_uint_t &other)
bb::fr get_value() const
void assert_is_not_zero(std::string const &msg="safe_uint_t::assert_is_not_zero") const
field_t< Builder > field_ct
Definition safe_uint.hpp:24
safe_uint_t operator+=(const safe_uint_t &other)
safe_uint_t madd(const safe_uint_t &to_mul, const safe_uint_t &to_add) const
std::string format(Args... args)
Definition log.hpp:22
std::ostream & operator<<(std::ostream &os, uint256_t const &a)
Definition uint256.hpp:245
Entry point for Barretenberg command-line interface.
Definition api.hpp:5
constexpr decltype(auto) get(::tuplet::tuple< T... > &&t) noexcept
Definition tuple.hpp:13
static constexpr uint256_t modulus