-
Notifications
You must be signed in to change notification settings - Fork 4
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Thoughts on overall architecture and possible alternatives #59
Comments
Thanks @emlun!
Indeed, The reason for having a separate HDK-Root is that the method to obtain the first blinded public key from As for diagrams, these will be needed indeed. For now possibly some of the slides help clarify: “Deriving the root HDK”, “Next: remote HDK derivation for batch issuance”.
This BL abstraction would make defining HDK less awkward indeed. The only disadvantage seems to be exposing a new datatype for blinding keys. The change however does not seem to leak new sensitive information to users, since BL already exposed private keys. I would like to keep the abstraction consistent with ARKG – is it feasible to update ARKG accordingly? I‘d just propose some minor changes:
Would BL-Combine-Blinding-Keys(a, b) not always equal BL-Blind-Private-Key(a, b) in practice? Or is this just the case for elliptic curves?
I like this simplification. Note that HDK-Derive-Private-Key may still not be needed as the blinded private key is never used directly. And instead of HDK-Derive-Public-Key, how about HDK-Blind-Public-Key, to better reflect what operation happens?
This would break compatibility with ARKG no? The current HDK design enables sharing the public HDK-Seed-Remote output with an issuer, who can then perform ARKG-Derive-Public-Key on it without needing to know that HDK was applied. If we drop this compatibility goal, indeed the issuer could just generate new blinding keys and pass these along with the issued attestations. But note that the wallet must then call BL-Combine-Blinding-Keys to obtain the blinding key relative to Edit 2024-09-16: If we go this path, I would still argue for keeping using a KEM as in ARKG to pass on the blinding key, to ensure that only the issuer and the wallet learn it, and not some proxy in between. Once blinding keys are exposed, the original device public key can be used for correlation.
This does not seem to be a problem:
It would not make a difference for proof of assocation since association is transitive. It seems to make it easier to model the ARKG-compatible structure of blinding keys. At each node it is possible to create a unique HDK-Seed-Remote output (achieving unlinkability) and derive child nodes using issuer-provided ARKG key handles. In BIP32 it seems to be used to have cross-wallet standardisation that makes it easier to recover an account structure using just a seed. This goal seems less relevant to EUDI. |
I wrote:
But I just realise that in draft-irtf-cfrg-signature-key-blinding-06, the blinding key We still need to decide whether to keep using algebraic |
Sketch for HDK dropping ARKG compatibility and with hierarchies only based on remote key handles: def HDK-Root(pk_device, seed):
msg = KMS-Serialize(pk_device)
ctx = ID || 0x00 || seed
salt = expand(msg, ctx, Ns)
return salt
def HDK-Delegate(seed, salt):
ctx = ID || 0x01 || seed
(pk_kem, _) = KEM-Derive-Key-Pair(salt, ctx)
return pk_kem
def HDK-Take(seed, salt, kh):
ctx = ID || 0x01 || seed
(_, sk_kem) = KEM-Derive-Key-Pair(salt, ctx)
bk = KEM-Decaps(sk_kem, kh, ctx)
return bk
def HDK-Yield(bk, idx):
msg = bk || I2OSP(idx, 4)
ctx = ID || 0x02
okm = expand(msg, ctx, Nk + Ns)
bf = factor(okm[:Nk])
salt = okm[Nk:]
return (bf, salt)
def HDK-Fold(pk_device, seed, path):
salt = HDK-Root(pk_device, seed)
def callback((bf, salt), (kh, idx)):
bk = HDK-Take(seed, salt, kh)
(bf', salt') = HDK-Yield(bk, idx)
bf'' = bf match:
case nil -> bf'
case bf -> BL-Combine-Blinding-Factors(bf, bf')
return (bf'', salt')
(bf, salt') = reduce(path, callback, (nil, salt))
return (bf, salt')
# Or recursively, and it can probably be made clearer:
def HDK-Fold(pk_device, seed, path):
salt = HDK-Root(pk_device, seed)
(kh, idx) :: tail = path
bk = HDK-Take(seed, salt, kh)
(bf, salt') = HDK-Yield(bk, idx)
def fold(path, salt, path):
path match:
case nil ->
return (bf, salt)
case (kh, idx) :: tail ->
bk = HDK-Take(seed, salt, kh)
(bf', salt') = HDK-Yield(bk, idx)
bf' = BL-Combine-Blinding-Factors(bf, bf')
return fold(tail, bf', salt')
return fold(tail, bf, salt') A document issuer would take a The WSCA would expose a function ARKG could be made compatible by adopting the algebraic BL structure. What do you think? |
Update: from the perspective of HDK, focus on the FIDO |
Here are some of my lightly-organized thoughts that were discussed on the 2024-09-02 call. Posting here as promised for record and for further consideration. These musings mostly arise from the initial question of why Derive-Local and Derive-Remote need to be distinct.
Does HDK-Root really need to be distinct from HDK-Derive-Local?
Could HDK-Root(pk_device, seed) = HDK-Derive-Local((pk_device, sk_device, seed), 0) ?
[Discussed on 2024-09-02 call: The distinction may not be strictly necessary, but it's useful to only need to inject the root public key once.]
I still don't really get why HDK makes a difference between HDK-Root and HDK-Derive-Local,
Multi-party sequence diagrams could greatly help illustrate how the pieces fit together.
Oooh, the
sk
output from HDK-Derive-Local isn't actually the private key corresponding topk
, just a shard (blinding factor) of it?In that case it's been very confusing to me to call it
sk
instead of "blinding factor" or "key handle" or something like that.Perhaps the hierarchy could be remodeled from a tree of (pk, sk) pairs to a tree of blinding factors?
HDK-Derive-Local (re-)blinds both pk and sk with the same factor simultaneously.
So maybe an appropriate abstraction for the blinding scheme could be something like:
BL-Generate-Keypair() -> (pk, sk)
BL-Derive-Blinding-Factor(seed, DST) -> tau
BL-Blind-Public-Key(pk, tau) -> pk'
BL-Blind-Private-Key(sk, tau) -> sk'
BL-Combine-Blinding-Factors(tau1, tau2) -> tau'
Compute
tau'
such thatBL-Blind-Public-Key(pk, tau') = BL-Blind-Public-Key(BL-Blind-Public-Key(pk, tau1), tau2)
and
BL-Blind-Private-Key(sk, tau') = BL-Blind-Private-Key(BL-Blind-Private-Key(sk, tau1), tau2)
Can't include the DST in Blind-Public-Key/Blind-Private-Key anymore, since that would break the algebra.
tau becomes a BL-specific type (scalars in the EC case) instead of arbitrary octet strings.
Anyway, with this abstraction, I think the HDK tree could be something like:
Maybe the distinction between Derive-Local and Derive-Remote disappears? I don't think the taus really need to be kept secret?
Not sure how this would interact with HDK-Authenticate, though. Maybe this makes it harder to implement the blinding using ECDH for multiplication, for example?
What is the advantage of the hierarchical tree structure?
What capabilities does this introduce that you don't get with just a single level of blinded keys?
[Discussed on 2024-09-02 call: Might enable some selective proofs of association that aren't as straightforward in a flat structure?]
The text was updated successfully, but these errors were encountered: