Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat!: Removes pedersen from schnorr algorithm #627

Draft
wants to merge 1 commit into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 7 additions & 19 deletions cpp/src/barretenberg/crypto/schnorr/schnorr.tcc
Original file line number Diff line number Diff line change
Expand Up @@ -11,23 +11,12 @@ namespace schnorr {
/**
* @brief Generate the schnorr signature challenge parameter `e` given a message, signer pubkey and nonce
*
* @details Normal Schnorr param e = H(R.x || pubkey || message)
* But we want to keep hash preimage to <= 64 bytes for a 32 byte message
* (for performance reasons in our join-split circuit!)
*
* barretenberg schnorr defines e as the following:
*
* e = H(pedersen(R.x || pubkey.x || pubkey.y), message)
*
* pedersen is collision resistant => e can be modelled as randomly distributed
* as long as H can be modelled as a random oracle
*
* @tparam Hash the hash-function used as random-oracle
* @tparam G1 Group over which the signature is produced
* @param message what are we signing over?
* @param pubkey the pubkey of the signer
* @param R the nonce
* @return e = H(pedersen(R.x || pubkey.x || pubkey.y), message) as a 256-bit integer,
* @return e = H(R.x || pubkey.x || pubkey.y || message) as a 256-bit integer,
* represented in a container of 32 uint8_t's
*
*
Expand All @@ -41,15 +30,14 @@ static auto generate_schnorr_challenge(const std::string& message,
const typename G1::affine_element& pubkey,
const typename G1::affine_element& R)
{
using Fq = typename G1::coordinate_field;
// create challenge message pedersen_commitment(R.x, pubkey)
Fq compressed_keys = crypto::pedersen_commitment::compress_native({ R.x, pubkey.x, pubkey.y });
std::vector<uint8_t> e_buffer;
write(e_buffer, compressed_keys);
write(e_buffer, R.x);
write(e_buffer, pubkey.x);
write(e_buffer, pubkey.y);
std::copy(message.begin(), message.end(), std::back_inserter(e_buffer));

// hash the result of the pedersen hash digest
// we return auto since some hash implementation return
// Hash the buffer to produce a 256-bit integer
// We return auto since some hash implementation return
// either a std::vector or a std::array with 32 bytes
return Hash::hash(e_buffer);
}
Expand Down Expand Up @@ -148,7 +136,7 @@ bool verify_signature(const std::string& message, const typename G1::affine_elem

// compare the _hashes_ rather than field elements modulo r

// e = H(pedersen(r, pk.x, pk.y), m), where r = x(R)
// e = H(r, pk.x, pk.y, m), where r = x(R)
auto target_e = generate_schnorr_challenge<Hash, G1>(message, public_key, R);
return std::equal(sig.e.begin(), sig.e.end(), target_e.begin(), target_e.end());
}
Expand Down
27 changes: 16 additions & 11 deletions cpp/src/barretenberg/stdlib/encryption/schnorr/schnorr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -244,7 +244,7 @@ point<C> variable_base_mul(const point<C>& pub_key, const point<C>& current_accu
}

// At this point, accumulator is [W + skew]pub + [2^{129}]collision_mask.
// If wnaf_skew, subtract pub_key frorm accumulator.
// If wnaf_skew, subtract pub_key from accumulator.
field_t<C> add_lambda = (accumulator.y + pub_key.y) / (accumulator.x - pub_key.x);
field_t<C> x_add = add_lambda.madd(add_lambda, -(accumulator.x + pub_key.x));
field_t<C> y_add = add_lambda.madd((pub_key.x - x_add), pub_key.y);
Expand All @@ -266,7 +266,7 @@ point<C> variable_base_mul(const point<C>& pub_key, const point<C>& current_accu

/**
* @brief Make the computations needed to verify a signature (s, e), i.e., compute
* e' = hash(([s]g + [e]pub).x | message)
* e' = hash(([s]g + [e]pub).x | pub.x | pub.y | message)
and return e'.
*
* @details TurboPlonk: ~10850 gates (~4k for variable_base_mul, ~6k for blake2s) for a string of length < 32.
Expand All @@ -276,25 +276,30 @@ std::array<field_t<C>, 2> verify_signature_internal(const byte_array<C>& message
const point<C>& pub_key,
const signature_bits<C>& sig)
{
// Compute [s]g, where s = (s_lo, s_hi) and g = G1::one.
// Compute [s]g, where s = (s_lo, s_hi) and g is the canonical generator.
point<C> R_1 = group<C>::fixed_base_scalar_mul(sig.s_lo, sig.s_hi);
// Compute [e]pub, where e = (e_lo, e_hi)
point<C> R_2 = variable_base_mul(pub_key, sig.e_lo, sig.e_hi);

// check R_1 != R_2
// TODO: This is checking that the x-coordinates are not equal.
// TODO: Theres no comment here stating why this is okay if for example R_1.y = -R_2.y
(R_1.x - R_2.x).assert_is_not_zero("Cannot add points in Schnorr verification.");
// Compute x-coord of R_1 + R_2 = [s]g + [e]pub.
// Compute x-coord of R_3 = R_1 + R_2 = [s]g + [e]pub.
field_t<C> lambda = (R_1.y - R_2.y) / (R_1.x - R_2.x);
field_t<C> x_3 = lambda * lambda - (R_1.x + R_2.x);
field_t<C> R_3_x = lambda * lambda - (R_1.x + R_2.x);

// build input (pedersen(([s]g + [e]pub).x | pub.x | pub.y) | message) to hash function
// pedersen hash ([r].x | pub.x) to make sure the size of `hash_input` is <= 64 bytes for a 32 byte message
byte_array<C> hash_input(stdlib::pedersen_commitment<C>::compress({ x_3, pub_key.x, pub_key.y }));
// Compute e' = hash(R_3.x | pub.x | pub.y | message)
byte_array<C> hash_input;

hash_input.write(static_cast<byte_array<C>>(R_3_x));
hash_input.write(static_cast<byte_array<C>>(pub_key.x));
hash_input.write(static_cast<byte_array<C>>(pub_key.y));
hash_input.write(message);

// compute e' = hash(([s]g + [e]pub).x | message)
byte_array<C> output = blake2s(hash_input);

// TODO(check): why is hi the first 16 bytes
field_t<C> output_hi(output.slice(0, 16));
field_t<C> output_lo(output.slice(16, 16));

Expand All @@ -303,7 +308,7 @@ std::array<field_t<C>, 2> verify_signature_internal(const byte_array<C>& message

/**
* @brief Verify that a signature (s, e) is valid, i.e., compute
* e' = hash(([s]g + [e]pub).x | message)
* e' = hash(([s]g + [e]pub).x | pub.x | pub.y | message)
* and check that
* e' == e is true.
*/
Expand All @@ -317,7 +322,7 @@ void verify_signature(const byte_array<C>& message, const point<C>& pub_key, con

/**
* @brief Attempt to verify a signature (s, e) and return the result, i.e., compute
* e' = hash(([s]g + [e]pub).x | message)
* e' = hash(([s]g + [e]pub).x | pub.x | pub.y | message)
* and return the boolean witness e' == e.
*/
template <typename C>
Expand Down