From 0655cc3c642bc65d5c515695a8e74f7bdda01634 Mon Sep 17 00:00:00 2001 From: Pieter Wuille Date: Tue, 15 Oct 2019 10:34:41 -0700 Subject: [PATCH 1/6] Use is_square/is_positive and introduce algorithm names --- bip-schnorr.mediawiki | 56 ++++++++++++++++++++++++------------------- 1 file changed, 31 insertions(+), 25 deletions(-) diff --git a/bip-schnorr.mediawiki b/bip-schnorr.mediawiki index 2674959f..af279c7f 100644 --- a/bip-schnorr.mediawiki +++ b/bip-schnorr.mediawiki @@ -68,9 +68,9 @@ Using the first option would be slightly more efficient for verification (around '''Implicit Y coordinates''' In order to support efficient verification and batch verification, the Y coordinate of ''P'' and of ''R'' cannot be ambiguous (every valid X coordinate has two possible Y coordinates). We have a choice between several options for symmetry breaking: # Implicitly choosing the Y coordinate that is in the lower half. # Implicitly choosing the Y coordinate that is evenSince ''p'' is odd, negation modulo ''p'' will map even numbers to odd numbers and the other way around. This means that for a valid X coordinate, one of the corresponding Y coordinates will be even, and the other will be odd.. -# Implicitly choosing the Y coordinate that is a quadratic residue (has a square root modulo the field size)A product of two numbers is a quadratic residue when either both or none of the factors are quadratic residues. As ''-1'' is not a quadratic residue, and the two Y coordinates corresponding to a given X coordinate are each other's negation, this means exactly one of the two must be a quadratic residue.. +# Implicitly choosing the Y coordinate that is a quadratic residue (has a square root modulo the field size, or "is square" for short)A product of two numbers is a quadratic residue when either both or none of the factors are quadratic residues. As ''-1'' is not a quadratic residue, and the two Y coordinates corresponding to a given X coordinate are each other's negation, this means exactly one of the two must be a quadratic residue.. -In the case of ''R'' the third option is slower at signing time but a bit faster to verify, as it is possible to directly compute whether the Y coordinate is a quadratic residue when the points are represented in +In the case of ''R'' the third option is slower at signing time but a bit faster to verify, as it is possible to directly compute whether the Y coordinate is square when the points are represented in [https://en.wikibooks.org/wiki/Cryptography/Prime_Curve/Jacobian_Coordinates Jacobian coordinates] (a common optimization to avoid modular inverses for elliptic curve operations). The two other options require a possibly expensive conversion to affine coordinates first. This would even be the case if the sign or oddness were explicitly coded (option 2 in the previous design choice). We therefore choose option 3. @@ -79,7 +79,7 @@ For ''P'' the speed of signing and verification does not significantly differ be It is important not to mix up the 32-byte bip-schnorr public key format and other existing public key formats (e.g. encodings used in Bitcoin's ECDSA). Concretely, a verifier should only accept 32-byte public keys and not, for example, convert a 33-byte public key by throwing away the first byte. Otherwise, two public keys would be valid for a single signature which can result in subtle malleability issues (although this type of malleability already exists in the case of ECDSA signatures). -Implicit Y coordinates are not a reduction in security when expressed as the number of elliptic curve operations an attacker is expected to perform to compute the secret key. An attacker can normalize any given public key to a point whose Y coordinate is a quadratic residue by negating the point if necessary. This is just a subtraction of field elements and not an elliptic curve operationThis can be formalized by a simple reduction that reduces an attack on Schnorr signatures with implicit Y coordinates to an attack to Schnorr signatures with explicit Y coordinates. The reduction works by reencoding public keys and negating the result of the hash function, which is modeled as random oracle, whenever the challenge public key has an explicit Y coordinate that is not a quadratic residue.. +Implicit Y coordinates are not a reduction in security when expressed as the number of elliptic curve operations an attacker is expected to perform to compute the secret key. An attacker can normalize any given public key to a point whose Y coordinate is square by negating the point if necessary. This is just a subtraction of field elements and not an elliptic curve operationThis can be formalized by a simple reduction that reduces an attack on Schnorr signatures with implicit Y coordinates to an attack to Schnorr signatures with explicit Y coordinates. The reduction works by reencoding public keys and negating the result of the hash function, which is modeled as random oracle, whenever the challenge public key has an explicit Y coordinate that is not square.. '''Tagged Hashes''' Cryptographic hash functions are used for multiple purposes in the specification below and in Bitcoin in general. To make sure hashes used in one context can't be reinterpreted in another one, hash functions can be tweaked with a context-dependent tag name, in such a way that collisions across contexts can be assumed to be infeasible. Such collisions obviously can not be ruled out completely, but only for schemes using tagging with a unique name. As for other schemes collisions are at least less likely with tagging than without. @@ -87,7 +87,7 @@ For example, without tagged hashing a bip-schnorr signature could also be valid This proposal suggests to include the tag by prefixing the hashed data with ''SHA256(tag) || SHA256(tag)''. Because this is a 64-byte long context-specific constant and the ''SHA256'' block size is also 64 bytes, optimized implementations are possible (identical to SHA256 itself, but with a modified initial state). Using SHA256 of the tag name itself is reasonably simple and efficient for implementations that don't choose to use the optimization. -'''Final scheme''' As a result, our final scheme ends up using public key ''pk'' which is the X coordinate of a point ''P'' on the curve whose Y coordinate is a quadratic residue and signatures ''(r,s)'' where ''r'' is the X coordinate of a point ''R'' whose Y coordinate is a quadratic residue. The signature satisfies ''sG = R + tagged_hash(r || pk || m)P''. +'''Final scheme''' As a result, our final scheme ends up using public key ''pk'' which is the X coordinate of a point ''P'' on the curve whose Y coordinate is square and signatures ''(r,s)'' where ''r'' is the X coordinate of a point ''R'' whose Y coordinate is square. The signature satisfies ''sG = R + tagged_hash(r || pk || m)P''. === Specification === @@ -100,33 +100,34 @@ The following conventions are used, with constants as defined for [https://www.s ** ''x(P)'' and ''y(P)'' are integers in the range ''0..p-1'' and refer to the X and Y coordinates of a point ''P'' (assuming it is not infinity). ** The constant ''G'' refers to the generator, for which ''x(G) = 0x79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798'' and ''y(G) = 0x483ADA7726A3C4655DA4FBFC0E1108A8FD17B448A68554199C47D08FFB10D4B8''. ** Addition of points refers to the usual [https://en.wikipedia.org/wiki/Elliptic_curve#The_group_law elliptic curve group operation]. -** [https://en.wikipedia.org/wiki/Elliptic_curve_point_multiplication Multiplication of an integer and a point] refers to the repeated application of the group operation. +** [https://en.wikipedia.org/wiki/Elliptic_curve_point_multiplication Multiplication (⋅) of an integer and a point] refers to the repeated application of the group operation. * Functions and operations: ** ''||'' refers to byte array concatenation. ** The function ''x[i:j]'', where ''x'' is a byte array, returns a ''(j - i)''-byte array with a copy of the ''i''-th byte (inclusive) to the ''j''-th byte (exclusive) of ''x''. ** The function ''bytes(x)'', where ''x'' is an integer, returns the 32-byte encoding of ''x'', most significant byte first. ** The function ''bytes(P)'', where ''P'' is a point, returns ''bytes(x(P))'. ** The function ''int(x)'', where ''x'' is a 32-byte array, returns the 256-bit unsigned integer whose most significant byte first encoding is ''x''. -** The function ''lift_x(x)'', where ''x'' is an integer in range ''0..p-1'', returns the point ''P'' for which ''x(P) = x'' and ''y(P)'' is a quadratic residue modulo ''p'', or fails if no such point existsGiven an candidate X coordinate ''x'' in the range ''0..p-1'', there exist either exactly two or exactly zero valid Y coordinates. If no valid Y coordinate exists, then ''x'' is not a valid X coordinate either, i.e., no point ''P'' exists for which ''x(P) = x''. Given a candidate ''x'', the valid Y coordinates are the square roots of ''c = x3 + 7 mod p'' and they can be computed as ''y = ±c(p+1)/4 mod p'' (see [https://en.wikipedia.org/wiki/Quadratic_residue#Prime_or_prime_power_modulus Quadratic residue]) if they exist, which can be checked by squaring and comparing with ''c''. Due to [https://en.wikipedia.org/wiki/Euler%27s_criterion Euler's criterion] it then holds that ''c(p-1)/2 = 1 mod p''. The same criterion applied to ''y'' results in ''y(p-1)/2 mod p = ±c((p+1)/4)((p-1)/2) mod p = ±1 mod p''. Therefore ''y = +c(p+1)/4 mod p'' is a quadratic residue and ''-y mod p'' is not.. The function ''lift_x(x)'' is equivalent to the following pseudocode: +** The function ''is_square(x)'', where ''x'' is an integer, returns whether or not ''x'' is a quadratic residue modulo ''p''. Since ''p'' is prime, it is equivalent to the Legendre symbol ''(x / p) = x(p-1)/2 mod p'' being equal to ''1'' (see [https://en.wikipedia.org/wiki/Euler%27s_criterion Euler's criterion])For points ''P'' on the secp256k1 curve it holds that ''x(p-1)/2 ≠ 0 mod p''.. +** The function ''is_positive(P)'', where ''P'' is a point, is defined as ''not infinite(P) and is_square(y(P))''For points ''P'' on the secp256k1 curve it holds that ''is_positive(P) = not is_positive(-P)''.. +** The function ''lift_x(x)'', where ''x'' is an integer in range ''0..p-1'', returns the point ''P'' for which ''x(P) = x'' and ''is_positive(P)'', or fails if no such point existsGiven an candidate X coordinate ''x'' in the range ''0..p-1'', there exist either exactly two or exactly zero valid Y coordinates. If no valid Y coordinate exists, then ''x'' is not a valid X coordinate either, i.e., no point ''P'' exists for which ''x(P) = x''. Given a candidate ''x'', the valid Y coordinates are the square roots of ''c = x3 + 7 mod p'' and they can be computed as ''y = ±c(p+1)/4 mod p'' (see [https://en.wikipedia.org/wiki/Quadratic_residue#Prime_or_prime_power_modulus Quadratic residue]) if they exist, which can be checked by squaring and comparing with ''c''. Due to [https://en.wikipedia.org/wiki/Euler%27s_criterion Euler's criterion] it then holds that ''c(p-1)/2 = 1 mod p''. The same criterion applied to ''y'' results in ''y(p-1)/2 mod p = ±c((p+1)/4)((p-1)/2) mod p = ±1 mod p''. Therefore ''y = +c(p+1)/4 mod p'' is a quadratic residue and ''-y mod p'' is not.. The function ''lift_x(x)'' is equivalent to the following pseudocode: *** Let ''c = x3 + 7 mod p''. *** Let ''y = c(p+1)/4 mod p''. *** Fail if ''c ≠ y2 mod p''. *** Return the unique point ''P'' such that ''x(P) = x'' and ''y(P) = y'', or fail if no such point exists. ** The function ''point(x)'', where ''x'' is a 32-byte array, returns the point ''P = lift_x(int(x))''. ** The function ''hashtag(x)'' where ''tag'' is a UTF-8 encoded tag name and ''x'' is a byte array returns the 32-byte hash ''SHA256(SHA256(tag) || SHA256(tag) || x)''. -** The function ''jacobi(x)'', where ''x'' is an integer, returns the [https://en.wikipedia.org/wiki/Jacobi_symbol Jacobi symbol] of ''x / p''. Since ''p'' is prime, it is equal to ''x(p-1)/2 mod p'' ([https://en.wikipedia.org/wiki/Euler%27s_criterion Euler's criterion])For points ''P'' on the secp256k1 curve it holds that ''jacobi(y(P)) ≠ 0''.. -** The function ''pubkey(x)'', where ''x'' is a 32-byte array, returns ''bytes(dG)'' where ''d = int(x) mod n''. ==== Public Key Generation ==== Input: * The secret key ''sk'': a 32-byte array, generated uniformly at random -To generate the corresponding public key: -* Fail if ''int(sk) = 0'' or ''int(sk) ≥ n'' -* The public key corresponding to secret key ''sk'' is ''pubkey(sk)''. +The algorithm ''PubKey(sk)'' is defined as: +* Let ''d = int(sk)''. +* Fail if ''d = 0'' or ''d ≥ n''. +* Return ''bytes(d⋅G)''. -Note that the two secret keys ''sk'' and ''bytes(n-int(sk))'' will generate the same public key. +Note that ''PubKey(sk) = PubKey(bytes(n - int(sk))'', so every public key has two corresponding private keys. Alternatively, the public key can be created according to [https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki BIP32] which describes the derivation of 33-byte compressed public keys. In order to translate such public keys into bip-schnorr compatible keys, the first byte must be dropped. @@ -137,19 +138,19 @@ Input: * The secret key ''sk'': a 32-byte array * The message ''m'': a 32-byte array -To sign ''m'' for public key ''pubkey(sk)'': +The algorithm ''Sign(sk,m)'' is defined as: * Let ''d' = int(sk)'' * Fail if ''d' = 0'' or ''d' ≥ n'' * Let ''P = d'G'' -* Let ''d = d' '' if ''jacobi(y(P)) = 1'', otherwise let ''d = n - d' ''. +* Let ''d = d' '' if ''is_positive(P)'', otherwise let ''d = n - d' ''. * Let ''k' = int(hashBIPSchnorrDerive(bytes(d) || m)) mod n''Note that in general, taking the output of a hash function modulo the curve order will produce an unacceptably biased result. However, for the secp256k1 curve, the order is sufficiently close to ''2256'' that this bias is not observable (''1 - n / 2256'' is around ''1.27 * 2-128'').. * Fail if ''k' = 0''. * Let ''R = k'G''. -* Let ''k = k' '' if ''jacobi(y(R)) = 1'', otherwise let ''k = n - k' ''. +* Let ''k = k' '' if ''is_positive(R)'', otherwise let ''k = n - k' ''. * Let ''e = int(hashBIPSchnorr(bytes(R) || bytes(P) || m)) mod n''. -* The signature is ''bytes(R) || bytes((k + ed) mod n)''. +* Return the signature ''bytes(R) || bytes((k + ed) mod n)''. -'''Above deterministic derivation of ''R'' is designed specifically for this signing algorithm and may not be secure when used in other signature schemes.''' +'''Above deterministic derivation of ''R'' is designed specifically for this signing algorithm and may not be secure when used in other signature schemes or for other curves.''' For example, using the same derivation in the MuSig multi-signature scheme leaks the secret key (see the [https://eprint.iacr.org/2018/068 MuSig paper] for details). Note that this is not a ''unique signature'' scheme: while this algorithm will always produce the same signature for a given message and public key, ''k'' (and hence ''R'') may be generated in other ways (such as by a CSPRNG) producing a different, but still valid, signature. @@ -161,14 +162,16 @@ Input: * The message ''m'': a 32-byte array * A signature ''sig'': a 64-byte array -The signature is valid if and only if the algorithm below does not fail. +The algorithm ''Verify(pk,m,sig)'' is defined as: * Let ''P = point(pk)''; fail if ''point(pk)'' fails. * Let ''r = int(sig[0:32])''; fail if ''r ≥ p''. * Let ''s = int(sig[32:64])''; fail if ''s ≥ n''. * Let ''e = int(hashBIPSchnorr(bytes(r) || bytes(P) || m)) mod n''. -* Let ''R = sG - eP''. -* Fail if ''infinite(R)''. -* Fail if ''jacobi(y(R)) ≠ 1'' or ''x(R) ≠ r''. +* Let ''R = s⋅G - e⋅P''. +* Fail if ''not is_positive(R)'' or ''x(R) ≠ r''. +* Return success iff no failure occurred before reaching this point. + +For every valid secret key ''sk'' and message ''m'', ''Verify(PubKey(sk),m,Sign(sk,m))'' will succeed. ==== Batch Verification ==== @@ -178,7 +181,7 @@ Input: * The messages ''m1..u'': ''u'' 32-byte arrays * The signatures ''sig1..u'': ''u'' 64-byte arrays -All provided signatures are valid with overwhelming probability if and only if the algorithm below does not fail. +The algorithm ''BatchVerify(pk1..u,m1..u,sig1..u)'' is defined as: * Generate ''u-1'' random integers ''a2...u'' in the range ''1...n-1''. They are generated deterministically using a [https://en.wikipedia.org/wiki/Cryptographically_secure_pseudorandom_number_generator CSPRNG] seeded by a cryptographic hash of all inputs of the algorithm, i.e. ''seed = seed_hash(pk1..pku || m1..mu || sig1..sigu )''. A safe choice is to instantiate ''seed_hash'' with SHA256 and use [https://tools.ietf.org/html/rfc8439 ChaCha20] with key ''seed'' as a CSPRNG to generate 256-bit integers, skipping integers not in the range ''1...n-1''. * For ''i = 1 .. u'': ** Let ''Pi = point(pki)''; fail if ''point(pki)'' fails. @@ -186,16 +189,19 @@ All provided signatures are valid with overwhelming probability if and only if t ** Let ''si = int(sigi[32:64])''; fail if ''si ≥ n''. ** Let ''ei = int(hashBIPSchnorr(bytes(ri) || bytes(Pi) || mi)) mod n''. ** Let ''Ri = lift_x(ri)''; fail if ''lift_x(ri)'' fails. -* Fail if ''(s1 + a2s2 + ... + ausu)G ≠ R1 + a2R2 + ... + auRu + e1P1 + (a2e2)P2 + ... + (aueu)Pu''. +* Fail if ''(s1 + a2s2 + ... + ausu)⋅G ≠ R1 + a2⋅R2 + ... + au⋅Ru + e1⋅P1 + (a2e2)⋅P2 + ... + (aueu)⋅Pu''. +* Return success iff no failure occurred before reaching this point. + +With overwhelming probability, ''BatchVerify(pk1..u,m1..u,sig1..u) = Verify(pk1,m1,sig1) and Verify(pk2,m2,sig2) and ... and Verify(pku,mu,sigu)''. If all signatures are valid it will always succeed. If one or more signatures are invalid, it will succeed with probability ''2-n''. === Optimizations === Many techniques are known for optimizing elliptic curve implementations. Several of them apply here, but are out of scope for this document. Two are listed below however, as they are relevant to the design decisions: -'''Jacobi symbol''' The function ''jacobi(x)'' is defined as above, but can be computed more efficiently using an [https://en.wikipedia.org/wiki/Jacobi_symbol#Calculating_the_Jacobi_symbol extended GCD algorithm]. +'''Quadratic residue testing''' The function ''is_square(x)'' is defined as above, but can be computed more efficiently using an [https://en.wikipedia.org/wiki/Jacobi_symbol#Calculating_the_Jacobi_symbol extended GCD algorithm]. '''Jacobian coordinates''' Elliptic Curve operations can be implemented more efficiently by using [https://en.wikibooks.org/wiki/Cryptography/Prime_Curve/Jacobian_Coordinates Jacobian coordinates]. Elliptic Curve operations implemented this way avoid many intermediate modular inverses (which are computationally expensive), and the scheme proposed in this document is in fact designed to not need any inversions at all for verification. When operating on a point ''P'' with Jacobian coordinates ''(x,y,z)'' which is not the point at infinity and for which ''x(P)'' is defined as ''x / z2'' and ''y(P)'' is defined as ''y / z3'': -* ''jacobi(y(P))'' can be implemented as ''jacobi(yz mod p)''. +* ''is_positive(P)'' can be implemented as ''is_square(yz mod p)''. * ''x(P) ≠ r'' can be implemented as ''(0 ≤ r < p) and (x ≠ z2r mod p)''. == Applications == From 1442d4dabca9ac9a5323c0c366c6d10fd9f9c38c Mon Sep 17 00:00:00 2001 From: Pieter Wuille Date: Tue, 15 Oct 2019 12:11:17 -0700 Subject: [PATCH 2/6] Formulate claims about BatchVerify more accurately --- bip-schnorr.mediawiki | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bip-schnorr.mediawiki b/bip-schnorr.mediawiki index af279c7f..b7bd541e 100644 --- a/bip-schnorr.mediawiki +++ b/bip-schnorr.mediawiki @@ -192,7 +192,7 @@ The algorithm ''BatchVerify(pk1..u,m1..u,sig1..u1 + a2s2 + ... + ausu)⋅G ≠ R1 + a2⋅R2 + ... + au⋅Ru + e1⋅P1 + (a2e2)⋅P2 + ... + (aueu)⋅Pu''. * Return success iff no failure occurred before reaching this point. -With overwhelming probability, ''BatchVerify(pk1..u,m1..u,sig1..u) = Verify(pk1,m1,sig1) and Verify(pk2,m2,sig2) and ... and Verify(pku,mu,sigu)''. If all signatures are valid it will always succeed. If one or more signatures are invalid, it will succeed with probability ''2-n''. +If all individual signatures are valid (i.e., ''Verify'' would return success for them), ''BatchVerify'' will always return success. If at least one signature is invalid, ''BatchVerify'' will return success with at most a negligable probability. === Optimizations === From 1e00d6ef6a7ecc0c235ed787ccdbbd1d1f84eb91 Mon Sep 17 00:00:00 2001 From: Pieter Wuille Date: Tue, 15 Oct 2019 12:22:31 -0700 Subject: [PATCH 3/6] Apply suggestions from code review Co-Authored-By: Tim Ruffing --- bip-schnorr.mediawiki | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/bip-schnorr.mediawiki b/bip-schnorr.mediawiki index b7bd541e..f63e3ae4 100644 --- a/bip-schnorr.mediawiki +++ b/bip-schnorr.mediawiki @@ -68,9 +68,9 @@ Using the first option would be slightly more efficient for verification (around '''Implicit Y coordinates''' In order to support efficient verification and batch verification, the Y coordinate of ''P'' and of ''R'' cannot be ambiguous (every valid X coordinate has two possible Y coordinates). We have a choice between several options for symmetry breaking: # Implicitly choosing the Y coordinate that is in the lower half. # Implicitly choosing the Y coordinate that is evenSince ''p'' is odd, negation modulo ''p'' will map even numbers to odd numbers and the other way around. This means that for a valid X coordinate, one of the corresponding Y coordinates will be even, and the other will be odd.. -# Implicitly choosing the Y coordinate that is a quadratic residue (has a square root modulo the field size, or "is square" for short)A product of two numbers is a quadratic residue when either both or none of the factors are quadratic residues. As ''-1'' is not a quadratic residue, and the two Y coordinates corresponding to a given X coordinate are each other's negation, this means exactly one of the two must be a quadratic residue.. +# Implicitly choosing the Y coordinate that is a quadratic residue (has a square root modulo the field size, or "is a square" for short)A product of two numbers is a square when either both or none of the factors are squares. As ''-1'' is not a square, and the two Y coordinates corresponding to a given X coordinate are each other's negation, this means exactly one of the two must be a square.. -In the case of ''R'' the third option is slower at signing time but a bit faster to verify, as it is possible to directly compute whether the Y coordinate is square when the points are represented in +In the case of ''R'' the third option is slower at signing time but a bit faster to verify, as it is possible to directly compute whether the Y coordinate is a square when the points are represented in [https://en.wikibooks.org/wiki/Cryptography/Prime_Curve/Jacobian_Coordinates Jacobian coordinates] (a common optimization to avoid modular inverses for elliptic curve operations). The two other options require a possibly expensive conversion to affine coordinates first. This would even be the case if the sign or oddness were explicitly coded (option 2 in the previous design choice). We therefore choose option 3. @@ -79,7 +79,7 @@ For ''P'' the speed of signing and verification does not significantly differ be It is important not to mix up the 32-byte bip-schnorr public key format and other existing public key formats (e.g. encodings used in Bitcoin's ECDSA). Concretely, a verifier should only accept 32-byte public keys and not, for example, convert a 33-byte public key by throwing away the first byte. Otherwise, two public keys would be valid for a single signature which can result in subtle malleability issues (although this type of malleability already exists in the case of ECDSA signatures). -Implicit Y coordinates are not a reduction in security when expressed as the number of elliptic curve operations an attacker is expected to perform to compute the secret key. An attacker can normalize any given public key to a point whose Y coordinate is square by negating the point if necessary. This is just a subtraction of field elements and not an elliptic curve operationThis can be formalized by a simple reduction that reduces an attack on Schnorr signatures with implicit Y coordinates to an attack to Schnorr signatures with explicit Y coordinates. The reduction works by reencoding public keys and negating the result of the hash function, which is modeled as random oracle, whenever the challenge public key has an explicit Y coordinate that is not square.. +Implicit Y coordinates are not a reduction in security when expressed as the number of elliptic curve operations an attacker is expected to perform to compute the secret key. An attacker can normalize any given public key to a point whose Y coordinate is a square by negating the point if necessary. This is just a subtraction of field elements and not an elliptic curve operationThis can be formalized by a simple reduction that reduces an attack on Schnorr signatures with implicit Y coordinates to an attack to Schnorr signatures with explicit Y coordinates. The reduction works by reencoding public keys and negating the result of the hash function, which is modeled as random oracle, whenever the challenge public key has an explicit Y coordinate that is not a square.. '''Tagged Hashes''' Cryptographic hash functions are used for multiple purposes in the specification below and in Bitcoin in general. To make sure hashes used in one context can't be reinterpreted in another one, hash functions can be tweaked with a context-dependent tag name, in such a way that collisions across contexts can be assumed to be infeasible. Such collisions obviously can not be ruled out completely, but only for schemes using tagging with a unique name. As for other schemes collisions are at least less likely with tagging than without. @@ -87,7 +87,7 @@ For example, without tagged hashing a bip-schnorr signature could also be valid This proposal suggests to include the tag by prefixing the hashed data with ''SHA256(tag) || SHA256(tag)''. Because this is a 64-byte long context-specific constant and the ''SHA256'' block size is also 64 bytes, optimized implementations are possible (identical to SHA256 itself, but with a modified initial state). Using SHA256 of the tag name itself is reasonably simple and efficient for implementations that don't choose to use the optimization. -'''Final scheme''' As a result, our final scheme ends up using public key ''pk'' which is the X coordinate of a point ''P'' on the curve whose Y coordinate is square and signatures ''(r,s)'' where ''r'' is the X coordinate of a point ''R'' whose Y coordinate is square. The signature satisfies ''sG = R + tagged_hash(r || pk || m)P''. +'''Final scheme''' As a result, our final scheme ends up using public key ''pk'' which is the X coordinate of a point ''P'' on the curve whose Y coordinate is a square and signatures ''(r,s)'' where ''r'' is the X coordinate of a point ''R'' whose Y coordinate is a square. The signature satisfies ''sG = R + tagged_hash(r || pk || m)P''. === Specification === @@ -138,10 +138,10 @@ Input: * The secret key ''sk'': a 32-byte array * The message ''m'': a 32-byte array -The algorithm ''Sign(sk,m)'' is defined as: +The algorithm ''Sign(sk, m)'' is defined as: * Let ''d' = int(sk)'' * Fail if ''d' = 0'' or ''d' ≥ n'' -* Let ''P = d'G'' + * Let ''P = d'⋅G'' * Let ''d = d' '' if ''is_positive(P)'', otherwise let ''d = n - d' ''. * Let ''k' = int(hashBIPSchnorrDerive(bytes(d) || m)) mod n''Note that in general, taking the output of a hash function modulo the curve order will produce an unacceptably biased result. However, for the secp256k1 curve, the order is sufficiently close to ''2256'' that this bias is not observable (''1 - n / 2256'' is around ''1.27 * 2-128'').. * Fail if ''k' = 0''. @@ -162,7 +162,7 @@ Input: * The message ''m'': a 32-byte array * A signature ''sig'': a 64-byte array -The algorithm ''Verify(pk,m,sig)'' is defined as: +The algorithm ''Verify(pk, m, sig)'' is defined as: * Let ''P = point(pk)''; fail if ''point(pk)'' fails. * Let ''r = int(sig[0:32])''; fail if ''r ≥ p''. * Let ''s = int(sig[32:64])''; fail if ''s ≥ n''. @@ -181,7 +181,7 @@ Input: * The messages ''m1..u'': ''u'' 32-byte arrays * The signatures ''sig1..u'': ''u'' 64-byte arrays -The algorithm ''BatchVerify(pk1..u,m1..u,sig1..u)'' is defined as: +The algorithm ''BatchVerify(pk1..u, m1..u, sig1..u)'' is defined as: * Generate ''u-1'' random integers ''a2...u'' in the range ''1...n-1''. They are generated deterministically using a [https://en.wikipedia.org/wiki/Cryptographically_secure_pseudorandom_number_generator CSPRNG] seeded by a cryptographic hash of all inputs of the algorithm, i.e. ''seed = seed_hash(pk1..pku || m1..mu || sig1..sigu )''. A safe choice is to instantiate ''seed_hash'' with SHA256 and use [https://tools.ietf.org/html/rfc8439 ChaCha20] with key ''seed'' as a CSPRNG to generate 256-bit integers, skipping integers not in the range ''1...n-1''. * For ''i = 1 .. u'': ** Let ''Pi = point(pki)''; fail if ''point(pki)'' fails. @@ -198,7 +198,7 @@ If all individual signatures are valid (i.e., ''Verify'' would return success fo Many techniques are known for optimizing elliptic curve implementations. Several of them apply here, but are out of scope for this document. Two are listed below however, as they are relevant to the design decisions: -'''Quadratic residue testing''' The function ''is_square(x)'' is defined as above, but can be computed more efficiently using an [https://en.wikipedia.org/wiki/Jacobi_symbol#Calculating_the_Jacobi_symbol extended GCD algorithm]. +'''Squareness testing''' The function ''is_square(x)'' is defined as above, but can be computed more efficiently using an [https://en.wikipedia.org/wiki/Jacobi_symbol#Calculating_the_Jacobi_symbol extended GCD algorithm]. '''Jacobian coordinates''' Elliptic Curve operations can be implemented more efficiently by using [https://en.wikibooks.org/wiki/Cryptography/Prime_Curve/Jacobian_Coordinates Jacobian coordinates]. Elliptic Curve operations implemented this way avoid many intermediate modular inverses (which are computationally expensive), and the scheme proposed in this document is in fact designed to not need any inversions at all for verification. When operating on a point ''P'' with Jacobian coordinates ''(x,y,z)'' which is not the point at infinity and for which ''x(P)'' is defined as ''x / z2'' and ''y(P)'' is defined as ''y / z3'': * ''is_positive(P)'' can be implemented as ''is_square(yz mod p)''. From 8c0b29cc94e7b8b13837a5d797d3d96bb581de8f Mon Sep 17 00:00:00 2001 From: Pieter Wuille Date: Tue, 15 Oct 2019 12:24:07 -0700 Subject: [PATCH 4/6] Prefix infinite with is_ --- bip-schnorr.mediawiki | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/bip-schnorr.mediawiki b/bip-schnorr.mediawiki index f63e3ae4..dbc474b4 100644 --- a/bip-schnorr.mediawiki +++ b/bip-schnorr.mediawiki @@ -96,7 +96,7 @@ The following conventions are used, with constants as defined for [https://www.s ** The constant ''p'' refers to the field size, ''0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F''. ** The constant ''n'' refers to the curve order, ''0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141''. * Uppercase variables refer to points on the curve with equation ''y2 = x3 + 7'' over the integers modulo ''p''. -** ''infinite(P)'' returns whether or not ''P'' is the point at infinity. +** ''is_infinite(P)'' returns whether or not ''P'' is the point at infinity. ** ''x(P)'' and ''y(P)'' are integers in the range ''0..p-1'' and refer to the X and Y coordinates of a point ''P'' (assuming it is not infinity). ** The constant ''G'' refers to the generator, for which ''x(G) = 0x79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798'' and ''y(G) = 0x483ADA7726A3C4655DA4FBFC0E1108A8FD17B448A68554199C47D08FFB10D4B8''. ** Addition of points refers to the usual [https://en.wikipedia.org/wiki/Elliptic_curve#The_group_law elliptic curve group operation]. @@ -108,7 +108,7 @@ The following conventions are used, with constants as defined for [https://www.s ** The function ''bytes(P)'', where ''P'' is a point, returns ''bytes(x(P))'. ** The function ''int(x)'', where ''x'' is a 32-byte array, returns the 256-bit unsigned integer whose most significant byte first encoding is ''x''. ** The function ''is_square(x)'', where ''x'' is an integer, returns whether or not ''x'' is a quadratic residue modulo ''p''. Since ''p'' is prime, it is equivalent to the Legendre symbol ''(x / p) = x(p-1)/2 mod p'' being equal to ''1'' (see [https://en.wikipedia.org/wiki/Euler%27s_criterion Euler's criterion])For points ''P'' on the secp256k1 curve it holds that ''x(p-1)/2 ≠ 0 mod p''.. -** The function ''is_positive(P)'', where ''P'' is a point, is defined as ''not infinite(P) and is_square(y(P))''For points ''P'' on the secp256k1 curve it holds that ''is_positive(P) = not is_positive(-P)''.. +** The function ''is_positive(P)'', where ''P'' is a point, is defined as ''not is_infinite(P) and is_square(y(P))''For points ''P'' on the secp256k1 curve it holds that ''is_positive(P) = not is_positive(-P)''.. ** The function ''lift_x(x)'', where ''x'' is an integer in range ''0..p-1'', returns the point ''P'' for which ''x(P) = x'' and ''is_positive(P)'', or fails if no such point existsGiven an candidate X coordinate ''x'' in the range ''0..p-1'', there exist either exactly two or exactly zero valid Y coordinates. If no valid Y coordinate exists, then ''x'' is not a valid X coordinate either, i.e., no point ''P'' exists for which ''x(P) = x''. Given a candidate ''x'', the valid Y coordinates are the square roots of ''c = x3 + 7 mod p'' and they can be computed as ''y = ±c(p+1)/4 mod p'' (see [https://en.wikipedia.org/wiki/Quadratic_residue#Prime_or_prime_power_modulus Quadratic residue]) if they exist, which can be checked by squaring and comparing with ''c''. Due to [https://en.wikipedia.org/wiki/Euler%27s_criterion Euler's criterion] it then holds that ''c(p-1)/2 = 1 mod p''. The same criterion applied to ''y'' results in ''y(p-1)/2 mod p = ±c((p+1)/4)((p-1)/2) mod p = ±1 mod p''. Therefore ''y = +c(p+1)/4 mod p'' is a quadratic residue and ''-y mod p'' is not.. The function ''lift_x(x)'' is equivalent to the following pseudocode: *** Let ''c = x3 + 7 mod p''. *** Let ''y = c(p+1)/4 mod p''. From cdf7dd8cca5178dcdf998d0e931ab9c51b8aacd8 Mon Sep 17 00:00:00 2001 From: Pieter Wuille Date: Tue, 15 Oct 2019 12:26:21 -0700 Subject: [PATCH 5/6] Drop other curve comment --- bip-schnorr.mediawiki | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bip-schnorr.mediawiki b/bip-schnorr.mediawiki index dbc474b4..5dd5305f 100644 --- a/bip-schnorr.mediawiki +++ b/bip-schnorr.mediawiki @@ -150,7 +150,7 @@ The algorithm ''Sign(sk, m)'' is defined as: * Let ''e = int(hashBIPSchnorr(bytes(R) || bytes(P) || m)) mod n''. * Return the signature ''bytes(R) || bytes((k + ed) mod n)''. -'''Above deterministic derivation of ''R'' is designed specifically for this signing algorithm and may not be secure when used in other signature schemes or for other curves.''' +'''Above deterministic derivation of ''R'' is designed specifically for this signing algorithm and may not be secure when used in other signature schemes.''' For example, using the same derivation in the MuSig multi-signature scheme leaks the secret key (see the [https://eprint.iacr.org/2018/068 MuSig paper] for details). Note that this is not a ''unique signature'' scheme: while this algorithm will always produce the same signature for a given message and public key, ''k'' (and hence ''R'') may be generated in other ways (such as by a CSPRNG) producing a different, but still valid, signature. From 348110ec52118c4751f38d1b48bef77be908e1a7 Mon Sep 17 00:00:00 2001 From: Pieter Wuille Date: Tue, 15 Oct 2019 12:29:52 -0700 Subject: [PATCH 6/6] Typo --- bip-schnorr.mediawiki | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bip-schnorr.mediawiki b/bip-schnorr.mediawiki index 5dd5305f..c936ed3b 100644 --- a/bip-schnorr.mediawiki +++ b/bip-schnorr.mediawiki @@ -192,7 +192,7 @@ The algorithm ''BatchVerify(pk1..u, m1..u, sig1..u1 + a2s2 + ... + ausu)⋅G ≠ R1 + a2⋅R2 + ... + au⋅Ru + e1⋅P1 + (a2e2)⋅P2 + ... + (aueu)⋅Pu''. * Return success iff no failure occurred before reaching this point. -If all individual signatures are valid (i.e., ''Verify'' would return success for them), ''BatchVerify'' will always return success. If at least one signature is invalid, ''BatchVerify'' will return success with at most a negligable probability. +If all individual signatures are valid (i.e., ''Verify'' would return success for them), ''BatchVerify'' will always return success. If at least one signature is invalid, ''BatchVerify'' will return success with at most a negligible probability. === Optimizations ===