From 7536af8b69fa2e984fe011eab78fdecb5fae906e Mon Sep 17 00:00:00 2001 From: Sean Bowe Date: Thu, 3 Dec 2020 13:13:40 -0700 Subject: [PATCH] Implement Fp/Fq for the Pallas and Vesta curves. Co-authored-by: Kris Nuttycombe --- src/tweedle/fields/fp.rs | 190 ++++++++++++++++++++++++++------------- src/tweedle/fields/fq.rs | 184 ++++++++++++++++++++++++------------- 2 files changed, 251 insertions(+), 123 deletions(-) diff --git a/src/tweedle/fields/fp.rs b/src/tweedle/fields/fp.rs index 2b969a3..fc37d36 100644 --- a/src/tweedle/fields/fp.rs +++ b/src/tweedle/fields/fp.rs @@ -9,9 +9,9 @@ use crate::arithmetic::{adc, mac, sbb, FieldExt, Group}; /// This represents an element of $\mathbb{F}_p$ where /// -/// `p = 0x40000000000000000000000000000000038aa1276c3f59b9a14064e200000001` +/// `p = 0x40000000000000000000000000000000224698fc094cf91b992d30ed00000001` /// -/// is the base field of the Tweedledum curve. +/// is the base field of the Pallas curve. // The internal representation of this type is four 64-bit unsigned // integers in little-endian order. `Fp` values are always in // Montgomery form; i.e., Fp(a) = aR mod p, with R = 2^256. @@ -94,11 +94,11 @@ impl ConditionallySelectable for Fp { } /// Constant representing the modulus -/// p = 0x40000000000000000000000000000000038aa1276c3f59b9a14064e200000001 +/// p = 0x40000000000000000000000000000000224698fc094cf91b992d30ed00000001 const MODULUS: Fp = Fp([ - 0xa14064e200000001, - 0x38aa1276c3f59b9, - 0x0, + 0x992d30ed00000001, + 0x224698fc094cf91b, + 0x0000000000000000, 0x4000000000000000, ]); @@ -106,9 +106,9 @@ const MODULUS: Fp = Fp([ #[cfg(not(target_pointer_width = "64"))] const MODULUS_LIMBS_32: [u32; 8] = [ 0x0000_0001, - 0xa140_64e2, - 0x6c3f_59b9, - 0x038a_a127, + 0x992d_30ed, + 0x094c_f91b, + 0x2246_98fc, 0x0000_0000, 0x0000_0000, 0x0000_0000, @@ -164,34 +164,34 @@ impl_binops_additive!(Fp, Fp); impl_binops_multiplicative!(Fp, Fp); /// INV = -(p^{-1} mod 2^64) mod 2^64 -const INV: u64 = 0xa14064e1ffffffff; +const INV: u64 = 0x992d30ecffffffff; /// R = 2^256 mod p const R: Fp = Fp([ - 0x1c3ed159fffffffd, - 0xf5601c89bb41f2d3, + 0x34786d38fffffffd, + 0x992c350be41914ad, 0xffffffffffffffff, 0x3fffffffffffffff, ]); /// R^2 = 2^512 mod p const R2: Fp = Fp([ - 0x280c9c4000000010, - 0x91a4409b5400af74, - 0xdd7b28e19094c659, - 0xc8ad9107ccca0e, + 0x8c78ecb30000000f, + 0xd7d30dbd8b0de0e7, + 0x7797a99bc3c95d18, + 0x96d41af7b9cb714, ]); /// R^3 = 2^768 mod p const R3: Fp = Fp([ - 0x98fb3d144380a737, - 0xf9fdbeb55b7eb87c, - 0x63f75cb999eafa89, - 0x217cb214ebb8fc72, + 0xf185a5993a9e10f9, + 0xf6a68f3b6ac5b1d1, + 0xdf8d1014353fd42c, + 0x2ae309222d2d9910, ]); -/// `GENERATOR = 5 mod p` is a generator of the `p - 1` order multiplicative subgroup, and -/// is also a quadratic non-residue. +/// `GENERATOR = 5 mod p` is a generator of the `p - 1` order multiplicative +/// subgroup, or in other words a primitive root of the field. const GENERATOR: Fp = Fp::from_raw([ 0x0000_0000_0000_0005, 0x0000_0000_0000_0000, @@ -199,34 +199,26 @@ const GENERATOR: Fp = Fp::from_raw([ 0x0000_0000_0000_0000, ]); -const S: u32 = 33; +const S: u32 = 32; /// GENERATOR^t where t * 2^s + 1 = p /// with t odd. In other words, this /// is a 2^s root of unity. -/// -/// `GENERATOR = 5 mod p` is a generator -/// of the p - 1 order multiplicative -/// subgroup. const ROOT_OF_UNITY: Fp = Fp::from_raw([ - 0x53de9f31b88837ce, - 0xff46e8f3f3ea99d6, - 0xf624f2eaaf8c2d57, - 0x2ae45117890ee2fc, + 0xbdad6fabd87ea32f, + 0xea322bf2b7bb7584, + 0x362120830561f81a, + 0x2bce74deac30ebda, ]); /// GENERATOR^{2^s} where t * 2^s + 1 = p /// with t odd. In other words, this /// is a t root of unity. -/// -/// `GENERATOR = 5 mod p` is a generator -/// of the p - 1 order multiplicative -/// subgroup. const DELTA: Fp = Fp::from_raw([ - 0x48796f6fde98a425, - 0xa99d8b67e918805e, - 0x671383de08b5fe3c, - 0x1e9372724e80300d, + 0x6a6ccd20dd7b9ba2, + 0xf5e4f3f13eee5636, + 0xbd455b7112a5049d, + 0xa757d0f0006ab6c, ]); impl Default for Fp { @@ -503,7 +495,7 @@ impl ff::Field for Fp { // https://eprint.iacr.org/2012/685.pdf (page 12, algorithm 5) // w = self^((t - 1) // 2) - let w = self.pow_vartime(&[0xdb0fd66e68501938, 0xe2a849, 0x0, 0x10000000]); + let w = self.pow_vartime(&[0x04a67c8dcc969876, 0x11234c7e, 0x0, 0x20000000]); let mut v = S; let mut x = self * w; @@ -544,8 +536,8 @@ impl ff::Field for Fp { /// failing if the element is zero. fn invert(&self) -> CtOption { let tmp = self.pow_vartime(&[ - 0xa14064e1ffffffff, - 0x38aa1276c3f59b9, + 0x992d30ecffffffff, + 0x224698fc094cf91b, 0x0, 0x4000000000000000, ]); @@ -646,43 +638,43 @@ impl ff::PrimeField for Fp { impl FieldExt for Fp { const ROOT_OF_UNITY: Self = ROOT_OF_UNITY; const ROOT_OF_UNITY_INV: Self = Fp::from_raw([ - 0x9246674078fa45bb, - 0xd822ebd60888c5ea, - 0x56d579133a11731f, - 0x1c88fa9e942120bb, + 0xf0b87c7db2ce91f6, + 0x84a0a1d8859f066f, + 0xb4ed8e647196dad1, + 0x2cd5282c53116b5c, ]); const UNROLL_T_EXPONENT: [u64; 4] = [ - 0x3b3a6633d1897d83, - 0x0000000000c93d5b, - 0xf000000000000000, - 0xe34ab16, + 0x955a0a417453113c, + 0x0000000022016b89, + 0xc000000000000000, + 0x3f7ed4c6, ]; const T_EXPONENT: [u64; 4] = [ - 0xb61facdcd0a03271, - 0x0000000001c55093, + 0x094cf91b992d30ed, + 0x00000000224698fc, 0x0000000000000000, - 0x20000000, + 0x40000000, ]; const DELTA: Self = DELTA; - const UNROLL_S_EXPONENT: u64 = 0x11cb54e91; + const UNROLL_S_EXPONENT: u64 = 0x204ace5; const TWO_INV: Self = Fp::from_raw([ - 0xd0a0327100000001, - 0x01c55093b61facdc, + 0xcc96987680000001, + 0x11234c7e04a67c8d, 0x0000000000000000, 0x2000000000000000, ]); const RESCUE_ALPHA: u64 = 5; const RESCUE_INVALPHA: [u64; 4] = [ - 0x810050b4cccccccd, - 0x360880ec56991494, + 0xe0f0f3f0cccccccd, + 0x4e9ee0c9a10a60e2, 0x3333333333333333, 0x3333333333333333, ]; const ZETA: Self = Fp::from_raw([ - 0x8598abb3a410c9c8, - 0x7881fb239ba41a26, - 0x9bebc9146ef83d9a, - 0x1508415ab5e97c94, + 0x7b7fd22f0201b547, + 0x05270d29d19fc7d2, + 0xd3552a23a8554e50, + 0x2d33357cb532458e, ]); fn ct_is_zero(&self) -> Choice { @@ -781,11 +773,36 @@ fn test_inv() { assert_eq!(inv, INV); } +#[test] +fn test_rescue() { + // NB: TWO_INV is standing in as a "random" field element + assert_eq!( + Fp::TWO_INV + .pow_vartime(&[Fp::RESCUE_ALPHA, 0, 0, 0]) + .pow_vartime(&Fp::RESCUE_INVALPHA), + Fp::TWO_INV + ); +} + +#[test] +fn test_sqrt() { + // NB: TWO_INV is standing in as a "random" field element + let v = (Fp::TWO_INV).square().sqrt().unwrap(); + assert!(v == Fp::TWO_INV || (-v) == Fp::TWO_INV); +} + +#[test] +fn test_deterministic_sqrt() { + // NB: TWO_INV is standing in as a "random" field element + let v = (Fp::TWO_INV).square().deterministic_sqrt().unwrap(); + assert!(v == Fp::TWO_INV || (-v) == Fp::TWO_INV); +} + #[test] fn test_zeta() { assert_eq!( format!("{:?}", Fp::ZETA), - "0x1508415ab5e97c949bebc9146ef83d9a7881fb239ba41a268598abb3a410c9c8" + "0x2d33357cb532458ed3552a23a8554e5005270d29d19fc7d27b7fd22f0201b547" ); let a = Fp::ZETA; @@ -796,6 +813,14 @@ fn test_zeta() { assert!(c == Fp::one()); } +#[test] +fn test_root_of_unity() { + assert_eq!( + Fp::ROOT_OF_UNITY.pow_vartime(&[1 << 32, 0, 0, 0]), + Fp::one() + ); +} + #[test] fn test_inv_root_of_unity() { assert_eq!(Fp::ROOT_OF_UNITY_INV, Fp::ROOT_OF_UNITY.invert().unwrap()); @@ -810,3 +835,42 @@ fn test_inv_2() { fn test_delta() { assert_eq!(Fp::DELTA, Fp::from(5).pow(&[1u64 << Fp::S, 0, 0, 0])); } + +#[cfg(not(target_pointer_width = "64"))] +#[test] +fn consistent_modulus_limbs() { + for (a, &b) in MODULUS + .0 + .iter() + .flat_map(|&limb| { + Some(limb as u32) + .into_iter() + .chain(Some((limb >> 32) as u32)) + }) + .zip(MODULUS_LIMBS_32.iter()) + { + assert_eq!(a, b); + } +} + +#[test] +fn test_from_u512() { + assert_eq!( + Fp::from_raw([ + 0x3daec14d565241d9, + 0x0b7af45b6073944b, + 0xea5b8bd611a5bd4c, + 0x150160330625db3d + ]), + Fp::from_u512([ + 0xee155641297678a1, + 0xd83e156bdbfdbe65, + 0xd9ccd834c68ba0b5, + 0xf508ede312272758, + 0x038df7cbf8228e89, + 0x3505a1e4a3c74b41, + 0xbfa46f775eb82db3, + 0x26ebe27e262f471d + ]) + ); +} diff --git a/src/tweedle/fields/fq.rs b/src/tweedle/fields/fq.rs index 7462922..aa414fd 100644 --- a/src/tweedle/fields/fq.rs +++ b/src/tweedle/fields/fq.rs @@ -9,9 +9,9 @@ use crate::arithmetic::{adc, mac, sbb, FieldExt, Group}; /// This represents an element of $\mathbb{F}_q$ where /// -/// `q = 0x40000000000000000000000000000000038aa127696286c9842cafd400000001` +/// `q = 0x40000000000000000000000000000000224698fc0994a8dd8c46eb2100000001` /// -/// is the base field of the Tweedledee curve. +/// is the base field of the Vesta curve. // The internal representation of this type is four 64-bit unsigned // integers in little-endian order. `Fq` values are always in // Montgomery form; i.e., Fq(a) = aR mod q, with R = 2^256. @@ -94,10 +94,10 @@ impl ConditionallySelectable for Fq { } /// Constant representing the modulus -/// q = 0x40000000000000000000000000000000038aa127696286c9842cafd400000001 +/// q = 0x40000000000000000000000000000000224698fc0994a8dd8c46eb2100000001 const MODULUS: Fq = Fq([ - 0x842cafd400000001, - 0x38aa127696286c9, + 0x8c46eb2100000001, + 0x224698fc0994a8dd, 0x0, 0x4000000000000000, ]); @@ -106,9 +106,9 @@ const MODULUS: Fq = Fq([ #[cfg(not(target_pointer_width = "64"))] const MODULUS_LIMBS_32: [u32; 8] = [ 0x0000_0001, - 0x842c_afd4, - 0x6962_86c9, - 0x038a_a127, + 0x8c46_eb21, + 0x0994_a8dd, + 0x2246_98fc, 0x0000_0000, 0x0000_0000, 0x0000_0000, @@ -164,30 +164,30 @@ impl_binops_additive!(Fq, Fq); impl_binops_multiplicative!(Fq, Fq); /// INV = -(q^{-1} mod 2^64) mod 2^64 -const INV: u64 = 0x842cafd3ffffffff; +const INV: u64 = 0x8c46eb20ffffffff; /// R = 2^256 mod q const R: Fq = Fq([ - 0x7379f083fffffffd, - 0xf5601c89c3d86ba3, + 0x5b2b3e9cfffffffd, + 0x992c350be3420567, 0xffffffffffffffff, 0x3fffffffffffffff, ]); /// R^2 = 2^512 mod q const R2: Fq = Fq([ - 0x8595fa8000000010, - 0x7e16a565c6895230, - 0xf4c0e6fcb03aa0a2, - 0xc8ad9106886013, + 0xfc9678ff0000000f, + 0x67bb433d891a16e3, + 0x7fae231004ccf590, + 0x96d41af7ccfdaa9, ]); /// R^3 = 2^768 mod q const R3: Fq = Fq([ - 0xa624f338075cdb5e, - 0x57964eacb8fe21f2, - 0xcb266d18c0413bc2, - 0xa42cdf95f959577, + 0x008b421c249dae4c, + 0xe13bda50dba41326, + 0x88fececb8e15cb63, + 0x7dd97a06e6792c8, ]); /// `GENERATOR = 5 mod q` is a generator of the `q - 1` order multiplicative subgroup, and @@ -199,34 +199,26 @@ const GENERATOR: Fq = Fq::from_raw([ 0x0000_0000_0000_0000, ]); -const S: u32 = 34; +const S: u32 = 32; /// GENERATOR^t where t * 2^s + 1 = q /// with t odd. In other words, this /// is a 2^s root of unity. -/// -/// `GENERATOR = 5 mod q` is a generator -/// of the q - 1 order multiplicative -/// subgroup. const ROOT_OF_UNITY: Fq = Fq::from_raw([ - 0x1cbd3234869d57ec, - 0xa287dd1b8084fbf, - 0xf1dbcb645a987293, - 0x113efc510dc03c0b, + 0xa70e2c1102b6d05f, + 0x9bb97ea3c106f049, + 0x9e5c4dfd492ae26e, + 0x2de6a9b8746d3f58, ]); /// GENERATOR^{2^s} where t * 2^s + 1 = q /// with t odd. In other words, this /// is a t root of unity. -/// -/// `GENERATOR = 5 mod q` is a generator -/// of the q - 1 order multiplicative -/// subgroup. const DELTA: Fq = Fq::from_raw([ - 0x83d2833d15f2bbf9, - 0x5127e2ce24a8e69c, - 0x4243423589e0a9b5, - 0x20daec44973be920, + 0x8494392472d1683c, + 0xe3ac3376541d1140, + 0x06f0a88e7f7949f8, + 0x2237d54423724166, ]); impl Default for Fq { @@ -518,7 +510,7 @@ impl ff::Field for Fq { // https://eprint.iacr.org/2012/685.pdf (page 12, algorithm 5) // w = self^((t - 1) // 2) - let w = self.pow_vartime(&[0xed2c50d9308595fa, 0x715424, 0x0, 0x8000000]); + let w = self.pow_vartime(&[0x04ca546ec6237590, 0x11234c7e, 0x0, 0x20000000]); let mut v = S; let mut x = self * w; @@ -559,8 +551,8 @@ impl ff::Field for Fq { /// failing if the element is zero. fn invert(&self) -> CtOption { let tmp = self.pow_vartime(&[ - 0x842cafd3ffffffff, - 0x38aa127696286c9, + 0x8c46eb20ffffffff, + 0x224698fc0994a8dd, 0x0, 0x4000000000000000, ]); @@ -661,43 +653,43 @@ impl ff::PrimeField for Fq { impl FieldExt for Fq { const ROOT_OF_UNITY: Self = ROOT_OF_UNITY; const ROOT_OF_UNITY_INV: Self = Fq::from_raw([ - 0x824860d3eb30de02, - 0xad9f0afd0ea63acc, - 0xd250318c11a16fe1, - 0x12a9f5e1dd62dabc, + 0x57eecda0a84b6836, + 0x4ad38b9084b8a80c, + 0xf4c8f353124086c1, + 0x2235e1a7415bf936, ]); const UNROLL_T_EXPONENT: [u64; 4] = [ - 0x9b71de17e6d2d5a0, - 0x0000000000296ee0, - 0x8c00000000000000, - 0x2ecc05e, + 0xcc771cc2ac1e1664, + 0x00000000062dfe9e, + 0xc000000000000000, + 0xb89e9c7, ]; const T_EXPONENT: [u64; 4] = [ - 0xda58a1b2610b2bf5, - 0x0000000000e2a849, + 0x0994a8dd8c46eb21, + 0x00000000224698fc, 0x0000000000000000, - 0x10000000, + 0x40000000, ]; const DELTA: Self = DELTA; - const UNROLL_S_EXPONENT: u64 = 0x344cfe85d; + const UNROLL_S_EXPONENT: u64 = 0xd1d858e1; const TWO_INV: Self = Fq::from_raw([ - 0xc21657ea00000001, - 0x01c55093b4b14364, + 0xc623759080000001, + 0x11234c7e04ca546e, 0x0000000000000000, 0x2000000000000000, ]); const RESCUE_ALPHA: u64 = 5; const RESCUE_INVALPHA: [u64; 4] = [ - 0xd023bfdccccccccd, - 0x360880ec544ed23a, + 0xd69f2280cccccccd, + 0x4e9ee0c9a143ba4a, 0x3333333333333333, 0x3333333333333333, ]; const ZETA: Self = Fq::from_raw([ - 0x4394c2bd148fa4fd, - 0x69cf8de720e52ec1, - 0x87ad8b5ff9731ffe, - 0x36c66d3a1e049a58, + 0x2aa9d2e050aa0e4f, + 0x0fed467d47c033af, + 0x511db4d81cf70f5a, + 0x6819a58283e528e, ]); fn ct_is_zero(&self) -> Choice { @@ -796,11 +788,36 @@ fn test_inv() { assert_eq!(inv, INV); } +#[test] +fn test_rescue() { + // NB: TWO_INV is standing in as a "random" field element + assert_eq!( + Fq::TWO_INV + .pow_vartime(&[Fq::RESCUE_ALPHA, 0, 0, 0]) + .pow_vartime(&Fq::RESCUE_INVALPHA), + Fq::TWO_INV + ); +} + +#[test] +fn test_sqrt() { + // NB: TWO_INV is standing in as a "random" field element + let v = (Fq::TWO_INV).square().sqrt().unwrap(); + assert!(v == Fq::TWO_INV || (-v) == Fq::TWO_INV); +} + +#[test] +fn test_deterministic_sqrt() { + // NB: TWO_INV is standing in as a "random" field element + let v = (Fq::TWO_INV).square().deterministic_sqrt().unwrap(); + assert!(v == Fq::TWO_INV || (-v) == Fq::TWO_INV); +} + #[test] fn test_zeta() { assert_eq!( format!("{:?}", Fq::ZETA), - "0x36c66d3a1e049a5887ad8b5ff9731ffe69cf8de720e52ec14394c2bd148fa4fd" + "0x06819a58283e528e511db4d81cf70f5a0fed467d47c033af2aa9d2e050aa0e4f" ); let a = Fq::ZETA; assert!(a != Fq::one()); @@ -810,6 +827,14 @@ fn test_zeta() { assert!(c == Fq::one()); } +#[test] +fn test_root_of_unity() { + assert_eq!( + Fq::ROOT_OF_UNITY.pow_vartime(&[1 << 32, 0, 0, 0]), + Fq::one() + ); +} + #[test] fn test_inv_root_of_unity() { assert_eq!(Fq::ROOT_OF_UNITY_INV, Fq::ROOT_OF_UNITY.invert().unwrap()); @@ -824,3 +849,42 @@ fn test_inv_2() { fn test_delta() { assert_eq!(Fq::DELTA, Fq::from(5).pow(&[1u64 << Fq::S, 0, 0, 0])); } + +#[cfg(not(target_pointer_width = "64"))] +#[test] +fn consistent_modulus_limbs() { + for (a, &b) in MODULUS + .0 + .iter() + .flat_map(|&limb| { + Some(limb as u32) + .into_iter() + .chain(Some((limb >> 32) as u32)) + }) + .zip(MODULUS_LIMBS_32.iter()) + { + assert_eq!(a, b); + } +} + +#[test] +fn test_from_u512() { + assert_eq!( + Fq::from_raw([ + 0xe22bd0d1b22cc43e, + 0x6b84e5b52490a7c8, + 0x264262941ac9e229, + 0x27dcfdf361ce4254 + ]), + Fq::from_u512([ + 0x64a80cce0b5a2369, + 0x84f2ef0501bc783c, + 0x696e5e63c86bbbde, + 0x924072f52dc6cc62, + 0x8288a507c8d61128, + 0x3b2efb1ef697e3fe, + 0x75a4998d06855f27, + 0x52ea589e69712cc0 + ]) + ); +}