11#include " zkir/Dialect/EllipticCurve/Conversions/EllipticCurveToField/PointOperations/Jacobian/Double.h"
22
33#include " mlir/Dialect/Arith/IR/Arith.h"
4+ #include " mlir/Dialect/SCF/IR/SCF.h"
45#include " mlir/Dialect/Tensor/IR/Tensor.h"
56#include " mlir/IR/ImplicitLocOpBuilder.h"
67#include " zkir/Dialect/EllipticCurve/IR/EllipticCurveTypes.h"
@@ -13,17 +14,14 @@ namespace mlir::zkir::elliptic_curve {
1314// https://www.hyperelliptic.org/EFD/g1p/auto-shortw-jacobian.html#doubling-mdbl-2007-bl
1415// Cost: 1M + 5S
1516// Assumption: Z == 1
16- Value affineToJacobianDouble (const Value &point, Type affineType ,
17+ Value affineToJacobianDouble (const Value &point, const Value &a ,
1718 ImplicitLocOpBuilder &b) {
1819 Value zero = b.create <arith::ConstantIndexOp>(0 );
1920 Value one = b.create <arith::ConstantIndexOp>(1 );
2021
2122 auto x = b.create <tensor::ExtractOp>(point, zero);
2223 auto y = b.create <tensor::ExtractOp>(point, one);
2324
24- field::PrimeFieldType basefield = cast<field::PrimeFieldType>(x.getType ());
25- field::PrimeFieldAttr aAttr;
26-
2725 // XX = X²
2826 auto xx = b.create <field::SquareOp>(x);
2927 // YY = Y²
@@ -39,8 +37,6 @@ Value affineToJacobianDouble(const Value &point, Type affineType,
3937 // M = 3*XX+a
4038 auto mTmp1 = b.create <field::DoubleOp>(xx);
4139 auto mTmp2 = b.create <field::AddOp>(mTmp1 , xx);
42- aAttr = cast<AffineType>(affineType).getCurve ().getA ();
43- auto a = b.create <field::ConstantOp>(basefield, aAttr.getValue ());
4440 auto m = b.create <field::AddOp>(mTmp2 , a);
4541 // X3 = M²-2*S
4642 auto x3Tmp1 = b.create <field::SquareOp>(m);
@@ -59,10 +55,56 @@ Value affineToJacobianDouble(const Value &point, Type affineType,
5955 return b.create <tensor::FromElementsOp>(SmallVector<Value>({x3, y3, z3}));
6056}
6157
58+ // dbl-2009-l
59+ // https://www.hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html#doubling-dbl-2009-l
60+ // Cost: 2M + 5S
61+ Value jacobianA0Double (const Value &point, ImplicitLocOpBuilder &b) {
62+ Value zero = b.create <arith::ConstantIndexOp>(0 );
63+ Value one = b.create <arith::ConstantIndexOp>(1 );
64+ Value two = b.create <arith::ConstantIndexOp>(2 );
65+
66+ auto x = b.create <tensor::ExtractOp>(point, zero);
67+ auto y = b.create <tensor::ExtractOp>(point, one);
68+ auto z = b.create <tensor::ExtractOp>(point, two);
69+
70+ // A = X²
71+ auto a = b.create <field::SquareOp>(x);
72+ // B = Y²
73+ auto yy = b.create <field::SquareOp>(y);
74+ // C = B²
75+ auto c = b.create <field::SquareOp>(yy);
76+ // D = 2*((X+B)²-A-C)
77+ auto dTmp1 = b.create <field::AddOp>(x, yy);
78+ auto dTmp2 = b.create <field::SquareOp>(dTmp1);
79+ auto dTmp3 = b.create <field::SubOp>(dTmp2, a);
80+ auto dTmp4 = b.create <field::SubOp>(dTmp3, c);
81+ auto d = b.create <field::DoubleOp>(dTmp4);
82+ // E = 3*A
83+ auto eTmp1 = b.create <field::DoubleOp>(a);
84+ auto e = b.create <field::AddOp>(eTmp1, a);
85+ // F = E²
86+ auto f = b.create <field::SquareOp>(e);
87+ // X3 = F-2*D
88+ auto x3Tmp1 = b.create <field::DoubleOp>(d);
89+ auto x3 = b.create <field::SubOp>(f, x3Tmp1);
90+ // Y3 = E*(D-X3)-8*C
91+ auto y3Tmp1 = b.create <field::SubOp>(d, x3);
92+ auto y3Tmp2 = b.create <field::MulOp>(e, y3Tmp1);
93+ auto y3Tmp3 = b.create <field::DoubleOp>(c);
94+ auto y3Tmp4 = b.create <field::DoubleOp>(y3Tmp3);
95+ auto y3Tmp5 = b.create <field::DoubleOp>(y3Tmp4);
96+ auto y3 = b.create <field::SubOp>(y3Tmp2, y3Tmp5);
97+ // Z3 = 2*Y*Z
98+ auto z3Tmp1 = b.create <field::DoubleOp>(y);
99+ auto z3 = b.create <field::MulOp>(z3Tmp1, z);
100+
101+ return b.create <tensor::FromElementsOp>(SmallVector<Value>({x3, y3, z3}));
102+ }
103+
62104// dbl-2007-bl
63105// https://www.hyperelliptic.org/EFD/g1p/auto-shortw-jacobian.html#doubling-dbl-2007-bl
64106// Cost: 1M + 8S + 1*a
65- Value jacobianDefaultDouble (const Value &point, Type jacobianType ,
107+ Value jacobianDefaultDouble (const Value &point, const Value &a ,
66108 ImplicitLocOpBuilder &b) {
67109 Value zero = b.create <arith::ConstantIndexOp>(0 );
68110 Value one = b.create <arith::ConstantIndexOp>(1 );
@@ -72,9 +114,6 @@ Value jacobianDefaultDouble(const Value &point, Type jacobianType,
72114 auto y = b.create <tensor::ExtractOp>(point, one);
73115 auto z = b.create <tensor::ExtractOp>(point, two);
74116
75- field::PrimeFieldType basefield = cast<field::PrimeFieldType>(x.getType ());
76- field::PrimeFieldAttr aAttr;
77-
78117 // XX = X²
79118 auto xx = b.create <field::SquareOp>(x);
80119 // YY = Y²
@@ -93,8 +132,6 @@ Value jacobianDefaultDouble(const Value &point, Type jacobianType,
93132 auto mTmp1 = b.create <field::DoubleOp>(xx);
94133 auto mTmp2 = b.create <field::AddOp>(mTmp1 , xx);
95134 auto mTmp3 = b.create <field::SquareOp>(zz);
96- aAttr = cast<JacobianType>(jacobianType).getCurve ().getA ();
97- auto a = b.create <field::ConstantOp>(basefield, aAttr.getValue ());
98135 auto mTmp4 = b.create <field::MulOp>(a, mTmp3 );
99136 auto m = b.create <field::AddOp>(mTmp2 , mTmp4 );
100137 // X3 = M²-2*S
@@ -119,10 +156,33 @@ Value jacobianDefaultDouble(const Value &point, Type jacobianType,
119156
120157Value jacobianDouble (const Value &point, Type inputType,
121158 ImplicitLocOpBuilder &b) {
122- if (isa<AffineType>(inputType)) {
123- return affineToJacobianDouble (point, inputType, b);
124- } else if (isa<JacobianType>(inputType)) {
125- return jacobianDefaultDouble (point, inputType, b);
159+ auto baseField = cast<field::PrimeFieldType>(
160+ cast<RankedTensorType>(point.getType ()).getElementType ());
161+ field::PrimeFieldAttr aAttr;
162+
163+ if (auto affineType = dyn_cast<AffineType>(inputType)) {
164+ aAttr = affineType.getCurve ().getA ();
165+ auto a = b.create <field::ConstantOp>(baseField, aAttr.getValue ());
166+ return affineToJacobianDouble (point, a, b);
167+ } else if (auto jacobianType = dyn_cast<JacobianType>(inputType)) {
168+ aAttr = jacobianType.getCurve ().getA ();
169+ auto a = b.create <field::ConstantOp>(baseField, aAttr.getValue ());
170+ auto zero = b.create <field::ConstantOp>(baseField, 0 );
171+
172+ auto cmpEq = b.create <field::CmpOp>(arith::CmpIPredicate::eq, a, zero);
173+ auto ifOp = b.create <scf::IfOp>(
174+ cmpEq,
175+ /* thenBuilder=*/
176+ [&](OpBuilder &builder, Location loc) {
177+ ImplicitLocOpBuilder b (loc, builder);
178+ b.create <scf::YieldOp>(jacobianA0Double (point, b));
179+ },
180+ /* elseBuilder=*/
181+ [&](OpBuilder &builder, Location loc) {
182+ ImplicitLocOpBuilder b (loc, builder);
183+ b.create <scf::YieldOp>(jacobianDefaultDouble (point, a, b));
184+ });
185+ return ifOp.getResult (0 );
126186 } else {
127187 assert (false && " Unsupported point type for Jacobian doubling" );
128188 }
0 commit comments