Module: Schnorr
- Defined in:
- lib/schnorr.rb,
lib/schnorr/signature.rb,
lib/schnorr/sign_to_contract.rb
Defined Under Namespace
Modules: SignToContract Classes: InvalidSignatureError, Signature
Constant Summary collapse
- GROUP =
ECDSA::Group::Secp256k1
- ALGO16 =
"SCHNORR + SHA256"
Class Method Summary collapse
-
.check_sig!(message, signature, public_key) ⇒ Boolean
Verifies the given Signature and raises an InvalidSignatureError if it is invalid.
-
.create_challenge(x, p, message) ⇒ Integer
create signature digest.
- .deterministic_nonce(message, private_key) ⇒ Object
-
.sign(message, private_key) ⇒ Schnorr::Signature
Generate schnorr signature.
-
.valid_sig?(message, signature, public_key) ⇒ Boolean
Verifies the given Signature and returns true if it is valid.
Class Method Details
.check_sig!(message, signature, public_key) ⇒ Boolean
Verifies the given Signature and raises an InvalidSignatureError if it is invalid.
56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 |
# File 'lib/schnorr.rb', line 56 def check_sig!(, signature, public_key) sig = Schnorr::Signature.decode(signature) pubkey = ECDSA::Format::PointOctetString.decode(public_key, GROUP) field = GROUP.field raise Schnorr::InvalidSignatureError, "Invalid signature: r is not in the field." unless field.include?(sig.r) raise Schnorr::InvalidSignatureError, "Invalid signature: s is not in the field." unless field.include?(sig.s) raise Schnorr::InvalidSignatureError, "Invalid signature: r is zero." if sig.r.zero? raise Schnorr::InvalidSignatureError, "Invalid signature: s is zero." if sig.s.zero? raise Schnorr::InvalidSignatureError, "Invalid signature: r is larger than field size." if sig.r >= field.prime raise Schnorr::InvalidSignatureError, "Invalid signature: s is larger than group order." if sig.s >= GROUP.order e = create_challenge(sig.r, pubkey, ) r = GROUP.new_point(sig.s) + pubkey.multiply_by_scalar(e).negate if r.infinity? || r.x != sig.r || ECDSA::PrimeField.jacobi(r.y, GROUP.field.prime) != 1 raise Schnorr::InvalidSignatureError, "signature verification failed." end true end |
.create_challenge(x, p, message) ⇒ Integer
create signature digest.
83 84 85 86 87 |
# File 'lib/schnorr.rb', line 83 def create_challenge(x, p, ) r_x = ECDSA::Format::IntegerOctetString.encode(x, GROUP.byte_length) p_str = p.to_hex.htb (ECDSA.normalize_digest(Digest::SHA256.digest(r_x + p_str + ), GROUP.bit_length)) % GROUP.order end |
.deterministic_nonce(message, private_key) ⇒ Object
30 31 32 33 34 35 36 37 38 |
# File 'lib/schnorr.rb', line 30 def deterministic_nonce(, private_key) secret = ECDSA::Format::IntegerOctetString.encode(private_key, GROUP.byte_length) secret = secret + + ALGO16 nonce = Tapyrus::Secp256k1::RFC6979.generate_rfc6979_nonce(secret, "") k0 = nonce % GROUP.order raise "Creation of signature failed. k is zero" if k0.zero? k0 end |
.sign(message, private_key) ⇒ Schnorr::Signature
Generate schnorr signature. (The number of times to add the generator point to itself to get the public key.)
15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
# File 'lib/schnorr.rb', line 15 def sign(, private_key) raise "The message must be a 32-byte array." unless .bytesize == 32 raise "private_key is zero or over the curve order." if private_key == 0 || private_key >= GROUP.order p = GROUP.new_point(private_key) k0 = deterministic_nonce(, private_key) r = GROUP.new_point(k0) k = ECDSA::PrimeField.jacobi(r.y, GROUP.field.prime) == 1 ? k0 : GROUP.order - k0 e = create_challenge(r.x, p, ) Schnorr::Signature.new(r.x, (k + e * private_key) % GROUP.order) end |
.valid_sig?(message, signature, public_key) ⇒ Boolean
Verifies the given Signature and returns true if it is valid.
45 46 47 48 49 |
# File 'lib/schnorr.rb', line 45 def valid_sig?(, signature, public_key) check_sig!(, signature, public_key) rescue InvalidSignatureError, ECDSA::Format::DecodeError false end |