diff --git a/spec/sodium/sign/secret_key_spec.cr b/spec/sodium/sign/secret_key_spec.cr index 116ce45..1952bee 100644 --- a/spec/sodium/sign/secret_key_spec.cr +++ b/spec/sodium/sign/secret_key_spec.cr @@ -64,7 +64,16 @@ describe Sodium::Sign::SecretKey do key1.seed.should eq key3.seed end - it "signs and verifies" do + it "signs and verifies combined" do + message = "foo" + skey = Sodium::Sign::SecretKey.new + sig = skey.sign message + + message2 = skey.public_key.verify_string sig + message2.should eq message + end + + it "signs and verifies detached" do message = "foo" skey = Sodium::Sign::SecretKey.new sig = skey.sign_detached message diff --git a/src/sodium/sign/public_key.cr b/src/sodium/sign/public_key.cr index ad66d12..3a838cd 100644 --- a/src/sodium/sign/public_key.cr +++ b/src/sodium/sign/public_key.cr @@ -20,13 +20,37 @@ module Sodium end end - # Verify signature made by `secret_key.sign_detached(message)` + # Verify signature made by `secret_key.sign(message)` # Raises on verification failure. - def verify_detached(message, sig : Bytes) - verify_detached message.to_slice, sig + # + # WARNING: returns pointer to message within messagesig (zerocopy) + # If you reuse messagesig, `#dup` the returned message + # `secret_key.verify(messagesig).dup` + @[Experimental] + def verify(messagesig) : Bytes + messagesig = messagesig.to_slice + bs = messagesig.bytesize + raise Sodium::Error::VerificationFailed.new("message shorter than SIG_SIZE") unless bs >= SIG_SIZE + + message = messagesig[SIG_SIZE, bs - SIG_SIZE] + sig = messagesig[0, SIG_SIZE] + + verify_detached message, sig + message end - def verify_detached(message : Bytes, sig : Bytes) + @[Experimental] + def verify_string(messagesig) : String + String.new(verify(messagesig)) + end + + # Verify signature made by `secret_key.sign_detached(message)` + # Raises on verification failure. + def verify_detached(message, sig) : Nil + verify_detached message.to_slice, sig.to_slice + end + + def verify_detached(message : Bytes, sig : Bytes) : Nil raise ArgumentError.new("Signature must be #{SIG_SIZE} bytes, got #{sig.bytesize}") if sig.bytesize != SIG_SIZE v = LibSodium.crypto_sign_verify_detached sig, message, message.bytesize, @bytes diff --git a/src/sodium/sign/secret_key.cr b/src/sodium/sign/secret_key.cr index 4ca2de1..5d1938b 100644 --- a/src/sodium/sign/secret_key.cr +++ b/src/sodium/sign/secret_key.cr @@ -91,14 +91,28 @@ module Sodium end.readonly end + # Signs message and returns a combined signature. + # Verify using `secret_key.public_key.verify(messagesig).dup` + # See warning about object reuse in `#verify` if you don't `#dup` + @[Experimental] + def sign(message) : Bytes + message = message.to_slice + + Bytes.new(SIG_SIZE + message.bytesize).tap do |msgsig| + sign_detached message, msgsig[0, SIG_SIZE] + message.copy_to msgsig[SIG_SIZE, message.bytesize] + end + end + # Signs message and returns a detached signature. # Verify using `secret_key.public_key.verify_detached(message, sig)` - def sign_detached(message) + def sign_detached(message) : Bytes sign_detached message.to_slice end - def sign_detached(message : Bytes) - sig = Bytes.new(SIG_SIZE) + def sign_detached(message : Bytes, sig : Bytes? = nil) : Bytes + raise ArgumentError.new("expected sig to be #{SIG_SIZE}, got #{sig.try(&.bytesize).inspect}") if sig && sig.bytesize != SIG_SIZE + sig ||= Bytes.new(SIG_SIZE) @key.readonly do |kslice| if LibSodium.crypto_sign_detached(sig, out sig_len, message, message.bytesize, kslice) != 0 raise Error.new("crypto_sign_detached")