From b6b05d54330a14579439e7f93b3c70e68a8d22b5 Mon Sep 17 00:00:00 2001 From: kilic Date: Sat, 25 May 2024 16:57:40 +0300 Subject: [PATCH] add field generator macros --- .gitignore | 2 +- Cargo.toml | 4 +- derive/Cargo.toml | 19 + derive/src/field/arith.rs | 340 +++++++ .../src/field/asm/limb4.rs | 67 +- derive/src/field/asm/mod.rs | 1 + derive/src/field/mod.rs | 618 +++++++++++++ derive/src/lib.rs | 7 + derive/src/utils.rs | 35 + src/arithmetic.rs | 24 - src/bn256/curve.rs | 8 +- src/bn256/engine.rs | 12 +- src/bn256/fq.rs | 305 +------ src/bn256/fq12.rs | 152 +--- src/bn256/fq2.rs | 400 +-------- src/bn256/fq6.rs | 190 +--- src/bn256/fr.rs | 364 +------- src/bn256/mod.rs | 3 - src/derive/curve.rs | 54 +- src/derive/field.rs | 790 ---------------- src/derive/field/common.rs | 105 +++ src/derive/field/mod.rs | 4 + src/derive/field/tower.rs | 517 +++++++++++ src/derive/mod.rs | 47 +- src/pluto_eris/curve.rs | 35 +- src/pluto_eris/engine.rs | 27 +- src/pluto_eris/fields/fp.rs | 415 --------- src/pluto_eris/fields/fq.rs | 406 --------- src/pluto_eris/fields/mod.rs | 843 ------------------ src/pluto_eris/fp.rs | 44 + src/pluto_eris/{fields => }/fp12.rs | 148 +-- src/pluto_eris/fp2.rs | 277 ++++++ src/pluto_eris/{fields => }/fp6.rs | 206 +---- src/pluto_eris/fq.rs | 44 + src/pluto_eris/mod.rs | 10 +- src/secp256k1/fp.rs | 312 +------ src/secp256k1/fq.rs | 318 +------ src/secp256r1/fp.rs | 329 +------ src/secp256r1/fq.rs | 314 +------ src/serde.rs | 42 + src/tests/curve.rs | 12 +- src/tests/field.rs | 69 +- src/tests/mod.rs | 17 +- 43 files changed, 2440 insertions(+), 5496 deletions(-) create mode 100644 derive/Cargo.toml create mode 100644 derive/src/field/arith.rs rename src/bn256/assembly.rs => derive/src/field/asm/limb4.rs (94%) create mode 100644 derive/src/field/asm/mod.rs create mode 100644 derive/src/field/mod.rs create mode 100644 derive/src/lib.rs create mode 100644 derive/src/utils.rs delete mode 100644 src/derive/field.rs create mode 100644 src/derive/field/common.rs create mode 100644 src/derive/field/mod.rs create mode 100644 src/derive/field/tower.rs delete mode 100644 src/pluto_eris/fields/fp.rs delete mode 100644 src/pluto_eris/fields/fq.rs delete mode 100644 src/pluto_eris/fields/mod.rs create mode 100644 src/pluto_eris/fp.rs rename src/pluto_eris/{fields => }/fp12.rs (80%) create mode 100644 src/pluto_eris/fp2.rs rename src/pluto_eris/{fields => }/fp6.rs (78%) create mode 100644 src/pluto_eris/fq.rs diff --git a/.gitignore b/.gitignore index 6bbc2b47..4def0c40 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,4 @@ -/target +target Cargo.lock **/*.rs.bk .vscode diff --git a/Cargo.toml b/Cargo.toml index 34882b1d..64c178ff 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -25,6 +25,7 @@ impls = "1" getrandom = { version = "0.2", features = ["js"] } [dependencies] +halo2derive = {path = "derive"} subtle = "2.5" ff = { version = "0.13.0", default-features = false, features = ["std"] } group = "0.13.0" @@ -35,6 +36,7 @@ rand = "0.8" rand_core = { version = "0.6", default-features = false } lazy_static = "1.4.0" num-bigint = "0.4.3" +num-integer = "0.1.46" num-traits = "0.2" paste = "1.0.11" serde = { version = "1.0", default-features = false, optional = true } @@ -48,7 +50,7 @@ digest = "0.10.7" [features] default = ["bits"] -asm = [] +asm = ["halo2derive/asm"] bits = ["ff/bits"] bn256-table = [] derive_serde = ["serde/derive", "serde_arrays", "hex", "pasta_curves/serde"] diff --git a/derive/Cargo.toml b/derive/Cargo.toml new file mode 100644 index 00000000..ef22120d --- /dev/null +++ b/derive/Cargo.toml @@ -0,0 +1,19 @@ +[package] +edition = "2021" +name = "halo2derive" +version = "0.1.0" + +[lib] +proc-macro = true + +[dependencies] +num-bigint = "0.4" +num-integer = "0.1" +num-traits = "0.2" +proc-macro2 = "1.0" +quote = "1.0" +syn = {version = "1.0", features = ["full"]} + +[features] +default = [] +asm = [] \ No newline at end of file diff --git a/derive/src/field/arith.rs b/derive/src/field/arith.rs new file mode 100644 index 00000000..3102c578 --- /dev/null +++ b/derive/src/field/arith.rs @@ -0,0 +1,340 @@ +use proc_macro2::TokenStream; +use quote::format_ident as fmtid; +use quote::quote; + +fn select(cond: bool, this: TokenStream, other: TokenStream) -> TokenStream { + if cond { + this + } else { + other + } +} + +pub(crate) fn impl_arith(field: &syn::Ident, num_limbs: usize, inv: u64) -> TokenStream { + let impl_add = impl_add(field, num_limbs); + let impl_sub = impl_sub(field, num_limbs); + let impl_neg = impl_neg(field, num_limbs); + let impl_mont = impl_mont(field, num_limbs, inv); + let impl_from_mont = impl_from_mont(field, num_limbs, inv); + let impl_mul = impl_mul(field, num_limbs, false); + let impl_square = impl_square(field, num_limbs); + let wide_num_limbs = num_limbs * 2; + quote::quote! { + impl #field { + #[inline(always)] + pub const fn add(&self, rhs: &Self) -> Self { + #impl_add + } + + #[inline] + pub const fn double(&self) -> Self { + self.add(self) + } + + #[inline(always)] + pub const fn sub(&self, rhs: &Self) -> Self { + #impl_sub + } + + #[inline(always)] + pub const fn neg(&self) -> Self { + #impl_neg + } + + #[inline(always)] + pub const fn mul(&self, rhs: &Self) -> Self{ + #impl_mul + } + + #[inline(always)] + pub const fn square(&self) -> Self{ + #impl_square + } + + #[inline(always)] + pub(crate) const fn montgomery_reduce(r: &[u64; #wide_num_limbs]) -> Self { + #impl_mont + } + + #[inline(always)] + pub(crate) const fn from_mont(&self) -> [u64; #num_limbs] { + #impl_from_mont + } + } + } +} + +pub(crate) fn impl_arith_always_const( + field: &syn::Ident, + num_limbs: usize, + inv: u64, +) -> TokenStream { + let impl_sub = impl_sub(field, num_limbs); + let impl_mont = impl_mont(field, num_limbs, inv); + let impl_mul = impl_mul(field, num_limbs, true); + let wide_num_limbs = num_limbs * 2; + quote::quote! { + impl #field { + + #[inline(always)] + pub(crate) const fn sub_const(&self, rhs: &Self) -> Self { + #impl_sub + } + + + #[inline(always)] + pub(crate) const fn mul_const(&self, rhs: &Self) -> Self{ + #impl_mul + } + + #[inline(always)] + pub(crate) const fn montgomery_reduce_const(r: &[u64; #wide_num_limbs]) -> Self { + #impl_mont + } + } + } +} + +fn impl_mul(field: &syn::Ident, num_limbs: usize, constant: bool) -> TokenStream { + let mut gen = quote! { use crate::arithmetic::{adc, sbb, mac}; }; + for i in 0..num_limbs { + for j in 0..num_limbs { + let r_out = fmtid!("r_{}", i + j); + let r_next = fmtid!("r_{}", i + j + 1); + let r_in = select(i == 0, quote! {0}, quote! {#r_out}); + let carry_in = select(j == 0, quote! {0}, quote! {carry}); + let carry_out = select(j == num_limbs - 1, quote! {#r_next}, quote! {carry}); + gen.extend( + quote! { let (#r_out, #carry_out) = mac(#r_in, self.0[#i], rhs.0[#j], #carry_in); }, + ); + } + } + + let r: Vec<_> = (0..num_limbs * 2).map(|i| fmtid!("r_{}", i)).collect(); + let mont_red = if constant { + quote! { #field::montgomery_reduce_const(&[#(#r),*]) } + } else { + quote! { #field::montgomery_reduce(&[#(#r),*]) } + }; + quote! { + #gen + #mont_red + } +} + +fn impl_square(field: &syn::Ident, num_limbs: usize) -> TokenStream { + let mut gen = quote! { use crate::arithmetic::{adc, sbb, mac}; }; + for i in 0..num_limbs - 1 { + let start_index = i * 2 + 1; + for j in 0..num_limbs - i - 1 { + let r_out = fmtid!("r_{}", start_index + j); + let r_in = select(i == 0, quote! {0}, quote! {#r_out}); + let r_next = fmtid!("r_{}", start_index + j + 1); + let carry_in = select(j == 0, quote! {0}, quote! {carry}); + let carry_out = select(j == num_limbs - i - 2, quote! {#r_next}, quote! {carry}); + let j = i + j + 1; + gen.extend(quote! { let (#r_out, #carry_out) = mac(#r_in, self.0[#i], self.0[#j], #carry_in); }); + } + } + + for i in (1..num_limbs * 2).rev() { + let (r_cur, r_next) = (fmtid!("r_{}", i), fmtid!("r_{}", i - 1)); + if i == num_limbs * 2 - 1 { + gen.extend(quote! { let #r_cur = #r_next >> 63; }); + } else if i == 1 { + gen.extend(quote! { let #r_cur = (#r_cur << 1); }); + } else { + gen.extend(quote! { let #r_cur = (#r_cur << 1) | (#r_next >> 63); }); + } + } + + for i in 0..num_limbs { + let index = i * 2; + let r_cur = fmtid!("r_{}", index); + let r_next = fmtid!("r_{}", index + 1); + let r_cur_in = select(i == 0, quote! {0}, quote! {#r_cur}); + let carry_in = select(i == 0, quote! {0}, quote! {carry}); + let carry_out = select(i == num_limbs - 1, quote! {_}, quote! {carry}); + gen.extend(quote! { + let (#r_cur, carry) = mac(#r_cur_in, self.0[#i], self.0[#i], #carry_in); + let (#r_next, #carry_out) = adc(0, #r_next, carry); + }); + } + + let r: Vec<_> = (0..num_limbs * 2).map(|i| fmtid!("r_{}", i)).collect(); + quote! { + #gen + #field::montgomery_reduce(&[#(#r),*]) + } +} + +fn impl_add(field: &syn::Ident, num_limbs: usize) -> TokenStream { + let mut gen = quote! { use crate::arithmetic::{adc, sbb}; }; + + (0..num_limbs).for_each(|i| { + let carry = select(i == 0, quote! {0}, quote! {carry}); + let d_i = fmtid!("d_{}", i); + gen.extend(quote! { let ( #d_i, carry) = adc(self.0[#i], rhs.0[#i], #carry); }); + }); + + (0..num_limbs).for_each(|i| { + let borrow = select(i == 0, quote! {0}, quote! {borrow}); + let d_i = fmtid!("d_{}", i); + gen.extend(quote! { let (#d_i, borrow) = sbb(#d_i, Self::MODULUS_LIMBS[#i], #borrow); }); + }); + gen.extend(quote! {let (_, borrow) = sbb(carry, 0, borrow);}); + + (0..num_limbs).for_each(|i| { + let carry_in = select(i == 0, quote! {0}, quote! {carry}); + let carry_out = select(i == num_limbs - 1, quote! {_}, quote! {carry}); + let d_i = fmtid!("d_{}", i); + gen.extend( + quote! { let (#d_i, #carry_out) = adc(#d_i, Self::MODULUS_LIMBS[#i] & borrow, #carry_in); }, + ); + }); + + let ret: Vec<_> = (0..num_limbs).map(|i| fmtid!("d_{}", i)).collect(); + + quote! { + #gen + #field([#(#ret),*]) + } +} + +fn impl_sub(field: &syn::Ident, num_limbs: usize) -> TokenStream { + let mut gen = quote! { use crate::arithmetic::{adc, sbb}; }; + + (0..num_limbs).for_each(|i| { + let borrow = select(i == 0, quote! {0}, quote! {borrow}); + let d_i = fmtid!("d_{}", i); + gen.extend(quote! { let (#d_i, borrow) = sbb(self.0[#i], rhs.0[#i], #borrow); }); + }); + + (0..num_limbs).for_each(|i| { + let carry_in = select(i == 0, quote! {0}, quote! {carry}); + let carry_out = select(i == num_limbs - 1, quote! {_}, quote! {carry}); + let d_i = fmtid!("d_{}", i); + gen.extend( + quote! { let (#d_i, #carry_out) = adc(#d_i, Self::MODULUS_LIMBS[#i] & borrow, #carry_in); }, + ); + }); + + let ret: Vec<_> = (0..num_limbs).map(|i| fmtid!("d_{}", i)).collect(); + + quote! { + #gen + #field([#(#ret),*]) + } +} + +fn impl_neg(field: &syn::Ident, num_limbs: usize) -> TokenStream { + let mut gen = quote! { use crate::arithmetic::{adc, sbb}; }; + + (0..num_limbs).for_each(|i| { + let borrow_in = select(i == 0, quote! {0}, quote! {borrow}); + let borrow_out = select(i == num_limbs - 1, quote! {_}, quote! {borrow}); + let d_i = fmtid!("d_{}", i); + gen.extend(quote! { let (#d_i, #borrow_out) = sbb(Self::MODULUS_LIMBS[#i], self.0[#i], #borrow_in); }) + }); + + let mask_limbs: Vec<_> = (0..num_limbs) + .map(|i| quote::quote! { self.0[#i] }) + .collect(); + gen.extend(quote! { let mask = (((#(#mask_limbs)|*) == 0) as u64).wrapping_sub(1); }); + + let ret: Vec<_> = (0..num_limbs) + .map(|i| { + let d_i = fmtid!("d_{}", i); + quote! { #d_i & mask } + }) + .collect(); + + quote! { + #gen + #field([#(#ret),*]) + } +} + +fn impl_mont(field: &syn::Ident, num_limbs: usize, inv: u64) -> TokenStream { + let mut gen = quote! { use crate::arithmetic::{adc, sbb, mac}; }; + + for i in 0..num_limbs { + if i == 0 { + gen.extend(quote! { let k = r[0].wrapping_mul(#inv); }); + + for j in 0..num_limbs { + let r_out = fmtid!("r_{}", j); + let r_out = select(j == 0, quote! {_}, quote! {#r_out}); + let carry_in = select(j == 0, quote! {0}, quote! {carry}); + gen.extend(quote! { let (#r_out, carry) = mac(r[#j], k, Self::MODULUS_LIMBS[#j], #carry_in); }); + } + let r_out = fmtid!("r_{}", num_limbs); + gen.extend(quote! { let (#r_out, carry2) = adc(r[#num_limbs], 0, carry); }); + } else { + let r_i = fmtid!("r_{}", i); + gen.extend(quote! { let k = #r_i.wrapping_mul(#inv); }); + + for j in 0..num_limbs { + let r_in = fmtid!("r_{}", j + i); + let r_out = select(j == 0, quote! {_}, quote! {#r_in}); + let carry_in = select(j == 0, quote! {0}, quote! {carry}); + gen.extend(quote! { let (#r_out, carry) = mac(#r_in, k, Self::MODULUS_LIMBS[#j], #carry_in); }); + } + let idx = num_limbs + i; + let r_out = fmtid!("r_{}", idx); + gen.extend(quote! { let (#r_out, carry2) = adc(r[#idx], carry2, carry); }); + } + } + + (0..num_limbs).for_each(|i| { + let borrow = select(i == 0, quote! {0}, quote! {borrow}); + let d_i = fmtid!("d_{}", i); + let r_in = fmtid!("r_{}", num_limbs + i); + gen.extend(quote! { let (#d_i, borrow) = sbb(#r_in, Self::MODULUS_LIMBS[#i], #borrow); }); + }); + + gen.extend(quote! {let (_, borrow) = sbb(carry2, 0, borrow);}); + + (0..num_limbs).for_each(|i| { + let carry_in = select(i == 0, quote! {0}, quote! {carry}); + let carry_out = select(i == num_limbs - 1, quote! {_}, quote! {carry}); + let d_i = fmtid!("d_{}", i); + gen.extend( + quote! { let (#d_i, #carry_out) = adc(#d_i, Self::MODULUS_LIMBS[#i] & borrow, #carry_in); }, + ); + }); + let ret: Vec<_> = (0..num_limbs).map(|i| fmtid!("d_{}", i)).collect(); + + quote! { + #gen + #field([#(#ret),*]) + } +} + +fn impl_from_mont(field: &syn::Ident, num_limbs: usize, inv: u64) -> TokenStream { + let mut gen = quote! { use crate::arithmetic::{adc, sbb, mac}; }; + + for i in 0..num_limbs { + let r_i = fmtid!("r_{}", i); + if i == 0 { + gen.extend(quote! { let k = self.0[0].wrapping_mul(#inv); }); + } else { + gen.extend(quote! { let k = #r_i.wrapping_mul(#inv); }); + } + + for j in 0..num_limbs { + let r_ij = fmtid!("r_{}", (j + i) % num_limbs); + let r_out = select(j == 0, quote! {_}, quote! {#r_ij}); + let r_ij = select(i == 0, quote! {self.0[#j]}, quote! {#r_ij}); + let carry_in = select(j == 0, quote! {0}, quote! {#r_i}); + gen.extend( + quote! { let (#r_out, #r_i) = mac(#r_ij, k, Self::MODULUS_LIMBS[#j], #carry_in); }, + ); + } + } + let ret: Vec<_> = (0..num_limbs).map(|i| fmtid!("r_{}", i)).collect(); + quote! { + #gen + #field([#(#ret),*]).sub(&#field(Self::MODULUS_LIMBS)).0 + } +} diff --git a/src/bn256/assembly.rs b/derive/src/field/asm/limb4.rs similarity index 94% rename from src/bn256/assembly.rs rename to derive/src/field/asm/limb4.rs index 7d99c321..8fc071e4 100644 --- a/src/bn256/assembly.rs +++ b/derive/src/field/asm/limb4.rs @@ -1,15 +1,12 @@ -macro_rules! field_arithmetic_asm { - ( - $field:ident, - $modulus:ident, - $inv:ident - ) => { - use std::arch::asm; +use proc_macro2::TokenStream; - impl $field { +pub(crate) fn impl_arith(field: &syn::Ident, inv: u64) -> TokenStream { + quote::quote! { + use std::arch::asm; + impl #field { /// Doubles this field element. #[inline] - pub fn double(&self) -> $field { + pub fn double(&self) -> #field { let mut r0: u64; let mut r1: u64; let mut r2: u64; @@ -46,7 +43,7 @@ macro_rules! field_arithmetic_asm { "cmovc r14, r10", "cmovc r15, r11", - m_ptr = in(reg) $modulus.0.as_ptr(), + m_ptr = in(reg) #field::MODULUS_LIMBS.as_ptr(), a_ptr = in(reg) self.0.as_ptr(), out("r8") _, out("r9") _, @@ -59,17 +56,17 @@ macro_rules! field_arithmetic_asm { options(pure, readonly, nostack) ); } - $field([r0, r1, r2, r3]) + #field([r0, r1, r2, r3]) } /// Squares this element. #[inline] - pub fn square(&self) -> $field { + pub fn square(&self) -> #field { self.mul(self) } #[inline(always)] - pub(crate) fn montgomery_reduce_256(&self) -> $field { + pub(crate) fn from_mont(&self) -> [u64; Self::NUM_LIMBS] { let mut r0: u64; let mut r1: u64; let mut r2: u64; @@ -179,8 +176,8 @@ macro_rules! field_arithmetic_asm { // high(inv * p3) + 2 < p3 a_ptr = in(reg) self.0.as_ptr(), - m_ptr = in(reg) $modulus.0.as_ptr(), - inv = in(reg) $inv, + m_ptr = in(reg) #field::MODULUS_LIMBS.as_ptr(), + inv = in(reg) #inv, out("rax") _, out("rcx") _, @@ -196,12 +193,12 @@ macro_rules! field_arithmetic_asm { options(pure, readonly, nostack) ) } - $field([r0, r1, r2, r3]) + [r0, r1, r2, r3] } /// Multiplies `rhs` by `self`, returning the result. #[inline] - pub fn mul(&self, rhs: &Self) -> $field { + pub fn mul(&self, rhs: &Self) -> #field { let mut r0: u64; let mut r1: u64; let mut r2: u64; @@ -419,10 +416,10 @@ macro_rules! field_arithmetic_asm { "cmovnc rax, rdx", "cmovnc r14, r15", - m_ptr = in(reg) $modulus.0.as_ptr(), + m_ptr = in(reg) #field::MODULUS_LIMBS.as_ptr(), a_ptr = in(reg) self.0.as_ptr(), b_ptr = in(reg) rhs.0.as_ptr(), - inv = in(reg) $inv, + inv = in(reg) #inv, out("rax") r2, out("rdx") _, out("r10") _, @@ -435,12 +432,12 @@ macro_rules! field_arithmetic_asm { ) } - $field([r0, r1, r2, r3]) + #field([r0, r1, r2, r3]) } /// Subtracts `rhs` from `self`, returning the result. #[inline] - pub fn sub(&self, rhs: &Self) -> $field { + pub fn sub(&self, rhs: &Self) -> #field { let mut r0: u64; let mut r1: u64; let mut r2: u64; @@ -480,7 +477,7 @@ macro_rules! field_arithmetic_asm { "adc r14, r10", "adc r15, r11", - m_ptr = in(reg) $modulus.0.as_ptr(), + m_ptr = in(reg) #field::MODULUS_LIMBS.as_ptr(), a_ptr = in(reg) self.0.as_ptr(), b_ptr = in(reg) rhs.0.as_ptr(), out("rax") _, @@ -495,12 +492,12 @@ macro_rules! field_arithmetic_asm { options(pure, readonly, nostack) ); } - $field([r0, r1, r2, r3]) + #field([r0, r1, r2, r3]) } /// Adds `rhs` to `self`, returning the result. #[inline] - pub fn add(&self, rhs: &Self) -> $field { + pub fn add(&self, rhs: &Self) -> #field { let mut r0: u64; let mut r1: u64; let mut r2: u64; @@ -537,7 +534,7 @@ macro_rules! field_arithmetic_asm { "cmovc r14, r10", "cmovc r15, r11", - m_ptr = in(reg) $modulus.0.as_ptr(), + m_ptr = in(reg) #field::MODULUS_LIMBS.as_ptr(), a_ptr = in(reg) self.0.as_ptr(), b_ptr = in(reg) rhs.0.as_ptr(), out("r8") _, @@ -551,12 +548,12 @@ macro_rules! field_arithmetic_asm { options(pure, readonly, nostack) ); } - $field([r0, r1, r2, r3]) + #field([r0, r1, r2, r3]) } /// Negates `self`. #[inline] - pub fn neg(&self) -> $field { + pub fn neg(&self) -> #field { let mut r0: u64; let mut r1: u64; let mut r2: u64; @@ -593,7 +590,7 @@ macro_rules! field_arithmetic_asm { "and r11, r13", a_ptr = in(reg) self.0.as_ptr(), - m_ptr = in(reg) $modulus.0.as_ptr(), + m_ptr = in(reg) #field::MODULUS_LIMBS.as_ptr(), out("r8") r0, out("r9") r1, out("r10") r2, @@ -605,18 +602,8 @@ macro_rules! field_arithmetic_asm { options(pure, readonly, nostack) ) } - $field([r0, r1, r2, r3]) - } - } - - impl From<$field> for [u64; 4] { - fn from(elt: $field) -> [u64; 4] { - // Turn into canonical form by computing - // (a.R) / R = a - elt.montgomery_reduce_256().0 + #field([r0, r1, r2, r3]) } } - }; + } } - -pub(crate) use field_arithmetic_asm; diff --git a/derive/src/field/asm/mod.rs b/derive/src/field/asm/mod.rs new file mode 100644 index 00000000..a2900fbc --- /dev/null +++ b/derive/src/field/asm/mod.rs @@ -0,0 +1 @@ +pub(crate) mod limb4; diff --git a/derive/src/field/mod.rs b/derive/src/field/mod.rs new file mode 100644 index 00000000..66786f7d --- /dev/null +++ b/derive/src/field/mod.rs @@ -0,0 +1,618 @@ +mod arith; +#[cfg(feature = "asm")] +mod asm; + +use num_bigint::BigUint; +use num_integer::Integer; +use num_traits::{Num, One}; +use proc_macro::TokenStream; +use proc_macro2::Span; +use quote::quote; +use syn::Token; + +struct FieldConfig { + identifier: String, + field: syn::Ident, + modulus: BigUint, + mul_gen: BigUint, + zeta: BigUint, + from_uniform: Vec, +} + +impl syn::parse::Parse for FieldConfig { + fn parse(input: syn::parse::ParseStream<'_>) -> syn::Result { + let identifier: syn::Ident = input.parse()?; + let identifier = identifier.to_string(); + input.parse::()?; + + let field: syn::Ident = input.parse()?; + input.parse::()?; + + let get_big = |is_key: &str| -> Result { + let key: syn::Ident = input.parse()?; + assert_eq!(key.to_string(), is_key); + input.parse::()?; + let n: syn::LitStr = input.parse()?; + let n = BigUint::from_str_radix(&n.value(), 16) + .map_err(|err| syn::Error::new(Span::call_site(), err.to_string()))?; + input.parse::()?; + Ok(n) + }; + + let get_usize_list = |is_key: &str| -> Result, syn::Error> { + let key: syn::Ident = input.parse()?; + assert_eq!(key.to_string(), is_key); + input.parse::()?; + + // chatgpt + let content; + syn::bracketed!(content in input); + let punctuated: syn::punctuated::Punctuated = + content.parse_terminated(syn::LitInt::parse)?; + let values = punctuated + .into_iter() + .map(|lit| lit.base10_parse::()) + .collect::, _>>()?; + Ok(values) + }; + + let modulus = get_big("modulus")?; + let mul_gen = get_big("mul_gen")?; + let zeta = get_big("zeta")?; + let from_uniform = get_usize_list("from_uniform")?; + + input.parse::()?; + assert!(input.is_empty()); + + Ok(FieldConfig { + identifier, + field, + modulus, + mul_gen, + zeta, + from_uniform, + }) + } +} + +pub(crate) fn impl_field(input: TokenStream) -> TokenStream { + use crate::utils::{big_to_token, mod_inv}; + let FieldConfig { + identifier, + field, + modulus, + mul_gen, + zeta, + from_uniform, + } = syn::parse_macro_input!(input as FieldConfig); + let _ = identifier; + + let num_bits = modulus.bits() as u32; + let limb_size = 64; + let num_limbs = ((num_bits - 1) / limb_size + 1) as usize; + let size = num_limbs * 8; + let modulus_limbs = crate::utils::big_to_limbs(&modulus, num_limbs); + let modulus_str = format!("0x{}", modulus.to_str_radix(16)); + let modulus_limbs_ident = quote! {[#(#modulus_limbs,)*]}; + + let modulus_limbs_32 = crate::utils::big_to_limbs_32(&modulus, num_limbs * 2); + let modulus_limbs_32_ident = quote! {[#(#modulus_limbs_32,)*]}; + + let to_token = |e: &BigUint| big_to_token(e, num_limbs); + + // binary modulus + let t = BigUint::from(1u64) << (num_limbs * limb_size as usize); + // r1 = mont(1) + let r1: BigUint = &t % &modulus; + let mont = |v: &BigUint| (v * &r1) % &modulus; + // r2 = mont(r) + let r2: BigUint = (&r1 * &r1) % &modulus; + // r3 = mont(r^2) + let r3: BigUint = (&r1 * &r1 * &r1) % &modulus; + + let r1 = to_token(&r1); + let r2 = to_token(&r2); + let r3 = to_token(&r3); + + // inv = -(r^{-1} mod 2^64) mod 2^64 + let mut inv64 = 1u64; + for _ in 0..63 { + inv64 = inv64.wrapping_mul(inv64); + inv64 = inv64.wrapping_mul(modulus_limbs[0]); + } + inv64 = inv64.wrapping_neg(); + + let mut by_inverter_constant: usize = 2; + loop { + let t = BigUint::from(1u64) << (62 * by_inverter_constant - 64); + if t > modulus { + break; + } + by_inverter_constant += 1; + } + + let mut jacobi_constant: usize = 1; + loop { + let t = BigUint::from(1u64) << (64 * jacobi_constant - 31); + if t > modulus { + break; + } + jacobi_constant += 1; + } + + let mut s: u32 = 0; + let mut t = &modulus - BigUint::one(); + while t.is_even() { + t >>= 1; + s += 1; + } + + let two_inv = mod_inv(&BigUint::from(2usize), &modulus); + + let sqrt_impl = { + if &modulus % 16u64 == BigUint::from(1u64) { + let tm1o2 = ((&t - 1usize) * &two_inv) % &modulus; + let tm1o2 = big_to_token(&tm1o2, num_limbs); + quote! { + fn sqrt(&self) -> subtle::CtOption { + ff::helpers::sqrt_tonelli_shanks(self, #tm1o2) + } + } + } else if &modulus % 4u64 == BigUint::from(3u64) { + let exp = (&modulus + 1usize) >> 2; + let exp = big_to_token(&exp, num_limbs); + quote! { + fn sqrt(&self) -> subtle::CtOption { + use subtle::ConstantTimeEq; + let t = self.pow(#exp); + subtle::CtOption::new(t, t.square().ct_eq(self)) + } + } + } else { + panic!("unsupported modulus") + } + }; + + let root_of_unity = mul_gen.modpow(&t, &modulus); + let root_of_unity_inv = mod_inv(&root_of_unity, &modulus); + let delta = mul_gen.modpow(&(BigUint::one() << s), &modulus); + + let root_of_unity = to_token(&mont(&root_of_unity)); + let root_of_unity_inv = to_token(&mont(&root_of_unity_inv)); + let two_inv = to_token(&mont(&two_inv)); + let mul_gen = to_token(&mont(&mul_gen)); + let delta = to_token(&mont(&delta)); + let zeta = to_token(&mont(&zeta)); + + let impl_field = quote! { + #[derive(Clone, Copy, PartialEq, Eq, Hash, Default)] + pub struct #field(pub(crate) [u64; #num_limbs]); + + impl core::fmt::Debug for #field { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + use ff::PrimeField; + let tmp = self.to_repr(); + write!(f, "0x")?; + for &b in tmp.as_ref().iter().rev() { + write!(f, "{:02x}", b)?; + } + Ok(()) + } + } + + impl ConstantTimeEq for #field { + fn ct_eq(&self, other: &Self) -> Choice { + Choice::from( + self.0 + .iter() + .zip(other.0) + .all(|(a, b)| bool::from(a.ct_eq(&b))) as u8, + ) + } + } + + impl ConditionallySelectable for #field { + fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self { + let limbs = (0..#num_limbs) + .map(|i| u64::conditional_select(&a.0[i], &b.0[i], choice)) + .collect::>() + .try_into() + .unwrap(); + #field(limbs) + } + } + + impl core::cmp::PartialOrd for #field { + fn partial_cmp(&self, other: &Self) -> Option { + Some(self.cmp(other)) + } + } + + impl core::cmp::Ord for #field { + fn cmp(&self, other: &Self) -> core::cmp::Ordering { + use ff::PrimeField; + let left = self.to_repr(); + let right = other.to_repr(); + left.as_ref().iter() + .zip(right.as_ref().iter()) + .rev() + .find_map(|(left_byte, right_byte)| match left_byte.cmp(right_byte) { + core::cmp::Ordering::Equal => None, + res => Some(res), + }) + .unwrap_or(core::cmp::Ordering::Equal) + } + } + + impl> ::core::iter::Sum for #field { + fn sum>(iter: I) -> Self { + iter.fold(Self::zero(), |acc, item| acc + item.borrow()) + } + } + + impl> ::core::iter::Product for #field { + fn product>(iter: I) -> Self { + iter.fold(Self::one(), |acc, item| acc * item.borrow()) + } + } + + impl ::core::ops::Neg for #field { + type Output = #field; + + #[inline] + fn neg(self) -> #field { + -&self + } + } + + impl #field { + pub const SIZE: usize = #num_limbs * 8; + pub const NUM_LIMBS: usize = #num_limbs; + pub(crate) const MODULUS_LIMBS: [u64; Self::NUM_LIMBS] = #modulus_limbs_ident; + pub(crate) const MODULUS_LIMBS_32: [u32; Self::NUM_LIMBS*2] = #modulus_limbs_32_ident; + const R: Self = Self(#r1); + const R2: Self = Self(#r2); + const R3: Self = Self(#r3); + + /// Returns zero, the additive identity. + #[inline(always)] + pub const fn zero() -> #field { + #field([0; Self::NUM_LIMBS]) + } + + /// Returns one, the multiplicative identity. + #[inline(always)] + pub const fn one() -> #field { + Self::R + } + + /// Converts from an integer represented in little endian + /// into its (congruent) `$field` representation. + pub const fn from_raw(val: [u64; Self::NUM_LIMBS]) -> Self { + Self(val).mul_const(&Self::R2) + } + + /// Attempts to convert a little-endian byte representation of + /// a scalar into a `$field`, failing if the input is not canonical. + pub fn from_bytes(bytes: &[u8; Self::SIZE]) -> CtOption<#field> { + let bytes: ::Repr = (*bytes).into(); + let z = ::from_repr(bytes); + z + } + + /// Converts an element of `$field` into a byte representation in + /// little-endian byte order. + pub fn to_bytes(&self) -> [u8; Self::SIZE] { + ::to_repr(self).into() + } + + + // Returns the Jacobi symbol, where the numerator and denominator + // are the element and the characteristic of the field, respectively. + // The Jacobi symbol is applicable to odd moduli + // while the Legendre symbol is applicable to prime moduli. + // They are equivalent for prime moduli. + #[inline(always)] + fn jacobi(&self) -> i64 { + crate::ff_ext::jacobi::jacobi::<#jacobi_constant>(&self.0, &#modulus_limbs_ident) + } + + // Returns the multiplicative inverse of the element. If it is zero, the method fails. + #[inline(always)] + fn invert(&self) -> subtle::CtOption { + const BYINVERTOR: crate::ff_ext::inverse::BYInverter<#by_inverter_constant> = + crate::ff_ext::inverse::BYInverter::<#by_inverter_constant>::new(&#modulus_limbs_ident, &#r2); + + if let Some(inverse) = BYINVERTOR.invert::<{ Self::NUM_LIMBS }>(&self.0) { + subtle::CtOption::new(Self(inverse), subtle::Choice::from(1)) + } else { + subtle::CtOption::new(Self::zero(), subtle::Choice::from(0)) + } + } + + #[inline(always)] + pub(crate) fn is_less_than_modulus(limbs: &[u64; Self::NUM_LIMBS]) -> bool { + let borrow = limbs.iter().enumerate().fold(0, |borrow, (i, limb)| { + crate::arithmetic::sbb(*limb, Self::MODULUS_LIMBS[i], borrow).1 + }); + (borrow as u8) & 1 == 1 + } + } + + impl ff::Field for #field { + const ZERO: Self = Self::zero(); + const ONE: Self = Self::one(); + + fn random(mut rng: impl RngCore) -> Self { + let mut wide = [0u8; Self::SIZE * 2]; + rng.fill_bytes(&mut wide); + <#field as ff::FromUniformBytes<{ #field::SIZE * 2 }>>::from_uniform_bytes(&wide) + } + + #[inline(always)] + #[must_use] + fn double(&self) -> Self { + self.double() + } + + #[inline(always)] + #[must_use] + fn square(&self) -> Self { + self.square() + } + + fn invert(&self) -> CtOption { + self.invert() + } + + #sqrt_impl + + fn sqrt_ratio(num: &Self, div: &Self) -> (Choice, Self) { + ff::helpers::sqrt_ratio_generic(num, div) + } + } + }; + + let field_repr = quote::format_ident!("Repr{}", field); + + let impl_prime_field = quote! { + + #[derive(Clone, Copy, Debug)] + pub struct #field_repr([u8; #size]); + + impl Default for #field_repr { + fn default() -> Self { + Self([0u8; #size]) + } + } + + impl From<[u8; #size]> for #field_repr { + fn from(repr: [u8; #size]) -> Self { + Self(repr) + } + } + + impl From<#field_repr> for [u8; #size] { + fn from(repr: #field_repr) -> Self { + repr.0 + } + } + + // TODO use ::core::borrow::Borrow or AsRef + impl From<#field> for #field_repr { + fn from(value: #field) -> #field_repr { + use ff::PrimeField; + value.to_repr() + } + } + + impl<'a> From<&'a #field> for #field_repr { + fn from(value: &'a #field) -> #field_repr { + use ff::PrimeField; + value.to_repr() + } + } + + impl AsMut<[u8]> for #field_repr { + fn as_mut(&mut self) -> &mut [u8] { + &mut self.0 + } + } + + impl AsRef<[u8]> for #field_repr { + fn as_ref(&self) -> &[u8] { + &self.0 + } + } + + impl core::ops::Index for #field_repr { + type Output = u8; + + fn index(&self, index: usize) -> &Self::Output { + &self.0[index] + } + } + + impl core::ops::Index> for #field_repr { + type Output = [u8]; + + fn index(&self, index: core::ops::Range) -> &Self::Output { + &self.0[index] + } + } + + impl ff::PrimeField for #field { + const NUM_BITS: u32 = #num_bits; + const CAPACITY: u32 = #num_bits-1; + const TWO_INV :Self = Self(#two_inv); + const MULTIPLICATIVE_GENERATOR: Self = Self(#mul_gen); + const S: u32 = #s; + const ROOT_OF_UNITY: Self = Self(#root_of_unity); + const ROOT_OF_UNITY_INV: Self = Self(#root_of_unity_inv); + const DELTA: Self = Self(#delta); + const MODULUS: &'static str = #modulus_str; + + type Repr = #field_repr; + + fn from_u128(v: u128) -> Self { + Self::R2 * Self( + [v as u64, (v >> 64) as u64] + .into_iter() + .chain(std::iter::repeat(0)) + .take(Self::NUM_LIMBS) + .collect::>() + .try_into() + .unwrap(), + ) + } + + fn from_repr(repr: Self::Repr) -> subtle::CtOption { + let mut el = #field::default(); + use crate::serde::endian::Endian; + crate::serde::endian::LE::from_bytes(repr.as_ref(), &mut el.0); + subtle::CtOption::new(el * Self::R2, subtle::Choice::from(Self::is_less_than_modulus(&el.0) as u8)) + } + + fn to_repr(&self) -> Self::Repr { + use crate::serde::endian::Endian; + let el = self.from_mont(); + let mut res = [0; #size]; + crate::serde::endian::LE::to_bytes(&mut res, &el); + res.into() + } + + fn is_odd(&self) -> Choice { + Choice::from(self.to_repr()[0] & 1) + } + } + }; + + let impl_serde_object = quote! { + impl crate::serde::SerdeObject for #field { + fn from_raw_bytes_unchecked(bytes: &[u8]) -> Self { + debug_assert_eq!(bytes.len(), #size); + + let inner = (0..#num_limbs) + .map(|off| { + u64::from_le_bytes(bytes[off * 8..(off + 1) * 8].try_into().unwrap()) + }) + .collect::>(); + Self(inner.try_into().unwrap()) + } + + fn from_raw_bytes(bytes: &[u8]) -> Option { + if bytes.len() != #size { + return None; + } + let elt = Self::from_raw_bytes_unchecked(bytes); + Self::is_less_than_modulus(&elt.0).then(|| elt) + } + + fn to_raw_bytes(&self) -> Vec { + let mut res = Vec::with_capacity(#num_limbs * 4); + for limb in self.0.iter() { + res.extend_from_slice(&limb.to_le_bytes()); + } + res + } + + fn read_raw_unchecked(reader: &mut R) -> Self { + let inner = [(); #num_limbs].map(|_| { + let mut buf = [0; 8]; + reader.read_exact(&mut buf).unwrap(); + u64::from_le_bytes(buf) + }); + Self(inner) + } + + fn read_raw(reader: &mut R) -> std::io::Result { + let mut inner = [0u64; #num_limbs]; + for limb in inner.iter_mut() { + let mut buf = [0; 8]; + reader.read_exact(&mut buf)?; + *limb = u64::from_le_bytes(buf); + } + let elt = Self(inner); + Self::is_less_than_modulus(&elt.0) + .then(|| elt) + .ok_or_else(|| { + std::io::Error::new( + std::io::ErrorKind::InvalidData, + "input number is not less than field modulus", + ) + }) + } + fn write_raw(&self, writer: &mut W) -> std::io::Result<()> { + for limb in self.0.iter() { + writer.write_all(&limb.to_le_bytes())?; + } + Ok(()) + } + } + }; + + #[cfg(feature = "asm")] + let impl_arith = { + if num_limbs == 4 && num_bits < 256 { + println!("implementing asm, {}", identifier); + asm::limb4::impl_arith(&field, inv64) + } else { + arith::impl_arith(&field, num_limbs, inv64) + } + }; + #[cfg(not(feature = "asm"))] + let impl_arith = arith::impl_arith(&field, num_limbs, inv64); + + let impl_arith_always_const = arith::impl_arith_always_const(&field, num_limbs, inv64); + + let impl_from_uniform_bytes = from_uniform + .iter() + .map(|size| { + quote! { + impl ff::FromUniformBytes<#size> for #field { + fn from_uniform_bytes(bytes: &[u8; #size]) -> Self { + let mut wide = [0u8; Self::SIZE * 2]; + wide[..#size].copy_from_slice(bytes); + let (a0, a1) = wide.split_at(Self::SIZE); + + let a0: [u64; Self::NUM_LIMBS] = (0..Self::NUM_LIMBS) + .map(|off| u64::from_le_bytes(a0[off * 8..(off + 1) * 8].try_into().unwrap())) + .collect::>() + .try_into() + .unwrap(); + let a0 = #field(a0); + + let a1: [u64; Self::NUM_LIMBS] = (0..Self::NUM_LIMBS) + .map(|off| u64::from_le_bytes(a1[off * 8..(off + 1) * 8].try_into().unwrap())) + .collect::>() + .try_into() + .unwrap(); + let a1 = #field(a1); + + // enforce non assmebly impl since asm is likely to be optimized for sparse fields + a0.mul_const(&Self::R2) + a1.mul_const(&Self::R3) + + } + } + } + }) + .collect::(); + + let impl_zeta = quote! { + impl ff::WithSmallOrderMulGroup<3> for #field { + const ZETA: Self = Self(#zeta); + } + }; + + let output = quote! { + #impl_arith + #impl_arith_always_const + #impl_field + #impl_prime_field + #impl_serde_object + #impl_from_uniform_bytes + #impl_zeta + }; + + output.into() +} diff --git a/derive/src/lib.rs b/derive/src/lib.rs new file mode 100644 index 00000000..4cdee00d --- /dev/null +++ b/derive/src/lib.rs @@ -0,0 +1,7 @@ +mod field; +mod utils; + +#[proc_macro] +pub fn impl_field(input: proc_macro::TokenStream) -> proc_macro::TokenStream { + field::impl_field(input) +} diff --git a/derive/src/utils.rs b/derive/src/utils.rs new file mode 100644 index 00000000..9b5cd3f8 --- /dev/null +++ b/derive/src/utils.rs @@ -0,0 +1,35 @@ +use core::ops::Shl; +use num_bigint::BigUint; +use num_traits::{One, ToPrimitive}; + +fn decompose(e: &BigUint, number_of_limbs: usize, limb_size: usize) -> Vec { + let mask = &(BigUint::one().shl(limb_size) - 1usize); + (0usize..) + .step_by(limb_size) + .take(number_of_limbs) + .map(|shift| ((e >> shift) & mask)) + .collect::>() +} + +pub(crate) fn big_to_limbs(e: &BigUint, number_of_limbs: usize) -> Vec { + decompose(e, number_of_limbs, 64) + .iter() + .map(|x| x.to_u64().unwrap()) + .collect() +} + +pub(crate) fn big_to_limbs_32(e: &BigUint, number_of_limbs: usize) -> Vec { + decompose(e, number_of_limbs, 32) + .iter() + .map(|x| x.to_u32().unwrap()) + .collect() +} + +pub(crate) fn big_to_token(e: &BigUint, number_of_limbs: usize) -> proc_macro2::TokenStream { + let limbs = big_to_limbs(e, number_of_limbs); + quote::quote! {[#(#limbs,)*]} +} + +pub(crate) fn mod_inv(e: &BigUint, modulus: &BigUint) -> BigUint { + e.modpow(&(modulus - BigUint::from(2u64)), modulus) +} diff --git a/src/arithmetic.rs b/src/arithmetic.rs index 04efdd8e..dc835177 100644 --- a/src/arithmetic.rs +++ b/src/arithmetic.rs @@ -45,30 +45,6 @@ pub(crate) const fn macx(a: u64, b: u64, c: u64) -> (u64, u64) { (res as u64, (res >> 64) as u64) } -/// Returns a >= b -#[inline(always)] -pub(crate) const fn bigint_geq(a: &[u64; 4], b: &[u64; 4]) -> bool { - if a[3] > b[3] { - return true; - } else if a[3] < b[3] { - return false; - } - if a[2] > b[2] { - return true; - } else if a[2] < b[2] { - return false; - } - if a[1] > b[1] { - return true; - } else if a[1] < b[1] { - return false; - } - if a[0] >= b[0] { - return true; - } - false -} - /// Compute a * b, returning the result. #[inline(always)] pub(crate) fn mul_512(a: [u64; 4], b: [u64; 4]) -> [u64; 8] { diff --git a/src/bn256/curve.rs b/src/bn256/curve.rs index ae245966..0160956a 100644 --- a/src/bn256/curve.rs +++ b/src/bn256/curve.rs @@ -63,14 +63,14 @@ pub(crate) fn hash_to_curve_g2<'a>(domain_prefix: &'a str) -> Box Gt { - Gt(Fq12::ONE) + Gt(Fq12::one()) } /// Doubles this group element. @@ -145,6 +145,7 @@ impl<'a, 'b> Mul<&'b Fr> for &'a Gt { for bit in other .to_repr() + .as_ref() .iter() .rev() .flat_map(|byte| (0..8).rev().map(move |i| Choice::from((byte >> i) & 1u8))) @@ -460,7 +461,7 @@ impl MillerLoopResult for Gt { fn final_exponentiation(&self) -> Gt { fn exp_by_x(f: &mut Fq12) { let x = BN_X; - let mut res = Fq12::ONE; + let mut res = Fq12::one(); for i in (0..64).rev() { res.cyclotomic_square(); if ((x >> i) & 1) == 1 { @@ -582,7 +583,7 @@ pub fn multi_miller_loop(terms: &[(&G1Affine, &G2Prepared)]) -> Gt { f.mul_by_034(&c0, &c1, &coeffs.2); } - let mut f = Fq12::ONE; + let mut f = Fq12::one(); for i in (1..SIX_U_PLUS_2_NAF.len()).rev() { if i != SIX_U_PLUS_2_NAF.len() - 1 { @@ -661,6 +662,7 @@ use rand_xorshift::XorShiftRng; #[test] fn test_pairing() { + use crate::ff::Field; let g1 = G1::generator(); let mut g2 = G2::generator(); g2 = g2.double(); @@ -716,6 +718,7 @@ fn test_pairing() { #[test] fn random_bilinearity_tests() { + use crate::ff::Field; let mut rng = XorShiftRng::from_seed([ 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, 0xe5, @@ -764,6 +767,7 @@ fn random_bilinearity_tests() { #[test] pub fn engine_tests() { + use crate::ff::Field; let mut rng = XorShiftRng::from_seed([ 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, 0xe5, diff --git a/src/bn256/fq.rs b/src/bn256/fq.rs index 0bfc37a5..02fb1ab0 100644 --- a/src/bn256/fq.rs +++ b/src/bn256/fq.rs @@ -1,294 +1,31 @@ -#[cfg(feature = "asm")] -use crate::bn256::assembly::field_arithmetic_asm; -#[cfg(not(feature = "asm"))] -use crate::{arithmetic::macx, field_arithmetic, field_specific}; - -use crate::arithmetic::{adc, bigint_geq, mac, sbb}; -use crate::extend_field_legendre; -use crate::ff::{FromUniformBytes, PrimeField, WithSmallOrderMulGroup}; -use crate::{ - field_bits, field_common, impl_add_binop_specify_output, impl_binops_additive, - impl_binops_additive_specify_output, impl_binops_multiplicative, - impl_binops_multiplicative_mixed, impl_from_u64, impl_sub_binop_specify_output, impl_sum_prod, -}; use core::convert::TryInto; -use core::fmt; -use core::ops::{Add, Mul, Neg, Sub}; +use halo2derive::impl_field; use rand::RngCore; use subtle::{Choice, ConditionallySelectable, ConstantTimeEq, CtOption}; -/// This represents an element of $\mathbb{F}_q$ where -/// -/// `p = 0x30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47` -/// -/// is the base field of the BN254 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. -#[derive(Clone, Copy, PartialEq, Eq, Hash)] -pub struct Fq(pub(crate) [u64; 4]); - -#[cfg(feature = "derive_serde")] -crate::serialize_deserialize_32_byte_primefield!(Fq); - -/// Constant representing the modulus -/// q = 0x30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47 -const MODULUS: Fq = Fq([ - 0x3c208c16d87cfd47, - 0x97816a916871ca8d, - 0xb85045b68181585d, - 0x30644e72e131a029, -]); - -/// The modulus as u32 limbs. -#[cfg(not(target_pointer_width = "64"))] -const MODULUS_LIMBS_32: [u32; 8] = [ - 0xd87c_fd47, - 0x3c20_8c16, - 0x6871_ca8d, - 0x9781_6a91, - 0x8181_585d, - 0xb850_45b6, - 0xe131_a029, - 0x3064_4e72, -]; - -/// INV = -(q^{-1} mod 2^64) mod 2^64 -const INV: u64 = 0x87d20782e4866389; - -/// R = 2^256 mod q -const R: Fq = Fq([ - 0xd35d438dc58f0d9d, - 0x0a78eb28f5c70b3d, - 0x666ea36f7879462c, - 0x0e0a77c19a07df2f, -]); - -/// R^2 = 2^512 mod q -const R2: Fq = Fq([ - 0xf32cfc5b538afa89, - 0xb5e71911d44501fb, - 0x47ab1eff0a417ff6, - 0x06d89f71cab8351f, -]); - -/// R^3 = 2^768 mod q -const R3: Fq = Fq([ - 0xb1cd6dafda1530df, - 0x62f210e6a7283db6, - 0xef7f0b0c0ada0afb, - 0x20fd6e902d592544, -]); - -pub const NEGATIVE_ONE: Fq = Fq([ - 0x68c3488912edefaa, - 0x8d087f6872aabf4f, - 0x51e1a24709081231, - 0x2259d6b14729c0fa, -]); - -const MODULUS_STR: &str = "0x30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47"; - -/// Obtained with: -/// `sage: GF(0x30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47).primitive_element()` -const MULTIPLICATIVE_GENERATOR: Fq = Fq::from_raw([0x03, 0x0, 0x0, 0x0]); - -const TWO_INV: Fq = Fq::from_raw([ - 0x9e10460b6c3e7ea4, - 0xcbc0b548b438e546, - 0xdc2822db40c0ac2e, - 0x183227397098d014, -]); - -/// `0x30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd46` -const ROOT_OF_UNITY: Fq = Fq::from_raw([ - 0x3c208c16d87cfd46, - 0x97816a916871ca8d, - 0xb85045b68181585d, - 0x30644e72e131a029, -]); - -/// `0x30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd46` -const ROOT_OF_UNITY_INV: Fq = Fq::from_raw([ - 0x3c208c16d87cfd46, - 0x97816a916871ca8d, - 0xb85045b68181585d, - 0x30644e72e131a029, -]); - -// `0x9` -const DELTA: Fq = Fq::from_raw([0x9, 0, 0, 0]); - -/// `ZETA^3 = 1 mod r` where `ZETA^2 != 1 mod r` -const ZETA: Fq = Fq::from_raw([ - 0xe4bd44e5607cfd48, - 0xc28f069fbb966e3d, - 0x5e6dd9e7e0acccb0, - 0x30644e72e131a029, -]); +use crate::{ + extend_field_legendre, field_bits, impl_add_binop_specify_output, impl_binops_additive, + impl_binops_additive_specify_output, impl_binops_calls, impl_binops_multiplicative, + impl_binops_multiplicative_mixed, impl_from_u64, impl_sub_binop_specify_output, + serialize_deserialize_primefield, +}; -impl_binops_additive!(Fq, Fq); -impl_binops_multiplicative!(Fq, Fq); -field_common!( +impl_field!( + bn256_base, Fq, - MODULUS, - INV, - MODULUS_STR, - TWO_INV, - ROOT_OF_UNITY_INV, - DELTA, - ZETA, - R, - R2, - R3 + modulus = "30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47", + mul_gen = "3", + zeta = "30644e72e131a0295e6dd9e7e0acccb0c28f069fbb966e3de4bd44e5607cfd48", + from_uniform = [64, 48], ); -impl_sum_prod!(Fq); -impl_from_u64!(Fq, R2); - -#[cfg(not(feature = "asm"))] -field_arithmetic!(Fq, MODULUS, INV, sparse); -#[cfg(feature = "asm")] -field_arithmetic_asm!(Fq, MODULUS, INV); - -#[cfg(target_pointer_width = "64")] -field_bits!(Fq, MODULUS); -#[cfg(not(target_pointer_width = "64"))] -field_bits!(Fq, MODULUS, MODULUS_LIMBS_32); - -impl Fq { - pub const fn size() -> usize { - 32 - } -} extend_field_legendre!(Fq); - -impl ff::Field for Fq { - const ZERO: Self = Self::zero(); - const ONE: Self = Self::one(); - - fn random(mut rng: impl RngCore) -> Self { - let mut random_bytes = [0; 64]; - rng.fill_bytes(&mut random_bytes[..]); - - Self::from_uniform_bytes(&random_bytes) - } - - fn double(&self) -> Self { - self.double() - } - - #[inline(always)] - fn square(&self) -> Self { - self.square() - } - - /// Computes the square root of this element, if it exists. - fn sqrt(&self) -> CtOption { - let tmp = self.pow([ - 0x4f082305b61f3f52, - 0x65e05aa45a1c72a3, - 0x6e14116da0605617, - 0x0c19139cb84c680a, - ]); - - CtOption::new(tmp, tmp.square().ct_eq(self)) - } - - fn sqrt_ratio(num: &Self, div: &Self) -> (Choice, Self) { - ff::helpers::sqrt_ratio_generic(num, div) - } - - /// Returns the multiplicative inverse of the - /// element. If it is zero, the method fails. - fn invert(&self) -> CtOption { - self.invert() - } -} - -impl ff::PrimeField for Fq { - type Repr = [u8; 32]; - - const NUM_BITS: u32 = 254; - const CAPACITY: u32 = 253; - const MODULUS: &'static str = MODULUS_STR; - const MULTIPLICATIVE_GENERATOR: Self = MULTIPLICATIVE_GENERATOR; - const ROOT_OF_UNITY: Self = ROOT_OF_UNITY; - const ROOT_OF_UNITY_INV: Self = ROOT_OF_UNITY_INV; - const TWO_INV: Self = TWO_INV; - const DELTA: Self = DELTA; - const S: u32 = 0; - - fn from_repr(repr: Self::Repr) -> CtOption { - let mut tmp = Fq([0, 0, 0, 0]); - - tmp.0[0] = u64::from_le_bytes(repr[0..8].try_into().unwrap()); - tmp.0[1] = u64::from_le_bytes(repr[8..16].try_into().unwrap()); - tmp.0[2] = u64::from_le_bytes(repr[16..24].try_into().unwrap()); - tmp.0[3] = u64::from_le_bytes(repr[24..32].try_into().unwrap()); - - // Try to subtract the modulus - let (_, borrow) = sbb(tmp.0[0], MODULUS.0[0], 0); - let (_, borrow) = sbb(tmp.0[1], MODULUS.0[1], borrow); - let (_, borrow) = sbb(tmp.0[2], MODULUS.0[2], borrow); - let (_, borrow) = sbb(tmp.0[3], MODULUS.0[3], borrow); - - // If the element is smaller than MODULUS then the - // subtraction will underflow, producing a borrow value - // of 0xffff...ffff. Otherwise, it'll be zero. - let is_some = (borrow as u8) & 1; - - // Convert to Montgomery form by computing - // (a.R^0 * R^2) / R = a.R - tmp *= &R2; - - CtOption::new(tmp, Choice::from(is_some)) - } - - fn to_repr(&self) -> Self::Repr { - let tmp: [u64; 4] = (*self).into(); - let mut res = [0; 32]; - res[0..8].copy_from_slice(&tmp[0].to_le_bytes()); - res[8..16].copy_from_slice(&tmp[1].to_le_bytes()); - res[16..24].copy_from_slice(&tmp[2].to_le_bytes()); - res[24..32].copy_from_slice(&tmp[3].to_le_bytes()); - - res - } - - fn is_odd(&self) -> Choice { - Choice::from(self.to_repr()[0] & 1) - } -} - -impl FromUniformBytes<64> for Fq { - /// Converts a 512-bit little endian integer into - /// an `Fq` by reducing by the modulus. - fn from_uniform_bytes(bytes: &[u8; 64]) -> Self { - Self::from_u512([ - u64::from_le_bytes(bytes[0..8].try_into().unwrap()), - u64::from_le_bytes(bytes[8..16].try_into().unwrap()), - u64::from_le_bytes(bytes[16..24].try_into().unwrap()), - u64::from_le_bytes(bytes[24..32].try_into().unwrap()), - u64::from_le_bytes(bytes[32..40].try_into().unwrap()), - u64::from_le_bytes(bytes[40..48].try_into().unwrap()), - u64::from_le_bytes(bytes[48..56].try_into().unwrap()), - u64::from_le_bytes(bytes[56..64].try_into().unwrap()), - ]) - } -} - -impl FromUniformBytes<48> for Fq { - fn from_uniform_bytes(bytes: &[u8; 48]) -> Self { - let repr = &mut [0u8; 64]; - (*repr)[0..48].copy_from_slice(&bytes[..48]); - Fq::from_uniform_bytes(repr) - } -} - -impl WithSmallOrderMulGroup<3> for Fq { - const ZETA: Self = ZETA; -} +impl_binops_calls!(Fq); +impl_binops_additive!(Fq, Fq); +impl_binops_multiplicative!(Fq, Fq); +field_bits!(Fq); +serialize_deserialize_primefield!(Fq); +impl_from_u64!(Fq); #[cfg(test)] mod test { @@ -299,8 +36,8 @@ mod test { crate::field_testing_suite!(Fq, "quadratic_residue"); crate::field_testing_suite!(Fq, "bits"); crate::field_testing_suite!(Fq, "serialization_check"); - crate::field_testing_suite!(Fq, "constants", MODULUS_STR); + crate::field_testing_suite!(Fq, "constants"); crate::field_testing_suite!(Fq, "sqrt"); crate::field_testing_suite!(Fq, "zeta"); - crate::field_testing_suite!(Fq, "from_uniform_bytes", 64); + crate::field_testing_suite!(Fq, "from_uniform_bytes", 64, 48); } diff --git a/src/bn256/fq12.rs b/src/bn256/fq12.rs index b77604d5..7dd08c45 100644 --- a/src/bn256/fq12.rs +++ b/src/bn256/fq12.rs @@ -1,108 +1,26 @@ use super::fq::Fq; use super::fq2::Fq2; use super::fq6::Fq6; -use crate::ff::Field; -use core::ops::{Add, Mul, Neg, Sub}; -use rand::RngCore; +use crate::impl_tower2_common; +use core::ops::{Add, Neg, Sub}; use subtle::{Choice, ConditionallySelectable, ConstantTimeEq, CtOption}; /// -GAMMA is a quadratic non-residue in Fp6. Fp12 = Fp6[X]/(X^2 + GAMMA) /// We introduce the variable w such that w^2 = -GAMMA // GAMMA = - v - /// An element of Fq12, represented by c0 + c1 * w. -#[derive(Copy, Clone, Debug, Eq, PartialEq, Default)] -pub struct Fq12 { - pub c0: Fq6, - pub c1: Fq6, -} - -impl ConditionallySelectable for Fq12 { - fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self { - Fq12 { - c0: Fq6::conditional_select(&a.c0, &b.c0, choice), - c1: Fq6::conditional_select(&a.c1, &b.c1, choice), - } - } -} - -impl ConstantTimeEq for Fq12 { - fn ct_eq(&self, other: &Self) -> Choice { - self.c0.ct_eq(&other.c0) & self.c1.ct_eq(&other.c1) - } -} - -impl Neg for Fq12 { - type Output = Fq12; - - #[inline] - fn neg(self) -> Fq12 { - -&self - } -} - -impl<'a> Neg for &'a Fq12 { - type Output = Fq12; - - #[inline] - fn neg(self) -> Fq12 { - self.neg() - } -} - -impl<'a, 'b> Sub<&'b Fq12> for &'a Fq12 { - type Output = Fq12; - - #[inline] - fn sub(self, rhs: &'b Fq12) -> Fq12 { - self.sub(rhs) - } -} - -impl<'a, 'b> Add<&'b Fq12> for &'a Fq12 { - type Output = Fq12; - - #[inline] - fn add(self, rhs: &'b Fq12) -> Fq12 { - self.add(rhs) - } -} - -impl<'a, 'b> Mul<&'b Fq12> for &'a Fq12 { - type Output = Fq12; - - #[inline] - fn mul(self, rhs: &'b Fq12) -> Fq12 { - self.mul(rhs) - } -} - use crate::{ impl_add_binop_specify_output, impl_binops_additive, impl_binops_additive_specify_output, - impl_binops_multiplicative, impl_binops_multiplicative_mixed, impl_sub_binop_specify_output, - impl_sum_prod, + impl_binops_calls, impl_binops_multiplicative, impl_binops_multiplicative_mixed, + impl_sub_binop_specify_output, impl_sum_prod, }; impl_binops_additive!(Fq12, Fq12); impl_binops_multiplicative!(Fq12, Fq12); +impl_tower2_common!(Fq6, Fq12); +impl_binops_calls!(Fq12); impl_sum_prod!(Fq12); impl Fq12 { - #[inline] - pub const fn zero() -> Self { - Fq12 { - c0: Fq6::ZERO, - c1: Fq6::ZERO, - } - } - - #[inline] - pub const fn one() -> Self { - Fq12 { - c0: Fq6::ONE, - c1: Fq6::ZERO, - } - } - pub fn mul_assign(&mut self, other: &Self) { let t0 = self.c0 * other.c0; let mut t1 = self.c1 * other.c1; @@ -134,64 +52,11 @@ impl Fq12 { self.c0 = c0; } - pub fn double(&self) -> Self { - Self { - c0: self.c0.double(), - c1: self.c1.double(), - } - } - - pub fn double_assign(&mut self) { - self.c0 = self.c0.double(); - self.c1 = self.c1.double(); - } - - pub fn add(&self, other: &Self) -> Self { - Self { - c0: self.c0 + other.c0, - c1: self.c1 + other.c1, - } - } - - pub fn sub(&self, other: &Self) -> Self { - Self { - c0: self.c0 - other.c0, - c1: self.c1 - other.c1, - } - } - - pub fn mul(&self, other: &Self) -> Self { - let mut t = *other; - t.mul_assign(self); - t - } - - pub fn square(&self) -> Self { - let mut t = *self; - t.square_assign(); - t - } - - #[inline(always)] - pub fn neg(&self) -> Self { - Self { - c0: -self.c0, - c1: -self.c1, - } - } - #[inline(always)] pub fn conjugate(&mut self) { self.c1 = -self.c1; } - // pub fn conjugate(&self) -> Self { - // Self { - // c0: self.c0, - // c1: -self.c1, - // } - // } - pub fn frobenius_map(&mut self, power: usize) { self.c0.frobenius_map(power); self.c1.frobenius_map(power); @@ -298,11 +163,12 @@ impl Fq12 { } } -impl Field for Fq12 { +#[cfg(test)] +impl ff::Field for Fq12 { const ZERO: Self = Self::zero(); const ONE: Self = Self::one(); - fn random(mut rng: impl RngCore) -> Self { + fn random(mut rng: impl rand_core::RngCore) -> Self { Fq12 { c0: Fq6::random(&mut rng), c1: Fq6::random(&mut rng), diff --git a/src/bn256/fq2.rs b/src/bn256/fq2.rs index 68924210..11a7c13a 100644 --- a/src/bn256/fq2.rs +++ b/src/bn256/fq2.rs @@ -1,8 +1,8 @@ -use super::fq::{Fq, NEGATIVE_ONE}; +use super::fq::Fq; use crate::ff::{Field, FromUniformBytes, PrimeField, WithSmallOrderMulGroup}; use crate::ff_ext::Legendre; use core::convert::TryInto; -use core::ops::{Add, Mul, Neg, Sub}; +use core::ops::{Add, Neg, Sub}; use rand::RngCore; use std::cmp::Ordering; use subtle::{Choice, ConditionallySelectable, ConstantTimeEq, CtOption}; @@ -10,168 +10,22 @@ use subtle::{Choice, ConditionallySelectable, ConstantTimeEq, CtOption}; #[cfg(feature = "derive_serde")] use serde::{Deserialize, Serialize}; -/// An element of Fq2, represented by c0 + c1 * u; where u^2 = -1. -#[derive(Copy, Clone, Debug, Eq, PartialEq)] -#[cfg_attr(feature = "derive_serde", derive(Serialize, Deserialize))] -pub struct Fq2 { - pub c0: Fq, - pub c1: Fq, -} - -/// `Fq2` elements are ordered lexicographically. -impl Ord for Fq2 { - #[inline(always)] - fn cmp(&self, other: &Fq2) -> Ordering { - match self.c1.cmp(&other.c1) { - Ordering::Greater => Ordering::Greater, - Ordering::Less => Ordering::Less, - Ordering::Equal => self.c0.cmp(&other.c0), - } - } -} - -impl PartialOrd for Fq2 { - #[inline(always)] - fn partial_cmp(&self, other: &Fq2) -> Option { - Some(self.cmp(other)) - } -} - -impl ConditionallySelectable for Fq2 { - fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self { - Fq2 { - c0: Fq::conditional_select(&a.c0, &b.c0, choice), - c1: Fq::conditional_select(&a.c1, &b.c1, choice), - } - } -} - -impl ConstantTimeEq for Fq2 { - fn ct_eq(&self, other: &Self) -> Choice { - self.c0.ct_eq(&other.c0) & self.c1.ct_eq(&other.c1) - } -} - -impl Default for Fq2 { - #[inline] - fn default() -> Self { - Self::ZERO - } -} - -impl From for [u8; 64] { - fn from(value: Fq2) -> [u8; 64] { - value.to_bytes() - } -} - -impl<'a> From<&'a Fq2> for [u8; 64] { - fn from(value: &'a Fq2) -> [u8; 64] { - value.to_bytes() - } -} - -impl Neg for Fq2 { - type Output = Fq2; - - #[inline] - fn neg(self) -> Fq2 { - -&self - } -} - -impl<'a> Neg for &'a Fq2 { - type Output = Fq2; - - #[inline] - fn neg(self) -> Fq2 { - self.neg() - } -} - -impl<'a, 'b> Sub<&'b Fq2> for &'a Fq2 { - type Output = Fq2; - - #[inline] - fn sub(self, rhs: &'b Fq2) -> Fq2 { - self.sub(rhs) - } -} - -impl<'a, 'b> Add<&'b Fq2> for &'a Fq2 { - type Output = Fq2; - - #[inline] - fn add(self, rhs: &'b Fq2) -> Fq2 { - self.add(rhs) - } -} - -impl<'a, 'b> Mul<&'b Fq2> for &'a Fq2 { - type Output = Fq2; - - #[inline] - fn mul(self, rhs: &'b Fq2) -> Fq2 { - self.mul(rhs) - } -} - use crate::{ impl_add_binop_specify_output, impl_binops_additive, impl_binops_additive_specify_output, - impl_binops_multiplicative, impl_binops_multiplicative_mixed, impl_sub_binop_specify_output, - impl_sum_prod, + impl_binops_calls, impl_binops_multiplicative, impl_binops_multiplicative_mixed, + impl_sub_binop_specify_output, impl_sum_prod, impl_tower2, impl_tower2_common, }; +impl_tower2_common!(Fq, Fq2, serde); +impl_tower2!(Fq, Fq2, ReprFq2); impl_binops_additive!(Fq2, Fq2); impl_binops_multiplicative!(Fq2, Fq2); +impl_binops_calls!(Fq2); impl_sum_prod!(Fq2); impl Fq2 { - #[inline] - pub const fn zero() -> Fq2 { - Fq2 { - c0: Fq::zero(), - c1: Fq::zero(), - } - } - - #[inline] - pub const fn one() -> Fq2 { - Fq2 { - c0: Fq::one(), - c1: Fq::zero(), - } - } - - pub const fn new(c0: Fq, c1: Fq) -> Self { - Fq2 { c0, c1 } - } - - pub const fn size() -> usize { - 64 - } - /// Attempts to convert a little-endian byte representation of - /// a scalar into a `Fq`, failing if the input is not canonical. - pub fn from_bytes(bytes: &[u8; 64]) -> CtOption { - let c0 = Fq::from_bytes(bytes[0..32].try_into().unwrap()); - let c1 = Fq::from_bytes(bytes[32..64].try_into().unwrap()); - CtOption::new( - Fq2 { - c0: c0.unwrap(), - c1: c1.unwrap(), - }, - c0.is_some() & c1.is_some(), - ) - } - - /// Converts an element of `Fq` into a byte representation in - /// little-endian byte order. - pub fn to_bytes(&self) -> [u8; 64] { - let mut res = [0u8; 64]; - let c0_bytes = self.c0.to_bytes(); - let c1_bytes = self.c1.to_bytes(); - res[0..32].copy_from_slice(&c0_bytes[..]); - res[32..64].copy_from_slice(&c1_bytes[..]); - res + pub fn double_assign(&mut self) { + self.c0 = self.c0.double(); + self.c1 = self.c1.double(); } pub fn mul_assign(&mut self, other: &Self) { @@ -197,51 +51,6 @@ impl Fq2 { self.c0 = c0 + ab; } - pub fn double(&self) -> Self { - Self { - c0: self.c0.double(), - c1: self.c1.double(), - } - } - - pub fn double_assign(&mut self) { - self.c0 = self.c0.double(); - self.c1 = self.c1.double(); - } - - pub fn add(&self, other: &Self) -> Self { - Self { - c0: self.c0.add(&other.c0), - c1: self.c1.add(&other.c1), - } - } - - pub fn sub(&self, other: &Self) -> Self { - Self { - c0: self.c0.sub(&other.c0), - c1: self.c1.sub(&other.c1), - } - } - - pub fn mul(&self, other: &Self) -> Self { - let mut t = *other; - t.mul_assign(self); - t - } - - pub fn square(&self) -> Self { - let mut t = *self; - t.square_assign(); - t - } - - pub fn neg(&self) -> Self { - Self { - c0: self.c0.neg(), - c1: self.c1.neg(), - } - } - // conjugate by negating c1 pub fn conjugate(&mut self) { self.c1 = -self.c1; @@ -260,9 +69,9 @@ impl Fq2 { let t1 = self.c1; // 8*x*i + 8*y - self.double_assign(); - self.double_assign(); - self.double_assign(); + *self = self.double(); + *self = self.double(); + *self = self.double(); // 9*y self.c0 += &t0; @@ -303,38 +112,8 @@ impl Fq2 { t1 = t1.square(); t1 + t0 } -} -impl Legendre for Fq2 { - fn legendre(&self) -> i64 { - self.norm().legendre() - } -} - -impl Field for Fq2 { - const ZERO: Self = Self::zero(); - const ONE: Self = Self::one(); - - fn random(mut rng: impl RngCore) -> Self { - Fq2 { - c0: Fq::random(&mut rng), - c1: Fq::random(&mut rng), - } - } - - fn is_zero(&self) -> Choice { - self.c0.is_zero() & self.c1.is_zero() - } - - fn square(&self) -> Self { - self.square() - } - - fn double(&self) -> Self { - self.double() - } - - fn sqrt(&self) -> CtOption { + pub fn sqrt(&self) -> CtOption { // Algorithm 9, https://eprint.iacr.org/2012/685.pdf if self.is_zero().into() { @@ -357,6 +136,7 @@ impl Field for Fq2 { a0.frobenius_map(1); a0.mul_assign(&alpha); + const NEGATIVE_ONE: Fq = Fq::ZERO.sub_const(&Fq::ONE); let neg1 = Fq2 { c0: NEGATIVE_ONE, c1: Fq::zero(), @@ -389,82 +169,6 @@ impl Field for Fq2 { } } } - - fn sqrt_ratio(num: &Self, div: &Self) -> (Choice, Self) { - ff::helpers::sqrt_ratio_generic(num, div) - } - - fn invert(&self) -> CtOption { - self.invert() - } -} - -impl From for Fq2 { - fn from(bit: bool) -> Fq2 { - if bit { - Fq2::ONE - } else { - Fq2::ZERO - } - } -} - -impl From for Fq2 { - fn from(val: u64) -> Self { - Fq2 { - c0: Fq::from(val), - c1: Fq::zero(), - } - } -} - -// This trait is only implemented to satisfy the requirement of CurveExt -impl PrimeField for Fq2 { - type Repr = Fq2Bytes; - - const MODULUS: &'static str = - "0x30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47"; - const MULTIPLICATIVE_GENERATOR: Self = Fq2 { - c0: Fq::from_raw([0x03, 0x0, 0x0, 0x0]), - c1: Fq::ZERO, - }; - const NUM_BITS: u32 = 254; - const CAPACITY: u32 = 253; - const S: u32 = 0; - // TODO: Check that we can just 0 this and forget. - const ROOT_OF_UNITY: Self = Fq2::zero(); - const ROOT_OF_UNITY_INV: Self = Fq2 { - c0: Fq::zero(), - c1: Fq::zero(), - }; - const DELTA: Self = Fq2 { - c0: Fq::zero(), - c1: Fq::zero(), - }; - const TWO_INV: Self = Fq2 { - c0: Fq::from_raw([ - 0x9e10460b6c3e7ea4, - 0xcbc0b548b438e546, - 0xdc2822db40c0ac2e, - 0x183227397098d014, - ]), - c1: Fq([0, 0, 0, 0]), - }; - - fn from_repr(repr: Self::Repr) -> CtOption { - let c0 = Fq::from_bytes(&repr.0[..32].try_into().unwrap()); - let c1 = Fq::from_bytes(&repr.0[32..].try_into().unwrap()); - // Disallow overflow representation - CtOption::new(Fq2::new(c0.unwrap(), c1.unwrap()), Choice::from(1)) - } - - fn to_repr(&self) -> Self::Repr { - Fq2Bytes(self.to_bytes()) - } - - fn is_odd(&self) -> Choice { - self.c0.is_odd() | (self.c0.is_zero() & self.c1.is_odd()) - } } impl FromUniformBytes<96> for Fq2 { @@ -475,74 +179,12 @@ impl FromUniformBytes<96> for Fq2 { } } -#[derive(Clone, Copy, Debug)] -pub struct Fq2Bytes([u8; 64]); - -impl Default for Fq2Bytes { - fn default() -> Self { - Self([0u8; 64]) - } -} - -impl AsMut<[u8]> for Fq2Bytes { - fn as_mut(&mut self) -> &mut [u8] { - &mut self.0 - } -} - -impl AsRef<[u8]> for Fq2Bytes { - fn as_ref(&self) -> &[u8] { - &self.0 - } -} - -impl crate::serde::SerdeObject for Fq2 { - fn from_raw_bytes_unchecked(bytes: &[u8]) -> Self { - debug_assert_eq!(bytes.len(), 64); - let [c0, c1] = [0, 32].map(|i| Fq::from_raw_bytes_unchecked(&bytes[i..i + 32])); - Self { c0, c1 } - } - fn from_raw_bytes(bytes: &[u8]) -> Option { - if bytes.len() != 64 { - return None; - } - let [c0, c1] = [0, 32].map(|i| Fq::from_raw_bytes(&bytes[i..i + 32])); - c0.zip(c1).map(|(c0, c1)| Self { c0, c1 }) - } - fn to_raw_bytes(&self) -> Vec { - let mut res = Vec::with_capacity(64); - for limb in self.c0.0.iter().chain(self.c1.0.iter()) { - res.extend_from_slice(&limb.to_le_bytes()); - } - res - } - fn read_raw_unchecked(reader: &mut R) -> Self { - let [c0, c1] = [(); 2].map(|_| Fq::read_raw_unchecked(reader)); - Self { c0, c1 } - } - fn read_raw(reader: &mut R) -> std::io::Result { - let c0 = Fq::read_raw(reader)?; - let c1 = Fq::read_raw(reader)?; - Ok(Self { c0, c1 }) - } - fn write_raw(&self, writer: &mut W) -> std::io::Result<()> { - self.c0.write_raw(writer)?; - self.c1.write_raw(writer) - } -} - -impl WithSmallOrderMulGroup<3> for Fq2 { - // Fq::ZETA ^2 - const ZETA: Self = Fq2 { - c0: Fq::from_raw([ - 0x5763473177fffffe, - 0xd4f263f1acdb5c4f, - 0x59e26bcea0d48bac, - 0x0000000000000000, - ]), - c1: Fq::zero(), - }; -} +const ZETA: Fq = Fq::from_raw([ + 0x5763473177fffffe, + 0xd4f263f1acdb5c4f, + 0x59e26bcea0d48bac, + 0x0000000000000000, +]); #[cfg(test)] mod test { diff --git a/src/bn256/fq6.rs b/src/bn256/fq6.rs index de01d6c8..f784bdf0 100644 --- a/src/bn256/fq6.rs +++ b/src/bn256/fq6.rs @@ -1,111 +1,26 @@ use super::fq::Fq; use super::fq2::Fq2; -use crate::ff::Field; -use core::ops::{Add, Mul, Neg, Sub}; +use crate::{ff::Field, impl_tower6}; use rand::RngCore; -use subtle::{Choice, ConditionallySelectable, ConstantTimeEq, CtOption}; +use subtle::CtOption; /// -BETA is a cubic non-residue in Fp2. Fp6 = Fp2[X]/(X^3 + BETA) /// We introduce the variable v such that v^3 = -BETA // BETA = - (u + 9) - /// An element of Fq6, represented by c0 + c1 * v + c2 * v^2. -#[derive(Copy, Clone, Debug, Eq, PartialEq, Default)] -pub struct Fq6 { - pub c0: Fq2, - pub c1: Fq2, - pub c2: Fq2, -} - -impl ConditionallySelectable for Fq6 { - fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self { - Fq6 { - c0: Fq2::conditional_select(&a.c0, &b.c0, choice), - c1: Fq2::conditional_select(&a.c1, &b.c1, choice), - c2: Fq2::conditional_select(&a.c2, &b.c2, choice), - } - } -} - -impl ConstantTimeEq for Fq6 { - fn ct_eq(&self, other: &Self) -> Choice { - self.c0.ct_eq(&other.c0) & self.c1.ct_eq(&other.c1) & self.c2.ct_eq(&other.c2) - } -} - -impl Neg for Fq6 { - type Output = Fq6; - - #[inline] - fn neg(self) -> Fq6 { - -&self - } -} - -impl<'a> Neg for &'a Fq6 { - type Output = Fq6; - - #[inline] - fn neg(self) -> Fq6 { - self.neg() - } -} - -impl<'a, 'b> Sub<&'b Fq6> for &'a Fq6 { - type Output = Fq6; - - #[inline] - fn sub(self, rhs: &'b Fq6) -> Fq6 { - self.sub(rhs) - } -} - -impl<'a, 'b> Add<&'b Fq6> for &'a Fq6 { - type Output = Fq6; - - #[inline] - fn add(self, rhs: &'b Fq6) -> Fq6 { - self.add(rhs) - } -} - -impl<'a, 'b> Mul<&'b Fq6> for &'a Fq6 { - type Output = Fq6; - - #[inline] - fn mul(self, rhs: &'b Fq6) -> Fq6 { - self.mul(rhs) - } -} - use crate::{ impl_add_binop_specify_output, impl_binops_additive, impl_binops_additive_specify_output, - impl_binops_multiplicative, impl_binops_multiplicative_mixed, impl_sub_binop_specify_output, - impl_sum_prod, + impl_binops_calls, impl_binops_multiplicative, impl_binops_multiplicative_mixed, + impl_sub_binop_specify_output, }; +impl_tower6!(Fq, Fq2, Fq6); impl_binops_additive!(Fq6, Fq6); impl_binops_multiplicative!(Fq6, Fq6); -impl_sum_prod!(Fq6); +impl_binops_calls!(Fq6); +#[cfg(test)] +crate::impl_sum_prod!(Fq6); impl Fq6 { - #[inline] - pub const fn zero() -> Self { - Fq6 { - c0: Fq2::ZERO, - c1: Fq2::ZERO, - c2: Fq2::ZERO, - } - } - - #[inline] - pub const fn one() -> Self { - Fq6 { - c0: Fq2::ONE, - c1: Fq2::ZERO, - c2: Fq2::ZERO, - } - } - pub fn mul_assign(&mut self, other: &Self) { let mut a_a = self.c0; let mut b_b = self.c1; @@ -200,56 +115,6 @@ impl Fq6 { self.c2 -= &s4; } - pub fn double(&self) -> Self { - Self { - c0: self.c0.double(), - c1: self.c1.double(), - c2: self.c2.double(), - } - } - - pub fn double_assign(&mut self) { - self.c0 = self.c0.double(); - self.c1 = self.c1.double(); - self.c2 = self.c2.double(); - } - - pub fn add(&self, other: &Self) -> Self { - Self { - c0: self.c0 + other.c0, - c1: self.c1 + other.c1, - c2: self.c2 + other.c2, - } - } - - pub fn sub(&self, other: &Self) -> Self { - Self { - c0: self.c0 - other.c0, - c1: self.c1 - other.c1, - c2: self.c2 - other.c2, - } - } - - pub fn mul(&self, other: &Self) -> Self { - let mut t = *other; - t.mul_assign(self); - t - } - - pub fn square(&self) -> Self { - let mut t = *self; - t.square_assign(); - t - } - - pub fn neg(&self) -> Self { - Self { - c0: -self.c0, - c1: -self.c1, - c2: -self.c2, - } - } - pub fn frobenius_map(&mut self, power: usize) { self.c0.frobenius_map(power); self.c1.frobenius_map(power); @@ -339,7 +204,7 @@ impl Fq6 { self.c2 = t3; } - fn invert(&self) -> CtOption { + pub fn invert(&self) -> CtOption { let mut c0 = self.c2; c0.mul_by_nonresidue(); c0 *= &self.c1; @@ -390,43 +255,6 @@ impl Fq6 { } } -impl Field for Fq6 { - const ZERO: Self = Self::zero(); - const ONE: Self = Self::one(); - - fn random(mut rng: impl RngCore) -> Self { - Fq6 { - c0: Fq2::random(&mut rng), - c1: Fq2::random(&mut rng), - c2: Fq2::random(&mut rng), - } - } - - fn is_zero(&self) -> Choice { - self.c0.is_zero() & self.c1.is_zero() - } - - fn square(&self) -> Self { - self.square() - } - - fn double(&self) -> Self { - self.double() - } - - fn sqrt(&self) -> CtOption { - unimplemented!() - } - - fn sqrt_ratio(_num: &Self, _div: &Self) -> (Choice, Self) { - unimplemented!() - } - - fn invert(&self) -> CtOption { - self.invert() - } -} - pub const FROBENIUS_COEFF_FQ6_C1: [Fq2; 6] = [ // Fq2(u + 9)**(((q^0) - 1) / 3) Fq2 { diff --git a/src/bn256/fr.rs b/src/bn256/fr.rs index a51c82c4..d21203a8 100644 --- a/src/bn256/fr.rs +++ b/src/bn256/fr.rs @@ -1,342 +1,52 @@ -#[cfg(feature = "asm")] -use crate::bn256::assembly::field_arithmetic_asm; -#[cfg(not(feature = "asm"))] -use crate::{arithmetic::macx, field_arithmetic, field_specific}; - -#[cfg(feature = "bn256-table")] -#[rustfmt::skip] -mod table; -#[cfg(feature = "bn256-table")] -#[cfg(test)] -mod table_tests; - -#[cfg(feature = "bn256-table")] -// This table should have being generated by `build.rs`; -// and stored in `src/bn256/fr/table.rs`. -pub use table::FR_TABLE; - -#[cfg(not(feature = "bn256-table"))] -use crate::impl_from_u64; - -use crate::arithmetic::{adc, bigint_geq, mac, sbb}; -use crate::extend_field_legendre; -use crate::ff::{FromUniformBytes, PrimeField, WithSmallOrderMulGroup}; -use crate::{ - field_bits, field_common, impl_add_binop_specify_output, impl_binops_additive, - impl_binops_additive_specify_output, impl_binops_multiplicative, - impl_binops_multiplicative_mixed, impl_sub_binop_specify_output, impl_sum_prod, -}; use core::convert::TryInto; -use core::fmt; -use core::ops::{Add, Mul, Neg, Sub}; +use halo2derive::impl_field; use rand::RngCore; use subtle::{Choice, ConditionallySelectable, ConstantTimeEq, CtOption}; -/// This represents an element of $\mathbb{F}_r$ where -/// -/// `r = 0x30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001` -/// -/// is the scalar field of the BN254 curve. -// The internal representation of this type is four 64-bit unsigned -// integers in little-endian order. `Fr` values are always in -// Montgomery form; i.e., Fr(a) = aR mod r, with R = 2^256. -#[derive(Clone, Copy, PartialEq, Eq, Hash)] -pub struct Fr(pub(crate) [u64; 4]); - -#[cfg(feature = "derive_serde")] -crate::serialize_deserialize_32_byte_primefield!(Fr); - -/// Constant representing the modulus -/// r = 0x30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001 -const MODULUS: Fr = Fr([ - 0x43e1f593f0000001, - 0x2833e84879b97091, - 0xb85045b68181585d, - 0x30644e72e131a029, -]); - -/// The modulus as u32 limbs. -#[cfg(not(target_pointer_width = "64"))] -const MODULUS_LIMBS_32: [u32; 8] = [ - 0xf000_0001, - 0x43e1_f593, - 0x79b9_7091, - 0x2833_e848, - 0x8181_585d, - 0xb850_45b6, - 0xe131_a029, - 0x3064_4e72, -]; - -const MODULUS_STR: &str = "0x30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001"; - -/// INV = -(r^{-1} mod 2^64) mod 2^64 -const INV: u64 = 0xc2e1f593efffffff; - -/// `R = 2^256 mod r` -/// `0xe0a77c19a07df2f666ea36f7879462e36fc76959f60cd29ac96341c4ffffffb` -const R: Fr = Fr([ - 0xac96341c4ffffffb, - 0x36fc76959f60cd29, - 0x666ea36f7879462e, - 0x0e0a77c19a07df2f, -]); - -/// `R^2 = 2^512 mod r` -/// `0x216d0b17f4e44a58c49833d53bb808553fe3ab1e35c59e31bb8e645ae216da7` -const R2: Fr = Fr([ - 0x1bb8e645ae216da7, - 0x53fe3ab1e35c59e3, - 0x8c49833d53bb8085, - 0x0216d0b17f4e44a5, -]); - -/// `R^3 = 2^768 mod r` -/// `0xcf8594b7fcc657c893cc664a19fcfed2a489cbe1cfbb6b85e94d8e1b4bf0040` -const R3: Fr = Fr([ - 0x5e94d8e1b4bf0040, - 0x2a489cbe1cfbb6b8, - 0x893cc664a19fcfed, - 0x0cf8594b7fcc657c, -]); - -/// `GENERATOR = 7 mod r` is a generator of the `r - 1` order multiplicative -/// subgroup, or in other words a primitive root of the field. -const GENERATOR: Fr = Fr::from_raw([0x07, 0x00, 0x00, 0x00]); - -const S: u32 = 28; - -/// GENERATOR^t where t * 2^s + 1 = r -/// with t odd. In other words, this -/// is a 2^s root of unity. -/// `0x3ddb9f5166d18b798865ea93dd31f743215cf6dd39329c8d34f1ed960c37c9c` -const ROOT_OF_UNITY: Fr = Fr::from_raw([ - 0xd34f1ed960c37c9c, - 0x3215cf6dd39329c8, - 0x98865ea93dd31f74, - 0x03ddb9f5166d18b7, -]); - -/// 1 / 2 mod r -const TWO_INV: Fr = Fr::from_raw([ - 0xa1f0fac9f8000001, - 0x9419f4243cdcb848, - 0xdc2822db40c0ac2e, - 0x183227397098d014, -]); - -/// 1 / ROOT_OF_UNITY mod r -const ROOT_OF_UNITY_INV: Fr = Fr::from_raw([ - 0x0ed3e50a414e6dba, - 0xb22625f59115aba7, - 0x1bbe587180f34361, - 0x048127174daabc26, -]); - -/// GENERATOR^{2^s} where t * 2^s + 1 = r with t odd. In other words, this is a t root of unity. -/// 0x09226b6e22c6f0ca64ec26aad4c86e715b5f898e5e963f25870e56bbe533e9a2 -const DELTA: Fr = Fr::from_raw([ - 0x870e56bbe533e9a2, - 0x5b5f898e5e963f25, - 0x64ec26aad4c86e71, - 0x09226b6e22c6f0ca, -]); - -/// `ZETA^3 = 1 mod r` where `ZETA^2 != 1 mod r` -const ZETA: Fr = Fr::from_raw([ - 0xb8ca0b2d36636f23, - 0xcc37a73fec2bc5e9, - 0x048b6e193fd84104, - 0x30644e72e131a029, -]); +use crate::{ + extend_field_legendre, field_bits, impl_add_binop_specify_output, impl_binops_additive, + impl_binops_additive_specify_output, impl_binops_calls, impl_binops_multiplicative, + impl_binops_multiplicative_mixed, impl_sub_binop_specify_output, + serialize_deserialize_primefield, +}; -impl_binops_additive!(Fr, Fr); -impl_binops_multiplicative!(Fr, Fr); -field_common!( +impl_field!( + bn256_scalar, Fr, - MODULUS, - INV, - MODULUS_STR, - TWO_INV, - ROOT_OF_UNITY_INV, - DELTA, - ZETA, - R, - R2, - R3 + modulus = "30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001", + mul_gen = "7", + zeta = "30644e72e131a029048b6e193fd84104cc37a73fec2bc5e9b8ca0b2d36636f23", + from_uniform = [64, 48], ); -impl_sum_prod!(Fr); + extend_field_legendre!(Fr); +impl_binops_calls!(Fr); +impl_binops_additive!(Fr, Fr); +impl_binops_multiplicative!(Fr, Fr); +field_bits!(Fr); +serialize_deserialize_primefield!(Fr); +#[cfg(feature = "bn256-table")] +pub use table::FR_TABLE; #[cfg(not(feature = "bn256-table"))] -impl_from_u64!(Fr, R2); +crate::impl_from_u64!(Fr); #[cfg(feature = "bn256-table")] -// A field element is represented in the montgomery form -- this allows for cheap mul_mod operations. -// The catch is, if we build an Fr element, regardless of its format, we need to perform one big integer multiplication: -// -// Fr([val, 0, 0, 0]) * R2 -// -// When the "bn256-table" feature is enabled, we read the Fr element directly from the table. -// This avoids a big integer multiplication. -// -// We use a table with 2^16 entries when the element is smaller than 2^16. impl From for Fr { fn from(val: u64) -> Fr { if val < 65536 { FR_TABLE[val as usize] } else { - Fr([val, 0, 0, 0]) * R2 + Self([val, 0, 0, 0]) * Fr::R2 } } } -#[cfg(not(feature = "asm"))] -field_arithmetic!(Fr, MODULUS, INV, sparse); -#[cfg(feature = "asm")] -field_arithmetic_asm!(Fr, MODULUS, INV); - -#[cfg(target_pointer_width = "64")] -field_bits!(Fr, MODULUS); -#[cfg(not(target_pointer_width = "64"))] -field_bits!(Fr, MODULUS, MODULUS_LIMBS_32); - -impl Fr { - pub const fn size() -> usize { - 32 - } -} - -impl ff::Field for Fr { - const ZERO: Self = Self::zero(); - const ONE: Self = Self::one(); - - fn random(mut rng: impl RngCore) -> Self { - Self::from_u512([ - rng.next_u64(), - rng.next_u64(), - rng.next_u64(), - rng.next_u64(), - rng.next_u64(), - rng.next_u64(), - rng.next_u64(), - rng.next_u64(), - ]) - } - - fn double(&self) -> Self { - self.double() - } - - #[inline(always)] - fn square(&self) -> Self { - self.square() - } - - /// Returns the multiplicative inverse of the - /// element. If it is zero, the method fails. - fn invert(&self) -> CtOption { - self.invert() - } - - fn sqrt(&self) -> CtOption { - /// `(t - 1) // 2` where t * 2^s + 1 = p with t odd. - const T_MINUS1_OVER2: [u64; 4] = [ - 0xcdcb848a1f0fac9f, - 0x0c0ac2e9419f4243, - 0x098d014dc2822db4, - 0x0000000183227397, - ]; - ff::helpers::sqrt_tonelli_shanks(self, T_MINUS1_OVER2) - } - - fn sqrt_ratio(num: &Self, div: &Self) -> (Choice, Self) { - ff::helpers::sqrt_ratio_generic(num, div) - } -} - -impl ff::PrimeField for Fr { - type Repr = [u8; 32]; - - const NUM_BITS: u32 = 254; - const CAPACITY: u32 = 253; - const MODULUS: &'static str = MODULUS_STR; - const MULTIPLICATIVE_GENERATOR: Self = GENERATOR; - const ROOT_OF_UNITY: Self = ROOT_OF_UNITY; - const ROOT_OF_UNITY_INV: Self = ROOT_OF_UNITY_INV; - const TWO_INV: Self = TWO_INV; - const DELTA: Self = DELTA; - const S: u32 = S; - - fn from_repr(repr: Self::Repr) -> CtOption { - let mut tmp = Fr([0, 0, 0, 0]); - - tmp.0[0] = u64::from_le_bytes(repr[0..8].try_into().unwrap()); - tmp.0[1] = u64::from_le_bytes(repr[8..16].try_into().unwrap()); - tmp.0[2] = u64::from_le_bytes(repr[16..24].try_into().unwrap()); - tmp.0[3] = u64::from_le_bytes(repr[24..32].try_into().unwrap()); - - // Try to subtract the modulus - let (_, borrow) = sbb(tmp.0[0], MODULUS.0[0], 0); - let (_, borrow) = sbb(tmp.0[1], MODULUS.0[1], borrow); - let (_, borrow) = sbb(tmp.0[2], MODULUS.0[2], borrow); - let (_, borrow) = sbb(tmp.0[3], MODULUS.0[3], borrow); - - // If the element is smaller than MODULUS then the - // subtraction will underflow, producing a borrow value - // of 0xffff...ffff. Otherwise, it'll be zero. - let is_some = (borrow as u8) & 1; - - // Convert to Montgomery form by computing - // (a.R^0 * R^2) / R = a.R - tmp *= &R2; - - CtOption::new(tmp, Choice::from(is_some)) - } - - fn to_repr(&self) -> Self::Repr { - let tmp: [u64; 4] = (*self).into(); - let mut res = [0; 32]; - res[0..8].copy_from_slice(&tmp[0].to_le_bytes()); - res[8..16].copy_from_slice(&tmp[1].to_le_bytes()); - res[16..24].copy_from_slice(&tmp[2].to_le_bytes()); - res[24..32].copy_from_slice(&tmp[3].to_le_bytes()); - - res - } - - fn is_odd(&self) -> Choice { - Choice::from(self.to_repr()[0] & 1) - } -} - -impl FromUniformBytes<64> for Fr { - /// Converts a 512-bit little endian integer into - /// an `Fr` by reducing by the modulus. - fn from_uniform_bytes(bytes: &[u8; 64]) -> Self { - Self::from_u512([ - u64::from_le_bytes(bytes[0..8].try_into().unwrap()), - u64::from_le_bytes(bytes[8..16].try_into().unwrap()), - u64::from_le_bytes(bytes[16..24].try_into().unwrap()), - u64::from_le_bytes(bytes[24..32].try_into().unwrap()), - u64::from_le_bytes(bytes[32..40].try_into().unwrap()), - u64::from_le_bytes(bytes[40..48].try_into().unwrap()), - u64::from_le_bytes(bytes[48..56].try_into().unwrap()), - u64::from_le_bytes(bytes[56..64].try_into().unwrap()), - ]) - } -} - -impl FromUniformBytes<48> for Fr { - fn from_uniform_bytes(bytes: &[u8; 48]) -> Self { - let repr = &mut [0u8; 64]; - (*repr)[0..48].copy_from_slice(&bytes[..48]); - Fr::from_uniform_bytes(repr) - } -} - -impl WithSmallOrderMulGroup<3> for Fr { - const ZETA: Self = ZETA; -} +#[cfg(feature = "bn256-table")] +#[rustfmt::skip] +mod table; +#[cfg(feature = "bn256-table")] +#[cfg(test)] +mod table_tests; #[cfg(test)] mod test { @@ -348,22 +58,8 @@ mod test { crate::field_testing_suite!(Fr, "quadratic_residue"); crate::field_testing_suite!(Fr, "bits"); crate::field_testing_suite!(Fr, "serialization_check"); - crate::field_testing_suite!(Fr, "constants", MODULUS_STR); + crate::field_testing_suite!(Fr, "constants"); crate::field_testing_suite!(Fr, "sqrt"); crate::field_testing_suite!(Fr, "zeta"); crate::field_testing_suite!(Fr, "from_uniform_bytes", 64); - - #[test] - fn bench_fr_from_u16() { - use ark_std::{end_timer, start_timer}; - - let repeat = 10000000; - let mut rng = ark_std::test_rng(); - let base = (0..repeat).map(|_| (rng.next_u32() % (1 << 16)) as u64); - - let timer = start_timer!(|| format!("generate {repeat} Bn256 scalar field elements")); - let _res: Vec<_> = base.map(Fr::from).collect(); - - end_timer!(timer); - } } diff --git a/src/bn256/mod.rs b/src/bn256/mod.rs index 3530b765..45c9f942 100644 --- a/src/bn256/mod.rs +++ b/src/bn256/mod.rs @@ -6,9 +6,6 @@ mod fq2; mod fq6; mod fr; -#[cfg(feature = "asm")] -mod assembly; - pub use curve::*; pub use engine::*; pub use fq::*; diff --git a/src/derive/curve.rs b/src/derive/curve.rs index 7621d9db..983dfb88 100644 --- a/src/derive/curve.rs +++ b/src/derive/curve.rs @@ -122,9 +122,9 @@ macro_rules! new_curve_impl { #[allow(non_upper_case_globals)] const [< $name _COMPRESSED_SIZE >]: usize = if $spare_bits == 0 { - $base::size() + 1 + $base::SIZE + 1 } else { - $base::size() + $base::SIZE }; #[derive(Copy, Clone, PartialEq, Eq)] @@ -220,8 +220,8 @@ macro_rules! new_curve_impl { tmp[[< $name _FLAG_BYTE_INDEX>]] &= ![< $name _FLAG_BITS >]; // Get x-coordinate - let mut xbytes = [0u8; $base::size()]; - xbytes.copy_from_slice(&tmp[..$base::size()]); + let mut xbytes = [0u8; $base::SIZE]; + xbytes.copy_from_slice(&tmp[..$base::SIZE]); @@ -281,7 +281,7 @@ macro_rules! new_curve_impl { let mut res = [0; [< $name _COMPRESSED_SIZE >]]; let x_bytes = $base::conditional_select(&self.x, &$base::zero(), self.is_identity()).to_bytes(); - res[..$base::size()].copy_from_slice(&x_bytes); + res[..$base::SIZE].copy_from_slice(&x_bytes); // Set identity flag if necessary. res[ [< $name _FLAG_BYTE_INDEX>]] |= u8::conditional_select(&0u8, &IDENTITY_MASK, self.is_identity()); @@ -343,7 +343,7 @@ macro_rules! new_curve_impl { paste::paste! { #[derive(Copy, Clone)] - pub struct [< $name Uncompressed >]([u8; 2*$base::size()]); + pub struct [< $name Uncompressed >]([u8; 2*$base::SIZE]); impl std::fmt::Debug for [< $name Uncompressed >] { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { self.0[..].fmt(f) @@ -352,7 +352,7 @@ macro_rules! new_curve_impl { impl Default for [< $name Uncompressed >] { fn default() -> Self { - [< $name Uncompressed >]([0; 2*$base::size() ]) + [< $name Uncompressed >]([0; 2*$base::SIZE ]) } } @@ -393,8 +393,8 @@ macro_rules! new_curve_impl { fn from_uncompressed_unchecked(bytes: &Self::Uncompressed) -> CtOption { let mut bytes = bytes.0; - let flag_idx_x = $base::size() -1; - let flag_idx_y = 2* $base::size() -1; + let flag_idx_x = $base::SIZE -1; + let flag_idx_y = 2* $base::SIZE -1; // In the uncompressed format, the spare bits in both coordinates must be 0. let mut any_flag_set = Choice::from(0u8); @@ -418,14 +418,14 @@ macro_rules! new_curve_impl { // Get x, y coordinates. - let mut repr = [0u8; $base::size()]; + let mut repr = [0u8; $base::SIZE]; let x = { - repr.copy_from_slice(&bytes[0..$base::size()]); + repr.copy_from_slice(&bytes[0..$base::SIZE]); $base::from_bytes(&repr) }; let y = { - repr.copy_from_slice(&bytes[$base::size()..2*$base::size()]); + repr.copy_from_slice(&bytes[$base::SIZE..2*$base::SIZE]); $base::from_bytes(&repr) }; @@ -451,8 +451,6 @@ macro_rules! new_curve_impl { is_identity, ); - eprintln!("Is the point valid? {:?}", is_valid); - CtOption::new( p, is_valid @@ -462,12 +460,12 @@ macro_rules! new_curve_impl { } fn to_uncompressed(&self) -> Self::Uncompressed { - let mut res = [0; 2*$base::size()]; + let mut res = [0; 2*$base::SIZE]; - res[0..$base::size()].copy_from_slice( + res[0..$base::SIZE].copy_from_slice( &$base::conditional_select(&self.x, &$base::zero(), self.is_identity()).to_bytes()[..], ); - res[$base::size().. 2*$base::size()].copy_from_slice( + res[$base::SIZE.. 2*$base::SIZE].copy_from_slice( &$base::conditional_select(&self.y, &$base::zero(), self.is_identity()).to_bytes()[..], ); @@ -916,17 +914,17 @@ macro_rules! new_curve_impl { impl $crate::serde::SerdeObject for $name { fn from_raw_bytes_unchecked(bytes: &[u8]) -> Self { - debug_assert_eq!(bytes.len(), 3 * $base::size()); + debug_assert_eq!(bytes.len(), 3 * $base::SIZE); let [x, y, z] = [0, 1, 2] - .map(|i| $base::from_raw_bytes_unchecked(&bytes[i * $base::size()..(i + 1) * $base::size()])); + .map(|i| $base::from_raw_bytes_unchecked(&bytes[i * $base::SIZE..(i + 1) * $base::SIZE])); Self { x, y, z } } fn from_raw_bytes(bytes: &[u8]) -> Option { - if bytes.len() != 3 * $base::size() { + if bytes.len() != 3 * $base::SIZE { return None; } let [x, y, z] = - [0, 1, 2].map(|i| $base::from_raw_bytes(&bytes[i * $base::size()..(i + 1) * $base::size()])); + [0, 1, 2].map(|i| $base::from_raw_bytes(&bytes[i * $base::SIZE..(i + 1) * $base::SIZE])); x.zip(y).zip(z).and_then(|((x, y), z)| { let res = Self { x, y, z }; // Check that the point is on the curve. @@ -934,7 +932,7 @@ macro_rules! new_curve_impl { }) } fn to_raw_bytes(&self) -> Vec { - let mut res = Vec::with_capacity(3 * $base::size()); + let mut res = Vec::with_capacity(3 * $base::SIZE); Self::write_raw(self, &mut res).unwrap(); res } @@ -1018,16 +1016,16 @@ macro_rules! new_curve_impl { impl $crate::serde::SerdeObject for $name_affine { fn from_raw_bytes_unchecked(bytes: &[u8]) -> Self { - debug_assert_eq!(bytes.len(), 2 * $base::size()); + debug_assert_eq!(bytes.len(), 2 * $base::SIZE); let [x, y] = - [0, $base::size()].map(|i| $base::from_raw_bytes_unchecked(&bytes[i..i + $base::size()])); + [0, $base::SIZE].map(|i| $base::from_raw_bytes_unchecked(&bytes[i..i + $base::SIZE])); Self { x, y } } fn from_raw_bytes(bytes: &[u8]) -> Option { - if bytes.len() != 2 * $base::size() { + if bytes.len() != 2 * $base::SIZE { return None; } - let [x, y] = [0, $base::size()].map(|i| $base::from_raw_bytes(&bytes[i..i + $base::size()])); + let [x, y] = [0, $base::SIZE].map(|i| $base::from_raw_bytes(&bytes[i..i + $base::SIZE])); x.zip(y).and_then(|(x, y)| { let res = Self { x, y }; // Check that the point is on the curve. @@ -1035,7 +1033,7 @@ macro_rules! new_curve_impl { }) } fn to_raw_bytes(&self) -> Vec { - let mut res = Vec::with_capacity(2 * $base::size()); + let mut res = Vec::with_capacity(2 * $base::SIZE); Self::write_raw(self, &mut res).unwrap(); res } @@ -1398,6 +1396,7 @@ macro_rules! new_curve_impl { let mut acc = $name::identity(); for bit in other .to_repr() + .as_ref() .iter() .rev() .flat_map(|byte| (0..8).rev().map(move |i| Choice::from((byte >> i) & 1u8))) @@ -1474,6 +1473,7 @@ macro_rules! new_curve_impl { for bit in other .to_repr() + .as_ref() .iter() .rev() .flat_map(|byte| (0..8).rev().map(move |i| Choice::from((byte >> i) & 1u8))) diff --git a/src/derive/field.rs b/src/derive/field.rs deleted file mode 100644 index e67b8289..00000000 --- a/src/derive/field.rs +++ /dev/null @@ -1,790 +0,0 @@ -#[macro_export] -macro_rules! impl_from_u64 { - ($field:ident, $r2:ident) => { - impl From for $field { - fn from(val: u64) -> $field { - $field([val, 0, 0, 0]) * $r2 - } - } - }; -} - -#[macro_export] -macro_rules! field_common { - ( - $field:ident, - $modulus:ident, - $inv:ident, - $modulus_str:ident, - $two_inv:ident, - $root_of_unity_inv:ident, - $delta:ident, - $zeta:ident, - $r:ident, - $r2:ident, - $r3:ident - ) => { - /// Bernstein-Yang modular multiplicative inverter created for the modulus equal to - /// the characteristic of the field to invert positive integers in the Montgomery form. - const BYINVERTOR: $crate::ff_ext::inverse::BYInverter<6> = - $crate::ff_ext::inverse::BYInverter::<6>::new(&$modulus.0, &$r2.0); - - impl $field { - /// Returns zero, the additive identity. - #[inline] - pub const fn zero() -> $field { - $field([0, 0, 0, 0]) - } - - /// Returns one, the multiplicative identity. - #[inline] - pub const fn one() -> $field { - $r - } - - /// Returns the multiplicative inverse of the - /// element. If it is zero, the method fails. - #[inline(always)] - pub fn invert(&self) -> CtOption { - if let Some(inverse) = BYINVERTOR.invert(&self.0) { - CtOption::new(Self(inverse), Choice::from(1)) - } else { - CtOption::new(Self::zero(), Choice::from(0)) - } - } - - // Returns the Jacobi symbol, where the numerator and denominator - // are the element and the characteristic of the field, respectively. - // The Jacobi symbol is applicable to odd moduli - // while the Legendre symbol is applicable to prime moduli. - // They are equivalent for prime moduli. - #[inline(always)] - pub fn jacobi(&self) -> i64 { - $crate::ff_ext::jacobi::jacobi::<5>(&self.0, &$modulus.0) - } - - const fn montgomery_form(val: [u64; 4], r: $field) -> $field { - // Converts a 4 64-bit limb value into its congruent field representation. - // If `val` represents a 256 bit value then `r` should be R^2, - // if `val` represents the 256 MSB of a 512 bit value, then `r` should be R^3. - - let (r0, carry) = mac(0, val[0], r.0[0], 0); - let (r1, carry) = mac(0, val[0], r.0[1], carry); - let (r2, carry) = mac(0, val[0], r.0[2], carry); - let (r3, r4) = mac(0, val[0], r.0[3], carry); - - let (r1, carry) = mac(r1, val[1], r.0[0], 0); - let (r2, carry) = mac(r2, val[1], r.0[1], carry); - let (r3, carry) = mac(r3, val[1], r.0[2], carry); - let (r4, r5) = mac(r4, val[1], r.0[3], carry); - - let (r2, carry) = mac(r2, val[2], r.0[0], 0); - let (r3, carry) = mac(r3, val[2], r.0[1], carry); - let (r4, carry) = mac(r4, val[2], r.0[2], carry); - let (r5, r6) = mac(r5, val[2], r.0[3], carry); - - let (r3, carry) = mac(r3, val[3], r.0[0], 0); - let (r4, carry) = mac(r4, val[3], r.0[1], carry); - let (r5, carry) = mac(r5, val[3], r.0[2], carry); - let (r6, r7) = mac(r6, val[3], r.0[3], carry); - - // Montgomery reduction - let k = r0.wrapping_mul($inv); - let (_, carry) = mac(r0, k, $modulus.0[0], 0); - let (r1, carry) = mac(r1, k, $modulus.0[1], carry); - let (r2, carry) = mac(r2, k, $modulus.0[2], carry); - let (r3, carry) = mac(r3, k, $modulus.0[3], carry); - let (r4, carry2) = adc(r4, 0, carry); - - let k = r1.wrapping_mul($inv); - let (_, carry) = mac(r1, k, $modulus.0[0], 0); - let (r2, carry) = mac(r2, k, $modulus.0[1], carry); - let (r3, carry) = mac(r3, k, $modulus.0[2], carry); - let (r4, carry) = mac(r4, k, $modulus.0[3], carry); - let (r5, carry2) = adc(r5, carry2, carry); - - let k = r2.wrapping_mul($inv); - let (_, carry) = mac(r2, k, $modulus.0[0], 0); - let (r3, carry) = mac(r3, k, $modulus.0[1], carry); - let (r4, carry) = mac(r4, k, $modulus.0[2], carry); - let (r5, carry) = mac(r5, k, $modulus.0[3], carry); - let (r6, carry2) = adc(r6, carry2, carry); - - let k = r3.wrapping_mul($inv); - let (_, carry) = mac(r3, k, $modulus.0[0], 0); - let (r4, carry) = mac(r4, k, $modulus.0[1], carry); - let (r5, carry) = mac(r5, k, $modulus.0[2], carry); - let (r6, carry) = mac(r6, k, $modulus.0[3], carry); - let (r7, carry2) = adc(r7, carry2, carry); - - // Result may be within MODULUS of the correct value - let (d0, borrow) = sbb(r4, $modulus.0[0], 0); - let (d1, borrow) = sbb(r5, $modulus.0[1], borrow); - let (d2, borrow) = sbb(r6, $modulus.0[2], borrow); - let (d3, borrow) = sbb(r7, $modulus.0[3], borrow); - let (_, borrow) = sbb(carry2, 0, borrow); - let (d0, carry) = adc(d0, $modulus.0[0] & borrow, 0); - let (d1, carry) = adc(d1, $modulus.0[1] & borrow, carry); - let (d2, carry) = adc(d2, $modulus.0[2] & borrow, carry); - let (d3, _) = adc(d3, $modulus.0[3] & borrow, carry); - - $field([d0, d1, d2, d3]) - } - - fn from_u512(limbs: [u64; 8]) -> $field { - // We reduce an arbitrary 512-bit number by decomposing it into two 256-bit digits - // with the higher bits multiplied by 2^256. Thus, we perform two reductions - // - // 1. the lower bits are multiplied by R^2, as normal - // 2. the upper bits are multiplied by R^2 * 2^256 = R^3 - // - // and computing their sum in the field. It remains to see that arbitrary 256-bit - // numbers can be placed into Montgomery form safely using the reduction. The - // reduction works so long as the product is less than R=2^256 multiplied by - // the modulus. This holds because for any `c` smaller than the modulus, we have - // that (2^256 - 1)*c is an acceptable product for the reduction. Therefore, the - // reduction always works so long as `c` is in the field; in this case it is either the - // constant `R2` or `R3`. - - let lower_256 = [limbs[0], limbs[1], limbs[2], limbs[3]]; - let upper_256 = [limbs[4], limbs[5], limbs[6], limbs[7]]; - - Self::montgomery_form(lower_256, $r2) + Self::montgomery_form(upper_256, $r3) - } - - /// Converts from an integer represented in little endian - /// into its (congruent) `$field` representation. - pub const fn from_raw(val: [u64; 4]) -> Self { - Self::montgomery_form(val, $r2) - } - - /// Attempts to convert a little-endian byte representation of - /// a scalar into a `Fr`, failing if the input is not canonical. - pub fn from_bytes(bytes: &[u8; 32]) -> CtOption<$field> { - ::from_repr(*bytes) - } - - /// Converts an element of `Fr` into a byte representation in - /// little-endian byte order. - pub fn to_bytes(&self) -> [u8; 32] { - ::to_repr(self) - } - - /// Lexicographic comparison of Montgomery forms. - #[inline(always)] - const fn is_less_than(x: &[u64; 4], y: &[u64; 4]) -> bool { - let (_, borrow) = sbb(x[0], y[0], 0); - let (_, borrow) = sbb(x[1], y[1], borrow); - let (_, borrow) = sbb(x[2], y[2], borrow); - let (_, borrow) = sbb(x[3], y[3], borrow); - borrow >> 63 == 1 - } - } - - impl fmt::Debug for $field { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let tmp = self.to_repr(); - write!(f, "0x")?; - for &b in tmp.iter().rev() { - write!(f, "{:02x}", b)?; - } - Ok(()) - } - } - - impl Default for $field { - #[inline] - fn default() -> Self { - Self::zero() - } - } - - impl From for $field { - fn from(bit: bool) -> $field { - if bit { - $field::one() - } else { - $field::zero() - } - } - } - - impl ConstantTimeEq for $field { - fn ct_eq(&self, other: &Self) -> Choice { - self.0[0].ct_eq(&other.0[0]) - & self.0[1].ct_eq(&other.0[1]) - & self.0[2].ct_eq(&other.0[2]) - & self.0[3].ct_eq(&other.0[3]) - } - } - - impl core::cmp::Ord for $field { - fn cmp(&self, other: &Self) -> core::cmp::Ordering { - let left = self.to_repr(); - let right = other.to_repr(); - left.iter() - .zip(right.iter()) - .rev() - .find_map(|(left_byte, right_byte)| match left_byte.cmp(right_byte) { - core::cmp::Ordering::Equal => None, - res => Some(res), - }) - .unwrap_or(core::cmp::Ordering::Equal) - } - } - - impl core::cmp::PartialOrd for $field { - fn partial_cmp(&self, other: &Self) -> Option { - Some(self.cmp(other)) - } - } - - impl ConditionallySelectable for $field { - fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self { - $field([ - u64::conditional_select(&a.0[0], &b.0[0], choice), - u64::conditional_select(&a.0[1], &b.0[1], choice), - u64::conditional_select(&a.0[2], &b.0[2], choice), - u64::conditional_select(&a.0[3], &b.0[3], choice), - ]) - } - } - - impl<'a> Neg for &'a $field { - type Output = $field; - - #[inline] - fn neg(self) -> $field { - self.neg() - } - } - - impl Neg for $field { - type Output = $field; - - #[inline] - fn neg(self) -> $field { - -&self - } - } - - impl<'a, 'b> Sub<&'b $field> for &'a $field { - type Output = $field; - - #[inline] - fn sub(self, rhs: &'b $field) -> $field { - self.sub(rhs) - } - } - - impl<'a, 'b> Add<&'b $field> for &'a $field { - type Output = $field; - - #[inline] - fn add(self, rhs: &'b $field) -> $field { - self.add(rhs) - } - } - - impl<'a, 'b> Mul<&'b $field> for &'a $field { - type Output = $field; - - #[inline] - fn mul(self, rhs: &'b $field) -> $field { - self.mul(rhs) - } - } - - impl From<[u64; 4]> for $field { - fn from(digits: [u64; 4]) -> Self { - Self::from_raw(digits) - } - } - - impl From<$field> for [u8; 32] { - fn from(value: $field) -> [u8; 32] { - value.to_repr() - } - } - - impl<'a> From<&'a $field> for [u8; 32] { - fn from(value: &'a $field) -> [u8; 32] { - value.to_repr() - } - } - - impl $crate::serde::SerdeObject for $field { - fn from_raw_bytes_unchecked(bytes: &[u8]) -> Self { - debug_assert_eq!(bytes.len(), 32); - let inner = - [0, 8, 16, 24].map(|i| u64::from_le_bytes(bytes[i..i + 8].try_into().unwrap())); - Self(inner) - } - fn from_raw_bytes(bytes: &[u8]) -> Option { - if bytes.len() != 32 { - return None; - } - let elt = Self::from_raw_bytes_unchecked(bytes); - Self::is_less_than(&elt.0, &$modulus.0).then(|| elt) - } - fn to_raw_bytes(&self) -> Vec { - let mut res = Vec::with_capacity(32); - for limb in self.0.iter() { - res.extend_from_slice(&limb.to_le_bytes()); - } - res - } - fn read_raw_unchecked(reader: &mut R) -> Self { - let inner = [(); 4].map(|_| { - let mut buf = [0; 8]; - reader.read_exact(&mut buf).unwrap(); - u64::from_le_bytes(buf) - }); - Self(inner) - } - fn read_raw(reader: &mut R) -> std::io::Result { - let mut inner = [0u64; 4]; - for limb in inner.iter_mut() { - let mut buf = [0; 8]; - reader.read_exact(&mut buf)?; - *limb = u64::from_le_bytes(buf); - } - let elt = Self(inner); - Self::is_less_than(&elt.0, &$modulus.0) - .then(|| elt) - .ok_or_else(|| { - std::io::Error::new( - std::io::ErrorKind::InvalidData, - "input number is not less than field modulus", - ) - }) - } - fn write_raw(&self, writer: &mut W) -> std::io::Result<()> { - for limb in self.0.iter() { - writer.write_all(&limb.to_le_bytes())?; - } - Ok(()) - } - } - }; -} - -#[macro_export] -macro_rules! field_arithmetic { - ($field:ident, $modulus:ident, $inv:ident, $field_type:ident) => { - field_specific!($field, $modulus, $inv, $field_type); - - impl $field { - /// Doubles this field element. - #[inline] - pub const fn double(&self) -> $field { - self.add(self) - } - - /// Squares this element. - #[inline] - pub const fn square(&self) -> $field { - let (r1, carry) = mac(0, self.0[0], self.0[1], 0); - let (r2, carry) = mac(0, self.0[0], self.0[2], carry); - let (r3, r4) = mac(0, self.0[0], self.0[3], carry); - - let (r3, carry) = mac(r3, self.0[1], self.0[2], 0); - let (r4, r5) = mac(r4, self.0[1], self.0[3], carry); - - let (r5, r6) = mac(r5, self.0[2], self.0[3], 0); - - let r7 = r6 >> 63; - let r6 = (r6 << 1) | (r5 >> 63); - let r5 = (r5 << 1) | (r4 >> 63); - let r4 = (r4 << 1) | (r3 >> 63); - let r3 = (r3 << 1) | (r2 >> 63); - let r2 = (r2 << 1) | (r1 >> 63); - let r1 = r1 << 1; - - let (r0, carry) = mac(0, self.0[0], self.0[0], 0); - let (r1, carry) = adc(0, r1, carry); - let (r2, carry) = mac(r2, self.0[1], self.0[1], carry); - let (r3, carry) = adc(0, r3, carry); - let (r4, carry) = mac(r4, self.0[2], self.0[2], carry); - let (r5, carry) = adc(0, r5, carry); - let (r6, carry) = mac(r6, self.0[3], self.0[3], carry); - let (r7, _) = adc(0, r7, carry); - - $field::montgomery_reduce(&[r0, r1, r2, r3, r4, r5, r6, r7]) - } - - /// Multiplies `rhs` by `self`, returning the result. - #[inline(always)] - #[unroll::unroll_for_loops] - #[allow(unused_assignments)] - pub const fn mul(&self, rhs: &Self) -> Self { - // Fast Coarsely Integrated Operand Scanning (CIOS) as described - // in Algorithm 2 of EdMSM: https://eprint.iacr.org/2022/1400.pdf - // - // Cannot use the fast version (algorithm 2) if - // modulus_high_word >= (WORD_SIZE - 1) / 2 - 1 = (2^64 - 1)/2 - 1 - - if $modulus.0[3] < (u64::MAX / 2) { - const N: usize = 4; - let mut t: [u64; N] = [0u64; N]; - let mut c_2: u64; - for i in 0..4 { - let mut c: u64 = 0u64; - for j in 0..4 { - (t[j], c) = mac(t[j], self.0[j], rhs.0[i], c); - } - c_2 = c; - - let m = t[0].wrapping_mul(INV); - (_, c) = macx(t[0], m, $modulus.0[0]); - - for j in 1..4 { - (t[j - 1], c) = mac(t[j], m, $modulus.0[j], c); - } - (t[N - 1], _) = adc(c_2, c, 0); - } - - if bigint_geq(&t, &$modulus.0) { - let mut borrow = 0; - (t[0], borrow) = sbb(t[0], $modulus.0[0], borrow); - (t[1], borrow) = sbb(t[1], $modulus.0[1], borrow); - (t[2], borrow) = sbb(t[2], $modulus.0[2], borrow); - (t[3], borrow) = sbb(t[3], $modulus.0[3], borrow); - } - $field(t) - } else { - // Schoolbook multiplication - - let (r0, carry) = mac(0, self.0[0], rhs.0[0], 0); - let (r1, carry) = mac(0, self.0[0], rhs.0[1], carry); - let (r2, carry) = mac(0, self.0[0], rhs.0[2], carry); - let (r3, r4) = mac(0, self.0[0], rhs.0[3], carry); - - let (r1, carry) = mac(r1, self.0[1], rhs.0[0], 0); - let (r2, carry) = mac(r2, self.0[1], rhs.0[1], carry); - let (r3, carry) = mac(r3, self.0[1], rhs.0[2], carry); - let (r4, r5) = mac(r4, self.0[1], rhs.0[3], carry); - - let (r2, carry) = mac(r2, self.0[2], rhs.0[0], 0); - let (r3, carry) = mac(r3, self.0[2], rhs.0[1], carry); - let (r4, carry) = mac(r4, self.0[2], rhs.0[2], carry); - let (r5, r6) = mac(r5, self.0[2], rhs.0[3], carry); - - let (r3, carry) = mac(r3, self.0[3], rhs.0[0], 0); - let (r4, carry) = mac(r4, self.0[3], rhs.0[1], carry); - let (r5, carry) = mac(r5, self.0[3], rhs.0[2], carry); - let (r6, r7) = mac(r6, self.0[3], rhs.0[3], carry); - - $field::montgomery_reduce(&[r0, r1, r2, r3, r4, r5, r6, r7]) - } - } - - /// Subtracts `rhs` from `self`, returning the result. - #[inline] - pub const fn sub(&self, rhs: &Self) -> Self { - let (d0, borrow) = sbb(self.0[0], rhs.0[0], 0); - let (d1, borrow) = sbb(self.0[1], rhs.0[1], borrow); - let (d2, borrow) = sbb(self.0[2], rhs.0[2], borrow); - let (d3, borrow) = sbb(self.0[3], rhs.0[3], borrow); - - // 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. - let (d0, carry) = adc(d0, $modulus.0[0] & borrow, 0); - let (d1, carry) = adc(d1, $modulus.0[1] & borrow, carry); - let (d2, carry) = adc(d2, $modulus.0[2] & borrow, carry); - let (d3, _) = adc(d3, $modulus.0[3] & borrow, carry); - - $field([d0, d1, d2, d3]) - } - - /// Negates `self`. - #[inline] - pub const fn neg(&self) -> Self { - // Subtract `self` from `MODULUS` to negate. Ignore the final - // borrow because it cannot underflow; self is guaranteed to - // be in the field. - let (d0, borrow) = sbb($modulus.0[0], self.0[0], 0); - let (d1, borrow) = sbb($modulus.0[1], self.0[1], borrow); - let (d2, borrow) = sbb($modulus.0[2], self.0[2], borrow); - let (d3, _) = sbb($modulus.0[3], self.0[3], borrow); - - // `tmp` could be `MODULUS` if `self` was zero. Create a mask that is - // zero if `self` was zero, and `u64::max_value()` if self was nonzero. - let mask = - (((self.0[0] | self.0[1] | self.0[2] | self.0[3]) == 0) as u64).wrapping_sub(1); - - $field([d0 & mask, d1 & mask, d2 & mask, d3 & mask]) - } - - /// Montgomery reduce where last 4 registers are 0 - #[inline(always)] - pub(crate) const fn montgomery_reduce_short(r: &[u64; 4]) -> $field { - // The Montgomery reduction here is based on Algorithm 14.32 in - // Handbook of Applied Cryptography - // . - - let k = r[0].wrapping_mul($inv); - let (_, r0) = macx(r[0], k, $modulus.0[0]); - let (r1, r0) = mac(r[1], k, $modulus.0[1], r0); - let (r2, r0) = mac(r[2], k, $modulus.0[2], r0); - let (r3, r0) = mac(r[3], k, $modulus.0[3], r0); - - let k = r1.wrapping_mul($inv); - let (_, r1) = macx(r1, k, $modulus.0[0]); - let (r2, r1) = mac(r2, k, $modulus.0[1], r1); - let (r3, r1) = mac(r3, k, $modulus.0[2], r1); - let (r0, r1) = mac(r0, k, $modulus.0[3], r1); - - let k = r2.wrapping_mul($inv); - let (_, r2) = macx(r2, k, $modulus.0[0]); - let (r3, r2) = mac(r3, k, $modulus.0[1], r2); - let (r0, r2) = mac(r0, k, $modulus.0[2], r2); - let (r1, r2) = mac(r1, k, $modulus.0[3], r2); - - let k = r3.wrapping_mul($inv); - let (_, r3) = macx(r3, k, $modulus.0[0]); - let (r0, r3) = mac(r0, k, $modulus.0[1], r3); - let (r1, r3) = mac(r1, k, $modulus.0[2], r3); - let (r2, r3) = mac(r2, k, $modulus.0[3], r3); - - // Result may be within MODULUS of the correct value - (&$field([r0, r1, r2, r3])).sub(&$modulus) - } - } - - impl From<$field> for [u64; 4] { - fn from(elt: $field) -> [u64; 4] { - // Turn into canonical form by computing - // (a.R) / R = a - $field::montgomery_reduce_short(&elt.0).0 - } - } - }; -} - -#[macro_export] -macro_rules! field_specific { - ($field:ident, $modulus:ident, $inv:ident, sparse) => { - impl $field { - /// Adds `rhs` to `self`, returning the result. - #[inline] - pub const fn add(&self, rhs: &Self) -> Self { - let (d0, carry) = adc(self.0[0], rhs.0[0], 0); - let (d1, carry) = adc(self.0[1], rhs.0[1], carry); - let (d2, carry) = adc(self.0[2], rhs.0[2], carry); - let (d3, _) = adc(self.0[3], rhs.0[3], carry); - - // Attempt to subtract the modulus, to ensure the value - // is smaller than the modulus. - (&$field([d0, d1, d2, d3])).sub(&$modulus) - } - - #[inline(always)] - pub(crate) const fn montgomery_reduce(r: &[u64; 8]) -> $field { - // The Montgomery reduction here is based on Algorithm 14.32 in - // Handbook of Applied Cryptography - // . - - let k = r[0].wrapping_mul($inv); - let (_, carry) = mac(r[0], k, $modulus.0[0], 0); - let (r1, carry) = mac(r[1], k, $modulus.0[1], carry); - let (r2, carry) = mac(r[2], k, $modulus.0[2], carry); - let (r3, carry) = mac(r[3], k, $modulus.0[3], carry); - let (r4, carry2) = adc(r[4], 0, carry); - - let k = r1.wrapping_mul($inv); - let (_, carry) = mac(r1, k, $modulus.0[0], 0); - let (r2, carry) = mac(r2, k, $modulus.0[1], carry); - let (r3, carry) = mac(r3, k, $modulus.0[2], carry); - let (r4, carry) = mac(r4, k, $modulus.0[3], carry); - let (r5, carry2) = adc(r[5], carry2, carry); - - let k = r2.wrapping_mul($inv); - let (_, carry) = mac(r2, k, $modulus.0[0], 0); - let (r3, carry) = mac(r3, k, $modulus.0[1], carry); - let (r4, carry) = mac(r4, k, $modulus.0[2], carry); - let (r5, carry) = mac(r5, k, $modulus.0[3], carry); - let (r6, carry2) = adc(r[6], carry2, carry); - - let k = r3.wrapping_mul($inv); - let (_, carry) = mac(r3, k, $modulus.0[0], 0); - let (r4, carry) = mac(r4, k, $modulus.0[1], carry); - let (r5, carry) = mac(r5, k, $modulus.0[2], carry); - let (r6, carry) = mac(r6, k, $modulus.0[3], carry); - let (r7, _) = adc(r[7], carry2, carry); - - // Result may be within MODULUS of the correct value - (&$field([r4, r5, r6, r7])).sub(&$modulus) - } - } - }; - ($field:ident, $modulus:ident, $inv:ident, dense) => { - impl $field { - /// Adds `rhs` to `self`, returning the result. - #[inline] - pub const fn add(&self, rhs: &Self) -> Self { - let (d0, carry) = adc(self.0[0], rhs.0[0], 0); - let (d1, carry) = adc(self.0[1], rhs.0[1], carry); - let (d2, carry) = adc(self.0[2], rhs.0[2], carry); - let (d3, carry) = adc(self.0[3], rhs.0[3], carry); - - // Attempt to subtract the modulus, to ensure the value - // is smaller than the modulus. - let (d0, borrow) = sbb(d0, $modulus.0[0], 0); - let (d1, borrow) = sbb(d1, $modulus.0[1], borrow); - let (d2, borrow) = sbb(d2, $modulus.0[2], borrow); - let (d3, borrow) = sbb(d3, $modulus.0[3], borrow); - let (_, borrow) = sbb(carry, 0, borrow); - - let (d0, carry) = adc(d0, $modulus.0[0] & borrow, 0); - let (d1, carry) = adc(d1, $modulus.0[1] & borrow, carry); - let (d2, carry) = adc(d2, $modulus.0[2] & borrow, carry); - let (d3, _) = adc(d3, $modulus.0[3] & borrow, carry); - - $field([d0, d1, d2, d3]) - } - - #[inline(always)] - pub(crate) const fn montgomery_reduce(r: &[u64; 8]) -> Self { - // The Montgomery reduction here is based on Algorithm 14.32 in - // Handbook of Applied Cryptography - // . - - let k = r[0].wrapping_mul($inv); - let (_, carry) = mac(r[0], k, $modulus.0[0], 0); - let (r1, carry) = mac(r[1], k, $modulus.0[1], carry); - let (r2, carry) = mac(r[2], k, $modulus.0[2], carry); - let (r3, carry) = mac(r[3], k, $modulus.0[3], carry); - let (r4, carry2) = adc(r[4], 0, carry); - - let k = r1.wrapping_mul($inv); - let (_, carry) = mac(r1, k, $modulus.0[0], 0); - let (r2, carry) = mac(r2, k, $modulus.0[1], carry); - let (r3, carry) = mac(r3, k, $modulus.0[2], carry); - let (r4, carry) = mac(r4, k, $modulus.0[3], carry); - let (r5, carry2) = adc(r[5], carry2, carry); - - let k = r2.wrapping_mul($inv); - let (_, carry) = mac(r2, k, $modulus.0[0], 0); - let (r3, carry) = mac(r3, k, $modulus.0[1], carry); - let (r4, carry) = mac(r4, k, $modulus.0[2], carry); - let (r5, carry) = mac(r5, k, $modulus.0[3], carry); - let (r6, carry2) = adc(r[6], carry2, carry); - - let k = r3.wrapping_mul($inv); - let (_, carry) = mac(r3, k, $modulus.0[0], 0); - let (r4, carry) = mac(r4, k, $modulus.0[1], carry); - let (r5, carry) = mac(r5, k, $modulus.0[2], carry); - let (r6, carry) = mac(r6, k, $modulus.0[3], carry); - let (r7, carry2) = adc(r[7], carry2, carry); - - // Result may be within MODULUS of the correct value - let (d0, borrow) = sbb(r4, $modulus.0[0], 0); - let (d1, borrow) = sbb(r5, $modulus.0[1], borrow); - let (d2, borrow) = sbb(r6, $modulus.0[2], borrow); - let (d3, borrow) = sbb(r7, $modulus.0[3], borrow); - let (_, borrow) = sbb(carry2, 0, borrow); - - let (d0, carry) = adc(d0, $modulus.0[0] & borrow, 0); - let (d1, carry) = adc(d1, $modulus.0[1] & borrow, carry); - let (d2, carry) = adc(d2, $modulus.0[2] & borrow, carry); - let (d3, _) = adc(d3, $modulus.0[3] & borrow, carry); - - $field([d0, d1, d2, d3]) - } - } - }; -} - -#[macro_export] -macro_rules! field_bits { - // For #[cfg(target_pointer_width = "64")] - ($field:ident, $modulus:ident) => { - #[cfg(feature = "bits")] - #[cfg_attr(docsrs, doc(cfg(feature = "bits")))] - impl ::ff::PrimeFieldBits for $field { - type ReprBits = [u64; 4]; - - fn to_le_bits(&self) -> ::ff::FieldBits { - let bytes = self.to_repr(); - - let limbs = [ - u64::from_le_bytes(bytes[0..8].try_into().unwrap()), - u64::from_le_bytes(bytes[8..16].try_into().unwrap()), - u64::from_le_bytes(bytes[16..24].try_into().unwrap()), - u64::from_le_bytes(bytes[24..32].try_into().unwrap()), - ]; - - ::ff::FieldBits::new(limbs) - } - - fn char_le_bits() -> ::ff::FieldBits { - ::ff::FieldBits::new($modulus.0) - } - } - }; - // For #[cfg(not(target_pointer_width = "64"))] - ($field:ident, $modulus:ident, $modulus_limbs_32:ident) => { - #[cfg(feature = "bits")] - #[cfg_attr(docsrs, doc(cfg(feature = "bits")))] - impl ::ff::PrimeFieldBits for $field { - type ReprBits = [u32; 8]; - - fn to_le_bits(&self) -> ::ff::FieldBits { - let bytes = self.to_repr(); - - let limbs = [ - u32::from_le_bytes(bytes[0..4].try_into().unwrap()), - u32::from_le_bytes(bytes[4..8].try_into().unwrap()), - u32::from_le_bytes(bytes[8..12].try_into().unwrap()), - u32::from_le_bytes(bytes[12..16].try_into().unwrap()), - u32::from_le_bytes(bytes[16..20].try_into().unwrap()), - u32::from_le_bytes(bytes[20..24].try_into().unwrap()), - u32::from_le_bytes(bytes[24..28].try_into().unwrap()), - u32::from_le_bytes(bytes[28..32].try_into().unwrap()), - ]; - - ::ff::FieldBits::new(limbs) - } - - fn char_le_bits() -> ::ff::FieldBits { - ::ff::FieldBits::new($modulus_limbs_32) - } - } - }; -} - -/// A macro to help define serialization and deserialization for prime field implementations -/// that use 32-byte representations. This assumes the concerned type implements PrimeField -/// (for from_repr, to_repr). -#[macro_export] -macro_rules! serialize_deserialize_32_byte_primefield { - ($type:ty) => { - impl ::serde::Serialize for $type { - fn serialize(&self, serializer: S) -> Result { - let bytes = &self.to_repr(); - if serializer.is_human_readable() { - hex::serde::serialize(bytes, serializer) - } else { - bytes.serialize(serializer) - } - } - } - - use ::serde::de::Error as _; - impl<'de> ::serde::Deserialize<'de> for $type { - fn deserialize>( - deserializer: D, - ) -> Result { - let bytes = if deserializer.is_human_readable() { - ::hex::serde::deserialize(deserializer)? - } else { - <[u8; 32]>::deserialize(deserializer)? - }; - Option::from(Self::from_repr(bytes)).ok_or_else(|| { - D::Error::custom("deserialized bytes don't encode a valid field element") - }) - } - } - }; -} diff --git a/src/derive/field/common.rs b/src/derive/field/common.rs new file mode 100644 index 00000000..ff3b7772 --- /dev/null +++ b/src/derive/field/common.rs @@ -0,0 +1,105 @@ +#[macro_export] +macro_rules! field_bits { + ($field:ident) => { + #[cfg(feature = "bits")] + #[cfg_attr(docsrs, doc(cfg(feature = "bits")))] + impl ff::PrimeFieldBits for $field { + #[cfg(target_pointer_width = "64")] + type ReprBits = [u64; Self::NUM_LIMBS]; + #[cfg(not(target_pointer_width = "64"))] + type ReprBits = [u32; Self::NUM_LIMBS * 2]; + + fn to_le_bits(&self) -> ff::FieldBits { + use ff::PrimeField; + let bytes: [u8; Self::SIZE] = self.to_repr().into(); + + #[cfg(target_pointer_width = "64")] + const STEP: usize = 8; + #[cfg(not(target_pointer_width = "64"))] + const STEP: usize = 4; + + let limbs = (0..Self::NUM_LIMBS * 8 / STEP) + .map(|off| { + #[cfg(target_pointer_width = "64")] + let limb = u64::from_le_bytes( + bytes[off * STEP..(off + 1) * STEP].try_into().unwrap(), + ); + #[cfg(not(target_pointer_width = "64"))] + let limb = u32::from_le_bytes( + bytes[off * STEP..(off + 1) * STEP].try_into().unwrap(), + ); + + limb + }) + .collect::>(); + + ff::FieldBits::new(limbs.try_into().unwrap()) + } + + fn char_le_bits() -> ff::FieldBits { + #[cfg(target_pointer_width = "64")] + let bits = ff::FieldBits::new(Self::MODULUS_LIMBS); + #[cfg(not(target_pointer_width = "64"))] + let bits = ff::FieldBits::new(Self::MODULUS_LIMBS_32); + + bits + } + } + }; +} + +#[macro_export] +macro_rules! impl_from_u64 { + ($field:ident) => { + impl From for $field { + fn from(val: u64) -> $field { + let limbs = std::iter::once(val) + .chain(std::iter::repeat(0)) + .take(Self::NUM_LIMBS) + .collect::>() + .try_into() + .unwrap(); + + $field(limbs) * Self::R2 + } + } + }; +} + +/// A macro to help define serialization and deserialization for prime field implementations +/// that use `$field::Repr`` representations. This assumes the concerned type implements PrimeField +/// (for from_repr, to_repr). +#[macro_export] +macro_rules! serialize_deserialize_primefield { + ($field:ident) => { + #[cfg(feature = "derive_serde")] + impl<'de> ::serde::Deserialize<'de> for $field { + fn deserialize>( + deserializer: D, + ) -> Result { + use ::serde::de::Error as _; + let bytes = if deserializer.is_human_readable() { + hex::serde::deserialize(deserializer)? + } else { + ::serde_arrays::deserialize::<_, u8, { $field::SIZE }>(deserializer)? + }; + use ff::PrimeField; + Option::from(Self::from_repr(bytes.into())).ok_or_else(|| { + D::Error::custom("deserialized bytes don't encode a valid field element") + }) + } + } + #[cfg(feature = "derive_serde")] + impl ::serde::Serialize for $field { + fn serialize(&self, serializer: S) -> Result { + use ff::PrimeField; + if serializer.is_human_readable() { + hex::serde::serialize(self.to_repr().as_ref(), serializer) + } else { + let bytes: [u8; $field::SIZE] = self.to_repr().into(); + ::serde_arrays::serialize(&bytes, serializer) + } + } + } + }; +} diff --git a/src/derive/field/mod.rs b/src/derive/field/mod.rs new file mode 100644 index 00000000..a9f66989 --- /dev/null +++ b/src/derive/field/mod.rs @@ -0,0 +1,4 @@ +#[macro_use] +pub mod common; +#[macro_use] +pub mod tower; diff --git a/src/derive/field/tower.rs b/src/derive/field/tower.rs new file mode 100644 index 00000000..37786919 --- /dev/null +++ b/src/derive/field/tower.rs @@ -0,0 +1,517 @@ +#[macro_export] +macro_rules! impl_tower2_common { + ( + $field:ident, + $tower:ident, + serde + ) => { + #[derive(Copy, Clone, Debug, Eq, PartialEq, Default)] + #[cfg_attr(feature = "derive_serde", derive(Serialize, Deserialize))] + pub struct $tower { + pub c0: $field, + pub c1: $field, + } + + impl_tower2_common!($field, $tower, implementations); + }; + + ( + $field:ident, + $tower:ident + + ) => { + #[derive(Copy, Clone, Debug, Eq, PartialEq, Default)] + pub struct $tower { + pub c0: $field, + pub c1: $field, + } + + impl_tower2_common!($field, $tower, implementations); + }; + + ( + $field:ident, + $tower:ident, + implementations + ) => { + impl ::core::ops::Neg for $tower { + type Output = $tower; + + #[inline] + fn neg(self) -> $tower { + -&self + } + } + + impl ConditionallySelectable for $tower { + fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self { + $tower { + c0: $field::conditional_select(&a.c0, &b.c0, choice), + c1: $field::conditional_select(&a.c1, &b.c1, choice), + } + } + } + + impl ConstantTimeEq for $tower { + fn ct_eq(&self, other: &Self) -> Choice { + self.c0.ct_eq(&other.c0) & self.c1.ct_eq(&other.c1) + } + } + + impl $tower { + #[inline] + pub const fn zero() -> $tower { + $tower { + c0: $field::zero(), + c1: $field::zero(), + } + } + + #[inline] + pub const fn one() -> $tower { + $tower { + c0: $field::one(), + c1: $field::zero(), + } + } + + #[inline] + pub const fn new(c0: $field, c1: $field) -> Self { + $tower { c0, c1 } + } + + pub fn double(&self) -> Self { + Self { + c0: self.c0.double(), + c1: self.c1.double(), + } + } + + pub fn add(&self, other: &Self) -> Self { + Self { + c0: self.c0.add(&other.c0), + c1: self.c1.add(&other.c1), + } + } + + pub fn sub(&self, other: &Self) -> Self { + Self { + c0: self.c0.sub(&other.c0), + c1: self.c1.sub(&other.c1), + } + } + + pub fn neg(&self) -> Self { + Self { + c0: self.c0.neg(), + c1: self.c1.neg(), + } + } + + pub fn mul(&self, other: &Self) -> Self { + let mut t = *other; + t.mul_assign(self); + t + } + + pub fn square(&self) -> Self { + let mut t = *self; + t.square_assign(); + t + } + } + }; +} + +#[macro_export] +macro_rules! impl_tower2 { + ( + $field:ident, + $tower:ident, + $repr:ident + ) => { + /// `$tower` elements are ordered lexicographically. + impl Ord for $tower { + #[inline(always)] + fn cmp(&self, other: &$tower) -> Ordering { + match self.c1.cmp(&other.c1) { + Ordering::Greater => Ordering::Greater, + Ordering::Less => Ordering::Less, + Ordering::Equal => self.c0.cmp(&other.c0), + } + } + } + + impl PartialOrd for $tower { + #[inline(always)] + fn partial_cmp(&self, other: &$tower) -> Option { + Some(self.cmp(other)) + } + } + + impl From<$tower> for [u8; $tower::SIZE] { + fn from(value: $tower) -> [u8; $tower::SIZE] { + value.to_bytes() + } + } + + impl<'a> From<&'a $tower> for [u8; $tower::SIZE] { + fn from(value: &'a $tower) -> [u8; $tower::SIZE] { + value.to_bytes() + } + } + + impl $tower { + pub const SIZE: usize = $field::SIZE * 2; + + /// Attempts to convert a little-endian byte representation of + /// a scalar into a `$field`, failing if the input is not canonical. + pub fn from_bytes(bytes: &[u8; $field::SIZE * 2]) -> CtOption<$tower> { + let c0 = $field::from_bytes(bytes[0..$field::SIZE].try_into().unwrap()); + let c1 = + $field::from_bytes(bytes[$field::SIZE..$field::SIZE * 2].try_into().unwrap()); + CtOption::new( + $tower { + c0: c0.unwrap(), + c1: c1.unwrap(), + }, + c0.is_some() & c1.is_some(), + ) + } + + /// Converts an element of `$field` into a byte representation in + /// little-endian byte order. + #[allow(clippy::wrong_self_convention)] + pub fn to_bytes(&self) -> [u8; $field::SIZE * 2] { + let mut res = [0u8; $field::SIZE * 2]; + let c0_bytes = self.c0.to_bytes(); + let c1_bytes = self.c1.to_bytes(); + res[0..$field::SIZE].copy_from_slice(&c0_bytes[..]); + res[$field::SIZE..$field::SIZE * 2].copy_from_slice(&c1_bytes[..]); + res + } + } + + impl ff::Field for $tower { + const ZERO: Self = Self::zero(); + const ONE: Self = Self::one(); + + fn random(mut rng: impl RngCore) -> Self { + $tower { + c0: $field::random(&mut rng), + c1: $field::random(&mut rng), + } + } + + fn is_zero(&self) -> Choice { + self.c0.is_zero() & self.c1.is_zero() + } + + fn square(&self) -> Self { + self.square() + } + + fn double(&self) -> Self { + self.double() + } + + fn sqrt(&self) -> CtOption { + self.sqrt() + } + + fn sqrt_ratio(num: &Self, div: &Self) -> (Choice, Self) { + ff::helpers::sqrt_ratio_generic(num, div) + } + + fn invert(&self) -> CtOption { + self.invert() + } + } + + impl PrimeField for $tower { + type Repr = $repr; + + const MODULUS: &'static str = <$field as PrimeField>::MODULUS; + const MULTIPLICATIVE_GENERATOR: Self = $tower { + c0: $field::MULTIPLICATIVE_GENERATOR, + c1: $field::ZERO, + }; + const NUM_BITS: u32 = $field::NUM_BITS; + const CAPACITY: u32 = $field::NUM_BITS; + const S: u32 = $field::S; + + // TODO: Check that we can just 0 this and forget. + const ROOT_OF_UNITY: Self = $tower::ZERO; + const ROOT_OF_UNITY_INV: Self = $tower::ZERO; + const DELTA: Self = $tower::ZERO; + + const TWO_INV: Self = $tower { + c0: $field::TWO_INV, + c1: $field::ZERO, + }; + + fn from_repr(repr: Self::Repr) -> CtOption { + let c0 = $field::from_bytes(&repr.0[..$field::SIZE].try_into().unwrap()); + let c1 = $field::from_bytes(&repr.0[$field::SIZE..].try_into().unwrap()); + CtOption::new($tower::new(c0.unwrap(), c1.unwrap()), Choice::from(1)) + } + + fn to_repr(&self) -> Self::Repr { + $repr(self.to_bytes()) + } + + fn is_odd(&self) -> Choice { + Choice::from(self.to_repr().as_ref()[0] & 1) + } + } + + impl WithSmallOrderMulGroup<3> for $tower { + // $field::ZETA ^2 + const ZETA: Self = $tower { + c0: ZETA, + c1: $field::ZERO, + }; + } + + impl From for $tower { + fn from(val: u64) -> Self { + $tower { + c0: $field::from(val), + c1: $field::ZERO, + } + } + } + + impl Legendre for $tower { + fn legendre(&self) -> i64 { + self.norm().legendre() + } + } + + #[derive(Clone, Copy, Debug)] + pub struct $repr([u8; $field::SIZE * 2]); + + impl Default for $repr { + fn default() -> Self { + Self([0u8; $field::SIZE * 2]) + } + } + + impl AsMut<[u8]> for $repr { + fn as_mut(&mut self) -> &mut [u8] { + &mut self.0 + } + } + + impl AsRef<[u8]> for $repr { + fn as_ref(&self) -> &[u8] { + &self.0 + } + } + + impl FromUniformBytes<{ $field::SIZE * 2 }> for $tower { + fn from_uniform_bytes(bytes: &[u8; $field::SIZE * 2]) -> Self { + Self::new($field::from_uniform_bytes(bytes), $field::ZERO) + } + } + + impl FromUniformBytes<{ $field::SIZE * 2 * 2 }> for $tower { + fn from_uniform_bytes(bytes: &[u8; $field::SIZE * 2 * 2]) -> Self { + let c0: [u8; $field::SIZE * 2] = bytes[..$field::SIZE * 2].try_into().unwrap(); + let c1: [u8; $field::SIZE * 2] = bytes[$field::SIZE * 2..].try_into().unwrap(); + Self::new( + $field::from_uniform_bytes(&c0), + $field::from_uniform_bytes(&c1), + ) + } + } + + impl $crate::serde::SerdeObject for $tower { + fn from_raw_bytes_unchecked(bytes: &[u8]) -> Self { + debug_assert_eq!(bytes.len(), $field::SIZE * 2); + let [c0, c1] = [0, $field::SIZE] + .map(|i| $field::from_raw_bytes_unchecked(&bytes[i..i + $field::SIZE])); + Self { c0, c1 } + } + fn from_raw_bytes(bytes: &[u8]) -> Option { + if bytes.len() != $field::SIZE * 2 { + return None; + } + let [c0, c1] = + [0, $field::SIZE].map(|i| $field::from_raw_bytes(&bytes[i..i + $field::SIZE])); + c0.zip(c1).map(|(c0, c1)| Self { c0, c1 }) + } + fn to_raw_bytes(&self) -> Vec { + let mut res = Vec::with_capacity($field::SIZE * 2); + for limb in self.c0.0.iter().chain(self.c1.0.iter()) { + res.extend_from_slice(&limb.to_le_bytes()); + } + res + } + fn read_raw_unchecked(reader: &mut R) -> Self { + let [c0, c1] = [(); 2].map(|_| $field::read_raw_unchecked(reader)); + Self { c0, c1 } + } + fn read_raw(reader: &mut R) -> std::io::Result { + let c0 = $field::read_raw(reader)?; + let c1 = $field::read_raw(reader)?; + Ok(Self { c0, c1 }) + } + fn write_raw(&self, writer: &mut W) -> std::io::Result<()> { + self.c0.write_raw(writer)?; + self.c1.write_raw(writer) + } + } + }; +} + +#[macro_export] +macro_rules! impl_tower6 { + ( + $field:ident, + $tower2:ident, + $tower6:ident + ) => { + #[derive(Copy, Clone, Debug, Eq, PartialEq, Default)] + pub struct $tower6 { + pub c0: $tower2, + pub c1: $tower2, + pub c2: $tower2, + } + + impl ::core::ops::Neg for $tower6 { + type Output = $tower6; + + #[inline] + fn neg(self) -> $tower6 { + -&self + } + } + + impl subtle::ConditionallySelectable for $tower6 { + fn conditional_select(a: &Self, b: &Self, choice: subtle::Choice) -> Self { + $tower6 { + c0: $tower2::conditional_select(&a.c0, &b.c0, choice), + c1: $tower2::conditional_select(&a.c1, &b.c1, choice), + c2: $tower2::conditional_select(&a.c2, &b.c2, choice), + } + } + } + + impl subtle::ConstantTimeEq for $tower6 { + fn ct_eq(&self, other: &Self) -> subtle::Choice { + self.c0.ct_eq(&other.c0) & self.c1.ct_eq(&other.c1) & self.c2.ct_eq(&other.c2) + } + } + + impl $tower6 { + #[inline] + pub const fn zero() -> Self { + $tower6 { + c0: $tower2::ZERO, + c1: $tower2::ZERO, + c2: $tower2::ZERO, + } + } + + #[inline] + pub const fn one() -> Self { + $tower6 { + c0: $tower2::ONE, + c1: $tower2::ZERO, + c2: $tower2::ZERO, + } + } + + #[inline] + pub fn double(&self) -> Self { + Self { + c0: self.c0.double(), + c1: self.c1.double(), + c2: self.c2.double(), + } + } + + #[inline] + pub fn add(&self, other: &Self) -> Self { + Self { + c0: self.c0 + other.c0, + c1: self.c1 + other.c1, + c2: self.c2 + other.c2, + } + } + + #[inline] + pub fn sub(&self, other: &Self) -> Self { + Self { + c0: self.c0 - other.c0, + c1: self.c1 - other.c1, + c2: self.c2 - other.c2, + } + } + + #[inline] + pub fn neg(&self) -> Self { + Self { + c0: -self.c0, + c1: -self.c1, + c2: -self.c2, + } + } + + pub fn mul(&self, other: &Self) -> Self { + let mut t = *other; + t.mul_assign(self); + t + } + + pub fn square(&self) -> Self { + let mut t = *self; + t.square_assign(); + t + } + + pub fn random(mut rng: impl RngCore) -> Self { + $tower6 { + c0: $tower2::random(&mut rng), + c1: $tower2::random(&mut rng), + c2: $tower2::random(&mut rng), + } + } + } + + #[cfg(test)] + impl Field for $tower6 { + const ZERO: Self = Self::zero(); + const ONE: Self = Self::one(); + + fn random(rng: impl RngCore) -> Self { + $tower6::random(rng) + } + + fn is_zero(&self) -> subtle::Choice { + self.c0.is_zero() & self.c1.is_zero() + } + + fn square(&self) -> Self { + self.square() + } + + fn double(&self) -> Self { + self.double() + } + + fn sqrt(&self) -> CtOption { + unimplemented!() + } + + fn sqrt_ratio(_num: &Self, _div: &Self) -> (subtle::Choice, Self) { + unimplemented!() + } + + fn invert(&self) -> CtOption { + self.invert() + } + } + }; +} diff --git a/src/derive/mod.rs b/src/derive/mod.rs index 5e5015a1..ad560f3f 100644 --- a/src/derive/mod.rs +++ b/src/derive/mod.rs @@ -3,6 +3,47 @@ pub mod curve; #[macro_use] pub mod field; +#[macro_export] +macro_rules! impl_binops_calls { + ($field:ident) => { + impl<'a> ::core::ops::Neg for &'a $field { + type Output = $field; + + #[inline] + fn neg(self) -> $field { + self.neg() + } + } + + impl<'a, 'b> ::core::ops::Sub<&'b $field> for &'a $field { + type Output = $field; + + #[inline] + fn sub(self, rhs: &'b $field) -> $field { + self.sub(rhs) + } + } + + impl<'a, 'b> ::core::ops::Add<&'b $field> for &'a $field { + type Output = $field; + + #[inline] + fn add(self, rhs: &'b $field) -> $field { + self.add(rhs) + } + } + + impl<'a, 'b> ::core::ops::Mul<&'b $field> for &'a $field { + type Output = $field; + + #[inline] + fn mul(self, rhs: &'b $field) -> $field { + self.mul(rhs) + } + } + }; +} + #[macro_export] macro_rules! impl_add_binop_specify_output { ($lhs:ident, $rhs:ident, $output:ident) => { @@ -168,15 +209,13 @@ macro_rules! impl_sum_prod { ($f:ident) => { impl> ::core::iter::Sum for $f { fn sum>(iter: I) -> Self { - use ::ff::Field; - iter.fold(Self::ZERO, |acc, item| acc + item.borrow()) + iter.fold(Self::zero(), |acc, item| acc + item.borrow()) } } impl> ::core::iter::Product for $f { fn product>(iter: I) -> Self { - use ::ff::Field; - iter.fold(Self::ONE, |acc, item| acc * item.borrow()) + iter.fold(Self::one(), |acc, item| acc * item.borrow()) } } }; diff --git a/src/pluto_eris/curve.rs b/src/pluto_eris/curve.rs index c102eb2a..6a394887 100644 --- a/src/pluto_eris/curve.rs +++ b/src/pluto_eris/curve.rs @@ -1,4 +1,4 @@ -use super::fields::{fp::Fp, fp2::Fp2, fq::Fq}; +use super::{fp::Fp, fp2::Fp2, fq::Fq}; use crate::derive::curve::{IDENTITY_MASK, IDENTITY_SHIFT, SIGN_MASK, SIGN_SHIFT}; use crate::ff::WithSmallOrderMulGroup; use crate::ff::{Field, PrimeField}; @@ -8,7 +8,6 @@ use core::cmp; use core::fmt::Debug; use core::iter::Sum; use core::ops::{Add, Mul, Neg, Sub}; -use ff::FromUniformBytes; use group::cofactor::CofactorGroup; use rand::RngCore; use subtle::{Choice, ConditionallySelectable, ConstantTimeEq, CtOption}; @@ -164,22 +163,6 @@ impl G1 { } } -impl FromUniformBytes<72> for Fp { - fn from_uniform_bytes(bytes: &[u8; 72]) -> Self { - let repr = &mut [0u8; Self::size()]; - - (*repr)[0..36].copy_from_slice(&bytes[..36]); - let e0 = Fp::from_repr((*repr).into()).unwrap(); - (*repr)[0..36].copy_from_slice(&bytes[36..]); - let e1 = Fp::from_repr((*repr).into()).unwrap(); - - // 2^(36*8) - const SHIFTER: Fp = Fp::from_raw([0, 0, 0, 0, 0x100000000, 0, 0]); - - e0 + e1 * SHIFTER - } -} - new_curve_impl!( (pub), Eris, @@ -260,22 +243,6 @@ impl Eris { } } -impl FromUniformBytes<72> for Fq { - fn from_uniform_bytes(bytes: &[u8; 72]) -> Self { - let repr = &mut [0u8; Self::size()]; - - (*repr)[0..36].copy_from_slice(&bytes[..36]); - let e0 = Fq::from_repr((*repr).into()).unwrap(); - (*repr)[0..36].copy_from_slice(&bytes[36..]); - let e1 = Fq::from_repr((*repr).into()).unwrap(); - - // 2^(36*8) - const SHIFTER: Fq = Fq::from_raw([0, 0, 0, 0, 0x100000000, 0, 0]); - - e0 + e1 * SHIFTER - } -} - new_curve_impl!( (pub), G2, diff --git a/src/pluto_eris/engine.rs b/src/pluto_eris/engine.rs index 3b47f878..7b6a8226 100644 --- a/src/pluto_eris/engine.rs +++ b/src/pluto_eris/engine.rs @@ -1,14 +1,14 @@ #![allow(clippy::suspicious_arithmetic_impl)] -use crate::ff::{Field, PrimeField}; +use crate::ff::PrimeField; use crate::group::cofactor::CofactorCurveAffine; use crate::group::Group; use crate::pairing::{Engine, MillerLoopResult, MultiMillerLoop, PairingCurveAffine}; use crate::pluto_eris::curve::*; -use crate::pluto_eris::fields::fp::*; -use crate::pluto_eris::fields::fp12::*; -use crate::pluto_eris::fields::fp2::*; -use crate::pluto_eris::fields::fp6::FROBENIUS_COEFF_FP6_C1; -use crate::pluto_eris::fields::fq::*; +use crate::pluto_eris::fp::*; +use crate::pluto_eris::fp12::*; +use crate::pluto_eris::fp2::*; +use crate::pluto_eris::fp6::FROBENIUS_COEFF_FP6_C1; +use crate::pluto_eris::fq::*; use core::borrow::Borrow; use core::iter::Sum; use core::ops::{Add, Mul, MulAssign, Neg, Sub}; @@ -99,7 +99,7 @@ impl PartialEq for Gt { impl Gt { /// Returns the group identity, which is $1$. pub const fn identity() -> Gt { - Gt(Fp12::ONE) + Gt(Fp12::one()) } /// Doubles this group element. @@ -155,6 +155,7 @@ impl<'a, 'b> Mul<&'b Fq> for &'a Gt { for bit in other .to_repr() + .as_ref() .iter() .rev() .flat_map(|byte| (0..8).rev().map(move |i| Choice::from((byte >> i) & 1u8))) @@ -489,7 +490,7 @@ impl MillerLoopResult for Gt { fn final_exponentiation(&self) -> Gt { fn exp_by_x(f: &mut Fp12) { let x = NEG_PLUTO_U; - let mut res = Fp12::ONE; + let mut res = Fp12::one(); for i in (0..111).rev() { res.cyclotomic_square(); if ((x >> i) & 1) == 1 { @@ -617,7 +618,7 @@ impl MultiMillerLoop for Pluto { f.mul_by_034(&c0, &c1, &coeffs.2); } - let mut f = Fp12::ONE; + let mut f = Fp12::one(); for &mut (p, ref mut coeffs) in &mut pairs { ell(&mut f, coeffs.next().unwrap(), p); @@ -690,6 +691,8 @@ use rand_xorshift::XorShiftRng; #[test] fn test_pairing() { + use ff::Field; + let g1 = G1::generator(); let mut g2 = G2::generator(); g2 = g2.double(); @@ -773,6 +776,8 @@ fn tricking_miller_loop_result() { #[test] fn random_bilinearity_tests() { + use ff::Field; + let mut rng = XorShiftRng::from_seed([ 0x55, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, 0xe5, @@ -821,6 +826,8 @@ fn random_bilinearity_tests() { #[test] pub fn engine_tests() { + use ff::Field; + let mut rng = XorShiftRng::from_seed([ 0x56, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, 0xe5, @@ -901,6 +908,8 @@ fn random_miller_loop_tests() { #[test] pub fn multi_miller_final_exp_tests() { + use ff::Field; + let g1 = G1::generator(); let g2 = G2::generator(); diff --git a/src/pluto_eris/fields/fp.rs b/src/pluto_eris/fields/fp.rs deleted file mode 100644 index 646ef7e8..00000000 --- a/src/pluto_eris/fields/fp.rs +++ /dev/null @@ -1,415 +0,0 @@ -use crate::arithmetic::{adc, mac, sbb}; -use crate::ff::{FromUniformBytes, PrimeField, WithSmallOrderMulGroup}; -use crate::{ - extend_field_legendre, field_arithmetic_7_limbs, field_bits_7_limbs, field_common_7_limbs, - impl_from_u64_7_limbs, -}; -use crate::{ - impl_add_binop_specify_output, impl_binops_additive, impl_binops_additive_specify_output, - impl_binops_multiplicative, impl_binops_multiplicative_mixed, impl_sub_binop_specify_output, - impl_sum_prod, -}; -use core::convert::TryInto; -use core::fmt; -use core::ops::{Add, Mul, Neg, Sub}; -use rand::RngCore; -use std::slice::Iter; -use subtle::{Choice, ConditionallySelectable, ConstantTimeEq, CtOption}; - -#[cfg(feature = "derive_serde")] -use serde::{Deserialize, Serialize}; - -/// This represents an element of $\mathbb{F}_p$ where -/// -/// `p = 0x24000000000024000130e0000d7f70e4a803ca76f439266f443f9a5cda8a6c7be4a7a5fe8fadffd6a2a7e8c30006b9459ffffcd300000001` -/// -/// is the base field of the Pluto curve. -/// The internal representation of this type is seven 64-bit unsigned -/// integers in little-endian order which account for the 446 bits required to be represented. -/// `Fp` values are always in Montgomery form; i.e., Fp(a) = aR mod p, with R = 2^448. -#[derive(Clone, Copy, PartialEq, Eq, Hash)] -#[cfg_attr(feature = "derive_serde", derive(Serialize, Deserialize))] -pub struct Fp(pub(crate) [u64; 7]); - -/// Size of `Fp` element in bytes -const SIZE: usize = 56; - -/// Constant representing the modulus -/// p = 0x24000000000024000130e0000d7f70e4a803ca76f439266f443f9a5cda8a6c7be4a7a5fe8fadffd6a2a7e8c30006b9459ffffcd300000001 -const MODULUS: Fp = Fp([ - 0x9ffffcd300000001, - 0xa2a7e8c30006b945, - 0xe4a7a5fe8fadffd6, - 0x443f9a5cda8a6c7b, - 0xa803ca76f439266f, - 0x0130e0000d7f70e4, - 0x2400000000002400, -]); - -/// The modulus as u32 limbs. -#[cfg(not(target_pointer_width = "64"))] -const MODULUS_LIMBS_32: [u32; 14] = [ - 0x00000001, 0x9ffffcd3, 0x0006b945, 0xa2a7e8c3, 0x8fadffd6, 0xe4a7a5fe, 0xda8a6c7b, 0x443f9a5c, - 0xf439266f, 0xa803ca76, 0x0d7f70e4, 0x0130e000, 0x00002400, 0x24000000, -]; - -// pub const NEGATIVE_ONE: Fp = Fp([]); - -pub(crate) const MODULUS_STR: &str = "0x24000000000024000130e0000d7f70e4a803ca76f439266f443f9a5cda8a6c7be4a7a5fe8fadffd6a2a7e8c30006b9459ffffcd300000001"; - -/// INV = -r^{-1} mod 2^64 -/// `0x9ffffcd2ffffffff` -const INV: u64 = 0x9ffffcd2ffffffff; - -/// Let M be the power of `2^64` nearest to `Self::MODULUS_BITS`. Then `R = M % Self::MODULUS`. -/// `R = 2^448 mod p` -/// `0x3ffffffffff03fff7a9dfffa183e9bf67e576bf526ff2f52242c7760637089cbf6a760a123e01218d68a2aaffd0ef18a000163afffffff9` -const R: Fp = Fp([ - 0xa000163afffffff9, - 0x8d68a2aaffd0ef18, - 0xbf6a760a123e0121, - 0x2242c7760637089c, - 0x67e576bf526ff2f5, - 0xf7a9dfffa183e9bf, - 0x03ffffffffff03ff, -]); - -/// `R^2 = 2^896 mod p` -/// `0x1a4b16581f66e3cc8bcb0f20758aec8520b6db3d7481a84c734fd363b575c23e7a42067a8ccd154b4b20c07277ae01f1d9702c6d54dc0598` -const R2: Fp = Fp([ - 0xd9702c6d54dc0598, - 0x4b20c07277ae01f1, - 0x7a42067a8ccd154b, - 0x734fd363b575c23e, - 0x20b6db3d7481a84c, - 0x8bcb0f20758aec85, - 0x1a4b16581f66e3cc, -]); - -/// `R^3 = 2^1792 mod p` -/// `0x1f51e40a048ddc1789010189f4df0ae1f3bc57efac4b3280b25aa8b46a40b225e5446680e4c4ea0449937d6b40e58f05c67afa3fe916dd69` -const R3: Fp = Fp([ - 0xc67afa3fe916dd69, - 0x49937d6b40e58f05, - 0xe5446680e4c4ea04, - 0xb25aa8b46a40b225, - 0xf3bc57efac4b3280, - 0x89010189f4df0ae1, - 0x1f51e40a048ddc17, -]); - -/// `GENERATOR = 10 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([0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]); - -/// Size of the 2-adic sub-group of the field. -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. -/// `0x2d39f8c5f9adb3f35fe3f4222db17451ddd9602a013af5276bdbe3903ec85fc889232f5c8bc6857060c75e6f399661d6c7b82d31d563091` -const ROOT_OF_UNITY: Fp = Fp::from_raw([ - 0x6c7b82d31d563091, - 0x060c75e6f399661d, - 0x889232f5c8bc6857, - 0x76bdbe3903ec85fc, - 0x1ddd9602a013af52, - 0x35fe3f4222db1745, - 0x02d39f8c5f9adb3f, -]); - -/// 1 / ROOT_OF_UNITY mod p -/// `0x17725d635b00cda4153eb10c7105919d012822bd86c08691803272fbc5c9f8378055eb56ae2d55f9272bf208aad57f666deaead2c693ff66` -const ROOT_OF_UNITY_INV: Fp = Fp::from_raw([ - 0x6deaead2c693ff66, - 0x272bf208aad57f66, - 0x8055eb56ae2d55f9, - 0x803272fbc5c9f837, - 0x012822bd86c08691, - 0x153eb10c7105919d, - 0x17725d635b00cda4, -]); - -/// 1 / 2 mod p -/// `0x12000000000012000098700006bfb8725401e53b7a1c9337a21fcd2e6d45363df253d2ff47d6ffeb5153f46180035ca2cffffe6980000001` -pub(crate) const TWO_INV: Fp = Fp::from_raw([ - 0xcffffe6980000001, - 0x5153f46180035ca2, - 0xf253d2ff47d6ffeb, - 0xa21fcd2e6d45363d, - 0x5401e53b7a1c9337, - 0x0098700006bfb872, - 0x1200000000001200, -]); -/// GENERATOR^{2^s} where t * 2^s + 1 = r with t odd. In other words, this is a t root of unity. -/// `0xeacefc6504d028d42ed23fc8766d5a5f195b456887e1e0021fb760c53233e9170c23749b459b95cc6cbb5faf3754a1e1916b2007775db04` -const DELTA: Fp = Fp::from_raw([ - 0x1916b2007775db04, - 0xc6cbb5faf3754a1e, - 0x70c23749b459b95c, - 0x21fb760c53233e91, - 0xf195b456887e1e00, - 0x42ed23fc8766d5a5, - 0x0eacefc6504d028d, -]); - -/// `ZETA^3 = 1 mod p` where `ZETA^2 != 1 mod p` -/// `0x480000000000360001c950000d7ee0e4a803c956d01c903d720dc8ad8b38dffaf50c100004c37ffffffe` -const ZETA: Fp = Fp::from_raw([ - 0x100004c37ffffffe, - 0xc8ad8b38dffaf50c, - 0xc956d01c903d720d, - 0x50000d7ee0e4a803, - 0x00000000360001c9, - 0x0000000000004800, - 0x0000000000000000, -]); - -/// NEG_ONE ; -1 mod p -pub(crate) const NEG_ONE: Fp = Fp::from_raw([ - 0x9ffffcd300000000, - 0xa2a7e8c30006b945, - 0xe4a7a5fe8fadffd6, - 0x443f9a5cda8a6c7b, - 0xa803ca76f439266f, - 0x0130e0000d7f70e4, - 0x2400000000002400, -]); - -impl_binops_additive!(Fp, Fp); -impl_binops_multiplicative!(Fp, Fp); -field_common_7_limbs!( - Fp, - FpRepr, - MODULUS, - INV, - MODULUS_STR, - TWO_INV, - ROOT_OF_UNITY_INV, - DELTA, - ZETA, - R, - R2, - R3 -); -impl_sum_prod!(Fp); -impl_from_u64_7_limbs!(Fp, R2); -field_arithmetic_7_limbs!(Fp, MODULUS, INV, sparse); - -#[cfg(target_pointer_width = "64")] -field_bits_7_limbs!(Fp, MODULUS); -#[cfg(not(target_pointer_width = "64"))] -field_bits_7_limbs!(Fp, MODULUS, MODULUS_LIMBS_32); - -extend_field_legendre!(Fp); - -impl Fp { - pub const fn size() -> usize { - SIZE - } -} - -impl ff::Field for Fp { - const ZERO: Self = Self::zero(); - const ONE: Self = Self::one(); - - fn random(mut rng: impl RngCore) -> Self { - Self::from_u512([ - rng.next_u64(), - rng.next_u64(), - rng.next_u64(), - rng.next_u64(), - rng.next_u64(), - rng.next_u64(), - rng.next_u64(), - rng.next_u64(), - ]) - } - - fn double(&self) -> Self { - self.double() - } - - #[inline(always)] - fn square(&self) -> Self { - self.square() - } - - /// Computes the multiplicative inverse of this element, - /// failing if the element is zero. - fn invert(&self) -> CtOption { - // self^(p - 2) - let tmp = self.pow([ - 0x9ffffcd2ffffffff, - 0xa2a7e8c30006b945, - 0xe4a7a5fe8fadffd6, - 0x443f9a5cda8a6c7b, - 0xa803ca76f439266f, - 0x0130e0000d7f70e4, - 0x2400000000002400, - ]); - - CtOption::new(tmp, !self.ct_eq(&Self::zero())) - } - - fn sqrt(&self) -> CtOption { - /// `(t - 1) // 2` where t * 2^s + 1 = p with t odd. - const T_MINUS1_OVER2: [u64; 7] = [ - 0x80035ca2cffffe69, - 0x47d6ffeb5153f461, - 0x6d45363df253d2ff, - 0x7a1c9337a21fcd2e, - 0x06bfb8725401e53b, - 0x0000120000987000, - 0x0000000012000000, - ]; - ff::helpers::sqrt_tonelli_shanks(self, T_MINUS1_OVER2) - } - - fn sqrt_ratio(num: &Self, div: &Self) -> (Choice, Self) { - ff::helpers::sqrt_ratio_generic(num, div) - } -} - -#[derive(Clone, Copy, Debug)] -/// Canonical little-endian representation of a `Fp` element. -pub struct FpRepr { - pub repr: [u8; SIZE], -} - -impl FpRepr { - /// Returns an iterator over the bytes of the canonical representation of the element. - pub fn iter(&self) -> Iter<'_, u8> { - self.repr.iter() - } -} - -impl Default for FpRepr { - fn default() -> Self { - FpRepr { repr: [0u8; SIZE] } - } -} - -impl AsRef<[u8]> for FpRepr { - fn as_ref(&self) -> &[u8] { - self.repr.as_ref() - } -} - -impl AsMut<[u8]> for FpRepr { - fn as_mut(&mut self) -> &mut [u8] { - self.repr.as_mut() - } -} -impl From<[u8; SIZE]> for FpRepr { - fn from(repr: [u8; SIZE]) -> Self { - Self { repr } - } -} - -impl ff::PrimeField for Fp { - type Repr = FpRepr; - - const NUM_BITS: u32 = 446; - const CAPACITY: u32 = 445; - const MODULUS: &'static str = MODULUS_STR; - const MULTIPLICATIVE_GENERATOR: Self = GENERATOR; - const ROOT_OF_UNITY: Self = ROOT_OF_UNITY; - const ROOT_OF_UNITY_INV: Self = ROOT_OF_UNITY_INV; - const TWO_INV: Self = TWO_INV; - const DELTA: Self = DELTA; - const S: u32 = S; - - fn from_repr(repr: Self::Repr) -> CtOption { - let mut tmp = Self([0, 0, 0, 0, 0, 0, 0]); - let repr = repr.repr; - - tmp.0[0] = u64::from_le_bytes(repr[0..8].try_into().unwrap()); - tmp.0[1] = u64::from_le_bytes(repr[8..16].try_into().unwrap()); - tmp.0[2] = u64::from_le_bytes(repr[16..24].try_into().unwrap()); - tmp.0[3] = u64::from_le_bytes(repr[24..32].try_into().unwrap()); - tmp.0[4] = u64::from_le_bytes(repr[32..40].try_into().unwrap()); - tmp.0[5] = u64::from_le_bytes(repr[40..48].try_into().unwrap()); - tmp.0[6] = u64::from_le_bytes(repr[48..56].try_into().unwrap()); - - // Try to subtract the modulus - let (_, borrow) = sbb(tmp.0[0], MODULUS.0[0], 0); - let (_, borrow) = sbb(tmp.0[1], MODULUS.0[1], borrow); - let (_, borrow) = sbb(tmp.0[2], MODULUS.0[2], borrow); - let (_, borrow) = sbb(tmp.0[3], MODULUS.0[3], borrow); - let (_, borrow) = sbb(tmp.0[4], MODULUS.0[4], borrow); - let (_, borrow) = sbb(tmp.0[5], MODULUS.0[5], borrow); - let (_, borrow) = sbb(tmp.0[6], MODULUS.0[6], borrow); - - // If the element is smaller than MODULUS then the - // subtraction will underflow, producing a borrow value - // of 0xffff...ffff. Otherwise, it'll be zero. - let is_some = (borrow as u8) & 1; - - // Convert to Montgomery form by computing - // (a.R^0 * R^2) / R = a.R - tmp *= &R2; - - CtOption::new(tmp, Choice::from(is_some)) - } - - fn to_repr(&self) -> Self::Repr { - // Turn into canonical form by computing - // (a.R) / R = a - let tmp = Self::montgomery_reduce(&[ - self.0[0], self.0[1], self.0[2], self.0[3], self.0[4], self.0[5], self.0[6], 0, 0, 0, - 0, 0, 0, 0, - ]); - - let mut res = [0; SIZE]; - res[0..8].copy_from_slice(&tmp.0[0].to_le_bytes()); - res[8..16].copy_from_slice(&tmp.0[1].to_le_bytes()); - res[16..24].copy_from_slice(&tmp.0[2].to_le_bytes()); - res[24..32].copy_from_slice(&tmp.0[3].to_le_bytes()); - res[32..40].copy_from_slice(&tmp.0[4].to_le_bytes()); - res[40..48].copy_from_slice(&tmp.0[5].to_le_bytes()); - res[48..56].copy_from_slice(&tmp.0[6].to_le_bytes()); - res.into() - } - - fn is_odd(&self) -> Choice { - Choice::from(self.to_repr().repr[0] & 1) - } -} - -impl FromUniformBytes<64> for Fp { - /// Converts a 512-bit little endian integer into - /// an `Fp` by reducing by the modulus. - fn from_uniform_bytes(bytes: &[u8; 64]) -> Self { - Self::from_u512([ - u64::from_le_bytes(bytes[0..8].try_into().unwrap()), - u64::from_le_bytes(bytes[8..16].try_into().unwrap()), - u64::from_le_bytes(bytes[16..24].try_into().unwrap()), - u64::from_le_bytes(bytes[24..32].try_into().unwrap()), - u64::from_le_bytes(bytes[32..40].try_into().unwrap()), - u64::from_le_bytes(bytes[40..48].try_into().unwrap()), - u64::from_le_bytes(bytes[48..56].try_into().unwrap()), - u64::from_le_bytes(bytes[56..64].try_into().unwrap()), - ]) - } -} - -impl WithSmallOrderMulGroup<3> for Fp { - const ZETA: Self = ZETA; -} - -#[cfg(test)] -mod test { - use super::*; - crate::field_testing_suite!(Fp, "field_arithmetic"); - crate::field_testing_suite!(Fp, "conversion"); - crate::field_testing_suite!(Fp, "serialization"); - crate::field_testing_suite!(Fp, "quadratic_residue"); - crate::field_testing_suite!(Fp, "bits"); - crate::field_testing_suite!(Fp, "serialization_check"); - crate::field_testing_suite!(Fp, "constants", MODULUS_STR); - crate::field_testing_suite!(Fp, "sqrt"); - crate::field_testing_suite!(Fp, "zeta"); - crate::field_testing_suite!(Fp, "from_uniform_bytes", 64); -} diff --git a/src/pluto_eris/fields/fq.rs b/src/pluto_eris/fields/fq.rs deleted file mode 100644 index 45d0f542..00000000 --- a/src/pluto_eris/fields/fq.rs +++ /dev/null @@ -1,406 +0,0 @@ -use crate::arithmetic::{adc, mac, sbb}; -use crate::ff::{FromUniformBytes, PrimeField, WithSmallOrderMulGroup}; -use crate::{ - extend_field_legendre, field_arithmetic_7_limbs, field_bits_7_limbs, field_common_7_limbs, - impl_from_u64_7_limbs, -}; -use crate::{ - impl_add_binop_specify_output, impl_binops_additive, impl_binops_additive_specify_output, - impl_binops_multiplicative, impl_binops_multiplicative_mixed, impl_sub_binop_specify_output, - impl_sum_prod, -}; -use core::convert::TryInto; -use core::fmt; -use core::ops::{Add, Mul, Neg, Sub}; -use rand::RngCore; -use std::slice::Iter; -use subtle::{Choice, ConditionallySelectable, ConstantTimeEq, CtOption}; - -#[cfg(feature = "derive_serde")] -use serde::{Deserialize, Serialize}; - -/// This represents an element of $\mathbb{F}_q$ where -/// -/// `q = 0x24000000000024000130e0000d7f70e4a803ca76f439266f443f9a5c7a8a6c7be4a775fe8e177fd69ca7e85d60050af41ffffcd300000001` -/// -/// is the scalar field of the Pluto curve (and the base field of the Eris curve). -/// The internal representation of this type is seven 64-bit unsigned -/// integers in little-endian order which account for the 446 bits required to be represented. -/// `Fq` values are always in Montgomery form; i.e., Fq(a) = aR mod q, with R = 2^448. -#[derive(Clone, Copy, PartialEq, Eq, Hash)] -#[cfg_attr(feature = "derive_serde", derive(Serialize, Deserialize))] -pub struct Fq(pub(crate) [u64; 7]); - -/// Size of `Fq` element in bytes -const SIZE: usize = 56; - -/// Constant representing the modulus -/// `p = 0x24000000000024000130e0000d7f70e4a803ca76f439266f443f9a5c7a8a6c7be4a775fe8e177fd69ca7e85d60050af41ffffcd300000001` -const MODULUS: Fq = Fq([ - 0x1ffffcd300000001, - 0x9ca7e85d60050af4, - 0xe4a775fe8e177fd6, - 0x443f9a5c7a8a6c7b, - 0xa803ca76f439266f, - 0x0130e0000d7f70e4, - 0x2400000000002400, -]); - -/// The modulus as u32 limbs. -#[cfg(not(target_pointer_width = "64"))] -const MODULUS_LIMBS_32: [u32; 14] = [ - 0x00000001, 0x1ffffcd3, 0x60050af4, 0x9ca7e85d, 0x8e177fd6, 0xe4a775fe, 0x7a8a6c7b, 0x443f9a5c, - 0xf439266f, 0xa803ca76, 0x0d7f70e4, 0x0130e000, 0x00002400, 0x24000000, -]; - -const MODULUS_STR: &str = "0x24000000000024000130e0000d7f70e4a803ca76f439266f443f9a5c7a8a6c7be4a775fe8e177fd69ca7e85d60050af41ffffcd300000001"; - -/// INV = -(q^{-1} mod 2^64) mod 2^64 -/// `0x1ffffcd2ffffffff` -const INV: u64 = 0x1ffffcd2ffffffff; - -/// Let M be the power of `2^64` nearest to `Self::MODULUS_BITS`. Then `R = M % Self::MODULUS`. -/// `R = 2^448 mod q` -/// `0x3ffffffffff03fff7a9dfffa183e9bf67e576bf526ff2f52242c778a637089cbf6bc60a1d5b8121b768a5725fdcb3532000163afffffff9` -const R: Fq = Fq([ - 0x2000163afffffff9, - 0xb768a5725fdcb353, - 0xbf6bc60a1d5b8121, - 0x2242c778a637089c, - 0x67e576bf526ff2f5, - 0xf7a9dfffa183e9bf, - 0x3ffffffffff03ff, -]); - -/// `R^2 = 2^896 mod q` -/// `0x50d7c998f46144ee436895a5a630ff544d51e923f64695651da4da1c97f716419bd905e6e4ff6c2bc64e865fe4552ad740808c831022522` -const R2: Fq = Fq([ - 0x740808c831022522, - 0xbc64e865fe4552ad, - 0x19bd905e6e4ff6c2, - 0x51da4da1c97f7164, - 0x44d51e923f646956, - 0xe436895a5a630ff5, - 0x050d7c998f46144e, -]); - -/// `R^3 = 2^1792 mod q` -/// `0x2f2c41fb476072baa10b8225e69f7de3b2c1031e6d01279e65191fab1f6ce25295c3c8bd6945406c89b51b218477a6f7252704d7495b38a` -const R3: Fq = Fq([ - 0x7252704d7495b38a, - 0xc89b51b218477a6f, - 0x295c3c8bd6945406, - 0xe65191fab1f6ce25, - 0x3b2c1031e6d01279, - 0xaa10b8225e69f7de, - 0x02f2c41fb476072b, -]); - -/// `GENERATOR = 7 mod q` is a generator of the `q - 1` order multiplicative -/// subgroup, or in other words a primitive root of the field. -const GENERATOR: Fq = Fq::from_raw([0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]); - -/// Size of the 2-adic sub-group of the field. -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. -/// `0x0a5e6f78289fd24b1c64c90821c44cdce9ba1b3e90f2e88957f869667f6dfdbdbce6bb9ed38a8c2382fa11e3d3810fcc3c7bb406ec7bce04` - -const ROOT_OF_UNITY: Fq = Fq::from_raw([ - 0x3c7bb406ec7bce04, - 0x82fa11e3d3810fcc, - 0xbce6bb9ed38a8c23, - 0x57f869667f6dfdbd, - 0xe9ba1b3e90f2e889, - 0x1c64c90821c44cdc, - 0x0a5e6f78289fd24b, -]); - -/// 1 / ROOT_OF_UNITY mod q -/// `0x1a8c636e293fe9928f85aa6ec68f950ebb57e3f0502dd05667c990c1c2f57128c77768be1824fd3f60869f410287a1879ec16a35ca69b6fb` - -const ROOT_OF_UNITY_INV: Fq = Fq::from_raw([ - 0x9ec16a35ca69b6fb, - 0x60869f410287a187, - 0xc77768be1824fd3f, - 0x67c990c1c2f57128, - 0xbb57e3f0502dd056, - 0x8f85aa6ec68f950e, - 0x1a8c636e293fe992, -]); - -/// 1 / 2 mod q -/// `0x12000000000012000098700006bfb8725401e53b7a1c9337a21fcd2e3d45363df253baff470bbfeb4e53f42eb002857a0ffffe6980000001` -const TWO_INV: Fq = Fq::from_raw([ - 0x0ffffe6980000001, - 0x4e53f42eb002857a, - 0xf253baff470bbfeb, - 0xa21fcd2e3d45363d, - 0x5401e53b7a1c9337, - 0x0098700006bfb872, - 0x1200000000001200, -]); - -/// GENERATOR^{2^s} where t * 2^s + 1 = q with t odd. In other words, this is a t root of unity. -/// 0x657946fe07116ceca983fe28713a2b257ab7a7866c95121e727f3776c3e84cb0a14f6a7f83f8cdaeadb479c657bdf2de4589640faf72e67 -const DELTA: Fq = Fq::from_raw([ - 0xe4589640faf72e67, - 0xeadb479c657bdf2d, - 0x0a14f6a7f83f8cda, - 0xe727f3776c3e84cb, - 0x57ab7a7866c95121, - 0xca983fe28713a2b2, - 0x657946fe07116ce, -]); - -/// `ZETA^3 = 1 mod q` where `ZETA^2 != 1 mod q` -/// `0x9000000000006c000392a0001afee1c9500792ae3039253e641ba35817a29ffaf50be000032cfffffffe` - -const ZETA: Fq = Fq::from_raw([ - 0xe000032cfffffffe, - 0xa35817a29ffaf50b, - 0x92ae3039253e641b, - 0xa0001afee1c95007, - 0x000000006c000392, - 0x0000000000009000, - 0x0000000000000000, -]); - -impl_binops_additive!(Fq, Fq); -impl_binops_multiplicative!(Fq, Fq); -field_common_7_limbs!( - Fq, - FqRepr, - MODULUS, - INV, - MODULUS_STR, - TWO_INV, - ROOT_OF_UNITY_INV, - DELTA, - ZETA, - R, - R2, - R3 -); -impl_sum_prod!(Fq); -impl_from_u64_7_limbs!(Fq, R2); -field_arithmetic_7_limbs!(Fq, MODULUS, INV, sparse); - -#[cfg(target_pointer_width = "64")] -field_bits_7_limbs!(Fq, MODULUS); -#[cfg(not(target_pointer_width = "64"))] -field_bits_7_limbs!(Fq, MODULUS, MODULUS_LIMBS_32); - -extend_field_legendre!(Fq); - -impl Fq { - /// Return field element size in bytes. - pub const fn size() -> usize { - SIZE - } -} - -impl ff::Field for Fq { - const ZERO: Self = Self::zero(); - const ONE: Self = Self::one(); - - fn random(mut rng: impl RngCore) -> Self { - Self::from_u512([ - rng.next_u64(), - rng.next_u64(), - rng.next_u64(), - rng.next_u64(), - rng.next_u64(), - rng.next_u64(), - rng.next_u64(), - rng.next_u64(), - ]) - } - - fn double(&self) -> Self { - self.double() - } - - #[inline(always)] - fn square(&self) -> Self { - self.square() - } - - /// Computes the multiplicative inverse of this element, - /// failing if the element is zero. - fn invert(&self) -> CtOption { - // self^(q - 2) - let tmp = self.pow_vartime([ - 0x1ffffcd2ffffffff, - 0x9ca7e85d60050af4, - 0xe4a775fe8e177fd6, - 0x443f9a5c7a8a6c7b, - 0xa803ca76f439266f, - 0x0130e0000d7f70e4, - 0x2400000000002400, - ]); - - CtOption::new(tmp, !self.ct_eq(&Self::zero())) - } - - fn sqrt(&self) -> CtOption { - /// `(t - 1) // 2` where t * 2^s + 1 = q with t odd. - const T_MINUS1_OVER2: [u64; 7] = [ - 0xb002857a0ffffe69, - 0x470bbfeb4e53f42e, - 0x3d45363df253baff, - 0x7a1c9337a21fcd2e, - 0x06bfb8725401e53b, - 0x0000120000987000, - 0x0000000012000000, - ]; - ff::helpers::sqrt_tonelli_shanks(self, T_MINUS1_OVER2) - } - - fn sqrt_ratio(num: &Self, div: &Self) -> (Choice, Self) { - ff::helpers::sqrt_ratio_generic(num, div) - } -} - -#[derive(Clone, Copy, Debug)] -/// Canonical little-endian representation of a `Fq` element. -pub struct FqRepr { - pub repr: [u8; SIZE], -} - -impl FqRepr { - /// Returns an iterator over the bytes of the canonical representation of the element. - pub fn iter(&self) -> Iter<'_, u8> { - self.repr.iter() - } -} - -impl Default for FqRepr { - fn default() -> Self { - FqRepr { repr: [0u8; SIZE] } - } -} - -impl AsRef<[u8]> for FqRepr { - fn as_ref(&self) -> &[u8] { - self.repr.as_ref() - } -} - -impl AsMut<[u8]> for FqRepr { - fn as_mut(&mut self) -> &mut [u8] { - self.repr.as_mut() - } -} -impl From<[u8; SIZE]> for FqRepr { - fn from(repr: [u8; SIZE]) -> Self { - Self { repr } - } -} - -impl ff::PrimeField for Fq { - type Repr = FqRepr; - - const NUM_BITS: u32 = 446; - const CAPACITY: u32 = 445; - const MODULUS: &'static str = MODULUS_STR; - const MULTIPLICATIVE_GENERATOR: Self = GENERATOR; - const ROOT_OF_UNITY: Self = ROOT_OF_UNITY; - const ROOT_OF_UNITY_INV: Self = ROOT_OF_UNITY_INV; - const TWO_INV: Self = TWO_INV; - const DELTA: Self = DELTA; - const S: u32 = S; - - fn from_repr(repr: Self::Repr) -> CtOption { - let mut tmp = Self([0, 0, 0, 0, 0, 0, 0]); - let repr = repr.repr; - - tmp.0[0] = u64::from_le_bytes(repr[0..8].try_into().unwrap()); - tmp.0[1] = u64::from_le_bytes(repr[8..16].try_into().unwrap()); - tmp.0[2] = u64::from_le_bytes(repr[16..24].try_into().unwrap()); - tmp.0[3] = u64::from_le_bytes(repr[24..32].try_into().unwrap()); - tmp.0[4] = u64::from_le_bytes(repr[32..40].try_into().unwrap()); - tmp.0[5] = u64::from_le_bytes(repr[40..48].try_into().unwrap()); - tmp.0[6] = u64::from_le_bytes(repr[48..56].try_into().unwrap()); - - // Try to subtract the modulus - let (_, borrow) = sbb(tmp.0[0], MODULUS.0[0], 0); - let (_, borrow) = sbb(tmp.0[1], MODULUS.0[1], borrow); - let (_, borrow) = sbb(tmp.0[2], MODULUS.0[2], borrow); - let (_, borrow) = sbb(tmp.0[3], MODULUS.0[3], borrow); - let (_, borrow) = sbb(tmp.0[4], MODULUS.0[4], borrow); - let (_, borrow) = sbb(tmp.0[5], MODULUS.0[5], borrow); - let (_, borrow) = sbb(tmp.0[6], MODULUS.0[6], borrow); - - // If the element is smaller than MODULUS then the - // subtraction will underflow, producing a borrow value - // of 0xffff...ffff. Otherwise, it'll be zero. - let is_some = (borrow as u8) & 1; - - // Convert to Montgomery form by computing - // (a.R^0 * R^2) / R = a.R - tmp *= &R2; - - CtOption::new(tmp, Choice::from(is_some)) - } - - fn to_repr(&self) -> Self::Repr { - // Turn into canonical form by computing - // (a.R) / R = a - let tmp = Self::montgomery_reduce(&[ - self.0[0], self.0[1], self.0[2], self.0[3], self.0[4], self.0[5], self.0[6], 0, 0, 0, - 0, 0, 0, 0, - ]); - - let mut res = [0; SIZE]; - res[0..8].copy_from_slice(&tmp.0[0].to_le_bytes()); - res[8..16].copy_from_slice(&tmp.0[1].to_le_bytes()); - res[16..24].copy_from_slice(&tmp.0[2].to_le_bytes()); - res[24..32].copy_from_slice(&tmp.0[3].to_le_bytes()); - res[32..40].copy_from_slice(&tmp.0[4].to_le_bytes()); - res[40..48].copy_from_slice(&tmp.0[5].to_le_bytes()); - res[48..56].copy_from_slice(&tmp.0[6].to_le_bytes()); - res.into() - } - - fn is_odd(&self) -> Choice { - Choice::from(self.to_repr().repr[0] & 1) - } -} - -impl FromUniformBytes<64> for Fq { - /// Converts a 512-bit little endian integer into - /// an `Fq` by reducing by the modulus. - fn from_uniform_bytes(bytes: &[u8; 64]) -> Self { - Self::from_u512([ - u64::from_le_bytes(bytes[0..8].try_into().unwrap()), - u64::from_le_bytes(bytes[8..16].try_into().unwrap()), - u64::from_le_bytes(bytes[16..24].try_into().unwrap()), - u64::from_le_bytes(bytes[24..32].try_into().unwrap()), - u64::from_le_bytes(bytes[32..40].try_into().unwrap()), - u64::from_le_bytes(bytes[40..48].try_into().unwrap()), - u64::from_le_bytes(bytes[48..56].try_into().unwrap()), - u64::from_le_bytes(bytes[56..64].try_into().unwrap()), - ]) - } -} - -impl WithSmallOrderMulGroup<3> for Fq { - const ZETA: Self = ZETA; -} - -#[cfg(test)] -mod test { - use super::*; - crate::field_testing_suite!(Fq, "field_arithmetic"); - crate::field_testing_suite!(Fq, "conversion"); - crate::field_testing_suite!(Fq, "serialization"); - crate::field_testing_suite!(Fq, "quadratic_residue"); - crate::field_testing_suite!(Fq, "bits"); - crate::field_testing_suite!(Fq, "serialization_check"); - crate::field_testing_suite!(Fq, "constants", MODULUS_STR); - crate::field_testing_suite!(Fq, "sqrt"); - crate::field_testing_suite!(Fq, "zeta"); - crate::field_testing_suite!(Fq, "from_uniform_bytes", 64); -} diff --git a/src/pluto_eris/fields/mod.rs b/src/pluto_eris/fields/mod.rs deleted file mode 100644 index 307f92d3..00000000 --- a/src/pluto_eris/fields/mod.rs +++ /dev/null @@ -1,843 +0,0 @@ -pub mod fp; -pub mod fp12; -pub mod fp2; -pub mod fp6; -pub mod fq; - -#[macro_export] -macro_rules! impl_from_u64_7_limbs { - ($field:ident, $r2:ident) => { - impl From for $field { - fn from(val: u64) -> $field { - $field([val, 0, 0, 0, 0, 0, 0]) * $r2 - } - } - }; -} - -#[macro_export] -macro_rules! field_common_7_limbs { - ( - $field:ident, - $field_repr:ident, - $modulus:ident, - $inv:ident, - $modulus_str:ident, - $two_inv:ident, - $root_of_unity_inv:ident, - $delta:ident, - $zeta:ident, - $r:ident, - $r2:ident, - $r3:ident - ) => { - impl $field { - /// Returns zero, the additive identity. - #[inline] - pub const fn zero() -> $field { - $field([0, 0, 0, 0, 0, 0, 0]) - } - - /// Returns one, the multiplicative identity. - #[inline] - pub const fn one() -> $field { - $r - } - - // Returns the Jacobi symbol, where the numerator and denominator - // are the element and the characteristic of the field, respectively. - // The Jacobi symbol is applicable to odd moduli - // while the Legendre symbol is applicable to prime moduli. - // They are equivalent for prime moduli. - #[inline(always)] - pub fn jacobi(&self) -> i64 { - $crate::ff_ext::jacobi::jacobi::<8>(&self.0, &$modulus.0) - } - - fn from_u512(limbs: [u64; 8]) -> $field { - let d0 = $field([ - limbs[0], limbs[1], limbs[2], limbs[3], limbs[4], limbs[5], limbs[6], - ]); - let d1 = $field([limbs[7], 0, 0, 0, 0, 0, 0]); - - d0 * $r2 + d1 * $r3 - } - - /// Converts from an integer represented in little endian - /// into its (congruent) `$field` representation. - pub const fn from_raw(val: [u64; 7]) -> Self { - #[cfg(feature = "asm")] - { - let (r0, carry) = mac(0, val[0], $r2.0[0], 0); - let (r1, carry) = mac(0, val[0], $r2.0[1], carry); - let (r2, carry) = mac(0, val[0], $r2.0[2], carry); - let (r3, carry) = mac(0, val[0], $r2.0[3], carry); - let (r4, carry) = mac(0, val[0], $r2.0[4], carry); - let (r5, carry) = mac(0, val[0], $r2.0[5], carry); - let (r6, r7) = mac(0, val[0], $r2.0[6], carry); - - let (r1, carry) = mac(r1, val[1], $r2.0[0], 0); - let (r2, carry) = mac(r2, val[1], $r2.0[1], carry); - let (r3, carry) = mac(r3, val[1], $r2.0[2], carry); - let (r4, carry) = mac(r4, val[1], $r2.0[3], carry); - let (r5, carry) = mac(r5, val[1], $r2.0[4], carry); - let (r6, carry) = mac(r6, val[1], $r2.0[5], carry); - let (r7, r8) = mac(r7, val[1], $r2.0[6], carry); - - let (r2, carry) = mac(r2, val[2], $r2.0[0], 0); - let (r3, carry) = mac(r3, val[2], $r2.0[1], carry); - let (r4, carry) = mac(r4, val[2], $r2.0[2], carry); - let (r5, carry) = mac(r5, val[2], $r2.0[3], carry); - let (r6, carry) = mac(r6, val[2], $r2.0[4], carry); - let (r7, carry) = mac(r7, val[2], $r2.0[5], carry); - let (r8, r9) = mac(r8, val[2], $r2.0[6], carry); - - let (r3, carry) = mac(r3, val[3], $r2.0[0], 0); - let (r4, carry) = mac(r4, val[3], $r2.0[1], carry); - let (r5, carry) = mac(r5, val[3], $r2.0[2], carry); - let (r6, carry) = mac(r6, val[3], $r2.0[3], carry); - let (r7, carry) = mac(r7, val[3], $r2.0[4], carry); - let (r8, carry) = mac(r8, val[3], $r2.0[5], carry); - let (r9, r10) = mac(r9, val[3], $r2.0[6], carry); - - let (r4, carry) = mac(r4, val[4], $r2.0[0], 0); - let (r5, carry) = mac(r5, val[4], $r2.0[1], carry); - let (r6, carry) = mac(r6, val[4], $r2.0[2], carry); - let (r7, carry) = mac(r7, val[4], $r2.0[3], carry); - let (r8, carry) = mac(r8, val[4], $r2.0[4], carry); - let (r9, carry) = mac(r9, val[4], $r2.0[5], carry); - let (r10, r11) = mac(r10, val[4], $r2.0[6], carry); - - let (r5, carry) = mac(r5, val[5], $r2.0[0], 0); - let (r6, carry) = mac(r6, val[5], $r2.0[1], carry); - let (r7, carry) = mac(r7, val[5], $r2.0[2], carry); - let (r8, carry) = mac(r8, val[5], $r2.0[3], carry); - let (r9, carry) = mac(r9, val[5], $r2.0[4], carry); - let (r10, carry) = mac(r10, val[5], $r2.0[5], carry); - let (r11, r12) = mac(r11, val[5], $r2.0[6], carry); - - let (r6, carry) = mac(r6, val[6], $r2.0[0], 0); - let (r7, carry) = mac(r7, val[6], $r2.0[1], carry); - let (r8, carry) = mac(r8, val[6], $r2.0[2], carry); - let (r9, carry) = mac(r9, val[6], $r2.0[3], carry); - let (r10, carry) = mac(r10, val[6], $r2.0[4], carry); - let (r11, carry) = mac(r11, val[6], $r2.0[5], carry); - let (r12, r13) = mac(r12, val[6], $r2.0[6], carry); - - // Montgomery reduction - let k = r0.wrapping_mul($inv); - let (_, carry) = mac(r0, k, $modulus.0[0], 0); - let (r1, carry) = mac(r1, k, $modulus.0[1], carry); - let (r2, carry) = mac(r2, k, $modulus.0[2], carry); - let (r3, carry) = mac(r3, k, $modulus.0[3], carry); - let (r4, carry) = mac(r4, k, $modulus.0[4], carry); - let (r5, carry) = mac(r5, k, $modulus.0[5], carry); - let (r6, carry) = mac(r6, k, $modulus.0[6], carry); - let (r7, carry2) = adc(r7, 0, carry); - - let k = r1.wrapping_mul($inv); - let (_, carry) = mac(r1, k, $modulus.0[0], 0); - let (r2, carry) = mac(r2, k, $modulus.0[1], carry); - let (r3, carry) = mac(r3, k, $modulus.0[2], carry); - let (r4, carry) = mac(r4, k, $modulus.0[3], carry); - let (r5, carry) = mac(r5, k, $modulus.0[4], carry); - let (r6, carry) = mac(r6, k, $modulus.0[5], carry); - let (r7, carry) = mac(r7, k, $modulus.0[6], carry); - let (r8, carry2) = adc(r8, carry2, carry); - - let k = r2.wrapping_mul($inv); - let (_, carry) = mac(r2, k, $modulus.0[0], 0); - let (r3, carry) = mac(r3, k, $modulus.0[1], carry); - let (r4, carry) = mac(r4, k, $modulus.0[2], carry); - let (r5, carry) = mac(r5, k, $modulus.0[3], carry); - let (r6, carry) = mac(r6, k, $modulus.0[4], carry); - let (r7, carry) = mac(r7, k, $modulus.0[5], carry); - let (r8, carry) = mac(r8, k, $modulus.0[6], carry); - let (r9, carry2) = adc(r9, carry2, carry); - - let k = r3.wrapping_mul($inv); - let (_, carry) = mac(r3, k, $modulus.0[0], 0); - let (r4, carry) = mac(r4, k, $modulus.0[1], carry); - let (r5, carry) = mac(r5, k, $modulus.0[2], carry); - let (r6, carry) = mac(r6, k, $modulus.0[3], carry); - let (r7, carry) = mac(r7, k, $modulus.0[4], carry); - let (r8, carry) = mac(r8, k, $modulus.0[5], carry); - let (r9, carry) = mac(r9, k, $modulus.0[6], carry); - let (r10, carry2) = adc(r10, carry2, carry); - - let k = r4.wrapping_mul($inv); - let (_, carry) = mac(r4, k, $modulus.0[0], 0); - let (r5, carry) = mac(r5, k, $modulus.0[1], carry); - let (r6, carry) = mac(r6, k, $modulus.0[2], carry); - let (r7, carry) = mac(r7, k, $modulus.0[3], carry); - let (r8, carry) = mac(r8, k, $modulus.0[4], carry); - let (r9, carry) = mac(r9, k, $modulus.0[5], carry); - let (r10, carry) = mac(r10, k, $modulus.0[6], carry); - let (r11, carry2) = adc(r11, carry2, carry); - - let k = r5.wrapping_mul($inv); - let (_, carry) = mac(r5, k, $modulus.0[0], 0); - let (r6, carry) = mac(r6, k, $modulus.0[1], carry); - let (r7, carry) = mac(r7, k, $modulus.0[2], carry); - let (r8, carry) = mac(r8, k, $modulus.0[3], carry); - let (r9, carry) = mac(r9, k, $modulus.0[4], carry); - let (r10, carry) = mac(r10, k, $modulus.0[5], carry); - let (r11, carry) = mac(r11, k, $modulus.0[6], carry); - let (r12, carry2) = adc(r12, carry2, carry); - - let k = r6.wrapping_mul($inv); - let (_, carry) = mac(r6, k, $modulus.0[0], 0); - let (r7, carry) = mac(r7, k, $modulus.0[1], carry); - let (r8, carry) = mac(r8, k, $modulus.0[2], carry); - let (r9, carry) = mac(r9, k, $modulus.0[3], carry); - let (r10, carry) = mac(r10, k, $modulus.0[4], carry); - let (r11, carry) = mac(r11, k, $modulus.0[5], carry); - let (r12, carry) = mac(r12, k, $modulus.0[6], carry); - let (r13, carry2) = adc(r13, carry2, carry); - - // Result may be within MODULUS of the correct value - let (d0, borrow) = sbb(r7, $modulus.0[0], 0); - let (d1, borrow) = sbb(r8, $modulus.0[1], borrow); - let (d2, borrow) = sbb(r9, $modulus.0[2], borrow); - let (d3, borrow) = sbb(r10, $modulus.0[3], borrow); - let (d4, borrow) = sbb(r11, $modulus.0[4], borrow); - let (d5, borrow) = sbb(r12, $modulus.0[5], borrow); - let (d6, borrow) = sbb(r13, $modulus.0[6], borrow); - let (_, borrow) = sbb(carry2, 0, borrow); - let (d0, carry) = adc(d0, $modulus.0[0] & borrow, 0); - let (d1, carry) = adc(d1, $modulus.0[1] & borrow, carry); - let (d2, carry) = adc(d2, $modulus.0[2] & borrow, carry); - let (d3, carry) = adc(d3, $modulus.0[3] & borrow, carry); - let (d4, carry) = adc(d4, $modulus.0[4] & borrow, carry); - let (d5, carry) = adc(d5, $modulus.0[5] & borrow, carry); - let (d6, _) = adc(d6, $modulus.0[6] & borrow, carry); - - $field([d0, d1, d2, d3, d4, d5, d6]) - } - #[cfg(not(feature = "asm"))] - { - (&$field(val)).mul(&$r2) - } - } - - /// Attempts to convert a little-endian byte representation of - /// a scalar into a `Fr`, failing if the input is not canonical. - pub fn from_bytes(bytes: &[u8; 56]) -> CtOption<$field> { - ::from_repr($field_repr { repr: *bytes }) - } - - /// Converts an element of `Fr` into a byte representation in - /// little-endian byte order. - pub fn to_bytes(&self) -> [u8; 56] { - ::to_repr(self).repr - } - - /// Lexicographic comparison of Montgomery forms. - #[inline(always)] - const fn is_less_than(x: &[u64; 7], y: &[u64; 7]) -> bool { - let (_, borrow) = sbb(x[0], y[0], 0); - let (_, borrow) = sbb(x[1], y[1], borrow); - let (_, borrow) = sbb(x[2], y[2], borrow); - let (_, borrow) = sbb(x[3], y[3], borrow); - let (_, borrow) = sbb(x[4], y[4], borrow); - let (_, borrow) = sbb(x[5], y[5], borrow); - let (_, borrow) = sbb(x[6], y[6], borrow); - borrow >> 63 == 1 - } - } - - impl fmt::Debug for $field { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - let tmp = self.to_repr(); - write!(f, "0x")?; - for &b in tmp.iter().rev() { - write!(f, "{:02x}", b)?; - } - Ok(()) - } - } - - impl Default for $field { - #[inline] - fn default() -> Self { - Self::zero() - } - } - - impl From for $field { - fn from(bit: bool) -> $field { - if bit { - $field::one() - } else { - $field::zero() - } - } - } - - impl ConstantTimeEq for $field { - fn ct_eq(&self, other: &Self) -> Choice { - self.0[0].ct_eq(&other.0[0]) - & self.0[1].ct_eq(&other.0[1]) - & self.0[2].ct_eq(&other.0[2]) - & self.0[3].ct_eq(&other.0[3]) - & self.0[4].ct_eq(&other.0[4]) - & self.0[5].ct_eq(&other.0[5]) - & self.0[6].ct_eq(&other.0[6]) - } - } - - impl core::cmp::Ord for $field { - fn cmp(&self, other: &Self) -> core::cmp::Ordering { - let left = self.to_repr(); - let right = other.to_repr(); - left.iter() - .zip(right.iter()) - .rev() - .find_map(|(left_byte, right_byte)| match left_byte.cmp(right_byte) { - core::cmp::Ordering::Equal => None, - res => Some(res), - }) - .unwrap_or(core::cmp::Ordering::Equal) - } - } - - impl core::cmp::PartialOrd for $field { - fn partial_cmp(&self, other: &Self) -> Option { - Some(self.cmp(other)) - } - } - - impl ConditionallySelectable for $field { - fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self { - $field([ - u64::conditional_select(&a.0[0], &b.0[0], choice), - u64::conditional_select(&a.0[1], &b.0[1], choice), - u64::conditional_select(&a.0[2], &b.0[2], choice), - u64::conditional_select(&a.0[3], &b.0[3], choice), - u64::conditional_select(&a.0[4], &b.0[4], choice), - u64::conditional_select(&a.0[5], &b.0[5], choice), - u64::conditional_select(&a.0[6], &b.0[6], choice), - ]) - } - } - - impl<'a> Neg for &'a $field { - type Output = $field; - - #[inline] - fn neg(self) -> $field { - self.neg() - } - } - - impl Neg for $field { - type Output = $field; - - #[inline] - fn neg(self) -> $field { - -&self - } - } - - impl<'a, 'b> Sub<&'b $field> for &'a $field { - type Output = $field; - - #[inline] - fn sub(self, rhs: &'b $field) -> $field { - self.sub(rhs) - } - } - - impl<'a, 'b> Add<&'b $field> for &'a $field { - type Output = $field; - - #[inline] - fn add(self, rhs: &'b $field) -> $field { - self.add(rhs) - } - } - - impl<'a, 'b> Mul<&'b $field> for &'a $field { - type Output = $field; - - #[inline] - fn mul(self, rhs: &'b $field) -> $field { - self.mul(rhs) - } - } - - impl From<$field> for [u8; 56] { - fn from(value: $field) -> [u8; 56] { - value.to_repr().repr - } - } - - impl<'a> From<&'a $field> for [u8; 56] { - fn from(value: &'a $field) -> [u8; 56] { - value.to_repr().repr - } - } - - impl $crate::serde::SerdeObject for $field { - fn from_raw_bytes_unchecked(bytes: &[u8]) -> Self { - debug_assert_eq!(bytes.len(), 56); - let inner = [0, 8, 16, 24, 32, 40, 48] - .map(|i| u64::from_le_bytes(bytes[i..i + 8].try_into().unwrap())); - Self(inner) - } - fn from_raw_bytes(bytes: &[u8]) -> Option { - if bytes.len() != 56 { - return None; - } - let elt = Self::from_raw_bytes_unchecked(bytes); - Self::is_less_than(&elt.0, &$modulus.0).then(|| elt) - } - fn to_raw_bytes(&self) -> Vec { - let mut res = Vec::with_capacity(56); - for limb in self.0.iter() { - res.extend_from_slice(&limb.to_le_bytes()); - } - res - } - fn read_raw_unchecked(reader: &mut R) -> Self { - let inner = [(); 7].map(|_| { - let mut buf = [0; 8]; - reader.read_exact(&mut buf).unwrap(); - u64::from_le_bytes(buf) - }); - Self(inner) - } - fn read_raw(reader: &mut R) -> std::io::Result { - let mut inner = [0u64; 7]; - for limb in inner.iter_mut() { - let mut buf = [0; 8]; - reader.read_exact(&mut buf)?; - *limb = u64::from_le_bytes(buf); - } - let elt = Self(inner); - Self::is_less_than(&elt.0, &$modulus.0) - .then(|| elt) - .ok_or_else(|| { - std::io::Error::new( - std::io::ErrorKind::InvalidData, - "input number is not less than field modulus", - ) - }) - } - fn write_raw(&self, writer: &mut W) -> std::io::Result<()> { - for limb in self.0.iter() { - writer.write_all(&limb.to_le_bytes())?; - } - Ok(()) - } - } - }; -} - -#[macro_export] -macro_rules! field_arithmetic_7_limbs { - ($field:ident, $modulus:ident, $inv:ident, $field_type:ident) => { - $crate::field_specific_7_limbs!($field, $modulus, $inv, $field_type); - impl $field { - /// Doubles this field element. - #[inline] - pub const fn double(&self) -> $field { - self.add(self) - } - - /// Squares this element. - #[inline] - pub const fn square(&self) -> $field { - let (r1, carry) = mac(0, self.0[0], self.0[1], 0); - let (r2, carry) = mac(0, self.0[0], self.0[2], carry); - let (r3, carry) = mac(0, self.0[0], self.0[3], carry); - let (r4, carry) = mac(0, self.0[0], self.0[4], carry); - let (r5, carry) = mac(0, self.0[0], self.0[5], carry); - let (r6, r7) = mac(0, self.0[0], self.0[6], carry); - - let (r3, carry) = mac(r3, self.0[1], self.0[2], 0); - let (r4, carry) = mac(r4, self.0[1], self.0[3], carry); - let (r5, carry) = mac(r5, self.0[1], self.0[4], carry); - let (r6, carry) = mac(r6, self.0[1], self.0[5], carry); - let (r7, r8) = mac(r7, self.0[1], self.0[6], carry); - - let (r5, carry) = mac(r5, self.0[2], self.0[3], 0); - let (r6, carry) = mac(r6, self.0[2], self.0[4], carry); - let (r7, carry) = mac(r7, self.0[2], self.0[5], carry); - let (r8, r9) = mac(r8, self.0[2], self.0[6], carry); - - let (r7, carry) = mac(r7, self.0[3], self.0[4], 0); - let (r8, carry) = mac(r8, self.0[3], self.0[5], carry); - let (r9, r10) = mac(r9, self.0[3], self.0[6], carry); - - let (r9, carry) = mac(r9, self.0[4], self.0[5], 0); - let (r10, r11) = mac(r10, self.0[4], self.0[6], carry); - - let (r11, r12) = mac(r11, self.0[5], self.0[6], 0); - - let r13 = r12 >> 63; - let r12 = (r12 << 1) | (r11 >> 63); - let r11 = (r11 << 1) | (r10 >> 63); - let r10 = (r10 << 1) | (r9 >> 63); - let r9 = (r9 << 1) | (r8 >> 63); - let r8 = (r8 << 1) | (r7 >> 63); - let r7 = (r7 << 1) | (r6 >> 63); - let r6 = (r6 << 1) | (r5 >> 63); - let r5 = (r5 << 1) | (r4 >> 63); - let r4 = (r4 << 1) | (r3 >> 63); - let r3 = (r3 << 1) | (r2 >> 63); - let r2 = (r2 << 1) | (r1 >> 63); - let r1 = r1 << 1; - - let (r0, carry) = mac(0, self.0[0], self.0[0], 0); - let (r1, carry) = adc(0, r1, carry); - let (r2, carry) = mac(r2, self.0[1], self.0[1], carry); - let (r3, carry) = adc(0, r3, carry); - let (r4, carry) = mac(r4, self.0[2], self.0[2], carry); - let (r5, carry) = adc(0, r5, carry); - let (r6, carry) = mac(r6, self.0[3], self.0[3], carry); - let (r7, carry) = adc(0, r7, carry); - let (r8, carry) = mac(r8, self.0[4], self.0[4], carry); - let (r9, carry) = adc(0, r9, carry); - let (r10, carry) = mac(r10, self.0[5], self.0[5], carry); - let (r11, carry) = adc(0, r11, carry); - let (r12, carry) = mac(r12, self.0[6], self.0[6], carry); - let (r13, _) = adc(0, r13, carry); - - $field::montgomery_reduce(&[ - r0, r1, r2, r3, r4, r5, r6, r7, r8, r9, r10, r11, r12, r13, - ]) - } - - /// Multiplies `rhs` by `self`, returning the result. - #[inline] - pub const fn mul(&self, rhs: &Self) -> $field { - // Schoolbook multiplication - let (r0, carry) = mac(0, self.0[0], rhs.0[0], 0); - let (r1, carry) = mac(0, self.0[0], rhs.0[1], carry); - let (r2, carry) = mac(0, self.0[0], rhs.0[2], carry); - let (r3, carry) = mac(0, self.0[0], rhs.0[3], carry); - let (r4, carry) = mac(0, self.0[0], rhs.0[4], carry); - let (r5, carry) = mac(0, self.0[0], rhs.0[5], carry); - let (r6, r7) = mac(0, self.0[0], rhs.0[6], carry); - - let (r1, carry) = mac(r1, self.0[1], rhs.0[0], 0); - let (r2, carry) = mac(r2, self.0[1], rhs.0[1], carry); - let (r3, carry) = mac(r3, self.0[1], rhs.0[2], carry); - let (r4, carry) = mac(r4, self.0[1], rhs.0[3], carry); - let (r5, carry) = mac(r5, self.0[1], rhs.0[4], carry); - let (r6, carry) = mac(r6, self.0[1], rhs.0[5], carry); - let (r7, r8) = mac(r7, self.0[1], rhs.0[6], carry); - - let (r2, carry) = mac(r2, self.0[2], rhs.0[0], 0); - let (r3, carry) = mac(r3, self.0[2], rhs.0[1], carry); - let (r4, carry) = mac(r4, self.0[2], rhs.0[2], carry); - let (r5, carry) = mac(r5, self.0[2], rhs.0[3], carry); - let (r6, carry) = mac(r6, self.0[2], rhs.0[4], carry); - let (r7, carry) = mac(r7, self.0[2], rhs.0[5], carry); - let (r8, r9) = mac(r8, self.0[2], rhs.0[6], carry); - - let (r3, carry) = mac(r3, self.0[3], rhs.0[0], 0); - let (r4, carry) = mac(r4, self.0[3], rhs.0[1], carry); - let (r5, carry) = mac(r5, self.0[3], rhs.0[2], carry); - let (r6, carry) = mac(r6, self.0[3], rhs.0[3], carry); - let (r7, carry) = mac(r7, self.0[3], rhs.0[4], carry); - let (r8, carry) = mac(r8, self.0[3], rhs.0[5], carry); - let (r9, r10) = mac(r9, self.0[3], rhs.0[6], carry); - - let (r4, carry) = mac(r4, self.0[4], rhs.0[0], 0); - let (r5, carry) = mac(r5, self.0[4], rhs.0[1], carry); - let (r6, carry) = mac(r6, self.0[4], rhs.0[2], carry); - let (r7, carry) = mac(r7, self.0[4], rhs.0[3], carry); - let (r8, carry) = mac(r8, self.0[4], rhs.0[4], carry); - let (r9, carry) = mac(r9, self.0[4], rhs.0[5], carry); - let (r10, r11) = mac(r10, self.0[4], rhs.0[6], carry); - - let (r5, carry) = mac(r5, self.0[5], rhs.0[0], 0); - let (r6, carry) = mac(r6, self.0[5], rhs.0[1], carry); - let (r7, carry) = mac(r7, self.0[5], rhs.0[2], carry); - let (r8, carry) = mac(r8, self.0[5], rhs.0[3], carry); - let (r9, carry) = mac(r9, self.0[5], rhs.0[4], carry); - let (r10, carry) = mac(r10, self.0[5], rhs.0[5], carry); - let (r11, r12) = mac(r11, self.0[5], rhs.0[6], carry); - - let (r6, carry) = mac(r6, self.0[6], rhs.0[0], 0); - let (r7, carry) = mac(r7, self.0[6], rhs.0[1], carry); - let (r8, carry) = mac(r8, self.0[6], rhs.0[2], carry); - let (r9, carry) = mac(r9, self.0[6], rhs.0[3], carry); - let (r10, carry) = mac(r10, self.0[6], rhs.0[4], carry); - let (r11, carry) = mac(r11, self.0[6], rhs.0[5], carry); - let (r12, r13) = mac(r12, self.0[6], rhs.0[6], carry); - - $field::montgomery_reduce(&[ - r0, r1, r2, r3, r4, r5, r6, r7, r8, r9, r10, r11, r12, r13, - ]) - } - - /// Subtracts `rhs` from `self`, returning the result. - #[inline] - pub const fn sub(&self, rhs: &Self) -> Self { - let (d0, borrow) = sbb(self.0[0], rhs.0[0], 0); - let (d1, borrow) = sbb(self.0[1], rhs.0[1], borrow); - let (d2, borrow) = sbb(self.0[2], rhs.0[2], borrow); - let (d3, borrow) = sbb(self.0[3], rhs.0[3], borrow); - let (d4, borrow) = sbb(self.0[4], rhs.0[4], borrow); - let (d5, borrow) = sbb(self.0[5], rhs.0[5], borrow); - let (d6, borrow) = sbb(self.0[6], rhs.0[6], borrow); - - // 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. - let (d0, carry) = adc(d0, $modulus.0[0] & borrow, 0); - let (d1, carry) = adc(d1, $modulus.0[1] & borrow, carry); - let (d2, carry) = adc(d2, $modulus.0[2] & borrow, carry); - let (d3, carry) = adc(d3, $modulus.0[3] & borrow, carry); - let (d4, carry) = adc(d4, $modulus.0[4] & borrow, carry); - let (d5, carry) = adc(d5, $modulus.0[5] & borrow, carry); - let (d6, _) = adc(d6, $modulus.0[6] & borrow, carry); - - $field([d0, d1, d2, d3, d4, d5, d6]) - } - - /// Negates `self`. - #[inline] - pub const fn neg(&self) -> Self { - // Subtract `self` from `MODULUS` to negate. Ignore the final - // borrow because it cannot underflow; self is guaranteed to - // be in the field. - let (d0, borrow) = sbb($modulus.0[0], self.0[0], 0); - let (d1, borrow) = sbb($modulus.0[1], self.0[1], borrow); - let (d2, borrow) = sbb($modulus.0[2], self.0[2], borrow); - let (d3, borrow) = sbb($modulus.0[3], self.0[3], borrow); - let (d4, borrow) = sbb($modulus.0[4], self.0[4], borrow); - let (d5, borrow) = sbb($modulus.0[5], self.0[5], borrow); - let (d6, _) = sbb($modulus.0[6], self.0[6], borrow); - - // `tmp` could be `MODULUS` if `self` was zero. Create a mask that is - // zero if `self` was zero, and `u64::max_value()` if self was nonzero. - let mask = (((self.0[0] - | self.0[1] - | self.0[2] - | self.0[3] - | self.0[4] - | self.0[5] - | self.0[6]) - == 0) as u64) - .wrapping_sub(1); - - $field([ - d0 & mask, - d1 & mask, - d2 & mask, - d3 & mask, - d4 & mask, - d5 & mask, - d6 & mask, - ]) - } - } - }; -} - -#[macro_export] -macro_rules! field_specific_7_limbs { - ($field:ident, $modulus:ident, $inv:ident, sparse) => { - impl $field { - /// Adds `rhs` to `self`, returning the result. - #[inline] - pub const fn add(&self, rhs: &Self) -> Self { - let (d0, carry) = adc(self.0[0], rhs.0[0], 0); - let (d1, carry) = adc(self.0[1], rhs.0[1], carry); - let (d2, carry) = adc(self.0[2], rhs.0[2], carry); - let (d3, carry) = adc(self.0[3], rhs.0[3], carry); - let (d4, carry) = adc(self.0[4], rhs.0[4], carry); - let (d5, carry) = adc(self.0[5], rhs.0[5], carry); - let (d6, _) = adc(self.0[6], rhs.0[6], carry); - - // Attempt to subtract the modulus, to ensure the value - // is smaller than the modulus. - (&$field([d0, d1, d2, d3, d4, d5, d6])).sub(&$modulus) - } - - #[inline(always)] - pub(crate) const fn montgomery_reduce(r: &[u64; 14]) -> $field { - // The Montgomery reduction here is based on Algorithm 14.32 in - // Handbook of Applied Cryptography - // . - - let k = r[0].wrapping_mul($inv); - let (_, carry) = mac(r[0], k, $modulus.0[0], 0); - let (r1, carry) = mac(r[1], k, $modulus.0[1], carry); - let (r2, carry) = mac(r[2], k, $modulus.0[2], carry); - let (r3, carry) = mac(r[3], k, $modulus.0[3], carry); - let (r4, carry) = mac(r[4], k, $modulus.0[4], carry); - let (r5, carry) = mac(r[5], k, $modulus.0[5], carry); - let (r6, carry) = mac(r[6], k, $modulus.0[6], carry); - let (r7, carry2) = adc(r[7], 0, carry); - - let k = r1.wrapping_mul($inv); - let (_, carry) = mac(r1, k, $modulus.0[0], 0); - let (r2, carry) = mac(r2, k, $modulus.0[1], carry); - let (r3, carry) = mac(r3, k, $modulus.0[2], carry); - let (r4, carry) = mac(r4, k, $modulus.0[3], carry); - let (r5, carry) = mac(r5, k, $modulus.0[4], carry); - let (r6, carry) = mac(r6, k, $modulus.0[5], carry); - let (r7, carry) = mac(r7, k, $modulus.0[6], carry); - let (r8, carry2) = adc(r[8], carry2, carry); - - let k = r2.wrapping_mul($inv); - let (_, carry) = mac(r2, k, $modulus.0[0], 0); - let (r3, carry) = mac(r3, k, $modulus.0[1], carry); - let (r4, carry) = mac(r4, k, $modulus.0[2], carry); - let (r5, carry) = mac(r5, k, $modulus.0[3], carry); - let (r6, carry) = mac(r6, k, $modulus.0[4], carry); - let (r7, carry) = mac(r7, k, $modulus.0[5], carry); - let (r8, carry) = mac(r8, k, $modulus.0[6], carry); - let (r9, carry2) = adc(r[9], carry2, carry); - - let k = r3.wrapping_mul($inv); - let (_, carry) = mac(r3, k, $modulus.0[0], 0); - let (r4, carry) = mac(r4, k, $modulus.0[1], carry); - let (r5, carry) = mac(r5, k, $modulus.0[2], carry); - let (r6, carry) = mac(r6, k, $modulus.0[3], carry); - let (r7, carry) = mac(r7, k, $modulus.0[4], carry); - let (r8, carry) = mac(r8, k, $modulus.0[5], carry); - let (r9, carry) = mac(r9, k, $modulus.0[6], carry); - let (r10, carry2) = adc(r[10], carry2, carry); - - let k = r4.wrapping_mul($inv); - let (_, carry) = mac(r4, k, $modulus.0[0], 0); - let (r5, carry) = mac(r5, k, $modulus.0[1], carry); - let (r6, carry) = mac(r6, k, $modulus.0[2], carry); - let (r7, carry) = mac(r7, k, $modulus.0[3], carry); - let (r8, carry) = mac(r8, k, $modulus.0[4], carry); - let (r9, carry) = mac(r9, k, $modulus.0[5], carry); - let (r10, carry) = mac(r10, k, $modulus.0[6], carry); - let (r11, carry2) = adc(r[11], carry2, carry); - - let k = r5.wrapping_mul($inv); - let (_, carry) = mac(r5, k, $modulus.0[0], 0); - let (r6, carry) = mac(r6, k, $modulus.0[1], carry); - let (r7, carry) = mac(r7, k, $modulus.0[2], carry); - let (r8, carry) = mac(r8, k, $modulus.0[3], carry); - let (r9, carry) = mac(r9, k, $modulus.0[4], carry); - let (r10, carry) = mac(r10, k, $modulus.0[5], carry); - let (r11, carry) = mac(r11, k, $modulus.0[6], carry); - let (r12, carry2) = adc(r[12], carry2, carry); - - let k = r6.wrapping_mul($inv); - let (_, carry) = mac(r6, k, $modulus.0[0], 0); - let (r7, carry) = mac(r7, k, $modulus.0[1], carry); - let (r8, carry) = mac(r8, k, $modulus.0[2], carry); - let (r9, carry) = mac(r9, k, $modulus.0[3], carry); - let (r10, carry) = mac(r10, k, $modulus.0[4], carry); - let (r11, carry) = mac(r11, k, $modulus.0[5], carry); - let (r12, carry) = mac(r12, k, $modulus.0[6], carry); - let (r13, _) = adc(r[13], carry2, carry); - // Result may be within MODULUS of the correct value - (&$field([r7, r8, r9, r10, r11, r12, r13])).sub(&$modulus) - } - } - }; - ($field:ident, $modulus:ident, $inv:ident, dense) => { - impl $field { - /// Adds `rhs` to `self`, returning the result. - #[inline] - pub const fn add(&self, rhs: &Self) -> Self { - let (d0, carry) = adc(self.0[0], rhs.0[0], 0); - let (d1, carry) = adc(self.0[1], rhs.0[1], carry); - let (d2, carry) = adc(self.0[2], rhs.0[2], carry); - let (d3, carry) = adc(self.0[3], rhs.0[3], carry); - let (d4, carry) = adc(self.0[4], rhs.0[4], carry); - let (d5, carry) = adc(self.0[5], rhs.0[5], carry); - let (d6, carry) = adc(self.0[6], rhs.0[6], carry); - - // Attempt to subtract the modulus, to ensure the value - // is smaller than the modulus. - let (d0, borrow) = sbb(d0, $modulus.0[0], 0); - let (d1, borrow) = sbb(d1, $modulus.0[1], borrow); - let (d2, borrow) = sbb(d2, $modulus.0[2], borrow); - let (d3, borrow) = sbb(d3, $modulus.0[3], borrow); - let (d4, borrow) = sbb(d4, $modulus.0[4], borrow); - let (d5, borrow) = sbb(d5, $modulus.0[5], borrow); - let (_, borrow) = sbb(carry, 0, borrow); - - let (d0, carry) = adc(d0, $modulus.0[0] & borrow, 0); - let (d1, carry) = adc(d1, $modulus.0[1] & borrow, carry); - let (d2, carry) = adc(d2, $modulus.0[2] & borrow, carry); - let (d3, carry) = adc(d3, $modulus.0[3] & borrow, carry); - let (d4, carry) = adc(d4, $modulus.0[4] & borrow, carry); - let (d5, carry) = adc(d5, $modulus.0[5] & borrow, carry); - let (d6, _) = adc(d6, $modulus.0[6] & borrow, carry); - - $field([d0, d1, d2, d3, d4, d5, d6]) - } - } - }; -} - -#[macro_export] -macro_rules! field_bits_7_limbs { - // For #[cfg(target_pointer_width = "64")] - ($field:ident, $modulus:ident) => { - #[cfg(feature = "bits")] - #[cfg_attr(docsrs, doc(cfg(feature = "bits")))] - impl ::ff::PrimeFieldBits for $field { - type ReprBits = [u64; 7]; - - fn to_le_bits(&self) -> ::ff::FieldBits { - let bytes = self.to_repr().repr; - - let limbs = [ - u64::from_le_bytes(bytes[0..8].try_into().unwrap()), - u64::from_le_bytes(bytes[8..16].try_into().unwrap()), - u64::from_le_bytes(bytes[16..24].try_into().unwrap()), - u64::from_le_bytes(bytes[24..32].try_into().unwrap()), - u64::from_le_bytes(bytes[32..40].try_into().unwrap()), - u64::from_le_bytes(bytes[40..48].try_into().unwrap()), - u64::from_le_bytes(bytes[48..56].try_into().unwrap()), - ]; - - ::ff::FieldBits::new(limbs) - } - - fn char_le_bits() -> ::ff::FieldBits { - ::ff::FieldBits::new($modulus.0) - } - } - }; - // For #[cfg(not(target_pointer_width = "64"))] - ($field:ident, $modulus:ident, $modulus_limbs_32:ident) => { - #[cfg(feature = "bits")] - #[cfg_attr(docsrs, doc(cfg(feature = "bits")))] - impl ::ff::PrimeFieldBits for $field { - type ReprBits = [u32; 14]; - - fn to_le_bits(&self) -> ::ff::FieldBits { - let bytes = self.to_repr().repr; - - let limbs = [ - u32::from_le_bytes(bytes[0..4].try_into().unwrap()), - u32::from_le_bytes(bytes[4..8].try_into().unwrap()), - u32::from_le_bytes(bytes[8..12].try_into().unwrap()), - u32::from_le_bytes(bytes[12..16].try_into().unwrap()), - u32::from_le_bytes(bytes[16..20].try_into().unwrap()), - u32::from_le_bytes(bytes[20..24].try_into().unwrap()), - u32::from_le_bytes(bytes[24..28].try_into().unwrap()), - u32::from_le_bytes(bytes[28..32].try_into().unwrap()), - u32::from_le_bytes(bytes[32..36].try_into().unwrap()), - u32::from_le_bytes(bytes[36..40].try_into().unwrap()), - u32::from_le_bytes(bytes[40..44].try_into().unwrap()), - u32::from_le_bytes(bytes[44..48].try_into().unwrap()), - u32::from_le_bytes(bytes[48..52].try_into().unwrap()), - u32::from_le_bytes(bytes[52..56].try_into().unwrap()), - ]; - - ::ff::FieldBits::new(limbs) - } - - fn char_le_bits() -> ::ff::FieldBits { - ::ff::FieldBits::new($modulus_limbs_32) - } - } - }; -} diff --git a/src/pluto_eris/fp.rs b/src/pluto_eris/fp.rs new file mode 100644 index 00000000..7df80c45 --- /dev/null +++ b/src/pluto_eris/fp.rs @@ -0,0 +1,44 @@ +use core::convert::TryInto; +use halo2derive::impl_field; +use rand::RngCore; +use subtle::{Choice, ConditionallySelectable, ConstantTimeEq, CtOption}; + +use crate::{ + extend_field_legendre, field_bits, impl_add_binop_specify_output, impl_binops_additive, + impl_binops_additive_specify_output, impl_binops_calls, impl_binops_multiplicative, + impl_binops_multiplicative_mixed, impl_sub_binop_specify_output, + serialize_deserialize_primefield, +}; + +impl_field!( + pluto_eris_fp, + Fp, + modulus = "24000000000024000130e0000d7f70e4a803ca76f439266f443f9a5cda8a6c7be4a7a5fe8fadffd6a2a7e8c30006b9459ffffcd300000001", + mul_gen = "a", + zeta = "480000000000360001c950000d7ee0e4a803c956d01c903d720dc8ad8b38dffaf50c100004c37ffffffe", + from_uniform = [64, 72, 112], +); + +extend_field_legendre!(Fp); +impl_binops_calls!(Fp); +impl_binops_additive!(Fp, Fp); +impl_binops_multiplicative!(Fp, Fp); +field_bits!(Fp); +serialize_deserialize_primefield!(Fp); +crate::impl_from_u64!(Fp); + +#[cfg(test)] +mod test { + + use super::*; + crate::field_testing_suite!(Fp, "field_arithmetic"); + crate::field_testing_suite!(Fp, "conversion"); + crate::field_testing_suite!(Fp, "serialization"); + crate::field_testing_suite!(Fp, "quadratic_residue"); + crate::field_testing_suite!(Fp, "bits"); + crate::field_testing_suite!(Fp, "serialization_check"); + crate::field_testing_suite!(Fp, "constants"); + crate::field_testing_suite!(Fp, "sqrt"); + crate::field_testing_suite!(Fp, "zeta"); + crate::field_testing_suite!(Fp, "from_uniform_bytes", 64, 72, 112); +} diff --git a/src/pluto_eris/fields/fp12.rs b/src/pluto_eris/fp12.rs similarity index 80% rename from src/pluto_eris/fields/fp12.rs rename to src/pluto_eris/fp12.rs index b6e08a8c..7dfbde32 100644 --- a/src/pluto_eris/fields/fp12.rs +++ b/src/pluto_eris/fp12.rs @@ -1,106 +1,25 @@ use super::fp::Fp; use super::fp2::Fp2; use super::fp6::Fp6; -use crate::ff::Field; -use core::ops::{Add, Mul, Neg, Sub}; -use rand::RngCore; +use crate::{ff::Field, impl_tower2_common}; +use core::ops::{Add, Neg, Sub}; use subtle::{Choice, ConditionallySelectable, ConstantTimeEq, CtOption}; /// -GAMMA is a quadratic non-residue in Fp6. Fp12 = Fp6[X]/(X^2 + GAMMA) /// We introduce the variable w such that w^2 = -GAMMA /// GAMMA = - v -#[derive(Copy, Clone, Debug, Eq, PartialEq, Default)] -pub struct Fp12 { - c0: Fp6, - c1: Fp6, -} - -impl ConditionallySelectable for Fp12 { - fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self { - Fp12 { - c0: Fp6::conditional_select(&a.c0, &b.c0, choice), - c1: Fp6::conditional_select(&a.c1, &b.c1, choice), - } - } -} - -impl ConstantTimeEq for Fp12 { - fn ct_eq(&self, other: &Self) -> Choice { - self.c0.ct_eq(&other.c0) & self.c1.ct_eq(&other.c1) - } -} - -impl Neg for Fp12 { - type Output = Fp12; - - #[inline] - fn neg(self) -> Fp12 { - -&self - } -} - -impl<'a> Neg for &'a Fp12 { - type Output = Fp12; - - #[inline] - fn neg(self) -> Fp12 { - self.neg() - } -} - -impl<'a, 'b> Sub<&'b Fp12> for &'a Fp12 { - type Output = Fp12; - - #[inline] - fn sub(self, rhs: &'b Fp12) -> Fp12 { - self.sub(rhs) - } -} - -impl<'a, 'b> Add<&'b Fp12> for &'a Fp12 { - type Output = Fp12; - - #[inline] - fn add(self, rhs: &'b Fp12) -> Fp12 { - self.add(rhs) - } -} - -impl<'a, 'b> Mul<&'b Fp12> for &'a Fp12 { - type Output = Fp12; - - #[inline] - fn mul(self, rhs: &'b Fp12) -> Fp12 { - self.mul(rhs) - } -} - use crate::{ impl_add_binop_specify_output, impl_binops_additive, impl_binops_additive_specify_output, - impl_binops_multiplicative, impl_binops_multiplicative_mixed, impl_sub_binop_specify_output, - impl_sum_prod, + impl_binops_calls, impl_binops_multiplicative, impl_binops_multiplicative_mixed, + impl_sub_binop_specify_output, impl_sum_prod, }; impl_binops_additive!(Fp12, Fp12); impl_binops_multiplicative!(Fp12, Fp12); +impl_tower2_common!(Fp6, Fp12); +impl_binops_calls!(Fp12); impl_sum_prod!(Fp12); impl Fp12 { - #[inline] - pub const fn zero() -> Self { - Fp12 { - c0: Fp6::ZERO, - c1: Fp6::ZERO, - } - } - - #[inline] - pub const fn one() -> Self { - Fp12 { - c0: Fp6::ONE, - c1: Fp6::ZERO, - } - } - pub fn mul_assign(&mut self, other: &Self) { let t0 = self.c0 * other.c0; let mut t1 = self.c1 * other.c1; @@ -132,52 +51,6 @@ impl Fp12 { self.c0 = c0; } - pub fn double(&self) -> Self { - Self { - c0: self.c0.double(), - c1: self.c1.double(), - } - } - - pub fn double_assign(&mut self) { - self.c0 = self.c0.double(); - self.c1 = self.c1.double(); - } - - pub fn add(&self, other: &Self) -> Self { - Self { - c0: self.c0 + other.c0, - c1: self.c1 + other.c1, - } - } - - pub fn sub(&self, other: &Self) -> Self { - Self { - c0: self.c0 - other.c0, - c1: self.c1 - other.c1, - } - } - - pub fn mul(&self, other: &Self) -> Self { - let mut t = *other; - t.mul_assign(self); - t - } - - pub fn square(&self) -> Self { - let mut t = *self; - t.square_assign(); - t - } - - #[inline(always)] - pub fn neg(&self) -> Self { - Self { - c0: -self.c0, - c1: -self.c1, - } - } - #[inline(always)] pub fn conjugate(&mut self) { self.c1 = -self.c1; @@ -289,11 +162,12 @@ impl Fp12 { } } +#[cfg(test)] impl Field for Fp12 { const ZERO: Self = Self::zero(); const ONE: Self = Self::one(); - fn random(mut rng: impl RngCore) -> Self { + fn random(mut rng: impl rand_core::RngCore) -> Self { Fp12 { c0: Fp6::random(&mut rng), c1: Fp6::random(&mut rng), @@ -313,16 +187,10 @@ impl Field for Fp12 { } fn sqrt(&self) -> CtOption { - // The square root method is typically only required for finding y-coordinate - // given the x-coordinate of an EC point. Fields over which we have not - // defined a curve do not need this method. unimplemented!() } fn sqrt_ratio(_num: &Self, _div: &Self) -> (Choice, Self) { - // The square root method is typically only required for finding y-coordinate - // given the x-coordinate of an EC point. Fields over which we have not - // defined a curve do not need this method. unimplemented!() } diff --git a/src/pluto_eris/fp2.rs b/src/pluto_eris/fp2.rs new file mode 100644 index 00000000..a5b1c544 --- /dev/null +++ b/src/pluto_eris/fp2.rs @@ -0,0 +1,277 @@ +use super::fp::Fp; +use crate::ff::{Field, FromUniformBytes, PrimeField, WithSmallOrderMulGroup}; +use crate::ff_ext::Legendre; +use core::convert::TryInto; +use core::ops::{Add, Neg, Sub}; +use rand::RngCore; +use std::cmp::Ordering; +use std::ops::MulAssign; +use subtle::{Choice, ConditionallySelectable, ConstantTimeEq, CtOption}; + +#[cfg(feature = "derive_serde")] +use serde::{Deserialize, Serialize}; + +use crate::{ + impl_add_binop_specify_output, impl_binops_additive, impl_binops_additive_specify_output, + impl_binops_calls, impl_binops_multiplicative, impl_binops_multiplicative_mixed, + impl_sub_binop_specify_output, impl_sum_prod, impl_tower2, impl_tower2_common, +}; +impl_tower2_common!(Fp, Fp2, serde); +impl_tower2!(Fp, Fp2, ReprFp2); +impl_binops_additive!(Fp2, Fp2); +impl_binops_multiplicative!(Fp2, Fp2); +impl_binops_calls!(Fp2); +impl_sum_prod!(Fp2); + +/// -ALPHA is a quadratic non-residue in Fp. Fp2 = Fp[X]/(X^2 + ALPHA) +/// We introduce the variable u such that u^2 = -ALPHA + +/// U_SQUARE = -5 +/// 0x24000000000024000130e0000d7f70e4a803ca76f439266f443f9a5cda8a6c7be4a7a5fe8fadffd6a2a7e8c30006b9459ffffcd2fffffffc +const U_SQUARE: Fp = Fp::from_raw([ + 0x9ffffcd2fffffffc, + 0xa2a7e8c30006b945, + 0xe4a7a5fe8fadffd6, + 0x443f9a5cda8a6c7b, + 0xa803ca76f439266f, + 0x0130e0000d7f70e4, + 0x2400000000002400, +]); + +impl Fp2 { + pub fn double_assign(&mut self) { + self.c0 = self.c0.double(); + self.c1 = self.c1.double(); + } + + // TODO: This is a naive method using 4 multiplications + pub fn mul_assign(&mut self, other: &Self) { + // r0 = s0 * s0 + U_SQUARE * s1 * o1 + // r1 = s0 * o1 - s1 * o0 + + let t0 = self.c0 * other.c0; + let t1 = self.c0 * other.c1; + let t2 = self.c1 * other.c0; + let t3 = self.c1 * other.c1; + + self.c0 = t0 + U_SQUARE * t3; + self.c1 = t1 + t2 + } + + // TODO: This is a naive method using 3 multiplications + pub fn square_assign(&mut self) { + // r0 = s0^2 + U_SQUARE * s1^2 + // r1 = 2* s0s1 + + let ab = self.c0 * self.c1; + let a2 = self.c0 * self.c0; + let b2 = self.c1 * self.c1; + + self.c1 = ab.double(); + self.c0 = a2 + U_SQUARE * b2; + } + + // conjucate by negating c1 + pub fn conjugate(&mut self) { + self.c1 = -self.c1; + } + + pub fn frobenius_map(&mut self, power: usize) { + //TODO Replace with constant time version if needed + if power % 2 != 0 { + self.conjugate() + } + } + + /// Multiply this element by cubic nonresidue: V_CUBE = 57/(u+3) + pub fn mul_by_nonresidue(&mut self) { + // (x + y * u) * 57/(u + 3) + self.mul_assign(&super::fp6::V_CUBE) + } + + pub fn invert(&self) -> CtOption { + let mut t1 = self.c1; + t1 = t1.square(); + t1 *= U_SQUARE; + let mut t0 = self.c0; + t0 = t0.square(); + //t0 = c0^2 - U_SQUARE c1^2 + t0 -= &t1; + t0.invert().map(|t| { + let mut tmp = Fp2 { + c0: self.c0, + c1: self.c1, + }; + tmp.c0 *= &t; + tmp.c1 *= &t; + tmp.c1 = -tmp.c1; + + tmp + }) + } + + /// Norm of Fp2 as extension field in u over Fp + fn norm(&self) -> Fp { + // norm = self * self.conjugate() + let t0 = self.c0.square(); + let t1 = self.c1.square() * U_SQUARE; + t1 - t0 + } + + fn sqrt(&self) -> CtOption { + // Algorithm 10, https://eprint.iacr.org/2012/685.pdf + + // Aux elements. Described in PRECOMPUTATION of Algorithm 10. + // As element of Fp2: E = 0 + U * + // 0x13e275a1fa6a13af7a82a3d83bc9e63a667c70cf991a36e603b21f15823a404a021848271d63f0875d232408689b4c6c67153f9701e19938 + const E: Fp2 = Fp2 { + c0: Fp::ZERO, + c1: Fp::from_raw([ + 0x67153f9701e19938, + 0x5d232408689b4c6c, + 0x021848271d63f087, + 0x03b21f15823a404a, + 0x667c70cf991a36e6, + 0x7a82a3d83bc9e63a, + 0x13e275a1fa6a13af, + ]), + }; + + // As element of Fp2: f = 5 + 0 * U + // 0x5 + const F: Fp2 = Fp2 { + c0: Fp::from_raw([0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]), + c1: Fp::ZERO, + }; + + // Algorithm (not constant time) + let b = self.pow_vartime([ + // (p-1)/4 = + // 0x900000000000900004c3800035fdc392a00f29dbd0e499bd10fe69736a29b1ef929e97fa3eb7ff5a8a9fa30c001ae5167ffff34c0000000 + 0x67ffff34c0000000, + 0xa8a9fa30c001ae51, + 0xf929e97fa3eb7ff5, + 0xd10fe69736a29b1e, + 0x2a00f29dbd0e499b, + 0x004c3800035fdc39, + 0x0900000000000900, + ]); + + let b_2 = b.square(); + let mut b_2_q = b_2; + b_2_q.frobenius_map(1); + + let a0 = b_2_q * b_2; + const NEG_ONE: Fp2 = Fp2 { + c0: Fp::ZERO.sub_const(&Fp::ONE), + c1: Fp::ZERO, + }; + if a0 == NEG_ONE { + CtOption::new(a0, Choice::from(0)) + } else { + let mut x = b; + x.frobenius_map(1); + if x * b == Fp2::ONE { + let x0 = (b_2 * self).c0.sqrt().unwrap(); + x.c0.mul_assign(x0); + x.c1.mul_assign(x0); + CtOption::new(x, Choice::from(1)) + } else { + let x0 = (self * b_2 * F).sqrt().unwrap(); + x *= x0 * E; + CtOption::new(x, Choice::from(1)) + } + } + } +} + +const ZETA: Fp = Fp::from_raw([ + 0x8ffff80f80000002, + 0xd9fa5d8a200bc439, + 0x1b50d5e1ff708dc8, + 0xf43f8cddf9a5c478, + 0xa803ca76be3924a5, + 0x0130e0000d7f28e4, + 0x2400000000002400, +]); + +#[cfg(test)] +mod test { + use super::*; + crate::field_testing_suite!(Fp2, "field_arithmetic"); + crate::field_testing_suite!(Fp2, "conversion"); + crate::field_testing_suite!(Fp2, "serialization"); + crate::field_testing_suite!(Fp2, "quadratic_residue"); + crate::field_testing_suite!(Fp2, "sqrt"); + crate::field_testing_suite!(Fp2, "zeta", Fp); + // extension field-specific + crate::field_testing_suite!(Fp2, "f2_tests", Fp); + crate::field_testing_suite!( + Fp2, + "frobenius", + // Frobenius endomorphism power parameter for extension field + // ϕ: E → E + // (x, y) ↦ (x^p, y^p) + // p: modulus of base field (Here, Fp::MODULUS) + [ + 0x9ffffcd300000001, + 0xa2a7e8c30006b945, + 0xe4a7a5fe8fadffd6, + 0x443f9a5cda8a6c7b, + 0xa803ca76f439266f, + 0x0130e0000d7f70e4, + 0x2400000000002400, + ] + ); + + #[test] + fn test_fp2_squaring() { + // u + 1 + let mut a = Fp2 { + c0: Fp::one(), + c1: Fp::one(), + }; + // (u + 1) ^2 = 1 + u^2 + 2u = -4 + 2u + a.square_assign(); + let minus_4 = -Fp::from(4u64); + assert_eq!( + a, + Fp2 { + c0: minus_4, + c1: Fp::one() + Fp::one(), + } + ); + + // u + let mut a = Fp2 { + c0: Fp::zero(), + c1: Fp::one(), + }; + // u^2 + a.square_assign(); + assert_eq!( + a, + Fp2 { + c0: U_SQUARE, + c1: Fp::zero(), + } + ); + } + + #[test] + fn test_fp2_mul_nonresidue() { + let mut rng = XorShiftRng::from_seed([ + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, + 0xbc, 0xe5, + ]); + let nqr = crate::pluto_eris::fp6::V_CUBE; + for _ in 0..1000 { + let mut a = Fp2::random(&mut rng); + let mut b = a; + a.mul_by_nonresidue(); + b.mul_assign(&nqr); + + assert_eq!(a, b); + } + } +} diff --git a/src/pluto_eris/fields/fp6.rs b/src/pluto_eris/fp6.rs similarity index 78% rename from src/pluto_eris/fields/fp6.rs rename to src/pluto_eris/fp6.rs index 2e298eca..6be5c657 100644 --- a/src/pluto_eris/fields/fp6.rs +++ b/src/pluto_eris/fp6.rs @@ -1,13 +1,22 @@ use super::fp::Fp; use super::fp2::Fp2; use crate::ff::Field; -use core::ops::{Add, Mul, Neg, Sub}; use rand::RngCore; -use subtle::{Choice, ConditionallySelectable, ConstantTimeEq, CtOption}; +use subtle::CtOption; /// -BETA is a cubic non-residue in Fp2. Fp6 = Fp2[X]/(X^3 + BETA) /// We introduce the variable v such that v^3 = -BETA /// BETA = - 57/(z+3) +use crate::{ + impl_add_binop_specify_output, impl_binops_additive, impl_binops_additive_specify_output, + impl_binops_calls, impl_binops_multiplicative, impl_binops_multiplicative_mixed, + impl_sub_binop_specify_output, impl_sum_prod, impl_tower6, +}; +impl_tower6!(Fp, Fp2, Fp6); +impl_binops_additive!(Fp6, Fp6); +impl_binops_multiplicative!(Fp6, Fp6); +impl_binops_calls!(Fp6); +impl_sum_prod!(Fp6); /// V_CUBE = 57/(u+3) pub(crate) const V_CUBE: Fp2 = Fp2 { @@ -33,103 +42,7 @@ pub(crate) const V_CUBE: Fp2 = Fp2 { ]), }; -#[derive(Copy, Clone, Debug, Eq, PartialEq, Default)] -/// The `Fp6` element c0 + c1 * v + c2 * v3 -pub struct Fp6 { - pub c0: Fp2, - pub c1: Fp2, - pub c2: Fp2, -} - -impl ConditionallySelectable for Fp6 { - fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self { - Fp6 { - c0: Fp2::conditional_select(&a.c0, &b.c0, choice), - c1: Fp2::conditional_select(&a.c1, &b.c1, choice), - c2: Fp2::conditional_select(&a.c2, &b.c2, choice), - } - } -} - -impl ConstantTimeEq for Fp6 { - fn ct_eq(&self, other: &Self) -> Choice { - self.c0.ct_eq(&other.c0) & self.c1.ct_eq(&other.c1) & self.c2.ct_eq(&other.c2) - } -} - -impl Neg for Fp6 { - type Output = Fp6; - - #[inline] - fn neg(self) -> Fp6 { - -&self - } -} - -impl<'a> Neg for &'a Fp6 { - type Output = Fp6; - - #[inline] - fn neg(self) -> Fp6 { - self.neg() - } -} - -impl<'a, 'b> Sub<&'b Fp6> for &'a Fp6 { - type Output = Fp6; - - #[inline] - fn sub(self, rhs: &'b Fp6) -> Fp6 { - self.sub(rhs) - } -} - -impl<'a, 'b> Add<&'b Fp6> for &'a Fp6 { - type Output = Fp6; - - #[inline] - fn add(self, rhs: &'b Fp6) -> Fp6 { - self.add(rhs) - } -} - -impl<'a, 'b> Mul<&'b Fp6> for &'a Fp6 { - type Output = Fp6; - - #[inline] - fn mul(self, rhs: &'b Fp6) -> Fp6 { - self.mul(rhs) - } -} - -use crate::{ - impl_add_binop_specify_output, impl_binops_additive, impl_binops_additive_specify_output, - impl_binops_multiplicative, impl_binops_multiplicative_mixed, impl_sub_binop_specify_output, - impl_sum_prod, -}; -impl_binops_additive!(Fp6, Fp6); -impl_binops_multiplicative!(Fp6, Fp6); -impl_sum_prod!(Fp6); - impl Fp6 { - #[inline] - pub const fn zero() -> Self { - Fp6 { - c0: Fp2::ZERO, - c1: Fp2::ZERO, - c2: Fp2::ZERO, - } - } - - #[inline] - pub const fn one() -> Self { - Fp6 { - c0: Fp2::ONE, - c1: Fp2::ZERO, - c2: Fp2::ZERO, - } - } - pub fn mul_assign(&mut self, other: &Self) { let mut a_a = self.c0; let mut b_b = self.c1; @@ -188,8 +101,8 @@ impl Fp6 { // s1 = 2ab let mut ab = self.c0; ab *= &self.c1; - let mut s1 = ab; - s1.double_assign(); + let s1 = ab; + let s1 = s1.double(); // s2 = (a - b + c)^2 let mut s2 = self.c0; s2 -= &self.c1; @@ -199,8 +112,8 @@ impl Fp6 { let mut bc = self.c1; bc *= &self.c2; // s3 = 2bc - let mut s3 = bc; - s3.double_assign(); + let s3 = bc; + let s3 = s3.double(); // s4 = c^2 let mut s4 = self.c2; s4.square_assign(); @@ -225,56 +138,6 @@ impl Fp6 { self.c2 -= &s4; } - pub fn double(&self) -> Self { - Self { - c0: self.c0.double(), - c1: self.c1.double(), - c2: self.c2.double(), - } - } - - pub fn double_assign(&mut self) { - self.c0 = self.c0.double(); - self.c1 = self.c1.double(); - self.c2 = self.c2.double(); - } - - pub fn add(&self, other: &Self) -> Self { - Self { - c0: self.c0 + other.c0, - c1: self.c1 + other.c1, - c2: self.c2 + other.c2, - } - } - - pub fn sub(&self, other: &Self) -> Self { - Self { - c0: self.c0 - other.c0, - c1: self.c1 - other.c1, - c2: self.c2 - other.c2, - } - } - - pub fn mul(&self, other: &Self) -> Self { - let mut t = *other; - t.mul_assign(self); - t - } - - pub fn square(&self) -> Self { - let mut t = *self; - t.square_assign(); - t - } - - pub fn neg(&self) -> Self { - Self { - c0: -self.c0, - c1: -self.c1, - c2: -self.c2, - } - } - pub fn frobenius_map(&mut self, power: usize) { self.c0.frobenius_map(power); self.c1.frobenius_map(power); @@ -364,7 +227,7 @@ impl Fp6 { self.c2 = t3; } - fn invert(&self) -> CtOption { + pub fn invert(&self) -> CtOption { let mut c0 = self.c2; c0.mul_by_nonresidue(); c0 *= &self.c1; @@ -415,43 +278,6 @@ impl Fp6 { } } -impl Field for Fp6 { - const ZERO: Self = Self::zero(); - const ONE: Self = Self::one(); - - fn random(mut rng: impl RngCore) -> Self { - Fp6 { - c0: Fp2::random(&mut rng), - c1: Fp2::random(&mut rng), - c2: Fp2::random(&mut rng), - } - } - - fn is_zero(&self) -> Choice { - self.c0.is_zero() & self.c1.is_zero() - } - - fn square(&self) -> Self { - self.square() - } - - fn double(&self) -> Self { - self.double() - } - - fn sqrt(&self) -> CtOption { - unimplemented!() - } - - fn sqrt_ratio(_num: &Self, _div: &Self) -> (Choice, Self) { - unimplemented!() - } - - fn invert(&self) -> CtOption { - self.invert() - } -} - /// Fp2 coefficients for the efficient computation of Frobenius Endomorphism in Fp6. pub(crate) const FROBENIUS_COEFF_FP6_C1: [Fp2; 6] = [ // Fp2(v^3)**(((p^0) - 1) / 3) diff --git a/src/pluto_eris/fq.rs b/src/pluto_eris/fq.rs new file mode 100644 index 00000000..ab96f901 --- /dev/null +++ b/src/pluto_eris/fq.rs @@ -0,0 +1,44 @@ +use core::convert::TryInto; +use halo2derive::impl_field; +use rand::RngCore; +use subtle::{Choice, ConditionallySelectable, ConstantTimeEq, CtOption}; + +use crate::{ + extend_field_legendre, field_bits, impl_add_binop_specify_output, impl_binops_additive, + impl_binops_additive_specify_output, impl_binops_calls, impl_binops_multiplicative, + impl_binops_multiplicative_mixed, impl_sub_binop_specify_output, + serialize_deserialize_primefield, +}; + +impl_field!( + pluto_eris_fq, + Fq, + modulus = "24000000000024000130e0000d7f70e4a803ca76f439266f443f9a5c7a8a6c7be4a775fe8e177fd69ca7e85d60050af41ffffcd300000001", + mul_gen = "7", + zeta = "9000000000006c000392a0001afee1c9500792ae3039253e641ba35817a29ffaf50be000032cfffffffe", + from_uniform = [64, 72, 112], +); + +extend_field_legendre!(Fq); +impl_binops_calls!(Fq); +impl_binops_additive!(Fq, Fq); +impl_binops_multiplicative!(Fq, Fq); +field_bits!(Fq); +serialize_deserialize_primefield!(Fq); +crate::impl_from_u64!(Fq); + +#[cfg(test)] +mod test { + + use super::*; + crate::field_testing_suite!(Fq, "field_arithmetic"); + crate::field_testing_suite!(Fq, "conversion"); + crate::field_testing_suite!(Fq, "serialization"); + crate::field_testing_suite!(Fq, "quadratic_residue"); + crate::field_testing_suite!(Fq, "bits"); + crate::field_testing_suite!(Fq, "serialization_check"); + crate::field_testing_suite!(Fq, "constants"); + crate::field_testing_suite!(Fq, "sqrt"); + crate::field_testing_suite!(Fq, "zeta"); + crate::field_testing_suite!(Fq, "from_uniform_bytes", 64, 72, 112); +} diff --git a/src/pluto_eris/mod.rs b/src/pluto_eris/mod.rs index 72118ca3..0d0538ab 100644 --- a/src/pluto_eris/mod.rs +++ b/src/pluto_eris/mod.rs @@ -7,9 +7,13 @@ //! Pairing constants derivation: https://github.com/John-Gong-Math/pluto_eris/blob/main/pluto_pairing.ipynb mod curve; mod engine; -mod fields; +mod fp; +mod fp12; +mod fp2; +mod fp6; +mod fq; pub use curve::*; pub use engine::*; -pub use fields::fp::*; -pub use fields::fq::*; +pub use fp::*; +pub use fq::*; diff --git a/src/secp256k1/fp.rs b/src/secp256k1/fp.rs index 34fd41d9..3522f5a2 100644 --- a/src/secp256k1/fp.rs +++ b/src/secp256k1/fp.rs @@ -1,305 +1,35 @@ -use crate::arithmetic::{adc, bigint_geq, mac, macx, sbb}; -use crate::extend_field_legendre; -use crate::ff::{FromUniformBytes, PrimeField, WithSmallOrderMulGroup}; -use crate::{ - field_arithmetic, field_bits, field_common, field_specific, impl_add_binop_specify_output, - impl_binops_additive, impl_binops_additive_specify_output, impl_binops_multiplicative, - impl_binops_multiplicative_mixed, impl_from_u64, impl_sub_binop_specify_output, impl_sum_prod, -}; use core::convert::TryInto; -use core::fmt; -use core::ops::{Add, Mul, Neg, Sub}; +use halo2derive::impl_field; use rand::RngCore; use subtle::{Choice, ConditionallySelectable, ConstantTimeEq, CtOption}; -/// This represents an element of $\mathbb{F}_p$ where -/// -/// `p = 0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f` -/// -/// is the base field of the secp256k1 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. -#[derive(Clone, Copy, PartialEq, Eq, Hash)] -pub struct Fp(pub(crate) [u64; 4]); - -#[cfg(feature = "derive_serde")] -crate::serialize_deserialize_32_byte_primefield!(Fp); - -/// Constant representing the modulus -/// p = 0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f -const MODULUS: Fp = Fp([ - 0xfffffffefffffc2f, - 0xffffffffffffffff, - 0xffffffffffffffff, - 0xffffffffffffffff, -]); - -/// Constant representing the multiplicative generator of the modulus. -/// It's derived with SageMath with: `GF(MODULUS).primitive_element()`. -const MULTIPLICATIVE_GENERATOR: Fp = Fp::from_raw([0x03, 0x00, 0x00, 0x00]); - -/// The modulus as u32 limbs. -#[cfg(not(target_pointer_width = "64"))] -const MODULUS_LIMBS_32: [u32; 8] = [ - 0xffff_fc2f, - 0xffff_fffe, - 0xffff_ffff, - 0xffff_ffff, - 0xffff_ffff, - 0xffff_ffff, - 0xffff_ffff, - 0xffff_ffff, -]; - -/// Constant representing the modulus as static str -const MODULUS_STR: &str = "0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f"; - -/// INV = -(p^{-1} mod 2^64) mod 2^64 -const INV: u64 = 0xd838091dd2253531; - -/// R = 2^256 mod p -/// 0x1000003d1 -const R: Fp = Fp([0x1000003d1, 0, 0, 0]); - -/// R^2 = 2^512 mod p -/// 0x1000007a2000e90a1 -const R2: Fp = Fp([0x000007a2000e90a1, 0x1, 0, 0]); - -/// R^3 = 2^768 mod p -/// 0x100000b73002bb1e33795f671 -const R3: Fp = Fp([0x002bb1e33795f671, 0x100000b73, 0, 0]); - -/// 1 / 2 mod p -const TWO_INV: Fp = Fp::from_raw([ - 0xffffffff7ffffe18, - 0xffffffffffffffff, - 0xffffffffffffffff, - 0x7fffffffffffffff, -]); - -const ZETA: Fp = Fp::from_raw([ - 0xc1396c28719501ee, - 0x9cf0497512f58995, - 0x6e64479eac3434e9, - 0x7ae96a2b657c0710, -]); - -/// Generator of the t-order multiplicative subgroup. -/// Computed by exponentiating Self::MULTIPLICATIVE_GENERATOR by 2^s, where s is Self::S. -/// `0x0000000000000000000000000000000000000000000000000000000000000009`. -const DELTA: Fp = Fp([0x900002259u64, 0, 0, 0]); - -/// Implementations of this trait MUST ensure that this is the generator used to derive Self::ROOT_OF_UNITY. -/// Derived from: -/// ```ignore -/// Zp(Zp(mul_generator)^t) where t = (modulus - 1 )/ 2 -/// 115792089237316195423570985008687907853269984665640564039457584007908834671662 -/// ``` -const ROOT_OF_UNITY: Fp = Fp([ - 0xfffffffdfffff85eu64, - 0xffffffffffffffffu64, - 0xffffffffffffffffu64, - 0xffffffffffffffffu64, -]); - -/// Inverse of [`ROOT_OF_UNITY`]. -const ROOT_OF_UNITY_INV: Fp = Fp([ - 0xfffffffdfffff85eu64, - 0xffffffffffffffffu64, - 0xffffffffffffffffu64, - 0xffffffffffffffffu64, -]); +use crate::{ + extend_field_legendre, field_bits, impl_add_binop_specify_output, impl_binops_additive, + impl_binops_additive_specify_output, impl_binops_calls, impl_binops_multiplicative, + impl_binops_multiplicative_mixed, impl_sub_binop_specify_output, + serialize_deserialize_primefield, +}; -impl_binops_additive!(Fp, Fp); -impl_binops_multiplicative!(Fp, Fp); -field_common!( +impl_field!( + secp256k1_base, Fp, - MODULUS, - INV, - MODULUS_STR, - TWO_INV, - ROOT_OF_UNITY_INV, - DELTA, - ZETA, - R, - R2, - R3 + modulus = "fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f", + mul_gen = "3", + zeta = "7ae96a2b657c07106e64479eac3434e99cf0497512f58995c1396c28719501ee", + from_uniform = [48, 64], ); -impl_from_u64!(Fp, R2); -field_arithmetic!(Fp, MODULUS, INV, dense); -impl_sum_prod!(Fp); - -#[cfg(target_pointer_width = "64")] -field_bits!(Fp, MODULUS); -#[cfg(not(target_pointer_width = "64"))] -field_bits!(Fp, MODULUS, MODULUS_LIMBS_32); - -impl Fp { - pub const fn size() -> usize { - 32 - } -} - -impl ff::Field for Fp { - const ZERO: Self = Self::zero(); - const ONE: Self = Self::one(); - - fn random(mut rng: impl RngCore) -> Self { - Self::from_u512([ - rng.next_u64(), - rng.next_u64(), - rng.next_u64(), - rng.next_u64(), - rng.next_u64(), - rng.next_u64(), - rng.next_u64(), - rng.next_u64(), - ]) - } - - fn double(&self) -> Self { - self.double() - } - - #[inline(always)] - fn square(&self) -> Self { - self.square() - } - - /// Computes the square root of this element, if it exists. - fn sqrt(&self) -> CtOption { - let tmp = self.pow([ - 0xffffffffbfffff0c, - 0xffffffffffffffff, - 0xffffffffffffffff, - 0x3fffffffffffffff, - ]); - - CtOption::new(tmp, tmp.square().ct_eq(self)) - } - - /// Returns the multiplicative inverse of the - /// element. If it is zero, the method fails. - fn invert(&self) -> CtOption { - self.invert() - } - - fn pow_vartime>(&self, exp: S) -> Self { - let mut res = Self::one(); - let mut found_one = false; - for e in exp.as_ref().iter().rev() { - for i in (0..64).rev() { - if found_one { - res = res.square(); - } - - if ((*e >> i) & 1) == 1 { - found_one = true; - res *= self; - } - } - } - res - } - - fn sqrt_ratio(num: &Self, div: &Self) -> (Choice, Self) { - ff::helpers::sqrt_ratio_generic(num, div) - } -} - -impl ff::PrimeField for Fp { - type Repr = [u8; 32]; - - const MODULUS: &'static str = MODULUS_STR; - const MULTIPLICATIVE_GENERATOR: Self = MULTIPLICATIVE_GENERATOR; - const TWO_INV: Self = TWO_INV; - const ROOT_OF_UNITY: Self = ROOT_OF_UNITY; - const ROOT_OF_UNITY_INV: Self = ROOT_OF_UNITY_INV; - const DELTA: Self = DELTA; - const NUM_BITS: u32 = 256; - const CAPACITY: u32 = 255; - const S: u32 = 1; - - fn from_repr(repr: Self::Repr) -> CtOption { - let mut tmp = Fp([0, 0, 0, 0]); - - tmp.0[0] = u64::from_le_bytes(repr[0..8].try_into().unwrap()); - tmp.0[1] = u64::from_le_bytes(repr[8..16].try_into().unwrap()); - tmp.0[2] = u64::from_le_bytes(repr[16..24].try_into().unwrap()); - tmp.0[3] = u64::from_le_bytes(repr[24..32].try_into().unwrap()); - - // Try to subtract the modulus - let (_, borrow) = sbb(tmp.0[0], MODULUS.0[0], 0); - let (_, borrow) = sbb(tmp.0[1], MODULUS.0[1], borrow); - let (_, borrow) = sbb(tmp.0[2], MODULUS.0[2], borrow); - let (_, borrow) = sbb(tmp.0[3], MODULUS.0[3], borrow); - - // If the element is smaller than MODULUS then the - // subtraction will underflow, producing a borrow value - // of 0xffff...ffff. Otherwise, it'll be zero. - let is_some = (borrow as u8) & 1; - - // Convert to Montgomery form by computing - // (a.R^0 * R^2) / R = a.R - tmp *= &R2; - - CtOption::new(tmp, Choice::from(is_some)) - } - - fn to_repr(&self) -> Self::Repr { - let tmp: [u64; 4] = (*self).into(); - let mut res = [0; 32]; - res[0..8].copy_from_slice(&tmp[0].to_le_bytes()); - res[8..16].copy_from_slice(&tmp[1].to_le_bytes()); - res[16..24].copy_from_slice(&tmp[2].to_le_bytes()); - res[24..32].copy_from_slice(&tmp[3].to_le_bytes()); - - res - } - - fn from_u128(v: u128) -> Self { - Self::from_raw([v as u64, (v >> 64) as u64, 0, 0]) - } - - fn is_odd(&self) -> Choice { - Choice::from(self.to_repr()[0] & 1) - } -} - -impl FromUniformBytes<64> for Fp { - /// Converts a 512-bit little endian integer into - /// an `Fp` by reducing by the modulus. - fn from_uniform_bytes(bytes: &[u8; 64]) -> Self { - Self::from_u512([ - u64::from_le_bytes(bytes[0..8].try_into().unwrap()), - u64::from_le_bytes(bytes[8..16].try_into().unwrap()), - u64::from_le_bytes(bytes[16..24].try_into().unwrap()), - u64::from_le_bytes(bytes[24..32].try_into().unwrap()), - u64::from_le_bytes(bytes[32..40].try_into().unwrap()), - u64::from_le_bytes(bytes[40..48].try_into().unwrap()), - u64::from_le_bytes(bytes[48..56].try_into().unwrap()), - u64::from_le_bytes(bytes[56..64].try_into().unwrap()), - ]) - } -} - -impl FromUniformBytes<48> for Fp { - fn from_uniform_bytes(bytes: &[u8; 48]) -> Self { - let repr = &mut [0u8; 64]; - (*repr)[0..48].copy_from_slice(&bytes[..48]); - Fp::from_uniform_bytes(repr) - } -} - -impl WithSmallOrderMulGroup<3> for Fp { - const ZETA: Self = ZETA; -} extend_field_legendre!(Fp); +impl_binops_calls!(Fp); +impl_binops_additive!(Fp, Fp); +impl_binops_multiplicative!(Fp, Fp); +field_bits!(Fp); +serialize_deserialize_primefield!(Fp); +crate::impl_from_u64!(Fp); #[cfg(test)] mod test { + use super::*; crate::field_testing_suite!(Fp, "field_arithmetic"); crate::field_testing_suite!(Fp, "conversion"); @@ -307,7 +37,7 @@ mod test { crate::field_testing_suite!(Fp, "quadratic_residue"); crate::field_testing_suite!(Fp, "bits"); crate::field_testing_suite!(Fp, "serialization_check"); - crate::field_testing_suite!(Fp, "constants", MODULUS_STR); + crate::field_testing_suite!(Fp, "constants"); crate::field_testing_suite!(Fp, "sqrt"); crate::field_testing_suite!(Fp, "zeta"); crate::field_testing_suite!(Fp, "from_uniform_bytes", 48, 64); diff --git a/src/secp256k1/fq.rs b/src/secp256k1/fq.rs index ca559623..4762e163 100644 --- a/src/secp256k1/fq.rs +++ b/src/secp256k1/fq.rs @@ -1,309 +1,31 @@ -use crate::arithmetic::{adc, bigint_geq, mac, macx, sbb}; -use crate::extend_field_legendre; -use crate::ff::{FromUniformBytes, PrimeField, WithSmallOrderMulGroup}; -use crate::{ - field_arithmetic, field_bits, field_common, field_specific, impl_add_binop_specify_output, - impl_binops_additive, impl_binops_additive_specify_output, impl_binops_multiplicative, - impl_binops_multiplicative_mixed, impl_from_u64, impl_sub_binop_specify_output, impl_sum_prod, -}; use core::convert::TryInto; -use core::fmt; -use core::ops::{Add, Mul, Neg, Sub}; +use halo2derive::impl_field; use rand::RngCore; use subtle::{Choice, ConditionallySelectable, ConstantTimeEq, CtOption}; -/// This represents an element of $\mathbb{F}_q$ where -/// -/// `q = 0xfffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141` -/// -/// is the scalar field of the secp256k1 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. -#[derive(Clone, Copy, PartialEq, Eq, Hash)] -pub struct Fq(pub(crate) [u64; 4]); - -#[cfg(feature = "derive_serde")] -crate::serialize_deserialize_32_byte_primefield!(Fq); - -/// Constant representing the modulus -/// q = 0xfffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141 -const MODULUS: Fq = Fq([ - 0xbfd25e8cd0364141, - 0xbaaedce6af48a03b, - 0xfffffffffffffffe, - 0xffffffffffffffff, -]); - -/// The modulus as u32 limbs. -#[cfg(not(target_pointer_width = "64"))] -const MODULUS_LIMBS_32: [u32; 8] = [ - 0xd036_4141, - 0xbfd2_5e8c, - 0xaf48_a03b, - 0xbaae_dce6, - 0xffff_fffe, - 0xffff_ffff, - 0xffff_ffff, - 0xffff_ffff, -]; - -///Constant representing the modulus as static str -const MODULUS_STR: &str = "0xfffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141"; - -/// INV = -(q^{-1} mod 2^64) mod 2^64 -const INV: u64 = 0x4b0dff665588b13f; - -/// R = 2^256 mod q -/// 0x14551231950b75fc4402da1732fc9bebf -const R: Fq = Fq([0x402da1732fc9bebf, 0x4551231950b75fc4, 0x1, 0]); - -/// R^2 = 2^512 mod q -/// 0x9d671cd581c69bc5e697f5e45bcd07c6741496c20e7cf878896cf21467d7d140 -const R2: Fq = Fq([ - 0x896cf21467d7d140, - 0x741496c20e7cf878, - 0xe697f5e45bcd07c6, - 0x9d671cd581c69bc5, -]); - -/// R^3 = 2^768 mod q -/// 0x555d800c18ef116db1b31347f1d0b2da0017648444d4322c7bc0cfe0e9ff41ed -const R3: Fq = Fq([ - 0x7bc0cfe0e9ff41ed, - 0x0017648444d4322c, - 0xb1b31347f1d0b2da, - 0x555d800c18ef116d, -]); - -/// `GENERATOR = 7 mod r` is a generator of the `q - 1` order multiplicative -/// subgroup, or in other words a primitive root of the field. -/// It's derived with SageMath with: `GF(MODULUS).primitive_element()`. -const GENERATOR: Fq = Fq::from_raw([0x07, 0x00, 0x00, 0x00]); - -/// GENERATOR^t where t * 2^s + 1 = r with t odd. In other words, this is a 2^s root of unity. -/// `0xc1dc060e7a91986df9879a3fbc483a898bdeab680756045992f4b5402b052f2` -const ROOT_OF_UNITY: Fq = Fq::from_raw([ - 0x992f4b5402b052f2, - 0x98bdeab680756045, - 0xdf9879a3fbc483a8, - 0xc1dc060e7a91986, -]); - -/// 1 / ROOT_OF_UNITY mod q -const ROOT_OF_UNITY_INV: Fq = Fq::from_raw([ - 0xb6fb30a0884f0d1c, - 0x77a275910aa413c3, - 0xefc7b0c75b8cbb72, - 0xfd3ae181f12d7096, -]); - -/// 1 / 2 mod q -const TWO_INV: Fq = Fq::from_raw([ - 0xdfe92f46681b20a1, - 0x5d576e7357a4501d, - 0xffffffffffffffff, - 0x7fffffffffffffff, -]); - -const ZETA: Fq = Fq::from_raw([ - 0xdf02967c1b23bd72, - 0x122e22ea20816678, - 0xa5261c028812645a, - 0x5363ad4cc05c30e0, -]); - -/// Generator of the t-order multiplicative subgroup. -/// Computed by exponentiating Self::MULTIPLICATIVE_GENERATOR by 2^s, where s is Self::S. -/// `0x0000000000000000000cbc21fe4561c8d63b78e780e1341e199417c8c0bb7601` -const DELTA: Fq = Fq([ - 0xd91b33d24319d9e8, - 0xb81c6596ff5d6740, - 0xa463969ca14c51c1, - 0x1900960de4b7929c, -]); +use crate::{ + extend_field_legendre, field_bits, impl_add_binop_specify_output, impl_binops_additive, + impl_binops_additive_specify_output, impl_binops_calls, impl_binops_multiplicative, + impl_binops_multiplicative_mixed, impl_sub_binop_specify_output, + serialize_deserialize_primefield, +}; -impl_binops_additive!(Fq, Fq); -impl_binops_multiplicative!(Fq, Fq); -field_common!( +impl_field!( + secp256k1_scalar, Fq, - MODULUS, - INV, - MODULUS_STR, - TWO_INV, - ROOT_OF_UNITY_INV, - DELTA, - ZETA, - R, - R2, - R3 + modulus = "fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141", + mul_gen = "7", + zeta = "5363ad4cc05c30e0a5261c028812645a122e22ea20816678df02967c1b23bd72", + from_uniform = [48, 64], ); -impl_from_u64!(Fq, R2); -field_arithmetic!(Fq, MODULUS, INV, dense); -impl_sum_prod!(Fq); - -#[cfg(target_pointer_width = "64")] -field_bits!(Fq, MODULUS); -#[cfg(not(target_pointer_width = "64"))] -field_bits!(Fq, MODULUS, MODULUS_LIMBS_32); - -impl Fq { - pub const fn size() -> usize { - 32 - } -} - -impl ff::Field for Fq { - const ZERO: Self = Self::zero(); - const ONE: Self = Self::one(); - - fn random(mut rng: impl RngCore) -> Self { - Self::from_u512([ - rng.next_u64(), - rng.next_u64(), - rng.next_u64(), - rng.next_u64(), - rng.next_u64(), - rng.next_u64(), - rng.next_u64(), - rng.next_u64(), - ]) - } - - fn double(&self) -> Self { - self.double() - } - - #[inline(always)] - fn square(&self) -> Self { - self.square() - } - - /// Returns the multiplicative inverse of the - /// element. If it is zero, the method fails. - fn invert(&self) -> CtOption { - self.invert() - } - - fn pow_vartime>(&self, exp: S) -> Self { - let mut res = Self::one(); - let mut found_one = false; - for e in exp.as_ref().iter().rev() { - for i in (0..64).rev() { - if found_one { - res = res.square(); - } - - if ((*e >> i) & 1) == 1 { - found_one = true; - res *= self; - } - } - } - res - } - - fn sqrt(&self) -> CtOption { - let tm1d2 = [ - 0x777fa4bd19a06c82, - 0xfd755db9cd5e9140, - 0xffffffffffffffff, - 0x01ffffffffffffff, - ]; - - ff::helpers::sqrt_tonelli_shanks(self, tm1d2) - } - - fn sqrt_ratio(num: &Self, div: &Self) -> (Choice, Self) { - ff::helpers::sqrt_ratio_generic(num, div) - } -} - -impl ff::PrimeField for Fq { - type Repr = [u8; 32]; - - const NUM_BITS: u32 = 256; - const CAPACITY: u32 = 255; - const MODULUS: &'static str = MODULUS_STR; - const MULTIPLICATIVE_GENERATOR: Self = GENERATOR; - const ROOT_OF_UNITY: Self = ROOT_OF_UNITY; - const ROOT_OF_UNITY_INV: Self = ROOT_OF_UNITY_INV; - const TWO_INV: Self = TWO_INV; - const DELTA: Self = DELTA; - const S: u32 = 6; - - fn from_repr(repr: Self::Repr) -> CtOption { - let mut tmp = Fq([0, 0, 0, 0]); - - tmp.0[0] = u64::from_le_bytes(repr[0..8].try_into().unwrap()); - tmp.0[1] = u64::from_le_bytes(repr[8..16].try_into().unwrap()); - tmp.0[2] = u64::from_le_bytes(repr[16..24].try_into().unwrap()); - tmp.0[3] = u64::from_le_bytes(repr[24..32].try_into().unwrap()); - - // Try to subtract the modulus - let (_, borrow) = sbb(tmp.0[0], MODULUS.0[0], 0); - let (_, borrow) = sbb(tmp.0[1], MODULUS.0[1], borrow); - let (_, borrow) = sbb(tmp.0[2], MODULUS.0[2], borrow); - let (_, borrow) = sbb(tmp.0[3], MODULUS.0[3], borrow); - - // If the element is smaller than MODULUS then the - // subtraction will underflow, producing a borrow value - // of 0xffff...ffff. Otherwise, it'll be zero. - let is_some = (borrow as u8) & 1; - - // Convert to Montgomery form by computing - // (a.R^0 * R^2) / R = a.R - tmp *= &R2; - - CtOption::new(tmp, Choice::from(is_some)) - } - - fn to_repr(&self) -> Self::Repr { - let tmp: [u64; 4] = (*self).into(); - let mut res = [0; 32]; - res[0..8].copy_from_slice(&tmp[0].to_le_bytes()); - res[8..16].copy_from_slice(&tmp[1].to_le_bytes()); - res[16..24].copy_from_slice(&tmp[2].to_le_bytes()); - res[24..32].copy_from_slice(&tmp[3].to_le_bytes()); - - res - } - - fn is_odd(&self) -> Choice { - Choice::from(self.to_repr()[0] & 1) - } -} - -impl FromUniformBytes<64> for Fq { - /// Converts a 512-bit little endian integer into - /// an `Fq` by reducing by the modulus. - fn from_uniform_bytes(bytes: &[u8; 64]) -> Self { - Self::from_u512([ - u64::from_le_bytes(bytes[0..8].try_into().unwrap()), - u64::from_le_bytes(bytes[8..16].try_into().unwrap()), - u64::from_le_bytes(bytes[16..24].try_into().unwrap()), - u64::from_le_bytes(bytes[24..32].try_into().unwrap()), - u64::from_le_bytes(bytes[32..40].try_into().unwrap()), - u64::from_le_bytes(bytes[40..48].try_into().unwrap()), - u64::from_le_bytes(bytes[48..56].try_into().unwrap()), - u64::from_le_bytes(bytes[56..64].try_into().unwrap()), - ]) - } -} - -impl FromUniformBytes<48> for Fq { - fn from_uniform_bytes(bytes: &[u8; 48]) -> Self { - let repr = &mut [0u8; 64]; - (*repr)[0..48].copy_from_slice(&bytes[..48]); - Fq::from_uniform_bytes(repr) - } -} - -impl WithSmallOrderMulGroup<3> for Fq { - const ZETA: Self = ZETA; -} extend_field_legendre!(Fq); +impl_binops_calls!(Fq); +impl_binops_additive!(Fq, Fq); +impl_binops_multiplicative!(Fq, Fq); +field_bits!(Fq); +serialize_deserialize_primefield!(Fq); +crate::impl_from_u64!(Fq); #[cfg(test)] mod test { @@ -314,7 +36,7 @@ mod test { crate::field_testing_suite!(Fq, "quadratic_residue"); crate::field_testing_suite!(Fq, "bits"); crate::field_testing_suite!(Fq, "serialization_check"); - crate::field_testing_suite!(Fq, "constants", MODULUS_STR); + crate::field_testing_suite!(Fq, "constants"); crate::field_testing_suite!(Fq, "sqrt"); crate::field_testing_suite!(Fq, "zeta"); crate::field_testing_suite!(Fq, "from_uniform_bytes", 48, 64); diff --git a/src/secp256r1/fp.rs b/src/secp256r1/fp.rs index 9e9805d7..057ee42b 100644 --- a/src/secp256r1/fp.rs +++ b/src/secp256r1/fp.rs @@ -1,320 +1,31 @@ -use crate::arithmetic::{adc, bigint_geq, mac, macx, sbb}; -use crate::extend_field_legendre; -use crate::ff::{FromUniformBytes, PrimeField, WithSmallOrderMulGroup}; -use crate::{ - field_arithmetic, field_bits, field_common, field_specific, impl_add_binop_specify_output, - impl_binops_additive, impl_binops_additive_specify_output, impl_binops_multiplicative, - impl_binops_multiplicative_mixed, impl_from_u64, impl_sub_binop_specify_output, impl_sum_prod, -}; use core::convert::TryInto; -use core::fmt; -use core::ops::{Add, Mul, Neg, Sub}; +use halo2derive::impl_field; use rand::RngCore; use subtle::{Choice, ConditionallySelectable, ConstantTimeEq, CtOption}; -/// This represents an element of $\mathbb{F}_p$ where -/// -/// `p = 0xffffffff00000001000000000000000000000000ffffffffffffffffffffffff -/// -/// is the base field of the secp256r1 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. -#[derive(Clone, Copy, PartialEq, Eq, Hash)] -pub struct Fp(pub(crate) [u64; 4]); - -#[cfg(feature = "derive_serde")] -crate::serialize_deserialize_32_byte_primefield!(Fp); - -/// Constant representing the modulus -/// p = 0xffffffff00000001000000000000000000000000ffffffffffffffffffffffff -const MODULUS: Fp = Fp([ - 0xffffffffffffffff, - 0x00000000ffffffff, - 0x0000000000000000, - 0xffffffff00000001, -]); - -/// Constant representing the multiplicative generator of the modulus. -/// It's derived with SageMath with: `GF(MODULUS).primitive_element()`. -const MULTIPLICATIVE_GENERATOR: Fp = Fp::from_raw([0x06, 0x00, 0x00, 0x00]); - -/// The modulus as u32 limbs. -#[cfg(not(target_pointer_width = "64"))] -const MODULUS_LIMBS_32: [u32; 8] = [ - 0xffff_ffff, - 0xffff_ffff, - 0xffff_ffff, - 0x0000_0000, - 0x0000_0000, - 0x0000_0000, - 0x0000_0001, - 0xffff_ffff, -]; - -/// Constant representing the modulus as static str -const MODULUS_STR: &str = "0xffffffff00000001000000000000000000000000ffffffffffffffffffffffff"; - -/// INV = -(p^{-1} mod 2^64) mod 2^64 -const INV: u64 = 0x1; - -/// R = 2^256 mod p -/// 0xfffffffeffffffffffffffffffffffff000000000000000000000001 -const R: Fp = Fp([ - 0x0000000000000001, - 0xffffffff00000000, - 0xffffffffffffffff, - 0xfffffffe, -]); - -/// R^2 = 2^512 mod p -/// 0x4fffffffdfffffffffffffffefffffffbffffffff0000000000000003 -const R2: Fp = Fp([ - 0x0000000000000003, - 0xfffffffbffffffff, - 0xfffffffffffffffe, - 0x4fffffffd, -]); - -/// R^3 = 2^768 mod p -/// 0x180000000100000005fffffffcffffffedfffffff7fffffffd0000000a -const R3: Fp = Fp([ - 0xfffffffd0000000a, - 0xffffffedfffffff7, - 0x00000005fffffffc, - 0x1800000001, -]); - -/// 1 / 2 mod p -/// 0x7fffffff80000000800000000000000000000000800000000000000000000000 -const TWO_INV: Fp = Fp::from_raw([ - 0x0000000000000000, - 0x0000000080000000, - 0x8000000000000000, - 0x7fffffff80000000, -]); - -const ZETA: Fp = Fp::from_raw([ - 0xd964598eb819acce, - 0x2e68c59bdef3e53f, - 0x62388a8e0ef62331, - 0x4d6ea8928adb86cf, -]); - -/// Generator of the t-order multiplicative subgroup. -/// Computed by exponentiating Self::MULTIPLICATIVE_GENERATOR by 2^s, where s is Self::S. -/// `0x0000000000000000000000000000000000000000000000000000000000000024`. -const DELTA: Fp = Fp::from_raw([0x24, 0, 0, 0]); - -/// Implementations of this trait MUST ensure that this is the generator used to derive Self::ROOT_OF_UNITY. -/// Derived from: -/// ```ignore -/// Zp(Zp(mul_generator)^t) where t = (modulus - 1 )/ 2 -/// 115792089237316195423570985008687907853269984665640564039457584007908834671662 -/// ``` -/// `0xffffffff00000001000000000000000000000000fffffffffffffffffffffffe` -const ROOT_OF_UNITY: Fp = Fp::from_raw([ - 0xfffffffffffffffe, - 0x00000000ffffffff, - 0x0000000000000000, - 0xffffffff00000001, -]); - -/// Inverse of [`ROOT_OF_UNITY`]. -/// `0xffffffff00000001000000000000000000000000fffffffffffffffffffffffe` -const ROOT_OF_UNITY_INV: Fp = Fp::from_raw([ - 0xfffffffffffffffe, - 0x00000000ffffffff, - 0x0000000000000000, - 0xffffffff00000001, -]); +use crate::{ + extend_field_legendre, field_bits, impl_add_binop_specify_output, impl_binops_additive, + impl_binops_additive_specify_output, impl_binops_calls, impl_binops_multiplicative, + impl_binops_multiplicative_mixed, impl_sub_binop_specify_output, + serialize_deserialize_primefield, +}; -impl_binops_additive!(Fp, Fp); -impl_binops_multiplicative!(Fp, Fp); -field_common!( +impl_field!( + secp256r1_base, Fp, - MODULUS, - INV, - MODULUS_STR, - TWO_INV, - ROOT_OF_UNITY_INV, - DELTA, - ZETA, - R, - R2, - R3 + modulus = "ffffffff00000001000000000000000000000000ffffffffffffffffffffffff", + mul_gen = "6", + zeta = "4d6ea8928adb86cf62388a8e0ef623312e68c59bdef3e53fd964598eb819acce", + from_uniform = [48, 64], ); -impl_from_u64!(Fp, R2); -field_arithmetic!(Fp, MODULUS, INV, dense); -impl_sum_prod!(Fp); - -#[cfg(target_pointer_width = "64")] -field_bits!(Fp, MODULUS); -#[cfg(not(target_pointer_width = "64"))] -field_bits!(Fp, MODULUS, MODULUS_LIMBS_32); - -impl Fp { - pub const fn size() -> usize { - 32 - } -} - -impl ff::Field for Fp { - const ZERO: Self = Self::zero(); - const ONE: Self = Self::one(); - - fn random(mut rng: impl RngCore) -> Self { - Self::from_u512([ - rng.next_u64(), - rng.next_u64(), - rng.next_u64(), - rng.next_u64(), - rng.next_u64(), - rng.next_u64(), - rng.next_u64(), - rng.next_u64(), - ]) - } - - fn double(&self) -> Self { - self.double() - } - - #[inline(always)] - fn square(&self) -> Self { - self.square() - } - - /// Computes the square root of this element, if it exists. - fn sqrt(&self) -> CtOption { - let tmp = self.pow([ - 0x0000000000000000, - 0x0000000040000000, - 0x4000000000000000, - 0x3fffffffc0000000, - ]); - - CtOption::new(tmp, tmp.square().ct_eq(self)) - } - - /// Returns the multiplicative inverse of the - /// element. If it is zero, the method fails. - fn invert(&self) -> CtOption { - self.invert() - } - - fn pow_vartime>(&self, exp: S) -> Self { - let mut res = Self::one(); - let mut found_one = false; - for e in exp.as_ref().iter().rev() { - for i in (0..64).rev() { - if found_one { - res = res.square(); - } - - if ((*e >> i) & 1) == 1 { - found_one = true; - res *= self; - } - } - } - res - } - - fn sqrt_ratio(num: &Self, div: &Self) -> (Choice, Self) { - ff::helpers::sqrt_ratio_generic(num, div) - } -} - -impl ff::PrimeField for Fp { - type Repr = [u8; 32]; - - const MODULUS: &'static str = MODULUS_STR; - const MULTIPLICATIVE_GENERATOR: Self = MULTIPLICATIVE_GENERATOR; - const TWO_INV: Self = TWO_INV; - const ROOT_OF_UNITY: Self = ROOT_OF_UNITY; - const ROOT_OF_UNITY_INV: Self = ROOT_OF_UNITY_INV; - const DELTA: Self = DELTA; - const NUM_BITS: u32 = 256; - const CAPACITY: u32 = 255; - const S: u32 = 1; - - fn from_repr(repr: Self::Repr) -> CtOption { - let mut tmp = Fp([0, 0, 0, 0]); - - tmp.0[0] = u64::from_le_bytes(repr[0..8].try_into().unwrap()); - tmp.0[1] = u64::from_le_bytes(repr[8..16].try_into().unwrap()); - tmp.0[2] = u64::from_le_bytes(repr[16..24].try_into().unwrap()); - tmp.0[3] = u64::from_le_bytes(repr[24..32].try_into().unwrap()); - - // Try to subtract the modulus - let (_, borrow) = sbb(tmp.0[0], MODULUS.0[0], 0); - let (_, borrow) = sbb(tmp.0[1], MODULUS.0[1], borrow); - let (_, borrow) = sbb(tmp.0[2], MODULUS.0[2], borrow); - let (_, borrow) = sbb(tmp.0[3], MODULUS.0[3], borrow); - - // If the element is smaller than MODULUS then the - // subtraction will underflow, producing a borrow value - // of 0xffff...ffff. Otherwise, it'll be zero. - let is_some = (borrow as u8) & 1; - - // Convert to Montgomery form by computing - // (a.R^0 * R^2) / R = a.R - tmp *= &R2; - - CtOption::new(tmp, Choice::from(is_some)) - } - - fn to_repr(&self) -> Self::Repr { - let tmp: [u64; 4] = (*self).into(); - let mut res = [0; 32]; - res[0..8].copy_from_slice(&tmp[0].to_le_bytes()); - res[8..16].copy_from_slice(&tmp[1].to_le_bytes()); - res[16..24].copy_from_slice(&tmp[2].to_le_bytes()); - res[24..32].copy_from_slice(&tmp[3].to_le_bytes()); - - res - } - - fn from_u128(v: u128) -> Self { - Self::from_raw([v as u64, (v >> 64) as u64, 0, 0]) - } - - fn is_odd(&self) -> Choice { - Choice::from(self.to_repr()[0] & 1) - } -} - -impl FromUniformBytes<64> for Fp { - /// Converts a 512-bit little endian integer into - /// an `Fp` by reducing by the modulus. - fn from_uniform_bytes(bytes: &[u8; 64]) -> Self { - Self::from_u512([ - u64::from_le_bytes(bytes[0..8].try_into().unwrap()), - u64::from_le_bytes(bytes[8..16].try_into().unwrap()), - u64::from_le_bytes(bytes[16..24].try_into().unwrap()), - u64::from_le_bytes(bytes[24..32].try_into().unwrap()), - u64::from_le_bytes(bytes[32..40].try_into().unwrap()), - u64::from_le_bytes(bytes[40..48].try_into().unwrap()), - u64::from_le_bytes(bytes[48..56].try_into().unwrap()), - u64::from_le_bytes(bytes[56..64].try_into().unwrap()), - ]) - } -} - -impl FromUniformBytes<48> for Fp { - fn from_uniform_bytes(bytes: &[u8; 48]) -> Self { - let repr = &mut [0u8; 64]; - (*repr)[0..48].copy_from_slice(&bytes[..48]); - Fp::from_uniform_bytes(repr) - } -} - -impl WithSmallOrderMulGroup<3> for Fp { - const ZETA: Self = ZETA; -} extend_field_legendre!(Fp); +impl_binops_calls!(Fp); +impl_binops_additive!(Fp, Fp); +impl_binops_multiplicative!(Fp, Fp); +field_bits!(Fp); +serialize_deserialize_primefield!(Fp); +crate::impl_from_u64!(Fp); #[cfg(test)] mod test { @@ -325,7 +36,7 @@ mod test { crate::field_testing_suite!(Fp, "quadratic_residue"); crate::field_testing_suite!(Fp, "bits"); crate::field_testing_suite!(Fp, "serialization_check"); - crate::field_testing_suite!(Fp, "constants", MODULUS_STR); + crate::field_testing_suite!(Fp, "constants"); crate::field_testing_suite!(Fp, "sqrt"); crate::field_testing_suite!(Fp, "zeta"); crate::field_testing_suite!(Fp, "from_uniform_bytes", 48, 64); diff --git a/src/secp256r1/fq.rs b/src/secp256r1/fq.rs index 2d965fb1..fa2e0c3d 100644 --- a/src/secp256r1/fq.rs +++ b/src/secp256r1/fq.rs @@ -1,312 +1,44 @@ -use crate::arithmetic::{adc, bigint_geq, mac, macx, sbb}; -use crate::extend_field_legendre; -use crate::ff::{FromUniformBytes, PrimeField, WithSmallOrderMulGroup}; -use core::fmt; -use core::ops::{Add, Mul, Neg, Sub}; +use core::convert::TryInto; +use halo2derive::impl_field; use rand::RngCore; use subtle::{Choice, ConditionallySelectable, ConstantTimeEq, CtOption}; -/// This represents an element of $\mathbb{F}_q$ where -/// -/// `q = 0xffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551` -/// -/// is the scalar field of the secp256r1 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. -#[derive(Clone, Copy, PartialEq, Eq, Hash)] -pub struct Fq(pub(crate) [u64; 4]); - -#[cfg(feature = "derive_serde")] -crate::serialize_deserialize_32_byte_primefield!(Fq); - -/// Constant representing the modulus -/// q = 0xffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551 -const MODULUS: Fq = Fq([ - 0xf3b9cac2fc632551, - 0xbce6faada7179e84, - 0xffffffffffffffff, - 0xffffffff00000000, -]); - -/// The modulus as u32 limbs. -#[cfg(not(target_pointer_width = "64"))] -const MODULUS_LIMBS_32: [u32; 8] = [ - 0xfc63_2551, - 0xf3b9_cac2, - 0xa717_9e84, - 0xbce6_faad, - 0xffff_ffff, - 0xffff_ffff, - 0x0000_0000, - 0xffff_ffff, -]; - -///Constant representing the modulus as static str -const MODULUS_STR: &str = "0xffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551"; - -/// INV = -(q^{-1} mod 2^64) mod 2^64 -const INV: u64 = 0xccd1c8aaee00bc4f; - -/// R = 2^256 mod q -/// 0xffffffff00000000000000004319055258e8617b0c46353d039cdaaf -const R: Fq = Fq([ - 0x0c46353d039cdaaf, - 0x4319055258e8617b, - 0x0000000000000000, - 0xffffffff, -]); - -/// R^2 = 2^512 mod q -/// 0x66e12d94f3d956202845b2392b6bec594699799c49bd6fa683244c95be79eea2 -const R2: Fq = Fq([ - 0x83244c95be79eea2, - 0x4699799c49bd6fa6, - 0x2845b2392b6bec59, - 0x66e12d94f3d95620, -]); - -/// R^3 = 2^768 mod q -/// 0x503a54e76407be652543b9246ba5e93f111f28ae0c0555c9ac8ebec90b65a624 -const R3: Fq = Fq([ - 0xac8ebec90b65a624, - 0x111f28ae0c0555c9, - 0x2543b9246ba5e93f, - 0x503a54e76407be65, -]); - -/// `GENERATOR = 7 mod r` is a generator of the `q - 1` order multiplicative -/// subgroup, or in other words a primitive root of the field. -/// It's derived with SageMath with: `GF(MODULUS).primitive_element()`. -const GENERATOR: Fq = Fq::from_raw([0x07, 0x00, 0x00, 0x00]); - -/// GENERATOR^t where t * 2^s + 1 = r with t odd. In other words, this is a 2^s root of unity. -/// `ffc97f062a770992ba807ace842a3dfc1546cad004378daf0592d7fbb41e6602` -const ROOT_OF_UNITY: Fq = Fq::from_raw([ - 0x0592d7fbb41e6602, - 0x1546cad004378daf, - 0xba807ace842a3dfc, - 0xffc97f062a770992, -]); - -/// 1 / ROOT_OF_UNITY mod q -/// `a0a66a5562d46f2ac645fa0458131caee3ac117c794c4137379c7f0657c73764` -const ROOT_OF_UNITY_INV: Fq = Fq::from_raw([ - 0x379c7f0657c73764, - 0xe3ac117c794c4137, - 0xc645fa0458131cae, - 0xa0a66a5562d46f2a, -]); - -/// 1 / 2 mod q -const TWO_INV: Fq = Fq::from_raw([ - 0x79dce5617e3192a9, - 0xde737d56d38bcf42, - 0x7fffffffffffffff, - 0x7fffffff80000000, -]); - -const ZETA: Fq = Fq::from_raw([ - 0x7cbf87ff12884e21, - 0x9405335ce9c83e1d, - 0x4e786d0777fd6aef, - 0x52891d43d946a035, -]); - -/// Generator of the t-order multiplicative subgroup. -/// Computed by exponentiating Self::MULTIPLICATIVE_GENERATOR by 2^s, where s is Self::S. -const DELTA: Fq = Fq::from_raw([0x1e39a5057d81, 0, 0, 0]); - use crate::{ - field_arithmetic, field_bits, field_common, field_specific, impl_add_binop_specify_output, - impl_binops_additive, impl_binops_additive_specify_output, impl_binops_multiplicative, - impl_binops_multiplicative_mixed, impl_from_u64, impl_sub_binop_specify_output, impl_sum_prod, + extend_field_legendre, field_bits, impl_add_binop_specify_output, impl_binops_additive, + impl_binops_additive_specify_output, impl_binops_calls, impl_binops_multiplicative, + impl_binops_multiplicative_mixed, impl_sub_binop_specify_output, + serialize_deserialize_primefield, }; -impl_binops_additive!(Fq, Fq); -impl_binops_multiplicative!(Fq, Fq); -field_common!( + +impl_field!( + secp256r1_scalar, Fq, - MODULUS, - INV, - MODULUS_STR, - TWO_INV, - ROOT_OF_UNITY_INV, - DELTA, - ZETA, - R, - R2, - R3 + modulus = "ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551", + mul_gen = "7", + zeta = "52891d43d946a0354e786d0777fd6aef9405335ce9c83e1d7cbf87ff12884e21", + from_uniform = [48, 64], ); -impl_from_u64!(Fq, R2); -field_arithmetic!(Fq, MODULUS, INV, dense); -impl_sum_prod!(Fq); - -#[cfg(target_pointer_width = "64")] -field_bits!(Fq, MODULUS); -#[cfg(not(target_pointer_width = "64"))] -field_bits!(Fq, MODULUS, MODULUS_LIMBS_32); - -impl Fq { - pub const fn size() -> usize { - 32 - } -} - -impl ff::Field for Fq { - const ZERO: Self = Self::zero(); - const ONE: Self = Self::one(); - - fn random(mut rng: impl RngCore) -> Self { - Self::from_u512([ - rng.next_u64(), - rng.next_u64(), - rng.next_u64(), - rng.next_u64(), - rng.next_u64(), - rng.next_u64(), - rng.next_u64(), - rng.next_u64(), - ]) - } - - fn double(&self) -> Self { - self.double() - } - - #[inline(always)] - fn square(&self) -> Self { - self.square() - } - - /// Returns the multiplicative inverse of the - /// element. If it is zero, the method fails. - fn invert(&self) -> CtOption { - self.invert() - } - - fn pow_vartime>(&self, exp: S) -> Self { - let mut res = Self::one(); - let mut found_one = false; - for e in exp.as_ref().iter().rev() { - for i in (0..64).rev() { - if found_one { - res = res.square(); - } - - if ((*e >> i) & 1) == 1 { - found_one = true; - res *= self; - } - } - } - res - } - - fn sqrt(&self) -> CtOption { - // 7fffffff800000007fffffffffffffffde737d56d38bcf4279dce5617e3192a - let tm1d2 = [ - 0x279dce5617e3192a, - 0xfde737d56d38bcf4, - 0x07ffffffffffffff, - 0x7fffffff8000000, - ]; - - ff::helpers::sqrt_tonelli_shanks(self, tm1d2) - } - - fn sqrt_ratio(num: &Self, div: &Self) -> (Choice, Self) { - ff::helpers::sqrt_ratio_generic(num, div) - } -} - -impl ff::PrimeField for Fq { - type Repr = [u8; 32]; - - const NUM_BITS: u32 = 256; - const CAPACITY: u32 = 255; - const MODULUS: &'static str = MODULUS_STR; - const MULTIPLICATIVE_GENERATOR: Self = GENERATOR; - const ROOT_OF_UNITY: Self = ROOT_OF_UNITY; - const ROOT_OF_UNITY_INV: Self = ROOT_OF_UNITY_INV; - const TWO_INV: Self = TWO_INV; - const DELTA: Self = DELTA; - const S: u32 = 4; - - fn from_repr(repr: Self::Repr) -> CtOption { - let mut tmp = Fq([0, 0, 0, 0]); - - tmp.0[0] = u64::from_le_bytes(repr[0..8].try_into().unwrap()); - tmp.0[1] = u64::from_le_bytes(repr[8..16].try_into().unwrap()); - tmp.0[2] = u64::from_le_bytes(repr[16..24].try_into().unwrap()); - tmp.0[3] = u64::from_le_bytes(repr[24..32].try_into().unwrap()); - - // Try to subtract the modulus - let (_, borrow) = sbb(tmp.0[0], MODULUS.0[0], 0); - let (_, borrow) = sbb(tmp.0[1], MODULUS.0[1], borrow); - let (_, borrow) = sbb(tmp.0[2], MODULUS.0[2], borrow); - let (_, borrow) = sbb(tmp.0[3], MODULUS.0[3], borrow); - - // If the element is smaller than MODULUS then the - // subtraction will underflow, producing a borrow value - // of 0xffff...ffff. Otherwise, it'll be zero. - let is_some = (borrow as u8) & 1; - - // Convert to Montgomery form by computing - // (a.R^0 * R^2) / R = a.R - tmp *= &R2; - - CtOption::new(tmp, Choice::from(is_some)) - } - - fn to_repr(&self) -> Self::Repr { - let tmp: [u64; 4] = (*self).into(); - let mut res = [0; 32]; - res[0..8].copy_from_slice(&tmp[0].to_le_bytes()); - res[8..16].copy_from_slice(&tmp[1].to_le_bytes()); - res[16..24].copy_from_slice(&tmp[2].to_le_bytes()); - res[24..32].copy_from_slice(&tmp[3].to_le_bytes()); - - res - } - - fn is_odd(&self) -> Choice { - Choice::from(self.to_repr()[0] & 1) - } -} - -impl FromUniformBytes<64> for Fq { - /// Converts a 512-bit little endian integer into - /// an `Fq` by reducing by the modulus. - fn from_uniform_bytes(bytes: &[u8; 64]) -> Self { - Self::from_u512([ - u64::from_le_bytes(bytes[0..8].try_into().unwrap()), - u64::from_le_bytes(bytes[8..16].try_into().unwrap()), - u64::from_le_bytes(bytes[16..24].try_into().unwrap()), - u64::from_le_bytes(bytes[24..32].try_into().unwrap()), - u64::from_le_bytes(bytes[32..40].try_into().unwrap()), - u64::from_le_bytes(bytes[40..48].try_into().unwrap()), - u64::from_le_bytes(bytes[48..56].try_into().unwrap()), - u64::from_le_bytes(bytes[56..64].try_into().unwrap()), - ]) - } -} - -impl WithSmallOrderMulGroup<3> for Fq { - const ZETA: Self = ZETA; -} extend_field_legendre!(Fq); +impl_binops_calls!(Fq); +impl_binops_additive!(Fq, Fq); +impl_binops_multiplicative!(Fq, Fq); +field_bits!(Fq); +serialize_deserialize_primefield!(Fq); +crate::impl_from_u64!(Fq); #[cfg(test)] mod test { + use super::*; crate::field_testing_suite!(Fq, "field_arithmetic"); crate::field_testing_suite!(Fq, "conversion"); crate::field_testing_suite!(Fq, "serialization"); crate::field_testing_suite!(Fq, "quadratic_residue"); + crate::field_testing_suite!(Fq, "bits"); crate::field_testing_suite!(Fq, "serialization_check"); - crate::field_testing_suite!(Fq, "constants", MODULUS_STR); + crate::field_testing_suite!(Fq, "constants"); crate::field_testing_suite!(Fq, "sqrt"); crate::field_testing_suite!(Fq, "zeta"); - crate::field_testing_suite!(Fq, "from_uniform_bytes", 64); + crate::field_testing_suite!(Fq, "from_uniform_bytes", 48, 64); } diff --git a/src/serde.rs b/src/serde.rs index 5d0f24fc..c648ebd7 100644 --- a/src/serde.rs +++ b/src/serde.rs @@ -23,3 +23,45 @@ pub trait SerdeObject: Sized { fn write_raw(&self, writer: &mut W) -> io::Result<()>; } + +pub(crate) mod endian { + + pub trait Endian { + fn to_bytes(res: &mut [u8], el: &[u64]); + fn from_bytes(res: &[u8], el: &mut [u64]); + } + + pub struct LE; + pub struct BE; + + impl Endian for LE { + fn to_bytes(res: &mut [u8], el: &[u64]) { + el.iter().enumerate().for_each(|(i, limb)| { + let off = i * 8; + res[off..off + 8].copy_from_slice(&limb.to_le_bytes()); + }); + } + + fn from_bytes(res: &[u8], el: &mut [u64]) { + el.iter_mut().enumerate().for_each(|(i, limb)| { + let off = i * 8; + *limb = u64::from_le_bytes(res[off..off + 8].try_into().unwrap()); + }); + } + } + impl Endian for BE { + fn to_bytes(res: &mut [u8], el: &[u64]) { + el.iter().rev().enumerate().for_each(|(i, limb)| { + let off = i * 8; + res[off..off + 8].copy_from_slice(&limb.to_be_bytes()); + }); + } + + fn from_bytes(res: &[u8], el: &mut [u64]) { + el.iter_mut().rev().enumerate().for_each(|(i, limb)| { + let off = i * 8; + *limb = u64::from_be_bytes(res[off..off + 8].try_into().unwrap()); + }); + } + } +} diff --git a/src/tests/curve.rs b/src/tests/curve.rs index ae63e30a..a482c9c0 100644 --- a/src/tests/curve.rs +++ b/src/tests/curve.rs @@ -235,20 +235,20 @@ macro_rules! curve_testing_suite { ($c: ident) => { assert!(bool::from( $c::from_bytes(&$c::identity().to_bytes()) - .unwrap() - .is_identity() + .unwrap() + .is_identity() )); assert!(bool::from( <$c as CurveExt>::AffineExt::from_uncompressed(&<$c as CurveExt>::AffineExt::identity().to_uncompressed()) - .unwrap() - .is_identity() + .unwrap() + .is_identity() )); assert!(bool::from( <$c as CurveExt>::AffineExt::from_bytes(&<$c as CurveExt>::AffineExt::identity().to_bytes()) - .unwrap() - .is_identity() + .unwrap() + .is_identity() )); for _ in 0..100 { diff --git a/src/tests/field.rs b/src/tests/field.rs index 5a62eb0b..6a44319e 100644 --- a/src/tests/field.rs +++ b/src/tests/field.rs @@ -1,10 +1,9 @@ use ff::{FromUniformBytes, PrimeField}; -use rand::RngCore; #[macro_export] macro_rules! field_testing_suite { ($field: ident, "field_arithmetic") => { - fn random_multiplication_tests(mut rng: R, n: usize) { + fn random_multiplication_tests(mut rng: R, n: usize) { for _ in 0..n { let a = F::random(&mut rng); let b = F::random(&mut rng); @@ -27,7 +26,7 @@ macro_rules! field_testing_suite { } } - fn random_addition_tests(mut rng: R, n: usize) { + fn random_addition_tests(mut rng: R, n: usize) { for _ in 0..n { let a = F::random(&mut rng); let b = F::random(&mut rng); @@ -50,7 +49,7 @@ macro_rules! field_testing_suite { } } - fn random_subtraction_tests(mut rng: R, n: usize) { + fn random_subtraction_tests(mut rng: R, n: usize) { for _ in 0..n { let a = F::random(&mut rng); let b = F::random(&mut rng); @@ -68,7 +67,7 @@ macro_rules! field_testing_suite { } } - fn random_negation_tests(mut rng: R, n: usize) { + fn random_negation_tests(mut rng: R, n: usize) { for _ in 0..n { let a = F::random(&mut rng); let mut b = a; @@ -79,7 +78,7 @@ macro_rules! field_testing_suite { } } - fn random_doubling_tests(mut rng: R, n: usize) { + fn random_doubling_tests(mut rng: R, n: usize) { for _ in 0..n { let mut a = F::random(&mut rng); let mut b = a; @@ -90,7 +89,7 @@ macro_rules! field_testing_suite { } } - fn random_squaring_tests(mut rng: R, n: usize) { + fn random_squaring_tests(mut rng: R, n: usize) { for _ in 0..n { let mut a = F::random(&mut rng); let mut b = a; @@ -101,7 +100,7 @@ macro_rules! field_testing_suite { } } - fn random_inversion_tests(mut rng: R, n: usize) { + fn random_inversion_tests(mut rng: R, n: usize) { assert!(bool::from(F::ZERO.invert().is_none())); for _ in 0..n { @@ -113,7 +112,7 @@ macro_rules! field_testing_suite { } } - fn random_expansion_tests(mut rng: R, n: usize) { + fn random_expansion_tests(mut rng: R, n: usize) { for _ in 0..n { // Compare (a + b)(c + d) and (a*c + b*c + a*d + b*d) @@ -145,7 +144,7 @@ macro_rules! field_testing_suite { } } - fn zero_tests(mut rng: R) { + fn zero_tests(mut rng: R) { assert_eq!(F::ZERO.is_zero().unwrap_u8(), 1); { let mut z = F::ZERO; @@ -171,7 +170,7 @@ macro_rules! field_testing_suite { } } - fn one_tests(mut rng: R) { + fn one_tests(mut rng: R) { assert!(bool::from(F::ONE.invert().is_some())); // Multiplication by one @@ -224,6 +223,7 @@ macro_rules! field_testing_suite { ($field: ident, "conversion") => { #[test] fn test_conversion() { + use ff::PrimeField; let mut rng = XorShiftRng::from_seed([ 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, 0xe5, @@ -316,7 +316,7 @@ macro_rules! field_testing_suite { #[test] #[cfg(feature = "bits")] fn test_bits() { - use ff::PrimeFieldBits; + use ff::{PrimeFieldBits,PrimeField}; // random bit test let mut rng = XorShiftRng::from_seed([ 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, @@ -334,17 +334,6 @@ macro_rules! field_testing_suite { }; ($field: ident, "serialization_check") => { - fn is_less_than(x: &[u64; N], y: &[u64; N]) -> bool { - for i in (1..N).rev() { - match x[i].cmp(&y[i]) { - core::cmp::Ordering::Less => return true, - core::cmp::Ordering::Greater => return false, - _ => {} - } - } - x[0].lt(&y[0]) - } - #[test] fn test_serialization_check() { use $crate::serde::SerdeObject; @@ -352,13 +341,14 @@ macro_rules! field_testing_suite { 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, 0xe5, ]); - const LIMBS: usize = $field::size() / 8; + const LIMBS: usize = $field::SIZE / 8; // failure check for _ in 0..1000000 { let rand_word = [(); LIMBS].map(|_| rng.next_u64()); let a = $field(rand_word); let rand_bytes = a.to_raw_bytes(); - match is_less_than::(&rand_word, &MODULUS.0) { + + match $field::is_less_than_modulus(&rand_word) { false => { assert!($field::from_raw_bytes(&rand_bytes).is_none()); } @@ -370,10 +360,10 @@ macro_rules! field_testing_suite { } }; - ($field: ident, "constants", $modulus_str: expr) => { + ($field: ident, "constants") => { #[test] fn test_primefield_constants() { - assert_eq!($field::MODULUS, $modulus_str); + use ff::PrimeField; assert_eq!( $field::ROOT_OF_UNITY_INV, $field::ROOT_OF_UNITY.invert().unwrap() @@ -396,6 +386,7 @@ macro_rules! field_testing_suite { #[test] fn test_sqrt() { use $crate::ff_ext::Legendre; + use ff::PrimeField; use rand_core::OsRng; let v = ($field::TWO_INV).square().sqrt().unwrap(); @@ -443,6 +434,7 @@ macro_rules! field_testing_suite { ($field: ident, "zeta" $(, $base_field: ident)*) => { #[test] fn test_zeta() { + use ff::WithSmallOrderMulGroup; assert_eq!($field::ZETA * $field::ZETA * $field::ZETA, $field::ONE); assert_ne!($field::ZETA * $field::ZETA, $field::ONE); $( @@ -731,19 +723,20 @@ where { use num_bigint::BigUint; use rand_core::OsRng; + use rand_core::RngCore; + + let uniform_bytes = [0u8; L]; + assert_eq!(F::from_uniform_bytes(&uniform_bytes), F::ZERO); - let mut uniform_bytes = [0u8; L]; - OsRng.fill_bytes(&mut uniform_bytes[..]); + let mut uniform_bytes = [u8::MAX; L]; - let e0 = { + for _ in 0..10000 { let e0 = BigUint::from_bytes_le(&uniform_bytes); - let e0 = e0 % crate::tests::modulus::(); - let bytes = e0.to_bytes_le(); - let mut e0 = F::Repr::default(); - e0.as_mut()[..bytes.len()].copy_from_slice(&bytes); - F::from_repr(e0).unwrap() - }; + let e0: F = crate::tests::big_to_fe(&e0); + + let e1 = F::from_uniform_bytes(&uniform_bytes); + assert_eq!(e0, e1); - let e1 = F::from_uniform_bytes(&uniform_bytes); - assert_eq!(e0, e1); + OsRng.fill_bytes(&mut uniform_bytes[..]); + } } diff --git a/src/tests/mod.rs b/src/tests/mod.rs index e0fff697..22feadc5 100644 --- a/src/tests/mod.rs +++ b/src/tests/mod.rs @@ -6,17 +6,18 @@ pub mod curve; pub mod field; pub(crate) fn hex_to_bytes(hex: &str) -> Vec { - hex.as_bytes() + let bytes = hex.as_bytes().to_vec(); + bytes .chunks(2) .map(|chunk| u8::from_str_radix(std::str::from_utf8(chunk).unwrap(), 16).unwrap()) .collect() } pub(crate) fn hex_to_field(hex: &str) -> F { - let bytes = hex_to_bytes(hex); + let mut bytes = hex_to_bytes(hex); + bytes.reverse(); let mut repr = F::Repr::default(); - repr.as_mut().copy_from_slice(&bytes); - repr.as_mut().reverse(); + repr.as_mut()[..bytes.len()].copy_from_slice(&bytes); F::from_repr(repr).unwrap() } @@ -30,6 +31,14 @@ pub(crate) fn fe_to_big(fe: &F) -> BigUint { BigUint::from_bytes_le(fe.to_repr().as_ref()) } +pub fn big_to_fe(e: &BigUint) -> F { + let e = e % modulus::(); + let bytes = e.to_bytes_le(); + let mut repr = F::Repr::default(); + repr.as_mut()[..bytes.len()].copy_from_slice(&bytes[..]); + F::from_repr(repr).unwrap() +} + pub(crate) fn modulus() -> BigUint { fe_to_big(&-F::ONE) + 1usize }