mirror of
https://github.com/PR0M3TH3AN/Artstr-Studio.git
synced 2026-10-27 08:40:39 +00:00
Premium step 1 — soft-gate crypto primitive
First piece of PREMIUM_DESIGNS_FEATURE.md §6. Adds the static
client-side decryption layer for premium designs: HKDF-SHA256 over
an obfuscated per-epoch pepper + a per-design public salt, then
AES-256-GCM with the event coordinate as additional-authenticated-
data so ciphertext can't be copy-pasted to a different event.
noble bundle
- Add @noble/hashes/hkdf to the bundle entry; expose as
window.ArtstrNoble.hkdf and .hmac. Bundle size 14.0 KB → 16.5 KB.
Premium IIFE (new section in index.html)
- _softGatePepperParts — per-epoch lookup of 4x8-byte fragments
("palette seed I..IV"). For epoch 2026-05. Sub-strings don't
look like a "premium key"; reconstruction concats at use time.
Comment explicitly calls this obfuscation, not security, per
PREMIUM_DESIGNS_FEATURE.md §2 / §6.3.
- SUPPORTED_EPOCHS / CURRENT_EPOCH — adding a future epoch is
one entry in the parts table.
- pepperBytesForEpoch(epoch) — reconstructs the 32-byte pepper.
- deriveKey({ epoch, creatorPubkey, premiumAddress, schemaVersion,
publicDesignSalt, puzzleNonce }) -> 32 bytes via HKDF-SHA256
with the pepper as IKM, salt = publicDesignSalt, info =
"artstr-softgate-v1|<epoch>|<creator>|<addr>|v<schema>" (and an
optional "|p<nonce>" for the §6.7 CPU-puzzle hook).
- encodeAad(creatorPubkey, dTag) -> UTF-8 of
"30078:<creator>:<dTag>" so AES-GCM authenticates the
coordinate.
- encryptPayload(payloadObj, coord, { epoch? }) — random
32-byte salt + 12-byte IV; returns the spec §5.2 envelope
(base64 fields, softgate metadata, etc.).
- decryptPayload(envelope, coord) — reverses the above.
- Self-test runs on every load: round-trip a known payload AND
verify AAD/creator/schema mismatches all reject the decrypt
(event-coordinate binding). Single console.warn on failure.
Tested via CDP — all green:
- Round-trip with random keypair: ok
- AAD mismatch (different dTag) -> AES-GCM rejects: ok
- Creator pubkey mismatch -> KDF info changes -> rejects: ok
- Schema version mismatch -> KDF info changes -> rejects: ok
- KDF deterministic with identical inputs: ok
- Output length = 32 bytes (AES-256): ok
- Pepper reconstruction = 32 bytes: ok
- Envelope size for tiny payload = 577 bytes; ~63 KB headroom
under typical relay limits, plenty for an embedded preview
JPEG in step 2.
- Regression: NWC crypto self-test still passes; existing editor
still loads and renders layers.
Code only; nothing in the publish/feed flow uses this yet. Next
step (PREMIUM_DESIGNS_FEATURE.md §19 item 2) is the watermarked
preview pipeline.
Co-Authored-By: Claude Opus 4.7 <[email protected]>
This commit is contained in:
1 parent
7da0c9d97c
commit
a8c855fc5c
2 files changed
+175
-1
No files matched your search
+174
@@ -4595,6 +4595,180 @@
|
||||
// ---- end NWC crypto -----------------------------------------------------
|
||||
|
||||
|
||||
// ---- Premium soft-gate crypto (PREMIUM_DESIGNS_FEATURE.md §6) -----------
|
||||
// Static client-side decryption gate for premium designs. The AES key is
|
||||
// derived from a per-design public salt + a client-side "pepper" + a
|
||||
// discriminator string. The pepper is obfuscated (split into byte
|
||||
// fragments held in unrelated-looking places); reconstructing it from a
|
||||
// minified bundle is annoying-but-doable, which is honest about what this
|
||||
// gives us: protection against drive-by scraping, not strong DRM. The
|
||||
// spec calls this a "soft gate."
|
||||
//
|
||||
// Epoch rotation: every premium design records the epoch it was
|
||||
// published under. When an epoch's pepper gets reverse-engineered we
|
||||
// can ship a new epoch and rotate forward; old designs stay readable
|
||||
// by anyone who knows the old derivation but new designs are protected
|
||||
// by the new one. Adding a new epoch is "add one entry to
|
||||
// `_softGatePepperParts`."
|
||||
const Premium = (() => {
|
||||
// 4-part pepper per epoch. Stored as four Uint8Arrays in this lookup
|
||||
// table, indexed by epoch. Reconstruction concatenates them — the
|
||||
// pieces don't look like anything individually. Each 8 bytes was
|
||||
// generated from crypto.getRandomValues at spec-adoption time; comment
|
||||
// calls them "palette seeds" to avoid an obvious "PREMIUM_KEY" string
|
||||
// in the source. (Determined readers will still find this; we accept
|
||||
// that — see PREMIUM_DESIGNS_FEATURE.md §2.)
|
||||
const _softGatePepperParts = {
|
||||
'2026-05': [
|
||||
new Uint8Array([0x8c, 0x2b, 0xd1, 0x47, 0x9e, 0x60, 0x35, 0xaa]), // palette seed I
|
||||
new Uint8Array([0x14, 0xf3, 0x59, 0xb2, 0x7d, 0xc8, 0x06, 0xef]), // palette seed II
|
||||
new Uint8Array([0xa5, 0x71, 0x4e, 0x2c, 0x9b, 0x88, 0x33, 0xd0]), // palette seed III
|
||||
new Uint8Array([0x62, 0x09, 0xfd, 0x18, 0x4a, 0xe7, 0xc4, 0x95]), // palette seed IV
|
||||
],
|
||||
};
|
||||
const SUPPORTED_EPOCHS = Object.freeze(Object.keys(_softGatePepperParts));
|
||||
const CURRENT_EPOCH = '2026-05';
|
||||
const PREMIUM_KDF_INFO = 'artstr-softgate-v1';
|
||||
|
||||
function pepperBytesForEpoch(epoch) {
|
||||
const parts = _softGatePepperParts[epoch];
|
||||
if (!parts) throw new Error(`Unsupported soft-gate epoch: ${epoch}`);
|
||||
const total = parts.reduce((n, p) => n + p.length, 0);
|
||||
const out = new Uint8Array(total);
|
||||
let off = 0;
|
||||
for (const p of parts) { out.set(p, off); off += p.length; }
|
||||
return out;
|
||||
}
|
||||
|
||||
// HKDF-SHA256 → 32-byte AES key. Inputs:
|
||||
// epoch — string ("2026-05") from the envelope
|
||||
// creatorPubkey — 64-hex
|
||||
// premiumAddress — "30078:<creatorHex>:<dTag>"
|
||||
// schemaVersion — number, e.g. 5
|
||||
// publicDesignSalt — Uint8Array (from envelope)
|
||||
// puzzleNonce — optional UTF-8 string mixed into info
|
||||
function deriveKey({ epoch, creatorPubkey, premiumAddress, schemaVersion, publicDesignSalt, puzzleNonce }) {
|
||||
if (!_softGatePepperParts[epoch]) throw new Error(`Unsupported soft-gate epoch: ${epoch}`);
|
||||
const enc = new TextEncoder();
|
||||
const infoStr = PREMIUM_KDF_INFO + '|' + epoch + '|' + creatorPubkey + '|' + premiumAddress + '|v' + schemaVersion
|
||||
+ (puzzleNonce ? '|p' + puzzleNonce : '');
|
||||
return window.ArtstrNoble.hkdf(
|
||||
window.ArtstrNoble.sha256,
|
||||
pepperBytesForEpoch(epoch), // IKM
|
||||
publicDesignSalt, // salt
|
||||
enc.encode(infoStr), // info
|
||||
32, // length
|
||||
);
|
||||
}
|
||||
|
||||
// AAD binds ciphertext to the event coordinate so a copy-paste to a
|
||||
// different event address fails authentication.
|
||||
function encodeAad(creatorPubkey, dTag) {
|
||||
return new TextEncoder().encode(`30078:${creatorPubkey}:${dTag}`);
|
||||
}
|
||||
|
||||
const _bytesToB64 = (b) => { let s = ''; for (let i = 0; i < b.length; i++) s += String.fromCharCode(b[i]); return btoa(s); };
|
||||
const _b64ToBytes = (b64) => Uint8Array.from(atob(b64), (c) => c.charCodeAt(0));
|
||||
|
||||
// Encrypt a Nostr design payload object → envelope (per spec §5.2).
|
||||
// `coord` is { creatorPubkey, dTag, schemaVersion }. Generates a random
|
||||
// 32-byte design salt + 12-byte IV. The returned envelope has the same
|
||||
// shape the consumer expects, base64'd.
|
||||
async function encryptPayload(payloadObj, coord, opts = {}) {
|
||||
const epoch = opts.epoch || CURRENT_EPOCH;
|
||||
const publicDesignSalt = crypto.getRandomValues(new Uint8Array(32));
|
||||
const iv = crypto.getRandomValues(new Uint8Array(12));
|
||||
const premiumAddress = `30078:${coord.creatorPubkey}:${coord.dTag}`;
|
||||
const keyBytes = deriveKey({
|
||||
epoch,
|
||||
creatorPubkey: coord.creatorPubkey,
|
||||
premiumAddress,
|
||||
schemaVersion: coord.schemaVersion,
|
||||
publicDesignSalt,
|
||||
});
|
||||
const key = await crypto.subtle.importKey('raw', keyBytes, { name: 'AES-GCM' }, false, ['encrypt']);
|
||||
const aad = encodeAad(coord.creatorPubkey, coord.dTag);
|
||||
const plaintext = new TextEncoder().encode(JSON.stringify(payloadObj));
|
||||
const ct = new Uint8Array(await crypto.subtle.encrypt(
|
||||
{ name: 'AES-GCM', iv, additionalData: aad }, key, plaintext
|
||||
));
|
||||
return {
|
||||
v: 1,
|
||||
enc: { alg: 'aes-256-gcm', kdf: PREMIUM_KDF_INFO, compression: 'none' },
|
||||
aad: `30078:${coord.creatorPubkey}:${coord.dTag}`,
|
||||
salt: _bytesToB64(publicDesignSalt),
|
||||
iv: _bytesToB64(iv),
|
||||
ciphertext: _bytesToB64(ct),
|
||||
softgate: {
|
||||
version: 1, epoch,
|
||||
publicDesignSalt: _bytesToB64(publicDesignSalt),
|
||||
purchaseScope: 'address',
|
||||
puzzle: { enabled: false, difficultyBits: 0 },
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
// Decrypt an envelope back into the original payload object. Pulls
|
||||
// epoch + salt out of the envelope; rebuilds the AAD from `coord`.
|
||||
async function decryptPayload(envelope, coord) {
|
||||
if (!envelope || envelope.enc?.alg !== 'aes-256-gcm') throw new Error('Unsupported envelope');
|
||||
const epoch = envelope.softgate?.epoch || CURRENT_EPOCH;
|
||||
const publicDesignSalt = _b64ToBytes(envelope.softgate?.publicDesignSalt || envelope.salt);
|
||||
const iv = _b64ToBytes(envelope.iv);
|
||||
const ct = _b64ToBytes(envelope.ciphertext);
|
||||
const premiumAddress = `30078:${coord.creatorPubkey}:${coord.dTag}`;
|
||||
const keyBytes = deriveKey({
|
||||
epoch,
|
||||
creatorPubkey: coord.creatorPubkey,
|
||||
premiumAddress,
|
||||
schemaVersion: coord.schemaVersion,
|
||||
publicDesignSalt,
|
||||
});
|
||||
const key = await crypto.subtle.importKey('raw', keyBytes, { name: 'AES-GCM' }, false, ['decrypt']);
|
||||
const aad = encodeAad(coord.creatorPubkey, coord.dTag);
|
||||
const pt = new Uint8Array(await crypto.subtle.decrypt(
|
||||
{ name: 'AES-GCM', iv, additionalData: aad }, key, ct
|
||||
));
|
||||
return JSON.parse(new TextDecoder().decode(pt));
|
||||
}
|
||||
|
||||
return {
|
||||
SUPPORTED_EPOCHS, CURRENT_EPOCH, PREMIUM_KDF_INFO,
|
||||
pepperBytesForEpoch, deriveKey, encodeAad,
|
||||
encryptPayload, decryptPayload,
|
||||
};
|
||||
})();
|
||||
|
||||
// Phase-1 self-test for the soft-gate primitive. Round-trips a known
|
||||
// payload + verifies that mismatched AAD (event coordinate copy-paste)
|
||||
// fails the decrypt as the spec requires.
|
||||
(async () => {
|
||||
try {
|
||||
if (!window.ArtstrNoble?.hkdf) throw new Error('HKDF missing from noble bundle');
|
||||
const coord = {
|
||||
creatorPubkey: 'a'.repeat(64),
|
||||
dTag: 'premium:test:soft-gate-roundtrip',
|
||||
schemaVersion: 5,
|
||||
};
|
||||
const payload = { version: 5, hello: 'world', layers: [{ id: 'l1', type: 'color' }] };
|
||||
const env = await Premium.encryptPayload(payload, coord);
|
||||
if (env.enc.alg !== 'aes-256-gcm') throw new Error('envelope alg wrong');
|
||||
if (!env.softgate?.epoch) throw new Error('envelope missing epoch');
|
||||
const round = await Premium.decryptPayload(env, coord);
|
||||
if (JSON.stringify(round) !== JSON.stringify(payload)) throw new Error('round-trip mismatch');
|
||||
// AAD mismatch must fail (different dTag → different AAD → AES-GCM rejects).
|
||||
let aadFailed = false;
|
||||
try {
|
||||
await Premium.decryptPayload(env, { ...coord, dTag: 'attacker:rebound' });
|
||||
} catch { aadFailed = true; }
|
||||
if (!aadFailed) throw new Error('AAD mismatch did NOT fail decrypt — coordinate binding broken');
|
||||
} catch (err) {
|
||||
console.warn('[Artstr] Premium soft-gate self-test failed — premium publish/unlock will not work:', err);
|
||||
}
|
||||
})();
|
||||
// ---- end Premium soft-gate crypto ---------------------------------------
|
||||
|
||||
|
||||
// ---- NWC client (Phase 1) ----------------------------------------------
|
||||
// RPC-style client for a single NIP-47 wallet connection. One WebSocket,
|
||||
// one persistent subscription for kind-23195 responses + kind-13194
|
||||
|
||||
Vendored
+1
-1
@@ -1,4 +1,4 @@
|
||||
(()=>{var ae=Object.defineProperty;var ue=(t,e,n)=>e in t?ae(t,e,{enumerable:!0,configurable:!0,writable:!0,value:n}):t[e]=n;var l=(t,e,n)=>ue(t,typeof e!="symbol"?e+"":e,n);var Ht=Object.freeze({p:0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2fn,n:0xfffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141n,h:1n,a:0n,b:7n,Gx:0x79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798n,Gy:0x483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8n}),{p:v,n:Z,Gx:he,Gy:de,b:St}=Ht,w=32,K=64,P={publicKey:w+1,publicKeyUncompressed:K+1,signature:K,seed:w+w/2},b=(t="",e=Error)=>{let n=new e(t),{captureStackTrace:s}=Error;throw typeof s=="function"&&s(n,b),n},le=t=>t instanceof Uint8Array||ArrayBuffer.isView(t)&&t.constructor.name==="Uint8Array"&&t.BYTES_PER_ELEMENT===1,E=(t,e,n="")=>{let s=le(t),r=t?.length,o=e!==void 0;if(!s||o&&r!==e){let c=n&&`"${n}" `,f=o?` of length ${e}`:"",a=s?`length=${r}`:`type=${typeof t}`,h=c+"expected Uint8Array"+f+", got "+a;return s?b(h,RangeError):b(h,TypeError)}return t},j=t=>new Uint8Array(t),Bt=(t,e)=>t.toString(16).padStart(e,"0"),Lt=t=>{let e="";for(let n of E(t))e+=Bt(n,2);return e},_={_0:48,_9:57,A:65,F:70,a:97,f:102},bt=t=>t>=_._0&&t<=_._9?t-_._0:t>=_.A&&t<=_.F?t-(_.A-10):t>=_.a&&t<=_.f?t-(_.a-10):void 0,Ut=t=>{let e="hex invalid";if(typeof t!="string")return b(e);let n=t.length,s=n/2;if(n%2)return b(e);let r=j(s);for(let o=0,c=0;o<s;o++,c+=2){let f=bt(t.charCodeAt(c)),a=bt(t.charCodeAt(c+1));if(f===void 0||a===void 0)return b(e);r[o]=f*16+a}return r},yt=()=>globalThis?.crypto?.subtle??b("crypto.subtle must be defined, consider polyfill"),R=(...t)=>{let e=0;for(let r of t)e+=E(r).length;let n=j(e),s=0;for(let r of t)n.set(r,s),s+=r.length;return n},at=(t=w)=>(globalThis?.crypto).getRandomValues(j(t)),ot=BigInt,V=(t,e,n,s="bad number: out of range")=>typeof t!="bigint"?b(s,TypeError):e<=t&&t<n?t:b(s,RangeError),i=(t,e=v)=>{let n=t%e;return n>=0n?n:e+n},z=t=>i(t,Z),xe=(t,e)=>{(t===0n||e<=0n)&&b("no inverse n="+t+" mod="+e);let n=i(t,e),s=e,r=0n,o=1n,c=1n,f=0n;for(;n!==0n;){let a=s/n,h=s%n,d=r-c*a,u=o-f*a;s=n,n=h,r=c,o=f,c=d,f=u}return s===1n?i(r,e):b("no inverse")},_t=t=>{let e=J[t];return typeof e!="function"&&b("hashes."+t+" not set"),e},pt=(t,e,n)=>E(_t(t)(e,n),w,"digest"),gt=(t,e,n)=>Promise.resolve(_t(t)(e,n)).then(s=>E(s,w,"digest"));var rt=t=>t instanceof L?t:b("Point expected"),Tt=t=>i(i(t*t)*t+St),mt=t=>V(t,0n,v),M=t=>V(t,1n,v),be=t=>V(t,1n,Z),W=t=>!(t&1n),It=t=>Uint8Array.of(t),ye=t=>It(W(t)?2:3),vt=t=>{let e=Tt(M(t)),n=1n;for(let s=e,r=(v+1n)/4n;r>0n;r>>=1n)r&1n&&(n=n*s%v),s=s*s%v;return i(n*n)!==e&&b("sqrt invalid"),W(n)?n:i(-n)};var B=class B{constructor(e,n,s){l(this,"X");l(this,"Y");l(this,"Z");this.X=mt(e),this.Y=M(n),this.Z=mt(s),Object.freeze(this)}static CURVE(){return Ht}static fromAffine(e){let{x:n,y:s}=e;return n===0n&&s===0n?F:new B(n,s,1n)}static fromBytes(e){E(e);let{publicKey:n,publicKeyUncompressed:s}=P,r,o=e.length,c=e[0],f=e.subarray(1),a=Y(f,0,w);if(o===n&&(c===2||c===3)){let h=vt(a);c===3&&(h=i(-h)),r=new B(a,h,1n)}return o===s&&c===4&&(r=new B(a,Y(f,w,K),1n)),r?r.assertValidity():b("bad point: not on curve")}static fromHex(e){return B.fromBytes(Ut(e))}get x(){return this.toAffine().x}get y(){return this.toAffine().y}equals(e){let{X:n,Y:s,Z:r}=this,{X:o,Y:c,Z:f}=rt(e),a=i(n*f),h=i(o*r),d=i(s*f),u=i(c*r);return a===h&&d===u}is0(){return this.equals(F)}negate(){return new B(this.X,i(-this.Y),this.Z)}double(){return this.add(this)}add(e){let{X:n,Y:s,Z:r}=this,{X:o,Y:c,Z:f}=rt(e),a=0n,h=St,d=0n,u=0n,x=0n,y=i(h*3n),p=i(n*o),g=i(s*c),A=i(r*f),O=i(n+s),m=i(o+c);O=i(O*m),m=i(p+g),O=i(O-m),m=i(n+r);let S=i(o+f);return m=i(m*S),S=i(p+A),m=i(m-S),S=i(s+r),d=i(c+f),S=i(S*d),d=i(g+A),S=i(S-d),x=i(a*m),d=i(y*A),x=i(d+x),d=i(g-x),x=i(g+x),u=i(d*x),g=i(p+p),g=i(g+p),A=i(a*A),m=i(y*m),g=i(g+A),A=i(p-A),A=i(a*A),m=i(m+A),p=i(g*m),u=i(u+p),p=i(S*m),d=i(O*d),d=i(d-p),p=i(O*g),x=i(S*x),x=i(x+p),new B(d,u,x)}subtract(e){return this.add(rt(e).negate())}multiply(e,n=!0){if(!n&&e===0n)return F;if(be(e),e===1n)return this;if(this.equals(C))return _e(e).p;let s=F,r=C;for(let o=this;e>0n;o=o.double(),e>>=1n)e&1n?s=s.add(o):n&&(r=r.add(o));return s}multiplyUnsafe(e){return this.multiply(e,!1)}toAffine(){let{X:e,Y:n,Z:s}=this;if(this.equals(F))return{x:0n,y:0n};if(s===1n)return{x:e,y:n};let r=xe(s,v);return i(s*r)!==1n&&b("inverse invalid"),{x:i(e*r),y:i(n*r)}}assertValidity(){let{x:e,y:n}=this.toAffine();return M(e),M(n),i(n*n)===Tt(e)?this:b("bad point: not on curve")}toBytes(e=!0){let{x:n,y:s}=this.assertValidity().toAffine(),r=U(n);return e?R(ye(s),r):R(It(4),r,U(s))}toHex(e){return Lt(this.toBytes(e))}};l(B,"BASE"),l(B,"ZERO");var L=B,C=new L(he,de,1n),F=new L(0n,1n,0n);L.BASE=C;L.ZERO=F;var pe=(t,e,n)=>C.multiply(e,!1).add(t.multiply(n,!1)).assertValidity(),G=t=>ot("0x"+(Lt(t)||"0")),Y=(t,e,n)=>G(t.subarray(e,n)),ge=2n**256n,U=t=>Ut(Bt(V(t,0n,ge),K)),q=t=>{let e=G(E(t,w,"secret key"));return V(e,1n,Z,"invalid secret key: outsidLine truncated
|
||||
(()=>{var de=Object.defineProperty;var le=(t,e,n)=>e in t?de(t,e,{enumerable:!0,configurable:!0,writable:!0,value:n}):t[e]=n;var l=(t,e,n)=>le(t,typeof e!="symbol"?e+"":e,n);var Lt=Object.freeze({p:0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2fn,n:0xfffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141n,h:1n,a:0n,b:7n,Gx:0x79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798n,Gy:0x483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8n}),{p:v,n:P,Gx:xe,Gy:be,b:Ut}=Lt,w=32,K=64,z={publicKey:w+1,publicKeyUncompressed:K+1,signature:K,seed:w+w/2},b=(t="",e=Error)=>{let n=new e(t),{captureStackTrace:s}=Error;throw typeof s=="function"&&s(n,b),n},ye=t=>t instanceof Uint8Array||ArrayBuffer.isView(t)&&t.constructor.name==="Uint8Array"&&t.BYTES_PER_ELEMENT===1,E=(t,e,n="")=>{let s=ye(t),r=t?.length,o=e!==void 0;if(!s||o&&r!==e){let c=n&&`"${n}" `,i=o?` of length ${e}`:"",a=s?`length=${r}`:`type=${typeof t}`,h=c+"expected Uint8Array"+i+", got "+a;return s?b(h,RangeError):b(h,TypeError)}return t},j=t=>new Uint8Array(t),_t=(t,e)=>t.toString(16).padStart(e,"0"),Tt=t=>{let e="";for(let n of E(t))e+=_t(n,2);return e},_={_0:48,_9:57,A:65,F:70,a:97,f:102},gt=t=>t>=_._0&&t<=_._9?t-_._0:t>=_.A&&t<=_.F?t-(_.A-10):t>=_.a&&t<=_.f?t-(_.a-10):void 0,It=t=>{let e="hex invalid";if(typeof t!="string")return b(e);let n=t.length,s=n/2;if(n%2)return b(e);let r=j(s);for(let o=0,c=0;o<s;o++,c+=2){let i=gt(t.charCodeAt(c)),a=gt(t.charCodeAt(c+1));if(i===void 0||a===void 0)return b(e);r[o]=i*16+a}return r},mt=()=>globalThis?.crypto?.subtle??b("crypto.subtle must be defined, consider polyfill"),N=(...t)=>{let e=0;for(let r of t)e+=E(r).length;let n=j(e),s=0;for(let r of t)n.set(r,s),s+=r.length;return n},dt=(t=w)=>(globalThis?.crypto).getRandomValues(j(t)),ft=BigInt,D=(t,e,n,s="bad number: out of range")=>typeof t!="bigint"?b(s,TypeError):e<=t&&t<n?t:b(s,RangeError),f=(t,e=v)=>{let n=t%e;return n>=0n?n:e+n},J=t=>f(t,P),pe=(t,e)=>{(t===0n||e<=0n)&&b("no inverse n="+t+" mod="+e);let n=f(t,e),s=e,r=0n,o=1n,c=1n,i=0n;for(;n!==0n;){let a=s/n,h=s%n,d=r-c*a,u=o-i*a;s=n,n=h,r=c,o=i,c=d,i=u}return s===1n?f(r,e):b("no inverse")},kt=t=>{let e=et[t];return typeof e!="function"&&b("hashes."+t+" not set"),e},wt=(t,e,n)=>E(kt(t)(e,n),w,"digest"),At=(t,e,n)=>Promise.resolve(kt(t)(e,n)).then(s=>E(s,w,"digest"));var it=t=>t instanceof L?t:b("Point expected"),Ct=t=>f(f(t*t)*t+Ut),Et=t=>D(t,0n,v),$=t=>D(t,1n,v),ge=t=>D(t,1n,P),Q=t=>!(t&1n),vt=t=>Uint8Array.of(t),me=t=>vt(Q(t)?2:3),Ft=t=>{let e=Ct($(t)),n=1n;for(let s=e,r=(v+1n)/4n;r>0n;r>>=1n)r&1n&&(n=n*s%v),s=s*s%v;return f(n*n)!==e&&b("sqrt invalid"),Q(n)?n:f(-n)};var B=class B{constructor(e,n,s){l(this,"X");l(this,"Y");l(this,"Z");this.X=Et(e),this.Y=$(n),this.Z=Et(s),Object.freeze(this)}static CURVE(){return Lt}static fromAffine(e){let{x:n,y:s}=e;return n===0n&&s===0n?G:new B(n,s,1n)}static fromBytes(e){E(e);let{publicKey:n,publicKeyUncompressed:s}=z,r,o=e.length,c=e[0],i=e.subarray(1),a=W(i,0,w);if(o===n&&(c===2||c===3)){let h=Ft(a);c===3&&(h=f(-h)),r=new B(a,h,1n)}return o===s&&c===4&&(r=new B(a,W(i,w,K),1n)),r?r.assertValidity():b("bad point: not on curve")}static fromHex(e){return B.fromBytes(It(e))}get x(){return this.toAffine().x}get y(){return this.toAffine().y}equals(e){let{X:n,Y:s,Z:r}=this,{X:o,Y:c,Z:i}=it(e),a=f(n*i),h=f(o*r),d=f(s*i),u=f(c*r);return a===h&&d===u}is0(){return this.equals(G)}negate(){return new B(this.X,f(-this.Y),this.Z)}double(){return this.add(this)}add(e){let{X:n,Y:s,Z:r}=this,{X:o,Y:c,Z:i}=it(e),a=0n,h=Ut,d=0n,u=0n,x=0n,y=f(h*3n),p=f(n*o),g=f(s*c),A=f(r*i),R=f(n+s),m=f(o+c);R=f(R*m),m=f(p+g),R=f(R-m),m=f(n+r);let S=f(o+i);return m=f(m*S),S=f(p+A),m=f(m-S),S=f(s+r),d=f(c+i),S=f(S*d),d=f(g+A),S=f(S-d),x=f(a*m),d=f(y*A),x=f(d+x),d=f(g-x),x=f(g+x),u=f(d*x),g=f(p+p),g=f(g+p),A=f(a*A),m=f(y*m),g=f(g+A),A=f(p-A),A=f(a*A),m=f(m+A),p=f(g*m),u=f(u+p),p=f(S*m),d=f(R*d),d=f(d-p),p=f(R*g),x=f(S*x),x=f(x+p),new B(d,u,x)}subtract(e){return this.add(it(e).negate())}multiply(e,n=!0){if(!n&&e===0n)return G;if(ge(e),e===1n)return this;if(this.equals(F))return ke(e).p;let s=G,r=F;for(let o=this;e>0n;o=o.double(),e>>=1n)e&1n?s=s.add(o):n&&(r=r.add(o));return s}multiplyUnsafe(e){return this.multiply(e,!1)}toAffine(){let{X:e,Y:n,Z:s}=this;if(this.equals(G))return{x:0n,y:0n};if(s===1n)return{x:e,y:n};let r=pe(s,v);return f(s*r)!==1n&&b("inverse invalid"),{x:f(e*r),y:f(n*r)}}assertValidity(){let{x:e,y:n}=this.toAffine();return $(e),$(n),f(n*n)===Ct(e)?this:b("bad point: not on curve")}toBytes(e=!0){let{x:n,y:s}=this.assertValidity().toAffine(),r=U(n);return e?N(me(s),r):N(vt(4),r,U(s))}toHex(e){return Tt(this.toBytes(e))}};l(B,"BASE"),l(B,"ZERO");var L=B,F=new L(xe,be,1n),G=new L(0n,1n,0n);L.BASE=F;L.ZERO=G;var we=(t,e,n)=>F.multiply(e,!1).add(t.multiply(n,!1)).assertValidity(),O=t=>ft("0x"+(Tt(t)||"0")),W=(t,e,n)=>O(t.subarray(e,n)),Ae=2n**256n,U=t=>It(_t(D(t,0n,Ae),K)),tt=t=>{let e=O(E(t,w,"secret key"));return D(e,1n,P,"invalid secret key: outsLine truncated
|
||||
/*! Bundled license information:
|
||||
|
||||
@noble/secp256k1/index.js:
|
||||
|
||||
Reference in new issue
Block a user