Sean Bowe
8 years ago
4 changed files with 190 additions and 1 deletions
@ -0,0 +1,82 @@ |
|||||
|
template<typename FieldT> |
||||
|
class note_gadget : public gadget<FieldT> { |
||||
|
public: |
||||
|
pb_variable_array<FieldT> value; |
||||
|
std::shared_ptr<digest_variable<FieldT>> r; |
||||
|
|
||||
|
note_gadget(protoboard<FieldT> &pb) : gadget<FieldT>(pb) { |
||||
|
value.allocate(pb, 64); |
||||
|
r.reset(new digest_variable<FieldT>(pb, 256, "")); |
||||
|
} |
||||
|
|
||||
|
void generate_r1cs_constraints() { |
||||
|
for (size_t i = 0; i < 64; i++) { |
||||
|
generate_boolean_r1cs_constraint<FieldT>( |
||||
|
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<typename FieldT> |
||||
|
class input_note_gadget : public note_gadget<FieldT> { |
||||
|
public: |
||||
|
std::shared_ptr<digest_variable<FieldT>> a_sk; |
||||
|
std::shared_ptr<digest_variable<FieldT>> a_pk; |
||||
|
|
||||
|
std::shared_ptr<PRF_addr_a_pk_gadget<FieldT>> spend_authority; |
||||
|
|
||||
|
input_note_gadget( |
||||
|
protoboard<FieldT>& pb, |
||||
|
pb_variable<FieldT>& ZERO |
||||
|
) : note_gadget<FieldT>(pb) { |
||||
|
a_sk.reset(new digest_variable<FieldT>(pb, 252, "")); |
||||
|
a_pk.reset(new digest_variable<FieldT>(pb, 256, "")); |
||||
|
spend_authority.reset(new PRF_addr_a_pk_gadget<FieldT>( |
||||
|
pb, |
||||
|
ZERO, |
||||
|
a_sk->bits, |
||||
|
a_pk |
||||
|
)); |
||||
|
} |
||||
|
|
||||
|
void generate_r1cs_constraints() { |
||||
|
note_gadget<FieldT>::generate_r1cs_constraints(); |
||||
|
|
||||
|
a_sk->generate_r1cs_constraints(); |
||||
|
|
||||
|
// TODO: This constraint may not be necessary if SHA256 |
||||
|
// already boolean constrains its outputs. |
||||
|
a_pk->generate_r1cs_constraints(); |
||||
|
|
||||
|
spend_authority->generate_r1cs_constraints(); |
||||
|
} |
||||
|
|
||||
|
void generate_r1cs_witness(const SpendingKey& key, const Note& note) { |
||||
|
note_gadget<FieldT>::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) |
||||
|
); |
||||
|
} |
||||
|
}; |
@ -0,0 +1,77 @@ |
|||||
|
template<typename FieldT> |
||||
|
class PRF_gadget : gadget<FieldT> { |
||||
|
private: |
||||
|
std::shared_ptr<block_variable<FieldT>> block; |
||||
|
std::shared_ptr<sha256_compression_function_gadget<FieldT>> hasher; |
||||
|
std::shared_ptr<digest_variable<FieldT>> result; |
||||
|
|
||||
|
public: |
||||
|
PRF_gadget( |
||||
|
protoboard<FieldT>& pb, |
||||
|
pb_variable<FieldT>& ZERO, |
||||
|
bool a, |
||||
|
bool b, |
||||
|
bool c, |
||||
|
bool d, |
||||
|
pb_variable_array<FieldT> x, |
||||
|
boost::optional<pb_variable_array<FieldT>> y, |
||||
|
std::shared_ptr<digest_variable<FieldT>> result |
||||
|
) : gadget<FieldT>(pb), result(result) { |
||||
|
|
||||
|
pb_linear_combination_array<FieldT> IV = SHA256_default_IV(pb); |
||||
|
|
||||
|
pb_variable_array<FieldT> discriminants; |
||||
|
discriminants.emplace_back(a ? ONE : ZERO); |
||||
|
discriminants.emplace_back(b ? ONE : ZERO); |
||||
|
discriminants.emplace_back(c ? ONE : ZERO); |
||||
|
discriminants.emplace_back(d ? ONE : ZERO); |
||||
|
|
||||
|
if (!y) { |
||||
|
// Create y and pad it with zeroes. |
||||
|
y = pb_variable_array<FieldT>(); |
||||
|
while (y->size() < 256) { |
||||
|
y->emplace_back(ZERO); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
block.reset(new block_variable<FieldT>(pb, { |
||||
|
discriminants, |
||||
|
x, |
||||
|
*y |
||||
|
}, "PRF_block")); |
||||
|
|
||||
|
hasher.reset(new sha256_compression_function_gadget<FieldT>( |
||||
|
pb, |
||||
|
IV, |
||||
|
block->bits, |
||||
|
*result, |
||||
|
"PRF_hasher")); |
||||
|
} |
||||
|
|
||||
|
void generate_r1cs_constraints() { |
||||
|
hasher->generate_r1cs_constraints(); |
||||
|
} |
||||
|
|
||||
|
void generate_r1cs_witness() { |
||||
|
hasher->generate_r1cs_witness(); |
||||
|
} |
||||
|
}; |
||||
|
|
||||
|
template<typename FieldT> |
||||
|
class PRF_addr_a_pk_gadget : public PRF_gadget<FieldT> { |
||||
|
public: |
||||
|
PRF_addr_a_pk_gadget( |
||||
|
protoboard<FieldT>& pb, |
||||
|
pb_variable<FieldT>& ZERO, |
||||
|
pb_variable_array<FieldT>& a_sk, |
||||
|
std::shared_ptr<digest_variable<FieldT>> result |
||||
|
) : PRF_gadget<FieldT>(pb, ZERO, 1, 1, 0, 0, a_sk, boost::none, result) {} |
||||
|
|
||||
|
void generate_r1cs_constraints() { |
||||
|
PRF_gadget<FieldT>::generate_r1cs_constraints(); |
||||
|
} |
||||
|
|
||||
|
void generate_r1cs_witness() { |
||||
|
PRF_gadget<FieldT>::generate_r1cs_witness(); |
||||
|
} |
||||
|
}; |
Loading…
Reference in new issue