-
Notifications
You must be signed in to change notification settings - Fork 71
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
Developing a Signer for P-256. (work in progress) #212
Changes from 43 commits
01cad8d
3665f66
b63394e
fc6dbbf
11583f6
28dd20b
a5c3cd9
bdc2bdb
d8a66f9
31ab707
4ccb1dd
4397a49
5ef3a89
fdbbfd7
75dc01b
369c419
f936324
c06dc4b
eda4633
d4c194b
45d2df8
4cc5bff
cc6e4ec
933a4ff
920ad85
831e0f0
09b50a9
5cf650b
8a38bb4
e3fa780
ace72fa
a4afd07
07c0be9
4aaf7a5
4fc2dbd
3190cf9
dc04d0c
03e8e52
8294a6b
3a65a2a
252688c
164537b
7c881f1
260e214
f9d8aba
aef3643
764f89f
05e883f
b768725
0b2f18c
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
import { EcdsaSignature } from '../util' | ||
|
||
// eslint-disable-next-line @typescript-eslint/no-explicit-any | ||
export function instanceOfEcdsaSignature(object: any): object is EcdsaSignature { | ||
return typeof object === 'object' && 'r' in object && 's' in object | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
import { Signer, SignerAlgorithm } from '../JWT' | ||
import { EcdsaSignature, fromJose, toJose } from '../util' | ||
import * as CommonSignerAlg from './CommonSignerAlg' | ||
|
||
export function ES256KSignerAlg(recoverable?: boolean): SignerAlgorithm { | ||
return async function sign(payload: string, signer: Signer): Promise<string> { | ||
const signature: EcdsaSignature | string = await signer(payload) | ||
if (CommonSignerAlg.instanceOfEcdsaSignature(signature)) { | ||
return toJose(signature, recoverable) | ||
} else { | ||
if (recoverable && typeof fromJose(signature).recoveryParam === 'undefined') { | ||
throw new Error(`not_supported: ES256K-R not supported when signer doesn't provide a recovery param`) | ||
} | ||
return signature | ||
} | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
import { Signer, SignerAlgorithm } from '../JWT' | ||
import { EcdsaSignature, fromJose, toJose } from '../util' | ||
import * as CommonSignerAlg from './CommonSignerAlg' | ||
|
||
export function ES256SignerAlg(recoverable?: boolean): SignerAlgorithm { | ||
return async function sign(payload: string, signer: Signer): Promise<string> { | ||
const signature: EcdsaSignature | string = await signer(payload) | ||
if (CommonSignerAlg.instanceOfEcdsaSignature(signature)) { | ||
return toJose(signature, recoverable) | ||
} else { | ||
if (recoverable && typeof fromJose(signature).recoveryParam === 'undefined') { | ||
throw new Error(`not_supported: ES256-R not supported when signer doesn't provide a recovery param`) | ||
} | ||
return signature | ||
} | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
import { Signer, SignerAlgorithm } from '../JWT' | ||
import { EcdsaSignature } from '../util' | ||
import * as CommonSignerAlg from './CommonSignerAlg' | ||
|
||
export function Ed25519SignerAlg(): SignerAlgorithm { | ||
return async function sign(payload: string, signer: Signer): Promise<string> { | ||
const signature: EcdsaSignature | string = await signer(payload) | ||
if (!CommonSignerAlg.instanceOfEcdsaSignature(signature)) { | ||
return signature | ||
} else { | ||
throw new Error('invalid_config: expected a signer function that returns a string instead of signature object') | ||
} | ||
} | ||
} |
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
@@ -1,49 +1,25 @@ | ||||||
import { Signer, SignerAlgorithm } from './JWT' | ||||||
import { EcdsaSignature, fromJose, toJose } from './util' | ||||||
import { SignerAlgorithm } from './JWT' | ||||||
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any | ||||||
function instanceOfEcdsaSignature(object: any): object is EcdsaSignature { | ||||||
return typeof object === 'object' && 'r' in object && 's' in object | ||||||
} | ||||||
|
||||||
export function ES256KSignerAlg(recoverable?: boolean): SignerAlgorithm { | ||||||
return async function sign(payload: string, signer: Signer): Promise<string> { | ||||||
const signature: EcdsaSignature | string = await signer(payload) | ||||||
if (instanceOfEcdsaSignature(signature)) { | ||||||
return toJose(signature, recoverable) | ||||||
} else { | ||||||
if (recoverable && typeof fromJose(signature).recoveryParam === 'undefined') { | ||||||
throw new Error(`not_supported: ES256K-R not supported when signer doesn't provide a recovery param`) | ||||||
} | ||||||
return signature | ||||||
} | ||||||
} | ||||||
} | ||||||
import * as ES256KSignerAlg from './SignerAlg/ES256KSignerAlg' | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. These imports can be rephrased as:
Suggested change
and then the code below is simplified as well There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Understandable. It might have a bit to do with how my mind was working. I grasped things as, and after, I worked through them. I realize it was a huge refactor. It seemed necessary as otherwise the files were getting to get huge combining multiple signers and it would be hard to follow. I told Joel (@ oed) that I was trying to figure things out for my particular project. I need a remote signer over a radio connection. I see mention of constructing a remote signer. I went ahead and added ES256 and walked through the library so I'd have it if I need it when bringing in https://github.com/decentralized-identity/did-jwt-vc later. I'm also trying to build something like this (https://github.com/ceramicnetwork/key-did-provider-ed25519) but for a remote signer and with the P-256 curve (because I'm using a cryptographic co-processor that only provides this curve https://github.com/sparkfun/SparkFun_ATECCX08a_Arduino_Library). Yeah, I was kind of aggressive with my commit. I think I have a got to get this done mentality. I've been working on a particular (presently unfunded/hobby/or whatever project) for over a year, and get onto myself for not making enough progress to be successful with it. To my knowledge, adding NIST curves is not a big ceramic/3box initiative (they're focusing on scaling I think now). I ask questions from time to time, and I see this effort as the other half to js-ceramic/key-did-resolver. (https://github.com/ceramicnetwork/js-ceramic/tree/develop/packages/key-did-resolver/src) . I think this eventually got into the repo because I was relentless and they wanted to support active projects going for their ceramic mainnet initiative. I'll be patient. Maybe in time I'll discover that I did some work that did not need to be done. I realize other people have to deal with what I put out. Maybe I'm at a point where I can talk intelligently about it, if I did not realize before... apologies ... fwiw, right now I'm looking at blockchain/cosmos.ts .... I'm trying to pull in a function that will default to secp256k1 , but will also allow for (P-256) secp256r1 because the publicKey needs to be compressed before construction in the rest of the function. fwiw, the test files were broken up into smaller files, and parts of them were cloned (swapping the secp256r1 curve for the secp256k1 curve) Again understandable... (+41,203 −9,451 ) is a huge change for a well used library. It kind of seemed like having fun on some trip, but then later getting the credit card bill. Since I am presently in busy beaver mode I'm sure I'll find some other things to do so no worries if you've got some other things to do as well (which I expect). Edit: for the sake of transparency I reached out via e-mail to @kimdhamilton because I felt new to typescript and good code quality and this library and verifiable credentials specialization. We seem to get along well, but I'm not sure I should have done that privately. I think she uses this library in some of her other work, however I am not sure if she's ever reviewed or built on it before. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. no need to apologise :) The bill of changes will be reduced once you remove It might not be worth trying to adapt the blockchain/cosmos bits since AFAIK there is no use of P-256 on the blockchains involved, only secp256k. Still, there is very much to review, and it will take very long. |
||||||
import * as Ed25519SignerAlg from './SignerAlg/Ed25519SignerAlg' | ||||||
|
||||||
export function Ed25519SignerAlg(): SignerAlgorithm { | ||||||
return async function sign(payload: string, signer: Signer): Promise<string> { | ||||||
const signature: EcdsaSignature | string = await signer(payload) | ||||||
if (!instanceOfEcdsaSignature(signature)) { | ||||||
return signature | ||||||
} else { | ||||||
throw new Error('invalid_config: expected a signer function that returns a string instead of signature object') | ||||||
} | ||||||
} | ||||||
} | ||||||
import * as ES256SignerAlg from './SignerAlg/ES256SignerAlg' | ||||||
|
||||||
interface SignerAlgorithms { | ||||||
[alg: string]: SignerAlgorithm | ||||||
} | ||||||
|
||||||
const algorithms: SignerAlgorithms = { | ||||||
ES256K: ES256KSignerAlg(), | ||||||
ES256: ES256SignerAlg.ES256SignerAlg(), | ||||||
'ES256-R': ES256SignerAlg.ES256SignerAlg(true), | ||||||
ES256K: ES256KSignerAlg.ES256KSignerAlg(), | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. With the above suggestion, this would simplify to:
Suggested change
|
||||||
// This is a non-standard algorithm but retained for backwards compatibility | ||||||
// see https://github.com/decentralized-identity/did-jwt/issues/146 | ||||||
'ES256K-R': ES256KSignerAlg(true), | ||||||
'ES256K-R': ES256KSignerAlg.ES256KSignerAlg(true), | ||||||
// This is actually incorrect but retained for backwards compatibility | ||||||
// see https://github.com/decentralized-identity/did-jwt/issues/130 | ||||||
Ed25519: Ed25519SignerAlg(), | ||||||
EdDSA: Ed25519SignerAlg(), | ||||||
Ed25519: Ed25519SignerAlg.Ed25519SignerAlg(), | ||||||
EdDSA: Ed25519SignerAlg.Ed25519SignerAlg(), | ||||||
} | ||||||
|
||||||
function SignerAlg(alg: string): SignerAlgorithm { | ||||||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,59 @@ | ||
import { ec as EC } from 'elliptic' | ||
import type { VerificationMethod } from 'did-resolver' | ||
import { bases } from 'multiformats/basics' | ||
import { hexToBytes, base58ToBytes, base64ToBytes, bytesToHex, EcdsaSignature } from '../util' | ||
|
||
const secp256k1 = new EC('secp256k1') | ||
const secp256r1 = new EC('p256') | ||
|
||
// converts a JOSE signature to it's components | ||
export function toSignatureObject(signature: string, recoverable = false): EcdsaSignature { | ||
const rawSig: Uint8Array = base64ToBytes(signature) | ||
if (rawSig.length !== (recoverable ? 65 : 64)) { | ||
throw new Error('wrong signature length') | ||
} | ||
const r: string = bytesToHex(rawSig.slice(0, 32)) | ||
const s: string = bytesToHex(rawSig.slice(32, 64)) | ||
const sigObj: EcdsaSignature = { r, s } | ||
if (recoverable) { | ||
sigObj.recoveryParam = rawSig[64] | ||
} | ||
return sigObj | ||
} | ||
|
||
interface LegacyVerificationMethod extends VerificationMethod { | ||
publicKeyBase64: string | ||
} | ||
|
||
export function extractPublicKeyBytes(pk: VerificationMethod): Uint8Array { | ||
if (pk.publicKeyBase58) { | ||
return base58ToBytes(pk.publicKeyBase58) | ||
} else if ((<LegacyVerificationMethod>pk).publicKeyBase64) { | ||
return base64ToBytes((<LegacyVerificationMethod>pk).publicKeyBase64) | ||
} else if (pk.publicKeyHex) { | ||
return hexToBytes(pk.publicKeyHex) | ||
} else if (pk.publicKeyJwk && pk.publicKeyJwk.crv === 'secp256k1' && pk.publicKeyJwk.x && pk.publicKeyJwk.y) { | ||
return hexToBytes( | ||
secp256k1 | ||
.keyFromPublic({ | ||
x: bytesToHex(base64ToBytes(pk.publicKeyJwk.x)), | ||
y: bytesToHex(base64ToBytes(pk.publicKeyJwk.y)), | ||
}) | ||
.getPublic('hex') | ||
) | ||
} else if (pk.publicKeyJwk && pk.publicKeyJwk.crv === 'P-256' && pk.publicKeyJwk.x && pk.publicKeyJwk.y) { | ||
return hexToBytes( | ||
secp256r1 | ||
.keyFromPublic({ | ||
x: bytesToHex(base64ToBytes(pk.publicKeyJwk.x)), | ||
y: bytesToHex(base64ToBytes(pk.publicKeyJwk.y)), | ||
}) | ||
.getPublic('hex') | ||
) | ||
} else if (pk.publicKeyMultibase) { | ||
const { base16, base58btc, base64, base64url } = bases | ||
const baseDecoder = base16.decoder.or(base58btc.decoder.or(base64.decoder.or(base64url.decoder))) | ||
return baseDecoder.decode(pk.publicKeyMultibase) | ||
} | ||
return new Uint8Array() | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,91 @@ | ||
import { ec as EC, SignatureInput } from 'elliptic' | ||
import { sha256, toEthereumAddress } from '../Digest' | ||
import type { VerificationMethod } from 'did-resolver' | ||
import { bytesToHex, EcdsaSignature } from '../util' | ||
import { verifyBlockchainAccountId } from '../blockchains' | ||
import * as CommonVerifierAlg from './CommonVerifierAlg' | ||
|
||
const secp256k1 = new EC('secp256k1') | ||
|
||
/* | ||
interface LegacyVerificationMethod extends VerificationMethod { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I prefer this simple extension of the publicly defined type as opposed to redefining the interfaces all together. |
||
publicKeyBase64: string | ||
} | ||
*/ | ||
|
||
export function verifyES256K( | ||
data: string, | ||
signature: string, | ||
authenticators: VerificationMethod[] | ||
): VerificationMethod { | ||
const hash: Uint8Array = sha256(data) | ||
const sigObj: EcdsaSignature = CommonVerifierAlg.toSignatureObject(signature) | ||
const fullPublicKeys = authenticators.filter(({ ethereumAddress, blockchainAccountId }) => { | ||
return typeof ethereumAddress === 'undefined' && typeof blockchainAccountId === 'undefined' | ||
}) | ||
const blockchainAddressKeys = authenticators.filter(({ ethereumAddress, blockchainAccountId }) => { | ||
return typeof ethereumAddress !== 'undefined' || typeof blockchainAccountId !== 'undefined' | ||
}) | ||
|
||
let signer: VerificationMethod | undefined = fullPublicKeys.find((pk: VerificationMethod) => { | ||
try { | ||
const pubBytes = CommonVerifierAlg.extractPublicKeyBytes(pk) | ||
return secp256k1.keyFromPublic(pubBytes).verify(hash, <SignatureInput>sigObj) | ||
} catch (err) { | ||
return false | ||
} | ||
}) | ||
|
||
if (!signer && blockchainAddressKeys.length > 0) { | ||
signer = verifyRecoverableES256K(data, signature, blockchainAddressKeys) | ||
} | ||
|
||
if (!signer) throw new Error('invalid_signature: Signature invalid for JWT') | ||
return signer | ||
} | ||
|
||
export function verifyRecoverableES256K( | ||
data: string, | ||
signature: string, | ||
authenticators: VerificationMethod[] | ||
): VerificationMethod { | ||
let signatures: EcdsaSignature[] | ||
if (signature.length > 86) { | ||
signatures = [CommonVerifierAlg.toSignatureObject(signature, true)] | ||
} else { | ||
const so = CommonVerifierAlg.toSignatureObject(signature, false) | ||
signatures = [ | ||
{ ...so, recoveryParam: 0 }, | ||
{ ...so, recoveryParam: 1 }, | ||
] | ||
} | ||
|
||
const checkSignatureAgainstSigner = (sigObj: EcdsaSignature): VerificationMethod | undefined => { | ||
const hash: Uint8Array = sha256(data) | ||
// eslint-disable-next-line @typescript-eslint/no-explicit-any | ||
const recoveredKey: any = secp256k1.recoverPubKey(hash, <SignatureInput>sigObj, <number>sigObj.recoveryParam) | ||
const recoveredPublicKeyHex: string = recoveredKey.encode('hex') | ||
const recoveredCompressedPublicKeyHex: string = recoveredKey.encode('hex', true) | ||
const recoveredAddress: string = toEthereumAddress(recoveredPublicKeyHex) | ||
|
||
const signer: VerificationMethod | undefined = authenticators.find((pk: VerificationMethod) => { | ||
const keyHex = bytesToHex(CommonVerifierAlg.extractPublicKeyBytes(pk)) | ||
return ( | ||
keyHex === recoveredPublicKeyHex || | ||
keyHex === recoveredCompressedPublicKeyHex || | ||
pk.ethereumAddress?.toLowerCase() === recoveredAddress || | ||
pk.blockchainAccountId?.split('@eip155')?.[0].toLowerCase() === recoveredAddress || // CAIP-2 | ||
verifyBlockchainAccountId(recoveredPublicKeyHex, pk.blockchainAccountId) // CAIP-10 | ||
) | ||
}) | ||
|
||
return signer | ||
} | ||
|
||
const signer: VerificationMethod[] = signatures | ||
.map(checkSignatureAgainstSigner) | ||
.filter((key) => typeof key !== 'undefined') as VerificationMethod[] | ||
|
||
if (signer.length === 0) throw new Error('invalid_signature: Signature invalid for JWT') | ||
return signer[0] | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,87 @@ | ||
import { ec as EC, SignatureInput } from 'elliptic' | ||
import { sha256, toEthereumAddress } from '../Digest' | ||
import type { VerificationMethod } from 'did-resolver' | ||
import { bytesToHex, EcdsaSignature } from '../util' | ||
import { verifyBlockchainAccountId } from '../blockchains' | ||
import * as CommonVerifierAlg from './CommonVerifierAlg' | ||
|
||
const secp256r1 = new EC('p256') | ||
|
||
/* | ||
interface LegacyVerificationMethod extends VerificationMethod { | ||
publicKeyBase64: string | ||
} | ||
*/ | ||
|
||
export function verifyES256(data: string, signature: string, authenticators: VerificationMethod[]): VerificationMethod { | ||
const hash: Uint8Array = sha256(data) | ||
const sigObj: EcdsaSignature = CommonVerifierAlg.toSignatureObject(signature) | ||
const fullPublicKeys = authenticators.filter(({ ethereumAddress, blockchainAccountId }) => { | ||
return typeof ethereumAddress === 'undefined' && typeof blockchainAccountId === 'undefined' | ||
}) | ||
const blockchainAddressKeys = authenticators.filter(({ ethereumAddress, blockchainAccountId }) => { | ||
return typeof ethereumAddress !== 'undefined' || typeof blockchainAccountId !== 'undefined' | ||
}) | ||
|
||
let signer: VerificationMethod | undefined = fullPublicKeys.find((pk: VerificationMethod) => { | ||
try { | ||
const pubBytes = CommonVerifierAlg.extractPublicKeyBytes(pk) | ||
return secp256r1.keyFromPublic(pubBytes).verify(hash, <SignatureInput>sigObj) | ||
} catch (err) { | ||
return false | ||
} | ||
}) | ||
|
||
if (!signer && blockchainAddressKeys.length > 0) { | ||
signer = verifyRecoverableES256(data, signature, blockchainAddressKeys) | ||
} | ||
|
||
if (!signer) throw new Error('invalid_signature: Signature invalid for JWT') | ||
return signer | ||
} | ||
|
||
export function verifyRecoverableES256( | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is probably not needed since ES256-R is not needed There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. agreed, ES256-R is not and probably will never be a thing.... ES256K-R is a thing already... even though it remains unregistered... I would discourage adding more "registered stuff" here. |
||
data: string, | ||
signature: string, | ||
authenticators: VerificationMethod[] | ||
): VerificationMethod { | ||
let signatures: EcdsaSignature[] | ||
if (signature.length > 86) { | ||
signatures = [CommonVerifierAlg.toSignatureObject(signature, true)] | ||
} else { | ||
const so = CommonVerifierAlg.toSignatureObject(signature, false) | ||
signatures = [ | ||
{ ...so, recoveryParam: 0 }, | ||
{ ...so, recoveryParam: 1 }, | ||
] | ||
} | ||
|
||
const checkSignatureAgainstSigner = (sigObj: EcdsaSignature): VerificationMethod | undefined => { | ||
const hash: Uint8Array = sha256(data) | ||
// eslint-disable-next-line @typescript-eslint/no-explicit-any | ||
const recoveredKey: any = secp256r1.recoverPubKey(hash, <SignatureInput>sigObj, <number>sigObj.recoveryParam) | ||
const recoveredPublicKeyHex: string = recoveredKey.encode('hex') | ||
const recoveredCompressedPublicKeyHex: string = recoveredKey.encode('hex', true) | ||
const recoveredAddress: string = toEthereumAddress(recoveredPublicKeyHex) | ||
|
||
const signer: VerificationMethod | undefined = authenticators.find((pk: VerificationMethod) => { | ||
const keyHex = bytesToHex(CommonVerifierAlg.extractPublicKeyBytes(pk)) | ||
return ( | ||
keyHex === recoveredPublicKeyHex || | ||
keyHex === recoveredCompressedPublicKeyHex || | ||
pk.ethereumAddress?.toLowerCase() === recoveredAddress || | ||
pk.blockchainAccountId?.split('@eip155')?.[0].toLowerCase() === recoveredAddress || // CAIP-2 | ||
verifyBlockchainAccountId(recoveredPublicKeyHex, pk.blockchainAccountId) // CAIP-10 | ||
) | ||
}) | ||
|
||
return signer | ||
} | ||
|
||
const signer: VerificationMethod[] = signatures | ||
.map(checkSignatureAgainstSigner) | ||
.filter((key) => typeof key !== 'undefined') as VerificationMethod[] | ||
|
||
if (signer.length === 0) throw new Error('invalid_signature: Signature invalid for JWT') | ||
return signer[0] | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is
ES256-R
really needed? Afaik no one uses this?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It clearly seemed like a non-standard key type. Adding a recoverySigner was a "oh why not" kind of thing. However, 'ES256-K' was a use your own discretion kind of thing (reference: #146) and I suppose 'ES256-R' would be as well if included. I'd need to know the logic behind having it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I agree with @oed,
ES256-R
is not needed.ES256K-R
existed as a pattern and was in use before it got a name.It exists now to allow for
blockchainAccountId
verification methods to be used as verifiers.We could probably phase it out of existence if we accept 1 bit less of security for ES256K + blockchainAccountId
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Okay, I have the code for ES256-R. I can archive it for now, and reconsider it later. (?) The reason for this PR was to support something like https://github.com/bshambaugh/key-did-provider-p256/blob/master/src/index.ts . This is a non-functional sketch (at the moment) to support EIP-2844 (https://eips.ethereum.org/EIPS/eip-2844) . At the EthDenver Hackathon I heard about https://f-o-a-m.github.io/foam.developer/foamlite/end-node.html which mentions use of a recovery method that grabs the public key based on a signature. (I discovered that they are also using LoRa.) I literally just read this 5 or 10 minutes ago so I am not educated in the use nor in foam. I think that their protocol is even lower level than what I am attempting.
https://www.youtube.com/watch?v=Z8Wf7Srsg5U&t=50m20s is a Ceramic Community Call that mentions Joel's (oed's) introduction of EIP-2844 to my problem which sent me down this road. Since this (described in the Call) is a preexisting project I may not apply it (or may not be allowed to) to the EthDenver hackathon. In the next week or so, as the hackathon event rolls up, I may in fact try something else, which could distract me from this PR started in January. For context, this is the project I was mentioning in the Community Call: https://github.com/bshambaugh/BlinkyProject .
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'll have to peruse the code to understand the context. Since Joel knows about what I have been up to, I assume I can just prune it out for now.