From 1faf7053885aaa6890e7d59ce90ede9b43ab0421 Mon Sep 17 00:00:00 2001 From: Jonas Nick Date: Sat, 6 Jul 2019 14:11:52 +0000 Subject: [PATCH 1/7] Fix point_from_bytes in bip-schnorr reference implementation --- bip-schnorr/reference.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bip-schnorr/reference.py b/bip-schnorr/reference.py index 48a36a63..d3efb528 100644 --- a/bip-schnorr/reference.py +++ b/bip-schnorr/reference.py @@ -34,7 +34,7 @@ def bytes_from_point(P): return (b'\x03' if P[1] & 1 else b'\x02') + bytes_from_int(P[0]) def point_from_bytes(b): - if b[0] in [b'\x02', b'\x03']: + if b[0:1] in [b'\x02', b'\x03']: odd = b[0] - 0x02 else: return None From ed01c1a7761570db6dd788a3d012d10fe7dbf93a Mon Sep 17 00:00:00 2001 From: Jonas Nick Date: Sat, 6 Jul 2019 16:32:41 +0000 Subject: [PATCH 2/7] Switch to 32 byte public keys in bip-schnorr --- bip-schnorr.mediawiki | 53 +++++---- bip-schnorr/reference.py | 44 +++---- bip-schnorr/test-vectors.csv | 30 +++-- bip-schnorr/test-vectors.py | 215 +++++++++++++++++++++++++++++++++++ 4 files changed, 288 insertions(+), 54 deletions(-) create mode 100644 bip-schnorr/test-vectors.py diff --git a/bip-schnorr.mediawiki b/bip-schnorr.mediawiki index f3df71e8..fa8faa55 100644 --- a/bip-schnorr.mediawiki +++ b/bip-schnorr.mediawiki @@ -35,6 +35,7 @@ propose a new standard, a number of improvements not specific to Schnorr signatu made: * '''Signature encoding''': Instead of [https://en.wikipedia.org/wiki/X.690#DER_encoding DER]-encoding for signatures (which are variable size, and up to 72 bytes), we can use a simple fixed 64-byte format. +* '''Public key encoding''': Instead of ''compressed'' 33-byte encoding of elliptic curve points which are common in Bitcoin, public keys in this proposal are encoded as 32 bytes. * '''Batch verification''': The specific formulation of ECDSA signatures that is standardized cannot be verified more efficiently in batch compared to individually, unless additional witness data is added. Changing the signature scheme offers an opportunity to avoid this. [[File:bip-schnorr/speedup-batch.png|frame|This graph shows the ratio between the time it takes to verify ''n'' signatures individually and to verify a batch of ''n'' signatures. This ratio goes up logarithmically with the number of signatures, or in other words: the total time to verify ''n'' signatures grows with ''O(n / log n)''.]] @@ -57,24 +58,35 @@ We choose the ''R''-option to support batch verification. '''Key prefixing''' When using the verification rule above directly, it is possible for a third party to convert a signature ''(R,s)'' for key ''P'' into a signature ''(R,s + aH(R || m))'' for key ''P + aG'' and the same message, for any integer ''a''. This is not a concern for Bitcoin currently, as all signature hashes indirectly commit to the public keys. However, this may change with proposals such as SIGHASH_NOINPUT ([https://github.com/bitcoin/bips/blob/master/bip-0118.mediawiki BIP 118]), or when the signature scheme is used for other purposes—especially in combination with schemes like [https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki BIP32]'s unhardened derivation. To combat this, we choose ''key prefixed''A limitation of committing to the public key (rather than to a short hash of it, or not at all) is that it removes the ability for public key recovery or verifying signatures against a short public key hash. These constructions are generally incompatible with batch verification. Schnorr signatures; changing the equation to ''sG = R + H(R || P || m)P''. -'''Encoding the sign of R''' As we chose the ''R''-option above, we're required to encode the point ''R'' into the signature. Several possibilities exist: +'''Encoding the sign of P and the sign of R''' There exist several possibilities for encoding the sign of the public key point: +# Encoding the full X and Y coordinate of P, resulting in a 64-byte public key. +# Encoding the full X coordinate, but only whether Y is even or odd (like compressed public keys). This would result in 33-byte public keys. +# Encoding only the X coordinate, resulting in 32-byte public keys. + +As we chose the ''R''-option above, we're required to encode the point ''R'' into the signature. The possibilities are similar to the encoding of ''P'': # Encoding the full X and Y coordinate of R, resulting in a 96-byte signature. # Encoding the full X coordinate, but only whether Y is even or odd (like compressed public keys). This would result in 65-byte signatures. # Encoding only the X coordinate, leaving us with 64-byte signature. -Using the first option would be slightly more efficient for verification (around 5%), but we prioritize compactness, and therefore choose option 3. +Using the first option for both ''P'' and ''R'' would be slightly more efficient for verification (around 5%), but we prioritize compactness, and therefore choose option 3. -'''Implicit Y coordinate''' In order to support batch verification, the Y coordinate of ''R'' cannot be ambiguous (every valid X coordinate has two possible Y coordinates). We have a choice between several options for symmetry breaking: +'''Implicit Y coordinates''' In order to support 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.. -The third option is slower at signing time but a bit faster to verify, as the quadratic residue of the Y coordinate can be computed directly for points represented in +In the case of ''R'' the third option is slower at signing time but a bit faster to verify, as the quadratic residue of the Y coordinate can be computed directly for points 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. -'''Final scheme''' As a result, our final scheme ends up using signatures ''(r,s)'' where ''r'' is the X coordinate of a point ''R'' on the curve whose Y coordinate is a quadratic residue, and which satisfies ''sG = R + H(r || P || m)P''. +For ''P'' the speed of signing and verification is not significantly different between any of the three options because affine coordinates of the point have to computed anyway. We therefore choose the same option as for ''R''. The signing algorithm ensures that the signature is valid under the correct public key by negating the secret key if necessary. + +It is important to not mix up the 32 byte public key format and other existing public key formats. 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. + +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 operation. + +'''Final scheme''' As a result, our final scheme ends up using public keys ''p'' where ''p'' 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 + H(r || p || m)P''. === Specification === @@ -94,26 +106,27 @@ The following convention is used, with constants as defined for secp256k1: ** ''||'' 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(0x02 + (y(P) & 1)) || bytes(x(P))''This matches the ''compressed'' encoding for elliptic curve points used in Bitcoin already, following section 2.3.3 of the [http://www.secg.org/sec1-v2.pdf SEC 1] standard.. +** 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 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: *** Let ''y = c(p+1)/4 mod p''. *** Fail if ''c ≠ y2 mod p''. *** Return ''(r, y)''. -** The function ''point(x)'', where ''x'' is a 33-byte array, returns the point ''P'' for which ''x(P) = int(x[1:33])'' and ''y(P) & 1 = int(x[0:1]) - 0x02)'', or fails if no such point exists. The function ''point(x)'' is equivalent to the following pseudocode: -*** Fail if (''x[0:1] ≠ 0x02'' and ''x[0:1] ≠ 0x03''). -*** Set flag ''odd'' if ''x[0:1] = 0x03''. -*** Let ''(r, y) = lift_x(x)''; fail if ''lift_x(x)'' fails. -*** If (flag ''odd'' is set and ''y'' is an even integer) or (flag ''odd'' is not set and ''y'' is an odd integer): -**** Let ''y = p - y''. -*** Return ''(r, y)''. +** The function ''point(x)'', where ''x'' is a 32-byte array, returns the point ''P = lift_x(int(x))''. ** The function ''hash(x)'', where ''x'' is a byte array, returns the 32-byte SHA256 hash of ''x''. ** The function ''jacobi(x)'', where ''x'' is an integer, returns the [https://en.wikipedia.org/wiki/Jacobi_symbol Jacobi symbol] of ''x / p''. 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''.. +=== Public Key Generation === + +Input: +* The secret key ''d'': an integer in the range ''1..n-1'' chosen uniformly at random. + +The public key corresponding to secret key ''d'' is ''bytes(dG)''. + ==== Verification ==== Input: -* The public key ''pk'': a 33-byte array +* The public key ''pk'': a 32-byte array * The message ''m'': a 32-byte array * A signature ''sig'': a 64-byte array @@ -130,7 +143,7 @@ The signature is valid if and only if the algorithm below does not fail. Input: * The number ''u'' of signatures -* The public keys ''pk1..u'': ''u'' 33-byte arrays +* The public keys ''pk1..u'': ''u'' 32-byte arrays * The messages ''m1..u'': ''u'' 32-byte arrays * The signatures ''sig1..u'': ''u'' 64-byte arrays @@ -147,16 +160,18 @@ All provided signatures are valid with overwhelming probability if and only if t ==== Signing ==== Input: -* The secret key ''d'': an integer in the range ''1..n-1''. +* The secret key ''d' '': an integer in the range ''1..n-1'' chosen uniformly at random. * The message ''m'': a 32-byte array -To sign ''m'' for public key ''dG'': +To sign ''m'' for public key ''bytes(dG)'': +* Let ''P = dG'' +* Let ''d = d' '' if ''jacobi(y(P)) = 1'', otherwise let ''d = n - d' ''. * Let ''k' = int(hash(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 ''e = int(hash(bytes(x(R)) || bytes(dG) || m)) mod n''. -* The signature is ''bytes(x(R)) || bytes((k + ed) mod n)''. +* Let ''e = int(hash(bytes(R) || bytes(P) || m)) mod n''. +* The signature is ''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.''' 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). diff --git a/bip-schnorr/reference.py b/bip-schnorr/reference.py index d3efb528..f89b3c4a 100644 --- a/bip-schnorr/reference.py +++ b/bip-schnorr/reference.py @@ -31,19 +31,14 @@ def bytes_from_int(x): return x.to_bytes(32, byteorder="big") def bytes_from_point(P): - return (b'\x03' if P[1] & 1 else b'\x02') + bytes_from_int(P[0]) + return bytes_from_int(P[0]) def point_from_bytes(b): - if b[0:1] in [b'\x02', b'\x03']: - odd = b[0] - 0x02 - else: - return None - x = int_from_bytes(b[1:33]) + x = int_from_bytes(b) y_sq = (pow(x, 3, p) + 7) % p - y0 = pow(y_sq, (p + 1) // 4, p) - if pow(y0, 2, p) != y_sq: + y = pow(y_sq, (p + 1) // 4, p) + if pow(y, 2, p) != y_sq: return None - y = p - y0 if y0 & 1 != odd else y0 return [x, y] def int_from_bytes(b): @@ -55,24 +50,30 @@ def hash_sha256(b): def jacobi(x): return pow(x, (p - 1) // 2, p) -def schnorr_sign(msg, seckey): +def pubkey_gen(seckey): + P = point_mul(G, seckey) + return bytes_from_point(P) + +def schnorr_sign(msg, seckey0): if len(msg) != 32: raise ValueError('The message must be a 32-byte array.') - if not (1 <= seckey <= n - 1): + if not (1 <= seckey0 <= n - 1): raise ValueError('The secret key must be an integer in the range 1..n-1.') + P = point_mul(G, seckey0) + seckey = seckey0 if (jacobi(P[1]) == 1) else n - seckey0 k0 = int_from_bytes(hash_sha256(bytes_from_int(seckey) + msg)) % n if k0 == 0: raise RuntimeError('Failure. This happens only with negligible probability.') R = point_mul(G, k0) k = n - k0 if (jacobi(R[1]) != 1) else k0 - e = int_from_bytes(hash_sha256(bytes_from_int(R[0]) + bytes_from_point(point_mul(G, seckey)) + msg)) % n - return bytes_from_int(R[0]) + bytes_from_int((k + e * seckey) % n) + e = int_from_bytes(hash_sha256(bytes_from_point(R) + bytes_from_point(P) + msg)) % n + return bytes_from_point(R) + bytes_from_int((k + e * seckey) % n) def schnorr_verify(msg, pubkey, sig): if len(msg) != 32: raise ValueError('The message must be a 32-byte array.') - if len(pubkey) != 33: - raise ValueError('The public key must be a 33-byte array.') + if len(pubkey) != 32: + raise ValueError('The public key must be a 32-byte array.') if len(sig) != 64: raise ValueError('The signature must be a 64-byte array.') P = point_from_bytes(pubkey) @@ -82,7 +83,7 @@ def schnorr_verify(msg, pubkey, sig): s = int_from_bytes(sig[32:64]) if (r >= p or s >= n): return False - e = int_from_bytes(hash_sha256(sig[0:32] + bytes_from_point(P) + msg)) % n + e = int_from_bytes(hash_sha256(sig[0:32] + pubkey + msg)) % n R = point_add(point_mul(G, s), point_mul(P, n - e)) if R is None or jacobi(R[1]) != 1 or R[0] != r: return False @@ -107,20 +108,25 @@ def test_vectors(): print('\nTest vector #%-3i: ' % int(index)) if seckey != '': seckey = int(seckey, 16) + pubkey_actual = pubkey_gen(seckey) + if pubkey != pubkey_actual: + print(' * Failed key generation.') + print(' Expected key:', pubkey.hex().upper()) + print(' Actual key:', pubkey_actual.hex().upper()) sig_actual = schnorr_sign(msg, seckey) if sig == sig_actual: print(' * Passed signing test.') else: print(' * Failed signing test.') - print(' Excepted signature:', sig.hex()) - print(' Actual signature:', sig_actual.hex()) + print(' Expected signature:', sig.hex().upper()) + print(' Actual signature:', sig_actual.hex().upper()) all_passed = False result_actual = schnorr_verify(msg, pubkey, sig) if result == result_actual: print(' * Passed verification test.') else: print(' * Failed verification test.') - print(' Excepted verification result:', result) + print(' Expected verification result:', result) print(' Actual verification result:', result_actual) if comment: print(' Comment:', comment) diff --git a/bip-schnorr/test-vectors.csv b/bip-schnorr/test-vectors.csv index a4218f76..3e17669c 100644 --- a/bip-schnorr/test-vectors.csv +++ b/bip-schnorr/test-vectors.csv @@ -1,17 +1,15 @@ index,secret key,public key,message,signature,verification result,comment -1,0000000000000000000000000000000000000000000000000000000000000001,0279BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798,0000000000000000000000000000000000000000000000000000000000000000,787A848E71043D280C50470E8E1532B2DD5D20EE912A45DBDD2BD1DFBF187EF67031A98831859DC34DFFEEDDA86831842CCD0079E1F92AF177F7F22CC1DCED05,TRUE, -2,B7E151628AED2A6ABF7158809CF4F3C762E7160F38B4DA56A784D9045190CFEF,02DFF1D77F2A671C5F36183726DB2341BE58FEAE1DA2DECED843240F7B502BA659,243F6A8885A308D313198A2E03707344A4093822299F31D0082EFA98EC4E6C89,2A298DACAE57395A15D0795DDBFD1DCB564DA82B0F269BC70A74F8220429BA1D1E51A22CCEC35599B8F266912281F8365FFC2D035A230434A1A64DC59F7013FD,TRUE, -3,C90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74020BBEA63B14E5C7,03FAC2114C2FBB091527EB7C64ECB11F8021CB45E8E7809D3C0938E4B8C0E5F84B,5E2D58D8B3BCDF1ABADEC7829054F90DDA9805AAB56C77333024B9D0A508B75C,00DA9B08172A9B6F0466A2DEFD817F2D7AB437E0D253CB5395A963866B3574BE00880371D01766935B92D2AB4CD5C8A2A5837EC57FED7660773A05F0DE142380,TRUE, -4,,03DEFDEA4CDB677750A420FEE807EACF21EB9898AE79B9768766E4FAA04A2D4A34,4DF3C3F68FCC83B27E9D42C90431A72499F17875C81A599B566C9889B9696703,00000000000000000000003B78CE563F89A0ED9414F5AA28AD0D96D6795F9C6302A8DC32E64E86A333F20EF56EAC9BA30B7246D6D25E22ADB8C6BE1AEB08D49D,TRUE, -5,,031B84C5567B126440995D3ED5AABA0565D71E1834604819FF9C17F5E9D5DD078F,0000000000000000000000000000000000000000000000000000000000000000,52818579ACA59767E3291D91B76B637BEF062083284992F2D95F564CA6CB4E3530B1DA849C8E8304ADC0CFE870660334B3CFC18E825EF1DB34CFAE3DFC5D8187,TRUE,"test fails if jacobi symbol of x(R) instead of y(R) is used" -6,,03FAC2114C2FBB091527EB7C64ECB11F8021CB45E8E7809D3C0938E4B8C0E5F84B,FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF,570DD4CA83D4E6317B8EE6BAE83467A1BF419D0767122DE409394414B05080DCE9EE5F237CBD108EABAE1E37759AE47F8E4203DA3532EB28DB860F33D62D49BD,TRUE,"test fails if msg is reduced modulo p or n" -7,,03EEFDEA4CDB677750A420FEE807EACF21EB9898AE79B9768766E4FAA04A2D4A34,4DF3C3F68FCC83B27E9D42C90431A72499F17875C81A599B566C9889B9696703,00000000000000000000003B78CE563F89A0ED9414F5AA28AD0D96D6795F9C6302A8DC32E64E86A333F20EF56EAC9BA30B7246D6D25E22ADB8C6BE1AEB08D49D,FALSE,"public key not on the curve" -8,,02DFF1D77F2A671C5F36183726DB2341BE58FEAE1DA2DECED843240F7B502BA659,243F6A8885A308D313198A2E03707344A4093822299F31D0082EFA98EC4E6C89,2A298DACAE57395A15D0795DDBFD1DCB564DA82B0F269BC70A74F8220429BA1DFA16AEE06609280A19B67A24E1977E4697712B5FD2943914ECD5F730901B4AB7,FALSE,"incorrect R residuosity" -9,,03FAC2114C2FBB091527EB7C64ECB11F8021CB45E8E7809D3C0938E4B8C0E5F84B,5E2D58D8B3BCDF1ABADEC7829054F90DDA9805AAB56C77333024B9D0A508B75C, 00DA9B08172A9B6F0466A2DEFD817F2D7AB437E0D253CB5395A963866B3574BED092F9D860F1776A1F7412AD8A1EB50DACCC222BC8C0E26B2056DF2F273EFDEC,FALSE,"negated message" -10,,0279BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798,0000000000000000000000000000000000000000000000000000000000000000,787A848E71043D280C50470E8E1532B2DD5D20EE912A45DBDD2BD1DFBF187EF68FCE5677CE7A623CB20011225797CE7A8DE1DC6CCD4F754A47DA6C600E59543C,FALSE,"negated s value" -11,,03DFF1D77F2A671C5F36183726DB2341BE58FEAE1DA2DECED843240F7B502BA659,243F6A8885A308D313198A2E03707344A4093822299F31D0082EFA98EC4E6C89,2A298DACAE57395A15D0795DDBFD1DCB564DA82B0F269BC70A74F8220429BA1D1E51A22CCEC35599B8F266912281F8365FFC2D035A230434A1A64DC59F7013FD,FALSE,"negated public key" -12,,02DFF1D77F2A671C5F36183726DB2341BE58FEAE1DA2DECED843240F7B502BA659,243F6A8885A308D313198A2E03707344A4093822299F31D0082EFA98EC4E6C89,00000000000000000000000000000000000000000000000000000000000000009E9D01AF988B5CEDCE47221BFA9B222721F3FA408915444A4B489021DB55775F,FALSE,"sG - eP is infinite. Test fails in single verification if jacobi(y(inf)) is defined as 1 and x(inf) as 0" -13,,02DFF1D77F2A671C5F36183726DB2341BE58FEAE1DA2DECED843240F7B502BA659,243F6A8885A308D313198A2E03707344A4093822299F31D0082EFA98EC4E6C89,0000000000000000000000000000000000000000000000000000000000000001D37DDF0254351836D84B1BD6A795FD5D523048F298C4214D187FE4892947F728,FALSE,"sG - eP is infinite. Test fails in single verification if jacobi(y(inf)) is defined as 1 and x(inf) as 1" -14,,02DFF1D77F2A671C5F36183726DB2341BE58FEAE1DA2DECED843240F7B502BA659,243F6A8885A308D313198A2E03707344A4093822299F31D0082EFA98EC4E6C89,4A298DACAE57395A15D0795DDBFD1DCB564DA82B0F269BC70A74F8220429BA1D1E51A22CCEC35599B8F266912281F8365FFC2D035A230434A1A64DC59F7013FD,FALSE,"sig[0:32] is not an X coordinate on the curve" -15,,02DFF1D77F2A671C5F36183726DB2341BE58FEAE1DA2DECED843240F7B502BA659,243F6A8885A308D313198A2E03707344A4093822299F31D0082EFA98EC4E6C89,FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC2F1E51A22CCEC35599B8F266912281F8365FFC2D035A230434A1A64DC59F7013FD,FALSE,"sig[0:32] is equal to field size" -16,,02DFF1D77F2A671C5F36183726DB2341BE58FEAE1DA2DECED843240F7B502BA659,243F6A8885A308D313198A2E03707344A4093822299F31D0082EFA98EC4E6C89,2A298DACAE57395A15D0795DDBFD1DCB564DA82B0F269BC70A74F8220429BA1DFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141,FALSE,"sig[32:64] is equal to curve order" +0,0000000000000000000000000000000000000000000000000000000000000001,79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798,0000000000000000000000000000000000000000000000000000000000000000,787A848E71043D280C50470E8E1532B2DD5D20EE912A45DBDD2BD1DFBF187EF6166FCCEE14F021B31AF22A90D0639CC010C2B764C304A8FFF266ABBC01A0A880,TRUE, +1,B7E151628AED2A6ABF7158809CF4F3C762E7160F38B4DA56A784D9045190CFEF,DFF1D77F2A671C5F36183726DB2341BE58FEAE1DA2DECED843240F7B502BA659,243F6A8885A308D313198A2E03707344A4093822299F31D0082EFA98EC4E6C89,3C4D3ADB1F05C3E948216ECB6007D1534D97D35D5589EDB226AD0370C0293C780AEA9BA361509DA2FDF7BC6E5E38926E40B6ACCD24EA9E06B9DA8244A1D0B691,TRUE, +2,C90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74020BBEA63B14E5C7,FAC2114C2FBB091527EB7C64ECB11F8021CB45E8E7809D3C0938E4B8C0E5F84B,5E2D58D8B3BCDF1ABADEC7829054F90DDA9805AAB56C77333024B9D0A508B75C,33380A613013115518CD6030ABC8220B2DED273FD3ABD13DF0882DC6A928E5AFAC72DF3248F8FAC522EF1A819EE5EE5BEA81D92D0E19A6FAB228E5D1D61BF833,TRUE, +3,0B432B2677937381AEF05BB02A66ECD012773062CF3FA2549E44F58ED2401710,25D1DFF95105F5253C4022F628A996AD3A0D95FBF21D468A1B33F8C160D8F517,FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF,7C4E8B0C2575A77A01AF41EE6678EF9C41F97CC4D15FF6D6CA45D73BC6FF7FF4919D246589AF2FA6306F4B7A392857E9C4A17CB21DBE72C38A48C99979EEDCB8,TRUE,test fails if msg is reduced modulo p or n +4,,D69C3509BB99E412E68B0FE8544E72837DFA30746D8BE2AA65975F29D22DC7B9,4DF3C3F68FCC83B27E9D42C90431A72499F17875C81A599B566C9889B9696703,00000000000000000000003B78CE563F89A0ED9414F5AA28AD0D96D6795F9C63F84A709CFFD89AD94FCBD808D41BD26BF62F263AA253527134DDC4A4715BF491,TRUE, +5,,EEFDEA4CDB677750A420FEE807EACF21EB9898AE79B9768766E4FAA04A2D4A34,243F6A8885A308D313198A2E03707344A4093822299F31D0082EFA98EC4E6C89,3C4D3ADB1F05C3E948216ECB6007D1534D97D35D5589EDB226AD0370C0293C780AEA9BA361509DA2FDF7BC6E5E38926E40B6ACCD24EA9E06B9DA8244A1D0B691,FALSE,public key not on the curve +6,,DFF1D77F2A671C5F36183726DB2341BE58FEAE1DA2DECED843240F7B502BA659,243F6A8885A308D313198A2E03707344A4093822299F31D0082EFA98EC4E6C89,F9308A019258C31049344F85F89D5229B531C845836F99B08601F113BCE036F98631F4EF21D5F231A1000ED069E0348ED057EDF4FB1B6672009EDE9DBB2DEE14,FALSE,incorrect R residuosity +7,,DFF1D77F2A671C5F36183726DB2341BE58FEAE1DA2DECED843240F7B502BA659,243F6A8885A308D313198A2E03707344A4093822299F31D0082EFA98EC4E6C89,07636CBE3092D11AFCA4DD1D32E50F039EB5FF5FB2AB72A7DC2BA0F3A4E7ED418C312ED6ABF6A41446D28789DF4AA43A15E166F001D072536ADC6E49C21DC419,FALSE,negated message +8,,DFF1D77F2A671C5F36183726DB2341BE58FEAE1DA2DECED843240F7B502BA659,243F6A8885A308D313198A2E03707344A4093822299F31D0082EFA98EC4E6C89,3C4D3ADB1F05C3E948216ECB6007D1534D97D35D5589EDB226AD0370C0293C78F515645C9EAF625D02084391A1C76D9079F830198A5E023505F7DC482E658AB0,FALSE,negated s value +9,,DFF1D77F2A671C5F36183726DB2341BE58FEAE1DA2DECED843240F7B502BA659,243F6A8885A308D313198A2E03707344A4093822299F31D0082EFA98EC4E6C89,0000000000000000000000000000000000000000000000000000000000000000221A96FEEBA7AD29F11B675DB394948A83A220FD8FE181A7667BDBEE178011B1,FALSE,sG - eP is infinite. Test fails in single verification if jacobi(y(inf)) is defined as 1 and x(inf) as 0 +10,,DFF1D77F2A671C5F36183726DB2341BE58FEAE1DA2DECED843240F7B502BA659,243F6A8885A308D313198A2E03707344A4093822299F31D0082EFA98EC4E6C89,00000000000000000000000000000000000000000000000000000000000000011A39648F31350D8E591106B43B9EB364F8617BCD52DC96A3FA8C4E50347F31DE,FALSE,sG - eP is infinite. Test fails in single verification if jacobi(y(inf)) is defined as 1 and x(inf) as 1 +11,,DFF1D77F2A671C5F36183726DB2341BE58FEAE1DA2DECED843240F7B502BA659,243F6A8885A308D313198A2E03707344A4093822299F31D0082EFA98EC4E6C89,4A298DACAE57395A15D0795DDBFD1DCB564DA82B0F269BC70A74F8220429BA1D0AEA9BA361509DA2FDF7BC6E5E38926E40B6ACCD24EA9E06B9DA8244A1D0B691,FALSE,sig[0:32] is not an X coordinate on the curve +12,,DFF1D77F2A671C5F36183726DB2341BE58FEAE1DA2DECED843240F7B502BA659,243F6A8885A308D313198A2E03707344A4093822299F31D0082EFA98EC4E6C89,FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F0AEA9BA361509DA2FDF7BC6E5E38926E40B6ACCD24EA9E06B9DA8244A1D0B691,FALSE,sig[0:32] is equal to field size +13,,DFF1D77F2A671C5F36183726DB2341BE58FEAE1DA2DECED843240F7B502BA659,243F6A8885A308D313198A2E03707344A4093822299F31D0082EFA98EC4E6C89,3C4D3ADB1F05C3E948216ECB6007D1534D97D35D5589EDB226AD0370C0293C78FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141,FALSE,sig[32:64] is equal to curve order diff --git a/bip-schnorr/test-vectors.py b/bip-schnorr/test-vectors.py new file mode 100644 index 00000000..5088400d --- /dev/null +++ b/bip-schnorr/test-vectors.py @@ -0,0 +1,215 @@ +import sys +from reference import * + +def vector0(): + seckey = 1 + msg = bytes_from_int(0) + sig = schnorr_sign(msg, seckey) + pubkey = pubkey_gen(seckey) + + # The point reconstructed from the public key has an even Y coordinate. + pubkey_point = point_from_bytes(pubkey) + assert(pubkey_point[1] & 1 == 0) + + return (bytes_from_int(seckey), pubkey, msg, sig, "TRUE", None) + +def vector1(): + seckey = 0xB7E151628AED2A6ABF7158809CF4F3C762E7160F38B4DA56A784D9045190CFEF + msg = bytes_from_int(0x243F6A8885A308D313198A2E03707344A4093822299F31D0082EFA98EC4E6C89) + sig = schnorr_sign(msg, seckey) + pubkey = pubkey_gen(seckey) + + # The point reconstructed from the public key has an odd Y coordinate. + pubkey_point = point_from_bytes(pubkey) + assert(pubkey_point[1] & 1 == 1) + + return (bytes_from_int(seckey), pubkey, msg, sig, "TRUE", None) + +def vector2(): + seckey = 0xC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74020BBEA63B14E5C7 + msg = bytes_from_int(0x5E2D58D8B3BCDF1ABADEC7829054F90DDA9805AAB56C77333024B9D0A508B75C) + sig = schnorr_sign(msg, seckey) + + # This signature does not verify vector if the implementer would check the + # jacobi symbol of the X coordinate of R instead of the Y coordinate. + R = point_from_bytes(sig[0:32]) + assert(jacobi(R[0]) != 1) + + return (bytes_from_int(seckey), pubkey_gen(seckey), msg, sig, "TRUE", None) + +def vector3(): + seckey = 0x0B432B2677937381AEF05BB02A66ECD012773062CF3FA2549E44F58ED2401710 + msg = bytes_from_int(0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF) + sig = schnorr_sign(msg, seckey) + return (bytes_from_int(seckey), pubkey_gen(seckey), msg, sig, "TRUE", "test fails if msg is reduced modulo p or n") + +# Signs with a given nonce. Results in an invalid signature if y(kG) is not a +# quadratic residue. +def schnorr_sign_fixed_nonce(msg, seckey0, k): + if len(msg) != 32: + raise ValueError('The message must be a 32-byte array.') + if not (1 <= seckey0 <= n - 1): + raise ValueError('The secret key must be an integer in the range 1..n-1.') + P = point_mul(G, seckey0) + seckey = seckey0 if (jacobi(P[1]) == 1) else n - seckey0 + R = point_mul(G, k) + e = int_from_bytes(hash_sha256(bytes_from_point(R) + bytes_from_point(P) + msg)) % n + return bytes_from_point(R) + bytes_from_int((k + e * seckey) % n) + +# Creates a singature with a small x(R) by using k = 1/2 +def vector4(): + one_half = 0x7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a0 + seckey = 0x763758E5CBEEDEE4F7D3FC86F531C36578933228998226672F13C4F0EBE855EB + msg = bytes_from_int(0x4DF3C3F68FCC83B27E9D42C90431A72499F17875C81A599B566C9889B9696703) + sig = schnorr_sign_fixed_nonce(msg, seckey, one_half) + return (None, pubkey_gen(seckey), msg, sig, "TRUE", None) + +default_seckey = 0xB7E151628AED2A6ABF7158809CF4F3C762E7160F38B4DA56A784D9045190CFEF +default_msg = bytes_from_int(0x243F6A8885A308D313198A2E03707344A4093822299F31D0082EFA98EC4E6C89) + +def vector5(): + seckey = default_seckey + msg = default_msg + sig = schnorr_sign(msg, seckey) + + # Public key is not on the curve + pubkey = bytes_from_int(0xEEFDEA4CDB677750A420FEE807EACF21EB9898AE79B9768766E4FAA04A2D4A34) + assert(point_from_bytes(pubkey) is None) + + return (None, pubkey, msg, sig, "FALSE", "public key not on the curve") + +def vector6(): + seckey = default_seckey + msg = default_msg + k = 3 + sig = schnorr_sign_fixed_nonce(msg, seckey, k) + + # Y coordinate of R is not a quadratic residue + R = point_mul(G, k) + assert(jacobi(R[1]) != 1) + + return (None, pubkey_gen(seckey), msg, sig, "FALSE", "incorrect R residuosity") + +def vector7(): + seckey = default_seckey + msg = int_from_bytes(default_msg) + neg_msg = bytes_from_int(n - msg) + sig = schnorr_sign(neg_msg, seckey) + return (None, pubkey_gen(seckey), bytes_from_int(msg), sig, "FALSE", "negated message") + +def vector8(): + seckey = default_seckey + msg = default_msg + sig = schnorr_sign(msg, seckey) + sig = sig[0:32] + bytes_from_int(n - int_from_bytes(sig[32:64])) + return (None, pubkey_gen(seckey), msg, sig, "FALSE", "negated s value") + +def bytes_from_point_inf0(P): + if P == None: + return bytes_from_int(0) + return bytes_from_int(P[0]) + +def vector9(): + seckey = default_seckey + msg = default_msg + + # Override bytes_from_point in schnorr_sign to allow creating a signature + # with k = 0. + k = 0 + bytes_from_point_tmp = bytes_from_point.__code__ + bytes_from_point.__code__ = bytes_from_point_inf0.__code__ + sig = schnorr_sign_fixed_nonce(msg, seckey, k) + bytes_from_point.__code__ = bytes_from_point_tmp + + return (None, pubkey_gen(seckey), msg, sig, "FALSE", "sG - eP is infinite. Test fails in single verification if jacobi(y(inf)) is defined as 1 and x(inf) as 0") + +def bytes_from_point_inf1(P): + if P == None: + return bytes_from_int(1) + return bytes_from_int(P[0]) + +def vector10(): + seckey = default_seckey + msg = default_msg + + # Override bytes_from_point in schnorr_sign to allow creating a signature + # with k = 0. + k = 0 + bytes_from_point_tmp = bytes_from_point.__code__ + bytes_from_point.__code__ = bytes_from_point_inf1.__code__ + sig = schnorr_sign_fixed_nonce(msg, seckey, k) + bytes_from_point.__code__ = bytes_from_point_tmp + + return (None, pubkey_gen(seckey), msg, sig, "FALSE", "sG - eP is infinite. Test fails in single verification if jacobi(y(inf)) is defined as 1 and x(inf) as 1") + +# It's cryptographically impossible to create a test vector that fails if run +# in an implementation which merely misses the check that sig[0:32] is an X +# coordinate on the curve. This test vector just increases test coverage. +def vector11(): + seckey = default_seckey + msg = default_msg + sig = schnorr_sign(msg, seckey) + + # Replace R's X coordinate with an X coordinate that's not on the curve + x_not_on_curve = bytes_from_int(0x4A298DACAE57395A15D0795DDBFD1DCB564DA82B0F269BC70A74F8220429BA1D) + assert(point_from_bytes(x_not_on_curve) is None) + sig = x_not_on_curve + sig[32:64] + + return (None, pubkey_gen(seckey), msg, sig, "FALSE", "sig[0:32] is not an X coordinate on the curve") + +# It's cryptographically impossible to create a test vector that fails if run +# in an implementation which merely misses the check that sig[0:32] is smaller +# than the field size. This test vector just increases test coverage. +def vector12(): + seckey = default_seckey + msg = default_msg + sig = schnorr_sign(msg, seckey) + + # Replace R's X coordinate with an X coordinate that's equal to field size + sig = bytes_from_int(p) + sig[32:64] + + return (None, pubkey_gen(seckey), msg, sig, "FALSE", "sig[0:32] is equal to field size") + +# It's cryptographically impossible to create a test vector that fails if run +# in an implementation which merely misses the check that sig[32:64] is smaller +# than the curve order. This test vector just increases test coverage. +def vector13(): + seckey = default_seckey + msg = default_msg + sig = schnorr_sign(msg, seckey) + + # Replace s with a number that's equal to the curve order + sig = sig[0:32] + bytes_from_int(n) + + return (None, pubkey_gen(seckey), msg, sig, "FALSE", "sig[32:64] is equal to curve order") + +vectors = [ + vector0(), + vector1(), + vector2(), + vector3(), + vector4(), + vector5(), + vector6(), + vector7(), + vector8(), + vector9(), + vector10(), + vector11(), + vector12(), + vector13(), + ] + +# Converts the byte strings of a test vector into hex strings +def bytes_to_hex(seckey, pubkey, msg, sig, result, comment): + return (seckey.hex().upper() if seckey is not None else None, pubkey.hex().upper(), msg.hex().upper(), sig.hex().upper(), result, comment) + +vectors = list(map(lambda vector: bytes_to_hex(vector[0], vector[1], vector[2], vector[3], vector[4], vector[5]), vectors)) + +def print_csv(vectors): + writer = csv.writer(sys.stdout) + writer.writerow(("index", "secret key", "public key", "message", "signature", "verification result", "comment")) + for (i,v) in enumerate(vectors): + writer.writerow((i,)+v) + +print_csv(vectors) From 5793d3d73561a94230b486cfe0ca88ea346568de Mon Sep 17 00:00:00 2001 From: Jonas Nick Date: Fri, 2 Aug 2019 13:52:29 +0000 Subject: [PATCH 3/7] Use short public keys for taproot output keys --- bip-taproot.mediawiki | 52 +++++++++++++++++++++++------------------ bip-tapscript.mediawiki | 18 +++++++------- 2 files changed, 37 insertions(+), 33 deletions(-) diff --git a/bip-taproot.mediawiki b/bip-taproot.mediawiki index f100e6ee..a5537913 100644 --- a/bip-taproot.mediawiki +++ b/bip-taproot.mediawiki @@ -62,24 +62,23 @@ In the text below, ''hashtag(m)'' is a shorthand for ''SHA256(SHA256( === Script validation rules === -A Taproot output is a SegWit output (native or P2SH-nested, see [https://github.com/bitcoin/bips/blob/master/bip-0141.mediawiki BIP141]) with version number 1, and a 33-byte witness program whose first byte is 0 or 1. -The following rules only apply when such an output is being spent. Any other outputs, including version 1 outputs with lengths other than 33 bytes, or with a first byte different from 0 or 1, remain unencumbered. +A Taproot output is a SegWit output (native or P2SH-nested, see [https://github.com/bitcoin/bips/blob/master/bip-0141.mediawiki BIP141]) with version number 1, and a 32-byte witness program. +The following rules only apply when such an output is being spent. Any other outputs, including version 1 outputs with lengths other than 32 bytes, remain unencumbered. -* Let ''u'' be the 33-byte array containing the witness program (second push in scriptPubKey or P2SH redeemScript). -* Let ''Q = point(byte(2 + u[0]) || u[1:33])'''''Why is the public key directly included in the output?''' While typical earlier constructions store a hash of a script or a public key in the output, this is rather wasteful when a public key is always involved. To guarantee batch verifiability, ''Q'' must be known to every verifier, and thus only revealing its hash as an output would imply adding an additional 33 bytes to the witness. Furthermore, to maintain [https://lists.linuxfoundation.org/pipermail/bitcoin-dev/2016-January/012198.html 128-bit collision security] for outputs, a 256-bit hash would be required anyway, which is comparable in size (and thus in cost for senders) to revealing the public key directly. While the usage of public key hashes is often said to protect against ECDLP breaks or quantum computers, this protection is very weak at best: transactions are not protected while being confirmed, and a very [https://twitter.com/pwuille/status/1108097835365339136 large portion] of the currency's supply is not under such protection regardless. Actual resistance to such systems can be introduced by relying on different cryptographic assumptions, but this proposal focuses on improvements that do not change the security model. Note that using P2SH-wrapped outputs only have 80-bit collision security. This is considered low, and is relevant whenever the output includes data from more than a single party (public keys, hashes, ...). If this is not a valid point on the curve, fail. +* Let ''q'' be the 32-byte array containing the witness program (second push in scriptPubKey or P2SH redeemScript) which represents a public key according to bip-schnorr.'''Why is the public key directly included in the output?''' While typical earlier constructions store a hash of a script or a public key in the output, this is rather wasteful when a public key is always involved. To guarantee batch verifiability, ''q'' must be known to every verifier, and thus only revealing its hash as an output would imply adding an additional 32 bytes to the witness. Furthermore, to maintain [https://lists.linuxfoundation.org/pipermail/bitcoin-dev/2016-January/012198.html 128-bit collision security] for outputs, a 256-bit hash would be required anyway, which is comparable in size (and thus in cost for senders) to revealing the public key directly. While the usage of public key hashes is often said to protect against ECDLP breaks or quantum computers, this protection is very weak at best: transactions are not protected while being confirmed, and a very [https://twitter.com/pwuille/status/1108097835365339136 large portion] of the currency's supply is not under such protection regardless. Actual resistance to such systems can be introduced by relying on different cryptographic assumptions, but this proposal focuses on improvements that do not change the security model. Note that using P2SH-wrapped outputs only have 80-bit collision security. This is considered low, and is relevant whenever the output includes data from more than a single party (public keys, hashes, ...). . * Fail if the witness stack has 0 elements. -* If there are at least two witness elements, and the first byte of the last element is 0x50'''Why is the first byte of the annex 0x50?''' Like the 0xc0-0xc1 constants, 0x50 is chosen as it could not be confused with a valid P2WPKH or P2WSH spending. As the control block's initial byte's lowest bit is used to indicate the public key's Y oddness, each script version needs two subsequence byte values that are both not yet used in P2WPKH or P2WSH spending. To indicate the annex, only an "unpaired" available byte is necessary like 0x50. This choice maximizes the available options for future script versions., this last element is called ''annex'' ''a'''''What is the purpose of the annex?''' The annex is a reserved space for future extensions, such as indicating the validation costs of computationally expensive new opcodes in a way that is recognizable without knowing the outputs being spent. Until the meaning of this field is defined by another softfork, users SHOULD NOT include annex in transactions, or it may lead to PERMANENT FUND LOSS. and is removed from the witness stack. The annex (or the lack of thereof) is always covered by the transaction digest and contributes to transaction weight, but is otherwise ignored during taproot validation. +* If there are at least two witness elements, and the first byte of the last element is 0x50'''Why is the first byte of the annex 0x50?''' Like the 0xc0-0xc1 constants, 0x50 is chosen as it could not be confused with a valid P2WPKH or P2WSH spending. As the control block's initial byte's lowest bit is used to indicate the public key's Y quadratic residuosity, each script version needs two subsequence byte values that are both not yet used in P2WPKH or P2WSH spending. To indicate the annex, only an "unpaired" available byte is necessary like 0x50. This choice maximizes the available options for future script versions., this last element is called ''annex'' ''a'''''What is the purpose of the annex?''' The annex is a reserved space for future extensions, such as indicating the validation costs of computationally expensive new opcodes in a way that is recognizable without knowing the outputs being spent. Until the meaning of this field is defined by another softfork, users SHOULD NOT include annex in transactions, or it may lead to PERMANENT FUND LOSS. and is removed from the witness stack. The annex (or the lack of thereof) is always covered by the transaction digest and contributes to transaction weight, but is otherwise ignored during taproot validation. * If there is exactly one element left in the witness stack, key path spending is used: -** The single witness stack element is interpreted as the signature and must be valid (see the next section) for the public key ''Q'' and taproot transaction digest (to be defined hereinafter) as message. Fail if it is not. Otherwise pass. +** The single witness stack element is interpreted as the signature and must be valid (see the next section) for the public key ''q'' and taproot transaction digest (to be defined hereinafter) as message. Fail if it is not. Otherwise pass. * If there are at least two witness elements left, script path spending is used: ** Call the second-to-last stack element ''s'', the script. ** The last stack element is called the control block ''c'', and must have length ''33 + 32m'', for a value of ''m'' that is an integer between 0 and 32, inclusive. Fail if it does not have such a length. -** Let ''P = point(byte(2 + (c[0] & 1)) || c[1:33])'''''What is the purpose of the first byte of the control block?''' The first byte of the control block has three distinct functions: -* The low bit is used to denote the oddness of the Y coordinate of the ''P'' point. +** Let ''P = point(c[1:33])'' where ''point'' is defined as in bip-schnorr. Fail if this point is not on the curve. +** Let ''l = c[0] & 0xfe'', the leaf version'''What is the purpose of the first byte of the control block?''' The first byte of the control block has three distinct functions: +* The low bit is used to denote whether the ''Q'' point's Y coordinate is a quadratic residue.'''Why is the quadratic residuosity of the output public key's Y coordinate required in a script path spend?''' The ''point'' function always constructs a point with Y coordinate having that property, but because ''Q'' is constructed by adding the taproot tweak to the internal public key ''P'', it cannot easily be guaranteed that ''Q'' in fact has such a Y coordinate. We can not ignore the Y coordinate because it would prevent batch verification. Trying out multiple internal keys until there's such a ''Q'' is possible but undesirable and unnecessary since this information about the Y coordinate only consumes an unused bit. * By keeping the top two bits set to true, it can be guaranteed that scripts can be recognized without knowledge of the UTXO being spent, simplifying analysis. This is because such values cannot occur as first byte of the final stack element in either P2WPKH or P2WSH spends. * The remaining five bits are used for introducing new script versions that are not observable unless actually executed. -. Fail if this point is not on the curve. -** Let ''l = c[0] & 0xfe'', the leaf version. +. ** Let ''k0 = hashTapLeaf(l || compact_size(size of s) || s)''; also call it the ''tapleaf hash''. ** For ''j'' in ''[0,1,...,m-1]'': *** Let ''ej = c[33+32j:65+32j]''. @@ -88,10 +87,11 @@ The following rules only apply when such an output is being spent. Any other out **** If ''kj ≥ ej'': ''kj+1 = hashTapBranch(ej || kj)''. ** Let ''t = hashTapTweak(bytes(P) || km) = hashTapTweak(2 + (c[0] & 1) || c[1:33] || km)''. ** If ''t ≥ 0xFFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFE BAAEDCE6 AF48A03B BFD25E8C D0364141'' (order of secp256k1), fail. +** Let ''Q = point(q) if (c[0] & 1) = 1 and -point(q) otherwise'' ** If ''Q ≠ P + int(t)G'', fail. ** Execute the script, according to the applicable script rules'''What are the applicable script rules in script path spends?''' Bip-tapscript specifies validity rules that apply if the leaf version is ''0xc0'', but future proposals can introduce rules for other leaf versions., using the witness stack elements excluding the script ''s'', the control block ''c'', and the annex ''a'' if present, as initial stack. -''Q'' is referred to as ''taproot output key'' and ''P'' as ''taproot internal key''. +''q'' is referred to as ''taproot output key'' and ''c[1:33]'' as ''taproot internal key''. === Signature validation rules === @@ -137,7 +137,7 @@ As the message for signature verification, transaction digest is ''hashTapS *** Bit-0 is set if the scriptPubKey being spent is P2SH (opposed to "native segwit"). *** Bit-1 is set if an annex is present (the original witness stack has two or more witness elements, and the first byte of the last element is 0x50). *** The other bits are unset. -** scriptPubKey (24 or 36): scriptPubKey of the previous output spent by this input, serialized as script inside CTxOut. The size is 24-byte for P2SH-embedded segwit, or 36-byte for native segwit. +** scriptPubKey (24 or 35): scriptPubKey of the previous output spent by this input, serialized as script inside CTxOut. The size is 24-byte for P2SH-embedded segwit, or 35-byte for native segwit. ** If the SIGHASH_ANYONECANPAY flag is set: *** outpoint (36): the COutPoint of this input (32-byte hash + 4-byte little-endian). *** amount (8): value of the previous output spent by this input. @@ -150,7 +150,7 @@ As the message for signature verification, transaction digest is ''hashTapS ** If the SIGHASH_SINGLE flag is set: *** sha_single_output (32): the SHA256 of the corresponding output in CTxOut format. -The total number of bytes hashed is at most ''209'''''What is the number of bytes hashed for the signature hash?''' The total size of the input to ''hashTapSighash'' (excluding the initial 64-byte hash tag) can be computed using the following formula: ''177 - is_anyonecanpay * 50 - is_none * 32 - is_p2sh_spending * 12 + has_annex * 32''.. +The total number of bytes hashed is at most ''209'''''What is the number of bytes hashed for the signature hash?''' The total size of the input to ''hashTapSighash'' (excluding the initial 64-byte hash tag) can be computed using the following formula: ''176 - is_anyonecanpay * 50 - is_none * 32 - is_p2sh_spending * 11 + has_annex * 32''.. In summary, the semantics of the BIP143 sighash types remain unchanged, except the following: # The way and order of serialization is changed.'''Why is the serialization in the transaction digest changed?''' Hashes that go into the digest and the digest itself are now computed with a single SHA256 invocation instead of double SHA256. There is no expected security improvement by doubling SHA256 because this only protects against length-extension attacks against SHA256 which are not a concern for transaction digests because there is no secret data. Therefore doubling SHA256 is a waste of resources. The digest computation now follows a logical order with transaction level data first, then input data and output data. This allows to efficiently cache the transaction part of the digest across different inputs using the SHA256 midstate. Additionally, digest computation avoids unnecessary hashing as opposed to BIP143 digests in which parts may be set zero and before hashing them. Despite that, collisions are made impossible by committing to the length of the data (implicit in hash_type and spend_type) before the variable length data. @@ -165,7 +165,7 @@ This section discusses how to construct and spend Taproot outputs. It only affec and is not consensus critical in any way. Conceptually, every Taproot output corresponds to a combination of a single public key condition (the internal key), and zero or more general conditions encoded in scripts organized in a tree. -Satisfying any of these conditions is sufficient to spend the output. +Satisfying any of these conditions is sufficient to spend the output. '''Initial steps''' The first step is determining what the internal key and the organization of the rest of the scripts should be. The specifics are likely application dependent, but here are some general guidelines: * When deciding between scripts with conditionals (OP_IF etc.) and splitting them up into multiple scripts (each corresponding to one execution path through the original script), it is generally preferable to pick the latter. @@ -173,7 +173,7 @@ Satisfying any of these conditions is sufficient to spend the output. * If one or more of the spending conditions consist of just a single key (after aggregation), the most likely one should be made the internal key. If no such condition exists, it may be worthwhile adding one that consists of an aggregation of all keys participating in all scripts combined; effectively adding an "everyone agrees" branch. If that is inacceptable, pick as internal key a point with unknown discrete logarithm (TODO). * The remaining scripts should be organized into the leaves of a binary tree. This can be a balanced tree if each of the conditions these scripts correspond to are equally likely. If probabilities for each condition are known, consider constructing the tree as a Huffman tree. -'''Computing the output script''' Once the spending conditions are split into an internal key internal_pubkey and a binary tree whose leaves are (leaf_version, script) tuples, the following Python3 algorithm can be used to compute the output script. In the code below, ser_script prefixes its input with a CCompactSize-encoded length, and public key objects have methods get_bytes to get their compressed encoding (see bip-schnorr) and tweak_add to add a multiple of the secp256k1 generator to it (similar to BIP32's derivation). +'''Computing the output script''' Once the spending conditions are split into an internal key internal_pubkey and a binary tree whose leaves are (leaf_version, script) tuples, the following Python3 algorithm can be used to compute the output script. In the code below, ser_script prefixes its input with a CCompactSize-encoded length. Public key objects hold 32-byte public keys according to bip-schnorr, have a method get_bytes to get the byte array and a method tweak_add which returns a new public key corresponding to the sum of the public key point and a multiple of the secp256k1 generator (similar to BIP32's derivation). The second return value of tweak_add is a boolean indicating the quadratic residuosity of the Y coordinate of the resulting point. import hashlib @@ -202,22 +202,26 @@ def taproot_output_script(internal_pubkey, script_tree): _, h = taproot_tree_helper(script_tree) t = tagged_hash("TapTweak", internal_pubkey.get_bytes() + h) assert int.from_bytes(t, 'big') < SECP256K1_ORDER - output_pubkey = internal_pubkey.tweak_add(t).get_bytes() - return bytes([0x51, 0x21, output_pubkey[0] & 1]) + output_pubkey[1:] + output_pubkey, _ = internal_pubkey.tweak_add(t) + return bytes([0x51, 0x20]) + output_pubkey.get_bytes() The function taproot_output_script returns a byte array with the scriptPubKey. It can be P2SH wrapped if desired (see BIP141). [[File:bip-taproot/tree.png|frame|This diagram shows the hashing structure to obtain the tweak from an internal key ''P'' and a Merkle tree consisting of 5 script leaves. ''A'', ''B'', ''C'' and ''E'' are ''TapLeaf'' hashes similar to ''D'' and ''AB'' is a ''TapBranch'' hash. Note that when ''CDE'' is computed ''E'' is hashed first because ''E'' is less than ''CD''.]] -'''Spending using the internal key''' A Taproot output can be spent with the private key corresponding to the internal_pubkey. To do so, a witness stack consisting of a single element, a bip-schnorr signature on the signature hash as defined above, with the private key tweaked by the same t in the above snippet. See the code below: +'''Spending using the internal key''' A Taproot output can be spent with the private key corresponding to the internal_pubkey. To do so, a witness stack consists of a single element: a bip-schnorr signature on the signature hash as defined above, with the private key tweaked by the same t in the above snippet. In the code below, internal_privkey has a method pubkey_gen that returns a public key according to bip-schnorr and a boolean indicating the quadratic residuosity of the Y coordinate of the underlying point. +See the code below: -def taproot_sign_internal_key(internal_pubkey, script_tree, internal_privkey, hash_type): +def taproot_sign_internal_key(script_tree, internal_privkey, hash_type): + internal_pubkey, is_y_qresidue = internal_privkey.pubkey_gen() + if is_y_qresidue: + internal_privkey = internal_privkey.negate() _, h = taproot_tree_helper(script_tree) t = tagged_hash("TapTweak", internal_pubkey.get_bytes() + h) output_privkey = internal_privkey.tweak_add(t) - sig = output_privkey.sign_schnorr(sighash(hash_type)) + sig = output_privkey.schnorr_sign(sighash(hash_type)) if hash_type != 0: sig += bytes([hash_type]) return [sig] @@ -229,10 +233,12 @@ This function returns the witness stack necessary, and assumes a tweak_add def taproot_sign_script(internal_pubkey, script_tree, script_num, inputs): - info, _ = taproot_tree_helper(script_tree) + info, h = taproot_tree_helper(script_tree) (leaf_version, script), path = info[script_num] - pubkey_bytes = internal_pubkey.get_bytes() - pubkey_data = bytes([(pubkey_bytes[0] & 1) + leaf_version]) + pubkey_bytes[1:] + t = tagged_hash("TapTweak", internal_pubkey.get_bytes() + h) + _, is_y_qresidue = internal_pubkey.tweak_add(t) + output_pubkey_tag = 0 if is_y_qresidue else 1 + pubkey_data = bytes([output_pubkey_tag + leaf_version]) + internal_pubkey.get_bytes() return inputs + [script, pubkey_data + path] diff --git a/bip-tapscript.mediawiki b/bip-tapscript.mediawiki index ce420989..af46afd2 100644 --- a/bip-tapscript.mediawiki +++ b/bip-tapscript.mediawiki @@ -45,7 +45,7 @@ Additionally, the new tapscript OP_SUCCESS opcodes allow introducin The rules below only apply when validating a transaction input for which all of the conditions below are true: * The transaction output is a '''segregated witness spend''' (i.e., either the scriptPubKey or BIP16 redeemScript is a witness program as defined in BIP141). -* It is a '''taproot spend''' as defined in bip-taproot (i.e., the witness version is 1, the witness program is 33 bytes, and the first of those is 0x00 or 0x01). +* It is a '''taproot spend''' as defined in bip-taproot (i.e., the witness version is 1, the witness program is 32 bytes). * It is a '''script path spend''' as defined in bip-taproot (i.e., after removing the optional annex from the witness stack, two or more stack elements remain). * The leaf version is ''0xc0'' (i.e. the first byte of the last witness element after removing the optional annex is ''0xc0'' or ''0xc1'')'''How is the ''0xc0'' constant chosen?''' Following the guidelines in bip-taproot, by choosing a value having the two top bits set, tapscript spends are identifiable even without access to the UTXO being spent., marking it as a '''tapscript spend'''. @@ -71,7 +71,7 @@ The execution rules for tapscript are based on those for P2WSH according to BIP1 * '''Disabled script opcodes''' The following script opcodes are disabled in tapscript: OP_CHECKMULTISIG and OP_CHECKMULTISIGVERIFY. The disabled opcodes behave in the same way as OP_RETURN, by failing and terminating the script immediately when executed, and being ignored when found in unexecuted branch. While being ignored, they are still counted towards the 201 non-push opcodes limit. * '''Consensus-enforced MINIMALIF''' The MINIMALIF rules, which are only a standardness rule in P2WSH, are consensus enforced in tapscript. This means that the input argument to the OP_IF and OP_NOTIF opcodes must be either exactly 0 (the empty vector) or exactly 1 (the one-byte vector with value 1)'''Why make MINIMALIF consensus?''' This makes it considerably easier to write non-malleable scripts that take branch information from the stack.. * '''OP_SUCCESSx opcodes''' As listed above, some opcodes are renamed to OP_SUCCESSx, and make the script unconditionally valid. -* '''Signature opcodes'''. The OP_CHECKSIG and OP_CHECKSIGVERIFY are modified to operate on Schnorr signatures (see bip-schnorr) instead of ECDSA, and a new opcode OP_CHECKSIGADD is added. +* '''Signature opcodes'''. The OP_CHECKSIG and OP_CHECKSIGVERIFY are modified to operate on Schnorr public keys and signatures (see bip-schnorr) instead of ECDSA, and a new opcode OP_CHECKSIGADD is added. ** The opcode 186 (0xba) is named as OP_CHECKSIGADD. '''OP_CHECKSIGADD''' This opcode is added to compensate for the loss of OP_CHECKMULTISIG-like opcodes, which are incompatible with batch verification. OP_CHECKSIGADD is functionally equivalent to OP_ROT OP_SWAP OP_CHECKSIG OP_ADD, but is only counted as one opcode towards the 201 non-push opcodes limit. All CScriptNum-related behaviours of OP_ADD are also applicable to OP_CHECKSIGADD.'''Comparison of CHECKMULTISIG and CHECKSIG''' A CHECKMULTISIG script m ... n CHECKMULTISIG with witness 0 ... can be rewritten as script CHECKSIG ... CHECKSIGADD m NUMEQUAL with witness ... . Every witness element w_i is either a signature corresponding to the public key with the same index or an empty vector. A similar CHECKMULTISIGVERIFY script can be translated to bip-tapscript by replacing NUMEQUAL with NUMEQUALVERIFY. Alternatively, an m-of-n multisig policy can be implemented by splitting the script into several leaves of the Merkle tree, each implementing an m-of-m policy using CHECKSIGVERIFY ... CHECKSIGVERIFY CHECKSIG. If the setting allows the participants to interactively collaborate while signing, multisig policies can be realized with [https://eprint.iacr.org/2018/068 MuSig] for m-of-m and with [http://cacr.uwaterloo.ca/techreports/2001/corr2001-13.ps threshold signatures] using verifiable secret sharing for m-of-n. ===Rules for signature opcodes=== @@ -84,11 +84,9 @@ The following rules apply to OP_CHECKSIG, OP_CHECKSIGVERIFYn is larger than 4 bytes, the script MUST fail and terminate immediately. * If the public key size is zero, the script MUST fail and terminate immediately. -* If the first byte of the public key is 0x04, 0x06, or 0x07, the script MUST fail and terminate immediately regardless of the public key size. -* If the first byte of the public key is 0x02 or 0x03, it is considered to be a public key as described in bip-schnorr: -** If the public key is not 33 bytes, the script MUST fail and terminate immediately. +* If the public key size is 32 bytes, it is considered to be a public key as described in bip-schnorr: ** If the signature is not the empty vector, the signature is validated according to the bip-taproot signing validation rules against the public key and the tapscript transaction digest (to be defined hereinafter) as message. Validation failure MUST cause the script to fail and terminate immediately. -* If the first byte of the public key is not 0x02, 0x03, 0x04, 0x06, or 0x07, the public key is of an ''unknown public key type'''''Unknown public key types''' allow adding new signature validation rules through softforks. A softfork could add actual signature validation which either passes or makes the script fail and terminate immediately. This way, new SIGHASH modes can be added, as well as [https://lists.linuxfoundation.org/pipermail/bitcoin-dev/2018-December/016549.html NOINPUT-tagged public keys] and a public key constant which is replaced by the taproot internal key for signature validation. and no actual signature verification is applied. During script execution of signature opcodes they behave exactly as known public key types except that signature validation is considered to be successful. +* If the public key size is not zero and not 32 bytes, the public key is of an ''unknown public key type'''''Unknown public key types''' allow adding new signature validation rules through softforks. A softfork could add actual signature validation which either passes or makes the script fail and terminate immediately. This way, new SIGHASH modes can be added, as well as [https://lists.linuxfoundation.org/pipermail/bitcoin-dev/2018-December/016549.html NOINPUT-tagged public keys] and a public key constant which is replaced by the taproot internal key for signature validation. and no actual signature verification is applied. During script execution of signature opcodes they behave exactly as known public key types except that signature validation is considered to be successful. * If the script did not fail and terminate before this step, regardless of the public key type: ** If the signature is the empty vector: *** For OP_CHECKSIGVERIFY, the script MUST fail and terminate immediately. @@ -113,14 +111,14 @@ The one-byte spend_type has a different value, specificially at bit As additional pieces of data, added at the end of the input to the ''hashTapSighash'' function: * tapleaf_hash (32): the tapleaf hash as defined in bip-taproot -* key_version (1): a constant value 0x02 representing the current version of public keys in the tapscript signature opcode execution. +* key_version (1): a constant value 0x00 representing the current version of public keys in the tapscript signature opcode execution. * codeseparator_position (2): the opcode position of the last executed OP_CODESEPARATOR before the currently executed signature opcode, with the value in little endian (or 0xffff if none executed). The first opcode in a script has a position of 0. A multi-byte push opcode is counted as one opcode, regardless of the size of data being pushed. -The total number of bytes hashed is at most ''244'''''What is the number of bytes hashed for the signature hash?''' The total size of the input to ''hashTapSighash'' (excluding the initial 64-byte hash tag) can be computed using the following formula: ''212 - is_anyonecanpay * 50 - is_none * 32 - is_p2sh_spending * 12 + has_annex * 32''.. +The total number of bytes hashed is at most ''244'''''What is the number of bytes hashed for the signature hash?''' The total size of the input to ''hashTapSighash'' (excluding the initial 64-byte hash tag) can be computed using the following formula: ''211 - is_anyonecanpay * 50 - is_none * 32 - is_p2sh_spending * 11 + has_annex * 32''.. In summary, the semantics of the BIP143 sighash types remain unchanged, except the following: # The exceptions mentioned in bip-taproot. -# The digest commits to taproot-specific data key_version.'''Why does the transaction digest commit to the key_version?''' This is for future extensions that define unknown public key types, making sure signatures can't be moved from one key type to another. This value is intended to be set equal to the first byte of the public key, after masking out flags like the oddness of the Y coordinate. +# The digest commits to taproot-specific data key_version.'''Why does the transaction digest commit to the key_version?''' This is for future extensions that define unknown public key types, making sure signatures can't be moved from one key type to another. # The digest commits to the executed script through the tapleaf_hash which includes the leaf version and script instead of scriptCode. This implies that this commitment is unaffected by OP_CODESEPARATOR. # The digest commits to the opcode position of the last executed OP_CODESEPARATOR.'''Why does the transaction digest commit to the position of the last executed OP_CODESEPARATOR?''' This allows continuing to use OP_CODESEPARATOR to sign the executed path of the script. Because the codeseparator_position is the last input to the digest, the SHA256 midstate can be efficiently cached for multiple OP_CODESEPARATORs in a single script. In contrast, the BIP143 handling of OP_CODESEPARATOR is to commit to the executed script only from the last executed OP_CODESEPARATOR onwards which requires unnecessary rehashing of the script. It should be noted that the one known OP_CODESEPARATOR use case of saving a second public key push in a script by sharing the first one between two code branches can be most likely expressed even cheaper by moving each branch into a separate taproot leaf. @@ -133,7 +131,7 @@ In addition to the 201 non-push opcodes limit, the use of signature opcodes is s * If 50 * (sigops_passed - 1) is greater than input_witness_weight, the script MUST fail and terminate immediately. This rule limits worst-case validation costs in tapscript similar to the ''sigops limit'' that only applies to legacy and P2WSH scripts'''The tapscript sigop limit''' The signature opcode limit protects against scripts which are slow to verify due to excessively many signature operations. In tapscript the number of signature opcodes does not count towards the BIP141 or legacy sigop limit. The old sigop limit makes transaction selection in block construction unnecessarily difficult because it is a second constraint in addition to weight. Instead, the number of tapscript signature opcodes is limited by witness weight. Additionally, the limit applies to the transaction input instead of the block and only actually executed signature opcodes are counted. Tapscript execution allows one signature opcode per 50 witness weight units plus one free signature opcode. The tapscript signature opcode limit allows to add new signature opcodes like CHECKSIGFROMSTACK to count towards the limit through a soft fork. Even if in the future new opcodes are introduced which change normal script cost there is need to stuff the witness with meaningless data. In that case the taproot annex can be used to add weight to the witness without increasing the actual witness size. -'''Parameter choice of the sigop limit''' Regular witnesses are unaffected by the limit as their weight is composed of public key and (SIGHASH_ALL) signature pairs with ''34 + 65'' weight units each (which includes a 1 weight unit CCompactSize tag). This is also the case if public keys are reused in the script because a signature's weight alone is 65 or 66 weight units. However, the limit increases the fees of abnormal scripts with duplicate signatures (and public keys) by requiring additional weight. The weight per sigop factor 50 corresponds to the ratio of BIP141 block limits: 4 mega weight units divided by 80,000 sigops. The "free" signature opcode permitted by the limit exists to account for the weight of the non-witness parts of the transaction input.. +'''Parameter choice of the sigop limit''' Regular witnesses are unaffected by the limit as their weight is composed of public key and (SIGHASH_ALL) signature pairs with ''33 + 65'' weight units each (which includes a 1 weight unit CCompactSize tag). This is also the case if public keys are reused in the script because a signature's weight alone is 65 or 66 weight units. However, the limit increases the fees of abnormal scripts with duplicate signatures (and public keys) by requiring additional weight. The weight per sigop factor 50 corresponds to the ratio of BIP141 block limits: 4 mega weight units divided by 80,000 sigops. The "free" signature opcode permitted by the limit exists to account for the weight of the non-witness parts of the transaction input.. ==Rationale== From 112d9c150ab16d3e536e5f29b91776f4f68d46a3 Mon Sep 17 00:00:00 2001 From: Jonas Nick Date: Mon, 19 Aug 2019 14:37:55 +0000 Subject: [PATCH 4/7] Address Tim's comments --- bip-schnorr.mediawiki | 27 +++++++++++---------------- bip-taproot.mediawiki | 6 +++--- 2 files changed, 14 insertions(+), 19 deletions(-) diff --git a/bip-schnorr.mediawiki b/bip-schnorr.mediawiki index fa8faa55..0eb79c46 100644 --- a/bip-schnorr.mediawiki +++ b/bip-schnorr.mediawiki @@ -34,8 +34,8 @@ from not being standardized. This document seeks to change that. As we propose a new standard, a number of improvements not specific to Schnorr signatures can be made: -* '''Signature encoding''': Instead of [https://en.wikipedia.org/wiki/X.690#DER_encoding DER]-encoding for signatures (which are variable size, and up to 72 bytes), we can use a simple fixed 64-byte format. -* '''Public key encoding''': Instead of ''compressed'' 33-byte encoding of elliptic curve points which are common in Bitcoin, public keys in this proposal are encoded as 32 bytes. +* '''Signature encoding''': Instead of using [https://en.wikipedia.org/wiki/X.690#DER_encoding DER]-encoding for signatures (which are variable size, and up to 72 bytes), we can use a simple fixed 64-byte format. +* '''Public key encoding''': Instead of using ''compressed'' 33-byte encodings of elliptic curve points which are common in Bitcoin today, public keys in this proposal are encoded as 32 bytes. * '''Batch verification''': The specific formulation of ECDSA signatures that is standardized cannot be verified more efficiently in batch compared to individually, unless additional witness data is added. Changing the signature scheme offers an opportunity to avoid this. [[File:bip-schnorr/speedup-batch.png|frame|This graph shows the ratio between the time it takes to verify ''n'' signatures individually and to verify a batch of ''n'' signatures. This ratio goes up logarithmically with the number of signatures, or in other words: the total time to verify ''n'' signatures grows with ''O(n / log n)''.]] @@ -58,19 +58,14 @@ We choose the ''R''-option to support batch verification. '''Key prefixing''' When using the verification rule above directly, it is possible for a third party to convert a signature ''(R,s)'' for key ''P'' into a signature ''(R,s + aH(R || m))'' for key ''P + aG'' and the same message, for any integer ''a''. This is not a concern for Bitcoin currently, as all signature hashes indirectly commit to the public keys. However, this may change with proposals such as SIGHASH_NOINPUT ([https://github.com/bitcoin/bips/blob/master/bip-0118.mediawiki BIP 118]), or when the signature scheme is used for other purposes—especially in combination with schemes like [https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki BIP32]'s unhardened derivation. To combat this, we choose ''key prefixed''A limitation of committing to the public key (rather than to a short hash of it, or not at all) is that it removes the ability for public key recovery or verifying signatures against a short public key hash. These constructions are generally incompatible with batch verification. Schnorr signatures; changing the equation to ''sG = R + H(R || P || m)P''. -'''Encoding the sign of P and the sign of R''' There exist several possibilities for encoding the sign of the public key point: -# Encoding the full X and Y coordinate of P, resulting in a 64-byte public key. -# Encoding the full X coordinate, but only whether Y is even or odd (like compressed public keys). This would result in 33-byte public keys. -# Encoding only the X coordinate, resulting in 32-byte public keys. +'''Encoding R and public key point P''' There exist several possibilities for encoding elliptic curve points: +# Encoding the full X and Y coordinates of ''P'' and ''R'', resulting in a 64-byte public key and a 96-byte signature. +# Encoding the full X coordinate and one bit of the Y coordinate to determine one of the two possible Y coordinates. This would result in 33-byte public keys and 65-byte signatures. +# Encoding only the X coordinate, resulting in 32-byte public keys and 64-byte signatures. -As we chose the ''R''-option above, we're required to encode the point ''R'' into the signature. The possibilities are similar to the encoding of ''P'': -# Encoding the full X and Y coordinate of R, resulting in a 96-byte signature. -# Encoding the full X coordinate, but only whether Y is even or odd (like compressed public keys). This would result in 65-byte signatures. -# Encoding only the X coordinate, leaving us with 64-byte signature. +Using the first option would be slightly more efficient for verification (around 10%), but we prioritize compactness, and therefore choose option 3. -Using the first option for both ''P'' and ''R'' would be slightly more efficient for verification (around 5%), but we prioritize compactness, and therefore choose option 3. - -'''Implicit Y coordinates''' In order to support 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: +'''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.. @@ -80,13 +75,13 @@ In the case of ''R'' the third option is slower at signing time but a bit faster 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. -For ''P'' the speed of signing and verification is not significantly different between any of the three options because affine coordinates of the point have to computed anyway. We therefore choose the same option as for ''R''. The signing algorithm ensures that the signature is valid under the correct public key by negating the secret key if necessary. +For ''P'' the speed of signing and verification does not significantly differ between any of the three options because affine coordinates of the point have to computed anyway. We therefore choose the same option as for ''R''. The signing algorithm ensures that the signature is valid under the correct public key by negating the secret key if necessary. -It is important to not mix up the 32 byte public key format and other existing public key formats. 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. +It is important to not 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 operation. -'''Final scheme''' As a result, our final scheme ends up using public keys ''p'' where ''p'' 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 + H(r || p || 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 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 + H(r || p || m)P''. === Specification === diff --git a/bip-taproot.mediawiki b/bip-taproot.mediawiki index a5537913..5f8537cb 100644 --- a/bip-taproot.mediawiki +++ b/bip-taproot.mediawiki @@ -65,7 +65,7 @@ In the text below, ''hashtag(m)'' is a shorthand for ''SHA256(SHA256( A Taproot output is a SegWit output (native or P2SH-nested, see [https://github.com/bitcoin/bips/blob/master/bip-0141.mediawiki BIP141]) with version number 1, and a 32-byte witness program. The following rules only apply when such an output is being spent. Any other outputs, including version 1 outputs with lengths other than 32 bytes, remain unencumbered. -* Let ''q'' be the 32-byte array containing the witness program (second push in scriptPubKey or P2SH redeemScript) which represents a public key according to bip-schnorr.'''Why is the public key directly included in the output?''' While typical earlier constructions store a hash of a script or a public key in the output, this is rather wasteful when a public key is always involved. To guarantee batch verifiability, ''q'' must be known to every verifier, and thus only revealing its hash as an output would imply adding an additional 32 bytes to the witness. Furthermore, to maintain [https://lists.linuxfoundation.org/pipermail/bitcoin-dev/2016-January/012198.html 128-bit collision security] for outputs, a 256-bit hash would be required anyway, which is comparable in size (and thus in cost for senders) to revealing the public key directly. While the usage of public key hashes is often said to protect against ECDLP breaks or quantum computers, this protection is very weak at best: transactions are not protected while being confirmed, and a very [https://twitter.com/pwuille/status/1108097835365339136 large portion] of the currency's supply is not under such protection regardless. Actual resistance to such systems can be introduced by relying on different cryptographic assumptions, but this proposal focuses on improvements that do not change the security model. Note that using P2SH-wrapped outputs only have 80-bit collision security. This is considered low, and is relevant whenever the output includes data from more than a single party (public keys, hashes, ...). . +* Let ''q'' be the 32-byte array containing the witness program (second push in scriptPubKey or P2SH redeemScript) which represents a public key according to bip-schnorr '''Why is the public key directly included in the output?''' While typical earlier constructions store a hash of a script or a public key in the output, this is rather wasteful when a public key is always involved. To guarantee batch verifiability, ''q'' must be known to every verifier, and thus only revealing its hash as an output would imply adding an additional 32 bytes to the witness. Furthermore, to maintain [https://lists.linuxfoundation.org/pipermail/bitcoin-dev/2016-January/012198.html 128-bit collision security] for outputs, a 256-bit hash would be required anyway, which is comparable in size (and thus in cost for senders) to revealing the public key directly. While the usage of public key hashes is often said to protect against ECDLP breaks or quantum computers, this protection is very weak at best: transactions are not protected while being confirmed, and a very [https://twitter.com/pwuille/status/1108097835365339136 large portion] of the currency's supply is not under such protection regardless. Actual resistance to such systems can be introduced by relying on different cryptographic assumptions, but this proposal focuses on improvements that do not change the security model. Note that using P2SH-wrapped outputs only have 80-bit collision security. This is considered low, and is relevant whenever the output includes data from more than a single party (public keys, hashes, ...). . * Fail if the witness stack has 0 elements. * If there are at least two witness elements, and the first byte of the last element is 0x50'''Why is the first byte of the annex 0x50?''' Like the 0xc0-0xc1 constants, 0x50 is chosen as it could not be confused with a valid P2WPKH or P2WSH spending. As the control block's initial byte's lowest bit is used to indicate the public key's Y quadratic residuosity, each script version needs two subsequence byte values that are both not yet used in P2WPKH or P2WSH spending. To indicate the annex, only an "unpaired" available byte is necessary like 0x50. This choice maximizes the available options for future script versions., this last element is called ''annex'' ''a'''''What is the purpose of the annex?''' The annex is a reserved space for future extensions, such as indicating the validation costs of computationally expensive new opcodes in a way that is recognizable without knowing the outputs being spent. Until the meaning of this field is defined by another softfork, users SHOULD NOT include annex in transactions, or it may lead to PERMANENT FUND LOSS. and is removed from the witness stack. The annex (or the lack of thereof) is always covered by the transaction digest and contributes to transaction weight, but is otherwise ignored during taproot validation. * If there is exactly one element left in the witness stack, key path spending is used: @@ -87,7 +87,7 @@ The following rules only apply when such an output is being spent. Any other out **** If ''kj ≥ ej'': ''kj+1 = hashTapBranch(ej || kj)''. ** Let ''t = hashTapTweak(bytes(P) || km) = hashTapTweak(2 + (c[0] & 1) || c[1:33] || km)''. ** If ''t ≥ 0xFFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFE BAAEDCE6 AF48A03B BFD25E8C D0364141'' (order of secp256k1), fail. -** Let ''Q = point(q) if (c[0] & 1) = 1 and -point(q) otherwise'' +** Let ''Q = point(q) if (c[0] & 1) = 1 and -point(q) otherwise''. Fail if this point is not on the curve. ** If ''Q ≠ P + int(t)G'', fail. ** Execute the script, according to the applicable script rules'''What are the applicable script rules in script path spends?''' Bip-tapscript specifies validity rules that apply if the leaf version is ''0xc0'', but future proposals can introduce rules for other leaf versions., using the witness stack elements excluding the script ''s'', the control block ''c'', and the annex ''a'' if present, as initial stack. @@ -210,7 +210,7 @@ The function taproot_output_script returns a byte array with the sc [[File:bip-taproot/tree.png|frame|This diagram shows the hashing structure to obtain the tweak from an internal key ''P'' and a Merkle tree consisting of 5 script leaves. ''A'', ''B'', ''C'' and ''E'' are ''TapLeaf'' hashes similar to ''D'' and ''AB'' is a ''TapBranch'' hash. Note that when ''CDE'' is computed ''E'' is hashed first because ''E'' is less than ''CD''.]] -'''Spending using the internal key''' A Taproot output can be spent with the private key corresponding to the internal_pubkey. To do so, a witness stack consists of a single element: a bip-schnorr signature on the signature hash as defined above, with the private key tweaked by the same t in the above snippet. In the code below, internal_privkey has a method pubkey_gen that returns a public key according to bip-schnorr and a boolean indicating the quadratic residuosity of the Y coordinate of the underlying point. +'''Spending using the internal key''' A Taproot output can be spent with the private key corresponding to the internal_pubkey. To do so, a witness stack consists of a single element: a bip-schnorr signature on the signature hash as defined above, with the private key tweaked by the same t as in the above snippet. In the code below, internal_privkey has a method pubkey_gen that returns a public key according to bip-schnorr and a boolean indicating the quadratic residuosity of the Y coordinate of the underlying point. See the code below: From 30fdc875993ccaaa7e15f310b79eda79e2f40a7e Mon Sep 17 00:00:00 2001 From: Jonas Nick Date: Tue, 20 Aug 2019 10:53:51 +0000 Subject: [PATCH 5/7] Update bip-schnorr.mediawiki Co-Authored-By: Tim Ruffing --- bip-schnorr.mediawiki | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bip-schnorr.mediawiki b/bip-schnorr.mediawiki index 0eb79c46..e3eb1875 100644 --- a/bip-schnorr.mediawiki +++ b/bip-schnorr.mediawiki @@ -77,7 +77,7 @@ expensive conversion to affine coordinates first. This would even be the case if For ''P'' the speed of signing and verification does not significantly differ between any of the three options because affine coordinates of the point have to computed anyway. We therefore choose the same option as for ''R''. The signing algorithm ensures that the signature is valid under the correct public key by negating the secret key if necessary. -It is important to not 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). +It is important to not 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 operation. From ae962289131f593f12a77fcae6d90971853c9d25 Mon Sep 17 00:00:00 2001 From: Jonas Nick Date: Tue, 20 Aug 2019 10:53:58 +0000 Subject: [PATCH 6/7] Update bip-schnorr/test-vectors.py Co-Authored-By: Tim Ruffing --- bip-schnorr/test-vectors.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bip-schnorr/test-vectors.py b/bip-schnorr/test-vectors.py index 5088400d..45c8b1ca 100644 --- a/bip-schnorr/test-vectors.py +++ b/bip-schnorr/test-vectors.py @@ -30,7 +30,7 @@ def vector2(): msg = bytes_from_int(0x5E2D58D8B3BCDF1ABADEC7829054F90DDA9805AAB56C77333024B9D0A508B75C) sig = schnorr_sign(msg, seckey) - # This signature does not verify vector if the implementer would check the + # This singature vector would not verify if the implementer checked the # jacobi symbol of the X coordinate of R instead of the Y coordinate. R = point_from_bytes(sig[0:32]) assert(jacobi(R[0]) != 1) From 0d28b3c37bbb66543900760634fe6e50718a186a Mon Sep 17 00:00:00 2001 From: Jonas Nick Date: Wed, 21 Aug 2019 11:40:42 +0000 Subject: [PATCH 7/7] Address sipa's feedback --- bip-schnorr.mediawiki | 7 +++++-- bip-taproot.mediawiki | 2 +- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/bip-schnorr.mediawiki b/bip-schnorr.mediawiki index e3eb1875..573a6782 100644 --- a/bip-schnorr.mediawiki +++ b/bip-schnorr.mediawiki @@ -75,7 +75,7 @@ In the case of ''R'' the third option is slower at signing time but a bit faster 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. -For ''P'' the speed of signing and verification does not significantly differ between any of the three options because affine coordinates of the point have to computed anyway. We therefore choose the same option as for ''R''. The signing algorithm ensures that the signature is valid under the correct public key by negating the secret key if necessary. +For ''P'' the speed of signing and verification does not significantly differ between any of the three options because affine coordinates of the point have to be computed anyway. For consistency resons we choose the same option as for ''R''. The signing algorithm ensures that the signature is valid under the correct public key by negating the secret key if necessary. It is important to not 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). @@ -118,6 +118,9 @@ Input: The public key corresponding to secret key ''d'' is ''bytes(dG)''. +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. + ==== Verification ==== Input: @@ -155,7 +158,7 @@ All provided signatures are valid with overwhelming probability if and only if t ==== Signing ==== Input: -* The secret key ''d' '': an integer in the range ''1..n-1'' chosen uniformly at random. +* The secret key ''d' '': an integer in the range ''1..n-1'' * The message ''m'': a 32-byte array To sign ''m'' for public key ''bytes(dG)'': diff --git a/bip-taproot.mediawiki b/bip-taproot.mediawiki index 5f8537cb..d9a4cbcd 100644 --- a/bip-taproot.mediawiki +++ b/bip-taproot.mediawiki @@ -85,7 +85,7 @@ The following rules only apply when such an output is being spent. Any other out *** Let ''kj+1 depend on whether ''kj < ej'' (lexicographically)'''Why are child elements sorted before hashing in the Merkle tree?''' By doing so, it is not necessary to reveal the left/right directions along with the hashes in revealed Merkle branches. This is possible because we do not actually care about the position of specific scripts in the tree; only that they are actually committed to.: **** If ''kj < ej'': ''kj+1 = hashTapBranch(kj || ej)'''''Why not use a more efficient hash construction for inner Merkle nodes?''' The chosen construction does require two invocations of the SHA256 compression functions, one of which can be avoided in theory (see BIP98). However, it seems preferable to stick to constructions that can be implemented using standard cryptographic primitives, both for implementation simplicity and analyzability. If necessary, a significant part of the second compression function can be optimized out by [https://github.com/bitcoin/bitcoin/pull/13191 specialization] for 64-byte inputs.. **** If ''kj ≥ ej'': ''kj+1 = hashTapBranch(ej || kj)''. -** Let ''t = hashTapTweak(bytes(P) || km) = hashTapTweak(2 + (c[0] & 1) || c[1:33] || km)''. +** Let ''t = hashTapTweak(bytes(P) || km) = hashTapTweak(c[1:33] || km)''. ** If ''t ≥ 0xFFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFE BAAEDCE6 AF48A03B BFD25E8C D0364141'' (order of secp256k1), fail. ** Let ''Q = point(q) if (c[0] & 1) = 1 and -point(q) otherwise''. Fail if this point is not on the curve. ** If ''Q ≠ P + int(t)G'', fail.