UNPKG

o1js

Version:

TypeScript framework for zk-SNARKs and zkApps

128 lines (116 loc) 3.98 kB
import { Pallas, Vesta } from './elliptic-curve.js'; import { Fp, Fq } from './finite-field.js'; import assert from 'node:assert/strict'; import { test, Random } from '../../lib/testing/property.js'; for (let [G, Field, Scalar] of [ [Pallas, Fp, Fq] as const, [Vesta, Fq, Fp] as const, ]) { // endomorphism constants assert.equal(Field.power(G.endoBase, 3n), 1n, 'cube root in base field'); assert.equal(Scalar.power(G.endoScalar, 3n), 1n, 'cube root in scalar field'); let randomScalar = Random(Scalar.random); let randomField = Random(Field.random); // create random points by scaling 1 with a random scalar let randomPoint = Random(() => G.scale(G.one, Scalar.random())); // let one / zero be sampled 20% of times each randomPoint = Random.oneOf( G.zero, G.one, randomPoint, randomPoint, randomPoint ); test( randomPoint, randomPoint, randomPoint, randomScalar, randomScalar, randomField, (X, Y, Z, x, y, f) => { // check on curve assert(G.isOnCurve(X) && G.isOnCurve(Y) && G.isOnCurve(Z), 'on curve'); // can't be on curve because b=5 is a non-square assert(!Field.isSquare(G.b)); assert( !G.isOnCurve({ x: 0n, y, z: 1n }), 'x=0 => y^2 = b is not on curve' ); // can't be on curve because the implied equation is f^6 = f^6 + b assert( !G.isOnCurve({ x: Field.power(f, 2n), y: Field.power(f, 3n), z: 1n }), 'x^3 = y^2 is not on curve' ); // equal assert(G.equal(X, X), 'equal'); assert( !G.equal(X, G.add(X, X)) || G.equal(X, G.zero), 'not equal to double of itself (or zero)' ); assert( !G.equal(X, G.negate(X)) || G.equal(X, G.zero), 'not equal to negation of itself (or zero)' ); assert(!G.equal(X, Y) || X === Y, 'not equal (random points)'); // case where `equal` checks non-trivial z relationship let X_ = { x: Field.mul(X.x, Field.square(f)), y: Field.mul(X.y, Field.power(f, 3n)), z: Field.mul(X.z, f), }; assert(G.equal(X, X_), 'equal non-trivial'); // algebraic laws - addition assert(G.equal(G.add(X, Y), G.add(Y, X)), 'commutative'); assert( G.equal(G.add(X, G.add(Y, Z)), G.add(G.add(X, Y), Z)), 'associative' ); assert(G.equal(G.add(X, G.zero), X), 'identity'); assert(G.equal(G.add(X, G.negate(X)), G.zero), 'inverse'); // addition does doubling assert(G.equal(G.add(X, X), G.double(X)), 'double'); // scaling by small factors assert(G.equal(G.scale(X, 0n), G.zero), 'scale by 0'); assert(G.equal(G.scale(X, 1n), X), 'scale by 1'); assert(G.equal(G.scale(X, 2n), G.add(X, X)), 'scale by 2'); assert(G.equal(G.scale(X, 3n), G.add(X, G.add(X, X))), 'scale by 3'); assert(G.equal(G.scale(X, 4n), G.double(G.double(X))), 'scale by 4'); // algebraic laws - scaling assert( G.equal( G.scale(X, Scalar.add(x, y)), G.add(G.scale(X, x), G.scale(X, y)) ), 'distributive' ); assert( G.equal(G.scale(X, Scalar.negate(x)), G.negate(G.scale(X, x))), 'distributive (negation)' ); assert( G.equal(G.scale(X, Scalar.mul(x, y)), G.scale(G.scale(X, x), y)), 'scale / multiply is associative' ); // endomorphism assert( G.equal(G.endomorphism(X), G.scale(X, G.endoScalar)), 'efficient endomorphism' ); // subgroup assert(G.isInSubgroup(X), 'subgroup check'); // affine let affineX = G.toAffine(X); assert( G.equal(G.fromAffine(affineX), X), 'affine - projective roundtrip' ); let { x: xa, y: ya } = affineX; assert( G.equal(X, G.zero) || Field.square(ya) === Field.add(Field.power(xa, 3n), G.b), 'affine on curve (or zero)' ); } ); }