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 {
83 witness_t<Builder> out(parent_context, value);
84 parent_context->assert_equal_constant(out.witness_index, value, "create_constant_witness");
85 auto result = safe_uint_t(value, uint256_t(value), IS_UNSAFE);
86 result.set_free_witness_tag();
87 return result;
88 }
89
90 // We take advantage of the range constraint already being applied in the bool constructor and don't make a
91 // redundant one.
92 safe_uint_t(const bool_ct& other)
93 : value(other)
94 , current_max(1)
95 {}
96
97 explicit operator bool_ct() { return bool_ct(value); }
98 static safe_uint_t from_witness_index(Builder* parent_context, const uint32_t witness_index);
99
100 // Subtraction when you have a pre-determined bound on the difference size
101 safe_uint_t subtract(const safe_uint_t& other,
102 const size_t difference_bit_size,
103 std::string const& description = "") const;
104
105 safe_uint_t operator-(const safe_uint_t& other) const;
106
107 // division when you have a pre-determined bound on the sizes of the quotient and remainder
109 const safe_uint_t& other,
110 const size_t quotient_bit_size,
111 const size_t remainder_bit_size,
112 std::string const& description = "",
113 const std::function<std::pair<uint256_t, uint256_t>(uint256_t, uint256_t)>& get_quotient =
114 [](uint256_t val, uint256_t divisor) {
115 return std::make_pair((uint256_t)(val / (uint256_t)divisor), (uint256_t)(val % (uint256_t)divisor));
116 }) const;
117
118 // Potentially less efficient than divide function - bounds remainder and quotient by max of this
119 safe_uint_t operator/(const safe_uint_t& other) const;
120
121 safe_uint_t add_two(const safe_uint_t& add_a, const safe_uint_t& add_b) const
122 {
123 BB_ASSERT_LTE(current_max + add_a.current_max + add_b.current_max, MAX_VALUE, "Exceeded modulus in add_two");
124 auto new_val = value.add_two(add_a.value, add_b.value);
125 auto new_max = current_max + add_a.current_max + add_b.current_max;
126 return safe_uint_t(new_val, new_max, IS_UNSAFE);
127 }
128
129 safe_uint_t madd(const safe_uint_t& to_mul, const safe_uint_t& to_add) const
130 {
132 MAX_VALUE,
133 "Exceeded modulus in madd");
134 auto new_val = value.madd(to_mul.value, to_add.value);
135 auto new_max = current_max * to_mul.current_max + to_add.current_max;
136 return safe_uint_t(new_val, new_max, IS_UNSAFE);
137 }
138
140 {
141 value = other.value;
142 current_max = other.current_max;
143 return *this;
144 }
145
147 {
148 value = other.value;
149 current_max = other.current_max;
150 return *this;
151 }
152
154 {
155 *this = *this + other;
156 return *this;
157 }
158
160 {
161 *this = *this * other;
162 return *this;
163 }
164
165 std::array<safe_uint_t<Builder>, 3> slice(const uint8_t msb, const uint8_t lsb) const;
166 void set_public() const { value.set_public(); }
167 operator field_ct() { return value; }
168 operator field_ct() const { return value; }
169 safe_uint_t operator+(const safe_uint_t& other) const;
170 safe_uint_t operator*(const safe_uint_t& other) const;
171 bool_ct operator==(const safe_uint_t& other) const;
172 bool_ct operator!=(const safe_uint_t& other) const;
173
181 safe_uint_t normalize() const;
182
183 bb::fr get_value() const;
184
185 Builder* get_context() const { return value.context; }
186
191 bool_ct is_zero() const;
192
193 void assert_equal(const safe_uint_t& rhs, std::string const& msg = "safe_uint_t::assert_equal") const
194 {
195 this->value.assert_equal(rhs.value, msg);
196 }
197 void assert_is_not_zero(std::string const& msg = "safe_uint_t::assert_is_not_zero") const;
198 void assert_is_zero(std::string const& msg = "safe_uint_t::assert_is_zero") const;
199 bool is_constant() const { return value.is_constant(); }
200
201 static safe_uint_t conditional_assign(const bool_ct& predicate, const safe_uint_t& lhs, const safe_uint_t& rhs)
202 {
203 auto new_val = (lhs.value - rhs.value).madd(predicate, rhs.value);
204 auto new_max = lhs.current_max > rhs.current_max ? lhs.current_max : rhs.current_max;
205 return safe_uint_t(new_val, new_max, IS_UNSAFE);
206 }
207
208 uint32_t get_witness_index() const { return value.get_witness_index(); }
210
214};
215
216template <typename Builder> inline std::ostream& operator<<(std::ostream& os, safe_uint_t<Builder> const& v)
217{
218 return os << v.value;
219}
220} // namespace bb::stdlib
#define BB_ASSERT_EQ(actual, expected,...)
Definition assert.hpp:59
#define BB_ASSERT_LTE(left, right,...)
Definition assert.hpp:129
constexpr uint64_t get_msb() const
Implements boolean logic in-circuit.
Definition bool.hpp:59
uint32_t set_public() const
Definition field.hpp:404
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:929
field_t madd(const field_t &to_mul, const field_t &to_add) const
Definition field.cpp:507
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:908
Builder * context
Definition field.hpp:51
void unset_free_witness_tag() const
Unset the free witness flag for the field element's tag.
Definition field.hpp:343
OriginTag get_origin_tag() const
Definition field.hpp:333
bool is_constant() const
Definition field.hpp:399
void set_free_witness_tag()
Set the free witness flag for the field element's tag.
Definition field.hpp:338
void set_origin_tag(const OriginTag &new_tag) const
Definition field.hpp:332
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:572
uint32_t get_witness_index() const
Get the witness index of the current field element.
Definition field.hpp:461
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:92
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:20
std::ostream & operator<<(std::ostream &os, uint256_t const &a)
Definition uint256.hpp:246
Entry point for Barretenberg command-line interface.
constexpr decltype(auto) get(::tuplet::tuple< T... > &&t) noexcept
Definition tuple.hpp:13
static constexpr uint256_t modulus