Skip to content
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

[NayNay] Sign takes a verifying key now #382

Merged
merged 18 commits into from
Jun 25, 2024
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions src/index.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { ApiPromise, WsProvider } from '@polkadot/api'
import { debug, isValidSubstrateAddress } from './utils'
import RegistrationManager, { RegistrationParams } from './registration'
import SignatureRequestManager, { SigOps, SigWithAdapptersOps } from './signing'
import SignatureRequestManager, { SigOps, SigWithAdaptersOps } from './signing'
import { crypto, loadCryptoLib } from './utils/crypto'
import { Adapter } from './signing/adapters/types'
import ProgramManager from './programs'
Expand Down Expand Up @@ -152,12 +152,12 @@ export default class Entropy {
/**
* Signs a given transaction based on the provided parameters using the appropriate adapter.
*
* @param {SigWithAdapptersOps} params - The parameters for signing the transaction.
* @param {SigWithAdaptersOps} params - The parameters for signing the transaction.
* @returns {Promise<unknown>} A promise that resolves to the transaction signature.
* @throws {Error} If no adapter is found for the specified transaction type.
*/

async signWithAdaptersInOrder (params: SigWithAdapptersOps): Promise<unknown> {
async signWithAdaptersInOrder (params: SigWithAdaptersOps): Promise<unknown> {
(await this.ready) && this.substrate.isReady
return await this.signingManager.signWithAdaptersInOrder(params)
}
Expand Down
43 changes: 26 additions & 17 deletions src/signing/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,15 +25,18 @@ export interface SigMsgOps {
type?: string
}

export interface SigWithAdapptersOps extends SigMsgOps {
export interface SigWithAdaptersOps extends SigMsgOps {
order: string[]
signatureVerifyingKey?: string
}

export interface SigOps {
sigRequestHash: string
hash: string
// hashing algorigthm will not always be a string, i.e faucet hash algo is {cutom:0}
hash: any
rh0delta marked this conversation as resolved.
Show resolved Hide resolved
type?: string
auxiliaryData?: unknown[]
signatureVerifyingKey?: string
}

/**
Expand All @@ -45,7 +48,7 @@ export interface UserSignatureRequest {
auxilary_data?: any
validatorsInfo: ValidatorInfo[]
timestamp: { secs_since_epoch: number; nanos_since_epoch: number }
hash: string
hash: any
signature_verifying_key: number[]
}

Expand Down Expand Up @@ -104,25 +107,24 @@ export default class SignatureRequestManager {
return key
}

/*



/**
DO NOT DELET THIS CODE BLOCK!

Signs a message using the appropriate adapter.

@param {SigMsgOps} params - The message and type for signing.
@param {TxParams} SigMsgOps.txParams - The parameters of the transaction to be signed.
@param {string} [sigTxOps.type] - The type of transaction.
@returns {Promise<unknown>} A promise resolving with the signed transaction.
@param {SigWithAdaptersOps} sigWithAdaptersOps - Parameters for the signature operation
@param {MsgParams} sigWithAdaptersOps.msg - object containing the msg hex string to be sign, in the shape of { msg: string }
@param {string[]} sigWithAdaptersOps.order - array containing the names of adapters in the expected order ['deviceKeyProxy', 'noop']
@param {string} sigWithAdaptersOps.signatureVerifyingKey - verifying key that can be supplied by the user to overwrite the verifying key used from the keyring
@returns {Promise<unknown>} A promise resolving with the signature.
@throws {Error} If no adapter or preSign function is found for the given type.
*/

async signWithAdaptersInOrder ({
msg,
order,
}: SigWithAdapptersOps): Promise<unknown> {
signatureVerifyingKey
}: SigWithAdaptersOps): Promise<unknown> {
if (!order) {
throw new Error(
`must provide order: expecting a string[] of adapter types got: ${order}`
Expand All @@ -142,7 +144,7 @@ export default class SignatureRequestManager {
}
return agg
}, [])
// const { sigRequestHash, auxilary_data } = await

rh0delta marked this conversation as resolved.
Show resolved Hide resolved
const results = await Promise.all(
adaptersToRun.map((adapter) => {
return adapter.preSign(this.signer, msg)
Expand All @@ -161,6 +163,7 @@ export default class SignatureRequestManager {
sigRequestHash,
hash: adaptersToRun[0].HASHING_ALGORITHM,
auxiliaryData,
signatureVerifyingKey,
})
return signature
}
Expand All @@ -170,25 +173,31 @@ export default class SignatureRequestManager {
*
* @param {SigOps} sigOps - Parameters for the signature operation.
* @param {string} sigOps.sigRequestHash - The hash of the signature request to be signed.
* @param {string} [sigOps.hash] - The hash type.
* @param {unknown[]} [sigOps.auxilaryData] - Additional data for the signature operation.
* @param {signatureVerifyingKey} signatureVerifyingKey - The verifying key for the signature requested
* @param {any} sigOps.hash - The name of the hashing algorithm used to hash the signature.
rh0delta marked this conversation as resolved.
Show resolved Hide resolved
rh0delta marked this conversation as resolved.
Show resolved Hide resolved
* @param {unknown[]} sigOps.auxilaryData - Additional data for the signature operation.
* @param {signatureVerifyingKey} sigOps.signatureVerifyingKey - The verifying key for the signature requested
* @returns {Promise<Uint8Array>} A promise resolving to the signed hash as a Uint8Array.
*/

async sign ({
sigRequestHash,
hash,
auxiliaryData,
signatureVerifyingKey: signatureVerifyingKeyOverwrite,
rh0delta marked this conversation as resolved.
Show resolved Hide resolved
}: SigOps): Promise<Uint8Array> {
const strippedsigRequestHash = stripHexPrefix(sigRequestHash)
const validatorsInfo: Array<ValidatorInfo> = await this.pickValidators(
strippedsigRequestHash
)
// @frankie is this comment still valid?
mixmix marked this conversation as resolved.
Show resolved Hide resolved
// TO-DO: this needs to be and accounId ie hex string of the address
// which means you need a new key ie device key here

const signatureVerifyingKey = this.verifyingKey
// The need to overwrite the signature verifying key in certain cases is for when
// the program being used to sign a message may require a different verifying key than
// that is generated by the keyring. An example of this is available in the faucet flow within
// Entropy CLI.
const signatureVerifyingKey = signatureVerifyingKeyOverwrite || this.verifyingKey

const txRequests: Array<EncMsg> = await this.formatTxRequests({
strippedsigRequestHash,
Expand Down
60 changes: 60 additions & 0 deletions tests/sign.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import {
spinNetworkUp,
spinNetworkDown,
charlieStashSeed,
charlieSeed,
} from './testing-utils'

const NETWORK_TYPE = 'two-nodes'
Expand Down Expand Up @@ -55,3 +56,62 @@ test('Sign', async (t) => {

t.end()
})

test('Sign: Inputted Verifying Keys', async (t) => {
const run = promiseRunner(t)

/* Setup Network */
await run('network up', spinNetworkUp(NETWORK_TYPE))
await sleep(process.env.GITHUB_WORKSPACE ? 30_000 : 5_000)
t.teardown(async () => {
// this gets called after all tests are run
await charlieStashEntropy.close()
await charlieEntropy.close()
await spinNetworkDown(NETWORK_TYPE).catch((error) =>
console.error('Error while spinning network down', error.message)
)
})

/* Setup Entropy */
await run('wasm', wasmGlobalsReady())
const charlieStashKeyring = new Keyring({ seed: charlieStashSeed, debug: true })
const charlieKeyring = new Keyring({ seed: charlieSeed, debug: true })
rh0delta marked this conversation as resolved.
Show resolved Hide resolved
const charlieStashEntropy = new Entropy({
keyring: charlieStashKeyring,
endpoint: 'ws://127.0.0.1:9944',
})
const charlieEntropy = new Entropy({
keyring: charlieKeyring,
endpoint: 'ws://127.0.0.1:9944',
})

await Promise.all([
run('charlieStashEntropy ready', charlieStashEntropy.ready),
run('charlieEntropy ready', charlieEntropy.ready)
])
await Promise.all([
run('charlie stash register', charlieStashEntropy.register()),
run('charlie register', charlieEntropy.register())
])

/* Sign */
const msg = Buffer
.from('Hello world: new signature from charlieStashEntropy!')
.toString('hex')

const signature = await run(
'sign',
charlieStashEntropy.signWithAdaptersInOrder({
msg: { msg },
order: ['deviceKeyProxy'],
// no rhyme or reason for the choice of using the charlie seed verifying key, needed to use
// a pre-loaded acct on our local devnet in order to get a valid verifying key
signatureVerifyingKey: charlieEntropy.keyring.accounts.deviceKey.verifyingKeys[0]
})
)

t.true(signature && signature.length > 32, 'signature has some body!')
signature && console.log(signature)

t.end()
})
Loading