Created
October 7, 2018 12:02
-
-
Save shamatar/d262e5e5b62e4002b8ae59dfcb56d65e to your computer and use it in GitHub Desktop.
roll_up_for_fungible_tokens
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
namespace libsnark { | |
template<typename FieldT, typename HashT> | |
tx<FieldT,HashT>::tx(protoboard<FieldT> &pb, | |
pb_variable_array<FieldT> &pub_key_x_bin, // sender's pubkey X | |
pb_variable_array<FieldT> &pub_key_y_bin, // sender's pubkey Y | |
pb_variable_array<FieldT> &balance_bin, // sender's leaf's balance | |
pb_variable_array<FieldT> &balance_recipient_bin, // recipients's leaf's balance | |
pb_variable_array<FieldT> &balance_new_bin, // sender's leaf's balance | |
pb_variable_array<FieldT> &balance_recipient_new_bin, // recipients's leaf's balance | |
pb_variable_array<FieldT> &tx_amount_bin, // tx amount | |
pb_variable_array<FieldT> &nonce_bin, // sender's nonce | |
pb_variable_array<FieldT> &new_nonce_bin, // sender's nonce | |
pb_variable_array<FieldT> &pub_key_x_rec_bin, // recipients's pubkey X | |
pb_variable_array<FieldT> &pub_key_y_rec_bin, // recipients's pubkey Y | |
pb_variable_array<FieldT> &nonce_rec_bin, // recipients's nonce | |
int tree_depth, // tree depth | |
pb_variable_array<FieldT> address_bits_va, // sender's address | |
pb_variable_array<FieldT> address_bits_va_destination, // recipient's address | |
std::shared_ptr<digest_variable<FieldT>> root_digest_old, // old merkle root | |
std::shared_ptr<digest_variable<FieldT>> root_digest_new, // new merkle root | |
std::vector<merkle_authentication_node> path_old, // old merkle proof for sender | |
std::vector<merkle_authentication_node> path_new, // new merkle proof for sender | |
std::vector<merkle_authentication_node> path_old_recipient, // old merkle proof for recipient | |
std::vector<merkle_authentication_node> path_new_recipient, // new merkle proof for recipient | |
pb_variable_array<FieldT> S, // signature S | |
pb_variable_array<FieldT> r_x_bin, // signature R_x | |
pb_variable_array<FieldT> r_y_bin, // signature R_y | |
// pb_variable_array<FieldT> rhs_leaf, // these two are from roll-up, discard them | |
// std::shared_ptr<digest_variable<FieldT>> new_leaf, | |
const std::string &annotation_prefix): gadget<FieldT>(pb, annotation_prefix) , | |
// f..k cpp, add these variables please | |
pub_key_x_bin(pub_key_x_bin), | |
pub_key_y_bin(pub_key_y_bin), tree_depth(tree_depth), path_old(path_old), | |
path_new(path_new), address_bits_va(address_bits_va), rhs_leaf(rhs_leaf), | |
root_digest_old(root_digest_old), root_digest_new(root_digest_new), new_leaf(new_leaf) { | |
// base-point for EDDSA | |
pb_variable<FieldT> base_x; | |
pb_variable<FieldT> base_y; | |
// baby jubjub's curve params | |
pb_variable<FieldT> a; | |
pb_variable<FieldT> d; | |
//public key assembled from bits | |
pb_variable<FieldT> pub_x; | |
pb_variable<FieldT> pub_y; | |
// balances and nonce from bits | |
pb_variable<FieldT> balance; | |
pb_variable<FieldT> balance_recipient; | |
pb_variable<FieldT> balance_new; | |
pb_variable<FieldT> balance_recipient_new; | |
pb_variable<FieldT> tx_amount; | |
pb_variable<FieldT> nonce; | |
pb_variable<FieldT> new_nonce; | |
base_x.allocate(pb, "base x"); | |
base_y.allocate(pb, "base y"); | |
pub_x.allocate(pb, "pub_x"); | |
pub_y.allocate(pb, "pub_y"); | |
a.allocate(pb, "a"); | |
d.allocate(pb, "d"); | |
pb.val(base_x) = FieldT("17777552123799933955779906779655732241715742912184938656739573121738514868268"); | |
pb.val(base_y) = FieldT("2626589144620713026669568689430873010625803728049924121243784502389097019475"); | |
pb.val(a) = FieldT("168700"); | |
pb.val(d) = FieldT("168696"); | |
pub_key_x.allocate(pb,2, "ZERO"); | |
pub_key_y.allocate(pb,2, "ZERO"); | |
ZERO.allocate(pb, "ZERO"); | |
pb.val(ZERO) = 0; | |
F_ONE.allocate(pb, "ONE"); | |
pb.val(F_ONE) = 1; | |
// allocate vars for digests | |
sender_h1.reset(new digest_variable<FieldT>(pb, 256, "sender_h1")); | |
sender_h2.reset(new digest_variable<FieldT>(pb, 256, "sender_h2")); | |
sender_leaf.reset(new digest_variable<FieldT>(pb, 256, "sender leaf")); | |
rec_h1.reset(new digest_variable<FieldT>(pb, 256, "rec_h1")); | |
rec_h1.reset(new digest_variable<FieldT>(pb, 256, "rec_h1")); | |
rec_leaf.reset(new digest_variable<FieldT>(pb, 256, "rec leaf")); | |
message_interm.reset(new digest_variable<FieldT>(pb, 256, "message intermediate digest")); | |
message.reset(new digest_variable<FieldT>(pb, 256, "message digest")); | |
// assemble current leaf's digest as | |
// t1 = concat[pub_key_x_bin, pub_key_y_bin] | |
// t2 = concat[balance, nonce] | |
// t3 = concat[sha256(t1), sha256(t2)] | |
input_variable.reset(new block_variable<FieldT>(pb, {pub_key_x_bin, pub_key_y_bin}, "input_variable")); | |
input_variable2.reset(new block_variable<FieldT>(pb, {balance_bin, nonce_bin}, "input_variable2")); | |
input_variable3.reset(new block_variable<FieldT>(pb, {sender_h1->bits, sender_h2->bits}, "input_variable3")); | |
input_variable_rec.reset(new block_variable<FieldT>(pb, {pub_key_x_rec_bin, pub_key_y_rec_bin}, "input_variable_rec")); | |
input_variable2_rec.reset(new block_variable<FieldT>(pb, {balance_rec_bin, nonce_rec_bin}, "input_variable2_rec")); | |
input_variable3.reset(new block_variable<FieldT>(pb, {rec_h1->bits, rec_h2->bits}, "input_variable3_rec")); | |
t1_hash.reset(new sha256_ethereum(pb, 256, *input_variable, *sender_h1, "t1 hash")); | |
t2_hash.reset(new sha256_ethereum(pb, 256, *input_variable2, *sender_h2, "t2 hash")); | |
t3_hash.reset(new sha256_ethereum(pb, 256, *input_variable3, *sender_leaf, "sender leaf hash")); | |
t1_rec_hash.reset(new sha256_ethereum(pb, 256, *input_variable_rec, *rec_h1, "t1 rec hash")); | |
t2_rec_hash.reset(new sha256_ethereum(pb, 256, *input_variable2_rec, *rec_h2, "t2 rec hash")); | |
t3_rec_hash.reset(new sha256_ethereum(pb, 256, *input_variable3_rec, *rec_leaf, "rec leaf hash")); | |
// tx_hash = sha256(sha256(amount, nonce), recipient) | |
message_interm_var.reset(new block_variable<FieldT>(pb, {tx_amount_bin, nonce_bin}, "msg interm")); | |
message_interm_var2.reset(new block_variable<FieldT>(pb, {message_interm->bits, &address_bits_va_destination}, "msg")); | |
message_hash_interm.reset(new sha256_ethereum(pb, 256, *message_interm_var, *message_interm, "msg interm hash")); | |
message_hash.reset(new sha256_ethereum(pb, 256, *message_interm_var2, *message, "msg hash")); | |
// pack pubkey X | |
unpacker_pub_key_x.reset(new multipacking_gadget<FieldT>( | |
pb, | |
pub_key_x_bin, //pb_linear_combination_array<FieldT>(cm->bits.begin(), cm->bits.begin() , cm->bits.size()), | |
pub_key_x, | |
FieldT::capacity() + 1, | |
"pack pub key x into var" | |
)); | |
// pack pubkey Y | |
unpacker_pub_key_y.reset(new multipacking_gadget<FieldT>( | |
pb, | |
pub_key_y_bin, //pb_linear_combination_array<FieldT>(cm->bits.begin(), cm->bits.begin() , cm->bits.size()), | |
pub_key_y, | |
FieldT::capacity() + 1, | |
"pack pub key y into var" | |
)); | |
// pack sender's balance | |
unpacker_balance.reset(new multipacking_gadget<FieldT>( | |
pb, | |
balance_bin, //pb_linear_combination_array<FieldT>(cm->bits.begin(), cm->bits.begin() , cm->bits.size()), | |
balance, | |
FieldT::capacity() + 1, | |
"pack sender's balance into var" | |
)); | |
// pack recipient's balance | |
unpacker_balance_recipient.reset(new multipacking_gadget<FieldT>( | |
pb, | |
balance_recipient_bin, //pb_linear_combination_array<FieldT>(cm->bits.begin(), cm->bits.begin() , cm->bits.size()), | |
balance_recipient, | |
FieldT::capacity() + 1, | |
"pack recipient's balance into var" | |
)); | |
// pack sender's balance | |
unpacker_balance_new.reset(new multipacking_gadget<FieldT>( | |
pb, | |
balance_new_bin, //pb_linear_combination_array<FieldT>(cm->bits.begin(), cm->bits.begin() , cm->bits.size()), | |
balance_new, | |
FieldT::capacity() + 1, | |
"pack sender's new balance into var" | |
)); | |
// pack recipient's balance | |
unpacker_balance_recipient_new.reset(new multipacking_gadget<FieldT>( | |
pb, | |
balance_recipient_new_bin, //pb_linear_combination_array<FieldT>(cm->bits.begin(), cm->bits.begin() , cm->bits.size()), | |
balance_recipient_new, | |
FieldT::capacity() + 1, | |
"pack recipient's new balance into var" | |
)); | |
unpacker_tx_amount.reset(new multipacking_gadget<FieldT>( | |
pb, | |
tx_amount_bin, //pb_linear_combination_array<FieldT>(cm->bits.begin(), cm->bits.begin() , cm->bits.size()), | |
tx_amount, | |
FieldT::capacity() + 1, | |
"pack tx amount into var" | |
)); | |
unpacker_nonce.reset(new multipacking_gadget<FieldT>( | |
pb, | |
nonce_bin, //pb_linear_combination_array<FieldT>(cm->bits.begin(), cm->bits.begin() , cm->bits.size()), | |
nonce, | |
FieldT::capacity() + 1, | |
"pack old nonce into var" | |
)); | |
unpacker_new_nonce.reset(new multipacking_gadget<FieldT>( | |
pb, | |
new_nonce_bin, //pb_linear_combination_array<FieldT>(cm->bits.begin(), cm->bits.begin() , cm->bits.size()), | |
new_nonce, | |
FieldT::capacity() + 1, | |
"pack new nonce into var" | |
)); | |
path_var_old.reset(new merkle_authentication_path_variable<FieldT, HashT> (pb, tree_depth, "path_var" )); | |
path_var_new.reset(new merkle_authentication_path_variable<FieldT, HashT> (pb, tree_depth, "path_var" )); | |
path_var_old_rec.reset(new merkle_authentication_path_variable<FieldT, HashT> (pb, tree_depth, "path_var_rec" )); | |
path_var_new_rec.reset(new merkle_authentication_path_variable<FieldT, HashT> (pb, tree_depth, "path_var_rec" )); | |
ml.reset(new merkle_tree_check_update_gadget<FieldT, HashT>(pb, tree_depth, address_bits_va, *leaf, *root_digest_old, *path_var_old, *new_leaf, *root_digest_new, *path_var_new, ONE, "ml")); | |
ml_rec.reset(new merkle_tree_check_update_gadget<FieldT, HashT>(pb, tree_depth, address_bits_va_destination, *leaf_rec, *root_digest_old, *path_var_old_rec, *new_leaf_rec, *root_digest_new, *path_var_new_rec, ONE, "ml_rec")); | |
jubjub_eddsa.reset(new eddsa<FieldT, HashT> (pb,a,d, pub_key_x_bin, pub_key_y_bin, base_x,base_y,r_x_bin, r_y_bin, message->bits, S)); | |
// constraint nonce | |
pb.add_r1cs_constraint(r1cs_constraint<FieldT>(zero, zero, new_nonce - nonce - F_ONE), "constraint nonces")); | |
// constraint balances | |
pb.add_r1cs_constraint(r1cs_constraint<FieldT>(zero, zero, balance - balance_new - tx_amount), "constraint sender's balance")); | |
pb.add_r1cs_constraint(r1cs_constraint<FieldT>(zero, zero, balance_recipient_new - balance_recipient - tx_amount), "constraint recipient's balance")); | |
// ideally we should constraint common prefix for addresses and merkle proofs, but too complicated for a hackathon | |
} | |
// add here constraints generation and witness generation for a new set of vars in constructor | |
template<typename FieldT, typename HashT> | |
void tx<FieldT, HashT>::generate_r1cs_constraints() { | |
jubjub_eddsa->generate_r1cs_constraints(); | |
public_key_hash->generate_r1cs_constraints(true); | |
leaf_hash->generate_r1cs_constraints(true); | |
message_hash->generate_r1cs_constraints(true); | |
unpacker_pub_key_x->generate_r1cs_constraints(true); | |
unpacker_pub_key_y->generate_r1cs_constraints(true); | |
path_var_old->generate_r1cs_constraints(); | |
path_var_new->generate_r1cs_constraints(); | |
root_digest_old->generate_r1cs_constraints(); | |
root_digest_new->generate_r1cs_constraints(); | |
ml->generate_r1cs_constraints(); | |
ml_rec->generate_r1cs_constraints(); | |
//make sure the traget root matched the calculated root | |
//for(int i = 0 ; i < 255; i++) { | |
// this->pb.add_r1cs_constraint(r1cs_constraint<FieldT>(1, root_digest_old->bits[i], root_digest_calculated->bits[i]), | |
// FMT(annotation_prefix, " root digests equal")); | |
//} | |
} | |
template<typename FieldT, typename HashT> | |
void tx<FieldT, HashT>::generate_r1cs_witness() { | |
//debug | |
public_key_hash->generate_r1cs_witness(); | |
leaf_hash->generate_r1cs_witness(); | |
message_hash->generate_r1cs_witness(); | |
unpacker_pub_key_x->generate_r1cs_witness_from_bits(); | |
unpacker_pub_key_y->generate_r1cs_witness_from_bits(); | |
auto address = address_bits_va.get_field_element_from_bits(this->pb); | |
path_var_old->generate_r1cs_witness(address.as_ulong(), path_old); | |
path_var_new->generate_r1cs_witness(address.as_ulong(), path_new); | |
ml->generate_r1cs_witness(); | |
ml_rec->generate_r1cs_witness(); | |
jubjub_eddsa->generate_r1cs_witness(); | |
//debug | |
/* | |
std::cout << " leaf " ; | |
for(uint i =0;i<256;i++) { | |
std::cout << " , " << this->pb.lc_val(leaf->bits[i]); | |
} | |
std::cout << "new leaf " ; | |
for(uint i =0;i<256;i++) { | |
std::cout << " , " << this->pb.lc_val(new_leaf->bits[i]); | |
} | |
std::cout << "message " ; | |
for(uint i =0;i<256;i++) { | |
std::cout << " , " << this->pb.lc_val(message->bits[i]); | |
} | |
std::cout << " pub_key_x " << this->pb.lc_val(pub_key_x[0]) << " " << this->pb.lc_val(pub_key_x[1]) << std::endl; | |
std::cout << " pub_key_y " << this->pb.lc_val(pub_key_y[0]) << " " << this->pb.lc_val(pub_key_y[1]) << std::endl; | |
*/ | |
std::cout << "pub_key_x " ; | |
for(uint i =0;i<256;i++) { | |
std::cout << " , " << this->pb.lc_val(pub_key_x_bin[i]); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment