optimize SEA.pair

This commit is contained in:
noname 2025-01-26 12:14:02 +07:00
parent 7e254ae13f
commit 93ba2115c4
2 changed files with 38 additions and 150 deletions

93
sea.js
View File

@ -332,86 +332,30 @@
return;
}});
//SEA.pair = async (data, proof, cb) => { try {
SEA.pair = SEA.pair || (async (cb, opt) => { try {
var ecdhSubtle = shim.ossl || shim.subtle;
var sa = {};
var dh = {};
const e = new shim.TextEncoder();
const h = async d => shim.Buffer.from(await shim.subtle.digest('SHA-256', e.encode(d))).toString('base64').replace(/[+/=]/g,c=>({'+':'-','/':'_','=':''})[c]).slice(0,43);
const g = async k => (await Promise.all([h(k+'-x'), h(k+'-y')])).join('.');
let r = {};
// Helper function to generate pub from priv
const pubFromPriv = async (priv) => {
const [x,y] = await Promise.all([
shim.subtle.digest('SHA-256', e.encode(priv+'-x')),
shim.subtle.digest('SHA-256', e.encode(priv+'-y'))
]);
return shim.Buffer.from(x).toString('base64').replace(/[+/=]/g,c=>({'+':'-','/':'_','=':''})[c]).slice(0,43) +
'.' +
shim.Buffer.from(y).toString('base64').replace(/[+/=]/g,c=>({'+':'-','/':'_','=':''})[c]).slice(0,43);
if(opt && opt.seed){
r = { priv: await h(opt.seed+'-sign'), epriv: await h(opt.seed+'-encrypt') };
}
// Helper function to generate epub from epriv
const epubFromEpriv = async (epriv) => {
const [ex,ey] = await Promise.all([
shim.subtle.digest('SHA-256', e.encode(epriv+'-x')),
shim.subtle.digest('SHA-256', e.encode(epriv+'-y'))
]);
return shim.Buffer.from(ex).toString('base64').replace(/[+/=]/g,c=>({'+':'-','/':'_','=':''})[c]).slice(0,43) +
'.' +
shim.Buffer.from(ey).toString('base64').replace(/[+/=]/g,c=>({'+':'-','/':'_','=':''})[c]).slice(0,43);
else if(opt && opt.priv){
r = { priv: opt.priv, epriv: opt.epriv || await h(opt.priv+'-encrypt') };
}
if(opt && opt.seed){ // Case 0: Generate from seed
const h = await shim.subtle.digest('SHA-256', e.encode(opt.seed+'-sign'));
sa.priv = shim.Buffer.from(h).toString('base64').replace(/[+/=]/g,c=>({'+':'-','/':'_','=':''})[c]).slice(0,43);
sa.pub = await pubFromPriv(sa.priv);
const eh = await shim.subtle.digest('SHA-256', e.encode(opt.seed+'-encrypt'));
dh.epriv = shim.Buffer.from(eh).toString('base64').replace(/[+/=]/g,c=>({'+':'-','/':'_','=':''})[c]).slice(0,43);
dh.epub = await epubFromEpriv(dh.epriv);
else if(opt && opt.epriv){
r = { epriv: opt.epriv, priv: await h(opt.epriv+'-sign') };
}
else if(opt && opt.priv){ // Case 1 & 3: Given priv
sa.priv = opt.priv;
sa.pub = await pubFromPriv(sa.priv);
if(!opt.epriv){ // Case 1: Generate epriv
// Generate a virtual seed from priv to maintain compatibility
const virtualSeed = sa.priv;
const eh = await shim.subtle.digest('SHA-256', e.encode(virtualSeed+'-encrypt'));
dh.epriv = shim.Buffer.from(eh).toString('base64').replace(/[+/=]/g,c=>({'+':'-','/':'_','=':''})[c]).slice(0,43);
} else { // Case 3: Use provided epriv
dh.epriv = opt.epriv;
}
dh.epub = await epubFromEpriv(dh.epriv);
}
else if(opt && opt.epriv){ // Case 2: Given epriv
dh.epriv = opt.epriv;
dh.epub = await epubFromEpriv(dh.epriv);
// Generate a virtual seed from epriv to maintain compatibility
const virtualSeed = dh.epriv;
const h = await shim.subtle.digest('SHA-256', e.encode(virtualSeed+'-sign'));
sa.priv = shim.Buffer.from(h).toString('base64').replace(/[+/=]/g,c=>({'+':'-','/':'_','=':''})[c]).slice(0,43);
sa.pub = await pubFromPriv(sa.priv);
}
else { // Case 4: Generate new keypair
// First: ECDSA keys for signing/verifying...
const keys = await shim.subtle.generateKey({name: 'ECDSA', namedCurve: 'P-256'}, true, [ 'sign', 'verify' ]);
const priv = await shim.subtle.exportKey('jwk', keys.privateKey);
const pub = await shim.subtle.exportKey('jwk', keys.publicKey);
sa = {
priv: priv.d,
pub: pub.x + '.' + pub.y
};
// Next: ECDH keys for encryption/decryption...
else {
const keys = await shim.subtle.generateKey({name: 'ECDSA', namedCurve: 'P-256'}, true, ['sign', 'verify']);
const [priv, pub] = await Promise.all([shim.subtle.exportKey('jwk', keys.privateKey), shim.subtle.exportKey('jwk', keys.publicKey)]);
r = { priv: priv.d, pub: pub.x+'.'+pub.y };
try {
const dhKeys = await ecdhSubtle.generateKey({name: 'ECDH', namedCurve: 'P-256'}, true, ['deriveKey']);
const dhPriv = await ecdhSubtle.exportKey('jwk', dhKeys.privateKey);
const dhPub = await ecdhSubtle.exportKey('jwk', dhKeys.publicKey);
dh = {
epriv: dhPriv.d,
epub: dhPub.x + '.' + dhPub.y
};
const dhKeys = await (shim.ossl || shim.subtle).generateKey({name: 'ECDH', namedCurve: 'P-256'}, true, ['deriveKey']);
const [dhPriv, dhPub] = await Promise.all([shim.subtle.exportKey('jwk', dhKeys.privateKey), shim.subtle.exportKey('jwk', dhKeys.publicKey)]);
r.epriv = dhPriv.d;
r.epub = dhPub.x+'.'+dhPub.y;
} catch(e) {
if(SEA.window){ throw e }
if(e == 'Error: ECDH is not a supported algorithm'){ console.log('Ignoring ECDH...') }
@ -419,7 +363,8 @@
}
}
var r = { pub: sa.pub, priv: sa.priv, epub: dh.epub, epriv: dh.epriv }
r.pub = r.pub || await g(r.priv);
r.epub = r.epub || await g(r.epriv);
if(cb){ try{ cb(r) }catch(e){console.log(e)} }
return r;
} catch(e) {

View File

@ -1,5 +1,4 @@
;(function(){
var SEA = require('./root');
var shim = require('./shim');
@ -14,86 +13,30 @@
return;
}});
//SEA.pair = async (data, proof, cb) => { try {
SEA.pair = SEA.pair || (async (cb, opt) => { try {
var ecdhSubtle = shim.ossl || shim.subtle;
var sa = {};
var dh = {};
const e = new shim.TextEncoder();
const h = async d => shim.Buffer.from(await shim.subtle.digest('SHA-256', e.encode(d))).toString('base64').replace(/[+/=]/g,c=>({'+':'-','/':'_','=':''})[c]).slice(0,43);
const g = async k => (await Promise.all([h(k+'-x'), h(k+'-y')])).join('.');
let r = {};
// Helper function to generate pub from priv
const pubFromPriv = async (priv) => {
const [x,y] = await Promise.all([
shim.subtle.digest('SHA-256', e.encode(priv+'-x')),
shim.subtle.digest('SHA-256', e.encode(priv+'-y'))
]);
return shim.Buffer.from(x).toString('base64').replace(/[+/=]/g,c=>({'+':'-','/':'_','=':''})[c]).slice(0,43) +
'.' +
shim.Buffer.from(y).toString('base64').replace(/[+/=]/g,c=>({'+':'-','/':'_','=':''})[c]).slice(0,43);
if(opt && opt.seed){
r = { priv: await h(opt.seed+'-sign'), epriv: await h(opt.seed+'-encrypt') };
}
// Helper function to generate epub from epriv
const epubFromEpriv = async (epriv) => {
const [ex,ey] = await Promise.all([
shim.subtle.digest('SHA-256', e.encode(epriv+'-x')),
shim.subtle.digest('SHA-256', e.encode(epriv+'-y'))
]);
return shim.Buffer.from(ex).toString('base64').replace(/[+/=]/g,c=>({'+':'-','/':'_','=':''})[c]).slice(0,43) +
'.' +
shim.Buffer.from(ey).toString('base64').replace(/[+/=]/g,c=>({'+':'-','/':'_','=':''})[c]).slice(0,43);
else if(opt && opt.priv){
r = { priv: opt.priv, epriv: opt.epriv || await h(opt.priv+'-encrypt') };
}
if(opt && opt.seed){ // Case 0: Generate from seed
const h = await shim.subtle.digest('SHA-256', e.encode(opt.seed+'-sign'));
sa.priv = shim.Buffer.from(h).toString('base64').replace(/[+/=]/g,c=>({'+':'-','/':'_','=':''})[c]).slice(0,43);
sa.pub = await pubFromPriv(sa.priv);
const eh = await shim.subtle.digest('SHA-256', e.encode(opt.seed+'-encrypt'));
dh.epriv = shim.Buffer.from(eh).toString('base64').replace(/[+/=]/g,c=>({'+':'-','/':'_','=':''})[c]).slice(0,43);
dh.epub = await epubFromEpriv(dh.epriv);
else if(opt && opt.epriv){
r = { epriv: opt.epriv, priv: await h(opt.epriv+'-sign') };
}
else if(opt && opt.priv){ // Case 1 & 3: Given priv
sa.priv = opt.priv;
sa.pub = await pubFromPriv(sa.priv);
if(!opt.epriv){ // Case 1: Generate epriv
// Generate a virtual seed from priv to maintain compatibility
const virtualSeed = sa.priv;
const eh = await shim.subtle.digest('SHA-256', e.encode(virtualSeed+'-encrypt'));
dh.epriv = shim.Buffer.from(eh).toString('base64').replace(/[+/=]/g,c=>({'+':'-','/':'_','=':''})[c]).slice(0,43);
} else { // Case 3: Use provided epriv
dh.epriv = opt.epriv;
}
dh.epub = await epubFromEpriv(dh.epriv);
}
else if(opt && opt.epriv){ // Case 2: Given epriv
dh.epriv = opt.epriv;
dh.epub = await epubFromEpriv(dh.epriv);
// Generate a virtual seed from epriv to maintain compatibility
const virtualSeed = dh.epriv;
const h = await shim.subtle.digest('SHA-256', e.encode(virtualSeed+'-sign'));
sa.priv = shim.Buffer.from(h).toString('base64').replace(/[+/=]/g,c=>({'+':'-','/':'_','=':''})[c]).slice(0,43);
sa.pub = await pubFromPriv(sa.priv);
}
else { // Case 4: Generate new keypair
// First: ECDSA keys for signing/verifying...
const keys = await shim.subtle.generateKey({name: 'ECDSA', namedCurve: 'P-256'}, true, [ 'sign', 'verify' ]);
const priv = await shim.subtle.exportKey('jwk', keys.privateKey);
const pub = await shim.subtle.exportKey('jwk', keys.publicKey);
sa = {
priv: priv.d,
pub: pub.x + '.' + pub.y
};
// Next: ECDH keys for encryption/decryption...
else {
const keys = await shim.subtle.generateKey({name: 'ECDSA', namedCurve: 'P-256'}, true, ['sign', 'verify']);
const [priv, pub] = await Promise.all([shim.subtle.exportKey('jwk', keys.privateKey), shim.subtle.exportKey('jwk', keys.publicKey)]);
r = { priv: priv.d, pub: pub.x+'.'+pub.y };
try {
const dhKeys = await ecdhSubtle.generateKey({name: 'ECDH', namedCurve: 'P-256'}, true, ['deriveKey']);
const dhPriv = await ecdhSubtle.exportKey('jwk', dhKeys.privateKey);
const dhPub = await ecdhSubtle.exportKey('jwk', dhKeys.publicKey);
dh = {
epriv: dhPriv.d,
epub: dhPub.x + '.' + dhPub.y
};
const dhKeys = await (shim.ossl || shim.subtle).generateKey({name: 'ECDH', namedCurve: 'P-256'}, true, ['deriveKey']);
const [dhPriv, dhPub] = await Promise.all([shim.subtle.exportKey('jwk', dhKeys.privateKey), shim.subtle.exportKey('jwk', dhKeys.publicKey)]);
r.epriv = dhPriv.d;
r.epub = dhPub.x+'.'+dhPub.y;
} catch(e) {
if(SEA.window){ throw e }
if(e == 'Error: ECDH is not a supported algorithm'){ console.log('Ignoring ECDH...') }
@ -101,7 +44,8 @@
}
}
var r = { pub: sa.pub, priv: sa.priv, epub: dh.epub, epriv: dh.epriv }
r.pub = r.pub || await g(r.priv);
r.epub = r.epub || await g(r.epriv);
if(cb){ try{ cb(r) }catch(e){console.log(e)} }
return r;
} catch(e) {
@ -113,5 +57,4 @@
}});
module.exports = SEA.pair;
}());