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#pragma once
2#include "../bool/bool.hpp"
3#include "../circuit_builders/circuit_builders.hpp"
4#include "../circuit_builders/circuit_builders_fwd.hpp"
5#include "../field/field.hpp"
6#include "../witness/witness.hpp"
8#include <functional>
9
10// The purpose of this class is to enable positive integer operations without a risk of overflow.
11// Despite the name, it is *not* a "safe" version of the uint class - as operations are positive integer
12// operations, and not modulo 2^t for some t, as they are in the uint class.
13
14namespace bb::stdlib {
15
16template <typename Builder> class safe_uint_t {
17 private:
20 // this constructor is private since we only want the operators to be able to define a positive int without a range
21 // check.
22 safe_uint_t(field_ct const& value, const uint256_t& current_max, size_t safety)
23 : value(value)
25 {
26 BB_ASSERT_EQ(safety, IS_UNSAFE);
27 BB_ASSERT_LTE(current_max, MAX_VALUE, "exceeded modulus in safe_uint class");
28 }
29
30 public:
31 // The following constant should be small enough that any thing with this bitnum is smaller than the modulus
32 static constexpr size_t MAX_BIT_NUM = bb::fr::modulus.get_msb();
33 static constexpr uint256_t MAX_VALUE = bb::fr::modulus - 1;
34 static constexpr size_t IS_UNSAFE = 143; // weird constant to make it hard to use accidentally
37
39 : value(0)
40 , current_max(0)
41 {}
42
43 safe_uint_t(field_ct const& value, size_t bit_num, std::string const& description = "unknown")
44 : value(value)
45 {
46 BB_ASSERT_LTE(bit_num, MAX_BIT_NUM);
47 this->value.create_range_constraint(bit_num, format("safe_uint_t range constraint failure: ", description));
48 current_max = ((uint256_t)1 << bit_num) - 1;
49 }
50
51 // When initialzing a constant, we can set the max value to the constant itself (rather than the usually larger
52 // 2^n-1)
53 safe_uint_t(const bb::fr& const_value)
54 : value(const_value)
55 , current_max(const_value)
56 {}
57
58 // When initialzing a constant, we can set the max value to the constant itself (rather than the usually larger
59 // 2^n-1)
60 safe_uint_t(const uint256_t& const_value)
61 : value(bb::fr(const_value))
62 , current_max(bb::fr(const_value))
63 {}
64 safe_uint_t(const unsigned int& const_value)
65 : value(bb::fr(const_value))
66 , current_max(bb::fr(const_value))
67 {}
68
70 : value(other.value)
72 {}
73
75 {
76 // Use witness_t's create_constant_witness which safely handles the assertion
78 auto result = safe_uint_t(value, uint256_t(value), IS_UNSAFE);
79 result.set_free_witness_tag();
80 return result;
81 }
82
83 // We take advantage of the range constraint already being applied in the bool constructor and don't make a
84 // redundant one.
85 safe_uint_t(const bool_ct& other)
86 : value(other)
87 , current_max(1)
88 {}
89
90 explicit operator bool_ct() { return bool_ct(value); }
91 static safe_uint_t from_witness_index(Builder* parent_context, const uint32_t witness_index);
92
93 // Subtraction when you have a pre-determined bound on the difference size
94 safe_uint_t subtract(const safe_uint_t& other,
95 const size_t difference_bit_size,
96 std::string const& description = "") const;
97
98 safe_uint_t operator-(const safe_uint_t& other) const;
99
100 // division when you have a pre-determined bound on the sizes of the quotient and remainder
102 const safe_uint_t& other,
103 const size_t quotient_bit_size,
104 const size_t remainder_bit_size,
105 std::string const& description = "",
106 const std::function<std::pair<uint256_t, uint256_t>(uint256_t, uint256_t)>& get_quotient =
107 [](uint256_t val, uint256_t divisor) {
108 return std::make_pair((uint256_t)(val / (uint256_t)divisor), (uint256_t)(val % (uint256_t)divisor));
109 }) const;
110
111 // Potentially less efficient than divide function - bounds remainder and quotient by max of this
112 safe_uint_t operator/(const safe_uint_t& other) const;
113
114 safe_uint_t add_two(const safe_uint_t& add_a, const safe_uint_t& add_b) const
115 {
116 BB_ASSERT_LTE(current_max + add_a.current_max + add_b.current_max, MAX_VALUE, "Exceeded modulus in add_two");
117 auto new_val = value.add_two(add_a.value, add_b.value);
118 auto new_max = current_max + add_a.current_max + add_b.current_max;
119 return safe_uint_t(new_val, new_max, IS_UNSAFE);
120 }
121
122 safe_uint_t madd(const safe_uint_t& to_mul, const safe_uint_t& to_add) const
123 {
125 MAX_VALUE,
126 "Exceeded modulus in madd");
127 auto new_val = value.madd(to_mul.value, to_add.value);
128 auto new_max = current_max * to_mul.current_max + to_add.current_max;
129 return safe_uint_t(new_val, new_max, IS_UNSAFE);
130 }
131
133 {
134 value = other.value;
135 current_max = other.current_max;
136 return *this;
137 }
138
140 {
141 value = other.value;
142 current_max = other.current_max;
143 return *this;
144 }
145
147 {
148 *this = *this + other;
149 return *this;
150 }
151
153 {
154 *this = *this * other;
155 return *this;
156 }
157
158 std::array<safe_uint_t<Builder>, 3> slice(const uint8_t msb, const uint8_t lsb) const;
159 void set_public() const { value.set_public(); }
160 operator field_ct() { return value; }
161 operator field_ct() const { return value; }
162 safe_uint_t operator+(const safe_uint_t& other) const;
163 safe_uint_t operator*(const safe_uint_t& other) const;
164 bool_ct operator==(const safe_uint_t& other) const;
165 bool_ct operator!=(const safe_uint_t& other) const;
166
174 safe_uint_t normalize() const;
175
176 bb::fr get_value() const;
177
178 Builder* get_context() const { return value.context; }
179
184 bool_ct is_zero() const;
185
186 void assert_equal(const safe_uint_t& rhs, std::string const& msg = "safe_uint_t::assert_equal") const
187 {
188 this->value.assert_equal(rhs.value, msg);
189 }
190 void assert_is_not_zero(std::string const& msg = "safe_uint_t::assert_is_not_zero") const;
191 void assert_is_zero(std::string const& msg = "safe_uint_t::assert_is_zero") const;
192 bool is_constant() const { return value.is_constant(); }
193
194 static safe_uint_t conditional_assign(const bool_ct& predicate, const safe_uint_t& lhs, const safe_uint_t& rhs)
195 {
196 auto new_val = (lhs.value - rhs.value).madd(predicate, rhs.value);
197 auto new_max = lhs.current_max > rhs.current_max ? lhs.current_max : rhs.current_max;
198 return safe_uint_t(new_val, new_max, IS_UNSAFE);
199 }
200
201 uint32_t get_witness_index() const { return value.get_witness_index(); }
203
207};
208
209template <typename Builder> inline std::ostream& operator<<(std::ostream& os, safe_uint_t<Builder> const& v)
210{
211 return os << v.value;
212}
213} // namespace bb::stdlib
#define BB_ASSERT_EQ(actual, expected,...)
Definition assert.hpp:93
#define BB_ASSERT_LTE(left, right,...)
Definition assert.hpp:168
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:64
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:35
bool_t< Builder > bool_ct
Definition safe_uint.hpp:19
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:33
safe_uint_t(field_ct const &value, size_t bit_num, std::string const &description="unknown")
Definition safe_uint.hpp:43
safe_uint_t & operator=(const safe_uint_t &other)
static constexpr size_t IS_UNSAFE
Definition safe_uint.hpp:34
static safe_uint_t< Builder > create_constant_witness(Builder *parent_context, bb::fr const &value)
Definition safe_uint.hpp:74
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:69
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:32
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:53
bool_ct operator==(const safe_uint_t &other) const
safe_uint_t(const uint256_t &const_value)
Definition safe_uint.hpp:60
safe_uint_t operator-(const safe_uint_t &other) const
Subtraction on two safe_uint_t objects.
Definition safe_uint.cpp:68
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:22
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:85
safe_uint_t operator*(const safe_uint_t &other) const
Definition safe_uint.cpp:16
safe_uint_t operator+(const safe_uint_t &other) const
Definition safe_uint.cpp:11
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:18
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:24
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