1
0
mirror of https://github.com/bitcoin/bips.git synced 2025-06-30 12:42:43 +00:00

Clarify that R=infinity is invalid in BIP340

Also rename is_infinity to is_infinite is reference implementation,
to match the wording in BIP340.
This commit is contained in:
Pieter Wuille 2020-09-02 14:20:42 -07:00
parent d8531483f5
commit 3b1fb9600b
3 changed files with 9 additions and 4 deletions

View File

@ -110,7 +110,7 @@ The following conventions are used, with constants as defined for [https://www.s
** The function ''bytes(x)'', where ''x'' is an integer, returns the 32-byte encoding of ''x'', most significant byte first. ** The function ''bytes(x)'', where ''x'' is an integer, returns the 32-byte encoding of ''x'', most significant byte first.
** The function ''bytes(P)'', where ''P'' is a point, returns ''bytes(x(P))''. ** The function ''bytes(P)'', where ''P'' is a point, returns ''bytes(x(P))''.
** The function ''int(x)'', where ''x'' is a 32-byte array, returns the 256-bit unsigned integer whose most significant byte first encoding is ''x''. ** The function ''int(x)'', where ''x'' is a 32-byte array, returns the 256-bit unsigned integer whose most significant byte first encoding is ''x''.
** The function ''has_even_y(P)'', where ''P'' is a point, returns ''y(P) mod 2 = 0''. ** The function ''has_even_y(P)'', where ''P'' is a point for which ''not is_infinite(P)'', returns ''y(P) mod 2 = 0''.
** The function ''lift_x(x)'', where ''x'' is an integer in range ''0..p-1'', returns the point ''P'' for which ''x(P) = x''<ref> ** The function ''lift_x(x)'', where ''x'' is an integer in range ''0..p-1'', returns the point ''P'' for which ''x(P) = x''<ref>
Given a 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''. The valid Y coordinates for a given candidate ''x'' are the square roots of ''c = x<sup>3</sup> + 7 mod p'' and they can be computed as ''y = &plusmn;c<sup>(p+1)/4</sup> 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''.</ref> and ''has_even_y(P)'', or fails if no such point exists. The function ''lift_x(x)'' is equivalent to the following pseudocode: Given a 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''. The valid Y coordinates for a given candidate ''x'' are the square roots of ''c = x<sup>3</sup> + 7 mod p'' and they can be computed as ''y = &plusmn;c<sup>(p+1)/4</sup> 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''.</ref> and ''has_even_y(P)'', or fails if no such point exists. The function ''lift_x(x)'' is equivalent to the following pseudocode:
*** Let ''c = x<sup>3</sup> + 7 mod p''. *** Let ''c = x<sup>3</sup> + 7 mod p''.
@ -184,7 +184,9 @@ The algorithm ''Verify(pk, m, sig)'' is defined as:
* Let ''s = int(sig[32:64])''; fail if ''s &ge; n''. * Let ''s = int(sig[32:64])''; fail if ''s &ge; n''.
* Let ''e = int(hash<sub>BIP0340/challenge</sub>(bytes(r) || bytes(P) || m)) mod n''. * Let ''e = int(hash<sub>BIP0340/challenge</sub>(bytes(r) || bytes(P) || m)) mod n''.
* Let ''R = s⋅G - e⋅P''. * Let ''R = s⋅G - e⋅P''.
* Fail if ''not has_even_y(R)'' or ''x(R) &ne; r''. * Fail if ''is_infinite(R)''.
* Fail if ''not has_even_y(R)''.
* Fail if ''x(R) &ne; r''.
* Return success iff no failure occurred before reaching this point. * Return success iff no failure occurred before reaching this point.
For every valid secret key ''sk'' and message ''m'', ''Verify(PubKey(sk),m,Sign(sk,m))'' will succeed. For every valid secret key ''sk'' and message ''m'', ''Verify(PubKey(sk),m,Sign(sk,m))'' will succeed.

View File

@ -26,13 +26,15 @@ def tagged_hash(tag: str, msg: bytes) -> bytes:
tag_hash = hashlib.sha256(tag.encode()).digest() tag_hash = hashlib.sha256(tag.encode()).digest()
return hashlib.sha256(tag_hash + tag_hash + msg).digest() return hashlib.sha256(tag_hash + tag_hash + msg).digest()
def is_infinity(P: Optional[Point]) -> bool: def is_infinite(P: Optional[Point]) -> bool:
return P is None return P is None
def x(P: Point) -> int: def x(P: Point) -> int:
assert not is_infinite(P)
return P[0] return P[0]
def y(P: Point) -> int: def y(P: Point) -> int:
assert not is_infinite(P)
return P[1] return P[1]
def point_add(P1: Optional[Point], P2: Optional[Point]) -> Optional[Point]: def point_add(P1: Optional[Point], P2: Optional[Point]) -> Optional[Point]:
@ -83,6 +85,7 @@ def hash_sha256(b: bytes) -> bytes:
return hashlib.sha256(b).digest() return hashlib.sha256(b).digest()
def has_even_y(P: Point) -> bool: def has_even_y(P: Point) -> bool:
assert not is_infinite(P)
return y(P) % 2 == 0 return y(P) % 2 == 0
def pubkey_gen(seckey: bytes) -> bytes: def pubkey_gen(seckey: bytes) -> bytes:

View File

@ -6,7 +6,7 @@ def is_square(x):
def has_square_y(P): def has_square_y(P):
"""Determine if P has a square Y coordinate. Used in an earlier draft of BIP340.""" """Determine if P has a square Y coordinate. Used in an earlier draft of BIP340."""
assert not is_infinity(P) assert not is_infinite(P)
return is_square(P[1]) return is_square(P[1])
def vector0(): def vector0():