Skip to main content

ark_vrf/suites/
bandersnatch_sw.rs

1//! `ECVRF Bandersnatch-SW SHA-512 Try and Increment` suite.
2//!
3//! Configuration:
4//!
5//! * `suite_string` = b"Bandersnatch_SW_SHA-512_TAI" for Short Weierstrass form.
6//!
7//! - The EC group **G** is the prime subgroup of the Bandersnatch elliptic curve,
8//!   in Short Weierstrass form, with finite field and curve parameters as specified in
9//!   [MSZ21](https://eprint.iacr.org/2021/1152).
10//!   For this group, `fLen` = `qLen` = $32$ and `cofactor` = $4$.
11//!
12//! - The prime subgroup generator G is defined as follows:
13//!   - G.x = 30900340493481298850216505686589334086208278925799850409469406976849338430199
14//!   - G.y = 12663882780877899054958035777720958383845500985908634476792678820121468453298
15//!
16//! * `cLen` = 16 (128-bit security level).
17//!
18//! * The key pair generation primitive is `PK = sk * G`, with x the secret
19//!   key scalar and `G` the group generator. In this ciphersuite, the secret
20//!   scalar x is equal to the secret key scalar sk.
21//!
22//! * Nonce generation is inspired by Section 5.4.2.2 of RFC-9381,
23//!   adapted to use the suite's pluggable transcript.
24//!
25//! * The int_to_string function encodes into the 32 bytes little endian
26//!   representation.
27//!
28//! * The string_to_int function decodes from the 32 bytes little endian
29//!   representation.
30//!
31//! * The point_to_string function converts a point in **G** to an octet
32//!   string using compressed form. The y coordinate is encoded using
33//!   int_to_string function and the most significant bit of the last
34//!   octet is used to keep track of the x's sign. This implies that
35//!   the point is encoded on 32 bytes.
36//!
37//! * The string_to_point function tries to decompress the point encoded
38//!   according to `point_to_string` procedure. This function MUST outputs
39//!   "INVALID" if the octet string does not decode to a point on G.
40//!
41//! * The hash function Hash is SHA-512 as specified in
42//!   [RFC6234](https://www.rfc-editor.org/rfc/rfc6234), with hLen = 64.
43//!
44//! * The `ECVRF_encode_to_curve` function uses *Try and Increment*, inspired
45//!   by section 5.4.1.1 of [RFC-9381](https://datatracker.ietf.org/doc/rfc9381),
46//!   with `h2c_suite_ID_string` = `"Bandersnatch_XMD:SHA-512_TAI_RO_"`
47//!   and domain separation tag `DST = "ECVRF_" || h2c_suite_ID_string || suite_string`.
48
49use super::{SuiteId, curve, h2c, hash};
50use crate::{pedersen::PedersenSuite, utils::te_sw_map::*, *};
51use ark_ff::MontFp;
52
53#[derive(Debug, Copy, Clone, PartialEq, Eq)]
54pub struct BandersnatchSha512Tai;
55
56type ThisSuite = BandersnatchSha512Tai;
57
58impl Suite for ThisSuite {
59    const SUITE_ID: SuiteId = SuiteId::new(1, curve::BANDERSNATCH_SW, hash::SHA512, h2c::TAI);
60    type Affine = ark_ed_on_bls12_381_bandersnatch::SWAffine;
61    type Transcript = utils::HashTranscript<sha2::Sha512>;
62}
63
64impl PedersenSuite for ThisSuite {
65    const BLINDING_BASE: AffinePoint = {
66        const X: BaseField = MontFp!(
67            "48417510423101441118061444208906839372921043480482028226883257289063255545370"
68        );
69        const Y: BaseField =
70            MontFp!("605975869554501667057064844799976277818323013043881651153113184398732331110");
71        AffinePoint::new_unchecked(X, Y)
72    };
73}
74
75suite_types!(ThisSuite);
76
77#[cfg(feature = "ring")]
78impl crate::ring::RingSuite for ThisSuite {
79    type Pairing = ark_bls12_381::Bls12_381;
80
81    const ACCUMULATOR_BASE: AffinePoint = {
82        const X: BaseField = MontFp!(
83            "25211608582516829155149684046519409765416282531700259721714491517260527956556"
84        );
85        const Y: BaseField = MontFp!(
86            "32863183837707411136510171551403506326134988374168040624784347522530012895695"
87        );
88        AffinePoint::new_unchecked(X, Y)
89    };
90
91    const PADDING: AffinePoint = {
92        const X: BaseField = MontFp!(
93            "46209466588428303799925407479102585354714183247629074296053567086083553831253"
94        );
95        const Y: BaseField = MontFp!(
96            "46784016388819574388957654398028401259803727732223934061065126175128758725649"
97        );
98        AffinePoint::new_unchecked(X, Y)
99    };
100}
101
102#[cfg(feature = "ring")]
103ring_suite_types!(ThisSuite);
104
105// sage: q = 52435875175126190479447740508185965837690552500527637822603658699938581184513
106// sage: Fq = GF(q)
107// sage: MONT_A = 29978822694968839326280996386011761570173833766074948509196803838190355340952
108// sage: MONT_B = 25465760566081946422412445027709227188579564747101592991722834452325077642517
109// sage: MONT_A/Fq(3) = 9992940898322946442093665462003920523391277922024982836398934612730118446984
110// sage: Fq(1)/MONT_B = 41180284393978236561320365279764246793818536543197771097409483252169927600582
111impl MapConfig for ark_ed_on_bls12_381_bandersnatch::BandersnatchConfig {
112    const MONT_A_OVER_THREE: ark_ed_on_bls12_381_bandersnatch::Fq =
113        MontFp!("9992940898322946442093665462003920523391277922024982836398934612730118446984");
114    const MONT_B_INV: ark_ed_on_bls12_381_bandersnatch::Fq =
115        MontFp!("41180284393978236561320365279764246793818536543197771097409483252169927600582");
116}
117
118#[cfg(test)]
119mod tests {
120    use super::*;
121    use crate::{testing, tiny_suite_tests};
122    use ark_ed_on_bls12_381_bandersnatch::{BandersnatchConfig, SWAffine};
123
124    impl crate::testing::SuiteExt for ThisSuite {
125        const SUITE_NAME: &str = "bandersnatch_sw_sha-512_tai";
126    }
127
128    tiny_suite_tests!(ThisSuite);
129    pedersen_suite_tests!(ThisSuite);
130    thin_suite_tests!(ThisSuite);
131
132    #[cfg(feature = "ring")]
133    ring_suite_tests!(ThisSuite);
134
135    #[cfg(feature = "ring")]
136    impl crate::ring::testing::RingSuiteExt for ThisSuite {
137        const SRS_FILE: &str = crate::testing::BLS12_381_PCS_SRS_FILE;
138
139        fn params() -> &'static RingProofParams {
140            use std::sync::OnceLock;
141            static PARAMS: OnceLock<RingProofParams> = OnceLock::new();
142            PARAMS.get_or_init(Self::load_context)
143        }
144    }
145
146    #[test]
147    fn sw_to_te_roundtrip() {
148        let roundtrip = |org_point| {
149            let te_point = sw_to_te::<BandersnatchConfig>(&org_point).unwrap();
150            assert!(te_point.is_on_curve());
151            let sw_point = te_to_sw::<BandersnatchConfig>(&te_point).unwrap();
152            assert!(sw_point.is_on_curve());
153            assert_eq!(org_point, sw_point);
154        };
155        roundtrip(testing::random_val::<SWAffine>(None));
156        roundtrip(AffinePoint::generator());
157    }
158}