paulmillr / noble-bls12-381 Goto Github PK
View Code? Open in Web Editor NEWDEPRECATED. Use noble-curves instead. Fastest JS implementation of BLS12-381.
Home Page: https://paulmillr.com/noble/
License: MIT License
DEPRECATED. Use noble-curves instead. Fastest JS implementation of BLS12-381.
Home Page: https://paulmillr.com/noble/
License: MIT License
How fast do the various operations run? For example, how many pairings per second?
Just a quick question regarding hash_to_field as a way to convert arbitrary bytes to Fr
In the ietf draft it says
https://www.ietf.org/archive/id/draft-irtf-cfrg-hash-to-curve-10.html#section-5-4
"The hash_to_field function is also suitable for securely hashing to scalars. For example, when hashing to scalars for an elliptic curve (sub)group with prime order r, it suffices to instantiate hash_to_curve with target field GF(r)."
I've modified noble-bls12-381 locally allowing hash_to_field to take a 4th parameter, field = math_1.CURVE.P
and then passing in math_1.CURVE.r
to generate bytes for Fr using hash_to_field (also exported hash_to_field function in utils).
From what I can see this is legitimate use of hash_to_field. Is there anything you're aware of that would make this a bad idea?
The idea doesn't seem widely used (unlike hash_g2) but it seems like it should be a robust and standardized kdf from arbitrary bytes to key without rejection sampling. Am I understanding it correctly?
Can’t use with react-native:
Uncaught (in promise) TypeError: Cannot convert a BigInt value to a number
Any idea how to solve this?
Following your suggestion here, I implemented your modexp
function in our bigint conversion PR. I may have uncovered an edge case not addressed in your method and wanted to get your input. In the modexptests
in the Ethereum/Tests
repo, there are a couple of tests that generate a call to the modexp
method with a 0 for the exponent and some other value for the modulo and one case in particular passes in a = 0, power = 0, and modulo 1. In your method as currently coded, this would result in a 1 being returned though the expected result in the ethereum test is 0 (I believe based on the understanding that any base ^ 0 = 1 and then 1 % 1 = 0. Does this look like a possible edge case that your code doesn't account for? I've added in a check where the exponent = 0 and then returned 1 % modulo in our code and this satisfies the test case and I believe is a correct result, at least on some definitions of exponentiation (though I'm far from an expert in this area) so I wanted to raise it and get your input.
As you can see here:
Lines 331 to 346 in b06f567
const htfDefaults = {
DST: 'BLS_SIG_BLS12381G2_XMD:SHA-256_SSWU_RO_NUL_',
p: math_js_1.CURVE.P,
m: 2,
k: 128,
expand: true,
hash: sha256,
};
This could be an issue for people meaning to use the library to do things on G1 and not providing their own DST or their own test vectors and thus not detecting the issue. Overall it doesn't look like a big security problem, but it does cause interoperability issues.
I need to perform hash to curve on G1, like this:
https://github.com/kilic/bls12-381/blob/6045b0235e36793a56ad254cc6d2af650c3a584f/g1.go#L827-L846
Is that currently possible with Noble? I wasn't able to find the required function.
If not, would you consider implementing it?
(We'd be happy to sponsor its implementation, since it's necessary to implement a JS lib compatible with our identity-based encryption scheme: https://github.com/drand/kyber/blob/master/encrypt/ibe/ibe.go#L47.)
Hey there 🙂
I'm trying to use this library for signing Filecoin messages. Specifically the signature/pubkey aggregation tools which aren't available in the Filecoin WASM lib
However, I've noticed that the public keys don't match up:
private key: 4eeb8f66c557115a7ec37e7debc2b0b9130f0d4a2b74cd64ec478a88e2ac052c
public key (from zondax lib): 84b1498c9332a1639f67c8e2fc49a9bae0ecfb68cb6182f12ad8c30cc62e8c37029aeaeaa5e1685fb2656792b926bc8d
public key (from noble-bls12-381): ac2d1dc191f5f8766ac7cef6877c10ff928b7a8217e1f64ca069499242f91e5f50064c8ee2b337e0b6a68b6808bc11f0
Do you have any quick thoughts on the matter. I'm relatively new to BLS, but from what I can tell, these should all be on the same pair of 2 curves, and I've verified that both this lib & filecoin use G1 for public keys and G2 for signatures.
I've also verified that the zondax lib calculates the same public key as the lotus node does (Go implementation of Filecoin).
Is there something else that I'm not thinking of?
Does the lib support multiplication of G1
, G2
by Fr
?
I don't see it in the code, but I could be wrong.
https://github.com/paulmillr/noble-bls12-381/blob/master/README.md#internals
DST BLS_SIG_BLS12381G2_XMD:SHA-256_SSWU_RO_POP_
should be
DST BLS_SIG_BLS12381G2_XMD:SHA-256_SSWU_RO_NUL_
Hi,
We are using noble-bls12-381 library in our project. And we also have to use the Bls12381G2KeyPair.ts > bls12381-key-pair library in our project.
Now I would like to know whether the noble-bls12-381 could support the Bls12381G2KeyPair.ts library.
Please let me know.
As explained above we will have to use the Bls12381G2KeyPair.ts library from noble-bls12-381.
My email id : [email protected]
TypeError: Cannot convert a BigInt value to a number
at Math.pow ()
at Object.../../../../webuy/uniapp/mui1/mui1/node_modules/noble-bls12-381/math.js (pages-wallet-setPwd.js:4330)
at webpack_require (index.js:854)
at fn (index.js:151)
at Object. (pages-wallet-setPwd.js:3760)
at Object.../../../../webuy/uniapp/mui1/mui1/node_modules/noble-bls12-381/index.js (pages-wallet-setPwd.js:4307)
at webpack_require (index.js:854)
at fn (index.js:151)
at Object. (pages-wallet-setPwd.js:2696)
at Object.../../../../webuy/uniapp/mui1/mui1/node_modules/chia-wallet-utils/build/index.js (pages-wallet-setPwd.js:3084)
I was attempting to do some benchmark between the existing BLS implementations however this library has an async API which breaks with what https://github.com/ChainSafe/bls currently has. I see that the reason of the async API is the hash function. Could a sync version of sha256
be used so the API stays sync?
hi! i got a error when to change DST_LABEL.
import * as bls from 'noble-bls12-381';
// Default domain (DST) is `BLS_SIG_BLS12381G2_XMD:SHA-256_SSWU_RO_NUL_`, use `bls.DST` to change it.
bls.DST_LABEL = 'BLS_SIG_BLS12381G2_XMD:SHA-256_SSWU_RO_AUG_';
/** Cannot assign to 'DST_LABEL' because it is a read-only property.ts(2540) */
is any other way to change it?
according to the original paper, BLS seems to support shortest signature size like 160bits, but i cant find any lib that can support that size directly. i know 160bits is less secure, but produce more user friendly signature for keyboard typing, which can be used in some cases.
This implementation uses BLS_SIG_BLS12381G2_XMD:SHA-256_SSWU_RO_NUL_
while Ethereum uses BLS_SIG_BLS12381G2_XMD:SHA-256_SSWU_RO_POP_
. To verify Ethereum signatures one has to set the DST label (bls.utils.setDSTLabel('BLS_SIG_BLS12381G2_XMD:SHA-256_SSWU_RO_POP_')
). Perhaps worth mentioning this in the README.
As specified in the introduction, BLS12-381 is used for non-signature applications such as SNARKs. It may make sense to expose a non-signature API (e.g. directly expose the pairing function).
Hello,
I need to use your library to sign a transaction and publish on a ethereum 2.0 supported testnet. Is there any tutorial or example to do it?
I'm getting several different errors while running the example code from the README.
Environment: running locally in node.js on a lightweight express server.
const privateKey = '67d53f170b908cabb9eb326c3c337762d59289a8fec79f7bc9254b584b73265c';
const msg = 'hello';
const publicKey = bls.getPublicKey(privateKey);
const signature = await bls.sign(msg, privateKey);
const isCorrect = await bls.verify(msg, publicKey, signature);
(node:6722) UnhandledPromiseRejectionWarning: Error: Expected hex string or Uint8Array, got 0hello
at hexToBytes (/home/daniel/Projects/fission/fil-cosigner/node_modules/noble-bls12-381/index.js:74:19)
at Function.hashToCurve (/home/daniel/Projects/fission/fil-cosigner/node_modules/noble-bls12-381/index.js:241:19)
...
Alrighty, no plaintext msgs. Let's convert the msg to a Uint8Array:
const fromHexString = hexString =>
new Uint8Array(hexString.match(/.{1,2}/g).map(byte => parseInt(byte, 16)));
const privateKey = '67d53f170b908cabb9eb326c3c337762d59289a8fec79f7bc9254b584b73265c';
const msg = fromHexString('hello');
const publicKey = bls.getPublicKey(privateKey);
const signature = await bls.sign(msg, privateKey);
const isCorrect = await bls.verify(msg, publicKey, signature);
(node:8466) UnhandledPromiseRejectionWarning: Error: The given point is not on G1: y**2 = x**3 + b
at Function.fromCompressedHex (/home/daniel/Projects/fission/fil-cosigner/node_modules/noble-bls12-381/index.js:187:19)
at normP1 (/home/daniel/Projects/fission/fil-cosigner/node_modules/noble-bls12-381/index.js:323:55)
at Object.verify (/home/daniel/Projects/fission/fil-cosigner/node_modules/noble-bls12-381/index.js:34
...
Everything works well up to verify
. I also tried, hashing the msg to a point on G2 before verify
which didn't change anything. This appears to be an issue with the public key, since the public key is supposed to be on G1.
Any thoughts/ideas?
Hi,
I may be wrong but I think the serialisation of the point at infinity is wrong. I would expect the two high order bits to be set (compressed = true, infinity = true), but converting Z1
to a private key has only the compressed bit set:
800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
As opposed to:
C00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
I thought I'd double check by deserialising again and comparing the points:
console.log(Z1);
console.log(publicKeyToG1(publicKeyFromG1(Z1)));
This produces the following:
Point {
x: Fp { _value: 1n },
y: Fp { _value: 1n },
z: Fp { _value: 0n },
C: [Function: Fp] {
ORDER: 4002409555221667393417789825735904156556882819939007885332058136124031650490837864442687629129015664037894272559787n
}
}
Point {
x: Fp { _value: 0n },
y: Fp { _value: 2n },
z: Fp { _value: 1n },
C: [Function: Fp] {
ORDER: 4002409555221667393417789825735904156556882819939007885332058136124031650490837864442687629129015664037894272559787n
}
}
Thanks
Mark
Hello and thank you for this library! It's really helping me learn about ECC and BLS. I have a use case in mind that does not seem to work, and I am not sure if I am doing it wrong, or if it is just not possible.
A simple addition to your example here illustrates what I'm trying to do:
// aggSignature3 = 3 different messages signed with 3 different private keys (3 diff individual public sigs) aggregated into one sig
// aggPubKey2 = 3 public keys corresponding to the 3 private keys above aggregated into one pub key
// any way to verify each individual message from the group of 3 with only the aggregated sigs and pub keys? or impossible?
const onlyFirstMessage = messages[0];
const isCorrect4 = await bls.verify(aggSignature3, onlyFirstMessage, aggPubKey2) // str, str, str
console.log('is correct: ', isCorrect4); // returns false
This code fails:
console.log(PointG1.ZERO);
console.log(PointG2.ZERO);
with the following stack trace:
Error: invert: expected positive integers, got n=0 mod=4002409555221667393417789825735904156556882819939007885332058136124031650490837864442687629129015664037894272559787
at invert (/node_modules/@noble/bls12-381/lib/math.js:75:15)
at Fp.invert (/node_modules/@noble/bls12-381/lib/math.js:108:23)
at PointG1.toAffine (/node_modules/@noble/bls12-381/lib/math.js:625:28)
at PointG1.toString (/node_modules/@noble/bls12-381/lib/math.js:619:29)
Should the ProjectivePoint.toString
function check for the ZERO point before trying to invert?
Currently, this module does not completely support the deno runtime environment.
When trying to use this with deno, the following error occurs:
error: Import 'https://deno.land/x/[email protected]/math' failed: 404 Not Found
at https://deno.land/x/[email protected]/index.ts:14:0
This is happening because deno requires an explicit extension for import statements. For example, './math.ts'
instead of './math'
.
Miller Loop is a basic but important algorithm to calculate pairing.
noble-bls12-381 is a clean and independent implementation of bls12-381 pairing without library dependency.
I know the original Miller Loop algorithm, but in above implementation, there exist a tricky pairingPrecomputes, is there any material or description about this pre-computing? thanks a lot
https://github.com/paulmillr/noble-bls12-381/blob/main/index.ts#L395
@paulmillr , utils.setDSTLabel
can not change htfDefaults.DST
, and func rely on htfDefaults.DST
intead of DST_LABEL
https://github.com/paulmillr/noble-bls12-381/blob/main/index.ts#L45
please ignore
I have been spending some time with this already, but I can't get it to work. I can't be the only one.
The readme has basic usage instructions for Node.js and browser, but it is never explained how to include the Javascipt files in your project. I have tried
index.js
and math.js
via <script>
tagimport from
None of it worked. I'd have given up, but it does work on NPM Runkit, so I know there is a way to do it, which is frustrating. I tried looking for a CDN version of the code, but it seems it does not yet exist either.
I don't know whether it makes sense to provide a compiled, single-file release version for the browser, but it sure would have made including this on a website easier.
Came across an issue where if i make two messages similar enough i can produce the same signature for two different messages, not sure if i should be hashing messages before passing them to bls.sign()? Documentation seems to suggest bls.sign hashes before signing
message: Uint8Array | string - message which would be hashed & signed
var bls = require('noble-bls12-381');
testfunction()
async function testfunction() {
privKey = "970a3e0249bc5e464291d5eee88ae364d8b794f648950055a382a28ed73d655472f218dae342d3ee4566443ff23a78d85580eb4b11954f6286c6cfc67ad1c082"
message1 = "test"
message2 = "tes3"
let signature1 = await bls.sign(message1, privKey)
let signature2 = await bls.sign(message2, privKey)
console.log(signature1 +" "+ signature2)
};
Result of this is
Sig1
175,108,55,86,26,251,15,127,253,213,104,43,200,96,1,209,89,116,108,207,203,153,209,235,196,140,78,183,134,165,209,6,236,115,195,3,34,60,8,206,114,48,62,206,39,129,17,62,0,138,178,86,37,175,157,169,168,138,78,130,147,204,36,130,255,89,38,124,134,252,16,192,209,18,225,6,107,203,116,129,81,194,75,230,226,178,210,79,239,165,8,110,90,253,199,246
Sig2
175,108,55,86,26,251,15,127,253,213,104,43,200,96,1,209,89,116,108,207,203,153,209,235,196,140,78,183,134,165,209,6,236,115,195,3,34,60,8,206,114,48,62,206,39,129,17,62,0,138,178,86,37,175,157,169,168,138,78,130,147,204,36,130,255,89,38,124,134,252,16,192,209,18,225,6,107,203,116,129,81,194,75,230,226,178,210,79,239,165,8,110,90,253,199,246
Which are identical, despite signing two different messages "test" and "tes3"
@paulmillr Hi,
Learning fast elliptic-curve cryptography in JS This blog helped me a lot and gave me an in-depth understanding of secp256k1, but bls12-381 is very different from secp256k1 and ed25519, which makes me very distressed. Do you have any plans to write an blog about bls12-381?
Quoting README.md:
But, JIT-compiler and Garbage Collector make "constant time" extremely hard to achieve in a scripting language.
In the context of cryptographic security "constant time" is not about elapsed wall-clock time it takes to perform an operation, but its invariance in relation to secret material. In other words it's not like there may be no timing variations whatsoever, but whatever variations there are, they may not depend on the secret value. And as long as this condition is met, JIT or Garbage Collector may intervene at any time, including during secret-key operations, and for as long as deemed necessary.
I'm not asserting that achieving constant-time-ness in pure JavaScript is feasible, but JIT or Garbage Collector are not as large of obstacles as suggested. In JavaScript or elsewhere.
The hash to curve draft standard does not support try-and-increment. The specific hashToG2 standard for blockchains is based on Wahby-Boneh.
When I tried to use this library instead of BLS_verify implementation into agent-js library I cannot make it work. I only obtained Error: Invalid G1 point: not on curve Fp
. Going into agent-rs library to watch what the original implementation does, I realize that in DFinity libraries PublicKey is G2 point and signature is a G1 point. So, there is anyway to fix this problem?
agent-rs library where implement bls verify https://github.com/dfinity/agent-rs/blob/88606ecc8288592a7bcc1c8d23e877914b3b31da/ic-agent/src/bls/bls12381/bls.rs#L137-L171
https://eprint.iacr.org/2019/814.pdf
The code is slower than this.multiplyUnsafe(CURVE.hEff).isZero()
. Need to understand why the "optimization" does not optimize. I mean, hEff aka 0xd201000000010001n
has low hamming weight et al; need to understand deeply why the opt is possible.
// σ(P)
private sigma(): PointG1 {
const BETA = 0x1a0111ea397fe699ec02408663d4de85aa0d857d89759ad4897d29650fb85f9b409427eb4f49fffd8bfd00000000aaacn;
const [x, y] = this.toAffine();
return new PointG1(x.multiply(BETA), y);
}
private isTorsionFree(): boolean {
// (x²−1)/3
const c1 = 76329603384216526021617858986798044501n;
const P = this;
let sP = P.sigma();
let Q = sP.double();
sP = sP.sigma();
Q = Q.subtract(P).subtract(sP).multiplyUnsafe(c1).subtract(sP);
return Q.isZero();
}
Hi @paulmillr,
Thanks for the great work.
Are you planning to add support for constructing points G1 and G2 from their uncompressed forms?
https://docs.rs/bls12_381/0.4.0/bls12_381/struct.G1Affine.html#method.from_uncompressed
https://docs.rs/bls12_381/0.4.0/bls12_381/struct.G2Affine.html#method.from_uncompressed
In PR #22:
Using the readme example the below does not verify using node v 12.0.
const msg = 'hello';
const privateKeys = [
'18f020b98eb798752a50ed0563b079c125b0db5dd0b1060d1c1b47d4a193e1e4',
'ed69a8c50cf8c9836be3b67c7eeff416612d45ba39a5c099d48fa668bf558c9c',
'16ae669f3be7a2121e17d0c68c05a8f3d6bef21ec0f2315f1d7aec12484e4cf5'
];
const publicKeys = privateKeys.map(bls.getPublicKey);
const signatures = await Promise.all(privateKeys.map(p => bls.sign(msg, p)));
const aggPubKey: any = await bls.aggregatePublicKeys(publicKeys);
const aggSignature = await bls.aggregateSignatures(signatures);
const isCorrect = await bls.verify(aggSignature, msg, aggPubKey);
//=> returns false
console.log({isCorrect});
@paulmillr Hi paulmillr,
Is noble-bls12-381 compatible with https://github.com/Chia-Network/bls-signatures?
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.