Add "raw digest" signature marker trait and sign/verify traits - #10

Closed
tarcieri wants to merge 1 commit into
masterfrom
raw-digest-blanket-impl
Closed

Add "raw digest" signature marker trait and sign/verify traits#10
tarcieri wants to merge 1 commit into
masterfrom
raw-digest-blanket-impl

Conversation

@tarcieri

@tarcieritarcieri commented Mar 26, 2019

Copy link
Copy Markdown
Member

Introduces the notion of a "raw digest" signature algorithm, i.e. any algorithm where signatures are always computed as S(H(m))) where:

  • S: signature algorithm
  • H: hash (a.k.a. digest) function
  • m: message

Notably this does not hold true for Ed25519, which hashes the input message twice in an effort to remain secure even in the event of collisions in the underlying hash function.

However, it supports a separate IUF mode Ed25519ph, which is trivial for any Ed25519 implementation to implement (it hashes the message in advance, then performs a regular Ed25519 signature albeit with a domain separation tweak).

For cases like this, where the IUF mode is deliberately domain separated from the normal mode, it would be nice to avoid a blanket impl which assumes all signature algorithms are composed as S(H(m)), so signers can, if they so desire, impl both traits and support both modes using a single underlying type (e.g. KeyPair for signers and PublicKey for verifiers), as the keys used for either algorithm are identical and both modes can be used safely under the same key due to domain separation.

To accomplish this, this commit adds a RawDigestSignature marker trait to be applied at the algorithm level to the corresponding signature trait.

For signature types marked as RawDigestSignature, it's possible to impl a corresponding SignRawDigest trait for which a blanket impl of Sign exists which hashes the message with the corresponding Digest algorithm.

Additionally, SignDigest is blanket impl'd for all SignRawDigest types.

Introduces the notion of a "raw digest" signature algorithm, i.e.
any algorithm where signatures are always computed as `S(H(m)))` where:
- `S`: signature algorithm
- `H`: hash (a.k.a. digest) function
- `m`: message
Notably this does not hold true for Ed25519, which hashes the input
message twice in an effort to remain secure even in the event of
collisions in the underlying hash function.
However, it supports a separate IUF mode Ed25519ph, which is trivial
for any Ed25519 implementation to implement (it hashes the message
in advance, then performs a regular Ed25519 signature albeit with a
domain separation tweak).
For cases like this, where the IUF mode is deliberately domain separated
from the normal mode, it would be nice to avoid a blanket impl which
assumes all signature algorithms are composed as `S(H(m))`.
To accomplish this, this commit adds a `RawDigestSignature` marker trait
to be applied at the algorithm level to the corresponding signature
trait.
For signature types marked as `RawDigestSignature`, it's possible to
`impl` a corresponding `SignRawDigest` trait for which a blanket `impl`
of `Sign` exists which hashes the message with the corresponding
`Digest` algorithm.
Additionally, `SignDigest` is blanket impl'd for all `SignRawDigest`
types.
@tarcieri

Copy link
Copy Markdown
MemberAuthor

@newpavlov I think this accomplishes what you were trying to do, which was to wrap a non-object-trait ala 80f518a with an object safe one, and use the former for the blanket impls so they could be constrained by the associated type.

I think this approach solves everything elegantly with simple trait composition, has clearer concepts it uses in the trait bounds, and best of all hoists the relevant marker trait up to the signature algorithm level so it can be solved once per algorithm.

@tarcieri

Copy link
Copy Markdown
MemberAuthor

If there aren't any objections, I'd like to merge this

@newpavlov

Copy link
Copy Markdown
Member

Sorry for the delay! I wanted to think more carefully about this PR on this weekend. I have some questions, which I think we can discuss in IRC.

@tarcieri

Copy link
Copy Markdown
MemberAuthor

@newpavlov sounds good

where
D: Digest,
S: Signature + RawDigestSignature,
T: SignRawDigest<S, Digest = D>,

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@newpavlov here is where the Digest associated type from SignRawDigest is used. It's needed to constrain the blanket impl.

@tarcieri

Copy link
Copy Markdown
MemberAuthor

@newpavlov I'll admit this still feels a bit weird. Let me briefly spell out the concerns I'm trying to juggle here:

  1. Allow Ed25519 crates to impl both Sign and SignDigest (and corresponding verify traits) on the same type which use slightly different algorithms (Ed25519/Ed25519ph) to accommodate an IUF mode
  2. Allow crates to electively impl SignDigest for multiple Digest algorithms on the same type
  3. Make it easy for crates to pick a canonical digest, and in the process receive a blanket impl of Sign which uses Digest to hash the message then does sign_digest

Alternative 1: proc macros

One alternative I can think of to the approach in this PR is to add signature_derive crate with a proc macro for deriving Sign (or Signer or whatever we end up calling it) for types which impl SignDigest. Something like:

  • #[derive(Sign(digest=Sha256))]

This is quite flexible and keeps the public facing API simple (just Sign/SignDigest), but resorting to a proc macro for this feels a bit dirty and of course they're something of a maintenance burden.

Alternative 2: move associated type to the signature trait

Another is to move the Digest associated type to the RawDigestSignature trait itself, and constrain the blanket impl with that.

It means that SignDigest types would only receive the blanket impl for the "preferred" digest algorithm, but that seems ok to me.

@tarcieri

Copy link
Copy Markdown
MemberAuthor

Actually I like alternative 2 so much I'm going to close this and try again 😉

@tarcieri
tarcieri deleted the raw-digest-blanket-impl branch March 29, 2019 18:43
@newpavlov

Copy link
Copy Markdown
Member

Allow Ed25519 crates to impl both Sign and SignDigest (and corresponding verify traits) on the same type which use slightly different algorithms

I would expect two different types for two different signature algorithms, even if they are jsut a slightly different.

Make it easy for crates to pick a canonical digest

I think it shouldn't be done on traits side. A better approach will be to use default type parameters, something like this:

structSignAlg<D:Digest<Output=U32> = Sha256>{ .. }

@tarcieri

tarcieri commented Mar 29, 2019

Copy link
Copy Markdown
MemberAuthor

I would expect two different types for two different signature algorithms, even if they are jsut a slightly different.

Presently ed25519_dalek::Keypair has a sign and sign_prehashed methods. I think it really makes sense to make it possible to support this, rather than making a redundant Keypair type just for Ed25519ph.

The same also goes for supporting multiple digest algorithms per type. Then the type can be generic around the digest function.

I think it shouldn't be done on traits side. A better approach will be to use default type parameters, something like this

Using a trait means the problem can be solved once at an algorithm level (e.g. in the ecdsa crate), rather than every crate that implements it having to make it a generic parameter of their struct.

It also means the blanket impl "Just Works" on signature algorithms that are constructed as S(H(m)) without impacting algorithms that don't have this property. It's something the implementer of the digest::Signer and digest::Verifier traits doesn't even have to think about.

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@tarcieri@newpavlov
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

Add "raw digest" signature marker trait and sign/verify traits - #10

Closed
tarcieri wants to merge 1 commit into
masterfrom
raw-digest-blanket-impl
Closed

Add "raw digest" signature marker trait and sign/verify traits#10
tarcieri wants to merge 1 commit into
masterfrom
raw-digest-blanket-impl

Conversation

@tarcieri

@tarcieritarcieri commented Mar 26, 2019

Copy link
Copy Markdown
Member

Introduces the notion of a "raw digest" signature algorithm, i.e. any algorithm where signatures are always computed as S(H(m))) where:

  • S: signature algorithm
  • H: hash (a.k.a. digest) function
  • m: message

Notably this does not hold true for Ed25519, which hashes the input message twice in an effort to remain secure even in the event of collisions in the underlying hash function.

However, it supports a separate IUF mode Ed25519ph, which is trivial for any Ed25519 implementation to implement (it hashes the message in advance, then performs a regular Ed25519 signature albeit with a domain separation tweak).

For cases like this, where the IUF mode is deliberately domain separated from the normal mode, it would be nice to avoid a blanket impl which assumes all signature algorithms are composed as S(H(m)), so signers can, if they so desire, impl both traits and support both modes using a single underlying type (e.g. KeyPair for signers and PublicKey for verifiers), as the keys used for either algorithm are identical and both modes can be used safely under the same key due to domain separation.

To accomplish this, this commit adds a RawDigestSignature marker trait to be applied at the algorithm level to the corresponding signature trait.

For signature types marked as RawDigestSignature, it's possible to impl a corresponding SignRawDigest trait for which a blanket impl of Sign exists which hashes the message with the corresponding Digest algorithm.

Additionally, SignDigest is blanket impl'd for all SignRawDigest types.

Introduces the notion of a "raw digest" signature algorithm, i.e.
any algorithm where signatures are always computed as `S(H(m)))` where:
- `S`: signature algorithm
- `H`: hash (a.k.a. digest) function
- `m`: message
Notably this does not hold true for Ed25519, which hashes the input
message twice in an effort to remain secure even in the event of
collisions in the underlying hash function.
However, it supports a separate IUF mode Ed25519ph, which is trivial
for any Ed25519 implementation to implement (it hashes the message
in advance, then performs a regular Ed25519 signature albeit with a
domain separation tweak).
For cases like this, where the IUF mode is deliberately domain separated
from the normal mode, it would be nice to avoid a blanket impl which
assumes all signature algorithms are composed as `S(H(m))`.
To accomplish this, this commit adds a `RawDigestSignature` marker trait
to be applied at the algorithm level to the corresponding signature
trait.
For signature types marked as `RawDigestSignature`, it's possible to
`impl` a corresponding `SignRawDigest` trait for which a blanket `impl`
of `Sign` exists which hashes the message with the corresponding
`Digest` algorithm.
Additionally, `SignDigest` is blanket impl'd for all `SignRawDigest`
types.
@tarcieri

Copy link
Copy Markdown
MemberAuthor

@newpavlov I think this accomplishes what you were trying to do, which was to wrap a non-object-trait ala 80f518a with an object safe one, and use the former for the blanket impls so they could be constrained by the associated type.

I think this approach solves everything elegantly with simple trait composition, has clearer concepts it uses in the trait bounds, and best of all hoists the relevant marker trait up to the signature algorithm level so it can be solved once per algorithm.

@tarcieri

Copy link
Copy Markdown
MemberAuthor

If there aren't any objections, I'd like to merge this

@newpavlov

Copy link
Copy Markdown
Member

Sorry for the delay! I wanted to think more carefully about this PR on this weekend. I have some questions, which I think we can discuss in IRC.

@tarcieri

Copy link
Copy Markdown
MemberAuthor

@newpavlov sounds good

where
D: Digest,
S: Signature + RawDigestSignature,
T: SignRawDigest<S, Digest = D>,

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@newpavlov here is where the Digest associated type from SignRawDigest is used. It's needed to constrain the blanket impl.

@tarcieri

Copy link
Copy Markdown
MemberAuthor

@newpavlov I'll admit this still feels a bit weird. Let me briefly spell out the concerns I'm trying to juggle here:

  1. Allow Ed25519 crates to impl both Sign and SignDigest (and corresponding verify traits) on the same type which use slightly different algorithms (Ed25519/Ed25519ph) to accommodate an IUF mode
  2. Allow crates to electively impl SignDigest for multiple Digest algorithms on the same type
  3. Make it easy for crates to pick a canonical digest, and in the process receive a blanket impl of Sign which uses Digest to hash the message then does sign_digest

Alternative 1: proc macros

One alternative I can think of to the approach in this PR is to add signature_derive crate with a proc macro for deriving Sign (or Signer or whatever we end up calling it) for types which impl SignDigest. Something like:

  • #[derive(Sign(digest=Sha256))]

This is quite flexible and keeps the public facing API simple (just Sign/SignDigest), but resorting to a proc macro for this feels a bit dirty and of course they're something of a maintenance burden.

Alternative 2: move associated type to the signature trait

Another is to move the Digest associated type to the RawDigestSignature trait itself, and constrain the blanket impl with that.

It means that SignDigest types would only receive the blanket impl for the "preferred" digest algorithm, but that seems ok to me.

@tarcieri

Copy link
Copy Markdown
MemberAuthor

Actually I like alternative 2 so much I'm going to close this and try again 😉

@tarcieri
tarcieri deleted the raw-digest-blanket-impl branch March 29, 2019 18:43
@newpavlov

Copy link
Copy Markdown
Member

Allow Ed25519 crates to impl both Sign and SignDigest (and corresponding verify traits) on the same type which use slightly different algorithms

I would expect two different types for two different signature algorithms, even if they are jsut a slightly different.

Make it easy for crates to pick a canonical digest

I think it shouldn't be done on traits side. A better approach will be to use default type parameters, something like this:

structSignAlg<D:Digest<Output=U32> = Sha256>{ .. }

@tarcieri

tarcieri commented Mar 29, 2019

Copy link
Copy Markdown
MemberAuthor

I would expect two different types for two different signature algorithms, even if they are jsut a slightly different.

Presently ed25519_dalek::Keypair has a sign and sign_prehashed methods. I think it really makes sense to make it possible to support this, rather than making a redundant Keypair type just for Ed25519ph.

The same also goes for supporting multiple digest algorithms per type. Then the type can be generic around the digest function.

I think it shouldn't be done on traits side. A better approach will be to use default type parameters, something like this

Using a trait means the problem can be solved once at an algorithm level (e.g. in the ecdsa crate), rather than every crate that implements it having to make it a generic parameter of their struct.

It also means the blanket impl "Just Works" on signature algorithms that are constructed as S(H(m)) without impacting algorithms that don't have this property. It's something the implementer of the digest::Signer and digest::Verifier traits doesn't even have to think about.

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@tarcieri@newpavlov
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Add "raw digest" signature marker trait and sign/verify traits - #10

Closed
tarcieri wants to merge 1 commit into
masterfrom
raw-digest-blanket-impl
Closed

Add "raw digest" signature marker trait and sign/verify traits#10
tarcieri wants to merge 1 commit into
masterfrom
raw-digest-blanket-impl

Conversation

@tarcieri

@tarcieritarcieri commented Mar 26, 2019

Copy link
Copy Markdown
Member

Introduces the notion of a "raw digest" signature algorithm, i.e. any algorithm where signatures are always computed as S(H(m))) where:

  • S: signature algorithm
  • H: hash (a.k.a. digest) function
  • m: message

Notably this does not hold true for Ed25519, which hashes the input message twice in an effort to remain secure even in the event of collisions in the underlying hash function.

However, it supports a separate IUF mode Ed25519ph, which is trivial for any Ed25519 implementation to implement (it hashes the message in advance, then performs a regular Ed25519 signature albeit with a domain separation tweak).

For cases like this, where the IUF mode is deliberately domain separated from the normal mode, it would be nice to avoid a blanket impl which assumes all signature algorithms are composed as S(H(m)), so signers can, if they so desire, impl both traits and support both modes using a single underlying type (e.g. KeyPair for signers and PublicKey for verifiers), as the keys used for either algorithm are identical and both modes can be used safely under the same key due to domain separation.

To accomplish this, this commit adds a RawDigestSignature marker trait to be applied at the algorithm level to the corresponding signature trait.

For signature types marked as RawDigestSignature, it's possible to impl a corresponding SignRawDigest trait for which a blanket impl of Sign exists which hashes the message with the corresponding Digest algorithm.

Additionally, SignDigest is blanket impl'd for all SignRawDigest types.

Introduces the notion of a "raw digest" signature algorithm, i.e.
any algorithm where signatures are always computed as `S(H(m)))` where:
- `S`: signature algorithm
- `H`: hash (a.k.a. digest) function
- `m`: message
Notably this does not hold true for Ed25519, which hashes the input
message twice in an effort to remain secure even in the event of
collisions in the underlying hash function.
However, it supports a separate IUF mode Ed25519ph, which is trivial
for any Ed25519 implementation to implement (it hashes the message
in advance, then performs a regular Ed25519 signature albeit with a
domain separation tweak).
For cases like this, where the IUF mode is deliberately domain separated
from the normal mode, it would be nice to avoid a blanket impl which
assumes all signature algorithms are composed as `S(H(m))`.
To accomplish this, this commit adds a `RawDigestSignature` marker trait
to be applied at the algorithm level to the corresponding signature
trait.
For signature types marked as `RawDigestSignature`, it's possible to
`impl` a corresponding `SignRawDigest` trait for which a blanket `impl`
of `Sign` exists which hashes the message with the corresponding
`Digest` algorithm.
Additionally, `SignDigest` is blanket impl'd for all `SignRawDigest`
types.
@tarcieri

Copy link
Copy Markdown
MemberAuthor

@newpavlov I think this accomplishes what you were trying to do, which was to wrap a non-object-trait ala 80f518a with an object safe one, and use the former for the blanket impls so they could be constrained by the associated type.

I think this approach solves everything elegantly with simple trait composition, has clearer concepts it uses in the trait bounds, and best of all hoists the relevant marker trait up to the signature algorithm level so it can be solved once per algorithm.

@tarcieri

Copy link
Copy Markdown
MemberAuthor

If there aren't any objections, I'd like to merge this

@newpavlov

Copy link
Copy Markdown
Member

Sorry for the delay! I wanted to think more carefully about this PR on this weekend. I have some questions, which I think we can discuss in IRC.

@tarcieri

Copy link
Copy Markdown
MemberAuthor

@newpavlov sounds good

where
D: Digest,
S: Signature + RawDigestSignature,
T: SignRawDigest<S, Digest = D>,

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@newpavlov here is where the Digest associated type from SignRawDigest is used. It's needed to constrain the blanket impl.

@tarcieri

Copy link
Copy Markdown
MemberAuthor

@newpavlov I'll admit this still feels a bit weird. Let me briefly spell out the concerns I'm trying to juggle here:

  1. Allow Ed25519 crates to impl both Sign and SignDigest (and corresponding verify traits) on the same type which use slightly different algorithms (Ed25519/Ed25519ph) to accommodate an IUF mode
  2. Allow crates to electively impl SignDigest for multiple Digest algorithms on the same type
  3. Make it easy for crates to pick a canonical digest, and in the process receive a blanket impl of Sign which uses Digest to hash the message then does sign_digest

Alternative 1: proc macros

One alternative I can think of to the approach in this PR is to add signature_derive crate with a proc macro for deriving Sign (or Signer or whatever we end up calling it) for types which impl SignDigest. Something like:

  • #[derive(Sign(digest=Sha256))]

This is quite flexible and keeps the public facing API simple (just Sign/SignDigest), but resorting to a proc macro for this feels a bit dirty and of course they're something of a maintenance burden.

Alternative 2: move associated type to the signature trait

Another is to move the Digest associated type to the RawDigestSignature trait itself, and constrain the blanket impl with that.

It means that SignDigest types would only receive the blanket impl for the "preferred" digest algorithm, but that seems ok to me.

@tarcieri

Copy link
Copy Markdown
MemberAuthor

Actually I like alternative 2 so much I'm going to close this and try again 😉

@tarcieri
tarcieri deleted the raw-digest-blanket-impl branch March 29, 2019 18:43
@newpavlov

Copy link
Copy Markdown
Member

Allow Ed25519 crates to impl both Sign and SignDigest (and corresponding verify traits) on the same type which use slightly different algorithms

I would expect two different types for two different signature algorithms, even if they are jsut a slightly different.

Make it easy for crates to pick a canonical digest

I think it shouldn't be done on traits side. A better approach will be to use default type parameters, something like this:

structSignAlg<D:Digest<Output=U32> = Sha256>{ .. }

@tarcieri

tarcieri commented Mar 29, 2019

Copy link
Copy Markdown
MemberAuthor

I would expect two different types for two different signature algorithms, even if they are jsut a slightly different.

Presently ed25519_dalek::Keypair has a sign and sign_prehashed methods. I think it really makes sense to make it possible to support this, rather than making a redundant Keypair type just for Ed25519ph.

The same also goes for supporting multiple digest algorithms per type. Then the type can be generic around the digest function.

I think it shouldn't be done on traits side. A better approach will be to use default type parameters, something like this

Using a trait means the problem can be solved once at an algorithm level (e.g. in the ecdsa crate), rather than every crate that implements it having to make it a generic parameter of their struct.

It also means the blanket impl "Just Works" on signature algorithms that are constructed as S(H(m)) without impacting algorithms that don't have this property. It's something the implementer of the digest::Signer and digest::Verifier traits doesn't even have to think about.

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@tarcieri@newpavlov
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Add "raw digest" signature marker trait and sign/verify traits - #10

Closed
tarcieri wants to merge 1 commit into
masterfrom
raw-digest-blanket-impl
Closed

Add "raw digest" signature marker trait and sign/verify traits#10
tarcieri wants to merge 1 commit into
masterfrom
raw-digest-blanket-impl

Conversation

@tarcieri

@tarcieritarcieri commented Mar 26, 2019

Copy link
Copy Markdown
Member

Introduces the notion of a "raw digest" signature algorithm, i.e. any algorithm where signatures are always computed as S(H(m))) where:

  • S: signature algorithm
  • H: hash (a.k.a. digest) function
  • m: message

Notably this does not hold true for Ed25519, which hashes the input message twice in an effort to remain secure even in the event of collisions in the underlying hash function.

However, it supports a separate IUF mode Ed25519ph, which is trivial for any Ed25519 implementation to implement (it hashes the message in advance, then performs a regular Ed25519 signature albeit with a domain separation tweak).

For cases like this, where the IUF mode is deliberately domain separated from the normal mode, it would be nice to avoid a blanket impl which assumes all signature algorithms are composed as S(H(m)), so signers can, if they so desire, impl both traits and support both modes using a single underlying type (e.g. KeyPair for signers and PublicKey for verifiers), as the keys used for either algorithm are identical and both modes can be used safely under the same key due to domain separation.

To accomplish this, this commit adds a RawDigestSignature marker trait to be applied at the algorithm level to the corresponding signature trait.

For signature types marked as RawDigestSignature, it's possible to impl a corresponding SignRawDigest trait for which a blanket impl of Sign exists which hashes the message with the corresponding Digest algorithm.

Additionally, SignDigest is blanket impl'd for all SignRawDigest types.

Introduces the notion of a "raw digest" signature algorithm, i.e.
any algorithm where signatures are always computed as `S(H(m)))` where:
- `S`: signature algorithm
- `H`: hash (a.k.a. digest) function
- `m`: message
Notably this does not hold true for Ed25519, which hashes the input
message twice in an effort to remain secure even in the event of
collisions in the underlying hash function.
However, it supports a separate IUF mode Ed25519ph, which is trivial
for any Ed25519 implementation to implement (it hashes the message
in advance, then performs a regular Ed25519 signature albeit with a
domain separation tweak).
For cases like this, where the IUF mode is deliberately domain separated
from the normal mode, it would be nice to avoid a blanket impl which
assumes all signature algorithms are composed as `S(H(m))`.
To accomplish this, this commit adds a `RawDigestSignature` marker trait
to be applied at the algorithm level to the corresponding signature
trait.
For signature types marked as `RawDigestSignature`, it's possible to
`impl` a corresponding `SignRawDigest` trait for which a blanket `impl`
of `Sign` exists which hashes the message with the corresponding
`Digest` algorithm.
Additionally, `SignDigest` is blanket impl'd for all `SignRawDigest`
types.
@tarcieri

Copy link
Copy Markdown
MemberAuthor

@newpavlov I think this accomplishes what you were trying to do, which was to wrap a non-object-trait ala 80f518a with an object safe one, and use the former for the blanket impls so they could be constrained by the associated type.

I think this approach solves everything elegantly with simple trait composition, has clearer concepts it uses in the trait bounds, and best of all hoists the relevant marker trait up to the signature algorithm level so it can be solved once per algorithm.

@tarcieri

Copy link
Copy Markdown
MemberAuthor

If there aren't any objections, I'd like to merge this

@newpavlov

Copy link
Copy Markdown
Member

Sorry for the delay! I wanted to think more carefully about this PR on this weekend. I have some questions, which I think we can discuss in IRC.

@tarcieri

Copy link
Copy Markdown
MemberAuthor

@newpavlov sounds good

where
D: Digest,
S: Signature + RawDigestSignature,
T: SignRawDigest<S, Digest = D>,

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@newpavlov here is where the Digest associated type from SignRawDigest is used. It's needed to constrain the blanket impl.

@tarcieri

Copy link
Copy Markdown
MemberAuthor

@newpavlov I'll admit this still feels a bit weird. Let me briefly spell out the concerns I'm trying to juggle here:

  1. Allow Ed25519 crates to impl both Sign and SignDigest (and corresponding verify traits) on the same type which use slightly different algorithms (Ed25519/Ed25519ph) to accommodate an IUF mode
  2. Allow crates to electively impl SignDigest for multiple Digest algorithms on the same type
  3. Make it easy for crates to pick a canonical digest, and in the process receive a blanket impl of Sign which uses Digest to hash the message then does sign_digest

Alternative 1: proc macros

One alternative I can think of to the approach in this PR is to add signature_derive crate with a proc macro for deriving Sign (or Signer or whatever we end up calling it) for types which impl SignDigest. Something like:

  • #[derive(Sign(digest=Sha256))]

This is quite flexible and keeps the public facing API simple (just Sign/SignDigest), but resorting to a proc macro for this feels a bit dirty and of course they're something of a maintenance burden.

Alternative 2: move associated type to the signature trait

Another is to move the Digest associated type to the RawDigestSignature trait itself, and constrain the blanket impl with that.

It means that SignDigest types would only receive the blanket impl for the "preferred" digest algorithm, but that seems ok to me.

@tarcieri

Copy link
Copy Markdown
MemberAuthor

Actually I like alternative 2 so much I'm going to close this and try again 😉

@tarcieri
tarcieri deleted the raw-digest-blanket-impl branch March 29, 2019 18:43
@newpavlov

Copy link
Copy Markdown
Member

Allow Ed25519 crates to impl both Sign and SignDigest (and corresponding verify traits) on the same type which use slightly different algorithms

I would expect two different types for two different signature algorithms, even if they are jsut a slightly different.

Make it easy for crates to pick a canonical digest

I think it shouldn't be done on traits side. A better approach will be to use default type parameters, something like this:

structSignAlg<D:Digest<Output=U32> = Sha256>{ .. }

@tarcieri

tarcieri commented Mar 29, 2019

Copy link
Copy Markdown
MemberAuthor

I would expect two different types for two different signature algorithms, even if they are jsut a slightly different.

Presently ed25519_dalek::Keypair has a sign and sign_prehashed methods. I think it really makes sense to make it possible to support this, rather than making a redundant Keypair type just for Ed25519ph.

The same also goes for supporting multiple digest algorithms per type. Then the type can be generic around the digest function.

I think it shouldn't be done on traits side. A better approach will be to use default type parameters, something like this

Using a trait means the problem can be solved once at an algorithm level (e.g. in the ecdsa crate), rather than every crate that implements it having to make it a generic parameter of their struct.

It also means the blanket impl "Just Works" on signature algorithms that are constructed as S(H(m)) without impacting algorithms that don't have this property. It's something the implementer of the digest::Signer and digest::Verifier traits doesn't even have to think about.

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@tarcieri@newpavlov
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

Add "raw digest" signature marker trait and sign/verify traits - #10

Closed
tarcieri wants to merge 1 commit into
masterfrom
raw-digest-blanket-impl
Closed

Add "raw digest" signature marker trait and sign/verify traits#10
tarcieri wants to merge 1 commit into
masterfrom
raw-digest-blanket-impl

Conversation

@tarcieri

@tarcieritarcieri commented Mar 26, 2019

Copy link
Copy Markdown
Member

Introduces the notion of a "raw digest" signature algorithm, i.e. any algorithm where signatures are always computed as S(H(m))) where:

  • S: signature algorithm
  • H: hash (a.k.a. digest) function
  • m: message

Notably this does not hold true for Ed25519, which hashes the input message twice in an effort to remain secure even in the event of collisions in the underlying hash function.

However, it supports a separate IUF mode Ed25519ph, which is trivial for any Ed25519 implementation to implement (it hashes the message in advance, then performs a regular Ed25519 signature albeit with a domain separation tweak).

For cases like this, where the IUF mode is deliberately domain separated from the normal mode, it would be nice to avoid a blanket impl which assumes all signature algorithms are composed as S(H(m)), so signers can, if they so desire, impl both traits and support both modes using a single underlying type (e.g. KeyPair for signers and PublicKey for verifiers), as the keys used for either algorithm are identical and both modes can be used safely under the same key due to domain separation.

To accomplish this, this commit adds a RawDigestSignature marker trait to be applied at the algorithm level to the corresponding signature trait.

For signature types marked as RawDigestSignature, it's possible to impl a corresponding SignRawDigest trait for which a blanket impl of Sign exists which hashes the message with the corresponding Digest algorithm.

Additionally, SignDigest is blanket impl'd for all SignRawDigest types.

Introduces the notion of a "raw digest" signature algorithm, i.e.
any algorithm where signatures are always computed as `S(H(m)))` where:
- `S`: signature algorithm
- `H`: hash (a.k.a. digest) function
- `m`: message
Notably this does not hold true for Ed25519, which hashes the input
message twice in an effort to remain secure even in the event of
collisions in the underlying hash function.
However, it supports a separate IUF mode Ed25519ph, which is trivial
for any Ed25519 implementation to implement (it hashes the message
in advance, then performs a regular Ed25519 signature albeit with a
domain separation tweak).
For cases like this, where the IUF mode is deliberately domain separated
from the normal mode, it would be nice to avoid a blanket impl which
assumes all signature algorithms are composed as `S(H(m))`.
To accomplish this, this commit adds a `RawDigestSignature` marker trait
to be applied at the algorithm level to the corresponding signature
trait.
For signature types marked as `RawDigestSignature`, it's possible to
`impl` a corresponding `SignRawDigest` trait for which a blanket `impl`
of `Sign` exists which hashes the message with the corresponding
`Digest` algorithm.
Additionally, `SignDigest` is blanket impl'd for all `SignRawDigest`
types.
@tarcieri

Copy link
Copy Markdown
MemberAuthor

@newpavlov I think this accomplishes what you were trying to do, which was to wrap a non-object-trait ala 80f518a with an object safe one, and use the former for the blanket impls so they could be constrained by the associated type.

I think this approach solves everything elegantly with simple trait composition, has clearer concepts it uses in the trait bounds, and best of all hoists the relevant marker trait up to the signature algorithm level so it can be solved once per algorithm.

@tarcieri

Copy link
Copy Markdown
MemberAuthor

If there aren't any objections, I'd like to merge this

@newpavlov

Copy link
Copy Markdown
Member

Sorry for the delay! I wanted to think more carefully about this PR on this weekend. I have some questions, which I think we can discuss in IRC.

@tarcieri

Copy link
Copy Markdown
MemberAuthor

@newpavlov sounds good

where
D: Digest,
S: Signature + RawDigestSignature,
T: SignRawDigest<S, Digest = D>,

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@newpavlov here is where the Digest associated type from SignRawDigest is used. It's needed to constrain the blanket impl.

@tarcieri

Copy link
Copy Markdown
MemberAuthor

@newpavlov I'll admit this still feels a bit weird. Let me briefly spell out the concerns I'm trying to juggle here:

  1. Allow Ed25519 crates to impl both Sign and SignDigest (and corresponding verify traits) on the same type which use slightly different algorithms (Ed25519/Ed25519ph) to accommodate an IUF mode
  2. Allow crates to electively impl SignDigest for multiple Digest algorithms on the same type
  3. Make it easy for crates to pick a canonical digest, and in the process receive a blanket impl of Sign which uses Digest to hash the message then does sign_digest

Alternative 1: proc macros

One alternative I can think of to the approach in this PR is to add signature_derive crate with a proc macro for deriving Sign (or Signer or whatever we end up calling it) for types which impl SignDigest. Something like:

  • #[derive(Sign(digest=Sha256))]

This is quite flexible and keeps the public facing API simple (just Sign/SignDigest), but resorting to a proc macro for this feels a bit dirty and of course they're something of a maintenance burden.

Alternative 2: move associated type to the signature trait

Another is to move the Digest associated type to the RawDigestSignature trait itself, and constrain the blanket impl with that.

It means that SignDigest types would only receive the blanket impl for the "preferred" digest algorithm, but that seems ok to me.

@tarcieri

Copy link
Copy Markdown
MemberAuthor

Actually I like alternative 2 so much I'm going to close this and try again 😉

@tarcieri
tarcieri deleted the raw-digest-blanket-impl branch March 29, 2019 18:43
@newpavlov

Copy link
Copy Markdown
Member

Allow Ed25519 crates to impl both Sign and SignDigest (and corresponding verify traits) on the same type which use slightly different algorithms

I would expect two different types for two different signature algorithms, even if they are jsut a slightly different.

Make it easy for crates to pick a canonical digest

I think it shouldn't be done on traits side. A better approach will be to use default type parameters, something like this:

structSignAlg<D:Digest<Output=U32> = Sha256>{ .. }

@tarcieri

tarcieri commented Mar 29, 2019

Copy link
Copy Markdown
MemberAuthor

I would expect two different types for two different signature algorithms, even if they are jsut a slightly different.

Presently ed25519_dalek::Keypair has a sign and sign_prehashed methods. I think it really makes sense to make it possible to support this, rather than making a redundant Keypair type just for Ed25519ph.

The same also goes for supporting multiple digest algorithms per type. Then the type can be generic around the digest function.

I think it shouldn't be done on traits side. A better approach will be to use default type parameters, something like this

Using a trait means the problem can be solved once at an algorithm level (e.g. in the ecdsa crate), rather than every crate that implements it having to make it a generic parameter of their struct.

It also means the blanket impl "Just Works" on signature algorithms that are constructed as S(H(m)) without impacting algorithms that don't have this property. It's something the implementer of the digest::Signer and digest::Verifier traits doesn't even have to think about.

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@tarcieri@newpavlov
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Add "raw digest" signature marker trait and sign/verify traits - #10

Closed
tarcieri wants to merge 1 commit into
masterfrom
raw-digest-blanket-impl
Closed

Add "raw digest" signature marker trait and sign/verify traits#10
tarcieri wants to merge 1 commit into
masterfrom
raw-digest-blanket-impl

Conversation

@tarcieri

@tarcieritarcieri commented Mar 26, 2019

Copy link
Copy Markdown
Member

Introduces the notion of a "raw digest" signature algorithm, i.e. any algorithm where signatures are always computed as S(H(m))) where:

  • S: signature algorithm
  • H: hash (a.k.a. digest) function
  • m: message

Notably this does not hold true for Ed25519, which hashes the input message twice in an effort to remain secure even in the event of collisions in the underlying hash function.

However, it supports a separate IUF mode Ed25519ph, which is trivial for any Ed25519 implementation to implement (it hashes the message in advance, then performs a regular Ed25519 signature albeit with a domain separation tweak).

For cases like this, where the IUF mode is deliberately domain separated from the normal mode, it would be nice to avoid a blanket impl which assumes all signature algorithms are composed as S(H(m)), so signers can, if they so desire, impl both traits and support both modes using a single underlying type (e.g. KeyPair for signers and PublicKey for verifiers), as the keys used for either algorithm are identical and both modes can be used safely under the same key due to domain separation.

To accomplish this, this commit adds a RawDigestSignature marker trait to be applied at the algorithm level to the corresponding signature trait.

For signature types marked as RawDigestSignature, it's possible to impl a corresponding SignRawDigest trait for which a blanket impl of Sign exists which hashes the message with the corresponding Digest algorithm.

Additionally, SignDigest is blanket impl'd for all SignRawDigest types.

Introduces the notion of a "raw digest" signature algorithm, i.e.
any algorithm where signatures are always computed as `S(H(m)))` where:
- `S`: signature algorithm
- `H`: hash (a.k.a. digest) function
- `m`: message
Notably this does not hold true for Ed25519, which hashes the input
message twice in an effort to remain secure even in the event of
collisions in the underlying hash function.
However, it supports a separate IUF mode Ed25519ph, which is trivial
for any Ed25519 implementation to implement (it hashes the message
in advance, then performs a regular Ed25519 signature albeit with a
domain separation tweak).
For cases like this, where the IUF mode is deliberately domain separated
from the normal mode, it would be nice to avoid a blanket impl which
assumes all signature algorithms are composed as `S(H(m))`.
To accomplish this, this commit adds a `RawDigestSignature` marker trait
to be applied at the algorithm level to the corresponding signature
trait.
For signature types marked as `RawDigestSignature`, it's possible to
`impl` a corresponding `SignRawDigest` trait for which a blanket `impl`
of `Sign` exists which hashes the message with the corresponding
`Digest` algorithm.
Additionally, `SignDigest` is blanket impl'd for all `SignRawDigest`
types.
@tarcieri

Copy link
Copy Markdown
MemberAuthor

@newpavlov I think this accomplishes what you were trying to do, which was to wrap a non-object-trait ala 80f518a with an object safe one, and use the former for the blanket impls so they could be constrained by the associated type.

I think this approach solves everything elegantly with simple trait composition, has clearer concepts it uses in the trait bounds, and best of all hoists the relevant marker trait up to the signature algorithm level so it can be solved once per algorithm.

@tarcieri

Copy link
Copy Markdown
MemberAuthor

If there aren't any objections, I'd like to merge this

@newpavlov

Copy link
Copy Markdown
Member

Sorry for the delay! I wanted to think more carefully about this PR on this weekend. I have some questions, which I think we can discuss in IRC.

@tarcieri

Copy link
Copy Markdown
MemberAuthor

@newpavlov sounds good

where
D: Digest,
S: Signature + RawDigestSignature,
T: SignRawDigest<S, Digest = D>,

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@newpavlov here is where the Digest associated type from SignRawDigest is used. It's needed to constrain the blanket impl.

@tarcieri

Copy link
Copy Markdown
MemberAuthor

@newpavlov I'll admit this still feels a bit weird. Let me briefly spell out the concerns I'm trying to juggle here:

  1. Allow Ed25519 crates to impl both Sign and SignDigest (and corresponding verify traits) on the same type which use slightly different algorithms (Ed25519/Ed25519ph) to accommodate an IUF mode
  2. Allow crates to electively impl SignDigest for multiple Digest algorithms on the same type
  3. Make it easy for crates to pick a canonical digest, and in the process receive a blanket impl of Sign which uses Digest to hash the message then does sign_digest

Alternative 1: proc macros

One alternative I can think of to the approach in this PR is to add signature_derive crate with a proc macro for deriving Sign (or Signer or whatever we end up calling it) for types which impl SignDigest. Something like:

  • #[derive(Sign(digest=Sha256))]

This is quite flexible and keeps the public facing API simple (just Sign/SignDigest), but resorting to a proc macro for this feels a bit dirty and of course they're something of a maintenance burden.

Alternative 2: move associated type to the signature trait

Another is to move the Digest associated type to the RawDigestSignature trait itself, and constrain the blanket impl with that.

It means that SignDigest types would only receive the blanket impl for the "preferred" digest algorithm, but that seems ok to me.

@tarcieri

Copy link
Copy Markdown
MemberAuthor

Actually I like alternative 2 so much I'm going to close this and try again 😉

@tarcieri
tarcieri deleted the raw-digest-blanket-impl branch March 29, 2019 18:43
@newpavlov

Copy link
Copy Markdown
Member

Allow Ed25519 crates to impl both Sign and SignDigest (and corresponding verify traits) on the same type which use slightly different algorithms

I would expect two different types for two different signature algorithms, even if they are jsut a slightly different.

Make it easy for crates to pick a canonical digest

I think it shouldn't be done on traits side. A better approach will be to use default type parameters, something like this:

structSignAlg<D:Digest<Output=U32> = Sha256>{ .. }

@tarcieri

tarcieri commented Mar 29, 2019

Copy link
Copy Markdown
MemberAuthor

I would expect two different types for two different signature algorithms, even if they are jsut a slightly different.

Presently ed25519_dalek::Keypair has a sign and sign_prehashed methods. I think it really makes sense to make it possible to support this, rather than making a redundant Keypair type just for Ed25519ph.

The same also goes for supporting multiple digest algorithms per type. Then the type can be generic around the digest function.

I think it shouldn't be done on traits side. A better approach will be to use default type parameters, something like this

Using a trait means the problem can be solved once at an algorithm level (e.g. in the ecdsa crate), rather than every crate that implements it having to make it a generic parameter of their struct.

It also means the blanket impl "Just Works" on signature algorithms that are constructed as S(H(m)) without impacting algorithms that don't have this property. It's something the implementer of the digest::Signer and digest::Verifier traits doesn't even have to think about.

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@tarcieri@newpavlov
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Add "raw digest" signature marker trait and sign/verify traits - #10

Closed
tarcieri wants to merge 1 commit into
masterfrom
raw-digest-blanket-impl
Closed

Add "raw digest" signature marker trait and sign/verify traits#10
tarcieri wants to merge 1 commit into
masterfrom
raw-digest-blanket-impl

Conversation

@tarcieri

@tarcieritarcieri commented Mar 26, 2019

Copy link
Copy Markdown
Member

Introduces the notion of a "raw digest" signature algorithm, i.e. any algorithm where signatures are always computed as S(H(m))) where:

  • S: signature algorithm
  • H: hash (a.k.a. digest) function
  • m: message

Notably this does not hold true for Ed25519, which hashes the input message twice in an effort to remain secure even in the event of collisions in the underlying hash function.

However, it supports a separate IUF mode Ed25519ph, which is trivial for any Ed25519 implementation to implement (it hashes the message in advance, then performs a regular Ed25519 signature albeit with a domain separation tweak).

For cases like this, where the IUF mode is deliberately domain separated from the normal mode, it would be nice to avoid a blanket impl which assumes all signature algorithms are composed as S(H(m)), so signers can, if they so desire, impl both traits and support both modes using a single underlying type (e.g. KeyPair for signers and PublicKey for verifiers), as the keys used for either algorithm are identical and both modes can be used safely under the same key due to domain separation.

To accomplish this, this commit adds a RawDigestSignature marker trait to be applied at the algorithm level to the corresponding signature trait.

For signature types marked as RawDigestSignature, it's possible to impl a corresponding SignRawDigest trait for which a blanket impl of Sign exists which hashes the message with the corresponding Digest algorithm.

Additionally, SignDigest is blanket impl'd for all SignRawDigest types.

Introduces the notion of a "raw digest" signature algorithm, i.e.
any algorithm where signatures are always computed as `S(H(m)))` where:
- `S`: signature algorithm
- `H`: hash (a.k.a. digest) function
- `m`: message
Notably this does not hold true for Ed25519, which hashes the input
message twice in an effort to remain secure even in the event of
collisions in the underlying hash function.
However, it supports a separate IUF mode Ed25519ph, which is trivial
for any Ed25519 implementation to implement (it hashes the message
in advance, then performs a regular Ed25519 signature albeit with a
domain separation tweak).
For cases like this, where the IUF mode is deliberately domain separated
from the normal mode, it would be nice to avoid a blanket impl which
assumes all signature algorithms are composed as `S(H(m))`.
To accomplish this, this commit adds a `RawDigestSignature` marker trait
to be applied at the algorithm level to the corresponding signature
trait.
For signature types marked as `RawDigestSignature`, it's possible to
`impl` a corresponding `SignRawDigest` trait for which a blanket `impl`
of `Sign` exists which hashes the message with the corresponding
`Digest` algorithm.
Additionally, `SignDigest` is blanket impl'd for all `SignRawDigest`
types.
@tarcieri

Copy link
Copy Markdown
MemberAuthor

@newpavlov I think this accomplishes what you were trying to do, which was to wrap a non-object-trait ala 80f518a with an object safe one, and use the former for the blanket impls so they could be constrained by the associated type.

I think this approach solves everything elegantly with simple trait composition, has clearer concepts it uses in the trait bounds, and best of all hoists the relevant marker trait up to the signature algorithm level so it can be solved once per algorithm.

@tarcieri

Copy link
Copy Markdown
MemberAuthor

If there aren't any objections, I'd like to merge this

@newpavlov

Copy link
Copy Markdown
Member

Sorry for the delay! I wanted to think more carefully about this PR on this weekend. I have some questions, which I think we can discuss in IRC.

@tarcieri

Copy link
Copy Markdown
MemberAuthor

@newpavlov sounds good

where
D: Digest,
S: Signature + RawDigestSignature,
T: SignRawDigest<S, Digest = D>,

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@newpavlov here is where the Digest associated type from SignRawDigest is used. It's needed to constrain the blanket impl.

@tarcieri

Copy link
Copy Markdown
MemberAuthor

@newpavlov I'll admit this still feels a bit weird. Let me briefly spell out the concerns I'm trying to juggle here:

  1. Allow Ed25519 crates to impl both Sign and SignDigest (and corresponding verify traits) on the same type which use slightly different algorithms (Ed25519/Ed25519ph) to accommodate an IUF mode
  2. Allow crates to electively impl SignDigest for multiple Digest algorithms on the same type
  3. Make it easy for crates to pick a canonical digest, and in the process receive a blanket impl of Sign which uses Digest to hash the message then does sign_digest

Alternative 1: proc macros

One alternative I can think of to the approach in this PR is to add signature_derive crate with a proc macro for deriving Sign (or Signer or whatever we end up calling it) for types which impl SignDigest. Something like:

  • #[derive(Sign(digest=Sha256))]

This is quite flexible and keeps the public facing API simple (just Sign/SignDigest), but resorting to a proc macro for this feels a bit dirty and of course they're something of a maintenance burden.

Alternative 2: move associated type to the signature trait

Another is to move the Digest associated type to the RawDigestSignature trait itself, and constrain the blanket impl with that.

It means that SignDigest types would only receive the blanket impl for the "preferred" digest algorithm, but that seems ok to me.

@tarcieri

Copy link
Copy Markdown
MemberAuthor

Actually I like alternative 2 so much I'm going to close this and try again 😉

@tarcieri
tarcieri deleted the raw-digest-blanket-impl branch March 29, 2019 18:43
@newpavlov

Copy link
Copy Markdown
Member

Allow Ed25519 crates to impl both Sign and SignDigest (and corresponding verify traits) on the same type which use slightly different algorithms

I would expect two different types for two different signature algorithms, even if they are jsut a slightly different.

Make it easy for crates to pick a canonical digest

I think it shouldn't be done on traits side. A better approach will be to use default type parameters, something like this:

structSignAlg<D:Digest<Output=U32> = Sha256>{ .. }

@tarcieri

tarcieri commented Mar 29, 2019

Copy link
Copy Markdown
MemberAuthor

I would expect two different types for two different signature algorithms, even if they are jsut a slightly different.

Presently ed25519_dalek::Keypair has a sign and sign_prehashed methods. I think it really makes sense to make it possible to support this, rather than making a redundant Keypair type just for Ed25519ph.

The same also goes for supporting multiple digest algorithms per type. Then the type can be generic around the digest function.

I think it shouldn't be done on traits side. A better approach will be to use default type parameters, something like this

Using a trait means the problem can be solved once at an algorithm level (e.g. in the ecdsa crate), rather than every crate that implements it having to make it a generic parameter of their struct.

It also means the blanket impl "Just Works" on signature algorithms that are constructed as S(H(m)) without impacting algorithms that don't have this property. It's something the implementer of the digest::Signer and digest::Verifier traits doesn't even have to think about.

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@tarcieri@newpavlov
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

Add "raw digest" signature marker trait and sign/verify traits - #10

Closed
tarcieri wants to merge 1 commit into
masterfrom
raw-digest-blanket-impl
Closed

Add "raw digest" signature marker trait and sign/verify traits#10
tarcieri wants to merge 1 commit into
masterfrom
raw-digest-blanket-impl

Conversation

@tarcieri

@tarcieritarcieri commented Mar 26, 2019

Copy link
Copy Markdown
Member

Introduces the notion of a "raw digest" signature algorithm, i.e. any algorithm where signatures are always computed as S(H(m))) where:

  • S: signature algorithm
  • H: hash (a.k.a. digest) function
  • m: message

Notably this does not hold true for Ed25519, which hashes the input message twice in an effort to remain secure even in the event of collisions in the underlying hash function.

However, it supports a separate IUF mode Ed25519ph, which is trivial for any Ed25519 implementation to implement (it hashes the message in advance, then performs a regular Ed25519 signature albeit with a domain separation tweak).

For cases like this, where the IUF mode is deliberately domain separated from the normal mode, it would be nice to avoid a blanket impl which assumes all signature algorithms are composed as S(H(m)), so signers can, if they so desire, impl both traits and support both modes using a single underlying type (e.g. KeyPair for signers and PublicKey for verifiers), as the keys used for either algorithm are identical and both modes can be used safely under the same key due to domain separation.

To accomplish this, this commit adds a RawDigestSignature marker trait to be applied at the algorithm level to the corresponding signature trait.

For signature types marked as RawDigestSignature, it's possible to impl a corresponding SignRawDigest trait for which a blanket impl of Sign exists which hashes the message with the corresponding Digest algorithm.

Additionally, SignDigest is blanket impl'd for all SignRawDigest types.

Introduces the notion of a "raw digest" signature algorithm, i.e.
any algorithm where signatures are always computed as `S(H(m)))` where:
- `S`: signature algorithm
- `H`: hash (a.k.a. digest) function
- `m`: message
Notably this does not hold true for Ed25519, which hashes the input
message twice in an effort to remain secure even in the event of
collisions in the underlying hash function.
However, it supports a separate IUF mode Ed25519ph, which is trivial
for any Ed25519 implementation to implement (it hashes the message
in advance, then performs a regular Ed25519 signature albeit with a
domain separation tweak).
For cases like this, where the IUF mode is deliberately domain separated
from the normal mode, it would be nice to avoid a blanket impl which
assumes all signature algorithms are composed as `S(H(m))`.
To accomplish this, this commit adds a `RawDigestSignature` marker trait
to be applied at the algorithm level to the corresponding signature
trait.
For signature types marked as `RawDigestSignature`, it's possible to
`impl` a corresponding `SignRawDigest` trait for which a blanket `impl`
of `Sign` exists which hashes the message with the corresponding
`Digest` algorithm.
Additionally, `SignDigest` is blanket impl'd for all `SignRawDigest`
types.
@tarcieri

Copy link
Copy Markdown
MemberAuthor

@newpavlov I think this accomplishes what you were trying to do, which was to wrap a non-object-trait ala 80f518a with an object safe one, and use the former for the blanket impls so they could be constrained by the associated type.

I think this approach solves everything elegantly with simple trait composition, has clearer concepts it uses in the trait bounds, and best of all hoists the relevant marker trait up to the signature algorithm level so it can be solved once per algorithm.

@tarcieri

Copy link
Copy Markdown
MemberAuthor

If there aren't any objections, I'd like to merge this

@newpavlov

Copy link
Copy Markdown
Member

Sorry for the delay! I wanted to think more carefully about this PR on this weekend. I have some questions, which I think we can discuss in IRC.

@tarcieri

Copy link
Copy Markdown
MemberAuthor

@newpavlov sounds good

where
D: Digest,
S: Signature + RawDigestSignature,
T: SignRawDigest<S, Digest = D>,

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@newpavlov here is where the Digest associated type from SignRawDigest is used. It's needed to constrain the blanket impl.

@tarcieri

Copy link
Copy Markdown
MemberAuthor

@newpavlov I'll admit this still feels a bit weird. Let me briefly spell out the concerns I'm trying to juggle here:

  1. Allow Ed25519 crates to impl both Sign and SignDigest (and corresponding verify traits) on the same type which use slightly different algorithms (Ed25519/Ed25519ph) to accommodate an IUF mode
  2. Allow crates to electively impl SignDigest for multiple Digest algorithms on the same type
  3. Make it easy for crates to pick a canonical digest, and in the process receive a blanket impl of Sign which uses Digest to hash the message then does sign_digest

Alternative 1: proc macros

One alternative I can think of to the approach in this PR is to add signature_derive crate with a proc macro for deriving Sign (or Signer or whatever we end up calling it) for types which impl SignDigest. Something like:

  • #[derive(Sign(digest=Sha256))]

This is quite flexible and keeps the public facing API simple (just Sign/SignDigest), but resorting to a proc macro for this feels a bit dirty and of course they're something of a maintenance burden.

Alternative 2: move associated type to the signature trait

Another is to move the Digest associated type to the RawDigestSignature trait itself, and constrain the blanket impl with that.

It means that SignDigest types would only receive the blanket impl for the "preferred" digest algorithm, but that seems ok to me.

@tarcieri

Copy link
Copy Markdown
MemberAuthor

Actually I like alternative 2 so much I'm going to close this and try again 😉

@tarcieri
tarcieri deleted the raw-digest-blanket-impl branch March 29, 2019 18:43
@newpavlov

Copy link
Copy Markdown
Member

Allow Ed25519 crates to impl both Sign and SignDigest (and corresponding verify traits) on the same type which use slightly different algorithms

I would expect two different types for two different signature algorithms, even if they are jsut a slightly different.

Make it easy for crates to pick a canonical digest

I think it shouldn't be done on traits side. A better approach will be to use default type parameters, something like this:

structSignAlg<D:Digest<Output=U32> = Sha256>{ .. }

@tarcieri

tarcieri commented Mar 29, 2019

Copy link
Copy Markdown
MemberAuthor

I would expect two different types for two different signature algorithms, even if they are jsut a slightly different.

Presently ed25519_dalek::Keypair has a sign and sign_prehashed methods. I think it really makes sense to make it possible to support this, rather than making a redundant Keypair type just for Ed25519ph.

The same also goes for supporting multiple digest algorithms per type. Then the type can be generic around the digest function.

I think it shouldn't be done on traits side. A better approach will be to use default type parameters, something like this

Using a trait means the problem can be solved once at an algorithm level (e.g. in the ecdsa crate), rather than every crate that implements it having to make it a generic parameter of their struct.

It also means the blanket impl "Just Works" on signature algorithms that are constructed as S(H(m)) without impacting algorithms that don't have this property. It's something the implementer of the digest::Signer and digest::Verifier traits doesn't even have to think about.

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@tarcieri@newpavlov