template class note_gadget : public gadget { public: pb_variable_array value; std::shared_ptr> r; note_gadget(protoboard &pb) : gadget(pb) { value.allocate(pb, 64); r.reset(new digest_variable(pb, 256, "")); } void generate_r1cs_constraints() { for (size_t i = 0; i < 64; i++) { generate_boolean_r1cs_constraint( this->pb, value[i], "boolean_value" ); } r->generate_r1cs_constraints(); } void generate_r1cs_witness(const Note& note) { r->bits.fill_with_bits(this->pb, uint256_to_bool_vector(note.r)); value.fill_with_bits(this->pb, uint64_to_bool_vector(note.value)); } }; template class input_note_gadget : public note_gadget { private: std::shared_ptr> a_pk; std::shared_ptr> rho; std::shared_ptr> commitment; std::shared_ptr> commit_to_inputs; std::shared_ptr> spend_authority; std::shared_ptr> expose_nullifiers; public: std::shared_ptr> a_sk; input_note_gadget( protoboard& pb, pb_variable& ZERO, std::shared_ptr> nullifier ) : note_gadget(pb) { a_sk.reset(new digest_variable(pb, 252, "")); a_pk.reset(new digest_variable(pb, 256, "")); rho.reset(new digest_variable(pb, 256, "")); commitment.reset(new digest_variable(pb, 256, "")); spend_authority.reset(new PRF_addr_a_pk_gadget( pb, ZERO, a_sk->bits, a_pk )); expose_nullifiers.reset(new PRF_nf_gadget( pb, ZERO, a_sk->bits, rho->bits, nullifier )); commit_to_inputs.reset(new note_commitment_gadget( pb, ZERO, a_pk->bits, this->value, rho->bits, this->r->bits, commitment )); } void generate_r1cs_constraints() { note_gadget::generate_r1cs_constraints(); a_sk->generate_r1cs_constraints(); rho->generate_r1cs_constraints(); // TODO: These constraints may not be necessary if SHA256 // already boolean constrains its outputs. a_pk->generate_r1cs_constraints(); commitment->generate_r1cs_constraints(); spend_authority->generate_r1cs_constraints(); expose_nullifiers->generate_r1cs_constraints(); commit_to_inputs->generate_r1cs_constraints(); } void generate_r1cs_witness(const SpendingKey& key, const Note& note) { note_gadget::generate_r1cs_witness(note); // Witness a_sk for the input a_sk->bits.fill_with_bits( this->pb, trailing252(uint256_to_bool_vector(key)) ); // Witness a_pk for a_sk with PRF_addr spend_authority->generate_r1cs_witness(); // [SANITY CHECK] Witness a_pk with note information a_pk->bits.fill_with_bits( this->pb, uint256_to_bool_vector(note.a_pk) ); // Witness rho for the input note rho->bits.fill_with_bits( this->pb, uint256_to_bool_vector(note.rho) ); // Witness the nullifier for the input note expose_nullifiers->generate_r1cs_witness(); // Witness the commitment of the input note commit_to_inputs->generate_r1cs_witness(); // [SANITY CHECK] Ensure the commitment is // valid. commitment->bits.fill_with_bits( this->pb, uint256_to_bool_vector(note.cm()) ); } }; template class output_note_gadget : public note_gadget { private: std::shared_ptr> rho; std::shared_ptr> a_pk; std::shared_ptr> prevent_faerie_gold; std::shared_ptr> commit_to_outputs; public: output_note_gadget( protoboard& pb, pb_variable& ZERO, pb_variable_array& phi, pb_variable_array& h_sig, bool nonce, std::shared_ptr> commitment ) : note_gadget(pb) { rho.reset(new digest_variable(pb, 256, "")); a_pk.reset(new digest_variable(pb, 256, "")); // Do not allow the caller to choose the same "rho" // for any two valid notes in a given view of the // blockchain. See protocol specification for more // details. prevent_faerie_gold.reset(new PRF_rho_gadget( pb, ZERO, phi, h_sig, nonce, rho )); // Commit to the output notes publicly without // disclosing them. commit_to_outputs.reset(new note_commitment_gadget( pb, ZERO, a_pk->bits, this->value, rho->bits, this->r->bits, commitment )); } void generate_r1cs_constraints() { note_gadget::generate_r1cs_constraints(); a_pk->generate_r1cs_constraints(); // TODO: This constraint may not be necessary if SHA256 // already boolean constrains its outputs. rho->generate_r1cs_constraints(); prevent_faerie_gold->generate_r1cs_constraints(); commit_to_outputs->generate_r1cs_constraints(); } void generate_r1cs_witness(const Note& note) { note_gadget::generate_r1cs_witness(note); prevent_faerie_gold->generate_r1cs_witness(); // [SANITY CHECK] Witness rho ourselves with the // note information. rho->bits.fill_with_bits( this->pb, uint256_to_bool_vector(note.rho) ); a_pk->bits.fill_with_bits( this->pb, uint256_to_bool_vector(note.a_pk) ); commit_to_outputs->generate_r1cs_witness(); } };