edwards: make zip215 false Strongly Binding Signature (SBS) secure. gh-40

This commit is contained in:
Paul Miller 2023-05-05 01:37:13 +00:00
parent 6621053c7d
commit 42de620010
No known key found for this signature in database
GPG Key ID: 697079DA6878B89B
3 changed files with 11 additions and 10 deletions

@ -5,7 +5,7 @@ Audited & minimal JS implementation of elliptic curve cryptography.
- 🔒 [**Audited**](#security) by an independent security firm - 🔒 [**Audited**](#security) by an independent security firm
- 🔻 Tree-shaking-friendly: use only what's necessary, other code won't be included - 🔻 Tree-shaking-friendly: use only what's necessary, other code won't be included
- 🏎 Ultra-fast, hand-optimized for caveats of JS engines - 🏎 Ultra-fast, hand-optimized for caveats of JS engines
- 🔍 Unique tests ensure correctness: property-based, cross-library and Wycheproof vectors, fuzzing - 🔍 Unique tests ensure correctness: property-based, cross-library and Wycheproof vectors, fuzzing
- ➰ Short Weierstrass, Edwards, Montgomery curves - ➰ Short Weierstrass, Edwards, Montgomery curves
- ✍️ ECDSA, EdDSA, Schnorr, BLS signature schemes, ECDH key agreement - ✍️ ECDSA, EdDSA, Schnorr, BLS signature schemes, ECDH key agreement
- #⃣ Hash-to-curve - #⃣ Hash-to-curve
@ -121,7 +121,10 @@ x25519 ECDH and [ristretto255](https://datatracker.ietf.org/doc/html/draft-irtf-
Default `verify` behavior follows [ZIP215](https://zips.z.cash/zip-0215) and Default `verify` behavior follows [ZIP215](https://zips.z.cash/zip-0215) and
[can be used in consensus-critical applications](https://hdevalence.ca/blog/2020-10-04-its-25519am). [can be used in consensus-critical applications](https://hdevalence.ca/blog/2020-10-04-its-25519am).
`zip215: false` option switches verification criteria to RFC8032 / FIPS 186-5. `zip215: false` option switches verification criteria to stricter
RFC8032 / FIPS 186-5 which is also
SUF-CMA (strong unforgeability under chosen message attacks) and
SBS (Strongly Binding signature) as per [eprint 2020/1244](https://eprint.iacr.org/2020/1244).
```ts ```ts
import { ed25519 } from '@noble/curves/ed25519'; import { ed25519 } from '@noble/curves/ed25519';
@ -554,7 +557,7 @@ aggregateSignatures: {
millerLoop: (ell: [Fp2, Fp2, Fp2][], g1: [Fp, Fp]) => Fp12; millerLoop: (ell: [Fp2, Fp2, Fp2][], g1: [Fp, Fp]) => Fp12;
pairing: (P: ProjPointType<Fp>, Q: ProjPointType<Fp2>, withFinalExponent?: boolean) => Fp12; pairing: (P: ProjPointType<Fp>, Q: ProjPointType<Fp2>, withFinalExponent?: boolean) => Fp12;
G1: CurvePointsRes<Fp> & ReturnType<typeof htf.createHasher<Fp>>; G1: CurvePointsRes<Fp> & ReturnType<typeof htf.createHasher<Fp>>;
G2: CurvePointsRes<Fp2> & ReturnType<typeof htf.createHasher<Fp2>>; G2: CurvePointsRes<Fp2> & ReturnType<typeof htf.createHasher<Fp2>>;
Signature: SignatureCoder<Fp2>; Signature: SignatureCoder<Fp2>;
params: { params: {
x: bigint; x: bigint;
@ -567,7 +570,7 @@ fields: {
Fp2: IField<Fp2>; Fp2: IField<Fp2>;
Fp6: IField<Fp6>; Fp6: IField<Fp6>;
Fp12: IField<Fp12>; Fp12: IField<Fp12>;
Fr: IField<bigint>; Fr: IField<bigint>;
}; };
utils: { utils: {
randomPrivateKey: () => Uint8Array; randomPrivateKey: () => Uint8Array;

@ -474,6 +474,7 @@ export function twistedEdwards(curveDef: CurveType): CurveFn {
} catch (error) { } catch (error) {
return false; return false;
} }
if (!zip215 && A.isSmallOrder()) return false;
const k = hashDomainToScalar(context, R.toRawBytes(), A.toRawBytes(), msg); const k = hashDomainToScalar(context, R.toRawBytes(), A.toRawBytes(), msg);
const RkA = R.add(A.multiplyUnsafe(k)); const RkA = R.add(A.multiplyUnsafe(k));

@ -410,12 +410,9 @@ describe('ed25519', () => {
} }
}); });
should('not verify when x=0 and x_0 = 1 (RFC8032)', () => { should('have strict SUF-CMA and SBS properties', () => {
const list = [edgeCases[8], edgeCases[10], edgeCases[11]]; // https://eprint.iacr.org/2020/1244
for (let v of list) { const list = [0, 1, 6, 7, 8, 9, 10, 11].map((i) => edgeCases[i]);
const result = ed.verify(v.signature, v.message, v.pub_key, { zip215: true });
strictEqual(result, true, `zip215: true must validate: ${v.signature}`);
}
for (let v of list) { for (let v of list) {
const result = ed.verify(v.signature, v.message, v.pub_key, { zip215: false }); const result = ed.verify(v.signature, v.message, v.pub_key, { zip215: false });
strictEqual(result, false, `zip215: false must not validate: ${v.signature}`); strictEqual(result, false, `zip215: false must not validate: ${v.signature}`);