@laceio/sdk 0.1.1 → 0.1.2-canary.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{TransactionBuilder-DrB3NVTi.cjs → TransactionBuilder-CCjOn7NA.cjs} +42 -0
- package/dist/{TransactionBuilder-V6aLx4SV.js → TransactionBuilder-CIzdw18M.js} +1 -1
- package/dist/{_polyfill-buffer-patch-BnPVerlG.cjs → _polyfill-buffer-patch-CM8X7JiY.cjs} +21 -2
- package/dist/_polyfill-buffer-patch-yNxN4d5E.js +1467 -0
- package/dist/_web-crypto-random-bytes-Bo-GTcRS.js +197 -0
- package/dist/acc-module-4iIUv6My.cjs +27654 -0
- package/dist/acc-module-Cmj8EsIb.js +27624 -0
- package/dist/account-BOQruszJ.js +6 -0
- package/dist/account-BUOj4pYJ.cjs +11 -0
- package/dist/account-call-7wnopBq0.cjs +5 -0
- package/dist/account-call-B9d_2Xwi.js +4 -0
- package/dist/account-call-Bd4Rpbvt.cjs +323 -0
- package/dist/account-call-C3CkDqEC.js +276 -0
- package/dist/account-guards-BtjTGxDZ.cjs +42 -0
- package/dist/account-guards-D9Lu5T3W.js +36 -0
- package/dist/account-tokens-DvkOFVON.js +16 -0
- package/dist/account-tokens-nwcvwLu4.cjs +21 -0
- package/dist/{activity-type.stable-BJEfeLxL.cjs → activity-type-Ch6ljxBy.cjs} +2 -1
- package/dist/{activity-type.stable-C76_hWd7.js → activity-type-GsJGWs-3.js} +2 -1
- package/dist/address-B9ntKL8K.js +13761 -0
- package/dist/address-BXp-mY8H.cjs +11270 -0
- package/dist/{address-book-address-validator-DIUolI-s.js → address-book-address-validator-0J9XAADH.js} +2 -2
- package/dist/address-book-address-validator-DK0dnsRS.cjs +41 -0
- package/dist/address-book-address-validator-Di_ywo8M.js +39 -0
- package/dist/{address-book-address-validator-DNwQGlOB.cjs → address-book-address-validator-Dte_YQ2L.cjs} +2 -2
- package/dist/artefact-loader-BWWYAD7E.cjs +183 -0
- package/dist/artefact-loader-Dik4HIfv.js +160 -0
- package/dist/auto-dismiss-failure-on-success-C-qoJuid.cjs +37 -0
- package/dist/auto-dismiss-failure-on-success-s8MGDEIu.js +31 -0
- package/dist/bip32-D6wd_QMn.cjs +3851 -0
- package/dist/bitcoin-data-provider-BYPSmuZS.js +21 -0
- package/dist/bitcoin-data-provider-w1oEDSU3.cjs +26 -0
- package/dist/bitcoin.cjs +45 -0
- package/dist/bitcoin.d.ts +29906 -1
- package/dist/bitcoin.js +20 -0
- package/dist/{blockfrost-tx-submit-provider-DPTrapz-.js → blockfrost-tx-submit-provider-CBWQ0wK9.js} +5 -157
- package/dist/{blockfrost-tx-submit-provider-BAIzV5o3.cjs → blockfrost-tx-submit-provider-CLNQ5ycR.cjs} +3 -167
- package/dist/bn-d3nSOIf7.cjs +2553 -0
- package/dist/browser-B1eMbDwh.js +7468 -0
- package/dist/bytes.vo-BB7_4JK6.js +23 -0
- package/dist/bytes.vo-BNRquqaO.cjs +34 -0
- package/dist/cardano-DfPwhwm-.js +3 -0
- package/dist/{cardano-network-id.vo-DSxrFk9S.cjs → cardano-network-id.vo-BEDPn6Li.cjs} +1 -1
- package/dist/{cardano-network-id.vo-CK1tNQDg.js → cardano-network-id.vo-Cfpvbod9.js} +1 -1
- package/dist/cardano.cjs +22 -18
- package/dist/cardano.d.ts +16956 -1716
- package/dist/cardano.js +16 -11
- package/dist/client-DXBLHk7K.cjs +808 -0
- package/dist/codecs-Cswkg7Tm.cjs +4051 -0
- package/dist/codecs-Dc1Krpbt.js +3903 -0
- package/dist/{const-C84qHkjp.js → const-BJfIK_G-.js} +4 -4
- package/dist/const-BhYOdznB.cjs +42 -0
- package/dist/const-BsnjG2_Q.cjs +32071 -0
- package/dist/const-CUnCl5U0.js +13 -0
- package/dist/{const-DXk2tFyv.js → const-CjmfjBP3.js} +1 -1
- package/dist/{const-BDEg2Trq.cjs → const-D-eZIS4n.cjs} +4 -4
- package/dist/const-D0CbQlo4.js +154 -0
- package/dist/{const-BY8B3_0_.cjs → const-iwzZEE_w.cjs} +1 -1
- package/dist/contract-1R86jhSw.js +171 -0
- package/dist/contract-MKLzYVkW.cjs +189 -0
- package/dist/create-add-accounts-Brqk84vF.js +102 -0
- package/dist/create-add-accounts-DzXIh7Ot.cjs +114 -0
- package/dist/{delegation-tx-builder-CRpLP6jH.cjs → delegation-tx-builder-CCjiakoy.cjs} +6 -6
- package/dist/{delegation-tx-builder-CGVqlaFE.js → delegation-tx-builder-DZFjHDS8.js} +5 -5
- package/dist/{deregistration-tx-builder-B-CrUyX6.js → deregistration-tx-builder-Bf6xAYp4.js} +5 -5
- package/dist/{deregistration-tx-builder-DZGwB4cz.cjs → deregistration-tx-builder-CQP35yex.cjs} +6 -6
- package/dist/device-commitment-hex.vo-5wFtQvDS.js +26 -0
- package/dist/device-commitment-hex.vo-CT3RmAug.cjs +31 -0
- package/dist/device-readers-CUHYoYOH.js +145 -0
- package/dist/device-readers-CdxS2btd.cjs +168 -0
- package/dist/device-readers-D_JZeNL2.cjs +8 -0
- package/dist/device-readers-DwSNCGPP.js +4 -0
- package/dist/dist-BMi5ZjEq.cjs +43175 -0
- package/dist/dist-BtIq4XFn.cjs +535 -0
- package/dist/dist-C3SHC_Ho.cjs +1394 -0
- package/dist/dist-CykEjYEX.cjs +3814 -0
- package/dist/dist-Dcsxh3be.cjs +3452 -0
- package/dist/dist-DqJfSlTd.cjs +4413 -0
- package/dist/dist-nTZ70qj7.cjs +1306 -0
- package/dist/{earn-rewards-tx-builder-BDbTDZmD.js → earn-rewards-tx-builder-Bsga3yFb.js} +5 -5
- package/dist/{earn-rewards-tx-builder-D5sUT5v8.cjs → earn-rewards-tx-builder-GuxofYns.cjs} +6 -6
- package/dist/enc-key-circuits-B7BjgUL9.js +13 -0
- package/dist/enc-key-circuits-BLrZrBVI.cjs +24 -0
- package/dist/english-Byb9M0E_.cjs +2057 -0
- package/dist/envelopes-BGoO_v8m.js +1621 -0
- package/dist/envelopes-CH25R-DN.cjs +1722 -0
- package/dist/errors-BIftM8ZN.cjs +688 -0
- package/dist/errors-DSq5wUwt.js +466 -0
- package/dist/esm-HBSUQw3w.js +384 -0
- package/dist/esm-LZuaZjMf.cjs +389 -0
- package/dist/experimental.cjs +7349 -0
- package/dist/experimental.d.ts +86273 -0
- package/dist/experimental.js +7184 -0
- package/dist/gated-call-CDCVZIK-.cjs +5 -0
- package/dist/gated-call-D-tT7P_t.js +722 -0
- package/dist/gated-call-D_VT2quk.js +4 -0
- package/dist/gated-call-DgJm1Mi_.cjs +787 -0
- package/dist/grant-circuits-DswmW3nI.cjs +71 -0
- package/dist/grant-circuits-Jxb5y1HW.js +42 -0
- package/dist/grant-rules-By07_eDi.js +6824 -0
- package/dist/grant-rules-BzVTWXS7.cjs +7099 -0
- package/dist/grant-spend-B3Md9L0n.js +215 -0
- package/dist/grant-spend-oWmzRsjH.cjs +217 -0
- package/dist/grant-status-B2y49iIu.js +2688 -0
- package/dist/grant-status-DOr3t_u8.cjs +2820 -0
- package/dist/grants-2BZ-qEVQ.js +5 -0
- package/dist/grants-BPoLSiMt.cjs +18 -0
- package/dist/grants-BoI5uwSF.cjs +272 -0
- package/dist/grants-CtofFu-e.js +213 -0
- package/dist/{group-cardano-addresses-by-account-B533oVXR.cjs → group-cardano-addresses-by-account-Bp0g4wEY.cjs} +3 -39
- package/dist/{group-cardano-addresses-by-account-RHKoEskR.js → group-cardano-addresses-by-account-SR8MMrZf.js} +5 -35
- package/dist/{guarded-transaction-signer-Bxl6_XNd.cjs → guarded-transaction-signer-MFpPg98D.cjs} +17 -18
- package/dist/{guarded-transaction-signer-CpKLj8Kp.js → guarded-transaction-signer-P6Rp1faj.js} +8 -15
- package/dist/hex-D9ITYbwt.cjs +263 -0
- package/dist/hex-mkXcV3pN.js +191 -0
- package/dist/http-client-B3N-TMxu.cjs +167 -0
- package/dist/http-client-TRlhDZGh.js +155 -0
- package/dist/identity-BMLuufva.cjs +263 -0
- package/dist/identity-DII6f-h7.js +233 -0
- package/dist/in-memory-wallet-integration-B2xzxORj.cjs +20741 -0
- package/dist/in-memory-wallet-integration-CBRiPjLO.js +130 -0
- package/dist/in-memory-wallet-integration-CULUB5Tf.cjs +240 -0
- package/dist/{in-memory-wallet-integration-D-qn65Kx.js → in-memory-wallet-integration-ChIOirMW.js} +5 -2
- package/dist/{in-memory-wallet-integration-Croiuopx.js → in-memory-wallet-integration-CljprQQV.js} +7 -104
- package/dist/{in-memory-wallet-integration-DVh9sRXa.cjs → in-memory-wallet-integration-Cm6P8sk6.cjs} +3 -2
- package/dist/in-memory-wallet-integration-TM9bBphA.js +20738 -0
- package/dist/{in-memory-wallet-integration-CnLYeX4-.cjs → in-memory-wallet-integration-t9I00R_V.cjs} +17 -108
- package/dist/index.cjs +84 -47
- package/dist/index.d.ts +37496 -10033
- package/dist/index.js +52 -24
- package/dist/{init-CLHuAMB-.js → init-0zzs9aqU.js} +4 -4
- package/dist/{init-U8c9yHYx.cjs → init-5KcGcBb5.cjs} +1 -1
- package/dist/init-8v_n8boO.js +1177 -0
- package/dist/{init-CigestoM.js → init-B3-1ghyx.js} +2 -2
- package/dist/init-B8U3ABhS.cjs +107 -0
- package/dist/init-BJn-8_hf.js +141 -0
- package/dist/init-BPU3j8sT.cjs +6 -0
- package/dist/init-BRzH6xu-2.cjs +2797 -0
- package/dist/init-BmzfDaKL.js +1142 -0
- package/dist/{init-C-jErzp5.cjs → init-BopV9ed4.cjs} +2 -2
- package/dist/init-BpHTq2R5.js +105 -0
- package/dist/init-BpSITBfF.js +39 -0
- package/dist/{init-DX4WyB0R.cjs → init-BrdVzxei.cjs} +3 -3
- package/dist/{init-LfyMo-sS.cjs → init-BwkU0ruo.cjs} +2 -2
- package/dist/{init-CB__aLD7.cjs → init-C-G32J12.cjs} +2 -2
- package/dist/init-C00gw1zi.js +422 -0
- package/dist/{init-TkPq_Ny_.js → init-C2RgrfZe.js} +1 -1
- package/dist/{init-DcYY6zMD.js → init-C8URA2OX.js} +1 -1
- package/dist/init-CDkRynJa.js +2796 -0
- package/dist/{init-Cg9XdAru.js → init-CNM5m7M2.js} +4 -4
- package/dist/init-CR7BfztQ.cjs +18 -0
- package/dist/{init-CSHwHnfg.cjs → init-CSDpdu0Q.cjs} +2 -2
- package/dist/{init-aJHl-7AO.js → init-CX0AMQUn.js} +2 -2
- package/dist/{init-FMGDET-9.js → init-CfTbSEKy.js} +259 -60
- package/dist/{init-CR6tpw1B.js → init-Cigr_tKx.js} +47 -43
- package/dist/init-CuW7rHNA.js +3584 -0
- package/dist/{init-CFYsq82V.js → init-CyAY4Lzl.js} +1 -1
- package/dist/init-Cz0rz5fU.cjs +3585 -0
- package/dist/{init-BKhH6mVR.cjs → init-D6BxBs7e.cjs} +1 -1
- package/dist/init-D8OeObDF.cjs +1141 -0
- package/dist/init-D9g1HXYf.cjs +40 -0
- package/dist/{init-CNLGJJRx.js → init-DA7zmptx.js} +1 -1
- package/dist/{init-DkIc5nqF.cjs → init-DFMiP2ZH.cjs} +1 -1
- package/dist/{init-zSzCjoor.js → init-DFjT8YvT.js} +4 -4
- package/dist/init-DGjXwWs2.cjs +143 -0
- package/dist/init-DHrCbpkW.cjs +121 -0
- package/dist/{init-B64zCLxG.cjs → init-DUF4ar8P.cjs} +4 -4
- package/dist/init-DlqJuHhl.js +119 -0
- package/dist/{init-y2Ra0vZP.js → init-Dnsv155v.js} +3 -3
- package/dist/init-DrRdf5sZ.cjs +1176 -0
- package/dist/init-DuYENxci.js +17 -0
- package/dist/{init-D6DBUsD3.cjs → init-Dv3zKj0r.cjs} +4 -4
- package/dist/{init-BtzMZ7Pk.cjs → init-Dy-05ktr.cjs} +1 -1
- package/dist/{init-BsCBAGWf.cjs → init-EP0CUWNK.cjs} +2 -2
- package/dist/{init-BJVU54pI.cjs → init-EhzD7a8i.cjs} +1 -1
- package/dist/{init-w9GEs73W.js → init-Fw89ZmrR.js} +2 -2
- package/dist/init-GsT2AEa4.cjs +424 -0
- package/dist/{init-Rxohwpmu.js → init-NCjgwCZy.js} +2 -2
- package/dist/{init-DxUHsN53.cjs → init-NdhG_VrF.cjs} +6 -6
- package/dist/{init-DDdhguVC.js → init-SZ01tARX2.js} +2 -2
- package/dist/{init-BAJJzBza.js → init-Y3mkB4XS.js} +2 -2
- package/dist/init-c4l6r-o-.js +5 -0
- package/dist/{init-Dku4b2lG.js → init-kEfUTuG2.js} +1 -1
- package/dist/{init-C7IeJwQR.cjs → init-lzHt4Cli.cjs} +256 -59
- package/dist/{init-anYu6XB7.cjs → init-rmt7-fQE.cjs} +2 -2
- package/dist/{init-C4Bkib9u.cjs → init-zU-_9Gsp.cjs} +67 -65
- package/dist/{is-retriable-error-BU0e3hVI.js → is-retriable-error-BUiVJDwH.js} +1 -1
- package/dist/{is-retriable-error-CeeuHqDa.cjs → is-retriable-error-Dpt860if.cjs} +1 -1
- package/dist/jubjub-authoriser-D7zDXu3V.js +86 -0
- package/dist/jubjub-authoriser-Dgu6o3Sv.cjs +87 -0
- package/dist/key-source-5oUBFiC7.cjs +583 -0
- package/dist/key-source-B08HukZg.js +2550 -0
- package/dist/keyDerivation-D3k9XyHg.js +4077 -0
- package/dist/keyDerivation-u0nBA93T.cjs +274 -0
- package/dist/{lace-context-CZcNHr4M.js → lace-context-BZciB9c7.js} +4 -4
- package/dist/{lace-context-fJTDghdp.cjs → lace-context-DgR6vLli.cjs} +4 -4
- package/dist/lib--iqvW4O_.js +2354 -0
- package/dist/lib-Yk6Upl5D.cjs +2359 -0
- package/dist/{libsodium-wrappers-UH0LaOUE.js → libsodium-wrappers-BhbOA8dQ.js} +3 -1647
- package/dist/midnight-account-id.vo-0x9X-r3l.cjs +10 -0
- package/dist/midnight-account-id.vo-DjCAGcqc.js +5 -0
- package/dist/midnight-engine-DpemplKO.js +5 -0
- package/dist/midnight-engine-xU1wotne.cjs +6 -0
- package/dist/midnight-wallet-DIsAlSn6.js +18 -0
- package/dist/midnight-wallet-XTZc2li7.cjs +24 -0
- package/dist/midnight.cjs +1408 -0
- package/dist/midnight.d.ts +28934 -0
- package/dist/midnight.js +1352 -0
- package/dist/modules-cardano-B1nDUWqy.js +995 -0
- package/dist/modules-cardano-BYeYHrRm.cjs +1108 -0
- package/dist/node-relay-DWe1U0w2.cjs +49 -0
- package/dist/node-relay-h4i5IlAQ.js +48 -0
- package/dist/outputs-Bd2yZVjx.js +720 -0
- package/dist/outputs-CJoQBIA2.cjs +990 -0
- package/dist/pbkdf2-CIW-oWrm.cjs +1337 -0
- package/dist/pending-operation-B0_P78Jo.cjs +26 -0
- package/dist/pending-operation-BIS6mpjB.js +21 -0
- package/dist/providers-FjhM47BH.cjs +388 -0
- package/dist/providers-WtiSuxFu.js +365 -0
- package/dist/redacted-BmE2aXqr.js +81 -0
- package/dist/redacted-CRZJLS3w.cjs +86 -0
- package/dist/{retry-config-DC5IMaH7.cjs → retry-config-BaCfVC1H.cjs} +1 -1
- package/dist/{retry-config-BcUmMS--.js → retry-config-Dmgt28wM.js} +1 -1
- package/dist/safe-buffer-B_vMqJWU.js +43 -0
- package/dist/safe-buffer-DYOwEfHB.cjs +48 -0
- package/dist/sdk-Cb-gZnS9.js +1241 -0
- package/dist/sdk-DffwmX8b.cjs +1439 -0
- package/dist/sdk-init-Bln9rFtn.js +4138 -0
- package/dist/sdk-init-CYViTJY_.cjs +3841 -0
- package/dist/{seam-cardano-CATqBEyK.js → seam-cardano-B_etH4F4.js} +1 -1
- package/dist/{bytes.vo-TgiwogWF.js → secret-box-DUR0ACYz.js} +3 -25
- package/dist/{bytes.vo-Ck5u40RA.cjs → secret-box-DrjLZuS1.cjs} +1 -35
- package/dist/send-proof-progress-C-ljq1x5.js +30 -0
- package/dist/send-proof-progress-vmsaSfbz.cjs +47 -0
- package/dist/side-effects-BnqYz7Nl.js +768 -0
- package/dist/side-effects-CngaeXi0.cjs +804 -0
- package/dist/sign-bitcoin-transaction-with-seed-D4z62-jV.js +147 -0
- package/dist/sign-bitcoin-transaction-with-seed-DsLYXnCY.cjs +158 -0
- package/dist/signer-3fk8lZtE.cjs +7 -0
- package/dist/signer-CsL28DrK.cjs +121 -0
- package/dist/signer-DGluibtn.js +92 -0
- package/dist/signer-RqB5pu3K.js +2 -0
- package/dist/signer-factory-BA7WFJVZ.js +282 -0
- package/dist/signer-factory-Cwd6o-lG.cjs +281 -0
- package/dist/{signer-factory-9URFliA5.js → signer-factory-DObB55D4.js} +6 -3
- package/dist/signer-factory-DhZiE03y.cjs +149 -0
- package/dist/{signer-factory-BWGUmnvm.cjs → signer-factory-Ds6G2AZk.cjs} +4 -3
- package/dist/signer-factory-hzSRaIw2.js +148 -0
- package/dist/{slice-CuHUaPZx.cjs → slice-7G2xxYKJ.cjs} +3 -3
- package/dist/{slice-DZmQJNV8.cjs → slice-B4CdYoPu.cjs} +2 -2
- package/dist/slice-BPNuHKfw.js +9091 -0
- package/dist/{slice-DGcNrbPR.cjs → slice-Bg6HEr3K.cjs} +4 -4
- package/dist/{slice-DtaO72qY.cjs → slice-Bs2aMERu.cjs} +3 -3
- package/dist/{slice-HeHCv3bl.cjs → slice-C34iOOUH.cjs} +7 -7
- package/dist/{slice-Do2R2CYW.cjs → slice-C9TT5KhY.cjs} +6 -6
- package/dist/{slice-eIwcwKHI.js → slice-CK07EBCo.js} +4 -4
- package/dist/{slice-CnyWevM9.js → slice-CU80pbiu.js} +3 -3
- package/dist/{slice-CobanYgn.js → slice-CwyYrh1H.js} +2 -2
- package/dist/slice-Czfp6t84.cjs +436 -0
- package/dist/{slice-d0p6-xj5.js → slice-D-9aPKG-.js} +6 -6
- package/dist/{slice-maaskdUn.js → slice-DBpJ2QGf.js} +6 -6
- package/dist/{slice-mxLQ_FeY.cjs → slice-DTZTiJle.cjs} +352 -39
- package/dist/{slice-zJ9XVYjZ.js → slice-Da426sf9.js} +1 -1
- package/dist/{slice-D11m2EKl.cjs → slice-DayJvMRD.cjs} +1 -1
- package/dist/slice-DnBWfA-k.cjs +9109 -0
- package/dist/{slice-oqm_r1cS.cjs → slice-DnG-yvpI.cjs} +2 -2
- package/dist/{slice-BNu73oBa.js → slice-DyNs7oWp.js} +2 -2
- package/dist/{slice-CB4SnzMm.js → slice-GwiiJRoq.js} +3 -3
- package/dist/slice-oWnc7YVD.js +412 -0
- package/dist/{slice-B2PhoWAg.js → slice-qt0uBExh.js} +325 -37
- package/dist/slice-t8Gzj55G2.cjs +106 -0
- package/dist/slice-t8Q1cHm-.js +88 -0
- package/dist/src-BDzYIksE.cjs +20637 -0
- package/dist/src-BFoefPv_.js +20755 -0
- package/dist/store-B1Lq3cEf.cjs +66 -0
- package/dist/store-DuBG8qh5.js +37 -0
- package/dist/submit-Bs77dPn_.cjs +413 -0
- package/dist/submit-DOv8Z0Vf.js +336 -0
- package/dist/submit-bitcoin-tx-D6oYgH5S.js +983 -0
- package/dist/submit-bitcoin-tx-goFuRL7K.cjs +1049 -0
- package/dist/{sync-operation-utils-BYXLO80m.js → sync-operation-utils-31iFLExW.js} +2 -38
- package/dist/{sync-operation-utils-SdPbwFoD.cjs → sync-operation-utils-COIZ66-I.cjs} +1 -67
- package/dist/token-id-mapper-Bnds3xKH.cjs +18 -0
- package/dist/{token-id-mapper-DsPAL6Nh.cjs → token-id-mapper-CVyQJUKY.cjs} +2 -2
- package/dist/token-id-mapper-CnKHQ8DV.js +16 -0
- package/dist/{token-id-mapper-B2ivlLv3.js → token-id-mapper-D29Ggv8h.js} +2 -2
- package/dist/tokens-Cevp7rdU.cjs +62 -0
- package/dist/tokens-Diw4MLRM.js +44 -0
- package/dist/types-B8uiJn-X.js +12 -0
- package/dist/types-BHC12eSa.js +33 -0
- package/dist/types-CJT6XF2c.js +10 -0
- package/dist/types-CLRUYpfe.cjs +23 -0
- package/dist/types-Cc3mC8u0.cjs +50 -0
- package/dist/types-DWbVZpnF.cjs +15 -0
- package/dist/unwrap-provider-result-BZSiwabU.js +32 -0
- package/dist/unwrap-provider-result-ZqfBsTkk.cjs +39 -0
- package/dist/{util-CGzqQ8IV.cjs → util-Bu4W5lF4.cjs} +1 -1
- package/dist/{util-BaLzwa32.js → util-Cp5cZkfK.js} +1 -1
- package/dist/{utils-o8aMjfln.js → utils-BfBEUvWA.js} +2 -2
- package/dist/utils-DFwzEvbv.js +65 -0
- package/dist/{utils-5JvjbqH3.cjs → utils-DsElZgCI.cjs} +7 -1
- package/dist/utils-IXxR-Djh.cjs +112 -0
- package/dist/v8Signatures-CO_Uloy7.cjs +71 -0
- package/dist/{vote-delegation-tx-builder-BpEMSti4.cjs → vote-delegation-tx-builder-BUg1S2Ep.cjs} +6 -6
- package/dist/{vote-delegation-tx-builder-CmKv6GoG.js → vote-delegation-tx-builder-C6FiS7zI.js} +5 -5
- package/dist/watch-CUEvcP-V.js +21997 -0
- package/dist/watch-DMF2s-II.cjs +52281 -0
- package/package.json +96 -4
- package/dist/account-guards.stable-B1DSSh9D.cjs +0 -10
- package/dist/account-guards.stable-JRQ5qx2V.js +0 -5
- package/dist/codecs-B7X9pAsK.cjs +0 -1945
- package/dist/codecs-CC1Xjntz.js +0 -1882
- package/dist/init-Bv53hpLM.js +0 -19
- package/dist/init-CRbjI7p1.js +0 -3494
- package/dist/init-DAna1KCg.cjs +0 -3495
- package/dist/init-DGe47B22.cjs +0 -364
- package/dist/init-DMtyvYfC.cjs +0 -21
- package/dist/init-TkPDD750.js +0 -363
- package/dist/modules-cardano-BDvuL4Xx.js +0 -5248
- package/dist/modules-cardano-D2G3De2P.cjs +0 -5432
- package/dist/slice-CGVHXHDt.cjs +0 -125
- package/dist/slice-DhvF7L6X.js +0 -107
- /package/dist/{account-id.vo-LvCBVn5r.cjs → account-id.vo-DwqFjK5u.cjs} +0 -0
- /package/dist/{account-id.vo-MYSI7YFm.js → account-id.vo-OPz2v-JZ.js} +0 -0
- /package/dist/{actions-DdGbj7c7.cjs → actions-B2BJ4RTy.cjs} +0 -0
- /package/dist/{actions-9QSQR-GB.js → actions-iLXdgL5Y.js} +0 -0
- /package/dist/{apply-vkey-witnesses-ClZbpk5w.js → apply-vkey-witnesses-BKx3lcs0.js} +0 -0
- /package/dist/{apply-vkey-witnesses-CLzVSWxl.cjs → apply-vkey-witnesses-ZnFS0jnJ.cjs} +0 -0
- /package/dist/{asyncoption-Cw07zPH7.js → asyncoption-CruEYOBI.js} +0 -0
- /package/dist/{asyncoption-DYoGuQfP.cjs → asyncoption-i0VbqVTq.cjs} +0 -0
- /package/dist/{bignum.vo-B0rK_PQ1.js → bignum.vo-CEXOIew0.js} +0 -0
- /package/dist/{bignum.vo-DsG3kNiZ.cjs → bignum.vo-hx2kuqlA.cjs} +0 -0
- /package/dist/{bip32ed25519-1ApqeAZk.cjs → bip32ed25519-B7Yat217.cjs} +0 -0
- /package/dist/{bip32ed25519-DetAdGwD.js → bip32ed25519-FQ8qvdcq.js} +0 -0
- /package/dist/{blake2b-DOEVc57D.js → blake2b-BiQTw3GC.js} +0 -0
- /package/dist/{blake2b-B9tftbvG.cjs → blake2b-DEeVUdKR.cjs} +0 -0
- /package/dist/{blockchain-network-id.vo-BXpZhvvQ.cjs → blockchain-network-id.vo-BAKEwGjG.cjs} +0 -0
- /package/dist/{blockchain-network-id.vo-DNRkuT5B.js → blockchain-network-id.vo-CiVykuqG.js} +0 -0
- /package/dist/{blockingWithLatestFrom-C5wp_uA-.js → blockingWithLatestFrom-Cd8c8EPG.js} +0 -0
- /package/dist/{blockingWithLatestFrom-DY8OPg0w.cjs → blockingWithLatestFrom-D8kBPBMX.cjs} +0 -0
- /package/dist/{cardano-network-id-to-network-type-CrZfUcyP.js → cardano-network-id-to-network-type-BWwzeEtM.js} +0 -0
- /package/dist/{cardano-network-id-to-network-type-BDTF-HmK.cjs → cardano-network-id-to-network-type-C0ufJOyE.cjs} +0 -0
- /package/dist/{cardano-tx-id.vo-BPhV-AmZ.cjs → cardano-tx-id.vo-TLjJZHCI.cjs} +0 -0
- /package/dist/{cardano-tx-id.vo-DF9NzZXk.js → cardano-tx-id.vo-eVnKuzlm.js} +0 -0
- /package/dist/{composite-signer-factory-_46QsNBz.js → composite-signer-factory-CR8YHA1y.js} +0 -0
- /package/dist/{composite-signer-factory-BpF1mIYA.cjs → composite-signer-factory-m5cVs9h_.cjs} +0 -0
- /package/dist/{error-CNIquqT5.cjs → error-Cb3EnD0u.cjs} +0 -0
- /package/dist/{error-BCp9NkPi.js → error-DIZOY2Lw.js} +0 -0
- /package/dist/{esm-browser-C93Q-EOI.js → esm-browser-MG97cre9.js} +0 -0
- /package/dist/{esm-browser-DTc9IK3D.cjs → esm-browser-bweqfBlL.cjs} +0 -0
- /package/dist/{feature-flag-key.vo-ofrB6ZVQ.js → feature-flag-key.vo-DN_-4-sG.js} +0 -0
- /package/dist/{feature-flag-key.vo-BPz-ZAp6.cjs → feature-flag-key.vo-RlfHL3hq.cjs} +0 -0
- /package/dist/{first-state-of-status-OROkXcRv.cjs → first-state-of-status-CbT7hPa4.cjs} +0 -0
- /package/dist/{first-state-of-status-DQnMT3ya.js → first-state-of-status-unPynOuM.js} +0 -0
- /package/dist/{init-Es3wHW7D.js → init-829HRYcz.js} +0 -0
- /package/dist/{init-CKipPE_c.js → init-A-VyGSNW2.js} +0 -0
- /package/dist/{init-DFQQ9dTW.cjs → init-Atisw4x2.cjs} +0 -0
- /package/dist/{init-C5CEZ1m0.cjs → init-BFcvPHL-.cjs} +0 -0
- /package/dist/{init-IAk_CkGa.cjs → init-BgNobbNq.cjs} +0 -0
- /package/dist/{init-cqN3uX2j.js → init-atCFur0v.js} +0 -0
- /package/dist/{is-redux-persist-state-CTn3WZVh.cjs → is-redux-persist-state-BCFnSm36.cjs} +0 -0
- /package/dist/{is-redux-persist-state-Cxcd0_bM.js → is-redux-persist-state-yBfq0h_E.js} +0 -0
- /package/dist/{key-value-store-8cMzeNyG.js → key-value-store--W3SrMaw.js} +0 -0
- /package/dist/{key-value-store-DUAepXQf.cjs → key-value-store-C2Xt5Emp.cjs} +0 -0
- /package/dist/{repo-slice-WxetRhMY.cjs → repo-slice-7X4AYYVm.cjs} +0 -0
- /package/dist/{repo-slice-DwyMhCR1.js → repo-slice-RxFm0zDZ.js} +0 -0
- /package/dist/{reselect-CRDqmQY9.cjs → reselect-Bd94u0K-.cjs} +0 -0
- /package/dist/{reselect-C06X06oX.js → reselect-CGoLzEPv.js} +0 -0
- /package/dist/{serializable-B8GahgE1.js → serializable-BHdKIgk3.js} +0 -0
- /package/dist/{serializable-CRdnFaLZ.cjs → serializable-BxHkoPdk.cjs} +0 -0
- /package/dist/{slice-D11FHQuQ.cjs → slice-BiRsDKOK.cjs} +0 -0
- /package/dist/{slice-Be7hj4Iy.js → slice-Bk0Sv05J.js} +0 -0
- /package/dist/{slice-FioKeHtA.cjs → slice-Dqw1ecum.cjs} +0 -0
- /package/dist/{slice-B87b52iM.js → slice-obCSLm1x.js} +0 -0
- /package/dist/{src-vq1wS9sZ.js → src-BlxEp6Mm.js} +0 -0
- /package/dist/{src-BTPIvlDI.cjs → src-Cqp0B2M_.cjs} +0 -0
- /package/dist/{time.vo-CQ8pSXz2.cjs → time.vo-D3wWRw9L.cjs} +0 -0
- /package/dist/{time.vo-DkYYGYp6.js → time.vo-tNheinXm.js} +0 -0
- /package/dist/{toEmpty-CgAl3097.js → toEmpty-8Zax1MPd.js} +0 -0
- /package/dist/{toEmpty-DAMmNB5r.cjs → toEmpty-CYAbupM4.cjs} +0 -0
- /package/dist/{token-id.vo-ClsroxHO.js → token-id.vo-Bvwhr3ZE.js} +0 -0
- /package/dist/{token-id.vo-BxG9TG0O.cjs → token-id.vo-DXv5uS9n.cjs} +0 -0
- /package/dist/{util-DxzlYNS5.js → util-C8a4fA9p.js} +0 -0
- /package/dist/{util-CmdAhheh.cjs → util-CzeB3hfa.cjs} +0 -0
- /package/dist/{util-selector-CcK-GAdE.js → util-selector-BSTsxgne.js} +0 -0
- /package/dist/{util-selector-BcAncU4L.cjs → util-selector-BWPH68_l.cjs} +0 -0
- /package/dist/{while-active-BpppWuCs.js → while-active-B0lWy_6l.js} +0 -0
- /package/dist/{while-active-Dhc2LwOm.cjs → while-active-Dsowp0Fi.cjs} +0 -0
|
@@ -0,0 +1,1722 @@
|
|
|
1
|
+
const require_bytes_vo = require("./bytes.vo-BNRquqaO.cjs");
|
|
2
|
+
const require_errors = require("./errors-BIftM8ZN.cjs");
|
|
3
|
+
const require_grant_rules = require("./grant-rules-BzVTWXS7.cjs");
|
|
4
|
+
//#region ../../packages/module/passport-account/node_modules/@noble/curves/abstract/montgomery.js
|
|
5
|
+
/**
|
|
6
|
+
* Montgomery curve methods. It's not really whole montgomery curve,
|
|
7
|
+
* just bunch of very specific methods for X25519 / X448 from
|
|
8
|
+
* [RFC 7748](https://www.rfc-editor.org/rfc/rfc7748)
|
|
9
|
+
* @module
|
|
10
|
+
*/
|
|
11
|
+
/*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
|
|
12
|
+
const _0n$1 = BigInt(0);
|
|
13
|
+
const _1n$1 = BigInt(1);
|
|
14
|
+
const _2n$1 = BigInt(2);
|
|
15
|
+
function validateOpts(curve) {
|
|
16
|
+
require_grant_rules.validateObject(curve, {
|
|
17
|
+
P: "bigint",
|
|
18
|
+
type: "string",
|
|
19
|
+
adjustScalarBytes: "function",
|
|
20
|
+
powPminus2: "function"
|
|
21
|
+
}, { randomBytes: "function" });
|
|
22
|
+
return Object.freeze({ ...curve });
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* @param curveDef - Montgomery curve definition.
|
|
26
|
+
* @returns ECDH helper namespace.
|
|
27
|
+
* @throws If the curve definition or derived shared point is invalid. {@link Error}
|
|
28
|
+
* @example
|
|
29
|
+
* Perform one X25519 key exchange through the generic Montgomery helper.
|
|
30
|
+
*
|
|
31
|
+
* ```ts
|
|
32
|
+
* import { x25519 } from '@noble/curves/ed25519.js';
|
|
33
|
+
* const alice = x25519.keygen();
|
|
34
|
+
* const shared = x25519.getSharedSecret(alice.secretKey, alice.publicKey);
|
|
35
|
+
* ```
|
|
36
|
+
*/
|
|
37
|
+
function montgomery(curveDef) {
|
|
38
|
+
const { P, type, adjustScalarBytes, powPminus2, randomBytes: rand } = validateOpts(curveDef);
|
|
39
|
+
const is25519 = type === "x25519";
|
|
40
|
+
if (!is25519 && type !== "x448") throw new Error("invalid type");
|
|
41
|
+
const randomBytes_ = rand === void 0 ? require_grant_rules.randomBytes : rand;
|
|
42
|
+
const montgomeryBits = is25519 ? 255 : 448;
|
|
43
|
+
const fieldLen = is25519 ? 32 : 56;
|
|
44
|
+
const Gu = is25519 ? BigInt(9) : BigInt(5);
|
|
45
|
+
const a24 = is25519 ? BigInt(121665) : BigInt(39081);
|
|
46
|
+
const minScalar = is25519 ? _2n$1 ** BigInt(254) : _2n$1 ** BigInt(447);
|
|
47
|
+
const maxScalar = minScalar + (is25519 ? BigInt(8) * _2n$1 ** BigInt(251) - _1n$1 : BigInt(4) * _2n$1 ** BigInt(445) - _1n$1) + _1n$1;
|
|
48
|
+
const modP = (n) => require_grant_rules.mod(n, P);
|
|
49
|
+
const GuBytes = encodeU(Gu);
|
|
50
|
+
function encodeU(u) {
|
|
51
|
+
return require_grant_rules.numberToBytesLE(modP(u), fieldLen);
|
|
52
|
+
}
|
|
53
|
+
function decodeU(u) {
|
|
54
|
+
const _u = require_grant_rules.copyBytes(require_grant_rules.abytes(u, fieldLen, "uCoordinate"));
|
|
55
|
+
if (is25519) _u[31] &= 127;
|
|
56
|
+
return modP(require_grant_rules.bytesToNumberLE(_u));
|
|
57
|
+
}
|
|
58
|
+
function decodeScalar(scalar) {
|
|
59
|
+
return require_grant_rules.bytesToNumberLE(adjustScalarBytes(require_grant_rules.copyBytes(require_grant_rules.abytes(scalar, fieldLen, "scalar"))));
|
|
60
|
+
}
|
|
61
|
+
function scalarMult(scalar, u) {
|
|
62
|
+
const pu = montgomeryLadder(decodeU(u), decodeScalar(scalar));
|
|
63
|
+
if (pu === _0n$1) throw new Error("invalid private or public key received");
|
|
64
|
+
return encodeU(pu);
|
|
65
|
+
}
|
|
66
|
+
function scalarMultBase(scalar) {
|
|
67
|
+
return scalarMult(scalar, GuBytes);
|
|
68
|
+
}
|
|
69
|
+
const getPublicKey = scalarMultBase;
|
|
70
|
+
const getSharedSecret = scalarMult;
|
|
71
|
+
function cswap(swap, x_2, x_3) {
|
|
72
|
+
const dummy = modP(swap * (x_2 - x_3));
|
|
73
|
+
x_2 = modP(x_2 - dummy);
|
|
74
|
+
x_3 = modP(x_3 + dummy);
|
|
75
|
+
return {
|
|
76
|
+
x_2,
|
|
77
|
+
x_3
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Montgomery x-only multiplication ladder for the selected X25519/X448 curve.
|
|
82
|
+
* @param pointU - decoded Montgomery u coordinate for the selected curve
|
|
83
|
+
* @param scalar - decoded clamped scalar by which the point is multiplied
|
|
84
|
+
* @returns resulting Montgomery u coordinate for the selected curve
|
|
85
|
+
*/
|
|
86
|
+
function montgomeryLadder(u, scalar) {
|
|
87
|
+
require_grant_rules.aInRange("u", u, _0n$1, P);
|
|
88
|
+
require_grant_rules.aInRange("scalar", scalar, minScalar, maxScalar);
|
|
89
|
+
const k = scalar;
|
|
90
|
+
const x_1 = u;
|
|
91
|
+
let x_2 = _1n$1;
|
|
92
|
+
let z_2 = _0n$1;
|
|
93
|
+
let x_3 = u;
|
|
94
|
+
let z_3 = _1n$1;
|
|
95
|
+
let swap = _0n$1;
|
|
96
|
+
for (let t = BigInt(montgomeryBits - 1); t >= _0n$1; t--) {
|
|
97
|
+
const k_t = k >> t & _1n$1;
|
|
98
|
+
swap ^= k_t;
|
|
99
|
+
({x_2, x_3} = cswap(swap, x_2, x_3));
|
|
100
|
+
({x_2: z_2, x_3: z_3} = cswap(swap, z_2, z_3));
|
|
101
|
+
swap = k_t;
|
|
102
|
+
const A = x_2 + z_2;
|
|
103
|
+
const AA = modP(A * A);
|
|
104
|
+
const B = x_2 - z_2;
|
|
105
|
+
const BB = modP(B * B);
|
|
106
|
+
const E = AA - BB;
|
|
107
|
+
const C = x_3 + z_3;
|
|
108
|
+
const DA = modP((x_3 - z_3) * A);
|
|
109
|
+
const CB = modP(C * B);
|
|
110
|
+
const dacb = DA + CB;
|
|
111
|
+
const da_cb = DA - CB;
|
|
112
|
+
x_3 = modP(dacb * dacb);
|
|
113
|
+
z_3 = modP(x_1 * modP(da_cb * da_cb));
|
|
114
|
+
x_2 = modP(AA * BB);
|
|
115
|
+
z_2 = modP(E * (AA + modP(a24 * E)));
|
|
116
|
+
}
|
|
117
|
+
({x_2, x_3} = cswap(swap, x_2, x_3));
|
|
118
|
+
({x_2: z_2, x_3: z_3} = cswap(swap, z_2, z_3));
|
|
119
|
+
const z2 = powPminus2(z_2);
|
|
120
|
+
return modP(x_2 * z2);
|
|
121
|
+
}
|
|
122
|
+
const lengths = {
|
|
123
|
+
secretKey: fieldLen,
|
|
124
|
+
publicKey: fieldLen,
|
|
125
|
+
seed: fieldLen
|
|
126
|
+
};
|
|
127
|
+
const randomSecretKey = (seed) => {
|
|
128
|
+
seed = seed === void 0 ? randomBytes_(fieldLen) : seed;
|
|
129
|
+
require_grant_rules.abytes(seed, lengths.seed, "seed");
|
|
130
|
+
return seed;
|
|
131
|
+
};
|
|
132
|
+
const utils = { randomSecretKey };
|
|
133
|
+
Object.freeze(lengths);
|
|
134
|
+
Object.freeze(utils);
|
|
135
|
+
return Object.freeze({
|
|
136
|
+
keygen: require_grant_rules.createKeygen(randomSecretKey, getPublicKey),
|
|
137
|
+
getSharedSecret,
|
|
138
|
+
getPublicKey,
|
|
139
|
+
scalarMult,
|
|
140
|
+
scalarMultBase,
|
|
141
|
+
utils,
|
|
142
|
+
GuBytes: GuBytes.slice(),
|
|
143
|
+
lengths
|
|
144
|
+
});
|
|
145
|
+
}
|
|
146
|
+
//#endregion
|
|
147
|
+
//#region ../../packages/module/passport-account/node_modules/@noble/curves/abstract/oprf.js
|
|
148
|
+
/**
|
|
149
|
+
* RFC 9497: Oblivious Pseudorandom Functions (OPRFs) Using Prime-Order Groups.
|
|
150
|
+
* https://www.rfc-editor.org/rfc/rfc9497
|
|
151
|
+
*
|
|
152
|
+
|
|
153
|
+
OPRF allows to interactively create an `Output = PRF(Input, serverSecretKey)`:
|
|
154
|
+
|
|
155
|
+
- Server cannot calculate Output by itself: it doesn't know Input
|
|
156
|
+
- Client cannot calculate Output by itself: it doesn't know server secretKey
|
|
157
|
+
- An attacker interception the communication can't restore Input/Output/serverSecretKey and can't
|
|
158
|
+
link Input to some value.
|
|
159
|
+
|
|
160
|
+
## Issues
|
|
161
|
+
|
|
162
|
+
- Low-entropy inputs (e.g. password '123') enable brute-forced dictionary attacks by the server
|
|
163
|
+
(solveable by domain separation in POPRF)
|
|
164
|
+
- High-level protocol needs to be constructed on top, because OPRF is low-level
|
|
165
|
+
|
|
166
|
+
## Use cases
|
|
167
|
+
|
|
168
|
+
1. **Password-Authenticated Key Exchange (PAKE):** Enables secure password login (e.g., OPAQUE)
|
|
169
|
+
without revealing the password to the server.
|
|
170
|
+
2. **Private Set Intersection (PSI):** Allows two parties to compute the intersection of their
|
|
171
|
+
private sets without revealing non-intersecting elements.
|
|
172
|
+
3. **Anonymous Credential Systems:** Supports issuance of anonymous, unlinkable credentials
|
|
173
|
+
(e.g., Privacy Pass) using blind OPRF evaluation.
|
|
174
|
+
4. **Private Information Retrieval (PIR):** Helps users query databases without revealing which
|
|
175
|
+
item they accessed.
|
|
176
|
+
5. **Encrypted Search / Secure Indexing:** Enables keyword search over encrypted data while keeping
|
|
177
|
+
queries private.
|
|
178
|
+
6. **Spam Prevention and Rate-Limiting:** Issues anonymous tokens to prevent abuse
|
|
179
|
+
(e.g., CAPTCHA bypass) without compromising user privacy.
|
|
180
|
+
|
|
181
|
+
## Modes
|
|
182
|
+
|
|
183
|
+
- OPRF: simple mode, client doesn't need to know server public key
|
|
184
|
+
- VOPRF: verifiable mode. It lets the client verify that the server used the
|
|
185
|
+
secret key corresponding to a known public key
|
|
186
|
+
- POPRF: partially oblivious mode, VOPRF + domain separation
|
|
187
|
+
|
|
188
|
+
There is also non-interactive mode (Evaluate), which creates Output
|
|
189
|
+
non-interactively with knowledge of the secret key.
|
|
190
|
+
|
|
191
|
+
Flow:
|
|
192
|
+
- (once) Server generates secret and public keys, distributes public keys to clients
|
|
193
|
+
- deterministically: `deriveKeyPair` or just random: `generateKeyPair`
|
|
194
|
+
- Client blinds input: `blind(secretInput)`
|
|
195
|
+
- Server evaluates blinded input: `blindEvaluate` generated by client, sends result to client
|
|
196
|
+
- Client creates output using result of evaluation via 'finalize'
|
|
197
|
+
|
|
198
|
+
* @module
|
|
199
|
+
*/
|
|
200
|
+
/*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
|
|
201
|
+
const _DST_scalarBytes = /* @__PURE__ */ require_grant_rules.asciiToBytes(require_grant_rules._DST_scalar);
|
|
202
|
+
/**
|
|
203
|
+
* @param opts - OPRF ciphersuite options. See {@link OPRFOpts}.
|
|
204
|
+
* @returns OPRF helper namespace.
|
|
205
|
+
* @example
|
|
206
|
+
* Instantiate an OPRF suite from curve-specific hashing hooks.
|
|
207
|
+
*
|
|
208
|
+
* ```ts
|
|
209
|
+
* import { createOPRF } from '@noble/curves/abstract/oprf.js';
|
|
210
|
+
* import { p256, p256_hasher } from '@noble/curves/nist.js';
|
|
211
|
+
* import { sha256 } from '@noble/hashes/sha2.js';
|
|
212
|
+
* const oprf = createOPRF({
|
|
213
|
+
* name: 'P256-SHA256',
|
|
214
|
+
* Point: p256.Point,
|
|
215
|
+
* hash: sha256,
|
|
216
|
+
* hashToGroup: p256_hasher.hashToCurve,
|
|
217
|
+
* hashToScalar: p256_hasher.hashToScalar,
|
|
218
|
+
* });
|
|
219
|
+
* const keys = oprf.oprf.generateKeyPair();
|
|
220
|
+
* ```
|
|
221
|
+
*/
|
|
222
|
+
function createOPRF(opts) {
|
|
223
|
+
require_grant_rules.validateObject(opts, {
|
|
224
|
+
name: "string",
|
|
225
|
+
hash: "function",
|
|
226
|
+
hashToScalar: "function",
|
|
227
|
+
hashToGroup: "function"
|
|
228
|
+
});
|
|
229
|
+
require_grant_rules.validatePointCons(opts.Point);
|
|
230
|
+
const { name, Point, hash } = opts;
|
|
231
|
+
const { Fn } = Point;
|
|
232
|
+
const hashToGroup = (msg, ctx) => opts.hashToGroup(msg, { DST: require_grant_rules.concatBytes(require_grant_rules.asciiToBytes("HashToGroup-"), ctx) });
|
|
233
|
+
const hashToScalarPrefixed = (msg, ctx) => opts.hashToScalar(msg, { DST: require_grant_rules.concatBytes(_DST_scalarBytes, ctx) });
|
|
234
|
+
const randomScalar = (rng = require_grant_rules.randomBytes) => {
|
|
235
|
+
const t = require_grant_rules.mapHashToField(rng(require_grant_rules.getMinHashLength(Fn.ORDER)), Fn.ORDER, Fn.isLE);
|
|
236
|
+
return Fn.isLE ? require_grant_rules.bytesToNumberLE(t) : require_grant_rules.bytesToNumberBE(t);
|
|
237
|
+
};
|
|
238
|
+
const msm = (points, scalars) => require_grant_rules.pippenger(Point, points, scalars);
|
|
239
|
+
const getCtx = (mode) => require_grant_rules.concatBytes(require_grant_rules.asciiToBytes("OPRFV1-"), new Uint8Array([mode]), require_grant_rules.asciiToBytes("-" + name));
|
|
240
|
+
const ctxOPRF = getCtx(0);
|
|
241
|
+
const ctxVOPRF = getCtx(1);
|
|
242
|
+
const ctxPOPRF = getCtx(2);
|
|
243
|
+
function encode(...args) {
|
|
244
|
+
const res = [];
|
|
245
|
+
for (const a of args) if (typeof a === "number") res.push(require_grant_rules.numberToBytesBE(a, 2));
|
|
246
|
+
else if (typeof a === "string") res.push(require_grant_rules.asciiToBytes(a));
|
|
247
|
+
else {
|
|
248
|
+
require_grant_rules.abytes(a);
|
|
249
|
+
res.push(require_grant_rules.numberToBytesBE(a.length, 2), a);
|
|
250
|
+
}
|
|
251
|
+
return require_grant_rules.concatBytes(...res);
|
|
252
|
+
}
|
|
253
|
+
const inputBytes = (title, bytes) => {
|
|
254
|
+
require_grant_rules.abytes(bytes, void 0, title);
|
|
255
|
+
if (bytes.length > 65535) throw new Error(`"${title}" expected Uint8Array of length <= 65535, got length=${bytes.length}`);
|
|
256
|
+
return bytes;
|
|
257
|
+
};
|
|
258
|
+
const hashInput = (...bytes) => hash(encode(...bytes, "Finalize"));
|
|
259
|
+
function getTranscripts(B, C, D, ctx) {
|
|
260
|
+
const seed = hash(encode(B.toBytes(), require_grant_rules.concatBytes(require_grant_rules.asciiToBytes("Seed-"), ctx)));
|
|
261
|
+
const res = [];
|
|
262
|
+
for (let i = 0; i < C.length; i++) {
|
|
263
|
+
const Ci = C[i].toBytes();
|
|
264
|
+
const Di = D[i].toBytes();
|
|
265
|
+
const di = hashToScalarPrefixed(encode(seed, i, Ci, Di, "Composite"), ctx);
|
|
266
|
+
res.push(di);
|
|
267
|
+
}
|
|
268
|
+
return res;
|
|
269
|
+
}
|
|
270
|
+
function computeComposites(B, C, D, ctx) {
|
|
271
|
+
const T = getTranscripts(B, C, D, ctx);
|
|
272
|
+
return {
|
|
273
|
+
M: msm(C, T),
|
|
274
|
+
Z: msm(D, T)
|
|
275
|
+
};
|
|
276
|
+
}
|
|
277
|
+
function computeCompositesFast(k, B, C, D, ctx) {
|
|
278
|
+
const M = msm(C, getTranscripts(B, C, D, ctx));
|
|
279
|
+
return {
|
|
280
|
+
M,
|
|
281
|
+
Z: M.multiply(k)
|
|
282
|
+
};
|
|
283
|
+
}
|
|
284
|
+
function challengeTranscript(B, M, Z, t2, t3, ctx) {
|
|
285
|
+
const [Bm, a0, a1, a2, a3] = [
|
|
286
|
+
B,
|
|
287
|
+
M,
|
|
288
|
+
Z,
|
|
289
|
+
t2,
|
|
290
|
+
t3
|
|
291
|
+
].map((i) => i.toBytes());
|
|
292
|
+
return hashToScalarPrefixed(encode(Bm, a0, a1, a2, a3, "Challenge"), ctx);
|
|
293
|
+
}
|
|
294
|
+
function generateProof(ctx, k, B, C, D, rng) {
|
|
295
|
+
const { M, Z } = computeCompositesFast(k, B, C, D, ctx);
|
|
296
|
+
const r = randomScalar(rng);
|
|
297
|
+
const c = challengeTranscript(B, M, Z, Point.BASE.multiply(r), M.multiply(r), ctx);
|
|
298
|
+
return require_grant_rules.concatBytes(...[c, Fn.sub(r, Fn.mul(c, k))].map((i) => Fn.toBytes(i)));
|
|
299
|
+
}
|
|
300
|
+
function verifyProof(ctx, B, C, D, proof) {
|
|
301
|
+
require_grant_rules.abytes(proof, 2 * Fn.BYTES);
|
|
302
|
+
const { M, Z } = computeComposites(B, C, D, ctx);
|
|
303
|
+
const [c, s] = [proof.subarray(0, Fn.BYTES), proof.subarray(Fn.BYTES)].map((f) => Fn.fromBytes(f));
|
|
304
|
+
const expectedC = challengeTranscript(B, M, Z, Point.BASE.multiply(s).add(B.multiply(c)), M.multiply(s).add(Z.multiply(c)), ctx);
|
|
305
|
+
if (!Fn.eql(c, expectedC)) throw new Error("proof verification failed");
|
|
306
|
+
}
|
|
307
|
+
function generateKeyPair() {
|
|
308
|
+
const skS = randomScalar();
|
|
309
|
+
const pkS = Point.BASE.multiply(skS);
|
|
310
|
+
return {
|
|
311
|
+
secretKey: Fn.toBytes(skS),
|
|
312
|
+
publicKey: pkS.toBytes()
|
|
313
|
+
};
|
|
314
|
+
}
|
|
315
|
+
function deriveKeyPair(ctx, seed, info) {
|
|
316
|
+
require_grant_rules.abytes(seed, 32, "seed");
|
|
317
|
+
info = inputBytes("keyInfo", info);
|
|
318
|
+
const dst = require_grant_rules.concatBytes(require_grant_rules.asciiToBytes("DeriveKeyPair"), ctx);
|
|
319
|
+
const msg = require_grant_rules.concatBytes(seed, encode(info), Uint8Array.of(0));
|
|
320
|
+
for (let counter = 0; counter <= 255; counter++) {
|
|
321
|
+
msg[msg.length - 1] = counter;
|
|
322
|
+
const skS = opts.hashToScalar(msg, { DST: dst });
|
|
323
|
+
if (Fn.is0(skS)) continue;
|
|
324
|
+
return {
|
|
325
|
+
secretKey: Fn.toBytes(skS),
|
|
326
|
+
publicKey: Point.BASE.multiply(skS).toBytes()
|
|
327
|
+
};
|
|
328
|
+
}
|
|
329
|
+
throw new Error("Cannot derive key");
|
|
330
|
+
}
|
|
331
|
+
const wirePoint = (label, bytes) => {
|
|
332
|
+
const point = Point.fromBytes(bytes);
|
|
333
|
+
if (point.equals(Point.ZERO)) throw new Error(label + " point at infinity");
|
|
334
|
+
return point;
|
|
335
|
+
};
|
|
336
|
+
function blind(ctx, input, rng = require_grant_rules.randomBytes) {
|
|
337
|
+
input = inputBytes("input", input);
|
|
338
|
+
const blind = randomScalar(rng);
|
|
339
|
+
const inputPoint = hashToGroup(input, ctx);
|
|
340
|
+
if (inputPoint.equals(Point.ZERO)) throw new Error("Input point at infinity");
|
|
341
|
+
const blinded = inputPoint.multiply(blind);
|
|
342
|
+
return {
|
|
343
|
+
blind: Fn.toBytes(blind),
|
|
344
|
+
blinded: blinded.toBytes()
|
|
345
|
+
};
|
|
346
|
+
}
|
|
347
|
+
function evaluate(ctx, secretKey, input) {
|
|
348
|
+
input = inputBytes("input", input);
|
|
349
|
+
const skS = Fn.fromBytes(secretKey);
|
|
350
|
+
const inputPoint = hashToGroup(input, ctx);
|
|
351
|
+
if (inputPoint.equals(Point.ZERO)) throw new Error("Input point at infinity");
|
|
352
|
+
const unblinded = inputPoint.multiply(skS).toBytes();
|
|
353
|
+
return hashInput(input, unblinded);
|
|
354
|
+
}
|
|
355
|
+
const oprf = Object.freeze({
|
|
356
|
+
generateKeyPair,
|
|
357
|
+
deriveKeyPair: (seed, keyInfo) => deriveKeyPair(ctxOPRF, seed, keyInfo),
|
|
358
|
+
blind: (input, rng = require_grant_rules.randomBytes) => blind(ctxOPRF, input, rng),
|
|
359
|
+
blindEvaluate(secretKey, blindedPoint) {
|
|
360
|
+
const skS = Fn.fromBytes(secretKey);
|
|
361
|
+
return wirePoint("blinded", blindedPoint).multiply(skS).toBytes();
|
|
362
|
+
},
|
|
363
|
+
finalize(input, blindBytes, evaluatedBytes) {
|
|
364
|
+
input = inputBytes("input", input);
|
|
365
|
+
const blind = Fn.fromBytes(blindBytes);
|
|
366
|
+
const unblinded = wirePoint("evaluated", evaluatedBytes).multiply(Fn.inv(blind)).toBytes();
|
|
367
|
+
return hashInput(input, unblinded);
|
|
368
|
+
},
|
|
369
|
+
evaluate: (secretKey, input) => evaluate(ctxOPRF, secretKey, input)
|
|
370
|
+
});
|
|
371
|
+
const voprf = Object.freeze({
|
|
372
|
+
generateKeyPair,
|
|
373
|
+
deriveKeyPair: (seed, keyInfo) => deriveKeyPair(ctxVOPRF, seed, keyInfo),
|
|
374
|
+
blind: (input, rng = require_grant_rules.randomBytes) => blind(ctxVOPRF, input, rng),
|
|
375
|
+
blindEvaluateBatch(secretKey, publicKey, blinded, rng = require_grant_rules.randomBytes) {
|
|
376
|
+
if (!Array.isArray(blinded)) throw new Error("expected array");
|
|
377
|
+
const skS = Fn.fromBytes(secretKey);
|
|
378
|
+
const pkS = wirePoint("public key", publicKey);
|
|
379
|
+
const blindedPoints = blinded.map((i) => wirePoint("blinded", i));
|
|
380
|
+
const evaluated = blindedPoints.map((i) => i.multiply(skS));
|
|
381
|
+
const proof = generateProof(ctxVOPRF, skS, pkS, blindedPoints, evaluated, rng);
|
|
382
|
+
return {
|
|
383
|
+
evaluated: evaluated.map((i) => i.toBytes()),
|
|
384
|
+
proof
|
|
385
|
+
};
|
|
386
|
+
},
|
|
387
|
+
blindEvaluate(secretKey, publicKey, blinded, rng = require_grant_rules.randomBytes) {
|
|
388
|
+
const res = this.blindEvaluateBatch(secretKey, publicKey, [blinded], rng);
|
|
389
|
+
return {
|
|
390
|
+
evaluated: res.evaluated[0],
|
|
391
|
+
proof: res.proof
|
|
392
|
+
};
|
|
393
|
+
},
|
|
394
|
+
finalizeBatch(items, publicKey, proof) {
|
|
395
|
+
if (!Array.isArray(items)) throw new Error("expected array");
|
|
396
|
+
verifyProof(ctxVOPRF, wirePoint("public key", publicKey), items.map((i) => wirePoint("blinded", i.blinded)), items.map((i) => wirePoint("evaluated", i.evaluated)), proof);
|
|
397
|
+
return items.map((i) => oprf.finalize(i.input, i.blind, i.evaluated));
|
|
398
|
+
},
|
|
399
|
+
finalize(input, blind, evaluated, blinded, publicKey, proof) {
|
|
400
|
+
return this.finalizeBatch([{
|
|
401
|
+
input,
|
|
402
|
+
blind,
|
|
403
|
+
evaluated,
|
|
404
|
+
blinded
|
|
405
|
+
}], publicKey, proof)[0];
|
|
406
|
+
},
|
|
407
|
+
evaluate: (secretKey, input) => evaluate(ctxVOPRF, secretKey, input)
|
|
408
|
+
});
|
|
409
|
+
const poprf = (info) => {
|
|
410
|
+
info = inputBytes("info", info);
|
|
411
|
+
const m = hashToScalarPrefixed(encode("Info", info), ctxPOPRF);
|
|
412
|
+
const T = Point.BASE.multiply(m);
|
|
413
|
+
return Object.freeze({
|
|
414
|
+
generateKeyPair,
|
|
415
|
+
deriveKeyPair: (seed, keyInfo) => deriveKeyPair(ctxPOPRF, seed, keyInfo),
|
|
416
|
+
blind(input, publicKey, rng = require_grant_rules.randomBytes) {
|
|
417
|
+
input = inputBytes("input", input);
|
|
418
|
+
const pkS = wirePoint("public key", publicKey);
|
|
419
|
+
const tweakedKey = T.add(pkS);
|
|
420
|
+
if (tweakedKey.equals(Point.ZERO)) throw new Error("tweakedKey point at infinity");
|
|
421
|
+
const blind = randomScalar(rng);
|
|
422
|
+
const inputPoint = hashToGroup(input, ctxPOPRF);
|
|
423
|
+
if (inputPoint.equals(Point.ZERO)) throw new Error("Input point at infinity");
|
|
424
|
+
const blindedPoint = inputPoint.multiply(blind);
|
|
425
|
+
return {
|
|
426
|
+
blind: Fn.toBytes(blind),
|
|
427
|
+
blinded: blindedPoint.toBytes(),
|
|
428
|
+
tweakedKey: tweakedKey.toBytes()
|
|
429
|
+
};
|
|
430
|
+
},
|
|
431
|
+
blindEvaluateBatch(secretKey, blinded, rng = require_grant_rules.randomBytes) {
|
|
432
|
+
if (!Array.isArray(blinded)) throw new Error("expected array");
|
|
433
|
+
const skS = Fn.fromBytes(secretKey);
|
|
434
|
+
const t = Fn.add(skS, m);
|
|
435
|
+
const invT = Fn.inv(t);
|
|
436
|
+
const blindedPoints = blinded.map((i) => wirePoint("blinded", i));
|
|
437
|
+
const evalPoints = blindedPoints.map((i) => i.multiply(invT));
|
|
438
|
+
const proof = generateProof(ctxPOPRF, t, Point.BASE.multiply(t), evalPoints, blindedPoints, rng);
|
|
439
|
+
return {
|
|
440
|
+
evaluated: evalPoints.map((i) => i.toBytes()),
|
|
441
|
+
proof
|
|
442
|
+
};
|
|
443
|
+
},
|
|
444
|
+
blindEvaluate(secretKey, blinded, rng = require_grant_rules.randomBytes) {
|
|
445
|
+
const res = this.blindEvaluateBatch(secretKey, [blinded], rng);
|
|
446
|
+
return {
|
|
447
|
+
evaluated: res.evaluated[0],
|
|
448
|
+
proof: res.proof
|
|
449
|
+
};
|
|
450
|
+
},
|
|
451
|
+
finalizeBatch(items, proof, tweakedKey) {
|
|
452
|
+
if (!Array.isArray(items)) throw new Error("expected array");
|
|
453
|
+
const inputs = items.map((i) => inputBytes("input", i.input));
|
|
454
|
+
const evalPoints = items.map((i) => wirePoint("evaluated", i.evaluated));
|
|
455
|
+
verifyProof(ctxPOPRF, wirePoint("tweakedKey", tweakedKey), evalPoints, items.map((i) => wirePoint("blinded", i.blinded)), proof);
|
|
456
|
+
return items.map((i, j) => {
|
|
457
|
+
const blind = Fn.fromBytes(i.blind);
|
|
458
|
+
const point = evalPoints[j].multiply(Fn.inv(blind)).toBytes();
|
|
459
|
+
return hashInput(inputs[j], info, point);
|
|
460
|
+
});
|
|
461
|
+
},
|
|
462
|
+
finalize(input, blind, evaluated, blinded, proof, tweakedKey) {
|
|
463
|
+
return this.finalizeBatch([{
|
|
464
|
+
input,
|
|
465
|
+
blind,
|
|
466
|
+
evaluated,
|
|
467
|
+
blinded
|
|
468
|
+
}], proof, tweakedKey)[0];
|
|
469
|
+
},
|
|
470
|
+
evaluate(secretKey, input) {
|
|
471
|
+
input = inputBytes("input", input);
|
|
472
|
+
const skS = Fn.fromBytes(secretKey);
|
|
473
|
+
const inputPoint = hashToGroup(input, ctxPOPRF);
|
|
474
|
+
if (inputPoint.equals(Point.ZERO)) throw new Error("Input point at infinity");
|
|
475
|
+
const t = Fn.add(skS, m);
|
|
476
|
+
const invT = Fn.inv(t);
|
|
477
|
+
const unblinded = inputPoint.multiply(invT).toBytes();
|
|
478
|
+
return hashInput(input, info, unblinded);
|
|
479
|
+
}
|
|
480
|
+
});
|
|
481
|
+
};
|
|
482
|
+
const res = {
|
|
483
|
+
name,
|
|
484
|
+
oprf,
|
|
485
|
+
voprf,
|
|
486
|
+
poprf,
|
|
487
|
+
__tests: Object.freeze({ Fn })
|
|
488
|
+
};
|
|
489
|
+
return Object.freeze(res);
|
|
490
|
+
}
|
|
491
|
+
//#endregion
|
|
492
|
+
//#region ../../packages/module/passport-account/node_modules/@noble/curves/ed25519.js
|
|
493
|
+
/**
|
|
494
|
+
* ed25519 Twisted Edwards curve with following addons:
|
|
495
|
+
* - X25519 ECDH
|
|
496
|
+
* - Ristretto cofactor elimination
|
|
497
|
+
* - Elligator hash-to-group / point indistinguishability
|
|
498
|
+
* @module
|
|
499
|
+
*/
|
|
500
|
+
/*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
|
|
501
|
+
const _0n = /* @__PURE__ */ BigInt(0), _1n = /* @__PURE__ */ BigInt(1), _2n = /* @__PURE__ */ BigInt(2), _3n = /* @__PURE__ */ BigInt(3);
|
|
502
|
+
const _5n = /* @__PURE__ */ BigInt(5), _8n = /* @__PURE__ */ BigInt(8);
|
|
503
|
+
const ed25519_CURVE_p = /* @__PURE__ */ BigInt("0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffed");
|
|
504
|
+
const ed25519_CURVE = {
|
|
505
|
+
p: ed25519_CURVE_p,
|
|
506
|
+
n: BigInt("0x1000000000000000000000000000000014def9dea2f79cd65812631a5cf5d3ed"),
|
|
507
|
+
h: _8n,
|
|
508
|
+
a: BigInt("0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffec"),
|
|
509
|
+
d: BigInt("0x52036cee2b6ffe738cc740797779e89800700a4d4141d8ab75eb4dca135978a3"),
|
|
510
|
+
Gx: BigInt("0x216936d3cd6e53fec0a4e231fdd6dc5c692cc7609525a7b2c9562d608f25d51a"),
|
|
511
|
+
Gy: BigInt("0x6666666666666666666666666666666666666666666666666666666666666658")
|
|
512
|
+
};
|
|
513
|
+
function ed25519_pow_2_252_3(x) {
|
|
514
|
+
const _10n = BigInt(10), _20n = BigInt(20), _40n = BigInt(40), _80n = BigInt(80);
|
|
515
|
+
const P = ed25519_CURVE_p;
|
|
516
|
+
const b2 = x * x % P * x % P;
|
|
517
|
+
const b5 = require_grant_rules.pow2(require_grant_rules.pow2(b2, _2n, P) * b2 % P, _1n, P) * x % P;
|
|
518
|
+
const b10 = require_grant_rules.pow2(b5, _5n, P) * b5 % P;
|
|
519
|
+
const b20 = require_grant_rules.pow2(b10, _10n, P) * b10 % P;
|
|
520
|
+
const b40 = require_grant_rules.pow2(b20, _20n, P) * b20 % P;
|
|
521
|
+
const b80 = require_grant_rules.pow2(b40, _40n, P) * b40 % P;
|
|
522
|
+
return {
|
|
523
|
+
pow_p_5_8: require_grant_rules.pow2(require_grant_rules.pow2(require_grant_rules.pow2(require_grant_rules.pow2(b80, _80n, P) * b80 % P, _80n, P) * b80 % P, _10n, P) * b10 % P, _2n, P) * x % P,
|
|
524
|
+
b2
|
|
525
|
+
};
|
|
526
|
+
}
|
|
527
|
+
function adjustScalarBytes(bytes) {
|
|
528
|
+
bytes[0] &= 248;
|
|
529
|
+
bytes[31] &= 127;
|
|
530
|
+
bytes[31] |= 64;
|
|
531
|
+
return bytes;
|
|
532
|
+
}
|
|
533
|
+
const ED25519_SQRT_M1 = /* @__PURE__ */ BigInt("19681161376707505956807079304988542015446066515923890162744021073123829784752");
|
|
534
|
+
function uvRatio(u, v) {
|
|
535
|
+
const P = ed25519_CURVE_p;
|
|
536
|
+
const v3 = require_grant_rules.mod(v * v * v, P);
|
|
537
|
+
const pow = ed25519_pow_2_252_3(u * require_grant_rules.mod(v3 * v3 * v, P)).pow_p_5_8;
|
|
538
|
+
let x = require_grant_rules.mod(u * v3 * pow, P);
|
|
539
|
+
const vx2 = require_grant_rules.mod(v * x * x, P);
|
|
540
|
+
const root1 = x;
|
|
541
|
+
const root2 = require_grant_rules.mod(x * ED25519_SQRT_M1, P);
|
|
542
|
+
const useRoot1 = vx2 === u;
|
|
543
|
+
const useRoot2 = vx2 === require_grant_rules.mod(-u, P);
|
|
544
|
+
const noRoot = vx2 === require_grant_rules.mod(-u * ED25519_SQRT_M1, P);
|
|
545
|
+
if (useRoot1) x = root1;
|
|
546
|
+
if (useRoot2 || noRoot) x = root2;
|
|
547
|
+
if (require_grant_rules.isNegativeLE(x, P)) x = require_grant_rules.mod(-x, P);
|
|
548
|
+
return {
|
|
549
|
+
isValid: useRoot1 || useRoot2,
|
|
550
|
+
value: x
|
|
551
|
+
};
|
|
552
|
+
}
|
|
553
|
+
const ed25519_Point = /* @__PURE__ */ require_grant_rules.edwards(ed25519_CURVE, { uvRatio });
|
|
554
|
+
const Fp = ed25519_Point.Fp;
|
|
555
|
+
const Fn = ed25519_Point.Fn;
|
|
556
|
+
require_grant_rules.createFROST({
|
|
557
|
+
name: "FROST-ED25519-SHA512-v1",
|
|
558
|
+
Point: ed25519_Point,
|
|
559
|
+
validatePoint: (p) => {
|
|
560
|
+
p.assertValidity();
|
|
561
|
+
if (!p.isTorsionFree()) throw new Error("bad point: not torsion-free");
|
|
562
|
+
},
|
|
563
|
+
hash: require_grant_rules.sha512,
|
|
564
|
+
H2: ""
|
|
565
|
+
});
|
|
566
|
+
/**
|
|
567
|
+
* ECDH using curve25519 aka x25519.
|
|
568
|
+
* `getSharedSecret()` rejects low-order peer inputs by default, and seeded
|
|
569
|
+
* `keygen(seed)` reuses the provided 32-byte seed buffer instead of copying it.
|
|
570
|
+
* @example
|
|
571
|
+
* Derive one shared secret between two X25519 peers.
|
|
572
|
+
*
|
|
573
|
+
* ```js
|
|
574
|
+
* import { x25519 } from '@noble/curves/ed25519.js';
|
|
575
|
+
* const alice = x25519.keygen();
|
|
576
|
+
* const bob = x25519.keygen();
|
|
577
|
+
* const shared = x25519.getSharedSecret(alice.secretKey, bob.publicKey);
|
|
578
|
+
* ```
|
|
579
|
+
*/
|
|
580
|
+
const x25519 = /* @__PURE__ */ (() => {
|
|
581
|
+
const P = ed25519_CURVE_p;
|
|
582
|
+
return montgomery({
|
|
583
|
+
P,
|
|
584
|
+
type: "x25519",
|
|
585
|
+
powPminus2: (x) => {
|
|
586
|
+
const { pow_p_5_8, b2 } = ed25519_pow_2_252_3(x);
|
|
587
|
+
return require_grant_rules.mod(require_grant_rules.pow2(pow_p_5_8, _3n, P) * b2, P);
|
|
588
|
+
},
|
|
589
|
+
adjustScalarBytes
|
|
590
|
+
});
|
|
591
|
+
})();
|
|
592
|
+
const ELL2_C1 = (ed25519_CURVE_p + _3n) / _8n;
|
|
593
|
+
const ELL2_C2 = Fp.pow(_2n, ELL2_C1);
|
|
594
|
+
const ELL2_C3 = Fp.sqrt(Fp.neg(Fp.ONE));
|
|
595
|
+
/**
|
|
596
|
+
* RFC 9380 method `map_to_curve_elligator2_curve25519`. Experimental name: may be renamed later.
|
|
597
|
+
* @private
|
|
598
|
+
*/
|
|
599
|
+
function _map_to_curve_elligator2_curve25519(u) {
|
|
600
|
+
const ELL2_C4 = (ed25519_CURVE_p - _5n) / _8n;
|
|
601
|
+
const ELL2_J = BigInt(486662);
|
|
602
|
+
let tv1 = Fp.sqr(u);
|
|
603
|
+
tv1 = Fp.mul(tv1, _2n);
|
|
604
|
+
let xd = Fp.add(tv1, Fp.ONE);
|
|
605
|
+
let x1n = Fp.neg(ELL2_J);
|
|
606
|
+
let tv2 = Fp.sqr(xd);
|
|
607
|
+
let gxd = Fp.mul(tv2, xd);
|
|
608
|
+
let gx1 = Fp.mul(tv1, ELL2_J);
|
|
609
|
+
gx1 = Fp.mul(gx1, x1n);
|
|
610
|
+
gx1 = Fp.add(gx1, tv2);
|
|
611
|
+
gx1 = Fp.mul(gx1, x1n);
|
|
612
|
+
let tv3 = Fp.sqr(gxd);
|
|
613
|
+
tv2 = Fp.sqr(tv3);
|
|
614
|
+
tv3 = Fp.mul(tv3, gxd);
|
|
615
|
+
tv3 = Fp.mul(tv3, gx1);
|
|
616
|
+
tv2 = Fp.mul(tv2, tv3);
|
|
617
|
+
let y11 = Fp.pow(tv2, ELL2_C4);
|
|
618
|
+
y11 = Fp.mul(y11, tv3);
|
|
619
|
+
let y12 = Fp.mul(y11, ELL2_C3);
|
|
620
|
+
tv2 = Fp.sqr(y11);
|
|
621
|
+
tv2 = Fp.mul(tv2, gxd);
|
|
622
|
+
let e1 = Fp.eql(tv2, gx1);
|
|
623
|
+
let y1 = Fp.cmov(y12, y11, e1);
|
|
624
|
+
let x2n = Fp.mul(x1n, tv1);
|
|
625
|
+
let y21 = Fp.mul(y11, u);
|
|
626
|
+
y21 = Fp.mul(y21, ELL2_C2);
|
|
627
|
+
let y22 = Fp.mul(y21, ELL2_C3);
|
|
628
|
+
let gx2 = Fp.mul(gx1, tv1);
|
|
629
|
+
tv2 = Fp.sqr(y21);
|
|
630
|
+
tv2 = Fp.mul(tv2, gxd);
|
|
631
|
+
let e2 = Fp.eql(tv2, gx2);
|
|
632
|
+
let y2 = Fp.cmov(y22, y21, e2);
|
|
633
|
+
tv2 = Fp.sqr(y1);
|
|
634
|
+
tv2 = Fp.mul(tv2, gxd);
|
|
635
|
+
let e3 = Fp.eql(tv2, gx1);
|
|
636
|
+
let xn = Fp.cmov(x2n, x1n, e3);
|
|
637
|
+
let y = Fp.cmov(y2, y1, e3);
|
|
638
|
+
let e4 = Fp.isOdd(y);
|
|
639
|
+
y = Fp.cmov(y, Fp.neg(y), e3 !== e4);
|
|
640
|
+
return {
|
|
641
|
+
xMn: xn,
|
|
642
|
+
xMd: xd,
|
|
643
|
+
yMn: y,
|
|
644
|
+
yMd: _1n
|
|
645
|
+
};
|
|
646
|
+
}
|
|
647
|
+
const ELL2_C1_EDWARDS = require_grant_rules.FpSqrtEven(Fp, Fp.neg(BigInt(486664)));
|
|
648
|
+
function map_to_curve_elligator2_edwards25519(u) {
|
|
649
|
+
const { xMn, xMd, yMn, yMd } = _map_to_curve_elligator2_curve25519(u);
|
|
650
|
+
let xn = Fp.mul(xMn, yMd);
|
|
651
|
+
xn = Fp.mul(xn, ELL2_C1_EDWARDS);
|
|
652
|
+
let xd = Fp.mul(xMd, yMn);
|
|
653
|
+
let yn = Fp.sub(xMn, xMd);
|
|
654
|
+
let yd = Fp.add(xMn, xMd);
|
|
655
|
+
let tv1 = Fp.mul(xd, yd);
|
|
656
|
+
let e = Fp.eql(tv1, Fp.ZERO);
|
|
657
|
+
xn = Fp.cmov(xn, Fp.ZERO, e);
|
|
658
|
+
xd = Fp.cmov(xd, Fp.ONE, e);
|
|
659
|
+
yn = Fp.cmov(yn, Fp.ONE, e);
|
|
660
|
+
yd = Fp.cmov(yd, Fp.ONE, e);
|
|
661
|
+
const [xd_inv, yd_inv] = require_grant_rules.FpInvertBatch(Fp, [xd, yd], true);
|
|
662
|
+
return {
|
|
663
|
+
x: Fp.mul(xn, xd_inv),
|
|
664
|
+
y: Fp.mul(yn, yd_inv)
|
|
665
|
+
};
|
|
666
|
+
}
|
|
667
|
+
require_grant_rules.createHasher(ed25519_Point, (scalars) => map_to_curve_elligator2_edwards25519(scalars[0]), {
|
|
668
|
+
DST: "edwards25519_XMD:SHA-512_ELL2_RO_",
|
|
669
|
+
encodeDST: "edwards25519_XMD:SHA-512_ELL2_NU_",
|
|
670
|
+
p: ed25519_CURVE_p,
|
|
671
|
+
m: 1,
|
|
672
|
+
k: 128,
|
|
673
|
+
expand: "xmd",
|
|
674
|
+
hash: require_grant_rules.sha512
|
|
675
|
+
});
|
|
676
|
+
const SQRT_M1 = ED25519_SQRT_M1;
|
|
677
|
+
const SQRT_AD_MINUS_ONE = /* @__PURE__ */ BigInt("25063068953384623474111414158702152701244531502492656460079210482610430750235");
|
|
678
|
+
const INVSQRT_A_MINUS_D = /* @__PURE__ */ BigInt("54469307008909316920995813868745141605393597292927456921205312896311721017578");
|
|
679
|
+
const ONE_MINUS_D_SQ = /* @__PURE__ */ BigInt("1159843021668779879193775521855586647937357759715417654439879720876111806838");
|
|
680
|
+
const D_MINUS_ONE_SQ = /* @__PURE__ */ BigInt("40440834346308536858101042469323190826248399146238708352240133220865137265952");
|
|
681
|
+
const invertSqrt = (number) => uvRatio(_1n, number);
|
|
682
|
+
const MAX_255B = /* @__PURE__ */ BigInt("0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff");
|
|
683
|
+
const bytes255ToNumberLE = (bytes) => Fp.create(require_grant_rules.bytesToNumberLE(bytes) & MAX_255B);
|
|
684
|
+
/**
|
|
685
|
+
* Computes Elligator map for Ristretto255.
|
|
686
|
+
* Primary formula source is RFC 9496 §4.3.4 MAP; RFC 9380 Appendix B builds
|
|
687
|
+
* `hash_to_ristretto255` on top of this helper.
|
|
688
|
+
* Returns an internal Edwards representative, not a public `_RistrettoPoint`.
|
|
689
|
+
*/
|
|
690
|
+
function calcElligatorRistrettoMap(r0) {
|
|
691
|
+
const { d } = ed25519_CURVE;
|
|
692
|
+
const P = ed25519_CURVE_p;
|
|
693
|
+
const mod = (n) => Fp.create(n);
|
|
694
|
+
const r = mod(SQRT_M1 * r0 * r0);
|
|
695
|
+
const Ns = mod((r + _1n) * ONE_MINUS_D_SQ);
|
|
696
|
+
let c = BigInt(-1);
|
|
697
|
+
const D = mod((c - d * r) * mod(r + d));
|
|
698
|
+
let { isValid: Ns_D_is_sq, value: s } = uvRatio(Ns, D);
|
|
699
|
+
let s_ = mod(s * r0);
|
|
700
|
+
if (!require_grant_rules.isNegativeLE(s_, P)) s_ = mod(-s_);
|
|
701
|
+
if (!Ns_D_is_sq) s = s_;
|
|
702
|
+
if (!Ns_D_is_sq) c = r;
|
|
703
|
+
const Nt = mod(c * (r - _1n) * D_MINUS_ONE_SQ - D);
|
|
704
|
+
const s2 = s * s;
|
|
705
|
+
const W0 = mod((s + s) * D);
|
|
706
|
+
const W1 = mod(Nt * SQRT_AD_MINUS_ONE);
|
|
707
|
+
const W2 = mod(_1n - s2);
|
|
708
|
+
const W3 = mod(_1n + s2);
|
|
709
|
+
return new ed25519_Point(mod(W0 * W3), mod(W2 * W1), mod(W1 * W3), mod(W0 * W2));
|
|
710
|
+
}
|
|
711
|
+
/**
|
|
712
|
+
* Wrapper over Edwards Point for ristretto255.
|
|
713
|
+
*
|
|
714
|
+
* Each ed25519/EdwardsPoint has 8 different equivalent points. This can be
|
|
715
|
+
* a source of bugs for protocols like ring signatures. Ristretto was created to solve this.
|
|
716
|
+
* Ristretto point operates in X:Y:Z:T extended coordinates like EdwardsPoint,
|
|
717
|
+
* but it should work in its own namespace: do not combine those two.
|
|
718
|
+
* See [RFC9496](https://www.rfc-editor.org/rfc/rfc9496).
|
|
719
|
+
*/
|
|
720
|
+
var _RistrettoPoint = class _RistrettoPoint extends require_grant_rules.PrimeEdwardsPoint {
|
|
721
|
+
static BASE = new _RistrettoPoint(ed25519_Point.BASE);
|
|
722
|
+
static ZERO = new _RistrettoPoint(ed25519_Point.ZERO);
|
|
723
|
+
static Fp = Fp;
|
|
724
|
+
static Fn = Fn;
|
|
725
|
+
constructor(ep) {
|
|
726
|
+
super(ep);
|
|
727
|
+
}
|
|
728
|
+
/**
|
|
729
|
+
* Create one Ristretto255 point from affine Edwards coordinates.
|
|
730
|
+
* This wraps the internal Edwards representative directly and is not a
|
|
731
|
+
* canonical ristretto255 decoding path.
|
|
732
|
+
* Use `toBytes()` / `fromBytes()` if canonical ristretto255 bytes matter.
|
|
733
|
+
*/
|
|
734
|
+
static fromAffine(ap) {
|
|
735
|
+
return new _RistrettoPoint(ed25519_Point.fromAffine(ap));
|
|
736
|
+
}
|
|
737
|
+
assertSame(other) {
|
|
738
|
+
if (!(other instanceof _RistrettoPoint)) throw new Error("RistrettoPoint expected");
|
|
739
|
+
}
|
|
740
|
+
init(ep) {
|
|
741
|
+
return new _RistrettoPoint(ep);
|
|
742
|
+
}
|
|
743
|
+
static fromBytes(bytes) {
|
|
744
|
+
require_grant_rules.abytes$1(bytes, 32);
|
|
745
|
+
const { a, d } = ed25519_CURVE;
|
|
746
|
+
const P = ed25519_CURVE_p;
|
|
747
|
+
const mod = (n) => Fp.create(n);
|
|
748
|
+
const s = bytes255ToNumberLE(bytes);
|
|
749
|
+
if (!require_grant_rules.equalBytes(Fp.toBytes(s), bytes) || require_grant_rules.isNegativeLE(s, P)) throw new Error("invalid ristretto255 encoding 1");
|
|
750
|
+
const s2 = mod(s * s);
|
|
751
|
+
const u1 = mod(_1n + a * s2);
|
|
752
|
+
const u2 = mod(_1n - a * s2);
|
|
753
|
+
const u1_2 = mod(u1 * u1);
|
|
754
|
+
const u2_2 = mod(u2 * u2);
|
|
755
|
+
const v = mod(a * d * u1_2 - u2_2);
|
|
756
|
+
const { isValid, value: I } = invertSqrt(mod(v * u2_2));
|
|
757
|
+
const Dx = mod(I * u2);
|
|
758
|
+
const Dy = mod(I * Dx * v);
|
|
759
|
+
let x = mod((s + s) * Dx);
|
|
760
|
+
if (require_grant_rules.isNegativeLE(x, P)) x = mod(-x);
|
|
761
|
+
const y = mod(u1 * Dy);
|
|
762
|
+
const t = mod(x * y);
|
|
763
|
+
if (!isValid || require_grant_rules.isNegativeLE(t, P) || y === _0n) throw new Error("invalid ristretto255 encoding 2");
|
|
764
|
+
return new _RistrettoPoint(new ed25519_Point(x, y, _1n, t));
|
|
765
|
+
}
|
|
766
|
+
/**
|
|
767
|
+
* Converts ristretto-encoded string to ristretto point.
|
|
768
|
+
* Described in [RFC9496](https://www.rfc-editor.org/rfc/rfc9496#name-decode).
|
|
769
|
+
* @param hex - Ristretto-encoded 32 bytes. Not every 32-byte string is valid ristretto encoding
|
|
770
|
+
*/
|
|
771
|
+
static fromHex(hex) {
|
|
772
|
+
return _RistrettoPoint.fromBytes(require_grant_rules.hexToBytes(hex));
|
|
773
|
+
}
|
|
774
|
+
/**
|
|
775
|
+
* Encodes ristretto point to Uint8Array.
|
|
776
|
+
* Described in [RFC9496](https://www.rfc-editor.org/rfc/rfc9496#name-encode).
|
|
777
|
+
*/
|
|
778
|
+
toBytes() {
|
|
779
|
+
let { X, Y, Z, T } = this.ep;
|
|
780
|
+
const P = ed25519_CURVE_p;
|
|
781
|
+
const mod = (n) => Fp.create(n);
|
|
782
|
+
const u1 = mod(mod(Z + Y) * mod(Z - Y));
|
|
783
|
+
const u2 = mod(X * Y);
|
|
784
|
+
const { value: invsqrt } = invertSqrt(mod(u1 * mod(u2 * u2)));
|
|
785
|
+
const D1 = mod(invsqrt * u1);
|
|
786
|
+
const D2 = mod(invsqrt * u2);
|
|
787
|
+
const zInv = mod(D1 * D2 * T);
|
|
788
|
+
let D;
|
|
789
|
+
if (require_grant_rules.isNegativeLE(T * zInv, P)) {
|
|
790
|
+
let _x = mod(Y * SQRT_M1);
|
|
791
|
+
let _y = mod(X * SQRT_M1);
|
|
792
|
+
X = _x;
|
|
793
|
+
Y = _y;
|
|
794
|
+
D = mod(D1 * INVSQRT_A_MINUS_D);
|
|
795
|
+
} else D = D2;
|
|
796
|
+
if (require_grant_rules.isNegativeLE(X * zInv, P)) Y = mod(-Y);
|
|
797
|
+
let s = mod((Z - Y) * D);
|
|
798
|
+
if (require_grant_rules.isNegativeLE(s, P)) s = mod(-s);
|
|
799
|
+
return Fp.toBytes(s);
|
|
800
|
+
}
|
|
801
|
+
/**
|
|
802
|
+
* Compares two Ristretto points.
|
|
803
|
+
* Described in [RFC9496](https://www.rfc-editor.org/rfc/rfc9496#name-equals).
|
|
804
|
+
*/
|
|
805
|
+
equals(other) {
|
|
806
|
+
this.assertSame(other);
|
|
807
|
+
const { X: X1, Y: Y1 } = this.ep;
|
|
808
|
+
const { X: X2, Y: Y2 } = other.ep;
|
|
809
|
+
const mod = (n) => Fp.create(n);
|
|
810
|
+
const one = mod(X1 * Y2) === mod(Y1 * X2);
|
|
811
|
+
const two = mod(Y1 * Y2) === mod(X1 * X2);
|
|
812
|
+
return one || two;
|
|
813
|
+
}
|
|
814
|
+
is0() {
|
|
815
|
+
return this.equals(_RistrettoPoint.ZERO);
|
|
816
|
+
}
|
|
817
|
+
};
|
|
818
|
+
Object.freeze(_RistrettoPoint.BASE);
|
|
819
|
+
Object.freeze(_RistrettoPoint.ZERO);
|
|
820
|
+
Object.freeze(_RistrettoPoint.prototype);
|
|
821
|
+
Object.freeze(_RistrettoPoint);
|
|
822
|
+
/**
|
|
823
|
+
* Hashing to ristretto255 points / field. RFC 9380 methods.
|
|
824
|
+
* `hashToCurve()` is RFC 9380 Appendix B, `deriveToCurve()` is the RFC 9496
|
|
825
|
+
* §4.3.4 element-derivation building block, and `hashToScalar()` is a
|
|
826
|
+
* library-specific helper for OPRF-style use.
|
|
827
|
+
* @example
|
|
828
|
+
* Hash one message onto ristretto255.
|
|
829
|
+
*
|
|
830
|
+
* ```ts
|
|
831
|
+
* const point = ristretto255_hasher.hashToCurve(new TextEncoder().encode('hello noble'));
|
|
832
|
+
* ```
|
|
833
|
+
*/
|
|
834
|
+
const ristretto255_hasher = Object.freeze({
|
|
835
|
+
Point: _RistrettoPoint,
|
|
836
|
+
hashToCurve(msg, options) {
|
|
837
|
+
const xmd = require_grant_rules.expand_message_xmd(msg, options?.DST === void 0 ? "ristretto255_XMD:SHA-512_R255MAP_RO_" : options.DST, 64, require_grant_rules.sha512);
|
|
838
|
+
return ristretto255_hasher.deriveToCurve(xmd);
|
|
839
|
+
},
|
|
840
|
+
hashToScalar(msg, options = { DST: require_grant_rules._DST_scalar }) {
|
|
841
|
+
const xmd = require_grant_rules.expand_message_xmd(msg, options.DST, 64, require_grant_rules.sha512);
|
|
842
|
+
return Fn.create(require_grant_rules.bytesToNumberLE(xmd));
|
|
843
|
+
},
|
|
844
|
+
deriveToCurve(bytes) {
|
|
845
|
+
require_grant_rules.abytes$1(bytes, 64);
|
|
846
|
+
const R1 = calcElligatorRistrettoMap(bytes255ToNumberLE(bytes.subarray(0, 32)));
|
|
847
|
+
const R2 = calcElligatorRistrettoMap(bytes255ToNumberLE(bytes.subarray(32, 64)));
|
|
848
|
+
return new _RistrettoPoint(R1.add(R2));
|
|
849
|
+
}
|
|
850
|
+
});
|
|
851
|
+
createOPRF({
|
|
852
|
+
name: "ristretto255-SHA512",
|
|
853
|
+
Point: _RistrettoPoint,
|
|
854
|
+
hash: require_grant_rules.sha512,
|
|
855
|
+
hashToGroup: ristretto255_hasher.hashToCurve,
|
|
856
|
+
hashToScalar: ristretto255_hasher.hashToScalar
|
|
857
|
+
});
|
|
858
|
+
require_grant_rules.createFROST({
|
|
859
|
+
name: "FROST-RISTRETTO255-SHA512-v1",
|
|
860
|
+
Point: _RistrettoPoint,
|
|
861
|
+
validatePoint: (p) => {
|
|
862
|
+
p.assertValidity();
|
|
863
|
+
},
|
|
864
|
+
hash: require_grant_rules.sha512
|
|
865
|
+
});
|
|
866
|
+
/**
|
|
867
|
+
* The most inbox entries one open-inbox request carries, held by the
|
|
868
|
+
* client that batches and the signer that answers alike: a busy inbox is
|
|
869
|
+
* opened over several requests, so no single request holds the signer
|
|
870
|
+
* decrypting without bound.
|
|
871
|
+
*/
|
|
872
|
+
const MAX_INBOX_ENTRIES_PER_REQUEST = 4096;
|
|
873
|
+
const ENTRY_VERSION = 1;
|
|
874
|
+
const ENTRY_SUITE = 1;
|
|
875
|
+
const EPHEMERAL_KEY_OFFSET$1 = 2;
|
|
876
|
+
const NONCE_OFFSET$1 = 34;
|
|
877
|
+
const TAG_OFFSET$1 = 46;
|
|
878
|
+
const CIPHERTEXT_OFFSET$1 = 62;
|
|
879
|
+
const NONCE_LENGTH$2 = 12;
|
|
880
|
+
const TAG_LENGTH$2 = 16;
|
|
881
|
+
const KEY_LENGTH$2 = 32;
|
|
882
|
+
const COIN_NONCE_LENGTH = 32;
|
|
883
|
+
const COLOR_LENGTH = 32;
|
|
884
|
+
const VALUE_LENGTH = 16;
|
|
885
|
+
const PLAINTEXT_LENGTH = COIN_NONCE_LENGTH + COLOR_LENGTH + VALUE_LENGTH;
|
|
886
|
+
const AEAD_TAG_BITS$2 = TAG_LENGTH$2 * 8;
|
|
887
|
+
const VALUE_MAX = (1n << BigInt(VALUE_LENGTH * 8)) - 1n;
|
|
888
|
+
const BYTE_BITS$1 = 8n;
|
|
889
|
+
const BYTE_MASK$1 = 255n;
|
|
890
|
+
const WRAPPING_KEY_INFO = new TextEncoder().encode("midnight:custody:inbox:v1");
|
|
891
|
+
/**
|
|
892
|
+
* The AES-256-GCM key that wraps one entry: HKDF-SHA256 over the X25519
|
|
893
|
+
* shared secret with an empty salt and the fixed inbox label, imported
|
|
894
|
+
* non-extractable so the key bytes never exist outside the shared secret,
|
|
895
|
+
* which is zeroed once the key is derived.
|
|
896
|
+
*/
|
|
897
|
+
const wrappingKey = async (shared) => {
|
|
898
|
+
try {
|
|
899
|
+
const material = await crypto.subtle.importKey("raw", shared, "HKDF", false, ["deriveKey"]);
|
|
900
|
+
return await crypto.subtle.deriveKey({
|
|
901
|
+
name: "HKDF",
|
|
902
|
+
hash: "SHA-256",
|
|
903
|
+
salt: new Uint8Array(0),
|
|
904
|
+
info: WRAPPING_KEY_INFO
|
|
905
|
+
}, material, {
|
|
906
|
+
name: "AES-GCM",
|
|
907
|
+
length: KEY_LENGTH$2 * 8
|
|
908
|
+
}, false, ["encrypt", "decrypt"]);
|
|
909
|
+
} finally {
|
|
910
|
+
shared.fill(0);
|
|
911
|
+
}
|
|
912
|
+
};
|
|
913
|
+
const encodeValue = (value) => {
|
|
914
|
+
const bytes = new Uint8Array(VALUE_LENGTH);
|
|
915
|
+
let remaining = value;
|
|
916
|
+
for (let index = VALUE_LENGTH - 1; index >= 0; index -= 1) {
|
|
917
|
+
bytes[index] = Number(remaining & BYTE_MASK$1);
|
|
918
|
+
remaining >>= BYTE_BITS$1;
|
|
919
|
+
}
|
|
920
|
+
return bytes;
|
|
921
|
+
};
|
|
922
|
+
const decodeValue = (bytes) => bytes.reduce((value, byte) => value << BYTE_BITS$1 | BigInt(byte), 0n);
|
|
923
|
+
const encodeCoin = ({ nonce, color, value }) => {
|
|
924
|
+
if (nonce.length !== COIN_NONCE_LENGTH || color.length !== COLOR_LENGTH) throw new Error(`An inbox coin description needs a ${COIN_NONCE_LENGTH}-byte nonce and a ${COLOR_LENGTH}-byte colour.`);
|
|
925
|
+
if (value < 0n || value > VALUE_MAX) throw new Error(`An inbox coin value must fit an unsigned 128-bit integer, got ${value}.`);
|
|
926
|
+
const plaintext = new Uint8Array(PLAINTEXT_LENGTH);
|
|
927
|
+
plaintext.set(nonce, 0);
|
|
928
|
+
plaintext.set(color, COIN_NONCE_LENGTH);
|
|
929
|
+
plaintext.set(encodeValue(value), COIN_NONCE_LENGTH + COLOR_LENGTH);
|
|
930
|
+
return plaintext;
|
|
931
|
+
};
|
|
932
|
+
const decodeCoin = (plaintext) => ({
|
|
933
|
+
nonce: plaintext.slice(0, COIN_NONCE_LENGTH),
|
|
934
|
+
color: plaintext.slice(COIN_NONCE_LENGTH, COIN_NONCE_LENGTH + COLOR_LENGTH),
|
|
935
|
+
value: decodeValue(plaintext.slice(COIN_NONCE_LENGTH + COLOR_LENGTH))
|
|
936
|
+
});
|
|
937
|
+
/**
|
|
938
|
+
* Seals a coin description towards an account as an InboxEntry v1: the
|
|
939
|
+
* plaintext is the coin nonce, colour and big-endian 128-bit value, wrapped
|
|
940
|
+
* under a key agreed between a fresh ephemeral X25519 key and the
|
|
941
|
+
* account's `enc_key`, with the version and suite bytes as associated
|
|
942
|
+
* data; the trailing padding stays zero. The ephemeral secret is zeroed
|
|
943
|
+
* before this returns.
|
|
944
|
+
*/
|
|
945
|
+
const sealInboxEntry = async (encPublicKey, coin) => {
|
|
946
|
+
const plaintext = encodeCoin(coin);
|
|
947
|
+
const ephemeral = x25519.keygen();
|
|
948
|
+
const entry = new Uint8Array(192);
|
|
949
|
+
entry[0] = ENTRY_VERSION;
|
|
950
|
+
entry[1] = ENTRY_SUITE;
|
|
951
|
+
try {
|
|
952
|
+
const key = await wrappingKey(x25519.getSharedSecret(ephemeral.secretKey, encPublicKey));
|
|
953
|
+
const nonce = crypto.getRandomValues(new Uint8Array(NONCE_LENGTH$2));
|
|
954
|
+
const sealed = new Uint8Array(await crypto.subtle.encrypt({
|
|
955
|
+
name: "AES-GCM",
|
|
956
|
+
iv: nonce,
|
|
957
|
+
additionalData: entry.slice(0, EPHEMERAL_KEY_OFFSET$1),
|
|
958
|
+
tagLength: AEAD_TAG_BITS$2
|
|
959
|
+
}, key, plaintext));
|
|
960
|
+
entry.set(ephemeral.publicKey, EPHEMERAL_KEY_OFFSET$1);
|
|
961
|
+
entry.set(nonce, NONCE_OFFSET$1);
|
|
962
|
+
entry.set(sealed.subarray(PLAINTEXT_LENGTH), TAG_OFFSET$1);
|
|
963
|
+
entry.set(sealed.subarray(0, PLAINTEXT_LENGTH), CIPHERTEXT_OFFSET$1);
|
|
964
|
+
return entry;
|
|
965
|
+
} finally {
|
|
966
|
+
ephemeral.secretKey.fill(0);
|
|
967
|
+
plaintext.fill(0);
|
|
968
|
+
}
|
|
969
|
+
};
|
|
970
|
+
/**
|
|
971
|
+
* Opens an InboxEntry v1 with the account encryption secret. Resolves the
|
|
972
|
+
* coin the entry describes, or null for an entry the inbox walk must skip
|
|
973
|
+
* rather than fail on: one of another length, version or suite, one
|
|
974
|
+
* sealed towards another key, or one whose authentication fails. The
|
|
975
|
+
* contract accepts any bytes from anyone, so a null is noise, not an
|
|
976
|
+
* error.
|
|
977
|
+
*/
|
|
978
|
+
const openInboxEntry = async (encSecret, entry) => {
|
|
979
|
+
if (entry.length !== 192 || entry[0] !== ENTRY_VERSION || entry[1] !== ENTRY_SUITE) return null;
|
|
980
|
+
try {
|
|
981
|
+
const key = await wrappingKey(x25519.getSharedSecret(encSecret, entry.slice(EPHEMERAL_KEY_OFFSET$1, NONCE_OFFSET$1)));
|
|
982
|
+
const sealed = new Uint8Array(PLAINTEXT_LENGTH + TAG_LENGTH$2);
|
|
983
|
+
sealed.set(entry.slice(CIPHERTEXT_OFFSET$1, CIPHERTEXT_OFFSET$1 + PLAINTEXT_LENGTH), 0);
|
|
984
|
+
sealed.set(entry.slice(TAG_OFFSET$1, CIPHERTEXT_OFFSET$1), PLAINTEXT_LENGTH);
|
|
985
|
+
const plaintext = new Uint8Array(await crypto.subtle.decrypt({
|
|
986
|
+
name: "AES-GCM",
|
|
987
|
+
iv: entry.slice(NONCE_OFFSET$1, TAG_OFFSET$1),
|
|
988
|
+
additionalData: entry.slice(0, EPHEMERAL_KEY_OFFSET$1),
|
|
989
|
+
tagLength: AEAD_TAG_BITS$2
|
|
990
|
+
}, key, sealed));
|
|
991
|
+
try {
|
|
992
|
+
return decodeCoin(plaintext);
|
|
993
|
+
} finally {
|
|
994
|
+
plaintext.fill(0);
|
|
995
|
+
}
|
|
996
|
+
} catch {
|
|
997
|
+
return null;
|
|
998
|
+
}
|
|
999
|
+
};
|
|
1000
|
+
const SEAL_VERSION = 1;
|
|
1001
|
+
const SEAL_SUITE = 1;
|
|
1002
|
+
const EPHEMERAL_KEY_OFFSET = 2;
|
|
1003
|
+
const NONCE_OFFSET = 34;
|
|
1004
|
+
const TAG_OFFSET = 46;
|
|
1005
|
+
const CIPHERTEXT_OFFSET = 62;
|
|
1006
|
+
const NONCE_LENGTH$1 = 12;
|
|
1007
|
+
const TAG_LENGTH$1 = 16;
|
|
1008
|
+
const KEY_LENGTH$1 = 32;
|
|
1009
|
+
const SECRET_LENGTH = 32;
|
|
1010
|
+
const AEAD_TAG_BITS$1 = TAG_LENGTH$1 * 8;
|
|
1011
|
+
const VIEW_KEY_INFO = new TextEncoder().encode("midnight:account:grant:view:v1");
|
|
1012
|
+
const concat$1 = (...parts) => {
|
|
1013
|
+
const joined = new Uint8Array(parts.reduce((length, part) => length + part.length, 0));
|
|
1014
|
+
let offset = 0;
|
|
1015
|
+
for (const part of parts) {
|
|
1016
|
+
joined.set(part, offset);
|
|
1017
|
+
offset += part.length;
|
|
1018
|
+
}
|
|
1019
|
+
return joined;
|
|
1020
|
+
};
|
|
1021
|
+
/**
|
|
1022
|
+
* The AES-256-GCM key that wraps one seal: HKDF-SHA256 over the X25519
|
|
1023
|
+
* shared secret with an empty salt and the view label followed by the
|
|
1024
|
+
* grant id, imported non-extractable; the shared secret is zeroed once
|
|
1025
|
+
* the key is derived.
|
|
1026
|
+
*/
|
|
1027
|
+
const sealingKey = async (shared, grantId) => {
|
|
1028
|
+
try {
|
|
1029
|
+
const material = await crypto.subtle.importKey("raw", shared, "HKDF", false, ["deriveKey"]);
|
|
1030
|
+
return await crypto.subtle.deriveKey({
|
|
1031
|
+
name: "HKDF",
|
|
1032
|
+
hash: "SHA-256",
|
|
1033
|
+
salt: new Uint8Array(0),
|
|
1034
|
+
info: concat$1(VIEW_KEY_INFO, grantId)
|
|
1035
|
+
}, material, {
|
|
1036
|
+
name: "AES-GCM",
|
|
1037
|
+
length: KEY_LENGTH$1 * 8
|
|
1038
|
+
}, false, ["encrypt"]);
|
|
1039
|
+
} finally {
|
|
1040
|
+
shared.fill(0);
|
|
1041
|
+
}
|
|
1042
|
+
};
|
|
1043
|
+
/**
|
|
1044
|
+
* Seals an account encryption secret towards a grantee's read key as a
|
|
1045
|
+
* GrantViewSeal v1: the secret is wrapped under a key agreed between a
|
|
1046
|
+
* fresh ephemeral X25519 key and the read key and derived with the grant
|
|
1047
|
+
* id in its label, with the version, suite, ephemeral key, grant id and
|
|
1048
|
+
* account as associated data, so the container opens only for that read
|
|
1049
|
+
* key, under that grant and for that account. A read key of small order
|
|
1050
|
+
* yields an all-zero shared secret, which the key agreement refuses. The
|
|
1051
|
+
* ephemeral secret is zeroed before this returns; the account secret is
|
|
1052
|
+
* the caller's to zero.
|
|
1053
|
+
*/
|
|
1054
|
+
const sealGrantView = async (encSecret, { grantId, account, readPublicKey }) => {
|
|
1055
|
+
if (encSecret.length !== SECRET_LENGTH) throw new Error(`A grant view seals a ${SECRET_LENGTH}-byte secret, got ${encSecret.length} bytes.`);
|
|
1056
|
+
const grantIdBytes = require_bytes_vo.ByteArray.fromHex(require_bytes_vo.HexBytes(grantId));
|
|
1057
|
+
const accountBytes = require_bytes_vo.ByteArray.fromHex(require_bytes_vo.HexBytes(account));
|
|
1058
|
+
const readKey = require_bytes_vo.ByteArray.fromHex(require_bytes_vo.HexBytes(readPublicKey));
|
|
1059
|
+
const ephemeral = x25519.keygen();
|
|
1060
|
+
const seal = new Uint8Array(94);
|
|
1061
|
+
seal[0] = SEAL_VERSION;
|
|
1062
|
+
seal[1] = SEAL_SUITE;
|
|
1063
|
+
seal.set(ephemeral.publicKey, EPHEMERAL_KEY_OFFSET);
|
|
1064
|
+
try {
|
|
1065
|
+
const key = await sealingKey(x25519.getSharedSecret(ephemeral.secretKey, readKey), grantIdBytes);
|
|
1066
|
+
const nonce = crypto.getRandomValues(new Uint8Array(NONCE_LENGTH$1));
|
|
1067
|
+
const sealed = new Uint8Array(await crypto.subtle.encrypt({
|
|
1068
|
+
name: "AES-GCM",
|
|
1069
|
+
iv: nonce,
|
|
1070
|
+
additionalData: concat$1(seal.slice(0, NONCE_OFFSET), grantIdBytes, accountBytes),
|
|
1071
|
+
tagLength: AEAD_TAG_BITS$1
|
|
1072
|
+
}, key, encSecret));
|
|
1073
|
+
seal.set(nonce, NONCE_OFFSET);
|
|
1074
|
+
seal.set(sealed.subarray(SECRET_LENGTH), TAG_OFFSET);
|
|
1075
|
+
seal.set(sealed.subarray(0, SECRET_LENGTH), CIPHERTEXT_OFFSET);
|
|
1076
|
+
return seal;
|
|
1077
|
+
} finally {
|
|
1078
|
+
ephemeral.secretKey.fill(0);
|
|
1079
|
+
}
|
|
1080
|
+
};
|
|
1081
|
+
//#endregion
|
|
1082
|
+
//#region ../../packages/module/passport-account/src/acc/envelopes.ts
|
|
1083
|
+
/**
|
|
1084
|
+
* The Lace record kinds an Account Custody Contract inbox carries beside
|
|
1085
|
+
* the coin entries senders write: device envelopes, which deliver the
|
|
1086
|
+
* account secret and the roster key to one device's reader key; device
|
|
1087
|
+
* registrations, which name an enrolled device's reader and device keys
|
|
1088
|
+
* under the roster key; and grant records, which keep the bookkeeping of
|
|
1089
|
+
* a grant this device issued under a key only it derives. Each is one
|
|
1090
|
+
* 192-byte entry led by a type byte no custody standard reader knows, so
|
|
1091
|
+
* every other reader skips it as noise, and each opens to null rather
|
|
1092
|
+
* than an error when it is malformed, tampered with or addressed to
|
|
1093
|
+
* someone else, since anyone may append any bytes to the inbox.
|
|
1094
|
+
*/
|
|
1095
|
+
/** Type byte of a device envelope. */
|
|
1096
|
+
const DEVICE_ENVELOPE_TYPE = 209;
|
|
1097
|
+
/** Type byte of a device registration. */
|
|
1098
|
+
const DEVICE_REGISTRATION_TYPE = 210;
|
|
1099
|
+
/** Type byte of a grant record. */
|
|
1100
|
+
const GRANT_RECORD_TYPE = 211;
|
|
1101
|
+
const SUITE = 2;
|
|
1102
|
+
const KEY_LENGTH = 32;
|
|
1103
|
+
const NONCE_LENGTH = 12;
|
|
1104
|
+
const TAG_LENGTH = 16;
|
|
1105
|
+
const RECIPIENT_TAG_LENGTH = 32;
|
|
1106
|
+
const AEAD_TAG_BITS = TAG_LENGTH * 8;
|
|
1107
|
+
const MAX_COIN_VALUE_LENGTH = 16;
|
|
1108
|
+
const BYTE_BITS = 8n;
|
|
1109
|
+
const BYTE_MASK = 255n;
|
|
1110
|
+
const RECIPIENT_TAG_OFFSET = 2;
|
|
1111
|
+
const RECIPIENT_TAG_END = RECIPIENT_TAG_OFFSET + RECIPIENT_TAG_LENGTH;
|
|
1112
|
+
const ENVELOPE_EPHEMERAL_OFFSET = RECIPIENT_TAG_END;
|
|
1113
|
+
const ENVELOPE_NONCE_OFFSET = ENVELOPE_EPHEMERAL_OFFSET + KEY_LENGTH;
|
|
1114
|
+
const ENVELOPE_PLAINTEXT_LENGTH = KEY_LENGTH * 2;
|
|
1115
|
+
const REGISTRATION_NONCE_OFFSET = 2;
|
|
1116
|
+
const REGISTRATION_PLAINTEXT_LENGTH = KEY_LENGTH * 2;
|
|
1117
|
+
const RECORD_NONCE_OFFSET = RECIPIENT_TAG_END;
|
|
1118
|
+
const RECORD_PLAINTEXT_LENGTH = 192 - (RECORD_NONCE_OFFSET + NONCE_LENGTH + TAG_LENGTH);
|
|
1119
|
+
const encoder = new TextEncoder();
|
|
1120
|
+
const ENVELOPE_TAG_DOMAIN = encoder.encode("lace:passport:envelope-tag:v2");
|
|
1121
|
+
const ENVELOPE_KEY_INFO = encoder.encode("lace:passport:device-envelope:v1");
|
|
1122
|
+
const REGISTRATION_KEY_INFO = encoder.encode("lace:passport:device-registration:v1");
|
|
1123
|
+
const RECORD_KEY_INFO = encoder.encode("lace:passport:grant-record:v1");
|
|
1124
|
+
const RECORD_TAG_KEY_INFO = encoder.encode("lace:passport:grant-record-tag:v1");
|
|
1125
|
+
/**
|
|
1126
|
+
* The kinds of grant record part, by the byte that leads its plaintext.
|
|
1127
|
+
* The jubjub grant, object and view values come first, so the records
|
|
1128
|
+
* written before secp256k1 grantees read back unchanged.
|
|
1129
|
+
*/
|
|
1130
|
+
const RECORD_PART_KINDS = [
|
|
1131
|
+
{
|
|
1132
|
+
part: "grant",
|
|
1133
|
+
granteeScheme: "jubjub-schnorr"
|
|
1134
|
+
},
|
|
1135
|
+
{ part: "object" },
|
|
1136
|
+
{ part: "view" },
|
|
1137
|
+
{
|
|
1138
|
+
part: "grant",
|
|
1139
|
+
granteeScheme: "secp256k1-ecdsa",
|
|
1140
|
+
keyPrefix: 2
|
|
1141
|
+
},
|
|
1142
|
+
{
|
|
1143
|
+
part: "grant",
|
|
1144
|
+
granteeScheme: "secp256k1-ecdsa",
|
|
1145
|
+
keyPrefix: 3
|
|
1146
|
+
}
|
|
1147
|
+
];
|
|
1148
|
+
/**
|
|
1149
|
+
* A Jubjub device public key in the compressed 32-byte form a device
|
|
1150
|
+
* registration carries, as lowercase hex: the y coordinate little-endian
|
|
1151
|
+
* with the parity of x in its top bit.
|
|
1152
|
+
*/
|
|
1153
|
+
const encodeDevicePublicKey = (point) => require_bytes_vo.HexBytes.fromByteArray(require_grant_rules.jubjub.Point.fromAffine(point).toBytes());
|
|
1154
|
+
/**
|
|
1155
|
+
* The affine Jubjub point a compressed device public key names, or
|
|
1156
|
+
* undefined for hex that is no point on the curve.
|
|
1157
|
+
*/
|
|
1158
|
+
const decodeDevicePublicKey = (hex) => {
|
|
1159
|
+
try {
|
|
1160
|
+
return require_grant_rules.jubjub.Point.fromBytes(require_bytes_vo.ByteArray.fromHex(require_bytes_vo.HexBytes(hex))).toAffine();
|
|
1161
|
+
} catch {
|
|
1162
|
+
return;
|
|
1163
|
+
}
|
|
1164
|
+
};
|
|
1165
|
+
const concat = (...parts) => {
|
|
1166
|
+
const joined = new Uint8Array(parts.reduce((length, part) => length + part.length, 0));
|
|
1167
|
+
let offset = 0;
|
|
1168
|
+
for (const part of parts) {
|
|
1169
|
+
joined.set(part, offset);
|
|
1170
|
+
offset += part.length;
|
|
1171
|
+
}
|
|
1172
|
+
return joined;
|
|
1173
|
+
};
|
|
1174
|
+
const isZero = (bytes) => bytes.every((byte) => byte === 0);
|
|
1175
|
+
const equalBytes = (left, right) => left.length === right.length && left.every((byte, index) => byte === right[index]);
|
|
1176
|
+
/** Whether an entry is a 192-byte record of the given type and suite. */
|
|
1177
|
+
const isRecordOf = (entry, type) => entry.length === 192 && entry[0] === type && entry[1] === SUITE;
|
|
1178
|
+
/**
|
|
1179
|
+
* Whether an inbox entry is one of the Lace record kinds, which a coin
|
|
1180
|
+
* walk passes over rather than counts as noise.
|
|
1181
|
+
*/
|
|
1182
|
+
const isLaceRecord = (entry) => isRecordOf(entry, DEVICE_ENVELOPE_TYPE) || isRecordOf(entry, DEVICE_REGISTRATION_TYPE) || isRecordOf(entry, GRANT_RECORD_TYPE);
|
|
1183
|
+
/** Whether an inbox entry is a device registration. */
|
|
1184
|
+
const isDeviceRegistration = (entry) => isRecordOf(entry, DEVICE_REGISTRATION_TYPE);
|
|
1185
|
+
/**
|
|
1186
|
+
* The HMAC-SHA256 key HKDF-SHA256 derives from `material` under `info`
|
|
1187
|
+
* with an empty salt, imported non-extractable, so the key bytes never
|
|
1188
|
+
* exist outside it.
|
|
1189
|
+
*/
|
|
1190
|
+
const hmacKey = async (material, info) => {
|
|
1191
|
+
const key = await crypto.subtle.importKey("raw", material, "HKDF", false, ["deriveKey"]);
|
|
1192
|
+
return crypto.subtle.deriveKey({
|
|
1193
|
+
name: "HKDF",
|
|
1194
|
+
hash: "SHA-256",
|
|
1195
|
+
salt: new Uint8Array(0),
|
|
1196
|
+
info
|
|
1197
|
+
}, key, {
|
|
1198
|
+
name: "HMAC",
|
|
1199
|
+
hash: "SHA-256",
|
|
1200
|
+
length: KEY_LENGTH * 8
|
|
1201
|
+
}, false, ["sign"]);
|
|
1202
|
+
};
|
|
1203
|
+
/**
|
|
1204
|
+
* The AES-256-GCM key HKDF-SHA256 derives from `material` under `info`,
|
|
1205
|
+
* imported non-extractable, so the key bytes never exist outside it.
|
|
1206
|
+
*/
|
|
1207
|
+
const aeadKey = async (material, info) => {
|
|
1208
|
+
const key = await crypto.subtle.importKey("raw", material, "HKDF", false, ["deriveKey"]);
|
|
1209
|
+
return crypto.subtle.deriveKey({
|
|
1210
|
+
name: "HKDF",
|
|
1211
|
+
hash: "SHA-256",
|
|
1212
|
+
salt: new Uint8Array(0),
|
|
1213
|
+
info
|
|
1214
|
+
}, key, {
|
|
1215
|
+
name: "AES-GCM",
|
|
1216
|
+
length: KEY_LENGTH * 8
|
|
1217
|
+
}, false, ["encrypt", "decrypt"]);
|
|
1218
|
+
};
|
|
1219
|
+
/** A fresh AEAD nonce. */
|
|
1220
|
+
const freshNonce = () => crypto.getRandomValues(new Uint8Array(NONCE_LENGTH));
|
|
1221
|
+
/**
|
|
1222
|
+
* The associated data of an entry: every byte before its AEAD tag, less
|
|
1223
|
+
* the recipient tag when it carries one, since that tag is computed over
|
|
1224
|
+
* the sealed entry and binds it in turn.
|
|
1225
|
+
*/
|
|
1226
|
+
const associatedData = ({ entry, nonceOffset, isTagged }) => {
|
|
1227
|
+
const tagOffset = nonceOffset + NONCE_LENGTH;
|
|
1228
|
+
return isTagged ? concat(entry.subarray(0, RECIPIENT_TAG_OFFSET), entry.subarray(RECIPIENT_TAG_END, tagOffset)) : entry.slice(0, tagOffset);
|
|
1229
|
+
};
|
|
1230
|
+
/**
|
|
1231
|
+
* Encrypts `plaintext` into `entry` behind its header: the AEAD tag
|
|
1232
|
+
* after the nonce the entry already holds at `nonceOffset`, and the
|
|
1233
|
+
* ciphertext after that, with the header as associated data, see
|
|
1234
|
+
* {@link associatedData}, so the header must be complete before this
|
|
1235
|
+
* runs, its recipient tag aside.
|
|
1236
|
+
*/
|
|
1237
|
+
const sealInto = async ({ key, entry, nonceOffset, isTagged, plaintext }) => {
|
|
1238
|
+
const nonce = entry.slice(nonceOffset, nonceOffset + NONCE_LENGTH);
|
|
1239
|
+
const tagOffset = nonceOffset + NONCE_LENGTH;
|
|
1240
|
+
const sealed = new Uint8Array(await crypto.subtle.encrypt({
|
|
1241
|
+
name: "AES-GCM",
|
|
1242
|
+
iv: nonce,
|
|
1243
|
+
additionalData: associatedData({
|
|
1244
|
+
entry,
|
|
1245
|
+
nonceOffset,
|
|
1246
|
+
isTagged
|
|
1247
|
+
}),
|
|
1248
|
+
tagLength: AEAD_TAG_BITS
|
|
1249
|
+
}, key, plaintext));
|
|
1250
|
+
entry.set(sealed.subarray(plaintext.length), tagOffset);
|
|
1251
|
+
entry.set(sealed.subarray(0, plaintext.length), tagOffset + TAG_LENGTH);
|
|
1252
|
+
};
|
|
1253
|
+
/**
|
|
1254
|
+
* Decrypts the ciphertext behind an entry's header, or null when the
|
|
1255
|
+
* authentication fails or the padding after the ciphertext is not zero.
|
|
1256
|
+
*/
|
|
1257
|
+
const openFrom = async ({ key, entry, nonceOffset, isTagged, plaintextLength }) => {
|
|
1258
|
+
const tagOffset = nonceOffset + NONCE_LENGTH;
|
|
1259
|
+
const ciphertextOffset = tagOffset + TAG_LENGTH;
|
|
1260
|
+
if (!isZero(entry.subarray(ciphertextOffset + plaintextLength))) return null;
|
|
1261
|
+
try {
|
|
1262
|
+
return new Uint8Array(await crypto.subtle.decrypt({
|
|
1263
|
+
name: "AES-GCM",
|
|
1264
|
+
iv: entry.slice(nonceOffset, tagOffset),
|
|
1265
|
+
additionalData: associatedData({
|
|
1266
|
+
entry,
|
|
1267
|
+
nonceOffset,
|
|
1268
|
+
isTagged
|
|
1269
|
+
}),
|
|
1270
|
+
tagLength: AEAD_TAG_BITS
|
|
1271
|
+
}, key, concat(entry.subarray(ciphertextOffset, ciphertextOffset + plaintextLength), entry.subarray(tagOffset, ciphertextOffset))));
|
|
1272
|
+
} catch {
|
|
1273
|
+
return null;
|
|
1274
|
+
}
|
|
1275
|
+
};
|
|
1276
|
+
/**
|
|
1277
|
+
* The recipient tag of a device envelope: SHA-256 over the tag domain,
|
|
1278
|
+
* the type and suite bytes, the reader public key and every byte after
|
|
1279
|
+
* the tag, the ephemeral key, the nonce, the AEAD tag, the ciphertext
|
|
1280
|
+
* and the padding. A reader finds its envelopes by recomputing it, so
|
|
1281
|
+
* an entry that copies a genuine envelope's tag with any other byte
|
|
1282
|
+
* changed is not taken for one, and writing an entry that is takes the
|
|
1283
|
+
* reader public key. Two envelopes to the same reader share nothing on
|
|
1284
|
+
* chain, since each carries its own ephemeral key.
|
|
1285
|
+
*/
|
|
1286
|
+
const envelopeTag = (readerPublicKey, entry) => require_errors.sha256(concat(ENVELOPE_TAG_DOMAIN, entry.subarray(0, RECIPIENT_TAG_OFFSET), readerPublicKey, entry.subarray(RECIPIENT_TAG_END)));
|
|
1287
|
+
/** Whether an entry is a device envelope addressed to this reader public key. */
|
|
1288
|
+
const isAddressedTo = (entry, readerPublicKey) => isRecordOf(entry, DEVICE_ENVELOPE_TYPE) && equalBytes(entry.subarray(RECIPIENT_TAG_OFFSET, RECIPIENT_TAG_END), envelopeTag(readerPublicKey, entry));
|
|
1289
|
+
/**
|
|
1290
|
+
* Every envelope in an inbox addressed to this device, newest first: the
|
|
1291
|
+
* ones a keyring carries. Anyone who knows a reader key can append
|
|
1292
|
+
* envelopes tagged for it, so none is left out, and the live one is
|
|
1293
|
+
* found however many land after it, at the cost of opening each.
|
|
1294
|
+
*/
|
|
1295
|
+
const deviceEnvelopes = (entries, readerPublicKey) => entries.filter((entry) => isAddressedTo(entry, readerPublicKey)).reverse();
|
|
1296
|
+
/**
|
|
1297
|
+
* The AES-256-GCM key of one envelope: HKDF-SHA256 over the X25519 shared
|
|
1298
|
+
* secret, zeroed once the key is derived.
|
|
1299
|
+
*/
|
|
1300
|
+
const envelopeKey = async (shared) => {
|
|
1301
|
+
try {
|
|
1302
|
+
return await aeadKey(shared, ENVELOPE_KEY_INFO);
|
|
1303
|
+
} finally {
|
|
1304
|
+
shared.fill(0);
|
|
1305
|
+
}
|
|
1306
|
+
};
|
|
1307
|
+
/**
|
|
1308
|
+
* Seals the account secret and the roster key to one device's reader key
|
|
1309
|
+
* as a device envelope: [0] type, [1] suite, [2..34) recipient tag,
|
|
1310
|
+
* [34..66) ephemeral X25519 public key, [66..78) nonce, [78..94) AEAD
|
|
1311
|
+
* tag, [94..158) the secret then the roster key, encrypted, and zero
|
|
1312
|
+
* padding to 192 bytes. The key is agreed between a fresh ephemeral key
|
|
1313
|
+
* and the reader key, everything before the AEAD tag but the recipient
|
|
1314
|
+
* tag is associated data, and the recipient tag, computed last, covers
|
|
1315
|
+
* the whole sealed envelope. The envelope carries no round or
|
|
1316
|
+
* `enc_key`: a reader trusts the secret only once it derives the
|
|
1317
|
+
* `enc_key` the ledger holds. The ephemeral secret is zeroed before this
|
|
1318
|
+
* returns.
|
|
1319
|
+
*/
|
|
1320
|
+
const sealDeviceEnvelope = async (readerPublicKey, { secret, rosterKey }) => {
|
|
1321
|
+
const ephemeral = x25519.keygen();
|
|
1322
|
+
const plaintext = concat(secret, rosterKey);
|
|
1323
|
+
const entry = new Uint8Array(192);
|
|
1324
|
+
entry[0] = DEVICE_ENVELOPE_TYPE;
|
|
1325
|
+
entry[1] = SUITE;
|
|
1326
|
+
entry.set(ephemeral.publicKey, ENVELOPE_EPHEMERAL_OFFSET);
|
|
1327
|
+
entry.set(freshNonce(), ENVELOPE_NONCE_OFFSET);
|
|
1328
|
+
try {
|
|
1329
|
+
await sealInto({
|
|
1330
|
+
key: await envelopeKey(x25519.getSharedSecret(ephemeral.secretKey, readerPublicKey)),
|
|
1331
|
+
entry,
|
|
1332
|
+
nonceOffset: ENVELOPE_NONCE_OFFSET,
|
|
1333
|
+
isTagged: true,
|
|
1334
|
+
plaintext
|
|
1335
|
+
});
|
|
1336
|
+
entry.set(envelopeTag(readerPublicKey, entry), RECIPIENT_TAG_OFFSET);
|
|
1337
|
+
return entry;
|
|
1338
|
+
} finally {
|
|
1339
|
+
ephemeral.secretKey.fill(0);
|
|
1340
|
+
plaintext.fill(0);
|
|
1341
|
+
}
|
|
1342
|
+
};
|
|
1343
|
+
/**
|
|
1344
|
+
* Opens a device envelope with this device's reader secret. Resolves the
|
|
1345
|
+
* account secret and roster key it delivers, which the caller zeroes once
|
|
1346
|
+
* used, or null for an entry that is not an envelope, is addressed to
|
|
1347
|
+
* another reader or fails to authenticate.
|
|
1348
|
+
*/
|
|
1349
|
+
const openDeviceEnvelope = async (readerSecret, entry) => {
|
|
1350
|
+
if (!isAddressedTo(entry, x25519.getPublicKey(readerSecret))) return null;
|
|
1351
|
+
let key;
|
|
1352
|
+
try {
|
|
1353
|
+
key = await envelopeKey(x25519.getSharedSecret(readerSecret, entry.slice(ENVELOPE_EPHEMERAL_OFFSET, ENVELOPE_NONCE_OFFSET)));
|
|
1354
|
+
} catch {
|
|
1355
|
+
return null;
|
|
1356
|
+
}
|
|
1357
|
+
const plaintext = await openFrom({
|
|
1358
|
+
key,
|
|
1359
|
+
entry,
|
|
1360
|
+
nonceOffset: ENVELOPE_NONCE_OFFSET,
|
|
1361
|
+
isTagged: true,
|
|
1362
|
+
plaintextLength: ENVELOPE_PLAINTEXT_LENGTH
|
|
1363
|
+
});
|
|
1364
|
+
if (!plaintext) return null;
|
|
1365
|
+
try {
|
|
1366
|
+
return {
|
|
1367
|
+
secret: plaintext.slice(0, KEY_LENGTH),
|
|
1368
|
+
rosterKey: plaintext.slice(KEY_LENGTH)
|
|
1369
|
+
};
|
|
1370
|
+
} finally {
|
|
1371
|
+
plaintext.fill(0);
|
|
1372
|
+
}
|
|
1373
|
+
};
|
|
1374
|
+
/**
|
|
1375
|
+
* Seals one enrolled device's reader and device keys under the roster key
|
|
1376
|
+
* as a device registration: [0] type, [1] suite, [2..14) nonce, [14..30)
|
|
1377
|
+
* AEAD tag, [30..94) the reader key then the device key, encrypted, and
|
|
1378
|
+
* zero padding to 192 bytes. Only a holder of the roster key, an enrolled
|
|
1379
|
+
* device, can write one that opens, and nothing on chain tells whose it
|
|
1380
|
+
* is.
|
|
1381
|
+
*/
|
|
1382
|
+
const sealDeviceRegistration = async (rosterKey, { readerPublicKey, devicePublicKey }) => {
|
|
1383
|
+
const entry = new Uint8Array(192);
|
|
1384
|
+
entry[0] = DEVICE_REGISTRATION_TYPE;
|
|
1385
|
+
entry[1] = SUITE;
|
|
1386
|
+
entry.set(freshNonce(), REGISTRATION_NONCE_OFFSET);
|
|
1387
|
+
await sealInto({
|
|
1388
|
+
key: await aeadKey(rosterKey, REGISTRATION_KEY_INFO),
|
|
1389
|
+
entry,
|
|
1390
|
+
nonceOffset: REGISTRATION_NONCE_OFFSET,
|
|
1391
|
+
isTagged: false,
|
|
1392
|
+
plaintext: concat(require_bytes_vo.ByteArray.fromHex(require_bytes_vo.HexBytes(readerPublicKey)), require_bytes_vo.ByteArray.fromHex(require_bytes_vo.HexBytes(devicePublicKey)))
|
|
1393
|
+
});
|
|
1394
|
+
return entry;
|
|
1395
|
+
};
|
|
1396
|
+
/**
|
|
1397
|
+
* Opens a device registration with the roster key: the device it names,
|
|
1398
|
+
* or null for an entry that is not a registration or was written under
|
|
1399
|
+
* another roster key.
|
|
1400
|
+
*/
|
|
1401
|
+
const openDeviceRegistration = async (rosterKey, entry) => {
|
|
1402
|
+
if (!isRecordOf(entry, DEVICE_REGISTRATION_TYPE)) return null;
|
|
1403
|
+
const plaintext = await openFrom({
|
|
1404
|
+
key: await aeadKey(rosterKey, REGISTRATION_KEY_INFO),
|
|
1405
|
+
entry,
|
|
1406
|
+
nonceOffset: REGISTRATION_NONCE_OFFSET,
|
|
1407
|
+
isTagged: false,
|
|
1408
|
+
plaintextLength: REGISTRATION_PLAINTEXT_LENGTH
|
|
1409
|
+
});
|
|
1410
|
+
return plaintext && {
|
|
1411
|
+
readerPublicKey: require_bytes_vo.HexBytes.fromByteArray(plaintext.slice(0, KEY_LENGTH)),
|
|
1412
|
+
devicePublicKey: require_bytes_vo.HexBytes.fromByteArray(plaintext.slice(KEY_LENGTH))
|
|
1413
|
+
};
|
|
1414
|
+
};
|
|
1415
|
+
/**
|
|
1416
|
+
* The keys of this device's grant records on one account, both derived
|
|
1417
|
+
* from its reader secret with the account address in the label: the
|
|
1418
|
+
* AES-256-GCM key and the key its recipient tags are computed under, so
|
|
1419
|
+
* only this device writes a record that opens or recognises one as its
|
|
1420
|
+
* own, and a record copied from another account is neither.
|
|
1421
|
+
*/
|
|
1422
|
+
const recordKeys = async (readerSecret, account) => {
|
|
1423
|
+
const accountBytes = require_bytes_vo.ByteArray.fromHex(require_bytes_vo.HexBytes(account));
|
|
1424
|
+
return {
|
|
1425
|
+
key: await aeadKey(readerSecret, concat(RECORD_KEY_INFO, accountBytes)),
|
|
1426
|
+
tagKey: await hmacKey(readerSecret, concat(RECORD_TAG_KEY_INFO, accountBytes))
|
|
1427
|
+
};
|
|
1428
|
+
};
|
|
1429
|
+
/**
|
|
1430
|
+
* The recipient tag of a grant record: HMAC-SHA256 under the tag key
|
|
1431
|
+
* over the type and suite bytes and every byte after the tag, the
|
|
1432
|
+
* nonce, the AEAD tag and the ciphertext, so a copied tag with any other
|
|
1433
|
+
* byte changed is not taken for this device's.
|
|
1434
|
+
*/
|
|
1435
|
+
const recordTag = async (tagKey, entry) => new Uint8Array(await crypto.subtle.sign("HMAC", tagKey, concat(entry.subarray(0, RECIPIENT_TAG_OFFSET), entry.subarray(RECIPIENT_TAG_END))));
|
|
1436
|
+
const encodeAmount = (value) => {
|
|
1437
|
+
const bytes = new Uint8Array(MAX_COIN_VALUE_LENGTH);
|
|
1438
|
+
let remaining = BigInt(value);
|
|
1439
|
+
for (let index = MAX_COIN_VALUE_LENGTH - 1; index >= 0; index -= 1) {
|
|
1440
|
+
bytes[index] = Number(remaining & BYTE_MASK);
|
|
1441
|
+
remaining >>= BYTE_BITS;
|
|
1442
|
+
}
|
|
1443
|
+
return bytes;
|
|
1444
|
+
};
|
|
1445
|
+
const decodeAmount = (bytes) => bytes.reduce((value, byte) => value << BYTE_BITS | BigInt(byte), 0n).toString();
|
|
1446
|
+
const hexBytes = (hex) => require_bytes_vo.ByteArray.fromHex(require_bytes_vo.HexBytes(hex));
|
|
1447
|
+
const encodeRecipient = (recipient) => concat(Uint8Array.of(Number(require_grant_rules.RECIPIENT_KINDS[recipient.kind])), recipient.kind === "any" ? new Uint8Array(KEY_LENGTH) : hexBytes(recipient.value));
|
|
1448
|
+
const RECIPIENT_BY_KIND = new Map(Object.entries(require_grant_rules.RECIPIENT_KINDS).map(([kind, value]) => [Number(value), kind]));
|
|
1449
|
+
const decodeRecipient = (bytes) => {
|
|
1450
|
+
const kind = RECIPIENT_BY_KIND.get(bytes[0]);
|
|
1451
|
+
const value = bytes.subarray(1);
|
|
1452
|
+
if (kind === void 0) return null;
|
|
1453
|
+
if (kind === "any") return isZero(value) ? { kind } : null;
|
|
1454
|
+
return {
|
|
1455
|
+
kind,
|
|
1456
|
+
value: require_bytes_vo.HexBytes.fromByteArray(value)
|
|
1457
|
+
};
|
|
1458
|
+
};
|
|
1459
|
+
/** The part byte of an object or a view part, which take one value each. */
|
|
1460
|
+
const partByteOf = (part) => RECORD_PART_KINDS.findIndex((kind) => kind.part === part);
|
|
1461
|
+
/**
|
|
1462
|
+
* The grantee field of a grant part and the part byte that names how it
|
|
1463
|
+
* reads back, see {@link RecordPartKind}.
|
|
1464
|
+
*
|
|
1465
|
+
* @throws Error when the key is not in a form the record holds: a 32-byte
|
|
1466
|
+
* jubjub key, or a 33-byte compressed secp256k1 key prefixed 02 or 03.
|
|
1467
|
+
*/
|
|
1468
|
+
const encodeGrantee = (part) => {
|
|
1469
|
+
const key = hexBytes(part.granteePublicKey);
|
|
1470
|
+
const keyPrefix = part.granteeScheme === "secp256k1-ecdsa" ? key[0] : void 0;
|
|
1471
|
+
const field = keyPrefix === void 0 ? key : key.subarray(1);
|
|
1472
|
+
const partByte = RECORD_PART_KINDS.findIndex((kind) => kind.part === "grant" && kind.granteeScheme === part.granteeScheme && kind.keyPrefix === keyPrefix);
|
|
1473
|
+
if (partByte < 0 || field.length !== KEY_LENGTH) throw new Error(`Grant record cannot carry this '${part.granteeScheme}' grantee key`);
|
|
1474
|
+
return {
|
|
1475
|
+
partByte,
|
|
1476
|
+
field
|
|
1477
|
+
};
|
|
1478
|
+
};
|
|
1479
|
+
/**
|
|
1480
|
+
* The plaintext of one grant record part, 130 bytes: the part byte and
|
|
1481
|
+
* the grant id, then for a grant the slot, the scope salt, the grantee
|
|
1482
|
+
* field and the read key (zero for none); for an object the colour, the
|
|
1483
|
+
* recipient kind and value, and the coin bound as a big-endian 128-bit
|
|
1484
|
+
* integer; for a view the leading bytes of `enc_key` and the 94-byte
|
|
1485
|
+
* seal; zero padding after. The part byte of a grant also names the form
|
|
1486
|
+
* of its grantee key, see {@link RecordPartKind}, and a grant part whose
|
|
1487
|
+
* grantee the format cannot hold is refused before anything is written.
|
|
1488
|
+
*/
|
|
1489
|
+
const encodeRecordPart = (part) => {
|
|
1490
|
+
const plaintext = new Uint8Array(RECORD_PLAINTEXT_LENGTH);
|
|
1491
|
+
plaintext.set(hexBytes(part.grantId), 1);
|
|
1492
|
+
const body = 1 + KEY_LENGTH;
|
|
1493
|
+
switch (part.part) {
|
|
1494
|
+
case "grant": {
|
|
1495
|
+
const { partByte, field } = encodeGrantee(part);
|
|
1496
|
+
plaintext[0] = partByte;
|
|
1497
|
+
plaintext[body] = part.slot;
|
|
1498
|
+
plaintext.set(hexBytes(part.scopeSalt), body + 1);
|
|
1499
|
+
plaintext.set(field, body + 1 + KEY_LENGTH);
|
|
1500
|
+
if (part.readPublicKey !== void 0) plaintext.set(hexBytes(part.readPublicKey), body + 1 + KEY_LENGTH * 2);
|
|
1501
|
+
return plaintext;
|
|
1502
|
+
}
|
|
1503
|
+
case "object":
|
|
1504
|
+
plaintext[0] = partByteOf(part.part);
|
|
1505
|
+
plaintext.set(hexBytes(part.object.color), body);
|
|
1506
|
+
plaintext.set(encodeRecipient(part.object.recipient), body + KEY_LENGTH);
|
|
1507
|
+
plaintext.set(encodeAmount(part.object.maxCoinValue), body + KEY_LENGTH * 2 + 1);
|
|
1508
|
+
return plaintext;
|
|
1509
|
+
case "view":
|
|
1510
|
+
plaintext[0] = partByteOf(part.part);
|
|
1511
|
+
plaintext.set(hexBytes(part.encKeyPrefix), body);
|
|
1512
|
+
plaintext.set(hexBytes(part.seal), body + 3);
|
|
1513
|
+
return plaintext;
|
|
1514
|
+
}
|
|
1515
|
+
};
|
|
1516
|
+
const decodeObject = (body) => {
|
|
1517
|
+
const recipient = decodeRecipient(body.subarray(KEY_LENGTH, KEY_LENGTH * 2 + 1));
|
|
1518
|
+
const amountOffset = KEY_LENGTH * 2 + 1;
|
|
1519
|
+
if (!recipient || !isZero(body.subarray(amountOffset + MAX_COIN_VALUE_LENGTH))) return null;
|
|
1520
|
+
return {
|
|
1521
|
+
color: require_bytes_vo.HexBytes.fromByteArray(body.subarray(0, KEY_LENGTH)),
|
|
1522
|
+
recipient,
|
|
1523
|
+
maxCoinValue: decodeAmount(body.subarray(amountOffset, amountOffset + MAX_COIN_VALUE_LENGTH))
|
|
1524
|
+
};
|
|
1525
|
+
};
|
|
1526
|
+
/** Reads a grant record part back, or null for a plaintext no writer produces. */
|
|
1527
|
+
const decodeRecordPart = (plaintext) => {
|
|
1528
|
+
const kind = RECORD_PART_KINDS.at(plaintext[0]);
|
|
1529
|
+
if (!kind) return null;
|
|
1530
|
+
const grantId = require_grant_rules.GrantId(require_bytes_vo.HexBytes.fromByteArray(plaintext.slice(1, 33)));
|
|
1531
|
+
const body = plaintext.subarray(1 + KEY_LENGTH);
|
|
1532
|
+
switch (kind.part) {
|
|
1533
|
+
case "grant": {
|
|
1534
|
+
const field = body.subarray(1 + KEY_LENGTH, 1 + KEY_LENGTH * 2);
|
|
1535
|
+
const readKey = body.subarray(1 + KEY_LENGTH * 2);
|
|
1536
|
+
return {
|
|
1537
|
+
part: kind.part,
|
|
1538
|
+
grantId,
|
|
1539
|
+
slot: require_grant_rules.GrantSlot(body[0]),
|
|
1540
|
+
scopeSalt: require_grant_rules.GrantScopeSalt(require_bytes_vo.HexBytes.fromByteArray(body.subarray(1, 1 + KEY_LENGTH))),
|
|
1541
|
+
granteeScheme: kind.granteeScheme,
|
|
1542
|
+
granteePublicKey: require_bytes_vo.HexBytes.fromByteArray(kind.keyPrefix === void 0 ? field : concat(Uint8Array.of(kind.keyPrefix), field)),
|
|
1543
|
+
...isZero(readKey) ? {} : { readPublicKey: require_bytes_vo.HexBytes.fromByteArray(readKey) }
|
|
1544
|
+
};
|
|
1545
|
+
}
|
|
1546
|
+
case "object": {
|
|
1547
|
+
const object = decodeObject(body);
|
|
1548
|
+
return object && {
|
|
1549
|
+
part: kind.part,
|
|
1550
|
+
grantId,
|
|
1551
|
+
object
|
|
1552
|
+
};
|
|
1553
|
+
}
|
|
1554
|
+
case "view": return {
|
|
1555
|
+
part: kind.part,
|
|
1556
|
+
grantId,
|
|
1557
|
+
encKeyPrefix: require_bytes_vo.HexBytes.fromByteArray(body.subarray(0, 3)),
|
|
1558
|
+
seal: require_bytes_vo.HexBytes.fromByteArray(body.subarray(3, 97))
|
|
1559
|
+
};
|
|
1560
|
+
}
|
|
1561
|
+
};
|
|
1562
|
+
/**
|
|
1563
|
+
* Seals one part of a grant's bookkeeping for this device alone as a
|
|
1564
|
+
* grant record: [0] type, [1] suite, [2..34) recipient tag, [34..46)
|
|
1565
|
+
* nonce, [46..62) AEAD tag, [62..192) the 130-byte part, encrypted, with
|
|
1566
|
+
* everything before the AEAD tag but the recipient tag as associated
|
|
1567
|
+
* data. The key and the tag key are derived from this device's reader
|
|
1568
|
+
* secret and the account, so only this device writes a record that opens
|
|
1569
|
+
* and recognises its own on that account, and the tag, computed last
|
|
1570
|
+
* over the whole sealed record and its fresh nonce, links no two
|
|
1571
|
+
* records.
|
|
1572
|
+
*/
|
|
1573
|
+
const sealGrantRecord = async (readerSecret, account, part) => {
|
|
1574
|
+
const { key, tagKey } = await recordKeys(readerSecret, account);
|
|
1575
|
+
const plaintext = encodeRecordPart(part);
|
|
1576
|
+
const entry = new Uint8Array(192);
|
|
1577
|
+
entry[0] = GRANT_RECORD_TYPE;
|
|
1578
|
+
entry[1] = SUITE;
|
|
1579
|
+
entry.set(freshNonce(), RECORD_NONCE_OFFSET);
|
|
1580
|
+
try {
|
|
1581
|
+
await sealInto({
|
|
1582
|
+
key,
|
|
1583
|
+
entry,
|
|
1584
|
+
nonceOffset: RECORD_NONCE_OFFSET,
|
|
1585
|
+
isTagged: true,
|
|
1586
|
+
plaintext
|
|
1587
|
+
});
|
|
1588
|
+
entry.set(await recordTag(tagKey, entry), RECIPIENT_TAG_OFFSET);
|
|
1589
|
+
return entry;
|
|
1590
|
+
} finally {
|
|
1591
|
+
plaintext.fill(0);
|
|
1592
|
+
}
|
|
1593
|
+
};
|
|
1594
|
+
/**
|
|
1595
|
+
* Opens a grant record of one account with this device's reader secret:
|
|
1596
|
+
* the part it holds, or null for an entry that is not a grant record,
|
|
1597
|
+
* carries another device's or another account's tag, fails to
|
|
1598
|
+
* authenticate or decodes to no part.
|
|
1599
|
+
*/
|
|
1600
|
+
const openGrantRecord = async (readerSecret, account, entry) => {
|
|
1601
|
+
if (!isRecordOf(entry, GRANT_RECORD_TYPE)) return null;
|
|
1602
|
+
const { key, tagKey } = await recordKeys(readerSecret, account);
|
|
1603
|
+
if (!equalBytes(await recordTag(tagKey, entry), entry.subarray(RECIPIENT_TAG_OFFSET, RECIPIENT_TAG_END))) return null;
|
|
1604
|
+
const plaintext = await openFrom({
|
|
1605
|
+
key,
|
|
1606
|
+
entry,
|
|
1607
|
+
nonceOffset: RECORD_NONCE_OFFSET,
|
|
1608
|
+
isTagged: true,
|
|
1609
|
+
plaintextLength: RECORD_PLAINTEXT_LENGTH
|
|
1610
|
+
});
|
|
1611
|
+
if (!plaintext) return null;
|
|
1612
|
+
try {
|
|
1613
|
+
return decodeRecordPart(plaintext);
|
|
1614
|
+
} catch {
|
|
1615
|
+
return null;
|
|
1616
|
+
} finally {
|
|
1617
|
+
plaintext.fill(0);
|
|
1618
|
+
}
|
|
1619
|
+
};
|
|
1620
|
+
//#endregion
|
|
1621
|
+
Object.defineProperty(exports, "MAX_INBOX_ENTRIES_PER_REQUEST", {
|
|
1622
|
+
enumerable: true,
|
|
1623
|
+
get: function() {
|
|
1624
|
+
return MAX_INBOX_ENTRIES_PER_REQUEST;
|
|
1625
|
+
}
|
|
1626
|
+
});
|
|
1627
|
+
Object.defineProperty(exports, "decodeDevicePublicKey", {
|
|
1628
|
+
enumerable: true,
|
|
1629
|
+
get: function() {
|
|
1630
|
+
return decodeDevicePublicKey;
|
|
1631
|
+
}
|
|
1632
|
+
});
|
|
1633
|
+
Object.defineProperty(exports, "deviceEnvelopes", {
|
|
1634
|
+
enumerable: true,
|
|
1635
|
+
get: function() {
|
|
1636
|
+
return deviceEnvelopes;
|
|
1637
|
+
}
|
|
1638
|
+
});
|
|
1639
|
+
Object.defineProperty(exports, "encodeDevicePublicKey", {
|
|
1640
|
+
enumerable: true,
|
|
1641
|
+
get: function() {
|
|
1642
|
+
return encodeDevicePublicKey;
|
|
1643
|
+
}
|
|
1644
|
+
});
|
|
1645
|
+
Object.defineProperty(exports, "isAddressedTo", {
|
|
1646
|
+
enumerable: true,
|
|
1647
|
+
get: function() {
|
|
1648
|
+
return isAddressedTo;
|
|
1649
|
+
}
|
|
1650
|
+
});
|
|
1651
|
+
Object.defineProperty(exports, "isDeviceRegistration", {
|
|
1652
|
+
enumerable: true,
|
|
1653
|
+
get: function() {
|
|
1654
|
+
return isDeviceRegistration;
|
|
1655
|
+
}
|
|
1656
|
+
});
|
|
1657
|
+
Object.defineProperty(exports, "isLaceRecord", {
|
|
1658
|
+
enumerable: true,
|
|
1659
|
+
get: function() {
|
|
1660
|
+
return isLaceRecord;
|
|
1661
|
+
}
|
|
1662
|
+
});
|
|
1663
|
+
Object.defineProperty(exports, "openDeviceEnvelope", {
|
|
1664
|
+
enumerable: true,
|
|
1665
|
+
get: function() {
|
|
1666
|
+
return openDeviceEnvelope;
|
|
1667
|
+
}
|
|
1668
|
+
});
|
|
1669
|
+
Object.defineProperty(exports, "openDeviceRegistration", {
|
|
1670
|
+
enumerable: true,
|
|
1671
|
+
get: function() {
|
|
1672
|
+
return openDeviceRegistration;
|
|
1673
|
+
}
|
|
1674
|
+
});
|
|
1675
|
+
Object.defineProperty(exports, "openGrantRecord", {
|
|
1676
|
+
enumerable: true,
|
|
1677
|
+
get: function() {
|
|
1678
|
+
return openGrantRecord;
|
|
1679
|
+
}
|
|
1680
|
+
});
|
|
1681
|
+
Object.defineProperty(exports, "openInboxEntry", {
|
|
1682
|
+
enumerable: true,
|
|
1683
|
+
get: function() {
|
|
1684
|
+
return openInboxEntry;
|
|
1685
|
+
}
|
|
1686
|
+
});
|
|
1687
|
+
Object.defineProperty(exports, "sealDeviceEnvelope", {
|
|
1688
|
+
enumerable: true,
|
|
1689
|
+
get: function() {
|
|
1690
|
+
return sealDeviceEnvelope;
|
|
1691
|
+
}
|
|
1692
|
+
});
|
|
1693
|
+
Object.defineProperty(exports, "sealDeviceRegistration", {
|
|
1694
|
+
enumerable: true,
|
|
1695
|
+
get: function() {
|
|
1696
|
+
return sealDeviceRegistration;
|
|
1697
|
+
}
|
|
1698
|
+
});
|
|
1699
|
+
Object.defineProperty(exports, "sealGrantRecord", {
|
|
1700
|
+
enumerable: true,
|
|
1701
|
+
get: function() {
|
|
1702
|
+
return sealGrantRecord;
|
|
1703
|
+
}
|
|
1704
|
+
});
|
|
1705
|
+
Object.defineProperty(exports, "sealGrantView", {
|
|
1706
|
+
enumerable: true,
|
|
1707
|
+
get: function() {
|
|
1708
|
+
return sealGrantView;
|
|
1709
|
+
}
|
|
1710
|
+
});
|
|
1711
|
+
Object.defineProperty(exports, "sealInboxEntry", {
|
|
1712
|
+
enumerable: true,
|
|
1713
|
+
get: function() {
|
|
1714
|
+
return sealInboxEntry;
|
|
1715
|
+
}
|
|
1716
|
+
});
|
|
1717
|
+
Object.defineProperty(exports, "x25519", {
|
|
1718
|
+
enumerable: true,
|
|
1719
|
+
get: function() {
|
|
1720
|
+
return x25519;
|
|
1721
|
+
}
|
|
1722
|
+
});
|