diff --git a/src/ec_mulmuladd.cairo b/src/ec_mulmuladd.cairo new file mode 100644 index 0000000..d198a5b --- /dev/null +++ b/src/ec_mulmuladd.cairo @@ -0,0 +1,304 @@ +//*************************************************************************************/ +///* Copyright (C) 2022 - Renaud Dubois - This file is part of Cairo_musig2 project */ +///* License: This software is licensed under a dual BSD and GPL v2 license. */ +///* See LICENSE file at the root folder of the project. */ +///* FILE: multipoint.cairo */ +///* */ +///* */ +///* DESCRIPTION: optimization of dual base multiplication*/ +///* the algorithm combines the so called Shamir's trick with Windowing method */ +//**************************************************************************************/ + +//Shamir's trick:https://crypto.stackexchange.com/questions/99975/strauss-shamir-trick-on-ec-multiplication-by-scalar, +//Windowing method : https://en.wikipedia.org/wiki/Exponentiation_by_squaring, section 'sliding window' +//The implementation use a 2 bits window with trick, leading to a 16 points elliptic point precomputation + + +from starkware.cairo.common.cairo_builtins import EcOpBuiltin +from starkware.cairo.common.registers import get_ap +from starkware.cairo.common.registers import get_fp_and_pc + +from starkware.cairo.common.uint256 import Uint256 + +from starkware.cairo.common.math_cmp import is_nn_le + +from starkware.cairo.common.cairo_secp.bigint import BigInt3, UnreducedBigInt3, nondet_bigint3 +from starkware.cairo.common.cairo_secp.field import ( + is_zero, + unreduced_mul, + unreduced_sqr, + verify_zero, +) + +from src.ec import EcPoint, ec_add, ec_mul, ec_double + + +//Structure storing all aP+b.Q for (a,b) in [0..3]x[0..3] +struct Window { + G: EcPoint, + Q: EcPoint, + W3: EcPoint, + W4: EcPoint, + W5: EcPoint, + W6: EcPoint, + W7: EcPoint, + W8: EcPoint, + W9: EcPoint, + W10: EcPoint, + W11: EcPoint, + W12: EcPoint, + W13: EcPoint, + W14: EcPoint, + W15: EcPoint, +} + + + +//https://crypto.stackexchange.com/questions/99975/strauss-shamir-trick-on-ec-multiplication-by-scalar, +//* Internal call for recursion of point multiplication via Shamir's trick */ +func ec_mulmuladd_inner{range_check_ptr}(R: EcPoint, G: EcPoint, Q: EcPoint, H: EcPoint,scalar_u: felt, scalar_v: felt, m: felt) -> (res: EcPoint){ + + + alloc_locals; + //this means if m=-1, beware if felt definition changes + if(m == 3618502788666131213697322783095070105623107215331596699973092056135872020480){ + //%{ print("\n end of recursion" ) %} + return(res=R); + } + + let (double_point: EcPoint) = ec_double(R); + // %{ print("\n double" ) %} + + let mm1:felt=m-1; + local dibit; + + //extract MSB values of both exponents + %{ ids.dibit = ((ids.scalar_u >>ids.m)&1) +2*((ids.scalar_v >>ids.m)&1) %} + //%{ print("\n ui=",ids.scalar_u >>ids.m, "\n vi=", ids.scalar_v >>ids.m) %} + + //set R:=R+R + if(dibit==0){ + let (res:EcPoint)= ec_mulmuladd_inner(double_point,G,Q,H,scalar_u,scalar_v,mm1 ); + return(res=res); + } + //if ui=1 and vi=0, set R:=R+G + if(dibit==1){ + let (res10:EcPoint)=ec_add(double_point,G); + let (res:EcPoint)= ec_mulmuladd_inner(res10,G,Q,H,scalar_u,scalar_v,mm1 ); + return(res=res); + } + //(else) if ui=0 and vi=1, set R:=R+Q + if(dibit==2){ + let (res01:EcPoint)=ec_add(double_point,Q); + let (res:EcPoint)= ec_mulmuladd_inner(res01,G,Q,H,scalar_u,scalar_v,mm1 ); + return(res=res); + } + //(else) if ui=1 and vi=1, set R:=R+Q + if(dibit==3){ + let (res11:EcPoint)=ec_add(double_point,H); + let (res:EcPoint)= ec_mulmuladd_inner(res11,G,Q,H,scalar_u,scalar_v,mm1 ); + + return(res=res); + } + + //you shall never end up here + return(res=R); +} + + + +//https://crypto.stackexchange.com/questions/99975/strauss-shamir-trick-on-ec-multiplication-by-scalar, +//* Internal call for recursion of point multiplication via Shamir's trick+Windowed method */ +func ec_mulmuladd_W_inner{range_check_ptr}(R: EcPoint, Prec:Window, scalar_u: felt, scalar_v: felt, m: felt) -> (res: EcPoint){ + alloc_locals; + let mm1:felt=m-2; + local quad_bit;//(8*v1 4*u1+ 2*v0 + u0), where (u1,u0) represents two bit at index m of scalar u, (resp for v) + + if(m == -1){ + //%{ print("\n end of recursion, no add" ) %} + return(res=R); + } + + let (double_point: EcPoint) = ec_double(R); + // %{ print("\n double" ) %} + + //still have to make the last addition over 1 bit (initial length was odd) + if(m == 0){ + %{ print("\n end of recursion, one bit" ) %} + let (res:EcPoint)=ec_mulmuladd_inner(R, Prec.G, Prec.Q, Prec.W3, scalar_u, scalar_v, m); + + return(res=res); + } + + let (quadruple_point: EcPoint) = ec_double(double_point); + //%{ print("\n double" ) %} + + + //compute quadruple (8*v1 4*u1+ 2*v0 + u0) + %{ ids.quad_bit = 8*((ids.scalar_v >>ids.m)&1) +4*((ids.scalar_u >>ids.m)&1) +2*((ids.scalar_v >>(ids.m-1))&1)+((ids.scalar_u >>(ids.m-1))&1) %} + // %{ print("\n index=",ids.m , "quad_bit=", ids.quad_bit) %} + + if(quad_bit==0){ + let (res:EcPoint)=ec_mulmuladd_W_inner(quadruple_point, Prec, scalar_u, scalar_v, m-2); + return(res=res); + } + if(quad_bit==1){ + let (ecTemp:EcPoint)=ec_add(quadruple_point,Prec.G); + let (res:EcPoint)=ec_mulmuladd_W_inner(ecTemp, Prec, scalar_u, scalar_v, m-2); + + return(res=res); + } + if(quad_bit==2){ + let (ecTemp:EcPoint)=ec_add(quadruple_point,Prec.Q); + let (res:EcPoint)=ec_mulmuladd_W_inner(ecTemp, Prec, scalar_u, scalar_v, m-2); + return(res=res); + } + + if(quad_bit==3){ + let (ecTemp:EcPoint)=ec_add(quadruple_point,Prec.W3); + let (res:EcPoint)=ec_mulmuladd_W_inner(ecTemp, Prec, scalar_u, scalar_v, m-2); + return(res=res); + } + if(quad_bit==4){ + let (ecTemp:EcPoint)=ec_add(quadruple_point,Prec.W4); + let (res:EcPoint)=ec_mulmuladd_W_inner(ecTemp, Prec, scalar_u, scalar_v, m-2); + return(res=res); + } + if(quad_bit==5){ + let (ecTemp:EcPoint)=ec_add(quadruple_point,Prec.W5); + let (res:EcPoint)=ec_mulmuladd_W_inner(ecTemp, Prec, scalar_u, scalar_v, m-2); + return(res=res); + } + if(quad_bit==6){ + let (ecTemp:EcPoint)=ec_add(quadruple_point,Prec.W6); + let (res:EcPoint)=ec_mulmuladd_W_inner(ecTemp, Prec, scalar_u, scalar_v, m-2); + return(res=res); + } + if(quad_bit==7){ + let (ecTemp:EcPoint)=ec_add(quadruple_point,Prec.W7); + let (res:EcPoint)=ec_mulmuladd_W_inner(ecTemp, Prec, scalar_u, scalar_v, m-2); + return(res=res); + } + if(quad_bit==8){ + let (ecTemp:EcPoint)=ec_add(quadruple_point,Prec.W8); + let (res:EcPoint)=ec_mulmuladd_W_inner(ecTemp, Prec, scalar_u, scalar_v, m-2); + return(res=res); + } + if(quad_bit==9){ + let (ecTemp:EcPoint)=ec_add(quadruple_point,Prec.W9); + let (res:EcPoint)=ec_mulmuladd_W_inner(ecTemp, Prec, scalar_u, scalar_v, m-2); + return(res=res); + } + if(quad_bit==10){ + let (ecTemp:EcPoint)=ec_add(quadruple_point,Prec.W10); + let (res:EcPoint)=ec_mulmuladd_W_inner(ecTemp, Prec, scalar_u, scalar_v, m-2); + return(res=res); + } + if(quad_bit==11){ + let (ecTemp:EcPoint)=ec_add(quadruple_point,Prec.W11); + let (res:EcPoint)=ec_mulmuladd_W_inner(ecTemp, Prec, scalar_u, scalar_v, m-2); + return(res=res); + } + if(quad_bit==12){ + let (ecTemp:EcPoint)=ec_add(quadruple_point,Prec.W12); + let (res:EcPoint)=ec_mulmuladd_W_inner(ecTemp, Prec, scalar_u, scalar_v, m-2); + return(res=res); + } + if(quad_bit==13){ + let (ecTemp:EcPoint)=ec_add(quadruple_point,Prec.W13); + let (res:EcPoint)=ec_mulmuladd_W_inner(ecTemp, Prec, scalar_u, scalar_v, m-2); + return(res=res); + } + if(quad_bit==14){ + let (ecTemp:EcPoint)=ec_add(quadruple_point,Prec.W14); + let (res:EcPoint)=ec_mulmuladd_W_inner(ecTemp, Prec, scalar_u, scalar_v, m-2); + return(res=res); + } + if(quad_bit==15){ + let (ecTemp:EcPoint)=ec_add(quadruple_point,Prec.W15); + let (res:EcPoint)=ec_mulmuladd_W_inner(ecTemp, Prec, scalar_u, scalar_v, m-2); + return(res=res); + } + + //shall not be reach + return(res=R); +} + +//https://crypto.stackexchange.com/questions/99975/strauss-shamir-trick-on-ec-multiplication-by-scalar, +//further optimized with 'windowing method' +func ec_mulmuladd_W{range_check_ptr}(G: EcPoint, Q: EcPoint, scalar_u: felt, scalar_v: felt) -> (res: EcPoint){ + + alloc_locals; + local m; + //Precompute a 4-bit window , W0=infty, W1=P, W2=Q, the window is indexed by (8*v1 4*u1+ 2*v0 + u0), where (u1,u0) represents two bit of scalar u, (resp for v) + + let W3:EcPoint=ec_add{range_check_ptr=range_check_ptr}(G,Q); //3:G+Q + let W4:EcPoint=ec_double{range_check_ptr=range_check_ptr}(G); //4:2G + let W5:EcPoint=ec_add{range_check_ptr=range_check_ptr}(G,W4); //5:3G + let W6:EcPoint=ec_add{range_check_ptr=range_check_ptr}(W4,Q); //6:2G+Q + let W7:EcPoint=ec_add{range_check_ptr=range_check_ptr}(W5,Q); //7:3G+Q + let W8:EcPoint=ec_double{range_check_ptr=range_check_ptr}(Q); //8:2Q + + let W9:EcPoint=ec_add{range_check_ptr=range_check_ptr}(W8,G); //9:2Q+G + let W10:EcPoint=ec_add{range_check_ptr=range_check_ptr}(W8,Q); //10:3Q + let W11:EcPoint=ec_add{range_check_ptr=range_check_ptr}(W10,G); //11:3Q+G + let W12:EcPoint=ec_add{range_check_ptr=range_check_ptr}(W8,W4); //12:2Q+2G + let W13:EcPoint=ec_add{range_check_ptr=range_check_ptr}(W8,W5); //13:2Q+3G + let W14:EcPoint=ec_add{range_check_ptr=range_check_ptr}(W10,W4); //14:3Q+2G + let W15:EcPoint=ec_add{range_check_ptr=range_check_ptr}(W10,W5); //15:3Q+3G + + let PrecPoint:Window=Window( G,Q,W3, W4, W5, W6, W7, W8, W9, W10, W11, W12, W13, W14, W15); + + //[ap]=0, ap++; + + //let test:EcPoint=ec_add{range_check_ptr=range_check_ptr}(Window_Points[0],Window_Points[1]); //15:3Q+3G + + //recover MSB bit index + %{ ids.m=max(ids.scalar_u.bit_length(), ids.scalar_v.bit_length())-1 %} + %{ print("\n window scalar length=", ids.m) %} + //initialize R with infinity point + let R = EcPoint(BigInt3(0, 0, 0), BigInt3(0, 0, 0)); + + let (resu:EcPoint)=ec_mulmuladd_W_inner(R, PrecPoint, scalar_u, scalar_v, m); + + + return (res=resu); +} + + +//https://crypto.stackexchange.com/questions/99975/strauss-shamir-trick-on-ec-multiplication-by-scalar +func ec_mulmuladd{range_check_ptr}(G: EcPoint, Q: EcPoint, scalar_u: felt, scalar_v: felt) -> (res: EcPoint){ + + alloc_locals; + local m; + //Precompute H=P+Q + let H:EcPoint=ec_add{range_check_ptr=range_check_ptr}(G,Q); + //recover MSB bit index + %{ ids.m=max(ids.scalar_u.bit_length(), ids.scalar_v.bit_length())-1 %} + //%{ print("\n length=", ids.m) %} + + //initialize R with infinity point + let R = EcPoint(BigInt3(0, 0, 0), BigInt3(0, 0, 0)); + let (resu:EcPoint)=ec_mulmuladd_inner(R,G,Q,H, scalar_u, scalar_v, m); + + return (res=resu); + +} + + + +//non optimized version of uG+vQ +func ec_mulmuladd_naive{range_check_ptr}(G: EcPoint, Q: EcPoint, scalar_u: BigInt3, scalar_v: BigInt3) -> (res: EcPoint){ + alloc_locals; + + let uG:EcPoint=ec_mul(G,scalar_u); + let vQ:EcPoint=ec_mul(Q,scalar_v); + let res:EcPoint=ec_add(uG,vQ); + return (res=res); + +} + + + + + diff --git a/src/ec_mulmuladd_secp256r1.cairo b/src/ec_mulmuladd_secp256r1.cairo new file mode 100644 index 0000000..94f8c8f --- /dev/null +++ b/src/ec_mulmuladd_secp256r1.cairo @@ -0,0 +1,122 @@ +//*************************************************************************************/ +///* Copyright (C) 2022 - Renaud Dubois - This file is part of Cairo_musig2 project */ +///* License: This software is licensed under a dual BSD and GPL v2 license. */ +///* See LICENSE file at the root folder of the project. */ +///* FILE: multipoint.cairo */ +///* */ +///* */ +///* DESCRIPTION: optimization of dual base multiplication*/ +///* the algorithm combines the so called Shamir's trick with Windowing method */ +//**************************************************************************************/ + +//Shamir's trick:https://crypto.stackexchange.com/questions/99975/strauss-shamir-trick-on-ec-multiplication-by-scalar, +//Windowing method : https://en.wikipedia.org/wiki/Exponentiation_by_squaring, section 'sliding window' +//The implementation use a 2 bits window with trick, leading to a 16 points elliptic point precomputation + + +from starkware.cairo.common.cairo_builtins import EcOpBuiltin +from starkware.cairo.common.registers import get_ap +from starkware.cairo.common.registers import get_fp_and_pc + +from starkware.cairo.common.uint256 import Uint256 + +from starkware.cairo.common.math_cmp import is_nn_le + +from starkware.cairo.common.cairo_secp.bigint import BigInt3, UnreducedBigInt3, nondet_bigint3 +from starkware.cairo.common.cairo_secp.field import ( + is_zero, + unreduced_mul, + unreduced_sqr, + verify_zero, +) +from starkware.cairo.common.cairo_secp.constants import BETA, N0, N1, N2 +from src.ec import EcPoint, ec_add, ec_mul, ec_double +from src.ec_mulmuladd import ec_mulmuladd_inner, ec_mulmuladd_W_inner, Window + + + + + +func ec_mulmuladd_bg3{range_check_ptr}(G: EcPoint, Q: EcPoint, scalar_u: BigInt3, scalar_v: BigInt3) -> (res: EcPoint){ + + alloc_locals; + local len_hi; + local len_med; + local len_low; + + //Precompute H=P+Q + let H:EcPoint=ec_add{range_check_ptr=range_check_ptr}(G,Q); + + //initialize R with infinity point + let R = EcPoint(BigInt3(0, 0, 0), BigInt3(0, 0, 0)); + + //recover MSB bit index of high part + %{ ids.len_hi=max(ids.scalar_u.d2.bit_length(), ids.scalar_v.d2.bit_length())-1 %} + //%{ print("\n length=", ids.len_hi) %} + let (hiR:EcPoint)=ec_mulmuladd_inner(R,G,Q,H, scalar_u.d2, scalar_v.d2, len_hi); + + //recover MSB bit index of med part + %{ ids.len_med=max(ids.scalar_u.d1.bit_length(), ids.scalar_v.d1.bit_length())-1 %} + //%{ print("\n length=", ids.len_med) %} + let (medR:EcPoint)=ec_mulmuladd_inner(hiR,G,Q,H, scalar_u.d1, scalar_v.d1, len_med); + + //recover MSB bit index of low part + %{ ids.len_low=max(ids.scalar_u.d0.bit_length(), ids.scalar_v.d0.bit_length())-1 %} + //%{ print("\n length=", ids.len_low) %} + + let (lowR:EcPoint)=ec_mulmuladd_inner(medR,G,Q,H, scalar_u.d0, scalar_v.d0, len_low); + + return (res=lowR); +} + + +func ec_mulmuladdW_bg3{range_check_ptr}(G: EcPoint, Q: EcPoint, scalar_u: BigInt3, scalar_v: BigInt3) -> (res: EcPoint){ + alloc_locals; + local len_hi; //hi 84 bits part of scalar + local len_med; //med 86 bits part + local len_low;//low bits part + + //Precompute a 4-bit window , W0=infty, W1=P, W2=Q, the window is indexed by (8*v1 4*u1+ 2*v0 + u0), where (u1,u0) represents two bit of scalar u, (resp for v) + + let W3:EcPoint=ec_add{range_check_ptr=range_check_ptr}(G,Q); //3:G+Q + let W4:EcPoint=ec_double{range_check_ptr=range_check_ptr}(G); //4:2G + let W5:EcPoint=ec_add{range_check_ptr=range_check_ptr}(G,W4); //5:3G + let W6:EcPoint=ec_add{range_check_ptr=range_check_ptr}(W4,Q); //6:2G+Q + let W7:EcPoint=ec_add{range_check_ptr=range_check_ptr}(W5,Q); //7:3G+Q + let W8:EcPoint=ec_double{range_check_ptr=range_check_ptr}(Q); //8:2Q + + let W9:EcPoint=ec_add{range_check_ptr=range_check_ptr}(W8,G); //9:2Q+G + let W10:EcPoint=ec_add{range_check_ptr=range_check_ptr}(W8,Q); //10:3Q + let W11:EcPoint=ec_add{range_check_ptr=range_check_ptr}(W10,G); //11:3Q+G + let W12:EcPoint=ec_add{range_check_ptr=range_check_ptr}(W8,W4); //12:2Q+2G + let W13:EcPoint=ec_add{range_check_ptr=range_check_ptr}(W8,W5); //13:2Q+3G + let W14:EcPoint=ec_add{range_check_ptr=range_check_ptr}(W10,W4); //14:3Q+2G + let W15:EcPoint=ec_add{range_check_ptr=range_check_ptr}(W10,W5); //15:3Q+3G + + let PrecPoint:Window=Window( G,Q,W3, W4, W5, W6, W7, W8, W9, W10, W11, W12, W13, W14, W15); + + + //initialize R with infinity point + let R = EcPoint(BigInt3(0, 0, 0), BigInt3(0, 0, 0)); + + %{ ids.len_hi=max(ids.scalar_u.d2.bit_length(), ids.scalar_v.d2.bit_length())-1 %} + //%{ print("\n length=", ids.len_hi) %} + + let (hiR:EcPoint)=ec_mulmuladd_W_inner(R, PrecPoint, scalar_u.d2, scalar_v.d2, len_hi); + + let (medR:EcPoint)=ec_mulmuladd_W_inner(hiR, PrecPoint, scalar_u.d1, scalar_v.d1, 85); + + let (lowR:EcPoint)=ec_mulmuladd_W_inner(medR, PrecPoint, scalar_u.d0, scalar_v.d0, 85); + + + return (res=lowR); + + +} + + + + + + + diff --git a/src/ecdsa_opti.cairo b/src/ecdsa_opti.cairo new file mode 100644 index 0000000..2dba187 --- /dev/null +++ b/src/ecdsa_opti.cairo @@ -0,0 +1,103 @@ +// From: https://github.com/EulerSmile/common-ec-cairo + +from starkware.cairo.common.math import assert_nn_le, assert_not_zero +from starkware.cairo.common.cairo_secp.bigint import BigInt3, UnreducedBigInt3, UnreducedBigInt5 +from starkware.cairo.common.cairo_secp.constants import BASE +from starkware.cairo.common.cairo_secp.ec import EcPoint + +from src.bigint import bigint_div_mod +from src.param_def import N0, N1, N2, GX0, GX1, GX2, GY0, GY1, GY2 +from src.ec import ec_add, ec_mul, verify_point +from src.ec_mulmuladd_secp256r1 import ec_mulmuladdW_bg3 + +// Verifies that val is in the range [1, N) and that the limbs of val are in the range [0, BASE). +// Taken from: https://github.com/starkware-libs/cairo-lang/blob/master/src/starkware/cairo/common/cairo_secp/signature.cairo#L85 +func validate_signature_entry{range_check_ptr}(val: BigInt3) { + assert_nn_le(val.d2, N2); + assert_nn_le(val.d1, BASE - 1); + assert_nn_le(val.d0, BASE - 1); + + if (val.d2 == N2) { + if (val.d1 == N1) { + assert_nn_le(val.d0, N0 - 1); + return (); + } + assert_nn_le(val.d1, N1 - 1); + return (); + } + + // Check that val > 0. + if (val.d2 == 0) { + if (val.d1 == 0) { + assert_not_zero(val.d0); + return (); + } + } + return (); +} + +// Verifies a ECDSA signature. +// Soundness assumptions: +// * All the limbs of public_key_pt.x, public_key_pt.y, msg_hash are in the range [0, 3 * BASE). +func verify_ecdsa_opti{range_check_ptr}( + public_key_pt: EcPoint, msg_hash: BigInt3, r: BigInt3, s: BigInt3 +) { + alloc_locals; + verify_point(public_key_pt); + + with_attr error_message("Signature out of range.") { + validate_signature_entry(r); + validate_signature_entry(s); + } + + let gen_pt = EcPoint(BigInt3(GX0, GX1, GX2), BigInt3(GY0, GY1, GY2)); + + let N = BigInt3(N0, N1, N2); + // Compute u1 and u2. + let (u1: BigInt3) = bigint_div_mod( + UnreducedBigInt5( + d0=msg_hash.d0, + d1=msg_hash.d1, + d2=msg_hash.d2, + d3=0, + d4=0 + ), + UnreducedBigInt3( + d0=s.d0, + d1=s.d1, + d2=s.d2 + ), + N, + ); + + let (u2: BigInt3) = bigint_div_mod( + UnreducedBigInt5( + d0=r.d0, + d1=r.d1, + d2=r.d2, + d3=0, + d4=0 + ), + UnreducedBigInt3( + d0=s.d0, + d1=s.d1, + d2=s.d2 + ), + N, + ); + //using ec_mulmuladd to optimize time and cells usage + // let (gen_u1) = ec_mul(gen_pt, u1); + // let (pub_u2) = ec_mul(public_key_pt, u2); + // let (res) = ec_add(gen_u1, pub_u2); + let (res:EcPoint) =ec_mulmuladdW_bg3(gen_pt, public_key_pt, u1, u2); + + //let computed=res.x.d0; + //let expected=r.d0; + + //%{ print("\n computed=",ids.computed, "expected=",ids.expected) %}//result of signature + + // The following assert also implies that res is not the zero point. + assert res.x = r; + + return (); +} diff --git a/tests/test_bench_ecdsa.cairo b/tests/test_bench_ecdsa.cairo new file mode 100644 index 0000000..f32a0fb --- /dev/null +++ b/tests/test_bench_ecdsa.cairo @@ -0,0 +1,67 @@ +//*************************************************************************************/ +///* Copyright (C) 2022 - Renaud Dubois - This file is part of Cairo_musig2 project */ +///* License: This software is licensed under a dual BSD and GPL v2 license. */ +///* See LICENSE file at the root folder of the project. */ +///* FILE: test_ecdsa_opti.cairo */ +///* */ +///* */ +///* DESCRIPTION: testing file for ecdsa speed up with mulmuladd over sec256r1 curve */ +//**************************************************************************************/ + +//Shamir's trick:https://crypto.stackexchange.com/questions/99975/strauss-shamir-trick-on-ec-multiplication-by-scalar, +//Windowing method : https://en.wikipedia.org/wiki/Exponentiation_by_squaring, section 'sliding window' +//The implementation use a 2 bits window with trick, leading to a 16 points elliptic point precomputation + +%builtins range_check + +from starkware.cairo.common.cairo_builtins import EcOpBuiltin +from starkware.cairo.common.registers import get_ap +from starkware.cairo.common.registers import get_fp_and_pc +from starkware.cairo.common.uint256 import Uint256 +from starkware.cairo.common.math_cmp import is_nn_le +from starkware.cairo.common.cairo_secp.bigint import BigInt3, UnreducedBigInt3, nondet_bigint3 +from starkware.cairo.common.cairo_secp.field import ( + is_zero, + unreduced_mul, + unreduced_sqr, + verify_zero, +) + +from src.ec import EcPoint, ec_add, ec_mul, ec_double + +from src.param_def import N0, N1, N2, GX0, GX1, GX2, GY0, GY1, GY2 +from src.ec_mulmuladd import ec_mulmuladd_W, ec_mulmuladd, ec_mulmuladd_naive +from src.ec_mulmuladd_secp256r1 import ec_mulmuladdW_bg3 + +from src.ecdsa import verify_ecdsa + + +func test_verify_ecdsa{range_check_ptr}() { + let public_key_pt = EcPoint( + BigInt3(0x3fb12f3c59ff46c271bf83, 0x3e89236e3f334d5977a52e, 0x1ccbe91c075fc7f4f033b), + BigInt3(0x4e78dc7ccd5ca89a4ca9, 0x2cb039844f81b6df2a4edd, 0xce4014c68811f9a21a1fd), + ); + let r = BigInt3(0x155a7acabb5e6f79c8c2ac, 0xf598a549fb4abf5ac7da9, 0xf3ac8061b514795b8843e); + let s = BigInt3(0x2f175a3ccdda2acc058903, 0x1898afdcdc73be5ec863a5, 0x8bf77819ca05a6b2786c7); + let msg_hash = BigInt3( + 0x100377dbc4e7a6a133ec56, 0x25c813f825413878bbec6a, 0x44acf6b7e36c1342c2c58 + ); + verify_ecdsa(public_key_pt=public_key_pt, msg_hash=msg_hash, r=r, s=s); + return (); +} + + +//////////// MAIN +func main{ range_check_ptr}() { + alloc_locals; + let (__fp__, _) = get_fp_and_pc(); + + + %{ print("\n ECDSA standard implementation over sec256r1") %}//result of signature + + + test_verify_ecdsa(); + + + return(); +} diff --git a/tests/test_bench_ecdsa_opti.cairo b/tests/test_bench_ecdsa_opti.cairo new file mode 100644 index 0000000..7955c1c --- /dev/null +++ b/tests/test_bench_ecdsa_opti.cairo @@ -0,0 +1,67 @@ +//*************************************************************************************/ +///* Copyright (C) 2022 - Renaud Dubois - This file is part of Cairo_musig2 project */ +///* License: This software is licensed under a dual BSD and GPL v2 license. */ +///* See LICENSE file at the root folder of the project. */ +///* FILE: test_ecdsa_opti.cairo */ +///* */ +///* */ +///* DESCRIPTION: testing file for ecdsa speed up with mulmuladd over sec256r1 curve */ +//**************************************************************************************/ + +//Shamir's trick:https://crypto.stackexchange.com/questions/99975/strauss-shamir-trick-on-ec-multiplication-by-scalar, +//Windowing method : https://en.wikipedia.org/wiki/Exponentiation_by_squaring, section 'sliding window' +//The implementation use a 2 bits window with trick, leading to a 16 points elliptic point precomputation + +%builtins range_check + +from starkware.cairo.common.cairo_builtins import EcOpBuiltin +from starkware.cairo.common.registers import get_ap +from starkware.cairo.common.registers import get_fp_and_pc +from starkware.cairo.common.uint256 import Uint256 +from starkware.cairo.common.math_cmp import is_nn_le +from starkware.cairo.common.cairo_secp.bigint import BigInt3, UnreducedBigInt3, nondet_bigint3 +from starkware.cairo.common.cairo_secp.field import ( + is_zero, + unreduced_mul, + unreduced_sqr, + verify_zero, +) + +from src.ec import EcPoint, ec_add, ec_mul, ec_double + +from src.param_def import N0, N1, N2, GX0, GX1, GX2, GY0, GY1, GY2 +from src.ec_mulmuladd import ec_mulmuladd_W, ec_mulmuladd, ec_mulmuladd_naive +from src.ec_mulmuladd_secp256r1 import ec_mulmuladdW_bg3 +from src.ecdsa_opti import verify_ecdsa_opti + + + +func test_verify_ecdsa_opti{range_check_ptr}() { + let public_key_pt = EcPoint( + BigInt3(0x3fb12f3c59ff46c271bf83, 0x3e89236e3f334d5977a52e, 0x1ccbe91c075fc7f4f033b), + BigInt3(0x4e78dc7ccd5ca89a4ca9, 0x2cb039844f81b6df2a4edd, 0xce4014c68811f9a21a1fd), + ); + let r = BigInt3(0x155a7acabb5e6f79c8c2ac, 0xf598a549fb4abf5ac7da9, 0xf3ac8061b514795b8843e); + let s = BigInt3(0x2f175a3ccdda2acc058903, 0x1898afdcdc73be5ec863a5, 0x8bf77819ca05a6b2786c7); + let msg_hash = BigInt3( + 0x100377dbc4e7a6a133ec56, 0x25c813f825413878bbec6a, 0x44acf6b7e36c1342c2c58 + ); + verify_ecdsa_opti(public_key_pt=public_key_pt, msg_hash=msg_hash, r=r, s=s); + return (); +} + + +//////////// MAIN +func main{ range_check_ptr}() { + alloc_locals; + let (__fp__, _) = get_fp_and_pc(); + + + %{ print("\n ECDSA optimized over sec256r1") %}//result of signature + + + test_verify_ecdsa_opti(); + + + return(); +} diff --git a/tests/test_ec_mulmuladd_secp256r1.cairo b/tests/test_ec_mulmuladd_secp256r1.cairo new file mode 100644 index 0000000..dfd9296 --- /dev/null +++ b/tests/test_ec_mulmuladd_secp256r1.cairo @@ -0,0 +1,245 @@ +//*************************************************************************************/ +///* Copyright (C) 2022 - Renaud Dubois - This file is part of Cairo_musig2 project */ +///* License: This software is licensed under a dual BSD and GPL v2 license. */ +///* See LICENSE file at the root folder of the project. */ +///* FILE: test_multipoint.cairo */ +///* */ +///* */ +///* DESCRIPTION: testing file for ec_mulmuladd over sec256k1 curve */ +//**************************************************************************************/ + +//Shamir's trick:https://crypto.stackexchange.com/questions/99975/strauss-shamir-trick-on-ec-multiplication-by-scalar, +//Windowing method : https://en.wikipedia.org/wiki/Exponentiation_by_squaring, section 'sliding window' +//The implementation use a 2 bits window with trick, leading to a 16 points elliptic point precomputation + +%builtins range_check + +from starkware.cairo.common.cairo_builtins import EcOpBuiltin +from starkware.cairo.common.registers import get_ap +from starkware.cairo.common.registers import get_fp_and_pc +from starkware.cairo.common.uint256 import Uint256 +from starkware.cairo.common.math_cmp import is_nn_le +from starkware.cairo.common.cairo_secp.bigint import BigInt3, UnreducedBigInt3, nondet_bigint3 +from starkware.cairo.common.cairo_secp.field import ( + is_zero, + unreduced_mul, + unreduced_sqr, + verify_zero, +) + +from src.ec import EcPoint, ec_add, ec_mul, ec_double + +from src.param_def import N0, N1, N2, GX0, GX1, GX2, GY0, GY1, GY2 +from src.ec_mulmuladd import ec_mulmuladd_W, ec_mulmuladd, ec_mulmuladd_naive +from src.ec_mulmuladd_secp256r1 import ec_mulmuladdW_bg3 + + + +func test_ecmulmuladd{range_check_ptr }()->(res:felt){ + %{ print("\n******************* Unitary Test 1: test mulmuladd (Shamir) on single precision scalar") %} + let G=EcPoint(BigInt3(GX0, GX1, GX2), BigInt3(GY0, GY1, GY2)); + + + let Q:EcPoint=ec_double(G); + + let scal_3=3; + let scal_31=31; + let m1=-1; + + //compute 3G+31Q= 65G + let computed:EcPoint=ec_mulmuladd( G, Q, scal_3, scal_31); + let compX=computed.x.d0; + %{ print("\n Computed x=", ids.compX) %} + + let soixantecinq=BigInt3(0x41, 0x0, 0x0); + + let expected:EcPoint=ec_mul(G, soixantecinq); + let expX=expected.x.d0; + + + %{ print("\n Expected x=", ids.expX) %} + return (res=1); +} + + +func test_ecmulmuladdW{range_check_ptr }()->(res:felt){ + alloc_locals; + %{ print("\n******************* Unitary Test 2: test mulmuladd (windowed Shamir version) on single precision scalar") %} + let G=EcPoint(BigInt3(GX0, GX1, GX2), BigInt3(GY0, GY1, GY2)); + + + + let Q:EcPoint=ec_double(G); + + let scal_3=3; + let scal_31=31; + let m1=-1; + + //compute 3G+31Q= 65G + let computed:EcPoint=ec_mulmuladd_W( G, Q, scal_3, scal_31); + let compX=computed.x.d0; + %{ print("\n Computed x=", ids.compX) %} + io_printPoint(computed); + + let soixantecinq=BigInt3(0x41, 0x0, 0x0); + + let expected:EcPoint=ec_mul(G, soixantecinq); + let expX=expected.x.d0; + + + %{ print("\n Expected x=", ids.expX) %} + io_printPoint(expected); + + let cmp:felt=ec_test_eq(expected, computed); + %{ print("\n Is Expected =Computed :", ids.cmp) %} + + + return (res=cmp); +} + +//print in hexadecimal, aligned on 128 bits (easier debug) +func io_printBigInt3{range_check_ptr }(bg3_a: BigInt3){ + + //let low=bg3_a.d0+((bg3_a.d1&0xffffffff)<<86); + //let hi=(bg3_a.d1>>(86-32))+(bg3_a.d2<<(86-32)) + %{ print("\n ", hex(ids.bg3_a.d0+((ids.bg3_a.d1&0x3ffffffffff)<<86)),hex((ids.bg3_a.d1>>(42))+(ids.bg3_a.d2<<(44)))) %} + + return(); +} + +func io_printPoint{range_check_ptr }(ec_G: EcPoint){ + %{ print("\n x:") %} + io_printBigInt3(ec_G.x); + %{ print("\n y:") %} + + io_printBigInt3(ec_G.y); + + return(); +} + +func bg3_test_eq{range_check_ptr }( bg3_a:BigInt3, bg3_b:BigInt3)->(res:felt){ + + if(bg3_a.d0!=bg3_b.d0){ + let res=0; + return (res=res); + } + if(bg3_a.d1!=bg3_b.d1){ + let res=1; + return (res=res); + } + if(bg3_a.d2!=bg3_b.d2){ + let res=1; + return (res=res); + } + + + + let res=1; + return (res=res); +} + +func ec_test_eq{range_check_ptr }(ec_G: EcPoint, ec_Q: EcPoint)->(res:felt){ + + let testx:felt=bg3_test_eq(ec_G.x,ec_Q.x); + if(testx==0){ + return (res=testx); + } + + let testy:felt=bg3_test_eq(ec_G.y,ec_Q.y); + if(testy==0){ + return (res=testy); + } + let res=1; + + + return (res=res); +} + +func test_naive{range_check_ptr }(){ + %{ print("\n******************* Unitary Test 0: test mulmuladd naive and IO functions") %} + alloc_locals; +//* parameters for 256k1: +//https://en.bitcoin.it/wiki/Secp256k1 +//order=115792089237316195423570985008687907852837564279074904382605163141518161494337 +//low=hex(n&(2^86-1)), med=hex((n>>86)&(2^86-1)), hi=hex((n>>(2*86))&(2^84-1)) +//0x8a03bbfd25e8cd0364141 , 0x3ffffffffffaeabb739abd, 0xfffffffffffffffffffff +//int(low,16)+(int(med,16)<<86)+(int(hi,16)<<2*86) + + + let G=EcPoint(BigInt3(GX0, GX1, GX2), BigInt3(GY0, GY1, GY2)); + + io_printPoint(G); + + let Q:EcPoint=ec_double(G); + + + +//u=N-1, vP=-P +let scalar_u=BigInt3(0x179e84f3b9cac2fc632550 , 0x3ffffffffffef39beab69c, 0xffffffff00000000fffff); + +//v=N+1, (N+1)Q=2G +let scalar_v=BigInt3(0x179e84f3b9cac2fc632552 , 0x3ffffffffffef39beab69c, 0xffffffff00000000fffff); + + //(qG)+(q-2)*G shall be equal to P using Fermat theorem + let res:EcPoint=ec_mulmuladd_naive(G,Q,scalar_u, scalar_v); + + + io_printPoint(res); + + let cmp:felt=ec_test_eq(res, G); + + + %{ print("\n cmp =", ids.cmp) %} + return(); +} + + +func test_full_windowed{range_check_ptr }(){ + %{ print("\n******************* Unitary Test 3: test windowed sharmir's trick mulmuladd :") %} + + + let G=EcPoint(BigInt3(GX0, GX1, GX2), BigInt3(GY0, GY1, GY2)); + + io_printPoint(G); + + let Q:EcPoint=ec_double(G); + + +//u=N-1, vP=-P +let scalar_u=BigInt3(0x179e84f3b9cac2fc632550 , 0x3ffffffffffef39beab69c, 0xffffffff00000000fffff); + +//v=N+1, (N+1)Q=2G +let scalar_v=BigInt3(0x179e84f3b9cac2fc632552 , 0x3ffffffffffef39beab69c, 0xffffffff00000000fffff); + + //(N-1)G+(N+1)*G shall be equal to P using Fermat theorem + let res:EcPoint=ec_mulmuladdW_bg3(G,Q,scalar_u, scalar_v); + + + io_printPoint(res); + + let cmp:felt=ec_test_eq(res, G); + + + %{ print("\n cmp =", ids.cmp) %} + return(); + } + + +//////////// MAIN +func main{range_check_ptr }() { + alloc_locals; + let (__fp__, _) = get_fp_and_pc(); + + + %{ print("\n*******************CAIRO:Shamir's trick+Windowing testing over sec256r1") %}//result of signature + + + test_naive(); + test_ecmulmuladd(); + test_ecmulmuladdW(); + test_full_windowed(); + + return(); +} + +