8 Implementation of Schnorr-based one-time signature from: "Two-tier
9 signatures, strongly unforgeable signatures, and Fiat-Shamir without random
10 oracles" by Bellare and Shoup (https://eprint.iacr.org/2007/273.pdf) over Curve
14 from __future__
import annotations
16 from os
import urandom
17 from hashlib
import sha256
18 from py_ecc
import bn128
as ec
19 from typing
import Dict, List, Tuple, Any
22 G1 = Tuple[ec.FQ, ec.FQ]
27 An OT-Schnorr verification key.
51 An OT-Schnorr signing key.
74 An OT-Schnorr signing and verification keypair.
76 def __init__(self, sk: SigningSecretKey, vk: SigningVerificationKey):
89 SigningSecretKey.from_json_dict(json_dict[
"sk"]),
90 SigningVerificationKey.from_json_dict(json_dict[
"vk"]))
95 Return a one-time signature key-pair
96 composed of elements of F_q and G1.
98 key_size_byte = ceil(len(
"{0:b}".format(ec.curve_order)) / 8)
100 int(
bytes(urandom(key_size_byte)).hex(), 16) % ec.curve_order)
102 int(
bytes(urandom(key_size_byte)).hex(), 16) % ec.curve_order)
103 X = ec.multiply(ec.G1, x.n)
104 Y = ec.multiply(ec.G1, y.n)
116 return signature.to_bytes(32, byteorder=
'big')
120 return int.from_bytes(sig_bytes, byteorder=
'big')
124 sk: SigningSecretKey,
125 m: bytes) -> Signature:
127 Generate a Schnorr signature on a message m.
128 We assume here that the message fits in an Ethereum word (i.e. bit_len(m)
129 <= 256), so that it can be represented by a single bytes32 on the smart-
130 contract during the signature verification.
137 challenge =
int(sha256(challenge_to_hash).hexdigest(), 16)
138 challenge = challenge % ec.curve_order
141 sigma = (sk.ssk[0].n + challenge * sk.psk.n) % ec.curve_order
146 vk: SigningVerificationKey,
150 Return true if the signature sigma is valid on message m and vk.
151 We assume here that the message is an hexadecimal string written in
152 less than 256 bits to conform with Ethereum bytes32 type.
157 challenge =
int(sha256(challenge_to_hash).hexdigest(), 16)
158 challenge = challenge % ec.curve_order
160 left_part = ec.multiply(ec.G1,
FQ(sigma).n)
161 right_part = ec.add(vk.spk, ec.multiply(vk.ppk,
FQ(challenge).n))
163 return ec.eq(left_part, right_part)
168 Transform a verification key to the format required by the mix function.
170 return [
int(vk.ppk[0]),
int(vk.ppk[1]),
int(vk.spk[0]),
int(vk.spk[1])]
174 param: List[int]) -> SigningVerificationKey:
176 Transform mix function parameter to verification key.
179 (
FQ(param[0]),
FQ(param[1])),
180 (
FQ(param[2]),
FQ(param[3])))
185 Transform a signature to the format required by the mix function.
194 Transform mix function parameters to a signature.
202 return int(fq_element.n).to_bytes(32, byteorder=
'big')
206 return FQ(int.from_bytes(fq_bytes, byteorder=
'big'))
219 Encode a group element into a byte string
220 We assume here the group prime $p$ is written in less than 256 bits
221 to conform with Ethereum bytes32 type.
224 int(group_el[0]).to_bytes(32, byteorder=
'big') + \
225 int(group_el[1]).to_bytes(32, byteorder=
'big')