diff --git a/Nargo.toml b/Nargo.toml index e76034a..6dc8c25 100644 --- a/Nargo.toml +++ b/Nargo.toml @@ -1,9 +1,9 @@ [package] -name = "ecdh" -type = "bin" +name = "noir-ecdh" +type = "lib" authors = [""] -compiler_version = "0.10.5" +compiler_version = ">=0.18.0" # [dependencies] noir_bigint = { tag = "v0.1.0", git = "https://github.com/shuklaayush/noir-bigint" } -biguint = { tag = "v0.1.0", git = "https://github.com/shuklaayush/noir-bigint" } \ No newline at end of file +biguint = { tag = "v0.1.0", git = "https://github.com/shuklaayush/noir-bigint" } diff --git a/Prover.toml b/Prover.toml deleted file mode 100644 index e0a6817..0000000 --- a/Prover.toml +++ /dev/null @@ -1,2 +0,0 @@ -x = "" -y = "" diff --git a/README.md b/README.md index ae27a41..18b4d3c 100644 --- a/README.md +++ b/README.md @@ -1,85 +1,3 @@ -# noir ecdh +# noir-ecdh -## Curve Params - -### secp256k1 - -p=FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F -a=0000000000000000000000000000000000000000000000000000000000000000 -b=0000000000000000000000000000000000000000000000000000000000000007 -Gx=79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798 -Gy=483ADA7726A3C4655DA4FBFC0E1108A8FD17B448A68554199C47D08FFB10D4B8 -n=FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - -### secp256r1 (p256) - -p=FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFF -a=FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFC -b=5AC635D8AA3A93E7B3EBBD55769886BC651D06B0CC53B0F63BCE3C3E27D2604B -Gx=6B17D1F2E12C4247F8BCE6E563A440F277037D812DEB33A0F4A13945D898C296 -Gy=4FE342E2FE1A7F9B8EE7EB4A7C0F9E162BCE33576B315ECECBB6406837BF51F5 -n=FFFFFFFF00000000FFFFFFFFFFFFFFFFBCE6FAADA7179E84F3B9CAC2FC632551 - -## arithmetic - -r = p + q - -$$ - - \begin{gathered} - \lambda_{1}=\mathbf x_{1}\mathrm z_{2}^{2} \\ - \lambda_2=\operatorname{x}_2\operatorname{z}_1^{\overline{2}} \\ - \lambda_{3}=\lambda_{1}-\lambda_{2} \\ - \lambda_4=\mathbf{y}_1\mathbf{z}_2^3 \\ - \lambda_5=\mathbf{y}_2\mathbf{z}_1^3 \\ - \lambda_{6}=\lambda_{4}-\lambda_{5} \\ - \lambda_{7}=\lambda_{1}+\lambda_{2} \\ - \lambda_8=\lambda_4+\lambda_5 \\ - \mathrm{x}_3=\lambda_6^2-\lambda_7\lambda_3^2 \\ - \lambda_{9}=\lambda_{7}\lambda_{3}^{2}-2\mathrm{x}_{3} \\ - \mathbf{y}_{3}=(\lambda_{9}\lambda_{6}-\lambda_{8}\lambda_{3}^{3})/2 \\ - \mathrm{z}_3=\mathrm{z}_1\mathrm{z}_2\lambda_3 - \end{gathered} -$$ - -r = p * 2 - -$$ - \begin{gathered} - \lambda_1=3\text{x}_1^2+\text{az}_1^4 \\ - \lambda_{2}=4\mathrm{x}_{1}\mathrm{y}_{1}^{2} \\ - \lambda_3=8\mathrm{y}_1^4 \\ - \mathrm{x}_3=\lambda_1^2-2\lambda_2 \\ - \mathbf{y}_{3}=\lambda_{1}(\lambda_{2}-\mathbf{x}_{3})-\lambda_{3} \\ - \mathrm{z}_3=2\mathrm{y}_1\mathrm{z}_1 - \end{gathered} -$$ - -### ECDH - -$$ -\begin{gathered} -secret = pk_1 * sk_2 = pk_2 * sk_1 \\ - -pk_1 = sk_1 * G \\ -pk_2 = sk_2 * G \\ - -\to sk_1 * G * sk_2 = sk_2 * G * sk_1 \\ -\to pk_1 * sk_2 = pk_2 * sk_1 -\end{gathered} -$$ - -## Tools - -- -- -- -- - -### Calculator - -[params calculator using sympy](https://colab.research.google.com/drive/15VYBufqaPGM2HPbdd2D9xlm5zj_9ul-F?usp=sharing) - -## ref - -- +All credit belongs to @storswiftlabs (GitHub), this is merely adapted for use in my personal projects. diff --git a/Verifier.toml b/Verifier.toml deleted file mode 100644 index 13cf16b..0000000 --- a/Verifier.toml +++ /dev/null @@ -1 +0,0 @@ -y = "" diff --git a/src/main.nr b/src/ecdh.nr similarity index 53% rename from src/main.nr rename to src/ecdh.nr index d03b4b5..01de7f6 100644 --- a/src/main.nr +++ b/src/ecdh.nr @@ -1,12 +1,11 @@ use dep::std::println; mod ecdsa_secp256k1; -mod ecdsa_secp256r1; mod biguint; use ecdsa_secp256k1::fp::PrimeField as Fp; use ecdsa_secp256k1::fq::PrimeField as Fq; -use ecdsa_secp256k1::{secp256k1,Secp256k1}; +use ecdsa_secp256k1::{secp256k1, Secp256k1}; use ecdsa_secp256k1::swcurve::Point; @@ -17,32 +16,19 @@ fn main() { assert(p.is_zero()); } -// #[test] -// fn test_main() { -// main(1, 2); - -// // Uncomment to make test fail -// // main(1, 1); -// } - -fn generate_shared_secret(privkey:Fq ,pubkey:Point) -> Fp { - +fn generate_shared_secret(privkey: Fq ,pubkey: Point) -> Fp { let Secp256k1 { curve } = secp256k1(); - - let result = curve.mul(privkey,pubkey); - + let result = curve.mul(privkey, pubkey); let x = result.to_affine().0; + x } #[test] fn test_generate_shared_secret() { let privkey = Fq::one(); - let pubkey = Point::from_affine(Fp::one(),Fp::one()); + let pubkey = Point::from_affine(Fp::one(), Fp::one()); - let secret = generate_shared_secret(privkey,pubkey); - + let secret = generate_shared_secret(privkey, pubkey); println(secret.to_bytes()); - // Uncomment to make test fail - // main(1, 1); } diff --git a/src/ecdsa_secp256r1.nr b/src/ecdsa_secp256r1.nr deleted file mode 100644 index 93f9290..0000000 --- a/src/ecdsa_secp256r1.nr +++ /dev/null @@ -1,264 +0,0 @@ -use dep::std::println; - -mod fp; -mod fq; -mod swcurve; - -use fp::PrimeField as Fp; -use fq::PrimeField as Fq; -use swcurve::Point; -use swcurve::Curve; - -struct Secp256r1 { - curve: Curve, -} - -fn secp256r1() -> Secp256r1 { - Secp256r1 { - curve: Curve::new( - // a FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFC - Fp::from_limbs([0xfffffffffffffc, 0x0000ffffffffff, 0x00000000000000, 0x00000001000000, 0xffffffff]), - // b 5AC635D8AA3A93E7B3EBBD55769886BC651D06B0CC53B0F63BCE3C3E27D2604B - Fp::from_limbs([0xce3c3e27d2604b, 0x06b0cc53b0f63b, 0x55769886bc651d, 0xaa3a93e7b3ebbd, 0x5ac635d8]), - Point::from_affine( - // G_x 6B17D1F2E12C4247F8BCE6E563A440F277037D812DEB33A0F4A13945D898C296 - Fp::from_limbs( - [0xA13945D898C296,0x7D812DEB33A0F4,0xE563A440F27703,0xE12C4247F8BCE6,0x6B17D1F2] - ), - // G_y 4FE342E2FE1A7F9B8EE7EB4A7C0F9E162BCE33576B315ECECBB6406837BF51F5 - Fp::from_limbs( - [ 0xB6406837BF51F5,0x33576B315ECECB,0x4A7C0F9E162BCE,0xFE1A7F9B8EE7EB,0x4FE342E2 ] - ), - ), - ), - } -} - -fn verify_signature(pubkey: Point, sig_r: Fq, sig_s: Fq, msghash: Fq) -> bool { - let Secp256r1 { curve } = secp256r1(); - - assert(!pubkey.is_zero()); - assert(curve.contains(pubkey)); - - assert(!sig_r.is_zero()); - assert(!sig_s.is_zero()); - - let s_inv = sig_s.invert(); - let you1 = msghash.mul(s_inv); - let you2 = sig_r.mul(s_inv); - - let u1G = curve.mul(you1, curve.gen); - let u2A = curve.mul(you2, pubkey); - - let sum = curve.add(u1G, u2A); - - let x = sum.to_affine().0; - let xq = Fq::from_biguint56(x.to_biguint56()); - - sig_r.eq(xq) -} - -#[test] -fn test_secp256r1_zero() { - assert(Point::zero().is_zero()); -} - -#[test] -fn test_secp256r1_add1() { - let Secp256r1 { curve } = secp256r1(); - - let p = curve.add(Point::zero(), Point::zero()); - assert(p.is_zero()); -} - -#[test] -fn test_secp256r1_add2() { - let Secp256r1 { curve } = secp256r1(); - - let p = curve.add(curve.gen, Point::zero()); - assert(p.eq(curve.gen)); -} - -#[test] -fn test_secp256r1_add3() { - let Secp256r1 { curve } = secp256r1(); - - let p1 = curve.add(curve.gen, curve.gen); - let p2 = Point::from_affine( - Fp::from_bytes([ - 0xe5, 0x9e, 0x70, 0x5c, 0xb9, 0x09, 0xac, 0xab, - 0xa7, 0x3c, 0xef, 0x8c, 0x4b, 0x8e, 0x77, 0x5c, - 0xd8, 0x7c, 0xc0, 0x95, 0x6e, 0x40, 0x45, 0x30, - 0x6d, 0x7d, 0xed, 0x41, 0x94, 0x7f, 0x04, 0xc6 - ]), - Fp::from_bytes([ - 0x2a, 0xe5, 0xcf, 0x50, 0xa9, 0x31, 0x64, 0x23, - 0xe1, 0xd0, 0x66, 0x32, 0x65, 0x32, 0xf6, 0xf7, - 0xee, 0xea, 0x6c, 0x46, 0x19, 0x84, 0xc5, 0xa3, - 0x39, 0xc3, 0x3d, 0xa6, 0xfe, 0x68, 0xe1, 0x1a - ]), - ); - - assert(p1.eq(p2)); -} - -#[test] -fn test_secp256r1_add4() { - let Secp256r1 { curve } = secp256r1(); - - let p1 = curve.add(curve.double(curve.gen), curve.gen); - let p2 = Point::from_affine( - Fp::from_bytes([ - 0xf9, 0x36, 0xe0, 0xbc, 0x13, 0xf1, 0x01, 0x86, - 0xb0, 0x99, 0x6f, 0x83, 0x45, 0xc8, 0x31, 0xb5, - 0x29, 0x52, 0x9d, 0xf8, 0x85, 0x4f, 0x34, 0x49, - 0x10, 0xc3, 0x58, 0x92, 0x01, 0x8a, 0x30, 0xf9 - ]), - Fp::from_bytes([ - 0x72, 0xe6, 0xb8, 0x84, 0x75, 0xfd, 0xb9, 0x6c, - 0x1b, 0x23, 0xc2, 0x34, 0x99, 0xa9, 0x00, 0x65, - 0x56, 0xf3, 0x37, 0x2a, 0xe6, 0x37, 0xe3, 0x0f, - 0x14, 0xe8, 0x2d, 0x63, 0x0f, 0x7b, 0x8f, 0x38 - ]), - ); - assert(p1.eq(p2)); -} - -#[test] -fn test_secp256r1_double1() { - let Secp256r1 { curve } = secp256r1(); - - let p = curve.double(Point::zero()); - assert(p.is_zero()); -} - -#[test] -fn test_secp256r1_double2() { - let Secp256r1 { curve } = secp256r1(); - - let p1 = curve.double(curve.gen); - let p2 = Point::from_affine( - Fp::from_bytes([ - 0xe5, 0x9e, 0x70, 0x5c, 0xb9, 0x09, 0xac, 0xab, - 0xa7, 0x3c, 0xef, 0x8c, 0x4b, 0x8e, 0x77, 0x5c, - 0xd8, 0x7c, 0xc0, 0x95, 0x6e, 0x40, 0x45, 0x30, - 0x6d, 0x7d, 0xed, 0x41, 0x94, 0x7f, 0x04, 0xc6 - ]), - Fp::from_bytes([ - 0x2a, 0xe5, 0xcf, 0x50, 0xa9, 0x31, 0x64, 0x23, - 0xe1, 0xd0, 0x66, 0x32, 0x65, 0x32, 0xf6, 0xf7, - 0xee, 0xea, 0x6c, 0x46, 0x19, 0x84, 0xc5, 0xa3, - 0x39, 0xc3, 0x3d, 0xa6, 0xfe, 0x68, 0xe1, 0x1a - ]), - ); - - assert(p1.eq(p2)); -} - -#[test] -fn test_secp256r1_mul1() { - let Secp256r1 { curve } = secp256r1(); - - let p = curve.mul(Fq::from_u56(2), Point::zero()); - assert(p.is_zero()); -} - -#[test] -fn test_secp256r1_mul2() { - let Secp256r1 { curve } = secp256r1(); - - let p = curve.mul(Fq::zero(), curve.gen); - assert(p.is_zero()); -} - -#[test] -fn test_secp256r1_mul3() { - let Secp256r1 { curve } = secp256r1(); - - let p = curve.mul(Fq::one(), curve.gen); - assert(p.eq(curve.gen)); -} - -#[test] -fn test_secp256r1_mul4() { - let Secp256r1 { curve } = secp256r1(); - - let p1 = curve.mul(Fq::from_u56(2), curve.gen); - let p2 = Point::from_affine( - Fp::from_bytes([ - 0xe5, 0x9e, 0x70, 0x5c, 0xb9, 0x09, 0xac, 0xab, - 0xa7, 0x3c, 0xef, 0x8c, 0x4b, 0x8e, 0x77, 0x5c, - 0xd8, 0x7c, 0xc0, 0x95, 0x6e, 0x40, 0x45, 0x30, - 0x6d, 0x7d, 0xed, 0x41, 0x94, 0x7f, 0x04, 0xc6 - ]), - Fp::from_bytes([ - 0x2a, 0xe5, 0xcf, 0x50, 0xa9, 0x31, 0x64, 0x23, - 0xe1, 0xd0, 0x66, 0x32, 0x65, 0x32, 0xf6, 0xf7, - 0xee, 0xea, 0x6c, 0x46, 0x19, 0x84, 0xc5, 0xa3, - 0x39, 0xc3, 0x3d, 0xa6, 0xfe, 0x68, 0xe1, 0x1a - ]), - ); - - assert(p1.eq(p2)); -} - -#[test] -fn test_secp256r1_mul5() { - let Secp256r1 { curve } = secp256r1(); - - let p1 = curve.mul(Fq::from_u56(3), curve.gen); - let p2 = Point::from_affine( - Fp::from_bytes([ - 0xf9, 0x36, 0xe0, 0xbc, 0x13, 0xf1, 0x01, 0x86, - 0xb0, 0x99, 0x6f, 0x83, 0x45, 0xc8, 0x31, 0xb5, - 0x29, 0x52, 0x9d, 0xf8, 0x85, 0x4f, 0x34, 0x49, - 0x10, 0xc3, 0x58, 0x92, 0x01, 0x8a, 0x30, 0xf9 - ]), - Fp::from_bytes([ - 0x72, 0xe6, 0xb8, 0x84, 0x75, 0xfd, 0xb9, 0x6c, - 0x1b, 0x23, 0xc2, 0x34, 0x99, 0xa9, 0x00, 0x65, - 0x56, 0xf3, 0x37, 0x2a, 0xe6, 0x37, 0xe3, 0x0f, - 0x14, 0xe8, 0x2d, 0x63, 0x0f, 0x7b, 0x8f, 0x38 - ]), - ); - - assert(p1.eq(p2)); -} - -#[test] -fn test_secp256r1_verification_preshashed() { - let pubkey = Point::from_affine( - Fp::from_bytes([ - 0xc7, 0x47, 0xe2, 0x47, 0x2a, 0x8e, 0xa6, 0x52, - 0xb7, 0xc2, 0x43, 0x19, 0x9b, 0xd4, 0x42, 0x34, - 0x5d, 0xae, 0xe6, 0x1a, 0x7b, 0x7c, 0x47, 0x35, - 0x62, 0xc8, 0xf3, 0x47, 0x9e, 0x4d, 0x43, 0xa0, - ]), - Fp::from_bytes([ - 0xd7, 0x68, 0x73, 0x03, 0x3b, 0xe5, 0xbe, 0x3c, - 0x59, 0xa1, 0x77, 0xd8, 0x2e, 0x4c, 0x79, 0x6f, - 0x69, 0x4c, 0xa2, 0x93, 0xe6, 0xc7, 0xb6, 0xa3, - 0x27, 0xbc, 0x19, 0x54, 0x42, 0xba, 0x3a, 0x89, - ]) - ); - let r = Fq::from_bytes([ - 0xfd, 0x54, 0xf4, 0x8d, 0x4e, 0x5a, 0xe5, 0x9a, - 0xdb, 0x61, 0x80, 0xc3, 0x98, 0x97, 0x8d, 0xad, - 0x2b, 0xaa, 0x31, 0x0e, 0x4a, 0x6f, 0x34, 0x70, - 0xc3, 0x7d, 0x42, 0xab, 0x80, 0x1c, 0x08, 0xe5, - ]); - let s = Fq::from_bytes([ - 0x55, 0xcd, 0x5f, 0x71, 0x9a, 0xe4, 0x61, 0x01, - 0x69, 0x69, 0xeb, 0xd6, 0x89, 0x0b, 0xbb, 0xec, - 0x80, 0xf4, 0x61, 0x1d, 0x93, 0xcc, 0x70, 0x87, - 0xb7, 0x71, 0x4e, 0x34, 0x94, 0x98, 0x11, 0x28, - ]); - let msghash = Fq::from_bytes([ - 0xe2, 0xc1, 0xc8, 0x3a, 0x63, 0xb4, 0x06, 0x68, - 0xda, 0xc2, 0xd9, 0x35, 0xd0, 0x49, 0x69, 0x47, - 0x35, 0x88, 0x35, 0x8d, 0x7e, 0xcd, 0x21, 0x1f, - 0x12, 0xd2, 0x5c, 0x3a, 0x12, 0xf4, 0x73, 0x3a, - ]); - - assert(verify_signature(pubkey, r, s, msghash)); -} \ No newline at end of file diff --git a/src/ecdsa_secp256r1/fp.nr b/src/ecdsa_secp256r1/fp.nr deleted file mode 100644 index 0e2f9b4..0000000 --- a/src/ecdsa_secp256r1/fp.nr +++ /dev/null @@ -1,249 +0,0 @@ -use dep::std::println; - -use crate::biguint::lib::BigUint56; -use crate::biguint::utils; -use crate::biguint::lib::{NUM_LIMBS, BITS_PER_LIMB, MAX_BITS, MAX_BYTES}; - -// Field element -struct PrimeField { - val: BigUint56 -} - -// 素数 p(曲线的模数) -impl PrimeField { - /////////////////////////////////////////////////////////////////////////// - // FIELD SPECIFIC CONSTANTS: Secp256k1 Fp - /////////////////////////////////////////////////////////////////////////// - - // Prime field modulus - fn modulus() -> Self { - // FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFF - let val = BigUint56 { limbs: [0xFFFFFFFFFFFFFF, 0x0000FFFFFFFFFF, 0x00000000000000, 0x00000001000000, 0xFFFFFFFF] }; - Self { val } - } - - // R = 2^{BITS_PER_LIMB*NUM_LIMBS} mod p - // = 2^280 mod p - fn R() -> Self { - let val = BigUint56 { limbs: [0x00000001000000, 0x00000000000000, 0xffffffffffff00, 0xfeffffffffffff, 0xffffff] }; - Self { val } - } - - // R^2 mod p - fn R2() -> Self { - let val = BigUint56 { limbs: [0x03000000050000, 0x00000000000000, 0xfffffbfffffffa , 0xfffafffffffeff, 0x02ffff] }; - Self { val } - } - - // INV = -p^{-1} mod 2^{BITS_PER_LIMB} - // = -p^{-1} mod 2^56 - fn P_INV() -> u56 { - 0x01 - } - - //////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////// - - // TODO: Emphasize that there's no montgomery mul here. - fn from_limbs(limbs: [u56; NUM_LIMBS]) -> Self { - Self { val: BigUint56{ limbs } } - } - - fn from_u56(val: u56) -> Self { - let tmp = Self { val: BigUint56::from_u56(val) }; - - // Convert to Montgomery form by computing - // (a.R^0 * R^2) / R = a.R - tmp.mul(PrimeField::R2()) - } - - fn from_biguint56(val: BigUint56) -> Self { - let tmp = Self { val }; - - // Convert to Montgomery form by computing - // (a.R^0 * R^2) / R = a.R - tmp.mul(PrimeField::R2()) - } - - fn from_bytes(bytes: [u8]) -> Self { - let tmp = Self { val: BigUint56::from_bytes(bytes) }; - - // TODO: Do I need to check this? - // Check that tmp < p - let modulus = PrimeField::modulus(); - assert(tmp.val.lt(modulus.val)); - - // Convert to Montgomery form by computing - // (a.R^0 * R^2) / R = a.R - tmp.mul(PrimeField::R2()) - } - - fn to_biguint56(self: Self) -> BigUint56 { - // Turn into canonical form by computing - // (a.R) / R = a - let tmp = PrimeField::montgomery_reduce(self.val, BigUint56::zero()); - tmp.val - } - - // Converts a field element into a byte representation in - // little-endian byte order. - fn to_bytes(self: Self) -> [u8; MAX_BYTES] { - // Turn into canonical form by computing - // (a.R) / R = a - let tmp = PrimeField::montgomery_reduce(self.val, BigUint56::zero()); - tmp.val.to_bytes() - } - - // Converts a field element into a bit representation - fn to_bits(self: Self) -> [u1; MAX_BITS] { - // Turn into canonical form by computing - // (a.R) / R = a - let tmp = PrimeField::montgomery_reduce(self.val, BigUint56::zero()); - tmp.val.to_bits() - } - - // Returns zero, the additive identity. - fn zero() -> Self { - let val: BigUint56 = BigUint56::zero(); - Self { val } - } - - // Returns one, the multiplicative identity. - fn one() -> Self { - PrimeField::R() - } - - // Negates `self`. - fn neg(self: Self) -> Self { - if self.is_zero() { - self - } else { - // Subtract `self` from `MODULUS` to negate - let modulus = PrimeField::modulus().val; - Self { val: modulus.sub(self.val) } - } - } - - // Adds `rhs` to `self`, returning the result. - fn add(self: Self, rhs: Self) -> Self { - let (sum, carry) = self.val.adc(rhs.val); - - let modulus = PrimeField::modulus().val; - if ((carry == 0) & sum.lt(modulus)) { - Self { val: sum } - } else { - Self { val: sum.sub(modulus) } - } - } - - // Subtracts `rhs` from `self`, returning the result. - fn sub(self: Self, rhs: Self) -> Self { - let (diff, borrow) = self.val.sbb(rhs.val); - // If underflow occurred on the final limb, borrow = 0xfff...fff, otherwise - // borrow = 0x000...000. Thus, we use it as a mask to conditionally add the modulus. - if borrow == 0 { - Self { val: diff } - } else { - let modulus = PrimeField::modulus().val; - Self { val: diff.add(modulus) } - } - } - - // Doubles this field element. - fn double(self: Self) -> Self { - self.add(self) - } - - // Multiplies `rhs` by `self`, returning the result. - fn mul(self: Self, other: Self) -> Self { - let (lo, hi) = self.val.mul(other.val); - - PrimeField::montgomery_reduce(lo, hi) - } - - // Squares this element. - // TODO: See if more efficient squaring is possible. - fn square(self: Self) -> Self { - self.mul(self) - } - - fn montgomery_reduce(lo: BigUint56, hi: BigUint56) -> Self { - let mut tmp = [0 as u56; 2*NUM_LIMBS]; - for i in 0..NUM_LIMBS { - tmp[i] = lo.limbs[i]; - tmp[i + NUM_LIMBS] = hi.limbs[i]; - } - - let modulus = PrimeField::modulus().val; - - let mut carry2 = 0; - for i in 0..NUM_LIMBS { - let k = tmp[i] * PrimeField::P_INV(); - let mut carry = 0; - for j in 0..NUM_LIMBS { - let (prod, c) = utils::mac(tmp[i + j], k, modulus.limbs[j], carry); - tmp[i + j] = prod; - carry = c; - } - - let (sum, c) = utils::adc(tmp[i + NUM_LIMBS], carry2, carry); - tmp[i + NUM_LIMBS] = sum; - carry2 = c; - } - - let mut limbs = [0; NUM_LIMBS]; - for i in 0..NUM_LIMBS { - limbs[i] = tmp[i + NUM_LIMBS]; - } - - let val = BigUint56{ limbs }; - if val.gte(modulus) { - Self { val: val.sub(modulus) } - } else { - Self { val } - } - } - - // Exponentiates `self` by `by`. - // Double-and-add algorithm - fn pow(self: Self, by: BigUint56) -> Self { - let mut res = PrimeField::one(); - for i in 0..NUM_LIMBS { - for j in 0..BITS_PER_LIMB { - res = res.square(); - - if ((by.limbs[NUM_LIMBS - i - 1] >> ((BITS_PER_LIMB - j - 1) as u56)) & 1) == 1 { - res = res.mul(self); - } - } - } - res - } - - // Computes the multiplicative inverse of this element, - // failing if the element is zero. - fn invert(self: Self) -> Self { - assert(!self.is_zero()); - // Exponentiate by p - 2 - self.pow(PrimeField::modulus().val.sub(BigUint56{ limbs: [2, 0, 0, 0, 0] })) - } - - // Checks if the field element is zero. - fn is_zero(self: Self) -> bool { - self.val.is_zero() - } - - // Checks if self == other. - fn eq(self: Self, other: Self) -> bool { - self.val.eq(other.val) - } - - // Print as bytes - fn println(self: Self) { - let bytes = self.to_bytes(); - println(bytes); - } -} - -// TODO: -// 1. Dedup when traits \ No newline at end of file diff --git a/src/ecdsa_secp256r1/fq.nr b/src/ecdsa_secp256r1/fq.nr deleted file mode 100644 index caf05f4..0000000 --- a/src/ecdsa_secp256r1/fq.nr +++ /dev/null @@ -1,257 +0,0 @@ -use dep::std::println; - -use crate::biguint::lib::BigUint56; -use crate::biguint::utils; -use crate::biguint::lib::{NUM_LIMBS, BITS_PER_LIMB, MAX_BITS, MAX_BYTES}; - -// Field element -struct PrimeField { - val: BigUint56 -} - -// 曲线的阶 n -impl PrimeField { - /////////////////////////////////////////////////////////////////////////// - // FIELD SPECIFIC CONSTANTS: Secp256k1 Fq - /////////////////////////////////////////////////////////////////////////// - - // Prime field modulus - fn modulus() -> Self { - // FFFFFFFF00000000FFFFFFFFFFFFFFFFBCE6FAADA7179E84F3B9CAC2FC632551 - let val = BigUint56 { limbs: [0xB9CAC2FC632551, 0xFAADA7179E84F3, 0xFFFFFFFFFFBCE6, 0x00000000FFFFFF, 0xFFFFFFFF] }; - Self { val } - } - - // R = 2^{BITS_PER_LIMB*NUM_LIMBS} mod p - // = 2^280 mod p - fn R() -> Self { - let val = BigUint56 { limbs: [0x039cdaaf000000, 0xe8617b0c46353d, 0x00004319055258, 0xff000000000000, 0xffffff] }; - Self { val } - } - - // R^2 mod p - fn R2() -> Self { - let val = BigUint56 { limbs: [0x7fbc24cfb36926, 0xa0a7b8636a7aea, 0x9076ab51d14956, 0x84a3d0b1ec5961, 0x83b51c1e] }; - Self { val } - } - - // 2^56 = 0x100000000000000 (0x14) - // INV = -p^{-1} mod 2^{BITS_PER_LIMB} - // = -p^{-1} mod 2^56 - fn P_INV() -> u56 { - 0xd1c8aaee00bc4f - } - - /////////////////////////////////////////////////////////////////////////// - /////////////////////////////////////////////////////////////////////////// - - // TODO: Emphasize that there's no montgomery mul here. - fn from_limbs(limbs: [u56; NUM_LIMBS]) -> Self { - Self { val: BigUint56{ limbs } } - } - - fn from_u56(val: u56) -> Self { - let tmp = Self { val: BigUint56::from_u56(val) }; - - // Convert to Montgomery form by computing - // (a.R^0 * R^2) / R = a.R - tmp.mul(PrimeField::R2()) - } - - fn from_biguint56(val: BigUint56) -> Self { - let tmp = Self { val }; - - // Convert to Montgomery form by computing - // (a.R^0 * R^2) / R = a.R - tmp.mul(PrimeField::R2()) - } - - fn from_bytes(bytes: [u8]) -> Self { - let tmp = Self { val: BigUint56::from_bytes(bytes) }; - - // TODO: Do I need to check this? - // Check that tmp < p - let modulus = PrimeField::modulus(); - assert(tmp.val.lt(modulus.val)); - - // Convert to Montgomery form by computing - // (a.R^0 * R^2) / R = a.R - tmp.mul(PrimeField::R2()) - } - - fn to_biguint56(self: Self) -> BigUint56 { - // Turn into canonical form by computing - // (a.R) / R = a - let tmp = PrimeField::montgomery_reduce(self.val, BigUint56::zero()); - tmp.val - } - - // Converts a field element into a byte representation in - // little-endian byte order. - fn to_bytes(self: Self) -> [u8; MAX_BYTES] { - // Turn into canonical form by computing - // (a.R) / R = a - let tmp = PrimeField::montgomery_reduce(self.val, BigUint56::zero()); - tmp.val.to_bytes() - } - - // Converts a field element into a bit representation - fn to_bits(self: Self) -> [u1; MAX_BITS] { - // Turn into canonical form by computing - // (a.R) / R = a - let tmp = PrimeField::montgomery_reduce(self.val, BigUint56::zero()); - tmp.val.to_bits() - } - - // Returns zero, the additive identity. - fn zero() -> Self { - let val: BigUint56 = BigUint56::zero(); - Self { val } - } - - // Returns one, the multiplicative identity. - fn one() -> Self { - PrimeField::R() - } - - // Negates `self`. - fn neg(self: Self) -> Self { - if self.is_zero() { - self - } else { - // Subtract `self` from `MODULUS` to negate - let modulus = PrimeField::modulus().val; - Self { val: modulus.sub(self.val) } - } - } - - // Adds `rhs` to `self`, returning the result. - fn add(self: Self, rhs: Self) -> Self { - let (sum, carry) = self.val.adc(rhs.val); - - let modulus = PrimeField::modulus().val; - if ((carry == 0) & sum.lt(modulus)) { - Self { val: sum } - } else { - Self { val: sum.sub(modulus) } - } - } - - // Subtracts `rhs` from `self`, returning the result. - fn sub(self: Self, rhs: Self) -> Self { - let (diff, borrow) = self.val.sbb(rhs.val); - // If underflow occurred on the final limb, borrow = 0xfff...fff, otherwise - // borrow = 0x000...000. Thus, we use it as a mask to conditionally add the modulus. - if borrow == 0 { - Self { val: diff } - } else { - let modulus = PrimeField::modulus().val; - Self { val: diff.add(modulus) } - } - } - - // Doubles this field element. - fn double(self: Self) -> Self { - self.add(self) - } - - // Multiplies `rhs` by `self`, returning the result. - fn mul(self: Self, other: Self) -> Self { - let (lo, hi) = self.val.mul(other.val); - - PrimeField::montgomery_reduce(lo, hi) - } - - // Squares this element. - // TODO: See if more efficient squaring is possible. - fn square(self: Self) -> Self { - self.mul(self) - } - - fn montgomery_reduce(lo: BigUint56, hi: BigUint56) -> Self { - let mut tmp = [0 as u56; 2*NUM_LIMBS]; - for i in 0..NUM_LIMBS { - tmp[i] = lo.limbs[i]; - tmp[i + NUM_LIMBS] = hi.limbs[i]; - } - - let modulus = PrimeField::modulus().val; - - let mut carry2 = 0; - for i in 0..NUM_LIMBS { - let k = tmp[i] * PrimeField::P_INV(); - let mut carry = 0; - for j in 0..NUM_LIMBS { - let (prod, c) = utils::mac(tmp[i + j], k, modulus.limbs[j], carry); - tmp[i + j] = prod; - carry = c; - } - - let (sum, c) = utils::adc(tmp[i + NUM_LIMBS], carry2, carry); - tmp[i + NUM_LIMBS] = sum; - carry2 = c; - } - - let mut limbs = [0; NUM_LIMBS]; - for i in 0..NUM_LIMBS { - limbs[i] = tmp[i + NUM_LIMBS]; - } - - let val = BigUint56{ limbs }; - if val.gte(modulus) { - Self { val: val.sub(modulus) } - } else { - Self { val } - } - } - - // Exponentiates `self` by `by`. - // Double-and-add algorithm - fn pow(self: Self, by: BigUint56) -> Self { - let mut res = PrimeField::one(); - for i in 0..NUM_LIMBS { - for j in 0..BITS_PER_LIMB { - res = res.square(); - - if ((by.limbs[NUM_LIMBS - i - 1] >> ((BITS_PER_LIMB - j - 1) as u56)) & 1) == 1 { - res = res.mul(self); - } - } - } - res - } - - // Computes the multiplicative inverse of this element, - // failing if the element is zero. - fn invert(self: Self) -> Self { - assert(!self.is_zero()); - // Exponentiate by p - 2 - self.pow(PrimeField::modulus().val.sub(BigUint56{ limbs: [2, 0, 0, 0, 0] })) - } - - // Checks if the field element is zero. - fn is_zero(self: Self) -> bool { - self.val.is_zero() - } - - // Checks if self == other. - fn eq(self: Self, other: Self) -> bool { - self.val.eq(other.val) - } - - // Print as bytes - fn println(self: Self) { - let bytes = self.to_bytes(); - println(bytes); - } -} - -#[test] -fn test_print() { - let p = PrimeField::R2(); - let limbs = p.val.limbs; - println(limbs); -} - -// TODO: -// 1. Dedup when traits \ No newline at end of file diff --git a/src/ecdsa_secp256r1/swcurve.nr b/src/ecdsa_secp256r1/swcurve.nr deleted file mode 100644 index b004826..0000000 --- a/src/ecdsa_secp256r1/swcurve.nr +++ /dev/null @@ -1,234 +0,0 @@ -use dep::std::println; - -use crate::ecdsa_secp256r1::fp::PrimeField as Fp; -use crate::ecdsa_secp256r1::fq::PrimeField as Fq; - -// Point in three-dimensional Jacobian coordinates -struct Point { - x: Fp, - y: Fp, - z: Fp // z = 0 corresponds to point at infinity. -} - -// Curve specification -struct Curve { // Short Weierstrass curve - // Coefficients in defining equation y^2 = x^3 + axz^4 + bz^6 - a: Fp, - b: Fp, - // Generator as point in projective coordinates - gen: Point -} - -impl Point { - fn from_affine(x: Fp, y: Fp) -> Self { - Self {x, y, z: Fp::one()} - } - - // Additive identity - fn zero() -> Self { - Self {x: Fp::zero(), y: Fp::zero(), z: Fp::zero()} - } - - // Check for equality - fn eq(self, p: Point) -> bool { - let Self {x: x1, y: y1, z: z1} = self; - let Self {x: x2, y: y2, z: z2} = p; - - let z1_is_zero = z1.is_zero(); - let z2_is_zero = z2.is_zero(); - - if (!z1_is_zero & !z2_is_zero) { - let z1sq = z1.square(); - let z2sq = z2.square(); - - let z1cb = z1sq.mul(z1); - let z2cb = z2sq.mul(z2); - - (x1.mul(z2sq).eq(x2.mul(z1sq))) & (y1.mul(z2cb).eq(y2.mul(z1cb))) - } else { - z1_is_zero & z2_is_zero - - } - } - - // Check if zero - fn is_zero(self) -> bool { - let Self {x: _x, y: _y, z} = self; - - z.is_zero() - } - - // Negation - fn negate(self) -> Self { - let Self {x, y, z} = self; - - Self { x, y: y.neg(), z } - } - - // Convert to affine coordinates - // TODO: Create affine struct - fn to_affine(self) -> (Fp, Fp) { - assert(!self.z.is_zero()); - - let zinv = self.z.invert(); - let zinv2 = zinv.square(); - - let x = self.x.mul(zinv2); - let y = self.y.mul(zinv2).mul(zinv); - - (x, y) - } - - // Print as bytes - fn println(self: Self) { - self.x.println(); - self.y.println(); - self.z.println(); - } - - // Print as bytes - fn println_affine(self: Self) { - if (self.z.is_zero()) { - println("O"); - println("O"); - } else { - let (x, y) = self.to_affine(); - - x.println(); - y.println(); - } - } -} - - -impl Curve { - // Curve constructor - fn new(a: Fp, b: Fp, gen: Point) -> Curve { - // Check curve coefficients - assert(!(Fp::from_u56(4).mul(a.square().mul(a)).add(Fp::from_u56(27).mul(b.square()))).is_zero()); - - let curve = Curve { a, b, gen }; - - // gen should be on the curve - assert(curve.contains(gen)); - - curve - } - - // Membership check - // y^2 = x^3 + axz^4 + bz^6 - fn contains(self, p: Point) -> bool { - let Point {x, y, z} = p; - - let xx = x.square(); - let zz = z.square(); - let zzzz = zz.square(); - - let lhs = y.square(); - let mut rhs = xx.mul(x).add(self.a.mul(x).mul(zzzz)); - rhs = rhs.add(self.b.mul(zzzz.mul(zz))); - - lhs.eq(rhs) - } - - // Point addition - fn add(self, p1: Point, p2: Point) -> Point { - if p1.is_zero() { - p2 - } else if p2.is_zero() { - p1 - } else { - let Point {x: x1, y: y1, z: z1} = p1; - let Point {x: x2, y: y2, z: z2} = p2; - - let z1z1 = z1.square(); - let z2z2 = z2.square(); - - let you1 = x1.mul(z2z2); - let you2 = x2.mul(z1z1); - - let s1 = y1.mul(z2z2.mul(z2)); - let s2 = y2.mul(z1z1.mul(z1)); - - if you1.eq(you2) { - if !s1.eq(s2) { - Point::zero() - } else { - self.double(p1) - } - } else { - let h = you2.sub(you1); - let r = s2.sub(s1); - - let hh = h.square(); - let hhh = hh.mul(h); - // BUG: Doesn't work in a single line - let mut x3 = r.square().sub(hhh); - x3 = x3.sub(you1.mul(hh).double()); - // BUG: Doesn't work in a single line - let mut y3 = r.mul(you1.mul(hh).sub(x3)); - y3 = y3.sub(s1.mul(hhh)); - let z3 = h.mul(z1).mul(z2); - - Point { x: x3, y: y3, z: z3 } - } - } - } - - // Point subtraction - fn sub(self, p1: Point, p2: Point) -> Point { - self.add(p1, p2.negate()) - } - - // Point doubling - fn double(self, p: Point) -> Point { - let Point {x, y, z} = p; - - if p.is_zero() { - p - } else if y.is_zero() { - Point::zero() - } else { - let xx = x.square(); - let yy = y.square(); - let yyyy = yy.square(); - - let zzzz = z.square().square(); - - let s = Fp::from_u56(4).mul(x.mul(yy)); - let m = Fp::from_u56(3).mul(xx).add(self.a.mul(zzzz)); - - let x0 = m.square().sub(s.double()); - let y0 = m.mul(s.sub(x0)).sub(Fp::from_u56(8).mul(yyyy)); - let z0 = y.mul(z).double(); - - Point{ x: x0, y: y0, z: z0 } - } - } - - // Scalar multiplication with scalar represented by a bit array (little-endian convention). - // If k is the natural number represented by `bits`, then this computes p + ... + p k times. - fn bit_mul(self, bits: [u1; N], p: Point) -> Point { - let mut out = Point::zero(); - - for i in 0..N { - // TODO: Only start at first non-zero bit - out = self.double(out); - if(bits[N - i - 1] == 1) { - out = self.add(out, p); - } - // BUG: This breaks - // out = self.add( - // self.add(out, out), - // if(bits[N - i - 1] == 0) {Point::zero()} else {p}); - } - - out - } - - // Scalar multiplication (p + ... + p n times) - fn mul(self, n: Fq, p: Point) -> Point { - let n_as_bits = n.to_bits(); - self.bit_mul(n_as_bits, p) - } -}