Code Freeze Fall 2021: Schnorr signatures

tags: project-notes

The code is templated in such a way that the primes and are defined relative to the group G1, which is unfortunate, since is chosen as a fixed, definite value in our specs. An alternative would be to have the templates in schnorr.tcc refer to F_nat and F_em (for 'native' and 'emulated') or something like this. The easier and probably better alternative for now is to just rename our primes in the Yellow Paper as and .

For Aztec's current uses cases, G1 is a cyclic subgroup of an elliptic curve defined over a field (implemented as a class Fq), and Fr (aka field_t) is the a field of size equal to the size of G1, so Fr is the field acting on G1 by scalar multiplication.

Role:

Yellow paper only mentions them here: The Blake2s hash is utilized for computing nullifiers and for generating pseudorandom challenges, when verifying Schnorr signatures and when recursively verifying Plonk proofs.

They are used by the account circuit and the join-split circuit.

Data types

crypto::schnorr::signature is a pair of two 256-bit integers represented as length-32 std::array's of uint32_t's.

crypto::schnorr::signature_b is a pair of the same type.

wnaf_record<C> is a vector of bool_t<C>'s along with a skew.

signature_bits<C> is four field_t's, representing a signature by splitting component into two.

Formulas

Elliptic curve addition.

We restrict in this code to working with curves described by Weierstrass equations of the form defined over a with prime. Consider two non-identity points , . If , then , so the two points are equal or one is the inverse of the other. If , then one has with . In the case of Grumpkin, the equation splits over , there are indeed distinct pairs of points satisfying this relation (for an example of how we handle this elsewhere in the code base, see https://github.com/AztecProtocol/aztec2-internal/issues/437).

Suppose . Then with where if and if .

Algorithms

Let be a generator of .

HMAC

We the HMAC algorithm as Pseudo-Random Function (PRF) to generate a randomly distributed Schnorr signature nonce in a deterministic way. HMAC is the Hash-based Message Authentication Code specification as defined in RFC4231.

The HMAC algorithm: Given a message , and a PRF key , the value is computed as

where:

  • is a hash function modeling a random oracle, whose block size is 64 bytes
  • is a block-sized key derived from .
    • If is larger than the block size, we first hash it using and set
    • Otherwise,
    • In both cases, is right-padded with 0s up to the 64 byte block size.
  • is a 64-byte string, consisting of repeated bytes valued 0x5c
  • is a 64-byte string, consisting of repeated bytes valued 0x36
  • denotes concatenation
  • denotes bitwise exclusive or
  • is a 32-byte string

In order to derive a secret nonce , we need to expand in order to derive a 512 bit integer Modeling as a uniformly sampled integer, taking ensures that the statistical distance between the distribution of and the uniform distribution over is negligible.

Sign

We use signatures with compression as described in Section 19.2.3 of [BS], in the sense that the signature contains the hash, meaning that the signature contains a hash and a field element, rather than a group element and a field element.

The algorithm: Given a message , an account produces the signature

where:

  • .
  • is the signer's secret nonce.
  • , is a commitment to the signer's nonce .
  • is the Fiat-Shamir response.
  • is the affine representation of the signer's public key
  • is a function interpreting a binary string as an integer and applying the modular reduction by .
  • is a collisian-resistant pedersen hash function.
  • is a hash function modeling a random oracle, which is instantiated with BLAKE2s.

The purpose of is to include the public key in the parameter whilst ensuring the input to is no more than 64 bytes.

Verify

Given , purported to be the signature of a messages by an account with respect to a random oracle hash function , compute

  • ;
  • .

The signature is verified if and only if , where the comparison is done bit-wise.

Imprecise rationale: The verification equation is where both sides of the equation are represented as an array of 256 bits. VERIFIER has seen that SIGNER can produce a preimage for a given which is outside of SIGNER's control by chosing a particular value of . The difficulty of this assumption is documented, in the case where is the units group of a finite field, in Schnorr's original paper [Sch] (cf especially pages 10-11).

Variable base multiplication

scalar presented as bit_array

scalar presented as a wnaf_record, provided along with a current_accumulator

Code Paths

verify_signature

  • There is an aborted state reached if and have the same x-coordinate.
  • Normal signature verification path.

variable_base_mul(pub_key, current_accumulator, wnaf)

  • This function is only called inside of variable_base_mul(pub_key, low_bits, high_bits). There is an init predicate given by: "current_accumulator and pub_key have the same x-coordinate". This is intended as a stand-in for the more general check that these two points are equal. This condition distinguishes between two modes in which the function is used in the implementation of the function variable_base_mul(pub_key, low_bits, high_bits): on the second call, the condition init is espected to be false, so that the results of the first call, recorded in current_accumulator, are incorporated in the output.
  • There is branching depending on whether on the parity of the scalar represented by wnaf.

variable_base_mul(pub_key, low_bits, high_bits)

  • There is an aborted state that is reached when either of the field elements is zero.

convert_signature(scontext, signature)

There is no branching here.

convert_message(context, message_string)

This function has not been investigated since I propose it be removed. It is not used or tested.

convert_field_into_wnaf(context, limb)

  • When accumulating a field_t element using the proposed wnaf representaiton, there is branching at each bit position depending on the 32nd digit of the current uint64_t element wnaf_entries[i+1].

Security Notes

Usage of HMAC for deterministic signatures

There are two main reasons why one may want deterministic signatures. In some instances, the entropy provided by the system may be insufficient to guarantee uniform k, and using HMAC with a proper cryptographic hash function should therefore ensure this property. By deriving it from the secret key, it also ensures that k remains private to the signer. Nowadays, and especially with the types of devices we would be creating signatures, we can assume that the system's randomness source is strong enough for creating signatures.

There are different ways of achieving this property, such as RFC 6979, or as defined by the EdDSA specification.

Our approach is closer to RFC 6979, though we do not use rejection sampling and instead generate a 512-bit value and apply modular reduction by . This ensures that the statistical difference between the distribution of k and the uniform distribution over is negligible.
Note that any leakage of the value of k may be catastrophic, especially in ECDSA.

Unfortunately, by using the secret key for signing and as input to HMAC, the original security proof of the signature scheme no longer applies. We would need to derive two independent signing and PRF keys from one 256-bit secret seed.

Signature malleability

Given a valid signature , it is possible to generate another valid signature , where but (take to be congruent to modulo ). In our context, signatures are used within the account and join_split circuits to link the public inputs to the user's spending key. The signatures themselves are private inputs to the circuit and are not revealed. We do not depend on their non-malleability in this context. The solution would be to check that .

Missing component in Pedersen hash

As mentioned, we use the collision-resistant Pedersen hash to compress and when computing the Fiat-Shamir challenge . We are aware that we do not embed the coordinate of and are working on a security proof to ensure this does not render the scheme insecure.

Biased sampling of Fiat-Shamir challenge

When we interpret as a field element by reducing the corresponding integer modulo , the resulting field element is slightly biased in favor of "smaller" field elements, since . Fixing this issue would require a technique similar to the method we use to derive without bias. Unfortunately, this would require many more gates inside the circuit verification algorithm (additional hash compuation and modular reduction of a 512 bit integer).

We are no longer in the random oracle model since the distribution of the challenge is not uniform. We are looking into alternative proofs to guarantee correctness.

Domain separation

We do not use domain separation when generating the Fiat-Shamir challenge with BLAKE2s. Other components using the same hash function as random oracle should be careful that this could not lead to collisions when similar inputs are being processed.

We also note that we do not hash the group generator into the hash function.

References

WNAF representation: https://github.com/bitcoin-core/secp256k1/blob/master/src/ecmult_impl.h, circa line 151

NOTE: the original NAF paper Morain, Olivos, "Speeding up the computations...", 1990 has a sign error in displayed equation (7). This is not present in our variable_base_mul function.

[BS20] Boneh, D., Shoup, V "A Graduate Course in Applied Cryptography" Version 0.5, January 2020.

[Sch] Schnorr, C. "Efficient Identification and Signatures for Smart Cards", 1990.