From 90e2a57614f0c3fff4102bc80ffa89949b2b2960 Mon Sep 17 00:00:00 2001 From: vbuterin Date: Mon, 28 Jan 2019 10:28:05 -0600 Subject: [PATCH 1/3] Modular squareroot clarification --- specs/bls_signature.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/specs/bls_signature.md b/specs/bls_signature.md index 4dd479a6a..034de479b 100644 --- a/specs/bls_signature.md +++ b/specs/bls_signature.md @@ -86,13 +86,15 @@ def hash_to_G2(message: bytes32, domain: uint64) -> [uint384]: ### `modular_squareroot` -`modular_squareroot(x)` returns a solution `y` to `y**2 % q == x`, and `None` if none exists. If there are two solutions the one with higher imaginary component is favored; if both solutions have equal imaginary component the one with higher real component is favored. +`modular_squareroot(x)` returns a solution `y` to `y**2 % q == x`, and `None` if none exists. If there are two solutions the one with higher imaginary component is favored; if both solutions have equal imaginary component the one with higher real component is favored (note that this is equivalent to saying that the single solution with either imaginary component > p/2 or imaginary component zero and real component > p/2 is favored). + +The following is a sample implementation; implementers are free to implement modular square roots as they wish. Note that `x2 = -x1` is an _additive modular inverse_ so real and imaginary coefficients remain in `[0 .. q-1]` ```python Fq2_order = q ** 2 - 1 eighth_roots_of_unity = [Fq2([1,1]) ** ((Fq2_order * k) // 8) for k in range(8)] -def modular_squareroot(value: int) -> int: +def modular_squareroot(value: Fq2) -> Fq2: candidate_squareroot = value ** ((Fq2_order + 8) // 16) check = candidate_squareroot ** 2 / value if check in eighth_roots_of_unity[::2]: From c6ca68db00a40acd205dabcb08038eb7a2dd5c0d Mon Sep 17 00:00:00 2001 From: vbuterin Date: Tue, 29 Jan 2019 07:52:42 -0600 Subject: [PATCH 2/3] Clarify further "choose the greater" mechanism --- specs/bls_signature.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/specs/bls_signature.md b/specs/bls_signature.md index 034de479b..44007d82e 100644 --- a/specs/bls_signature.md +++ b/specs/bls_signature.md @@ -88,7 +88,7 @@ def hash_to_G2(message: bytes32, domain: uint64) -> [uint384]: `modular_squareroot(x)` returns a solution `y` to `y**2 % q == x`, and `None` if none exists. If there are two solutions the one with higher imaginary component is favored; if both solutions have equal imaginary component the one with higher real component is favored (note that this is equivalent to saying that the single solution with either imaginary component > p/2 or imaginary component zero and real component > p/2 is favored). -The following is a sample implementation; implementers are free to implement modular square roots as they wish. Note that `x2 = -x1` is an _additive modular inverse_ so real and imaginary coefficients remain in `[0 .. q-1]` +The following is a sample implementation; implementers are free to implement modular square roots as they wish. Note that `x2 = -x1` is an _additive modular inverse_ so real and imaginary coefficients remain in `[0 .. q-1]`. `coerce_to_int` is a function that takes Fq elements (ie. integers mod q) and converts them to regular integers. ```python Fq2_order = q ** 2 - 1 @@ -100,7 +100,9 @@ def modular_squareroot(value: Fq2) -> Fq2: if check in eighth_roots_of_unity[::2]: x1 = candidate_squareroot / eighth_roots_of_unity[eighth_roots_of_unity.index(check) // 2] x2 = -x1 - return x1 if (x1.coeffs[1].n, x1.coeffs[0].n) > (x2.coeffs[1].n, x2.coeffs[0].n) else x2 + x1_re, x1_im = coerce_to_int(x1.coeffs[0]), coerce_to_int(x1.coeffs[1]) + x2_re, x2_im = coerce_to_int(x2.coeffs[0]), coerce_to_int(x2.coeffs[1]) + return x1 if (x1_im > x2_im or (x1_im == x2_im and x1_re > x2_re)) else x2 return None ``` From 51f8ed8992b7e6a3661f5c8696210f6fc9d6e429 Mon Sep 17 00:00:00 2001 From: Hsiao-Wei Wang Date: Tue, 29 Jan 2019 15:57:05 -0600 Subject: [PATCH 3/3] Update specs/bls_signature.md Co-Authored-By: vbuterin --- specs/bls_signature.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/specs/bls_signature.md b/specs/bls_signature.md index 44007d82e..fd9bae58e 100644 --- a/specs/bls_signature.md +++ b/specs/bls_signature.md @@ -88,7 +88,7 @@ def hash_to_G2(message: bytes32, domain: uint64) -> [uint384]: `modular_squareroot(x)` returns a solution `y` to `y**2 % q == x`, and `None` if none exists. If there are two solutions the one with higher imaginary component is favored; if both solutions have equal imaginary component the one with higher real component is favored (note that this is equivalent to saying that the single solution with either imaginary component > p/2 or imaginary component zero and real component > p/2 is favored). -The following is a sample implementation; implementers are free to implement modular square roots as they wish. Note that `x2 = -x1` is an _additive modular inverse_ so real and imaginary coefficients remain in `[0 .. q-1]`. `coerce_to_int` is a function that takes Fq elements (ie. integers mod q) and converts them to regular integers. +The following is a sample implementation; implementers are free to implement modular square roots as they wish. Note that `x2 = -x1` is an _additive modular inverse_ so real and imaginary coefficients remain in `[0 .. q-1]`. `coerce_to_int(element: Fq) -> int` is a function that takes Fq element `element` (ie. integers `mod q`) and converts it to a regular integer. ```python Fq2_order = q ** 2 - 1