barretenberg
Loading...
Searching...
No Matches
bridge_call_data.hpp
1#pragma once
2#include "../constants.hpp"
3#include "../native/bridge_call_data.hpp"
4#include "./asset_id.hpp"
5#include "barretenberg/join_split_example/types.hpp"
6
7namespace join_split_example {
8namespace proofs {
9namespace notes {
10namespace circuit {
11
12using namespace proof_system::plonk::stdlib;
13
14constexpr uint32_t input_asset_id_a_shift = DEFI_BRIDGE_ADDRESS_ID_LEN;
15constexpr uint32_t input_asset_id_b_shift = input_asset_id_a_shift + DEFI_BRIDGE_INPUT_A_ASSET_ID_LEN;
16constexpr uint32_t output_asset_id_a_shift = input_asset_id_b_shift + DEFI_BRIDGE_INPUT_B_ASSET_ID_LEN;
17constexpr uint32_t output_asset_id_b_shift = output_asset_id_a_shift + DEFI_BRIDGE_OUTPUT_A_ASSET_ID_LEN;
18constexpr uint32_t bitconfig_shift = output_asset_id_b_shift + DEFI_BRIDGE_OUTPUT_B_ASSET_ID_LEN;
19constexpr uint32_t aux_data_shift = bitconfig_shift + DEFI_BRIDGE_BITCONFIG_LEN;
20
22
35 struct bit_config {
36 bool_ct second_input_in_use;
37 bool_ct second_output_in_use;
38
39 bit_config(){};
41 {
42 ASSERT(builder != nullptr);
43
44 constexpr auto bitconfig_mask = (1ULL << DEFI_BRIDGE_BITCONFIG_LEN) - 1;
45 uint32_t config_u32 = uint32_t((bridge_call_data >> bitconfig_shift) & bitconfig_mask);
46 second_input_in_use = witness_ct(builder, config_u32 & 1ULL);
47 second_output_in_use = witness_ct(builder, (config_u32 >> 1) & 1ULL);
48 }
49
50 suint_ct to_suint() const
51 {
52 const suint_ct bitconfig_scaling_factor(uint256_t(1) << bitconfig_shift);
53
54 suint_ct result(second_input_in_use);
55 result += suint_ct(second_output_in_use) * 2;
56 result *= bitconfig_scaling_factor;
57 return result;
58 }
59 };
60
69 // 32-bit integer which maps to a 20-byte bridge contract address.
71 // Note: for virtual assets, the asset_id will be `1` in the 30th-bit, followed by the defi interaction nonce of the
72 // interaction which created the asset
73 // 30-bit asset_id of first input asset
74 suint_ct input_asset_id_a;
75 // 30-bit asset_id of second input asset
76 suint_ct input_asset_id_b = 0;
77 // Note: if the user expects virtual output assets to be returned from a bridge, they must at least specify an
78 // output_asset_id of `100...00` (30-bits) to signal the asset's virtualness.
79 // 30-bit asset_id of the first output asset.
80 suint_ct output_asset_id_a;
81 // 30-bit asset_id of the second output asset.
82 suint_ct output_asset_id_b;
83
84 // 32-bit bit configuration that describes input/output note structure of bridge:
85 // see bit_config constructor for details.
86 bit_config config;
87 // 64-bit auxiliary data to be passed on to the bridge contract.
88 suint_ct aux_data = 0;
89
91 bridge_call_data(Builder* builder, const native::bridge_call_data& native_id)
92 : bridge_call_data(builder, native_id.to_uint256_t())
93 {}
94
95 bridge_call_data(Builder* builder, uint256_t const& bridge_call_data)
96 {
97 // constants
98 constexpr auto one = uint256_t(1);
99
100 auto bridge_address_id_value = bridge_call_data & uint256_t((one << DEFI_BRIDGE_ADDRESS_ID_LEN) - 1);
101 auto input_asset_id_a_value =
102 (bridge_call_data >> input_asset_id_a_shift) & uint256_t((one << DEFI_BRIDGE_INPUT_A_ASSET_ID_LEN) - 1);
103 auto input_asset_id_b_value =
104 (bridge_call_data >> input_asset_id_b_shift) & uint256_t((one << DEFI_BRIDGE_INPUT_B_ASSET_ID_LEN) - 1);
105 auto output_asset_id_a_value =
106 (bridge_call_data >> output_asset_id_a_shift) & uint256_t((one << DEFI_BRIDGE_OUTPUT_A_ASSET_ID_LEN) - 1);
107 auto output_asset_id_b_value =
108 (bridge_call_data >> output_asset_id_b_shift) & uint256_t((one << DEFI_BRIDGE_OUTPUT_B_ASSET_ID_LEN) - 1);
109 auto aux_data_value = (bridge_call_data >> aux_data_shift) & uint256_t((one << DEFI_BRIDGE_AUX_DATA) - 1);
110
112 suint_ct(witness_ct(builder, bridge_address_id_value), DEFI_BRIDGE_ADDRESS_ID_LEN, "bridge_address");
113 input_asset_id_a =
114 suint_ct(witness_ct(builder, input_asset_id_a_value), DEFI_BRIDGE_INPUT_A_ASSET_ID_LEN, "input_asset_id_a");
115 input_asset_id_b =
116 suint_ct(witness_ct(builder, input_asset_id_b_value), DEFI_BRIDGE_INPUT_B_ASSET_ID_LEN, "input_asset_id_b");
117 output_asset_id_a = suint_ct(
118 witness_ct(builder, output_asset_id_a_value), DEFI_BRIDGE_OUTPUT_A_ASSET_ID_LEN, "output_asset_id_a");
119 output_asset_id_b = suint_ct(
120 witness_ct(builder, output_asset_id_b_value), DEFI_BRIDGE_OUTPUT_B_ASSET_ID_LEN, "output_asset_id_b");
121 aux_data = suint_ct(witness_ct(builder, aux_data_value), DEFI_BRIDGE_AUX_DATA, "aux_data");
122
123 config = bit_config(builder, bridge_call_data);
124
126 }
127
129 {
130 // If the second input/output asset_id is nonzero, then it must be in-use.
131 //
132 // Note: If it's zero, it could be ETH (which has asset_id = 0), so we can't enforce the opposite direction of
133 // implication (that if second_input_in_use, then it must be nonzero).
134 // This does mean that if someone deposits ETH as the second input asset_id, but forgets to set
135 // second_input_in_use to be `true`, then this circuit cannot catch this mistake. Therefore it's important that
136 // every bridge contract validates the inputs it receives.
137 (!input_asset_id_b.is_zero())
138 .must_imply(config.second_input_in_use, "Expected second_input_in_use, given input_asset_id_b != 0");
139 (!output_asset_id_b.is_zero())
140 .must_imply(config.second_output_in_use, "Expected second_output_in_use, given output_asset_id_b != 0");
141
149 config.second_input_in_use.must_imply(
150 input_asset_id_a != input_asset_id_b,
151 "input asset ids must be different for the second bridge input to be in-use");
152
171 const bool_ct first_output_virtual = get_asset_id_flag(output_asset_id_a);
172 const bool_ct second_output_virtual = get_asset_id_flag(output_asset_id_b);
173 const bool_ct both_outputs_real = (!first_output_virtual && !second_output_virtual);
174
175 (config.second_output_in_use && both_outputs_real)
176 .must_imply(output_asset_id_a != output_asset_id_b,
177 "real output asset ids must be different for the second bridge output to be in-use");
178
179 const suint_ct virtual_asset_id_placeholder = suint_ct(1 << (MAX_NUM_ASSETS_BIT_LENGTH - 1)); // 2**29
180 first_output_virtual.must_imply(output_asset_id_a == virtual_asset_id_placeholder,
181 "output_asset_id_a detected as virtual, but has incorrect placeholder value");
182 second_output_virtual.must_imply(output_asset_id_b == virtual_asset_id_placeholder,
183 "output_asset_id_b detected as virtual, but has incorrect placeholder value");
184 }
185
186 suint_ct to_safe_uint() const
187 {
188 // constants
189 constexpr auto one = uint256_t(1);
190
191 auto result = bridge_address_id + (input_asset_id_a * suint_ct(one << (input_asset_id_a_shift))) +
192 (input_asset_id_b * suint_ct(one << (input_asset_id_b_shift))) +
193 (output_asset_id_a * suint_ct(one << (output_asset_id_a_shift))) +
194 (output_asset_id_b * suint_ct(one << (output_asset_id_b_shift))) + config.to_suint() +
195 (aux_data * suint_ct(one << (aux_data_shift)));
196 return result;
197 }
198};
199
200inline std::ostream& operator<<(std::ostream& os, bridge_call_data::bit_config const& config)
201{
202 os << " second_input_in_use: " << config.second_input_in_use << ",\n"
203 << " second_output_in_use: " << config.second_output_in_use << ",\n";
204 return os;
205}
206
207inline std::ostream& operator<<(std::ostream& os, bridge_call_data const& bridge_call_data)
208{
209 os << "{\n"
210 << " bridge_address_id: " << bridge_call_data.bridge_address_id << ",\n"
211 << " input_asset_id_a: " << bridge_call_data.input_asset_id_a << ",\n"
212 << " input_asset_id_b: " << bridge_call_data.input_asset_id_b << ",\n"
213 << " output_asset_id_a: " << bridge_call_data.output_asset_id_a << ",\n"
214 << " output_asset_id_b: " << bridge_call_data.output_asset_id_b << ",\n"
215 << bridge_call_data.config << " aux_data: " << bridge_call_data.aux_data << "\n}";
216 return os;
217}
218
219} // namespace circuit
220} // namespace notes
221} // namespace proofs
222} // namespace join_split_example
Definition: uint256.hpp:25
Definition: ultra_circuit_builder.hpp:31
void must_imply(const bool_t &other, std::string const &msg="bool_t::must_imply") const
Definition: bool.cpp:447
Definition: safe_uint.hpp:17
bool_ct is_zero() const
Definition: safe_uint.cpp:184
Definition: witness.hpp:10
suint_ct bridge_address_id
Definition: bridge_call_data.hpp:70
void validate_bit_config()
Definition: bridge_call_data.hpp:128