Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
8ca0316
chore: upgrade noble curves
gabrocheleau Nov 8, 2025
330b5d6
chore: upgrade noble hashes
gabrocheleau Nov 8, 2025
f01f788
chore: fix type issue for cjs
gabrocheleau Nov 9, 2025
fa1d794
Merge branch 'master' into chore/upgrade-noble-2.0.1
gabrocheleau Nov 9, 2025
d1c5a66
chore: attempt to fix import issues
gabrocheleau Nov 9, 2025
50c6774
fix: lint issue
gabrocheleau Nov 9, 2025
6b73c9f
evm: fix p256 import
Nov 10, 2025
de911f4
evm: use updated p256 API
Nov 10, 2025
4f0bf95
evm: use updated Point api
Nov 10, 2025
62e6b1f
chore: attempt to fix tests
gabrocheleau Nov 10, 2025
c67605f
Merge branch 'master' into chore/upgrade-noble-2.0.1
gabrocheleau Nov 13, 2025
2f43b85
Merge branch 'chore/upgrade-noble-2.0.1' of https://github.com/ethere…
gabrocheleau Nov 13, 2025
dab0ad2
chore: attempt higher timeout
gabrocheleau Nov 13, 2025
1b2c07e
chore: attempt to fix
gabrocheleau Nov 13, 2025
0676037
chore: add prehash to cspell
gabrocheleau Nov 13, 2025
8f3a014
Merge branch 'master' into chore/upgrade-noble-2.0.1
gabrocheleau Nov 13, 2025
ff218fc
Merge branch 'master' into chore/upgrade-noble-2.0.1
gabrocheleau Nov 14, 2025
ec52436
Merge branch 'master' into chore/upgrade-noble-2.0.1
gabrocheleau Nov 14, 2025
4327552
chore: attempt noble fix
gabrocheleau Nov 14, 2025
3479d29
Merge branch 'master' into chore/upgrade-noble-2.0.1
gabrocheleau Nov 15, 2025
23504fb
Add lowS: false to p256.sign() and p256.verify()
holgerd77 Nov 17, 2025
f52c026
Add prehash: false to p256.verify/sign methods
holgerd77 Nov 18, 2025
d46b971
Merge branch 'master' into chore/upgrade-noble-2.0.1
holgerd77 Nov 18, 2025
c2bf887
Merge branch 'master' into chore/upgrade-noble-2.0.1
holgerd77 Nov 20, 2025
928ff77
Attempted Noble bn254 mul fix (modulus is embedded in the create() me…
holgerd77 Nov 20, 2025
bfea62b
Merge branch 'chore/upgrade-noble-2.0.1' of https://github.com/ethere…
holgerd77 Nov 20, 2025
f00c827
Merge branch 'master' into chore/upgrade-noble-2.0.1
holgerd77 Nov 20, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion config/cspell-ts.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
}
],
"words": [
"prehash",
"viem",
"immediates",
"unerasable",
Expand Down Expand Up @@ -644,4 +645,4 @@
"Damgård",
"viem"
]
}
}
29 changes: 28 additions & 1 deletion package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion packages/evm/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -382,7 +382,7 @@ const pointY = bigIntToHex(pointPubKey.Y)

// Message (hash) / signature
const msg = new TextEncoder().encode('Hello Fusaka!')
const sig = p256.sign(msg, secretKey)
const sig = p256.sign(msg, secretKey, { lowS: false, prehash: false })
const msgHash = bytesToHex(sha256(msg))
const sigR = bytesToHex(sig).substring(2, 64 + 2)
const sigS = bytesToHex(sig).substring(64 + 2)
Expand Down
21 changes: 14 additions & 7 deletions packages/evm/examples/precompiles/100-p256verify.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
import { Hardfork } from '@ethereumjs/common'
import { type PrefixedHexString, bytesToHex, randomBytes, utf8ToBytes } from '@ethereumjs/util'
import { p256 } from '@noble/curves/p256'
import {
type PrefixedHexString,
bytesToHex,
bytesToUnprefixedHex,
randomBytes,
utf8ToBytes,
} from '@ethereumjs/util'
import { p256 } from '@noble/curves/nist.js'
import { sha256 } from 'ethereum-cryptography/sha256.js'
import { runPrecompile } from './util.ts'

Expand All @@ -18,18 +24,19 @@ const main = async () => {
const message = 'ethereumjs-evm-p256verify-example'
const messageHash = sha256(utf8ToBytes(message))

const privateKey = randomBytes(32)
const publicKey = p256.ProjectivePoint.fromPrivateKey(privateKey).toAffine()
const privateKey = p256.utils.randomSecretKey()
const publicKey = p256.getPublicKey(privateKey, false) // Get uncompressed public key

const signature = p256.sign(messageHash, privateKey)
const signatureBytes = p256.sign(messageHash, privateKey, { lowS: false, prehash: false })
const signature = p256.Signature.fromBytes(signatureBytes)

const padHex = (value: bigint) => value.toString(16).padStart(64, '0')

const msgHashHex = bytesToHex(messageHash)
const rHex = padHex(signature.r)
const sHex = padHex(signature.s)
const qxHex = padHex(publicKey.x)
const qyHex = padHex(publicKey.y)
const qxHex = bytesToUnprefixedHex(publicKey.slice(1, 33)).padStart(64, '0')
const qyHex = bytesToUnprefixedHex(publicKey.slice(33, 65)).padStart(64, '0')

const data: PrefixedHexString = `${msgHashHex}${rHex}${sHex}${qxHex}${qyHex}`

Expand Down
2 changes: 1 addition & 1 deletion packages/evm/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@
"@ethereumjs/common": "^10.1.0",
"@ethereumjs/statemanager": "^10.1.0",
"@ethereumjs/util": "^10.1.0",
"@noble/curves": "^1.9.0",
"@noble/curves": "^2.0.1",
"debug": "^4.4.0",
"ethereum-cryptography": "^3.2.0",
"eventemitter3": "^5.0.1"
Expand Down
11 changes: 7 additions & 4 deletions packages/evm/src/precompiles/100-p256verify.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { bytesToBigInt, bytesToHex, setLengthLeft } from '@ethereumjs/util'
import { p256 } from '@noble/curves/p256'
import { p256 } from '@noble/curves/nist.js'

import { OOGResult } from '../evm.ts'

Expand Down Expand Up @@ -103,7 +103,7 @@ export function precompile100(opts: PrecompileInput): ExecResult {

try {
// Create public key point
const publicKey = p256.ProjectivePoint.fromAffine({
const publicKey = p256.Point.fromAffine({
x: qxBigInt,
y: qyBigInt,
})
Expand All @@ -115,10 +115,13 @@ export function precompile100(opts: PrecompileInput): ExecResult {
signatureBytes.set(rBytes, 0)
signatureBytes.set(sBytes, 32)

const signature = p256.Signature.fromCompact(signatureBytes)
const signature = p256.Signature.fromBytes(signatureBytes).toBytes()

// Verify signature
const isValid = p256.verify(signature, msgHash, publicKey.toRawBytes(false))
const isValid = p256.verify(signature, msgHash, publicKey.toBytes(false), {
lowS: false,
prehash: false,
})

if (isValid) {
if (opts._debug !== undefined) {
Expand Down
59 changes: 24 additions & 35 deletions packages/evm/src/precompiles/bls12_381/noble.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
equalsBytes,
setLengthLeft,
} from '@ethereumjs/util'
import { bls12_381 } from '@noble/curves/bls12-381'
import { bls12_381 } from '@noble/curves/bls12-381.js'

import { EVMError } from '../../errors.ts'

Expand All @@ -20,12 +20,14 @@
BLS_ZERO_BUFFER,
} from './constants.ts'

import type { Fp2 } from '@noble/curves/abstract/tower'
import type { AffinePoint } from '@noble/curves/abstract/weierstrass'
import type { Fp2 } from '@noble/curves/abstract/tower.js'
import type { AffinePoint } from '@noble/curves/abstract/weierstrass.js'
import type { EVMBLSInterface } from '../../types.ts'

const G1_ZERO = bls12_381.G1.ProjectivePoint.ZERO
const G2_ZERO = bls12_381.G2.ProjectivePoint.ZERO
// @ts-ignore - @noble/curves v2 is ESM-only, TypeScript's moduleResolution: "node" doesn't properly resolve types for CJS build

Check warning on line 27 in packages/evm/src/precompiles/bls12_381/noble.ts

View workflow job for this annotation

GitHub Actions / lint / lint

Use "@ts-expect-error" instead of "@ts-ignore", as "@ts-ignore" will do nothing if the following line is error-free
const G1_ZERO = bls12_381.G1.Point.ZERO
// @ts-ignore - @noble/curves v2 is ESM-only, TypeScript's moduleResolution: "node" doesn't properly resolve types for CJS build

Check warning on line 29 in packages/evm/src/precompiles/bls12_381/noble.ts

View workflow job for this annotation

GitHub Actions / lint / lint

Use "@ts-expect-error" instead of "@ts-ignore", as "@ts-ignore" will do nothing if the following line is error-free
const G2_ZERO = bls12_381.G2.Point.ZERO

function BLS12_381_ToFp2Point(fpXCoordinate: Uint8Array, fpYCoordinate: Uint8Array) {
// check if the coordinates are in the field
Expand Down Expand Up @@ -56,7 +58,8 @@
const x = bytesToBigInt(input.subarray(16, BLS_G1_POINT_BYTE_LENGTH / 2))
const y = bytesToBigInt(input.subarray(80, BLS_G1_POINT_BYTE_LENGTH))

const G1 = bls12_381.G1.ProjectivePoint.fromAffine({
// @ts-ignore - @noble/curves v2 is ESM-only, TypeScript's moduleResolution: "node" doesn't properly resolve types for CJS build

Check warning on line 61 in packages/evm/src/precompiles/bls12_381/noble.ts

View workflow job for this annotation

GitHub Actions / lint / lint

Use "@ts-expect-error" instead of "@ts-ignore", as "@ts-ignore" will do nothing if the following line is error-free
const G1 = bls12_381.G1.Point.fromAffine({
x,
y,
})
Expand Down Expand Up @@ -99,7 +102,8 @@
const Fp2X = BLS12_381_ToFp2Point(p_x_1, p_x_2)
const Fp2Y = BLS12_381_ToFp2Point(p_y_1, p_y_2)

const pG2 = bls12_381.G2.ProjectivePoint.fromAffine({
// @ts-ignore - @noble/curves v2 is ESM-only, TypeScript's moduleResolution: "node" doesn't properly resolve types for CJS build

Check warning on line 105 in packages/evm/src/precompiles/bls12_381/noble.ts

View workflow job for this annotation

GitHub Actions / lint / lint

Use "@ts-expect-error" instead of "@ts-ignore", as "@ts-ignore" will do nothing if the following line is error-free
const pG2 = bls12_381.G2.Point.fromAffine({
x: Fp2X,
y: Fp2Y,
})
Expand Down Expand Up @@ -130,26 +134,9 @@

function BLS12_381_ToFrPoint(input: Uint8Array): bigint {
const Fr = bls12_381.fields.Fr.fromBytes(input)

// TODO: This fixes the following two failing tests:
// bls_g1mul_random*g1_unnormalized_scalar
// bls_g1mul_random*p1_unnormalized_scalar
// It should be nevertheless validated if this is (fully) correct,
// especially if ">" or ">=" should be applied.
//
// Unfortunately the scalar in both test vectors is significantly
// greater than the ORDER threshold, here are th values from both tests:
//
// Scalar / Order
// 69732848789442042582239751384143889712113271203482973843852656394296700715236n
// 52435875175126190479447740508185965837690552500527637822603658699938581184513n
//
// There should be 4 test cases added to the official test suite:
// 1. bls_g1mul_random*g1_unnormalized_scalar within threshold (ORDER (?))
// 2. bls_g1mul_random*g1_unnormalized_scalar outside threshold (ORDER + 1 (?))
// 3. bls_g1mul_random*p1_unnormalized_scalar within threshold (ORDER (?))
// 4. bls_g1mul_random*p1_unnormalized_scalar outside threshold (ORDER + 1 (?))
//
if (Fr >= bls12_381.fields.Fr.ORDER) {
return bls12_381.fields.Fr.create(Fr % bls12_381.fields.Fr.ORDER)
}
return bls12_381.fields.Fr.create(Fr)
}

Expand Down Expand Up @@ -180,7 +167,7 @@
)

const p = p1.add(p2)
const result = BLS12_381_FromG1Point(p)
const result = BLS12_381_FromG1Point(p.toAffine())

return result
}
Expand All @@ -194,7 +181,7 @@
return BLS_G1_INFINITY_POINT_BYTES
}
const result = p.multiplyUnsafe(scalar)
return BLS12_381_FromG1Point(result)
return BLS12_381_FromG1Point(result.toAffine())
}

addG2(input: Uint8Array): Uint8Array {
Expand All @@ -204,7 +191,7 @@
false,
)
const p = p1.add(p2)
const result = BLS12_381_FromG2Point(p)
const result = BLS12_381_FromG2Point(p.toAffine())

return result
}
Expand All @@ -218,20 +205,22 @@
return BLS_G2_INFINITY_POINT_BYTES
}
const result = p.multiplyUnsafe(scalar)
return BLS12_381_FromG2Point(result)
return BLS12_381_FromG2Point(result.toAffine())
}

mapFPtoG1(input: Uint8Array): Uint8Array {
// convert input to Fp1 point
const FP = BLS12_381_ToFpPoint(input.subarray(0, 64))
const result = bls12_381.G1.mapToCurve([FP]).toAffine()
// @ts-ignore - @noble/curves v2 is ESM-only, TypeScript's moduleResolution: "node" doesn't properly resolve types for CJS build

Check warning on line 214 in packages/evm/src/precompiles/bls12_381/noble.ts

View workflow job for this annotation

GitHub Actions / lint / lint

Use "@ts-expect-error" instead of "@ts-ignore", as "@ts-ignore" will do nothing if the following line is error-free
const result = bls12_381.G1.mapToCurve(FP).toAffine()
const resultBytes = BLS12_381_FromG1Point(result)
return resultBytes
}

mapFP2toG2(input: Uint8Array): Uint8Array {
// convert input to Fp2 point
const Fp2Point = BLS12_381_ToFp2Point(input.subarray(0, 64), input.subarray(64, 128))
// @ts-ignore - @noble/curves v2 is ESM-only, TypeScript's moduleResolution: "node" doesn't properly resolve types for CJS build

Check warning on line 223 in packages/evm/src/precompiles/bls12_381/noble.ts

View workflow job for this annotation

GitHub Actions / lint / lint

Use "@ts-expect-error" instead of "@ts-ignore", as "@ts-ignore" will do nothing if the following line is error-free
const result = bls12_381.G2.mapToCurve([Fp2Point.c0, Fp2Point.c1]).toAffine()
const resultBytes = BLS12_381_FromG2Point(result)
return resultBytes
Expand Down Expand Up @@ -266,7 +255,7 @@
pRes = pRes.add(pMul)
}

return BLS12_381_FromG1Point(pRes)
return BLS12_381_FromG1Point(pRes.toAffine())
}

msmG2(input: Uint8Array): Uint8Array {
Expand Down Expand Up @@ -298,7 +287,7 @@
pRes = pRes.add(pMul)
}

return BLS12_381_FromG2Point(pRes)
return BLS12_381_FromG2Point(pRes.toAffine())
}

pairingCheck(input: Uint8Array): Uint8Array {
Expand All @@ -319,7 +308,7 @@

// Filter out infinity pairs
const filteredPairs = pairs.filter(
(pair) => !pair.g1.equals(G1_ZERO) && !pair.g2.equals(G2_ZERO),
(pair) => pair.g1.equals(G1_ZERO) === false && pair.g2.equals(G2_ZERO) === false,
)

const FP12 = bls12_381.pairingBatch(filteredPairs, true)
Expand Down
Loading
Loading