Skip to content
KitploitKITPLOIT
도구블로그
제출
도구블로그
제출

해킹, 침투 테스트 및 사이버 보안 도구를 당신의 보안 무기고에!

Kitploit은 해킹, 사이버 보안 및 침투 테스트 도구 디렉토리입니다. 최신 프로젝트 업데이트를 발견하여 취약점을 찾고, 시스템을 분석하고, 테스트를 자동화하고, 보안을 강화하세요.

··피드·문의·개인정보·© 2026 Kitploit

도구 디렉토리

카테고리

모든 카테고리 보기
Loading categories
noble-curves — 감사된 & 최소한의 타원 곡선 암호화 JS 구현. | Kitploit
도구/GitHubGitHub/paulmillr/noble-curves
Encryption/Decryption ToolsHash AnalysisCryptographyUtilities & FrameworksLearning & Education
GitHubpaulmillr/noble-curves

noble-curves

감사된 & 최소한의 타원 곡선 암호화 JS 구현.

저장소 보기
958101157일 전Kitploit 검토 완료

인기

모두 보기 →

커뮤니티에서 가장 많이 사용되는 도구를 찾아보세요.

모든 도구 탐색

도구 컬렉션을 둘러보세요

모든 도구 보기 →
공유
웹사이트

noble-curves

감사된 & 최소한의 타원 곡선 암호 구현 JS.

  • 🔒 독립적인 보안 회사에 의해 감사됨
  • 🪶 최소한: 15KB (gzip 압축) secp256k1, 사용되지 않는 코드는 빌드에서 제외됨
  • 🏎 빠름: JS 엔진의 특성을 고려하여 수작업으로 최적화됨
  • 🔍 신뢰할 수 있음: 교차 라이브러리 / wycheproof 테스트로 정확성 보장
  • ➰ Weierstrass, Edwards 곡선; ECDSA, EdDSA, Schnorr, BLS 서명
  • ✍️ ECDH, hash-to-curve, OPRF, FROST, Poseidon 해시, FFT
  • 🔖 ed25519, ed448에서 부인 방지 (SUF-CMA, SBS) & 합의 친화성 (ZIP215)
  • 🥈 네이티브 WebCrypto 위에 동일한 API를 가진 래퍼

곡선에는 5kb 자매 프로젝트가 있습니다 secp256k1 & ed25519. 이들은 공격 표면이 더 작지만 기능이 적습니다.

이 라이브러리는 noble 암호학에 속합니다

noble 암호학 — 높은 보안성, 쉽게 감사할 수 있는 포함된 암호 라이브러리 및 도구 세트.

  • 의존성 없음 또는 최소
  • 매우 읽기 쉬운 TypeScript / JS 코드
  • PGP 서명된 릴리스 및 투명한 NPM 빌드
  • 모든 라이브러리: ciphers, curves, hashes, post-quantum, 5kb secp256k1 / ed25519
  • WASM 버전: awasm-noble
  • 홈페이지를 확인하세요 읽기 자료, 문서, noble로 만든 앱을 위해

사용법

npm install @noble/curves

deno add jsr:@noble/curves

우리는 모든 주요 플랫폼과 런타임을 지원합니다. React Native의 경우 getRandomValues용 폴리필이 필요할 수 있습니다. 독립 실행형 파일 noble-curves.js도 사용할 수 있습니다.```js // import * from '@noble/curves'; // Error: use sub-imports, to ensure small app size import { secp256k1 } from '@noble/curves/secp256k1.js'; const { secretKey, publicKey } = secp256k1.keygen(); const msg = new TextEncoder().encode('hello noble'); const sig = secp256k1.sign(msg, secretKey); const isValid = secp256k1.verify(sig, msg, publicKey);

root@kitploit:~
- [ECDSA, EdDSA, Schnorr 서명](#ecdsa-eddsa-schnorr-signatures)
- [ECDH: Diffie-Hellman 공유 비밀](#ecdh-diffie-hellman-shared-secrets)
- [webcrypto: 친화적 래퍼](#webcrypto-friendly-wrapper)
- [BLS 서명, bls12-381, bn254 aka alt\_bn128](#bls-signatures-bls12-381-bn254-aka-alt_bn128)
- [hash-to-curve: 곡선 점으로 해싱](#hash-to-curve-hashing-to-curve-points)
- [OPRFs](#oprfs) | [FROST 임계 서명](#frost-threshold-signatures)
- [poseidon: Poseidon 해시](#poseidon-poseidon-hash) | [fft: 고속 푸리에 변환](#fft-fast-fourier-transform) | [utils](#utils-byte-shuffling-conversion)
- 내부: [점 수학](#elliptic-curve-point-math) | [모듈러](#modular-modular-arithmetics--finite-fields) | [사용자 정의 곡선](#weierstrass-custom-weierstrass-curve--ecdsa)
- [사양](#specs)
- [보안](#security) | [속도](#speed) | [업그레이드](#upgrading) | [기여 및 테스트](#contributing--testing) | [라이선스](#license)

### ECDSA, EdDSA, Schnorr 서명

#### secp256k1, p256, p384, p521, ed25519, ed448, brainpool```js
import { secp256k1, schnorr } from '@noble/curves/secp256k1.js';
import { p256, p384, p521 } from '@noble/curves/nist.js';
import { ed25519 } from '@noble/curves/ed25519.js';
import { ed448 } from '@noble/curves/ed448.js';
import { brainpoolP256r1, brainpoolP384r1, brainpoolP512r1 } from '@noble/curves/misc.js';
for (const curve of [
  secp256k1, schnorr,
  p256, p384, p521,
  ed25519, ed448,
  brainpoolP256r1, brainpoolP384r1, brainpoolP512r1
]) {
  const { secretKey, publicKey } = curve.keygen();
  const msg = new TextEncoder().encode('hello noble');
  const sig = curve.sign(msg, secretKey);
  const isValid = curve.verify(sig, msg, publicKey);
  console.log(curve, secretKey, publicKey, sig, isValid);
}

// Specific private key
import { hexToBytes } from '@noble/curves/utils.js';
const secret2 = hexToBytes('46c930bc7bb4db7f55da20798697421b98c4175a52c630294d75a84b9c126236');
const pub2 = secp256k1.getPublicKey(secret2);

Messages는 항상 먼저 해시됩니다: prehashed signing을 참조하세요. ECDSA는 결정적 k를 사용하고, EdDSA는 RFC 8032를 따르며, Schnorr(secp256k1 전용)는 BIP 340을 따릅니다: Specs를 참조하세요.

MuSig2 서명 방식과 secp256k1용 BIP324 ElligatorSwift 매핑은 별도 패키지에서 사용할 수 있습니다.

ristretto255, decaf448```ts

import { ristretto255, ristretto255_hasher, ristretto255_oprf } from '@noble/curves/ed25519.js'; import { decaf448, decaf448_hasher, decaf448_oprf } from '@noble/curves/ed448.js';

console.log(ristretto255.Point, decaf448.Point);

root@kitploit:~
[RFC 9496](https://www.rfc-editor.org/rfc/rfc9496)에서 ristretto255 및 decaf448에 대한 더 많은 정보를 확인하세요.
[Point](#elliptic-curve-point-math), [hasher](#hash-to-curve-hashing-to-curve-points) 및 [oprf](#oprfs)에 대한 별도 문서를 확인하세요.

#### 사전 해시 서명```js
import { secp256k1 } from '@noble/curves/secp256k1.js';
import { keccak_256 } from '@noble/hashes/sha3.js';
const { secretKey } = secp256k1.keygen();
const msg = new TextEncoder().encode('hello noble');
// prehash: true (default) - hash using secp256k1.hash (sha256)
const sig = secp256k1.sign(msg, secretKey);
// prehash: false - hash using custom hash
const sigKeccak = secp256k1.sign(keccak_256(msg), secretKey, { prehash: false });

기본적으로(prehash: true), sign()과 verify()는 먼저 메시지에 곡선의 내장 해시를 적용합니다: secp256k1에는 sha256, p521에는 sha512. prehash: false를 사용하면 사용자 정의 해시를 사용할 수 있습니다 (예: secp256k1 + keccak_256). noble-curves v1에서는 prehash: false가 기본값이었습니다.

서명에서 공개 키 복구하기```js

import { secp256k1 } from '@noble/curves/secp256k1.js'; const { secretKey, publicKey } = secp256k1.keygen(); const msg = new TextEncoder().encode('hello noble'); const sigRec = secp256k1.sign(msg, secretKey, { format: 'recovered' }); const publicKey_ = secp256k1.recoverPublicKey(sigRec, msg); // == publicKey

// recovered sig is compact sig with an extra byte const sigNoRec = secp256k1.sign(msg, secretKey, { format: 'compact' }); // sigNoRec == sigRec.slice(1)

// Signature instance const sigInstance = secp256k1.Signature.fromBytes(sigRec, 'recovered');

root@kitploit:~
Public key recovery는 ECDSA에서만 지원됩니다. 이는 단순한 수학 연산입니다:
서명이 실제로 수행되었다는 보장은 없습니다. 위조된 (r, s, h)는
임의의 공개 키로 복구되지만, 이 특정 위조된 h로 이어질 m을 찾는 것은 실행 가능하지 않습니다.

#### 노이즈를 사용한 Hedged ECDSA```js
import { secp256k1 } from '@noble/curves/secp256k1.js';
const { secretKey } = secp256k1.keygen();
const msg = new TextEncoder().encode('hello noble');
// extraEntropy: false - default, hedging disabled
const sigNoisy = secp256k1.sign(msg, secretKey);
// extraEntropy: true - fetch 32 random bytes from CSPRNG
const sigNoisyA = secp256k1.sign(msg, secretKey, { extraEntropy: true });
// extraEntropy: bytes - specific extra entropy
const ent = Uint8Array.from([0xca, 0xfe, 0x01, 0x23]);
const sigNoisy2 = secp256k1.sign(msg, secretKey, { extraEntropy: ent });

기본적으로 ECDSA 서명은 결정적입니다(RFC 6979). 순수하게 결정적인 서명은 폴트 공격에 취약하므로, BIP340 schnorr과 같은 최신 방식은 서명 생성에 무작위성을 도입합니다 - 일명 헤징(hedging)이라고 합니다. extraEntropy는 헤지드 모드를 활성화합니다. 더 많은 정보는 Deterministic signatures are not your friends를 확인하세요.

합의 친화성 vs 전자 투표```js

import { ed25519 } from '@noble/curves/ed25519.js'; const { secretKey, publicKey } = ed25519.keygen(); const msg = new TextEncoder().encode('hello noble'); const sig = ed25519.sign(msg, secretKey); // zip215: true const isValid = ed25519.verify(sig, msg, publicKey); // SBS / e-voting / RFC8032 / FIPS 186-5 const isValidRfc = ed25519.verify(sig, msg, publicKey, { zip215: false });

root@kitploit:~
* `zip215: true` (기본값)는 [ZIP215](https://zips.z.cash/zip-0215)에 정의된 더 관대하고 [합의 친화적인](https://hdevalence.ca/blog/2020-10-04-its-25519am) 검증 규칙을 사용합니다.
* `zip215: false`는 엄격한 RFC 8032 / FIPS 186-5 검증을 적용하고 SBS 기반
  부인 방지를 추가하는데, 이는 계약 서명, 전자 투표 및 블록체인에 유용합니다.

두 모드 모두 SUF-CMA(선택 메시지 공격에 대한 강한 위조 불가능성)를 갖추고 있습니다;
대부분의 다른 라이브러리는 SUF-CMA도 SBS도 갖추고 있지 않습니다.
자세한 내용은 [Taming the many EdDSAs](https://eprint.iacr.org/2020/1244)를 참조하세요.

### ECDH: Diffie-Hellman 공유 비밀```js
import { x25519 } from '@noble/curves/ed25519.js';
const alice = x25519.keygen();
const bob = x25519.keygen();
const sharedKey = x25519.getSharedSecret(alice.secretKey, bob.publicKey);
// Same API: secp256k1, p256, p384, p521, x448

// converting ed25519 keys to x25519
import { ed25519 } from '@noble/curves/ed25519.js';
const alice2 = ed25519.keygen();
const bob2 = ed25519.keygen();
const aliceSecX = ed25519.utils.toMontgomerySecret(alice2.secretKey);
const bobPubX = ed25519.utils.toMontgomery(bob2.publicKey);
const sharedKey2 = x25519.getSharedSecret(aliceSecX, bobPubX);

우리는 모든 Weierstrass 곡선과 2개의 Montgomery 곡선 X25519 (Curve25519) & X448 (Curve448)에 대한 ECDH를 제공하며, RFC 7748을 준수합니다.

Weierstrass 곡선에서 공유 비밀은:

  • y-패리티 바이트를 포함합니다: key.slice(1)을 사용하여 제거하세요
  • 해시되지 않습니다: sha256(shared) 또는 hkdf(shared)와 같이 해싱이나 KDF를 위에 적용하세요

webcrypto: 친화적인 래퍼```js

import { ed25519, x25519 } from '@noble/curves/webcrypto.js';

// signatures: p256, p384, p521, ed25519, ed448 const keys = await ed25519.keygen(); const msg = new TextEncoder().encode('hello noble'); const sig = await ed25519.sign(msg, keys.secretKey); const isValid = await ed25519.verify(sig, msg, keys.publicKey);

// ECDH: p256, p384, p521, x25519, x448 const alice = await x25519.keygen(); const bob = await x25519.keygen(); const shared = await x25519.getSharedSecret(alice.secretKey, bob.publicKey);

// key conversion between noble (raw) and webcrypto (pkcs8 / spki) formats import { p256 as p256n } from '@noble/curves/nist.js'; import { p256 } from '@noble/curves/webcrypto.js'; const nobleKeys = p256n.keygen(); const secretKeyPkcs8 = await p256.utils.convertSecretKey(nobleKeys.secretKey, 'raw', 'pkcs8'); const publicKeySpki = await p256.utils.convertPublicKey(nobleKeys.publicKey, 'raw', 'spki');

root@kitploit:~
WebCrypto 내장 기능을 감싼 얇은 래퍼로, noble API를 그대로 따릅니다. 메서드는 항상 비동기이며,
런타임 지원은 다양하므로 `await curve.isSupported()`로 확인하세요.
순수 JS 키 변환 유틸리티는 [micro-key-producer](https://github.com/paulmillr/micro-key-producer)를
확인하세요.

### BLS 서명, bls12-381, bn254 aka alt_bn128```ts
import { bls12_381 } from '@noble/curves/bls12-381.js';

// G1 pubkeys, G2 sigs
const blsl = bls12_381.longSignatures;
const { secretKey, publicKey } = blsl.keygen();
const msg = new TextEncoder().encode('hello noble');
const msgp = blsl.hash(msg); // hash to point, default DST
const msgpd = blsl.hash(msg, 'BLS_SIG_BLS12381G2_XMD:SHA-256_SSWU_RO_POP_'); // custom DST (Ethereum)
const signature = blsl.sign(msgp, secretKey);
const isValid = blsl.verify(signature, msgp, publicKey);

// G1 sigs, G2 pubkeys: identical API
const blss = bls12_381.shortSignatures;

// Aggregation
const aggregatedKey = blsl.aggregatePublicKeys([
  blsl.getPublicKey(bls12_381.utils.randomSecretKey()),
  blsl.getPublicKey(bls12_381.utils.randomSecretKey()),
]);
// const aggregatedSig = blsl.aggregateSignatures(sigs)

// Pairings: bls12_381.pairing(PointG1, PointG2)
// Fields: bls12_381.fields.Fp, Fp2, Fp12, Fr

예를 들어 사용법은 BLS EVM 프리컴파일 구현을 확인하세요.

BN254 API는 bls12-381을 미러링합니다. 이 곡선은 이전에 alt_bn128이라고 불렸습니다. 구현은 EIP-196 및 EIP-197과 호환됩니다: bn254 EVM 프리컴파일 구현을 확인하세요. bn254 포인트는 toBytes를 구현하지 않습니다, 직렬화 표준이 없기 때문입니다: 구현마다 엔디안, 플래그, G2 허수부 순서가 다릅니다. 대신 bigint에서 포인트를 초기화하세요.

hash-to-curve: 곡선 포인트로 해싱```ts

import { secp256k1_hasher } from '@noble/curves/secp256k1.js';

const msg = Uint8Array.from([0xca, 0xfe, 0x01, 0x23]); const point = secp256k1_hasher.hashToCurve(msg); const pointDst = secp256k1_hasher.hashToCurve(msg, { DST: 'hello noble' }); const pointNu = secp256k1_hasher.encodeToCurve(msg); const scalar = secp256k1_hasher.hashToScalar(msg);

// Same API: p256_hasher, p384_hasher, p521_hasher (nist.js), // ed25519_hasher, ristretto255_hasher (ed25519.js), ed448_hasher, decaf448_hasher (ed448.js), // bls12_381.G1, bls12_381.G2. // ristretto255 & decaf448 also provide deriveToCurve.

// abstract methods import { expand_message_xmd, expand_message_xof, hash_to_field } from '@noble/curves/abstract/hash-to-curve.js';

root@kitploit:~
모듈은 임의의 문자열을 타원 곡선 점으로 해시할 수 있게 해줍니다. [RFC 9380](https://www.rfc-editor.org/rfc/rfc9380)을 구현합니다.
`_hasher` 네임스페이스는 트리 셰이킹을 위해 곡선과 분리되어 있습니다:
hash-to-curve가 필요 없는 사용자는 빌드에 포함되지 않습니다.

### OPRFs```js
import { p256_oprf, p384_oprf, p521_oprf } from '@noble/curves/nist.js';
import { ristretto255_oprf } from '@noble/curves/ed25519.js';
import { decaf448_oprf } from '@noble/curves/ed448.js';

우리는 RFC 9497을 준수하는 OPRF(oblivious pseudorandom function)를 제공합니다.

OPRF를 사용하면 Output = PRF(Input, serverSecretKey)를 대화식으로 생성할 수 있습니다:

  • 서버는 Output을 스스로 계산할 수 없습니다: 서버는 Input을 알지 못합니다
  • 클라이언트는 Output을 스스로 계산할 수 없습니다: 클라이언트는 server secretKey를 알지 못합니다
  • 통신을 가로채는 공격자는 Input/Output/serverSecretKey를 복원할 수 없으며 Input을 특정 값과 연결할 수 없습니다.

FROST 임계 서명

FROST는 RFC 9591 임계 Schnorr 서명을 구현합니다. 애플리케이션 관점에서 이는 멀티시그와 유사합니다: max 참여자 중 임의의 min 명이 공유 공개 키 아래에서 하나의 Schnorr 서명을 공동으로 생성할 수 있습니다. 지원되는 암호 스위트는 p256_FROST, ed25519_FROST, ed448_FROST, ristretto255_FROST, secp256k1_FROST, 그리고 schnorr_FROST(Taproot 호환 secp256k1)입니다. 서명은 두 라운드로 진행됩니다: 선택된 서명자들이 먼저 커밋한 다음 서명 공유를 생성합니다.```js import { p256_FROST } from '@noble/curves/nist.js';

const signers = { min: 2, max: 3 }; const alice = p256_FROST.Identifier.derive('[email protected]'); const bob = p256_FROST.Identifier.derive('[email protected]'); const carol = p256_FROST.Identifier.derive('[email protected]'); // trusted dealer const deal = p256_FROST.trustedDealer(signers, [alice, bob, carol]); for (const id of [alice, bob, carol]) p256_FROST.validateSecret(deal.secretShares[id], deal.public);

const msg = new TextEncoder().encode('hello threshold'); // round 1: selected signers commit const aliceRound1 = p256_FROST.commit(deal.secretShares[alice]); const bobRound1 = p256_FROST.commit(deal.secretShares[bob]); const commitmentList = [aliceRound1.commitments, bobRound1.commitments]; // round 2: signers produce signature shares const sigShares = { [alice]: https://raw.githubusercontent.com/paulmillr/noble-curves/main/p256_FROST.signShare( deal.secretShares[alice], deal.public, aliceRound1.nonces, commitmentList, msg ), [bob]: https://raw.githubusercontent.com/paulmillr/noble-curves/main/p256_FROST.signShare( deal.secretShares[bob], deal.public, bobRound1.nonces, commitmentList, msg ), }; const sig = p256_FROST.aggregate(deal.public, commitmentList, msg, sigShares); const isValid = p256_FROST.verify(sig, msg, deal.public.commitments[0]);

root@kitploit:~
키 생성은 신뢰할 수 있는 딜러(위 참조) 또는 DKG(분산 키 생성)를 통해 수행할 수 있습니다.
DKG는 세 라운드로 구성됩니다: 참여자들이 키 생성에 커밋하고, 비공개 공유를 교환한 뒤,
최종 참여자 키를 도출합니다 - [테스트](https://github.com/paulmillr/noble-curves/blob/main/test/rfc9591-frost.test.ts)에서 `DKG.round1` / `round2` / `round3` 사용법을 참조하세요.
이 라이브러리는 암호화 단계를 구현하며, 주변 애플리케이션 프로토콜은 구현하지 않습니다:
호출자는 여전히 인증된 통신, 조정, 재시도, 세션 처리, 정책을 직접 처리해야 합니다.

### poseidon: Poseidon 해시

ZK 친화적 해시인 [Poseidon](https://www.poseidon-hash.info)을 구현합니다:
순열과 스폰지.

서로 다른 상수를 가진 많은 poseidon 변형이 있습니다.
우리는 그것들을 제공하지 않습니다: 직접 구성해야 합니다.
적절한 예시는 [scure-starknet](https://github.com/paulmillr/scure-starknet) 패키지를 확인하세요.```ts
import { bn254 } from '@noble/curves/bn254.js';
import { grainGenConstants, poseidon, poseidonSponge } from '@noble/curves/abstract/poseidon.js';

const rate = 2;
const capacity = 1;
const Fp = bn254.fields.Fr;
const { mds, roundConstants } = grainGenConstants({
  Fp,
  t: rate + capacity,
  roundsFull: 8,
  roundsPartial: 31,
});
const opts = {
  Fp,
  rate,
  capacity,
  sboxPower: 17,
  mds,
  roundConstants,
  roundsFull: 8,
  roundsPartial: 31,
};
const permutation = poseidon({ ...opts, t: rate + capacity });
const sponge = poseidonSponge(opts); // use carefully, not specced

fft: 고속 푸리에 변환```ts

import * as fft from '@noble/curves/abstract/fft.js'; import { bls12_381 } from '@noble/curves/bls12-381.js'; const Fr = bls12_381.fields.Fr; const roots = fft.rootsOfUnity(Fr, 7n); const fftFr = fft.FFT(roots, Fr);

root@kitploit:~
유한체 상에서의 NTT / FFT(고속 푸리에 변환).

### utils: 바이트 셔플링, 변환```ts
import { bytesToHex, concatBytes, equalBytes, hexToBytes } from '@noble/curves/utils.js';

bytesToHex(Uint8Array.from([0xca, 0xfe, 0x01, 0x23]));
hexToBytes('cafe0123');
concatBytes(Uint8Array.from([0xca, 0xfe]), Uint8Array.from([0x01, 0x23]));
equalBytes(Uint8Array.of(0xca), Uint8Array.of(0xca));

내부 구조

타원 곡선 점 연산```js

import { secp256k1 } from '@noble/curves/secp256k1.js'; const { Point } = secp256k1; const { BASE, ZERO, Fp, Fn } = Point; const p = BASE.multiply(2n);

// Math const p1 = p.add(p); const p2 = p.double(); const p3 = p.subtract(p); const p4 = p.negate(); const p5 = p.multiply(451n);

// MSM (multi-scalar multiplication) import { pippenger } from '@noble/curves/abstract/curve.js'; const pa = [BASE, BASE.multiply(2n), BASE.multiply(4n), BASE.multiply(8n)]; const p6 = pippenger(Point, pa, [3n, 5n, 7n, 11n]); // == BASE.multiply(129n)

// Cofactor const pcl = p.clearCofactor(); const isTorsionFree = p.isTorsionFree();

// Conversions const bytes = p.toBytes(); const p_ = Point.fromBytes(bytes); const { x, y } = p.toAffine(); const p__ = Point.fromAffine({ x, y });

root@kitploit:~
모든 곡선은 자체 Point 클래스를 노출합니다: secp256k1, schnorr, p256, p384, p521, ed25519, ed448,
ristretto255, decaf448, bls12_381.G1 / G2, bn254.G1, jubjub, babyjubjub.
Weierstrass 점은 사영(동차) 좌표 `new Point(X, Y, Z)`를 사용하고,
edwards 점은 확장 좌표 `new Point(X, Y, Z, T)`를 사용합니다; 둘 다 x=X/Z, y=Y/Z입니다.

#### modular: 모듈러 산술 & 유한체```js
import { mod, invert, Field } from '@noble/curves/abstract/modular.js';

// Finite Field utils
const fp = Field(2n ** 255n - 19n); // Finite field over 2^255-19
fp.mul(591n, 932n); // multiplication
fp.pow(481n, 11024858120n); // exponentiation
fp.div(5n, 17n); // division: 5/17 mod 2^255-19 == 5 * invert(17)
fp.inv(5n); // modular inverse
fp.sqrt(4n); // square root

// Non-Field generic utils are also available
mod(21n, 10n); // 21 mod 10 == 1n; fixed version of 21 % 10
invert(17n, 10n); // invert(17) mod 10; modular multiplicative inverse

모든 산술 연산은 modular 서브모듈에서 정의된 유한체 상에서 JS bigint로 수행됩니다.

체 연산은 상수 시간이 아닙니다: security를 참조하세요. 이 사실은 대부분 무관하지만, 염두에 두어야 할 중요한 메서드는 pow이며, 이는 순진하게 사용될 경우 지수 비트를 누출할 수 있습니다.

weierstrass: 사용자 정의 Weierstrass 곡선 및 ECDSA```js

import { weierstrass, ecdsa } from '@noble/curves/abstract/weierstrass.js'; import { sha256 } from '@noble/hashes/sha2.js'; // NIST secp192r1 aka p192. https://www.secg.org/sec2-v2.pdf const p192_CURVE = { p: 0xfffffffffffffffffffffffffffffffeffffffffffffffffn, n: 0xffffffffffffffffffffffff99def836146bc9b1b4d22831n, h: 1n, a: 0xfffffffffffffffffffffffffffffffefffffffffffffffcn, b: 0x64210519e59c80e70fa7e9ab72243049feb8deecc146b9b1n, Gx: 0x188da80eb03090f67cbf20eb43a18800f4ff0afd82ff1012n, Gy: 0x07192b95ffc8da78631011ed6b24cdd573f977a11e794811n, }; const p192_Point = weierstrass(p192_CURVE); const p192 = ecdsa(p192_Point, sha256);

const keys = p192.keygen(); const msg = new TextEncoder().encode('custom curve'); const sig = p192.sign(msg, keys.secretKey); const isValid = p192.verify(sig, msg, keys.publicKey);

root@kitploit:~
Short Weierstrass 곡선의 공식은 `y² = x³ + ax + b`입니다. `weierstrass`는
인수 `a`, `b`, 체 특성 `p`, 곡선 위수 `n`,
공동인자 `h` 그리고 생성점의 좌표 `Gx`, `Gy`를 받아서 Point 클래스를 반환합니다.
`ecdsa`는 Point 클래스와 해시 함수를 결합하여 서명 스킴으로 만듭니다.

#### edwards: 사용자 정의 Edwards 곡선```js
import { edwards } from '@noble/curves/abstract/edwards.js';
const ed25519_CURVE = {
  p: 0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffedn,
  n: 0x1000000000000000000000000000000014def9dea2f79cd65812631a5cf5d3edn,
  h: 8n,
  a: 0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffecn,
  d: 0x52036cee2b6ffe738cc740797779e89800700a4d4141d8ab75eb4dca135978a3n,
  Gx: 0x216936d3cd6e53fec0a4e231fdd6dc5c692cc7609525a7b2c9562d608f25d51an,
  Gy: 0x6666666666666666666666666666666666666666666666666666666666666658n,
};
const ed25519_Point = edwards(ed25519_CURVE);

Twisted Edwards 곡선의 공식은 ax² + y² = 1 + dx²y²입니다. a, d, 필드 특성 p, 곡선 위수 n(때때로 L로 명명됨), 공동인자 h, 그리고 생성점의 좌표 Gx, Gy를 지정해야 합니다.

사양

  • ECDSA: RFC 6979의 결정적 k, cfrg-det-sigs-with-noise 초안의 헤지 서명
  • EdDSA: RFC 8032, FIPS 186-5; 합의 친화적 검증: ZIP215
  • Schnorr 서명: BIP 340
  • X25519, X448 ECDH: RFC 7748
  • ristretto255, decaf448: RFC 9496
  • hash-to-curve: RFC 9380
  • OPRF: RFC 9497
  • FROST: RFC 9591
  • bn254: EIP-196, EIP-197
  • Poseidon: 사이트

보안

이 라이브러리는 감사를 받았습니다:

  • 버전 2.3.0, 2026년 8월, Trail of Bits에 의해, OpenAI와 협력하여
    • "Patch the Planet" 이니셔티브 중에 수행되었습니다
    • 범위: 전체
  • 버전 1.6.0, 2024년 9월, 독립적으로 Cure53에 의해
    • PDF: 웹사이트, 저장소 내
    • 범위: ed25519, ed448, 그들의 애드온, bls12-381, bn254, hash-to-curve, 저수준 프리미티브 bls, tower, edwards, montgomery.
    • 감사는 OpenSats의 지원을 받았습니다
  • 버전 1.2.0, 2023년 9월, 독립적으로 Kudelski Security에 의해
    • PDF: 저장소 내
    • 범위: scure-starknet 및 관련 noble-curves의 추상 모듈: curve, modular, poseidon, weierstrass
    • 감사는 Starkware의 지원을 받았습니다
  • 버전 0.7.3, 2023년 2월, 독립적으로 Trail of Bits에 의해
    • PDF: 웹사이트, 저장소 내
    • 범위: 추상 모듈 curve, hash-to-curve, , , , 및 최상위 모듈 와

2026년 4월부터 정기적인 AI 지원 자체 감사를 시작했습니다.

속성 기반, 교차 라이브러리 및 Wycheproof 벡터에 대해 테스트되며, github ci에서 퍼징됩니다.

이상한 점이 보이면: 조사하고 보고하세요.

상수 시간성

우리는 알고리즘적 상수 시간을 목표로 합니다. _JIT 컴파일러_와 _가비지 컬렉터_는 스크립팅 언어에서 "상수 시간" 타이밍 공격 저항을 달성하기 극히 어렵게 만듭니다. 이는 _다른 어떤 JS 라이브러리도 상수 시간성을 가질 수 없다_는 것을 의미합니다. GC가 없는 정적 타입 언어인 Rust조차도 일부 경우에 상수 시간 달성을 더 어렵게 만듭니다. 절대적인 보안이 목표라면, 네이티브 바인딩을 포함한 어떤 JS 라이브러리도 사용하지 마세요. 저수준 라이브러리와 언어를 사용하세요.

이러한 한계 내에서, 비밀 스칼라 곱셈은 구체적이고 측정 가능한 속성을 제공합니다:

  • 고정 연산 순서: multiply()는 데이터 무관 테이블 스캔을 사용하는 부호 있는 고정 윈도우 테이블을 사용합니다 — 점 연산의 수와 순서가 스칼라 값과 무관합니다.
  • 스칼라 블라인딩: 비밀 스칼라는 곱셈 전에 무작위 128비트 r로 s + r·n으로 추가 마스킹됩니다. 이는 공동인자-1 곡선(p256, p384, p521, secp256k1)의 모든 곱셈과 모든 곳의 기저점 곱셈에 적용됩니다.
  • 통계적 검증: dudect 스타일 Welch t-검정 하네스(benchmark/ct.ts)가 적대적 스칼라 클래스(희소 vs 밀집, 낮은 비트 vs 높은 비트, 위수 근처, 비트 패턴) 간의 타이밍을 비교합니다. 기저점 곱셈은 어떤 곡선에서도 구별 가능한 타이밍을 보이지 않으며, 임의점 곱셈은 Weierstrass 곡선에서 아무것도 보이지 않습니다(1000 샘플에서 최대 |t| ≤ 2.8; 임계값 4.5).

알려진 한계: 공동인자가 있는 Edwards 곡선(ed25519, ed448)에서 비기저 점을 비밀 스칼라로 곱하는 것은 블라인딩되지 않습니다. 동일한 하네스가 이를 안정적으로 감지합니다. EdDSA 서명은 영향을 받지 않으며(블라인딩된 기저점만 곱함), X25519/X448은 별도의 Montgomery-래더 구현을 사용합니다(역시 영향 없음). 이는 임의의 Edwards/Ristretto 점을 장기 비밀 스칼라로 곱하는 프로토콜에 중요합니다. 그런 곳에서는 구성상 전체 폭인 스칼라를 선호하세요. 격리된 하네스에서의 감지 가능성이 실제 악용 가능성을 의미하지는 않는다는 점에 유의하세요: 우리는 현실적인 교차 테넌트 / 브라우저 내 설정에서 스칼라 추출을 시도했고 100,000개의 타이밍 샘플로도 Edwards 스칼라를 복구할 수 없었습니다.

메모리 덤핑

절대적인 보안이 목표라면 JS / WASM 대신 저수준 언어를 사용하세요.

이 라이브러리는 주로 Uint8Array와 bigint를 사용합니다.

  • Uint8Array에는 내용을 0으로 채우도록 지시하는 .fill(0)이 있지만 JS에서는 보장이 없습니다
  • bigint는 불변이며 내용을 제로화하는 메서드가 없습니다: 사용자는 다음 가비지 컬렉션 주기까지 기다려야 합니다
  • hex 문자열도 불변입니다: 제로화할 방법이 없습니다
  • await fn()은 모든 내부 변수를 메모리에 기록합니다. 비동기 함수에서는 코드 청크가 언제 실행될지 보장이 없습니다. 이는 공격자가 메모리에서 데이터를 읽을 충분한 시간을 가질 수 있음을 의미합니다.

이는 일부 비밀이 예상보다 오래 메모리에 남을 수 있음을 의미합니다. 그러나 공격자가 애플리케이션 메모리를 읽을 수 있다면 어차피 끝장입니다: 프로세스 메모리를 덤프하고 민감한 데이터가 남아 있지 않은지 검증하는 복잡한 테스트 스위트 없이는 민감한 데이터 제로화에 대해 아무것도 보장할 방법이 없습니다. JS의 경우 이는 모든 브라우저(모바일 포함)를 테스트하는 것을 의미합니다. 그리고 물론, 라이브러리를 소비하는 실제 애플리케이션에서 동일한 테스트 스위트를 사용하지 않으면 무용지물입니다.

공급망 보안

  • 커밋은 위조를 방지하기 위해 PGP 키로 서명됩니다. 커밋 서명을 반드시 검증하세요
  • 릴리스는 토큰 없는 GitHub CI와 Trusted Publishing을 통해 투명하게 이루어집니다. 진위성을 위해 출처 로그를 반드시 검증하세요.
  • 드문 릴리스는 최종 사용자의 재감사 필요성을 최소화하기 위해 실천됩니다.
  • 의존성은 공급망 위험을 줄이기 위해 최소화되고 엄격하게 고정됩니다.
    • 가능한 한 적은 의존성을 사용합니다.
    • 버전 범위는 잠기고, 변경 사항은 npm-diff로 확인됩니다.
  • 개발 의존성은 최종 사용자 설치에서 제외됩니다. 개발 및 빌드 단계에서만 사용됩니다.

이 패키지에는 1개의 의존성과 몇 개의 개발 의존성이 있습니다:

  • noble-hashes는 암호화 해싱 기능을 제공합니다
  • jsbt는 벤치마킹 / 테스트 / 빌드 도구에 사용되며 동일 저자에 의해 개발되었습니다
  • prettier, fast-check, typescript는 코드 품질 / 테스트 생성 / ts 컴파일에 사용됩니다

무작위성

우리는 암호학적으로 안전한 PRNG로 간주되는 내장 crypto.getRandomValues에 의존합니다.

브라우저는 과거에 약점을 가졌었고 - 다시 가질 수도 있습니다 - 하지만 사용자 공간 CSPRNG를 구현하는 것은 고품질 엔트로피의 신뢰할 수 있는 사용자 공간 소스가 없기 때문에 훨씬 더 나쁩니다.

양자 컴퓨터

암호학적으로 관련된 양자 컴퓨터가 구축된다면, Shor 알고리즘을 사용하여 타원 곡선 암호(ECDSA / EdDSA 및 ECDH 모두)를 깰 수 있게 됩니다.

SPHINCS+와 같은 더 새롭거나 하이브리드 알고리즘으로 전환하는 것을 고려하세요. 이들은 noble-post-quantum에서 사용할 수 있습니다.

NIST는 2035년 이후 고전 암호(RSA, DSA, ECDSA, ECDH)를 금지합니다. 호주 ASD는 2030년 이후 금지합니다.

속도```sh

npm run benchmark

root@kitploit:~
noble-curves는 20MB 이상의 베이스 포인트 사전 계산을 생성하는 데 10ms 이상을 소비합니다.
이는 곡선당 **한 번만** 수행됩니다.

생성은 어떤 메서드(pubkey, sign, verify)가 호출될 때까지 지연됩니다.
사용자는 `Point.BASE.precompute(windowSize, false)`를 수동으로 호출하여 사전 계산 생성을 강제할 수 있습니다.
소스 코드를 확인하세요.

Apple M4에서의 벤치마크 결과:```
# algorithm=getPublicKey
ed25519                    7,299 ops/sec · 137 μs/op
secp256k1                  4,872 ops/sec · 205 μs/op · -1.5x
p256                       4,724 ops/sec · 212 μs/op · -1.5x
bls12_381 (long, G2 sig)   3,466 ops/sec · 288 μs/op · -2.1x
ed448                      3,224 ops/sec · 310 μs/op · -2.3x
p384                       2,185 ops/sec · 458 μs/op · -3.3x
p521                       1,221 ops/sec · 819 μs/op · -6x
bls12_381 (short, G1 sig)  1,070 ops/sec · 934 μs/op · -6.8x

# algorithm=sign
secp256k1                  4,217 ops/sec · 237 μs/op
p256                       4,116 ops/sec · 243 μs/op · ≈
ed25519                    3,536 ops/sec · 283 μs/op · -1.2x
p384                       1,992 ops/sec · 502 μs/op · -2.1x
ed448                      1,577 ops/sec · 634 μs/op · -2.7x
p521                       1,131 ops/sec · 884 μs/op · -3.7x
bls12_381 (short, G1 sig)  417 ops/sec · 2.39 ms/op · -10x
bls12_381 (long, G2 sig)   112 ops/sec · 8.88 ms/op · -37x

# algorithm=verify
ed25519                    1,504 ops/sec · 665 μs/op
secp256k1                  1,352 ops/sec · 739 μs/op · -1.1x
p256                       917 ops/sec · 1.09 ms/op · -1.6x
ed448                      546 ops/sec · 1.83 ms/op · -2.8x
p384                       381 ops/sec · 2.62 ms/op · -3.9x
p521                       187 ops/sec · 5.34 ms/op · -8x
bls12_381 (short, G1 sig)  100 ops/sec · 9.98 ms/op · -15x
bls12_381 (long, G2 sig)   77 ops/sec · 12.9 ms/op · -19x

# algorithm=getSharedSecret
ed25519                    1,695 ops/sec · 590 μs/op
secp256k1                  763 ops/sec · 1.31 ms/op · -2.2x
p256                       737 ops/sec · 1.36 ms/op · -2.3x
ed448                      599 ops/sec · 1.67 ms/op · -2.8x
p384                       326 ops/sec · 3.06 ms/op · -5.2x
p521                       176 ops/sec · 5.68 ms/op · -9.6x

업그레이드

지원되는 node.js 버전:

  • v2 (2025-08): v20.19+ (ESM 전용)
  • v1 (2023-04): v14.21+ (ESM & CJS)

v1에서 v2로

v2는 내부 구조를 대폭 단순화하고, 보안을 개선하며, 번들 크기를 줄이고, 미래를 위한 기반을 마련합니다. v2는 최대한 하위 호환성을 유지하려고 노력했습니다.

업그레이드 경로: 먼저 curves v1.9.x로 업그레이드하세요. 사용 중단(deprecation) 경고를 수정한 다음 v2로 전환하세요.

모듈:

  • 패키지가 이제 ESM 전용입니다. ESM은 마침내 node v20.19+에서 common.js로부터 로드할 수 있습니다.
  • 이제 .js 확장자가 필요합니다: @noble/curves/ed25519 => @noble/curves/ed25519.js. 이를 통해 트랜스파일러 없이 네이티브 브라우저 사용이 가능합니다.
  • p256, p384, p521은 nist로 이동되었고, jubjub은 misc로 이동되었습니다.
  • pasta와 bn254_weierstrass (페어링 기반이 아닌 bn254) 곡선은 제거되었습니다.

새로운 기능:

  • webcrypto: 내장 WebCrypto에 대한 친숙한 noble 스타일 래퍼
  • oprf: RFC 9497 OPRF (oblivious pseudorandom functions) p256, p384, p521, ristretto255 및 decaf448용
  • weierstrass, edwards: 새로운 isValidSecretKey, isValidPublicKey 메서드
  • misc: Brainpool 곡선 brainpoolP256r1, brainpoolP384r1, brainpoolP512r1
  • 대폭 개선되고 더 설명적인 오류 메시지

호환성을 깨는 변경 사항:

  • 대부분의 메서드가 이제 Uint8Array만 허용하며, 문자열 hex 입력은 금지됩니다. 이는 추론을 단순화하고 보안을 개선하며 가변성(malleability)을 줄입니다. Point.fromHex는 이제 문자열 전용입니다: Uint8Array에는 Point.fromBytes를 사용하세요.
  • ECDSA (secp256k1, p256, p384...) 서명 및 검증:
    • 사전 해시된 메시지: 메서드가 이제 messageHash 대신 해시되지 않은 메시지를 기대합니다. 이전 동작: {prehash: false}
    • 기본적으로 lowS 서명. secp256k1은 영향을 받지 않습니다: 처음부터 lowS를 사용해 왔습니다. 이전 동작: {lowS: false}
    • 기본적으로 Uint8Array 서명 (형식: 'compact')
    • verify: der 형식은 {format: 'der'}에 명시적으로 지정해야 합니다. 이는 가변성을 줄입니다.
    • verify: Signature 인스턴스는 금지됩니다: 먼저 signature.toBytes()를 호출하세요.
  • BLS 서명 (bls12-381, bn254):
    • getPublicKey, sign, verify, signShortSignature 등이 두 개의 새로운 네임스페이스로 이동되었습니다: longSignatures (G1 공개키, G2 서명) 및 shortSignatures (G1 서명, G2 공개키)
    • verifyBatch는 이제 입력 배열 {message: ..., publicKey: ...}[]을 기대합니다.
  • 사용자 정의 곡선:
    • 곡선 생성이 대폭 단순화되어 포인트 생성과 서명 생성기 생성으로 분리되었습니다: weierstrass() + ecdsa() / . weierstrass / edwards는 단순화된 곡선 매개변수를 기대합니다 (Fp가 p가 됨); ecdsa / eddsa는 Point 클래스와 해시를 기대합니다.

이름 변경 (curves v1.9는 이전 이름을 사용 중단으로 표시):

  • 포인트
    • ExtendedPoint, ProjectivePoint => Point
    • 포인트 좌표 px/ex, py/ey, pz/ez, et => X, Y, Z, T
    • toRawBytes, fromRawBytes => toBytes, fromBytes
    • Point.normalizeZ, Point.msm => abstract/curve.js 서브모듈의 별도 메서드
    • Point.fromPrivateKey(key) => Point.BASE.multiply(Point.Fn.fromBytes(key))
    • 온갖 잡다한 것을 담은 CURVE 속성 => 곡선 매개변수만 제공하는 Point.CURVE()
    • RistrettoPoint => ristretto255.Point, DecafPoint => decaf448.Point
  • ECDSA 서명
    • toCompactRawBytes, toDERRawBytes => toBytes('compact'), toBytes('der')
    • toCompactHex, toDERHex => toHex('compact'), toHex('der')
    • fromCompact, fromDER => fromBytes(bytes, format), fromHex(hex, format)
  • utils
    • randomPrivateKey => randomSecretKey
    • normPrivateKeyToScalar => Point.Fn.fromBytes
    • utils.precompute, Point#_setWindowSize => Point#precompute
    • edwardsToMontgomery, edwardsToMontgomeryPriv => utils.toMontgomery, utils.toMontgomerySecret
  • 곡선별 hash-to-curve 메서드 => *curve*_hasher. 예: secp256k1.hashToCurve => secp256k1_hasher.hashToCurve()
  • 대규모 타입 이름 변경 및 개선

제거된 기능: Point#multiplyAndAddUnsafe, Point#hasEvenY, Field.MASK

기여 및 테스트

npm install && npm run build && npm test는 코드를 빌드하고 테스트를 실행합니다.

추가 스위트가 있습니다: 느린 대형 스칼라 / 대형 곡선 테스트 npm run test:slow, 그리고 상수 시간(constant-timeness) 하네스 npm run benchmark:ct.

라이브러리와 관련된 유용한 리소스, 문서, 기사 및 데모는 paulmillr.com/noble을 참조하세요.

라이선스

The MIT License (MIT)

Copyright (c) 2022 Paul Miller (https://paulmillr.com)

LICENSE 파일을 참조하세요.

도구 다운로드
modular
poseidon
utils
weierstrass
_shortw_utils
secp256k1
  • 감사는 Ryan Shea의 지원을 받았습니다
  • edwards() + eddsa()
  • pippenger: 불필요한 Fn 인수가 제거되었습니다.
  • Field#fromBytes()는 이제 요소가 0..order-1 범위에 있는지 검증합니다.