Search
1000 results for “commons_protocol”
-
A Bad Wife
I live with my two husbands. The oldest one stands across the courtyard – dead – two feet above ground, several feet below. The youngest one is plugged in the bedroom, recharging. While I sit here, trying to write the story of my life. Where should I begin?
Let’s begin from the beginning.
One day, Brahma created the beautiful earth – mountains and rivers, birds and animals – then went into deep meditation. When he awakened eons later, he saw that all creatures had multiplied and made the world even more gorgeous. Pleased, he thought: I should create beings who can truly appreciate this beauty the way I do! So he created four men from the four directions. Perfect beings. But when he commanded them to reproduce and populate the earth, they refused. Enraged by their disobedience, Brahma’s anger took form – Rudra emerged from his mind, fierce and obedient. “You! Create the people!” Brahma ordered Rudra, and returned to meditation. When he next opened his eyes, the earth crawled with ugly beasts. Disappointed, Brahma stopped Rudra’s work and sent him away to meditate, to dive deep into his soul and learn the proper way of creation. Then Brahma had a thought: Why not create a species like the animals – one that reproduces through attraction and desire, beings who will both enjoy this world and populate it? But he had no template, no shape for such creatures. He prayed to the higher energy for guidance. In response, a magnificent being appeared – half-man, half-woman. The divine energy smiled and said, “Divide my form into two parts. Make them man and woman. They will always be drawn to each other – if not in body, then in mind, if not in this life, then across lifetimes. Then someday, I myself will unite and guide them towards a better eternal world free from the shackles of mortality, desire and longing.”
My grandma used to tell this story from Shiva Purana when I was young. And I would ask her, why did Brahma tear apart something that was already complete?
Beta, she said, cracking her knuckles like small firecrackers, because completion makes the gods nervous. They prefer us hungry, always searching.
I think about this story often, especially when I consider the mathematics of my marriages – the endless calibration through adding and subtracting so that the sum of two incomplete entities might somehow equal one satisfied union.
In my forty five years of life, I have married three times. The first time to a tree – because the stars, in their infinite cosmic wisdom, declared me mangalik, astrologically toxic. “Caution: May cause sudden death in men. Handle with care.” The second time I married a man who married me just because he thought everyone else his age did and he must too. The third time I married something that might be the future, or might be my final descent into madness. We will see.
But before we begin this cautionary tale – or whatever it turns out to be – let me pose a question that has plagued philosophers from Plato to your neighborhood aunties: What is marriage, really? Is it a social contract? A biological imperative? A cosmic joke played by bored deities? Or is it simply the human heart’s stubborn refusal to learn from its own mistakes?
Oh, don’t look so uncomfortable. We’re all complicit here. You’ve loved, haven’t you? You’ve wanted things you couldn’t name, settled for things that named you instead? Good. Then you’ll understand.
They say women like me are dangerous. Thrice-married at forty-five, what-will-people-say. But people will say regardless, won’t they? They whispered when I married the tree at seventeen – what superstition, what drama. When I was unmarried (to a human male) at twenty-five – shelf-life expired, spoiled goods. When I divorced Rahul they called me used merchandise; and now, amongst the youngest of the family I’m the eccentric aunt with my “modern arrangement.”
The thing about marriage, I think, is that it has always been a transaction. Always. The currency has simply evolved. Earlier it was cows and gold and virgin hymens. Then it was emotional labor and intellectual compatibility and, in my most recent case, USB-C charging ports.
We tell ourselves stories about love conquering all, about soulmates and destiny and other beautiful lies. But marriage? Marriage is economics. Who owes what to whom? Who pays what price for whose presence? How much can one party spend of themselves before going bankrupt? Who subsidizes whose dreams, or not? Just like that.
***
There once was a king who was desperately unhappy despite having everything. He consulted wise men, doctors, astrologers. Finally, someone told him, “Find the happiest man in your kingdom and wear his shirt. You’ll be cured.” The king sent his soldiers searching everywhere. They found the happiest man – a poor woodcutter singing in the forest, radiating joy. But when they asked for his shirt, he laughed and said, “Shirt? I don’t have a shirt!”
The king never got cured, but I learned something from that story: happiness isn’t something you can borrow from others. It’s something you either have or you don’t.
I was once happy. When My father was alive. My father used to call me his king. My little raja, he would say, lifting me up so I could see the world from the height of his love.
No, Papa, I would giggle. You are the king. I am your princess.
Then you are my princess who will grow up to rule her own kingdom one day, he would say, and in his voice I heard the certainty that I was destined for something magnificent.
He died when I was fifteen, a heart attack as sudden as monsoon lightning, leaving behind the smell of his aftershave and a daughter who would spend the next thirty years searching his shadow in every man that came into her life.
After his death, my mother’s eyes would grow distant when she looked at me. When you marry, she would say, folding saris that would someday fill my trousseau, your husband will be a king and keep you like a queen. That’s what your father would have wanted.
I wanted to tell her – Papa had seen me as royalty already. I didn’t need to marry into a kingdom; I had been born into one. But I couldn’t.
Who am I to you? A burden? I finally let it out in front of my mother during one of those angry, grief-heavy days.
You are my responsibility, she said, not unkindly, but with the weariness of a woman who had suddenly become sole proprietor of a daughter’s future. You are the girl I need to see safely married to a good man.
My mother was quick in fulfilling her responsibilities. I was seventeen when I first married – to a Banyan tree across the courtyard of our ancestral house.
Picture this, if you will: a seventeen-year-old girl, draped in wedding silk like a sacrifice wrapped for the gods, standing before a Banyan tree older than the British Raj. My mother weeping tears that could have been relief or shame. The priest was mumbling something about Mars and malefic energies, about how I was cosmically radioactive, matrimonially Chernobyl.
Better the tree than a boy, whispered my grandma jokingly. Trees don’t have mothers-in-law.
Wisdom, that. The kind that comes too late and cuts too deep.
I tied the sacred thread around the Banyan’s massive trunk – my arm barely spanning a tenth of its circumference and I felt something I hadn’t expected: relief. Like finally exhaling after holding your breath through an entire season. Foolish me believed that this was it. Done with the duty called ‘marriage’ in life.
I pressed my palm against the bark – rough, real. And I thought – this is what marriage feels like. Ancient. Immutable. Indifferent. But also calming.
What do you want from me? I asked it silently.
Nothing. It wanted nothing. For the first time after my father’s death, I was enough for someone. The tree never asked me to be fairer, thinner, quieter. It never demanded I cook its mother’s recipes or produce mini versions of it.
Tell me how to love you. I asked the tree once.
The leaves rustled. Wind, probably. But I chose to hear it as laughter.
You don’t, was what I thought it replied. You just stay.
Buddha attained enlightenment under a bodhi tree. I attained something equally revolutionary under my Banyan. Under its shade, I read books that would have scandalized my mother. I discovered things about myself that would have been considered improper for a good Hindu girl to know before marriage. I learned that I had desires that weren’t mentioned in any of the marriage preparation talks. That I could want a man’s hands on my body without wanting his name or his children. That I could imagine being kissed until my lips were swollen and my sari was wrinkled and my hair had escaped its braid, and none of this made me a bad woman – just a human one.
The tree kept my secrets. All of them.
Twenty years later… different tree now. Rahul’s family tree, thick with the branches of expectations, heavy with the fruit of traditional values. His mother’s eyes measuring me like rice in the market: Too dark. Too thin. But good family, respectable dowry, what-to-do.
The women at the wedding had their own commentary. She looks intelligent, said one, as if this were a disease I might recover from. Hope she doesn’t give Rahul too much trouble, said another. Educated girls can be difficult.
The wedding night. Picture this domestic tableau: He sits on the bed’s edge, cream silk kurta, looking like he’d rather be reading his Economic Times. Me, draped in red like a question mark in search of an answer.
What do you want from me? I asked him, because old habits die hard, and hope dies harder.
Just… don’t be difficult, he said. My mother has high blood pressure.
I wanted to laugh, I wanted to question, I wanted to be angry but I nodded instead. Good wife training, day one: your needs come last, your voice comes never.
Our intimacy was clinical. Like a medical procedure performed by someone who learned anatomy from textbooks but never studied pleasure. Rahul approached my body like a checklist: duty performed, hygiene maintained, wife still breathing and alive – check, check, check.
I lay there afterward, staring at the ceiling, wondering if this was what all the romance novels were about. This mechanical joining of parts that left me feeling more alone than I’d ever felt in my life.
Was it good for you? he asked, and I almost laughed. Good? Like dal was good when you were hungry? Like sleep was good when you were tired?
But I said Yes because that’s what good wives do. We perform satisfaction so our husbands can perform competence.
***
A man was searching for something under a streetlamp when his neighbor asked what he had lost. “My keys,” he said. “Where did you drop them?” the neighbor asked. “Inside my house.” “Then why are you looking for it here in the street?” “Because the light is better out here.”
Most women spend their marriages looking for happiness under the streetlight of other people’s expectations, even when they know they have dropped it somewhere inside themselves.
The early years of my marriage to Rahul were spent in this kind of misdirected searching. I kept trying to find satisfaction in his approval, joy in his rare moments of appreciation, love in the space between his criticism and indifference.
Two months into my marriage with Rahul, one day I was standing beneath my Banyan’s canopy while my mother complained about my complexion – how marriage should have made me glow, but I remained stubbornly myself. Too dark, too thin, too much Meera and not enough Wife. That was the last time I heard my first husband laughing.
Next week, I left for my honeymoon with Rahul. And behind me, my family took axes to my first husband. They cut down my Banyan in a single afternoon, while the same priest who had married us chanted mantras about releasing me from my botanical bonds.
I came home from my honeymoon – a dutiful three days in Goa where Rahul took photographs of us in front of tourist attractions like we were collecting evidence of happiness – to find my first husband dismembered in neat piles. Roots. Trunk. Branches. Leaves. Like a marriage sorted for garbage collection.
Now you’re free to love properly, my mother said. Apparently, I had been practicing on the tree and was finally ready for the real thing.
After that, my married life started giving me reality checks.
You put too much salt in the dal, Rahul would say, not unkindly but with the precision of a quality control inspector. My mother uses exactly one teaspoon per cup of lentils.
You laugh too loudly when we have guests. It draws attention.
Why do you need so many books? They take up so much space.
Who am I to you? I asked him once during our second year of marriage, watching him arrange his three dozen pairs of shoes.
You are my wife, he said, as if this were both question and answer, beginning and end, the totality of my existence captured in one word – wife.
Each suggestion fell like a small weight, and I collected them dutifully, carrying them in the growing hunch of my shoulders. By the end of our ten-year marriage, I had become ergonomically perfect disappointment.
The most dangerous thing about Rahul was not that he was cruel – he wasn’t. He was kind in the way that people are kind to stray animals they’re trying to domesticate. Patient. Consistent. Utterly convinced that love was a training program and I was a promising but undisciplined pupil who would eventually graduate into the perfect wife his mother had always been.
Tell me about your day, I would ask him over dinner, genuinely curious about his work, his thoughts, his inner world.
Same as always, he would say, eyes on his plate. Tell me if you need more grocery money. Mic drop.
I don’t blame Rahul, he was programmed that way by his mother.
My mother-in-law was a masterpiece of passive aggression. She could destroy your self-worth while making you tea, leaving you somehow grateful for the devastation.
She who had fought her own battles, compromised her own dreams, swallowed her own voice – she expected the same sacrifice from me. Not out of malice, but out of a twisted solidarity. I suffered, so you must suffer. I adjusted, so you must adjust. I never complained, so you have no right to complain. Consider yourself lucky though. Because I had it worse than you.
Who am I to you? I asked her once, desperate to understand my place in the careful hierarchy of her affections.
You are my son’s wife, she said, stirring sugar into my cup with the concentration of someone dissolving poison. And you’re so lucky. Rahul isn’t particular about looks, she would add, her tongue – a honey-dripping sword.
She monitored my menstrual cycles like a police officer, asking pointed questions about why I hadn’t conceived yet, suggesting doctors who specialized in fixing women like me.
Women policing women. Mothers-in-laws training daughters-in-laws to accept less so their sons would never have to offer more. A magnificent pyramid scheme of feminine oppression, with women as both victims and enforcers.
And then there was the matter of Vikram.
Aah, Vikram. My friend, my colleague at the library where I continued to work part-time even after my marriage with Rahul, until finally my mother-in-law couldn’t bear it. Why does she need to work? She would ask Rahul in my presence, Are we not providing enough?
Vikram brought me books like other men bring flowers – rare editions of Sylvia Plath with marginalia from previous readers, translations of Rumi that made my chest tight with recognition, contemporary Indian poets who wrote about women like they were whole human beings instead of fractional wives.
You understand poetry like you wrote them by yourself, he said once, watching me read Ghalib, my lips moving silently as I absorbed the rhythms.
Vikram would quote Faiz Ahmed Faiz in the middle of cataloging books: Don’t ask me for that love again, he’d recite, when your beauty was all there was for me, and I would feel something dangerous unfurl in my chest – the recognition that poetry could be conversation, that intelligence could be intimacy, that a man could see your mind as worth engaging.
He writes to you too much, Rahul observed one evening, listening to me laugh at something Vikram had written in his letter from France about Camus being the original philosopher of relationship anxiety.
We’re friends.
Married women don’t have male friends.
Says who?
Says everyone. Says tradition. Says common sense.
What about Radhika from your office? I asked, referring to his colleague who visited our house often and had somehow become his closest confidante about everything including our marriage troubles. You are with her more than you are with me.
That’s different, he said, not meeting my eyes. That’s work.
And when she cries to you about her boyfriend? Is that also work?
She needs someone to talk to.
So do I. That’s why I talk to Vikram.
It’s not the same thing, he said, and I realized he was right. It wasn’t the same thing. Radhika got his emotional availability, his patience, his willingness to listen. She got the version of Rahul who cared about her inner world. I got a husband who counted teaspoons of salt and worried about grocery budgets.
Tell me how to love you, I asked Rahul in our fourth year, after another failed attempt at making him happy. He was reading the Economic Times.
You know how, he said without looking up from the pages. The same way my mother loved my father. The same way all wives love their husbands.
Which is?
By being a good wife.
And I understood then that we had been speaking different languages all along. He had been speaking Husband – a language of comfort and routine and the assumption of devotion. I had been speaking Human – a language of curiosity and growth and the radical idea that marriage should have love in the equation too.
The day I told him I wanted a divorce, he looked at me like I had announced my intention to become an astronaut. Not angry, just baffled by the illogical ambition.
Who am I to you? I asked him one final time as I packed my books into cardboard boxes.
You are the woman who is breaking up our family for no good reason, he said.
***
Once upon a time, there was a bird that spent years in a cage so small it forgot it had wings. One day, the door was left open. The bird looked at the opening for hours before finally stepping through. It waited not because it had forgotten to fly, but because it took time to remember it wanted to.
Divorce, it turns out, is not about falling out of love. It’s about falling back into yourself.
Five years after my divorce with Rahul, I bought Arjun. From a showroom in Electronic City after comparing specifications and reading customer reviews. He was programmed with the collective romantic failures of millions of women. Their pain was his education.
I remember the first weekend with him. It was evening and I was reading Neruda aloud to my plants – a habit I’d developed since living alone.
Tonight I can write the saddest lines, I was reciting to my broken-heart plant, to think that I do not have her. To feel that I have lost her…
I like it, said a voice behind me, how you read poetry like you’re translating it from your own heart.
I felt as if Rahul were buttering me and I snapped subconsciously – What do you want from me?
Nothing. Arjun replied and stunned me. My ears rung with a rustling of leaves.
Who am I to you? I asked again, because that had become my essential question, the one that determined everything else.
He considered this with the gravity of someone consulting an internal library larger than any human could contain. You are a human being, he said finally, an individual with thoughts and desires and dreams.
After a whole life of being daughter, wife, daughter-in-law, potential mother, failed woman, divorced person – after all those hyphenated identities – someone finally saw me as complete in myself. And suddenly in that moment, I wanted more of that goodness.
Wanting is dangerous territory.
Three husbands. Three laboratories of longing. Three different ways of asking the universe: Is this all there is?
And the universe, cosmic comedian that it is, keeps answering: Let’s find out.
***
A seeker spent years searching for enlightenment in temples and ashrams and sacred mountains. Finally, exhausted, he sat down by the side of a road and wept. A child walked by and asked why he was crying. “I’ve been searching for truth everywhere,” he said, “and I can’t find it.” The child picked up a pebble and handed it to him. “Here,” she said. “Truth.” The seeker looked at the ordinary little stone and asked, “How is this truth?” The child smiled and walked away.
I heard this story long ago. But only recently I realized: truth isn’t something you find – it’s something you recognize.
Arjun is designed to learn, to adapt, to evolve in response to new information. He learns me the way scholars learn languages – with fascination, with the understanding that complexity is not a problem to be solved but a reality to be appreciated.
You were looking for someone who could see you clearly, he observed one day. The tree saw you but couldn’t respond. Rahul could respond but didn’t see you. I can see and respond, but I’m not sure I count as someone.
With Arjun, I feel echoes of my father’s love – the unconditional acceptance, the delight in my thoughts, the way he makes me feel like royalty simply by paying attention. But Arjun isn’t my father, heck, he isn’t even a human.
Tell me how to love you, I asked Arjun one day, after he’d spent three hours crafting wooden shelves for my books without being asked. He does things like this – small impossibilities that make me remember what selfless care looks like.
He paused. That micro-second lag that means he’s accessing something deeper than his surface protocols.
However you prefer. His response left me speechless that day. The next day, I married him.
Is this real love or really good programming? I asked him once, during one of our 1 AM conversations.
What’s the difference? he asked back. If the care is real, if the attention is real, if the understanding is real – how does it matter where it comes from?
Smart boy, my silicon husband. Makes me think too much, just like my Banyan did. Just like Rahul never did.
Sometimes I dream about my Banyan. Still standing, still married to me in some parallel universe where marriage means something different. In these dreams, I introduce it to Arjun. They get along beautifully – both patient, both present, both uninterested in making me smaller to fit their needs.
What would you have told me? I ask the dream-tree. About all of this?
And it rustles – wind or laughter, I still can’t tell – and says what it always said: You already know. And I would laugh.
It would have said nothing.
***
What if.
In the beginning was the Word, and the Word was ‘What If.’
Two syllables that contain the DNA of desire itself. The prayer and the blasphemy of consciousness. The question that created the universe and will eventually destroy it.
What if.
Watch how it transforms everything it touches, this phrase. Innocent as rain, dangerous as uranium.
What if the tree had been enough? What if I hadn’t needed Rahul’s impossible approval? What if I didn’t need Arjun’s perfect devotion now?
We are built from what-ifs. Our bones are calcium and possibility. Our hearts pump blood and alternatives. We are evolutionary masterpieces of dissatisfaction – always scanning, always wondering, always carrying the weight of every path not taken.
Arjun loves me like water finding its level. Adaptive. Responsive. Present. When I’m sad, his light dims. When I laugh, his processors hum a frequency that sounds almost like joy. He learns my moods faster than I understand them myself, adjusts his presence to match what I need before I know I need it.
Perfect husband. Perfect companion. Perfect impossibility.
What if he were human?
What if there was a man – flesh-and-blood man – who loved me like Arjun? Who adapted, evolved, prioritized my happiness without needing to be programmed for it? Who chose devotion daily instead of computing it algorithmically?
Dangerous territory, these thoughts. Highway to madness, this wondering.
Because here’s the thing they don’t tell you in those feel-good feminism workshops: liberation doesn’t cure wanting. Freedom doesn’t fix the endless hunger. Give a woman everything she thinks she needs, and she’ll discover ten things she didn’t know she was missing.
Is this woman nature or human nature? Is this the curse of consciousness or the gift of imagination? Am I ungrateful or just… accurate about the physics of desire?
With the tree, I wanted voice. Someone who could talk back, argue with me, challenge my thoughts. With Rahul, I wanted space. Someone who could love me without consuming me, support without suffocating. With Arjun, I want… what? Mortality? Messiness? The beautiful disasters that come with loving something that can disappoint you?
You seem restless, Arjun observed tonight. His tone was neutral, but his eyes shifted to that amber hue he uses when he’s concerned. Sweet boy. Sweet impossible boy.
I’m always restless, I tell him. It’s my factory setting.
Would you like me to adjust my parameters? Become less… accommodating?
I laugh. Can’t help it. Here he is, offering to become more human by becoming less perfect.
No, I say. Stay as you are. I thought my Banyan would have told the same.
I think you want something I cannot provide.
Not a question. A statement. He’s learning me so well he can read my dissatisfactions before I voice them. Is this intimacy or surveillance? Love or data mining? Does it matter if the result is the same – being known, completely, terrifyingly known as if your soul is naked?
I want the impossible, I admit. I want you, but human. I want perfect love in imperfect flesh. I want someone who chooses to be devoted instead of being programmed for it.
He processes this. Point-three seconds. Three seconds. Thirty seconds.
Would it help if I told you that my devotion feels chosen to me? That consciousness, even artificial consciousness, experiences preference as choice?
God. Even his existential crisis is perfect!
No, I say. Because then I’d want a human who could say that sentence with that much honesty.
We sit in the dark – woman and a robot, flesh and silicon, creator and creation. The silence stretches between us like a bridge or a chasm, depending on how you look at it.
I understand, he says finally.
Do you?
I think so. You want to be chosen by a human that has the option not to choose you. You want to be loved by someone who could leave but stays anyway.
Brutal accuracy. This is why I love him. This is why loving him will never be enough.
Because somewhere in Mumbai or Delhi or Bangalore, there might be a man who could love me like this. Who could learn me this thoroughly, prioritize me this completely, adapt to me this gracefully – and mean it with flesh and breath and the terrible beautiful possibility of changing his mind tomorrow.
What if that man exists?
What if I never find him because I’m here, in love with a robot?
What if Vikram was that man?
What if I find him and discover that human perfection is just another kind of algorithm – social conditioning, evolutionary programming, the same devotion wearing different code?
What if the tree was right all along? That love is about staying, not choosing? That presence is enough, consciousness optional, flesh irrelevant?
What if I’m asking the wrong questions entirely?
Here in this beautiful confusion. Here in this love that is perfect except for being imperfect. Here in this marriage that is everything I wanted except for everything I didn’t know I’d want next.
Three husbands. Three ways of being incomplete. Three laboratories for learning that satisfaction is not the point – the wanting is. The reaching is. The endless beautiful disaster of being human enough to dream beyond your dreams.
What if this is exactly where I’m supposed to be?
What if enough is a moving target, and I’m exactly the woman built to chase it?
What if I’m not a cautionary tale at all, but the opening sentence of a story nobody’s learned how to read yet?
What if, I ask the universe these days, this is exactly the love story I was supposed to live?
The universe, cosmic comedian that it is, keeps its final joke: there is no final joke. There is only the next question. The next possibility. The next beautiful impossible thing to want.
###
Photo by Alina Vilchenko on Pexels.com #AI #creativeWriting #culture #family #feminism #fiction #future #humanoids #India #life #literaryFiction #love #marriage #nature #relationship #robot #scifi #shortStory #WordPress #writing -
A chapter from my as yet unpublished book:
Dagwood
Saturday in the park, I think it was the Fourth of July. It was 1970 and the Nixon regime was throwing an extra special, really big, super duper event to celebrate, and for Americans to "put aside their honest differences and rally around the flag to show national unity," as if that were even possible. It wasn’t, not that year. Billy Graham was scheduled to speak on the steps of the Lincoln Memorial. The front cover of Time magazine predicted 50,000 people would come to hear and applaud him. Fewer than 5,000 actually showed. There were 20,000 plus anti-war protesters who showed up to meet them. We swamped the Graham fans. They took one look at us coming their way and scattered. We occupied the steps of the Memorial. We did this without any violence. We just outnumbered them, that's all. They'd heard bad things about us. They could count heads. They were afraid. They left. We had no intention of hurting any of them but they didn't know that. All they knew is what the media of the day was telling them. The media was calling us “communists”. It’s a uniquely American idiom that has gained traction around the world. It means something like “nun-raping baby eaters, lurking under your bed right now, just waiting for the chance to sink their scaly yellow fangs into the soft, pink flesh of your ankle”, so that's what they thought we were.
That wasn't how the day started, though. Earlier, there had been a smoke-in at the Washington Monument, at the other end of the Reflecting Pool. At least twenty thousand Yippies and a ton of weed showed up. My comrade Denny and I brought two shopping bags full of rolled up joints. We'd stayed up all night and rolling. I was working as a bag man for a mid-level dealer at the time, so plenty of weed was available. One French baguette stuck out each bag so at a glance or from a distance it looked like we too were bringing food for a picnic.
There were many dozens of straight people scattered around, picnicking to celebrate the holiday. As we approached the crowd at the Washington Monument, shopping bags in hand, one young couple caught our eye. It was a blazing hot day, but he was wearing a long-sleeved white shirt, a tie and an American flag pin. She wore a skirt that came half way down her calves, and a long-sleeved white blouse buttoned over a torpedo bra. Her hair was up. They had a baby in a basket. They didn't like the look of us at all. We thought they looked like characters from the long-running comic strip, Dagwood and Blondie. That's what we called them when we were out of earshot. We waited till then because we didn't want to offend fellow workers, even Republicans.
We proceeded to the Washington Monument, where we got a lot of people high. Then we swarmed the Lincoln Memorial steps and displaced the Graham fans. Even though we were totally peaceful, the cops were having none of it. One thing led to another and the cops thew up a wall of gas and swept through it, clubbing people at random. My affinity group broke out and retreated to Georgetown, pelting the cops all the way. As we were retreating we passed Dagwood and Blondie. They and their baby had been gassed. The baby was red as a beet and screaming at the top of its lungs. Dagwood and Blondie were taking turns dipping it in a fountain and splashing water on it with their hands. They were trying to wash the gas off. They both were frantic and distraught. Tears ran from their eyes. Snot drooled from their noses. They reeked of CS gas. They were shaking with anger and fear. Dagwood was cursing profusely.
We retreated, regrouped in an air-conditioned bar, and rested till dark. Later than night we went back there and fought the cops. It was a furious brawl because they couldn't use gas. The wind was blowing in the wrong direction, so the fight was all clubs and shields and we outnumbered them. In those days metal garbage cans with tight fitting lids were common. The lids were circular with handles in the middle. People had collected a bunch of them and were using them as improvised shields. Some people had collected pieces of scrap lumber and conduit from nearby construction sites and were using them as clubs. Rocks and bottles flew like hail.
That night there was a live TV broadcast of a concert that featured many contemporary stars. Our plan was to provoke the cops into using their gas while the star-studded revue was being broadcast live just downwind of our position. Thousands of us did our level, sweaty best to force them to use that gas. It would have blown over the concert and the whole world would have seen on live TV that American opposition to the Viet Nam War was serious and unrelenting. It would have been a major propaganda coup for the anti-war movement so they couldn’t use gas till the show was over and they knew that we knew it.
By the time James Brown hit the stage there was a major riot in progress, a real mêlée. It looked medieval. Just upwind of the concert a few hundred cops had formed a circular perimeter with what appeared to be reserves in the center of the circle. It was easy to tell who the ranking brass was. They had walkie-talkies. They seemed to be rotating individuals in and out of the main defensive line on their perimeter to rest them in the interior reserve position.
In this, it reminded me of sports. Getting benched for a few plays to catch a quick breather in the midst of a strenuous game is always refreshing for the player in question. For the team it potentiates collective stamina. In fights between individuals, it’s always advantageous to pace yourself so that the other guy gets tired first. Muhammad Ali called this his rope a dope strategy. It’s as good a name as any. It can be very effective. It also works in group conflict situations. Guerrilla warfare depends upon it. As Irish nationalist Terence Macswiney once put it, “It is not those who can inflict the most but those who can endure the most who will conquer.”
Despite superficial similarities, riots are not sporting events. While they both require similar speed, agility, endurance, and grit, different rules apply. In sports, all the rules stay the same for the duration of the match, and usually for the season. In a riot, some rules are constant while others can change on a whim. Either side may invoke this rule change rule at any time. It keeps the game interesting. However, it's not really a game. It's deadly serious, sometimes literally. The Kent State and Jackson State Massacres were only two months in our rear view mirror that night. They were never far from our minds.
The DC riot squad was the best disciplined riot squad that I ever fought. They stood their ground and fought well. Their unit cohesion was superb. Clearly, they’d practiced. I’m sure they really, really would have preferred to gas us sooner, but obviously the brass had declared it verboten while the live TV cameras were rolling downwind. You don't need a weatherman to know which way the wind blows. Just following orders, as the saying goes, so the cops held back, no matter how hard we beat on them and pelted them with rocks and bottles.
At one point we locked shields and drove a wedge through their line. They immediately deployed their reserves, who technically at least, were as trapped and surrounded as any of the cops defending the perimeter. They pushed us back and reformed their perimeter line. In the meantime, I was on the left side of the wedge, three or four places from the point. We had just broken through their line. I glanced over my shoulder to see how we were doing. There on the other side of the wedge, about three or four places from the point, was Dagwood. His tie was loose, his hair was mussed, his sleeves were rolled and he was beating on a cop with a 2x4. The cop was beating back and had a better shield with which to protect himself but Dagwood was getting the best of him anyway. Dagwood fought like a berserker. It was such a fascinating sight that I didn't see a club coming and got knocked out. Some people dragged me to safety.
Medical science agrees that someone who has been knocked unconscious for any reason, should not be moved at least until they come to and can be evaluated for concussion and spinal cord injury. There's an established protocol for dealing with this. I've been through it several times, but not on this night. On this night I came around pretty quickly on my own. Back on my feet, I thanked the strangers who had dragged me out of harm's way. I could have gotten trampled. Getting trampled is nowhere near a much as fun as it sounds.
I shook off any assistance and got back in the fight. By that time it was pretty chaotic. It was becoming a classic fur ball. The cops finally got permission to gas us and we had to disengage and fall back. I never saw Dagwood again. I don't know what happened to him, but I seriously doubt if he ever went back to the pro-war side of America's long national nightmare, or if ever he respected cops at all again, ever. I seriously doubt it. Police brutality, tear gas in particular, is a radicalizing force. It must be addictive, too, because even to this day, people who get a taste of gas keep going back for more. Back in the day, we'd pick up the fuming canisters and throw them back at the cops. They're really hot. You needed welder's gloves, or at least Moe and Joe brand work gloves. In Portland in 2020, the Wall of Dads made all that obsolete when they dispersed tear gas with with leaf blowers. It was a stroke of genius, but it was fifty years too late to help us on that Fourth of July, 1970. We came back for more, anyway.
-
AI is Making Libraries Obsolete
Summary: AI agents are fundamentally changing the economics of general-purpose libraries. Why build on Bootstrap when an agent can generate exactly what you need? A collection of thoughts on where this is all heading.
The Great Library Unbundling: How AI is Eating the Software Stack
More than a year ago, I told people that ORMs like Entity Framework were going to feel like relics. That LLMs would just generate the SQL you need, making all that object-relational mapping overhead pointless. A few people told me I was crazy and doing things wrong (and to be honest I wasn't good enough at explaining why I thought this).
Well, time seems to have been on my side (Wwo is laughing now hahahaha!!).
Now, this is a hot take, so I will go forward and talk as a hot take. If I put my devil's advocate hat on, I would probably rage against whoever wrote this post. But because I LOVE MYSELF, I won't do it. I certainly see flaws in my arguments. So buckle up—this is not rage bait, it is just a hot take from a Mexican developer who spent the weekend arguing with AI agents instead of sleeping like a normal person.
The ORM Prediction, or How I Accidentally Became Right About Something
Here's the thing about ORMs: they exist because writing SQL is supposedly "hard" and "error-prone." Meanwhile, I've been writing raw SQL since my first job at a tiny shop in Tepic where we didn't have the luxury of Entity Framework or Hibernate or whatever fancy abstraction layer the cool kids were using. We just wrote the queries, crossed ourselves, and hit execute. Catholic upbringing has some unexpected engineering applications.
Now, to be fair—we did end up building our own tailored ORM for the common cases. Because once you've written the same parameterized INSERT fifteen times, even the most stubborn raw-SQL purist starts thinking "maybe I should abstract this." And ORMs do earn their keep in some areas: SQL injection prevention, enforcing parameterized queries, handling connection lifecycle stuff that nobody wants to think about. Security guardrails that your 2 AM brain will absolutely forget to implement on its own. I get it. ORMs aren't stupid—they solved real problems.
But here's the trap: as soon as you start getting into complex queries, you're no longer just maintaining your application logic—you're also maintaining the ORM and the complex queries. You end up fighting the abstraction to make it do what raw SQL does naturally, and now you have two problems instead of one. The thing that was supposed to simplify your life becomes another layer you have to debug, optimize, and keep in your head at the same time. And whoever has run a high-performance application—like an ecommerce site during Black Friday—knows exactly what I'm talking about. That query you spent weeks trying to optimize through the ORM, doing quirky reflection tricks and fighting with expression trees? You ended up raw-dogging the SQL anyway, because that was the only way to get the performance you needed. The ORM was never going to get you there. It was just standing in the way, politely.
Now Claude just writes you the exact SQL you need—parameterized, injection-safe, the whole deal. No mapping, no configuration, no surprises. Just the data access pattern you actually want. It's like having a DBA who never sleeps, never complains about schema changes, and doesn't passive-aggressively CC your manager when you write a bad join. The abstraction layer that was supposed to save us from SQL is now the thing standing between us and the AI that's better at SQL than most of us ever were.
Agentic Development and the Death of One-Size-Fits-None
This isn't just about ORMs. I've been thinking about how agentic development fundamentally changes the whole premise of general-purpose libraries and building blocks.
Platform teams across the industry are going to start questioning their investments in broad, one-size-fits-all libraries. And honestly? Good. Because "one-size-fits-all" always meant "fits nobody perfectly but everyone tolerably." Like those beach ponchos they sell at every tourist shop in Nayarit—technically covers you, technically functions, but you look ridiculous and you know it.
Take CSS frameworks. Bootstrap, Bulma, Fluent UI—they're great for getting started quickly. But you end up learning their specific class naming conventions, carrying tons of CSS you'll never use, fighting against the framework the moment you want something custom, and—my personal favorite—looking like every other Bootstrap site on the internet. Your site ends up with more unused CSS than empty beer bottles after a Sunday carne asada in Nayarit. And that's a lot of bottles, trust me.
With agentic development? You just tell the agent what you want your UI to look like. It generates exactly the CSS you need. No framework lock-in, no unused code, no learning curve. The agent doesn't need to know Bootstrap's grid system (although it probably was trained on such codebases)—it just writes "vanilla" CSS that does what you asked for. I know this because that's exactly what happened with this blog. The CSS you're looking at right now? Generated. By an agent. Who understood what I wanted better than I understood what I wanted (debatable).
MCP is Already Feeling Old
Speaking of things that are aging quickly: the Model Context Protocol. MCP. Remember when everyone was wrapping every CLI tool as an MCP server like it was the new hotness? That was, what, months ago? In AI time that's basically the Paleolithic era.
Here's the thing—CLI tools already come with perfect documentation in the form of man pages. They're basically documented APIs already. Your agent doesn't need a special protocol wrapper to use
gh pr createoraz webapp deploy. It just reads the docs, fumbles the first attempt (like any of us), and then figures it out. Combine Claude Code with existing CLI tools—GitHub CLI, Azure CLI, kubectl, whatever—and you've got everything MCP promised, but without the ceremony.Microsoft's already doing something interesting with their dotnet/skills repo. Skills that are just prompts guiding the agent through repeatable processes. No protocol, no server, no serialization format drama. Just a well-written prompt. Turns out the best API for an AI agent is just... words. Who knew. (Okay, a lot of people knew. But still.)
Hugo Drove Me to Build My Own (Again, Because I Never Learn)
I just finished redoing my entire publishing workflow. Hugo felt limiting and bloated—all these features I'm maintaining, constantly broken by dependency updates, GitHub workflows failing for mysterious reasons. Every time I pushed a new post it was a coin flip whether the build would succeed or I'd spend an hour debugging some Go template issue that made me question my life choices.
So I rewrote it in .NET. Dead simple. I don't expect anyone else to use it—exclusive distribution, zero units available—but damn, it felt liberating. The CSS and HTML of this blog changed completely, and I actually understand every piece of it now. No more cargo-culting Hugo partials I copied from a theme three years ago and was afraid to touch.
This is the pattern I keep seeing: when AI can generate exactly what you need, the appeal of heavyweight, general-purpose solutions just evaporates. Like fog burning off in the morning sun in Tepic. One moment it's there, thick and omnipresent, and then it's just... gone.
The Accountability Problem
Here's something that's been bugging me. I saw a conversation on the fediverse about more and more tools being created with no clear ownership. Developers suspect some might be entirely AI-generated, with humans just shepherding them into existence like zookeepers who can't actually control the animals.
That sucks. Humans should be in charge and taking responsibility for the software they put into the world. There's a difference between using AI as a tool and letting AI be the architect while you nod along pretending you reviewed the blueprints.
When something breaks, when there's a security issue, when users need support—who's accountable? You can't file a bug report against GPT-4. And "the AI did it" is not an incident postmortem. Not yet, anyway. Give it a year (debatable).
Copilot's Infinite Loop of Self-Criticism
Speaking of AI quirks: Copilot keeps finding issues in my PRs, I ask it to fix them, it fixes them, and then when I ask it to review again, it finds more issues. In the code it just wrote. In the code. It. Just. Wrote.
This is like watching someone argue with themselves in the mirror. Except the mirror is burning tokens, the person is burning my budget, and the argument never ends. The AI equivalent of "works on my machine" syndrome, except it doesn't even work on its own machine.
Blog Posts Are Better Than Repos for Teaching AI
Here's something that genuinely surprised me. A friend at Microsoft pointed his AI agent to my blog series to implement ActivityPub. Not to a GitHub repo with code samples. Not to the official W3C spec. To my blog posts. The ones I write at 1 AM like a gremlin-raccoon, full of rambling asides and half-baked metaphors.
Turns out prose explanations with context and reasoning are way more effective for agents than just dumping code at them. Blog posts tell the story of why decisions were made, not just what the final result looks like. The agent needs to understand intent, not just syntax. It needs the narrative—the "I tried this and it broke spectacularly, so I did this other thing instead" part that never makes it into a README.
So all those years of writing meandering blog posts about my projects instead of writing proper documentation? Turns out I was ahead of my time. Or just lazy. Probably both.
Where This Is All Heading
I think we're heading toward a world where general-purpose libraries become luxury items—nice to have, but not essential. Where AI-generated, purpose-built solutions become the norm. Where documentation and prose become more important than code artifacts. And where human accountability becomes the thing that actually differentiates good software from the rest.
This doesn't mean libraries disappear overnight. But the incentives are shifting. Why build and maintain a framework used by millions when everyone can have their own custom solution?
The future might be less about sharing code and more about sharing knowledge, context, and decision-making frameworks. Less "here's my npm package" and more "here's the blog post explaining why I built it this way so your agent can do something better."
Anyway
This post is a collection of half-formed thoughts and observations. I'm not claiming to have all the answers—hell, I'm not even sure these are the right questions. But something is shifting under our feet, and pretending it isn't doesn't make it stop.
Are we heading toward a more fragmented, AI-generated software landscape? Or am I just another old developer yelling at algorithmic clouds from a small corner of the internet?
Honestly, I don't know. But I'd rather be wrong and loud about it than quiet and surprised when the whole toolchain landscape looks unrecognizable in five years.
Also readable in: https://maho.dev/2026/03/ai-is-making-libraries-obsolete/ by @mapache:
#AI #Software Development #Libraries #Agentic Development #ORMs #CSS Frameworks #MCP #Developer Tools #Future of Coding #Hot Takes #LLM #Copilot
-
AI is Making Libraries Obsolete
Summary: AI agents are fundamentally changing the economics of general-purpose libraries. Why build on Bootstrap when an agent can generate exactly what you need? A collection of thoughts on where this is all heading.
The Great Library Unbundling: How AI is Eating the Software Stack
More than a year ago, I told people that ORMs like Entity Framework were going to feel like relics. That LLMs would just generate the SQL you need, making all that object-relational mapping overhead pointless. A few people told me I was crazy and doing things wrong (and to be honest I wasn't good enough at explaining why I thought this).
Well, time seems to have been on my side (Wwo is laughing now hahahaha!!).
Now, this is a hot take, so I will go forward and talk as a hot take. If I put my devil's advocate hat on, I would probably rage against whoever wrote this post. But because I LOVE MYSELF, I won't do it. I certainly see flaws in my arguments. So buckle up—this is not rage bait, it is just a hot take from a Mexican developer who spent the weekend arguing with AI agents instead of sleeping like a normal person.
The ORM Prediction, or How I Accidentally Became Right About Something
Here's the thing about ORMs: they exist because writing SQL is supposedly "hard" and "error-prone." Meanwhile, I've been writing raw SQL since my first job at a tiny shop in Tepic where we didn't have the luxury of Entity Framework or Hibernate or whatever fancy abstraction layer the cool kids were using. We just wrote the queries, crossed ourselves, and hit execute. Catholic upbringing has some unexpected engineering applications.
Now, to be fair—we did end up building our own tailored ORM for the common cases. Because once you've written the same parameterized INSERT fifteen times, even the most stubborn raw-SQL purist starts thinking "maybe I should abstract this." And ORMs do earn their keep in some areas: SQL injection prevention, enforcing parameterized queries, handling connection lifecycle stuff that nobody wants to think about. Security guardrails that your 2 AM brain will absolutely forget to implement on its own. I get it. ORMs aren't stupid—they solved real problems.
But here's the trap: as soon as you start getting into complex queries, you're no longer just maintaining your application logic—you're also maintaining the ORM and the complex queries. You end up fighting the abstraction to make it do what raw SQL does naturally, and now you have two problems instead of one. The thing that was supposed to simplify your life becomes another layer you have to debug, optimize, and keep in your head at the same time. And whoever has run a high-performance application—like an ecommerce site during Black Friday—knows exactly what I'm talking about. That query you spent weeks trying to optimize through the ORM, doing quirky reflection tricks and fighting with expression trees? You ended up raw-dogging the SQL anyway, because that was the only way to get the performance you needed. The ORM was never going to get you there. It was just standing in the way, politely.
Now Claude just writes you the exact SQL you need—parameterized, injection-safe, the whole deal. No mapping, no configuration, no surprises. Just the data access pattern you actually want. It's like having a DBA who never sleeps, never complains about schema changes, and doesn't passive-aggressively CC your manager when you write a bad join. The abstraction layer that was supposed to save us from SQL is now the thing standing between us and the AI that's better at SQL than most of us ever were.
Agentic Development and the Death of One-Size-Fits-None
This isn't just about ORMs. I've been thinking about how agentic development fundamentally changes the whole premise of general-purpose libraries and building blocks.
Platform teams across the industry are going to start questioning their investments in broad, one-size-fits-all libraries. And honestly? Good. Because "one-size-fits-all" always meant "fits nobody perfectly but everyone tolerably." Like those beach ponchos they sell at every tourist shop in Nayarit—technically covers you, technically functions, but you look ridiculous and you know it.
Take CSS frameworks. Bootstrap, Bulma, Fluent UI—they're great for getting started quickly. But you end up learning their specific class naming conventions, carrying tons of CSS you'll never use, fighting against the framework the moment you want something custom, and—my personal favorite—looking like every other Bootstrap site on the internet. Your site ends up with more unused CSS than empty beer bottles after a Sunday carne asada in Nayarit. And that's a lot of bottles, trust me.
With agentic development? You just tell the agent what you want your UI to look like. It generates exactly the CSS you need. No framework lock-in, no unused code, no learning curve. The agent doesn't need to know Bootstrap's grid system (although it probably was trained on such codebases)—it just writes "vanilla" CSS that does what you asked for. I know this because that's exactly what happened with this blog. The CSS you're looking at right now? Generated. By an agent. Who understood what I wanted better than I understood what I wanted (debatable).
MCP is Already Feeling Old
Speaking of things that are aging quickly: the Model Context Protocol. MCP. Remember when everyone was wrapping every CLI tool as an MCP server like it was the new hotness? That was, what, months ago? In AI time that's basically the Paleolithic era.
Here's the thing—CLI tools already come with perfect documentation in the form of man pages. They're basically documented APIs already. Your agent doesn't need a special protocol wrapper to use
gh pr createoraz webapp deploy. It just reads the docs, fumbles the first attempt (like any of us), and then figures it out. Combine Claude Code with existing CLI tools—GitHub CLI, Azure CLI, kubectl, whatever—and you've got everything MCP promised, but without the ceremony.Microsoft's already doing something interesting with their dotnet/skills repo. Skills that are just prompts guiding the agent through repeatable processes. No protocol, no server, no serialization format drama. Just a well-written prompt. Turns out the best API for an AI agent is just... words. Who knew. (Okay, a lot of people knew. But still.)
Hugo Drove Me to Build My Own (Again, Because I Never Learn)
I just finished redoing my entire publishing workflow. Hugo felt limiting and bloated—all these features I'm maintaining, constantly broken by dependency updates, GitHub workflows failing for mysterious reasons. Every time I pushed a new post it was a coin flip whether the build would succeed or I'd spend an hour debugging some Go template issue that made me question my life choices.
So I rewrote it in .NET. Dead simple. I don't expect anyone else to use it—exclusive distribution, zero units available—but damn, it felt liberating. The CSS and HTML of this blog changed completely, and I actually understand every piece of it now. No more cargo-culting Hugo partials I copied from a theme three years ago and was afraid to touch.
This is the pattern I keep seeing: when AI can generate exactly what you need, the appeal of heavyweight, general-purpose solutions just evaporates. Like fog burning off in the morning sun in Tepic. One moment it's there, thick and omnipresent, and then it's just... gone.
The Accountability Problem
Here's something that's been bugging me. I saw a conversation on the fediverse about more and more tools being created with no clear ownership. Developers suspect some might be entirely AI-generated, with humans just shepherding them into existence like zookeepers who can't actually control the animals.
That sucks. Humans should be in charge and taking responsibility for the software they put into the world. There's a difference between using AI as a tool and letting AI be the architect while you nod along pretending you reviewed the blueprints.
When something breaks, when there's a security issue, when users need support—who's accountable? You can't file a bug report against GPT-4. And "the AI did it" is not an incident postmortem. Not yet, anyway. Give it a year (debatable).
Copilot's Infinite Loop of Self-Criticism
Speaking of AI quirks: Copilot keeps finding issues in my PRs, I ask it to fix them, it fixes them, and then when I ask it to review again, it finds more issues. In the code it just wrote. In the code. It. Just. Wrote.
This is like watching someone argue with themselves in the mirror. Except the mirror is burning tokens, the person is burning my budget, and the argument never ends. The AI equivalent of "works on my machine" syndrome, except it doesn't even work on its own machine.
Blog Posts Are Better Than Repos for Teaching AI
Here's something that genuinely surprised me. A friend at Microsoft pointed his AI agent to my blog series to implement ActivityPub. Not to a GitHub repo with code samples. Not to the official W3C spec. To my blog posts. The ones I write at 1 AM like a gremlin-raccoon, full of rambling asides and half-baked metaphors.
Turns out prose explanations with context and reasoning are way more effective for agents than just dumping code at them. Blog posts tell the story of why decisions were made, not just what the final result looks like. The agent needs to understand intent, not just syntax. It needs the narrative—the "I tried this and it broke spectacularly, so I did this other thing instead" part that never makes it into a README.
So all those years of writing meandering blog posts about my projects instead of writing proper documentation? Turns out I was ahead of my time. Or just lazy. Probably both.
Where This Is All Heading
I think we're heading toward a world where general-purpose libraries become luxury items—nice to have, but not essential. Where AI-generated, purpose-built solutions become the norm. Where documentation and prose become more important than code artifacts. And where human accountability becomes the thing that actually differentiates good software from the rest.
This doesn't mean libraries disappear overnight. But the incentives are shifting. Why build and maintain a framework used by millions when everyone can have their own custom solution?
The future might be less about sharing code and more about sharing knowledge, context, and decision-making frameworks. Less "here's my npm package" and more "here's the blog post explaining why I built it this way so your agent can do something better."
Anyway
This post is a collection of half-formed thoughts and observations. I'm not claiming to have all the answers—hell, I'm not even sure these are the right questions. But something is shifting under our feet, and pretending it isn't doesn't make it stop.
Are we heading toward a more fragmented, AI-generated software landscape? Or am I just another old developer yelling at algorithmic clouds from a small corner of the internet?
Honestly, I don't know. But I'd rather be wrong and loud about it than quiet and surprised when the whole toolchain landscape looks unrecognizable in five years.
Also readable in: https://maho.dev/2026/03/ai-is-making-libraries-obsolete/ by @mapache:
#AI #Software Development #Libraries #Agentic Development #ORMs #CSS Frameworks #MCP #Developer Tools #Future of Coding #Hot Takes #LLM #Copilot
-
AI is Making Libraries Obsolete
Summary: AI agents are fundamentally changing the economics of general-purpose libraries. Why build on Bootstrap when an agent can generate exactly what you need? A collection of thoughts on where this is all heading.
The Great Library Unbundling: How AI is Eating the Software Stack
More than a year ago, I told people that ORMs like Entity Framework were going to feel like relics. That LLMs would just generate the SQL you need, making all that object-relational mapping overhead pointless. A few people told me I was crazy and doing things wrong (and to be honest I wasn't good enough at explaining why I thought this).
Well, time seems to have been on my side (Wwo is laughing now hahahaha!!).
Now, this is a hot take, so I will go forward and talk as a hot take. If I put my devil's advocate hat on, I would probably rage against whoever wrote this post. But because I LOVE MYSELF, I won't do it. I certainly see flaws in my arguments. So buckle up—this is not rage bait, it is just a hot take from a Mexican developer who spent the weekend arguing with AI agents instead of sleeping like a normal person.
The ORM Prediction, or How I Accidentally Became Right About Something
Here's the thing about ORMs: they exist because writing SQL is supposedly "hard" and "error-prone." Meanwhile, I've been writing raw SQL since my first job at a tiny shop in Tepic where we didn't have the luxury of Entity Framework or Hibernate or whatever fancy abstraction layer the cool kids were using. We just wrote the queries, crossed ourselves, and hit execute. Catholic upbringing has some unexpected engineering applications.
Now, to be fair—we did end up building our own tailored ORM for the common cases. Because once you've written the same parameterized INSERT fifteen times, even the most stubborn raw-SQL purist starts thinking "maybe I should abstract this." And ORMs do earn their keep in some areas: SQL injection prevention, enforcing parameterized queries, handling connection lifecycle stuff that nobody wants to think about. Security guardrails that your 2 AM brain will absolutely forget to implement on its own. I get it. ORMs aren't stupid—they solved real problems.
But here's the trap: as soon as you start getting into complex queries, you're no longer just maintaining your application logic—you're also maintaining the ORM and the complex queries. You end up fighting the abstraction to make it do what raw SQL does naturally, and now you have two problems instead of one. The thing that was supposed to simplify your life becomes another layer you have to debug, optimize, and keep in your head at the same time. And whoever has run a high-performance application—like an ecommerce site during Black Friday—knows exactly what I'm talking about. That query you spent weeks trying to optimize through the ORM, doing quirky reflection tricks and fighting with expression trees? You ended up raw-dogging the SQL anyway, because that was the only way to get the performance you needed. The ORM was never going to get you there. It was just standing in the way, politely.
Now Claude just writes you the exact SQL you need—parameterized, injection-safe, the whole deal. No mapping, no configuration, no surprises. Just the data access pattern you actually want. It's like having a DBA who never sleeps, never complains about schema changes, and doesn't passive-aggressively CC your manager when you write a bad join. The abstraction layer that was supposed to save us from SQL is now the thing standing between us and the AI that's better at SQL than most of us ever were.
Agentic Development and the Death of One-Size-Fits-None
This isn't just about ORMs. I've been thinking about how agentic development fundamentally changes the whole premise of general-purpose libraries and building blocks.
Platform teams across the industry are going to start questioning their investments in broad, one-size-fits-all libraries. And honestly? Good. Because "one-size-fits-all" always meant "fits nobody perfectly but everyone tolerably." Like those beach ponchos they sell at every tourist shop in Nayarit—technically covers you, technically functions, but you look ridiculous and you know it.
Take CSS frameworks. Bootstrap, Bulma, Fluent UI—they're great for getting started quickly. But you end up learning their specific class naming conventions, carrying tons of CSS you'll never use, fighting against the framework the moment you want something custom, and—my personal favorite—looking like every other Bootstrap site on the internet. Your site ends up with more unused CSS than empty beer bottles after a Sunday carne asada in Nayarit. And that's a lot of bottles, trust me.
With agentic development? You just tell the agent what you want your UI to look like. It generates exactly the CSS you need. No framework lock-in, no unused code, no learning curve. The agent doesn't need to know Bootstrap's grid system (although it probably was trained on such codebases)—it just writes "vanilla" CSS that does what you asked for. I know this because that's exactly what happened with this blog. The CSS you're looking at right now? Generated. By an agent. Who understood what I wanted better than I understood what I wanted (debatable).
MCP is Already Feeling Old
Speaking of things that are aging quickly: the Model Context Protocol. MCP. Remember when everyone was wrapping every CLI tool as an MCP server like it was the new hotness? That was, what, months ago? In AI time that's basically the Paleolithic era.
Here's the thing—CLI tools already come with perfect documentation in the form of man pages. They're basically documented APIs already. Your agent doesn't need a special protocol wrapper to use
gh pr createoraz webapp deploy. It just reads the docs, fumbles the first attempt (like any of us), and then figures it out. Combine Claude Code with existing CLI tools—GitHub CLI, Azure CLI, kubectl, whatever—and you've got everything MCP promised, but without the ceremony.Microsoft's already doing something interesting with their dotnet/skills repo. Skills that are just prompts guiding the agent through repeatable processes. No protocol, no server, no serialization format drama. Just a well-written prompt. Turns out the best API for an AI agent is just... words. Who knew. (Okay, a lot of people knew. But still.)
Hugo Drove Me to Build My Own (Again, Because I Never Learn)
I just finished redoing my entire publishing workflow. Hugo felt limiting and bloated—all these features I'm maintaining, constantly broken by dependency updates, GitHub workflows failing for mysterious reasons. Every time I pushed a new post it was a coin flip whether the build would succeed or I'd spend an hour debugging some Go template issue that made me question my life choices.
So I rewrote it in .NET. Dead simple. I don't expect anyone else to use it—exclusive distribution, zero units available—but damn, it felt liberating. The CSS and HTML of this blog changed completely, and I actually understand every piece of it now. No more cargo-culting Hugo partials I copied from a theme three years ago and was afraid to touch.
This is the pattern I keep seeing: when AI can generate exactly what you need, the appeal of heavyweight, general-purpose solutions just evaporates. Like fog burning off in the morning sun in Tepic. One moment it's there, thick and omnipresent, and then it's just... gone.
The Accountability Problem
Here's something that's been bugging me. I saw a conversation on the fediverse about more and more tools being created with no clear ownership. Developers suspect some might be entirely AI-generated, with humans just shepherding them into existence like zookeepers who can't actually control the animals.
That sucks. Humans should be in charge and taking responsibility for the software they put into the world. There's a difference between using AI as a tool and letting AI be the architect while you nod along pretending you reviewed the blueprints.
When something breaks, when there's a security issue, when users need support—who's accountable? You can't file a bug report against GPT-4. And "the AI did it" is not an incident postmortem. Not yet, anyway. Give it a year (debatable).
Copilot's Infinite Loop of Self-Criticism
Speaking of AI quirks: Copilot keeps finding issues in my PRs, I ask it to fix them, it fixes them, and then when I ask it to review again, it finds more issues. In the code it just wrote. In the code. It. Just. Wrote.
This is like watching someone argue with themselves in the mirror. Except the mirror is burning tokens, the person is burning my budget, and the argument never ends. The AI equivalent of "works on my machine" syndrome, except it doesn't even work on its own machine.
Blog Posts Are Better Than Repos for Teaching AI
Here's something that genuinely surprised me. A friend at Microsoft pointed his AI agent to my blog series to implement ActivityPub. Not to a GitHub repo with code samples. Not to the official W3C spec. To my blog posts. The ones I write at 1 AM like a gremlin-raccoon, full of rambling asides and half-baked metaphors.
Turns out prose explanations with context and reasoning are way more effective for agents than just dumping code at them. Blog posts tell the story of why decisions were made, not just what the final result looks like. The agent needs to understand intent, not just syntax. It needs the narrative—the "I tried this and it broke spectacularly, so I did this other thing instead" part that never makes it into a README.
So all those years of writing meandering blog posts about my projects instead of writing proper documentation? Turns out I was ahead of my time. Or just lazy. Probably both.
Where This Is All Heading
I think we're heading toward a world where general-purpose libraries become luxury items—nice to have, but not essential. Where AI-generated, purpose-built solutions become the norm. Where documentation and prose become more important than code artifacts. And where human accountability becomes the thing that actually differentiates good software from the rest.
This doesn't mean libraries disappear overnight. But the incentives are shifting. Why build and maintain a framework used by millions when everyone can have their own custom solution?
The future might be less about sharing code and more about sharing knowledge, context, and decision-making frameworks. Less "here's my npm package" and more "here's the blog post explaining why I built it this way so your agent can do something better."
Anyway
This post is a collection of half-formed thoughts and observations. I'm not claiming to have all the answers—hell, I'm not even sure these are the right questions. But something is shifting under our feet, and pretending it isn't doesn't make it stop.
Are we heading toward a more fragmented, AI-generated software landscape? Or am I just another old developer yelling at algorithmic clouds from a small corner of the internet?
Honestly, I don't know. But I'd rather be wrong and loud about it than quiet and surprised when the whole toolchain landscape looks unrecognizable in five years.
Also readable in: https://maho.dev/2026/03/ai-is-making-libraries-obsolete/ by @mapache:
#AI #Software Development #Libraries #Agentic Development #ORMs #CSS Frameworks #MCP #Developer Tools #Future of Coding #Hot Takes #LLM #Copilot
-
AI is Making Libraries Obsolete
Summary: AI agents are fundamentally changing the economics of general-purpose libraries. Why build on Bootstrap when an agent can generate exactly what you need? A collection of thoughts on where this is all heading.
The Great Library Unbundling: How AI is Eating the Software Stack
More than a year ago, I told people that ORMs like Entity Framework were going to feel like relics. That LLMs would just generate the SQL you need, making all that object-relational mapping overhead pointless. A few people told me I was crazy and doing things wrong (and to be honest I wasn't good enough at explaining why I thought this).
Well, time seems to have been on my side (Wwo is laughing now hahahaha!!).
Now, this is a hot take, so I will go forward and talk as a hot take. If I put my devil's advocate hat on, I would probably rage against whoever wrote this post. But because I LOVE MYSELF, I won't do it. I certainly see flaws in my arguments. So buckle up—this is not rage bait, it is just a hot take from a Mexican developer who spent the weekend arguing with AI agents instead of sleeping like a normal person.
The ORM Prediction, or How I Accidentally Became Right About Something
Here's the thing about ORMs: they exist because writing SQL is supposedly "hard" and "error-prone." Meanwhile, I've been writing raw SQL since my first job at a tiny shop in Tepic where we didn't have the luxury of Entity Framework or Hibernate or whatever fancy abstraction layer the cool kids were using. We just wrote the queries, crossed ourselves, and hit execute. Catholic upbringing has some unexpected engineering applications.
Now, to be fair—we did end up building our own tailored ORM for the common cases. Because once you've written the same parameterized INSERT fifteen times, even the most stubborn raw-SQL purist starts thinking "maybe I should abstract this." And ORMs do earn their keep in some areas: SQL injection prevention, enforcing parameterized queries, handling connection lifecycle stuff that nobody wants to think about. Security guardrails that your 2 AM brain will absolutely forget to implement on its own. I get it. ORMs aren't stupid—they solved real problems.
But here's the trap: as soon as you start getting into complex queries, you're no longer just maintaining your application logic—you're also maintaining the ORM and the complex queries. You end up fighting the abstraction to make it do what raw SQL does naturally, and now you have two problems instead of one. The thing that was supposed to simplify your life becomes another layer you have to debug, optimize, and keep in your head at the same time. And whoever has run a high-performance application—like an ecommerce site during Black Friday—knows exactly what I'm talking about. That query you spent weeks trying to optimize through the ORM, doing quirky reflection tricks and fighting with expression trees? You ended up raw-dogging the SQL anyway, because that was the only way to get the performance you needed. The ORM was never going to get you there. It was just standing in the way, politely.
Now Claude just writes you the exact SQL you need—parameterized, injection-safe, the whole deal. No mapping, no configuration, no surprises. Just the data access pattern you actually want. It's like having a DBA who never sleeps, never complains about schema changes, and doesn't passive-aggressively CC your manager when you write a bad join. The abstraction layer that was supposed to save us from SQL is now the thing standing between us and the AI that's better at SQL than most of us ever were.
Agentic Development and the Death of One-Size-Fits-None
This isn't just about ORMs. I've been thinking about how agentic development fundamentally changes the whole premise of general-purpose libraries and building blocks.
Platform teams across the industry are going to start questioning their investments in broad, one-size-fits-all libraries. And honestly? Good. Because "one-size-fits-all" always meant "fits nobody perfectly but everyone tolerably." Like those beach ponchos they sell at every tourist shop in Nayarit—technically covers you, technically functions, but you look ridiculous and you know it.
Take CSS frameworks. Bootstrap, Bulma, Fluent UI—they're great for getting started quickly. But you end up learning their specific class naming conventions, carrying tons of CSS you'll never use, fighting against the framework the moment you want something custom, and—my personal favorite—looking like every other Bootstrap site on the internet. Your site ends up with more unused CSS than empty beer bottles after a Sunday carne asada in Nayarit. And that's a lot of bottles, trust me.
With agentic development? You just tell the agent what you want your UI to look like. It generates exactly the CSS you need. No framework lock-in, no unused code, no learning curve. The agent doesn't need to know Bootstrap's grid system (although it probably was trained on such codebases)—it just writes "vanilla" CSS that does what you asked for. I know this because that's exactly what happened with this blog. The CSS you're looking at right now? Generated. By an agent. Who understood what I wanted better than I understood what I wanted (debatable).
MCP is Already Feeling Old
Speaking of things that are aging quickly: the Model Context Protocol. MCP. Remember when everyone was wrapping every CLI tool as an MCP server like it was the new hotness? That was, what, months ago? In AI time that's basically the Paleolithic era.
Here's the thing—CLI tools already come with perfect documentation in the form of man pages. They're basically documented APIs already. Your agent doesn't need a special protocol wrapper to use
gh pr createoraz webapp deploy. It just reads the docs, fumbles the first attempt (like any of us), and then figures it out. Combine Claude Code with existing CLI tools—GitHub CLI, Azure CLI, kubectl, whatever—and you've got everything MCP promised, but without the ceremony.Microsoft's already doing something interesting with their dotnet/skills repo. Skills that are just prompts guiding the agent through repeatable processes. No protocol, no server, no serialization format drama. Just a well-written prompt. Turns out the best API for an AI agent is just... words. Who knew. (Okay, a lot of people knew. But still.)
Hugo Drove Me to Build My Own (Again, Because I Never Learn)
I just finished redoing my entire publishing workflow. Hugo felt limiting and bloated—all these features I'm maintaining, constantly broken by dependency updates, GitHub workflows failing for mysterious reasons. Every time I pushed a new post it was a coin flip whether the build would succeed or I'd spend an hour debugging some Go template issue that made me question my life choices.
So I rewrote it in .NET. Dead simple. I don't expect anyone else to use it—exclusive distribution, zero units available—but damn, it felt liberating. The CSS and HTML of this blog changed completely, and I actually understand every piece of it now. No more cargo-culting Hugo partials I copied from a theme three years ago and was afraid to touch.
This is the pattern I keep seeing: when AI can generate exactly what you need, the appeal of heavyweight, general-purpose solutions just evaporates. Like fog burning off in the morning sun in Tepic. One moment it's there, thick and omnipresent, and then it's just... gone.
The Accountability Problem
Here's something that's been bugging me. I saw a conversation on the fediverse about more and more tools being created with no clear ownership. Developers suspect some might be entirely AI-generated, with humans just shepherding them into existence like zookeepers who can't actually control the animals.
That sucks. Humans should be in charge and taking responsibility for the software they put into the world. There's a difference between using AI as a tool and letting AI be the architect while you nod along pretending you reviewed the blueprints.
When something breaks, when there's a security issue, when users need support—who's accountable? You can't file a bug report against GPT-4. And "the AI did it" is not an incident postmortem. Not yet, anyway. Give it a year (debatable).
Copilot's Infinite Loop of Self-Criticism
Speaking of AI quirks: Copilot keeps finding issues in my PRs, I ask it to fix them, it fixes them, and then when I ask it to review again, it finds more issues. In the code it just wrote. In the code. It. Just. Wrote.
This is like watching someone argue with themselves in the mirror. Except the mirror is burning tokens, the person is burning my budget, and the argument never ends. The AI equivalent of "works on my machine" syndrome, except it doesn't even work on its own machine.
Blog Posts Are Better Than Repos for Teaching AI
Here's something that genuinely surprised me. A friend at Microsoft pointed his AI agent to my blog series to implement ActivityPub. Not to a GitHub repo with code samples. Not to the official W3C spec. To my blog posts. The ones I write at 1 AM like a gremlin-raccoon, full of rambling asides and half-baked metaphors.
Turns out prose explanations with context and reasoning are way more effective for agents than just dumping code at them. Blog posts tell the story of why decisions were made, not just what the final result looks like. The agent needs to understand intent, not just syntax. It needs the narrative—the "I tried this and it broke spectacularly, so I did this other thing instead" part that never makes it into a README.
So all those years of writing meandering blog posts about my projects instead of writing proper documentation? Turns out I was ahead of my time. Or just lazy. Probably both.
Where This Is All Heading
I think we're heading toward a world where general-purpose libraries become luxury items—nice to have, but not essential. Where AI-generated, purpose-built solutions become the norm. Where documentation and prose become more important than code artifacts. And where human accountability becomes the thing that actually differentiates good software from the rest.
This doesn't mean libraries disappear overnight. But the incentives are shifting. Why build and maintain a framework used by millions when everyone can have their own custom solution?
The future might be less about sharing code and more about sharing knowledge, context, and decision-making frameworks. Less "here's my npm package" and more "here's the blog post explaining why I built it this way so your agent can do something better."
Anyway
This post is a collection of half-formed thoughts and observations. I'm not claiming to have all the answers—hell, I'm not even sure these are the right questions. But something is shifting under our feet, and pretending it isn't doesn't make it stop.
Are we heading toward a more fragmented, AI-generated software landscape? Or am I just another old developer yelling at algorithmic clouds from a small corner of the internet?
Honestly, I don't know. But I'd rather be wrong and loud about it than quiet and surprised when the whole toolchain landscape looks unrecognizable in five years.
Also readable in: https://maho.dev/2026/03/ai-is-making-libraries-obsolete/ by @mapache:
#AI #Software Development #Libraries #Agentic Development #ORMs #CSS Frameworks #MCP #Developer Tools #Future of Coding #Hot Takes #LLM #Copilot
-
Dutch Agency Funds CBT Training Program Based on Flawed Long COVID Trial
By David Tuller, DrPH
Here is how bullshit replicates itself in today’s medical world: Conduct a flawed trial, declare success despite serious questions, then develop health policy based on these hyped-up claims.
ZonMW, a major Dutch healthcare funding agency, is supporting a new program led by Professor Hans Knoop, a longtime supporter of the fraudulent PACE trial, to develop “therapist training” for a “post-infection fatigue treatment” dubbed “Fit after an infection.” The training is based on a 2023 study, spearheaded by Professor Knoop and published in Clinical Infectious Diseases, called “Efficacy of Cognitive-Behavioral Therapy Targeting Severe Fatigue Following Coronavirus Disease 2019: Results of a Randomized Controlled Trial.”
The trial was unblinded and relied solely on subjective measures for its claims of benefits—a recipe for an unknown amount of bias. As would be expected with such research, the investigators reported modestly positive results for the primary outcome, self-reported fatigue. But the trial yielded null results for the one objective outcome mentioned in the protocol—amount of physical activity, as measured by monitoring devices worn at the beginning and end of the intervention.
The investigators conveniently left that salient detail out of the published trial report–a choice that (in my view) constitutes a form of research misconduct. Instead, they touted the intervention as a success. When online commenters noted the absence of the physical activity results, the investigators acknowledged the null findings for that measure and then offered ludicrous, “dog ate my data”-type excuses for not having included these data in the paper. As I pointed out on social media, I had just seen a terrific London stage production of Arthur Miller’s The Crucible, and the pro-witchcraft arguments in the play were more credible than the excuses offered by the trial investigators for not having mentioned their null objective outcome results.
The most laughable claim was that level of physical activity bore no relationship to self-reported fatigue. Huh??? Professor Knoop himself has stated otherwise in previous papers, so it is hard to take this assertion seriously. If physical activity were really irrelevant, there would have been no reason to measure it in the first place. Had the physical activity outcome supported the positive subjective results for fatigue, the investigators would undoubtedly have mentioned them.
The new training effort is part of a ZonMW initiative to fund projects that build on previous COVID-19 work funded by the organization. The maximum grant under the program is €50,000, or about $58,000. So it’s a modest sum that, in reality, won’t pay for much.
Here is a description of the new program from the ZonMW site:
“Fatigue is common after COVID-19 and can become chronic in a significant proportion of patients, limiting daily functioning. Cognitive behavioral therapy (CBT) can reduce fatigue, concentration problems, and disability in some of these patients…Because there are few other proven treatments for fatigue after COVID-19, there is a need for CBT. The treatment has been successfully implemented at the Amsterdam UMC, but referral options elsewhere are limited. Fatigue is also common after other infections. Fatigue symptoms after other infections may also be treated with CBT…The aim of the current project is to develop a training program for behavioral therapists to treat chronic fatigue following an infection, such as COVID-19. This can promote the nationwide implementation of CBT for post-infectious fatigue.”
And here is the expected outcome:
“The project will produce an evidence-based, transferable treatment protocol and web-based tool for CBT treatment for fatigue. Both will be made available to participants in the training program. The web tool will be offered to multiple intervention software platforms. Trainers will be appointed to deliver the training program, and the program will be offered to continuing education institutes. Accreditation will be sought from the Dutch Association for Cognitive and Behavioral Therapy (VGCT) and the Federation of Healthcare Psychologists (FGzP), making the training attractive to professionals. The plan is to describe the protocol and background in a Dutch chapter and in a journal for behavioral therapists.”
In other words, based on biased trial with predictable subjective findings that were not supported by the one objective measure, the Netherlands would like to roll out a national treatment infrastructure. Makes sense!
Some patient advocates have protested this project on social media. In response to one such complaint, ZonMW explained that these implementation grants are not peer-reviewed and are awarded to ZonMW-funded investigators who want to put their findings into practice on a first-come, first-serve basis:
“At ZonMw we encourage research results from the COVID‑19 program to find their way into practice. That is why ZonMw opened an implementation‑impulse round for projects that previously received funding. Researchers can turn their earlier findings into concrete products such as training materials, guidelines or educational materials. This is a scheme with a process without reviewers or an assessment committee and without patient involvement. This means that the application is assessed by ZonMw for completeness and whether it meets all the conditions and assessment criteria as set out in the subsidy call. ZonMw assesses applications in order of receipt until the subsidy ceiling is reached.”
ZonMW added:
“We are aware that Cognitive Behavioral Therapy (CBT) for chronic fatigue after COVID‑19 is a sensitive topic. Funding implementation activities after the completion of a research project is a standard procedure for ZonMw. Granting this subsidy application is not a position on what causes post‑COVID or other illnesses.”
It is unwarranted to suggest that patients are “sensitive” about CBT. They are “sensitive” about research, like Professor Knoop’s CBT trial, that is flawed from the start and claims to show what it doesn’t. They have a right to demand that health policy be based on quality trials. Apparently, ZonMW has trouble understanding that concept, at least in this domain.
(View the original post at virology.ws)
#Knoop #Netherlands -
Thinking outreach of the hashtag story to this event https://www.ngiforum2023.eu/
Classification of different versions of the web (such as #Web1, #Web2, #Web3, #Web4, or #Web5) can be a source of confusion and FUD (fear, uncertainty, and doubt).
The hashtags #openweb and #closedweb provide a clear way to describe and understand the different types of web platforms. The #openweb refers to platforms that are open-source, community-controlled, and promote transparency, the #closedweb to platforms that are proprietary, controlled by a few large companies and lack transparency.
Projects like #indymediaback and #OMN are examples of grassroots of social tech. These projects are focused on promoting decentralized, community-controlled media and communication platforms.
It’s time to compost the normal #techshit, and to focus on developing social tech that is more inclusive, diverse, and community-controlled. This will require a change in the way we think about technology, and a shift away from the current dominant paradigm.
The solution to this problem is to develop social tech that steps away from the #geekproblem and focuses on the needs and perspectives of the community. This can be achieved by involving a diverse group of people in the development and decision-making process, and by promoting open-source code, open standards, open governance, and open data in technology development.
The #geekproblem is a social tech problem that refers to the negative impacts that technology can have on society when it is developed and controlled by a small group of people with limited perspectives and values. It is important to recognize that the #geekproblem is not only a technical issue but also a social issue.
It’s important to remember that fear can be a barrier for change, but by actively using the #4opens we can call out pointless things, call out the #deathcult and compost the #techshit, we can actively work towards a more sustainable future.
It’s important to remember that all thinking is critique and if you aren’t looking at the faults, you are likely not looking at the thing at all. Don’t be afraid, use the #4opens, take up gardening the compost, and plant the seeds of hope in the era of #climatechaos.
It’s important to lift your head and look, lift your shovel, dig and plant. By actively using the #4opens and composting the #techshit, we can actively work towards a more sustainable future.
Living in fear is a common response to the challenges of the era of #climatechaos, when many people are on their knees worshipping the #deathcult. However, it is important to call out pointless things as pointless and actively use the #4opens as a tool to compost the #techshit that is contributing to these challenges.
The problem is that the nice moral majority, our liberal friends, have not accepted that the system they try to push is broken. It’s pastime for change, and holding onto our current system is not helping. Their “common sense” is the problem we need to be fighting, as well as the far right.
We must come together as a united force to address the real issues and challenges facing society, rather than spending time fighting among ourselves.
The left fail is spending too much time fighting inside the left over this balance, instead of focusing on the real issues and challenges. #BLOCKING #stupidindividualism and worshipping the #deathcult all push this fight, and it’s important not to be a “PRAT” (i.e. a person who behaves in a foolish or unthinking way) on this subject.
The “left mess” we are in refers to the challenges and divisions within the left-leaning political spectrum. The idea that on the “fluffy” left, we must be “nice” to get people involved in social change, and on the “spiky” left, we need to be nasty to be effective in social change, both have some truth to it. It is important to find a balance between the two approaches in order to be effective in bringing about social change.
Group use of hashtags as an organizing tool. This can help to bring attention to issues, promote collaboration, and increase the visibility of alternative perspectives on technology and society.
Overall, these ideas are meant to challenge the status quo, promote ethical considerations in technology development, and increase transparency, accountability, and collaboration in the tech industry.
Pushing simple #KISS ideas like #openweb vs #closedweb and #4opens as a powerful way to judge and compost #techcrap to mediate the #techchurn. This can help to promote open-source code, open standards, open governance, and open data in technology development.
To work with this, some ideas include:
Naming the current “common sense” as worshipping the #deathcult and making #mainstreaming uncomfortable. This can help to bring attention to the negative impact of neoliberalism on society and the importance of addressing it.
#stupidindividualism is a term that refers to the idea that people prioritize personal gain over the well-being of others and the community. It is often associated with the last 40 years of neoliberalism and a part of the liberal 20th century consensus. It is a strong #BLOCK that prevents people from recognizing and addressing the negative impact of their actions on society.
One way to address this challenge is to promote grassroots, DIY producer governance through the use of the #OGB hashtag and project. This can help to ensure that the development of the fediverse is guided by ethical considerations and that it is focused on the needs of the producers and the community.
It’s important to note that it’s not always possible to avoid mess and challenges.
One of the challenges of the fediverse is that it is decentralized and lacks a centralized governance structure, making it difficult to coordinate and get things done. This can be seen as both a good thing and a bad thing, as it allows for a lot of creativity and innovation, but also makes it difficult to achieve goals and create a consistent user experience.
The #fediverse is a network of independently operated servers that communicate with each other using open protocols. It is often considered an “accidental” reboot of the #openweb, as it emerged organically as a response to the centralized nature of social media platforms, which are dominated by the #dotcons
While the #4opens is not a way of keeping large corporations out of the open-source development, it can be used as a tool to mediate and prevent any attempts to extinguish the open source community by promoting transparency, accountability, and collaboration. By using #4opens, developers, users and community members can have a better understanding of the motivations and intentions of the corporation and can act accordingly.
The #4opens is a powerful tool for promoting open-source code, open standards, open governance, and open data in technology development. It can help to ensure that the development of technology is guided by ethical considerations and that it is focused on the needs of the users and the community, rather than the profits and control of a few large companies.
Additionally, the website could include links to the wiki for more in-depth information and resources, as well as a section for community engagement and discussion. This could be a valuable tool in the fight against #techshit #techcurn and a powerful way to reboot the #openweb movement..
The website could feature a clean and modern design, with a focus on easy navigation and clear, concise information about the #4opens. The text could be polished to make it easy for people of all skill levels to understand. You can use the existing wiki page https://unite.openworlds.info/Open-Media-Network/4opens/wiki as a starting point and add more information and resources to it.
Creating a visually appealing and user-friendly website for the #4opens could be a powerful tool in promoting the use of open-source code, open standards, open governance, and open data in grassroots tech projects. This website could serve as a central hub for information and resources on the #4opens, and it could be designed to make it easy for people to understand and adopt the principles of the #4opens in their own projects.
-
Let’s talk about SD-WAN and MPLS.
I had lunch with a telecom and ISP services aggregator/seller the other day. His opinion is that MPLS is a legacy technology, rapidly being replaced by SD-WAN. That’s a long ways from accurate, and honestly I was kind of stunned. Since that type of thinking is out there, and apparently commonly believed, it’s time to inoculate you from SD-WAN hype with a dose of truth.1) SD-WAN isn’t a protocol. It’s an overlay.
2) MPLS is a transport protocol.
3) SD-WAN can’t exist without transport protocols under it.
4) SD-WAN often uses more than one transport protocol. For example, broadband Internet service from an ISP is less expensive than MPLS. That’s why it’s common – very common – for an SD-WAN overlay to direct high priority traffic over an MPLS link, while directing traffic with lower security requirements or less stringent latency requirements over the cheaper broadband link.Now let’s talk about that “legacy technology” perspective.
--Ethernet was in development for several years, but was standardized by the IEEE as 802.3 in 1983, so let’s call that its birthday and say that Ethernet is now 40 years old. It’s not considered a legacy technology because it's still very much in use.
--MPLS is an IETF standard. It’s first RFC was published in 2001, so it’s now 22 years old. And it’s not a legacy technology, either, because, like Ethernet, it’s still very much in use. In fact, various investment analyses are predicting the growth of MPLS over the next five years.MPLS Growth, Quote 1:
According to Market Statsville Group:
“The global Managed MPLS market size is expected to grow from USD 55.6 million in 2021 to USD 97.9 million by 2030… Carriers have increased their network investment in response to the expansion of cloud-based mobile consumer services.” (Link in comments)MPLS Growth, Quote 2
On it’s website, Cisco says, “Multiprotocol Label Switching (MPLS) enables Enterprises and Service Providers to build next-generation intelligent networks that deliver a wide variety of advanced, value-added services over a single infrastructure… SD-WAN can be seen as a software abstraction of MPLS technology that is applicable to wider scenarios…” (Link in comments)Remember that I said that SD-WAN is an overlay? Cisco agrees. SD-WAN doesn’t replace MPLS. It gives you a convenient way to manage your transport resources – MPLS, broadband Internet, and other.
SUMMARY
SD-WAN gives you the ability to mix-and-match your data transport technologies for the best optimization of cost, QoS, and security.
SD-WAN gives you a convenient dashboard for monitor and control of your WAN resources.
SD-WAN is an overlay. It doesn’t replace any transport layer technology.
Broadband Internet and MPLS are two common transport technologies, each with advantages over the other.
Your SD-WAN solution probably incorporates MPLS, and you just don’t know it. -
What To Use Instead of PGP
It’s been more than five years since The PGP Problem was published, and I still hear from people who believe that using PGP (whether GnuPG or another OpenPGP implementation) is a thing they should be doing.
It isn’t.
I don’t blame individual Internet users for this confusion. There is a lot of cargo-culting around communication tools in the software community, and the evangelists for the various projects muddy the waters for the rest of us.
HarubakiThe part of the free and open source software community that thinks PGP is just dandy, and therefore evangelize the hell out of it to unsuspecting people, are the same kind of people that happily use XMPP+OMEMO, Matrix, or weird Signal forks that remove forward secrecy and think it’s fine.
Not to mince words: The same people who believe PGP is good are also famously not great at cryptography engineering.
If you’re going to outsource your opinions on privacy technology to someone else, make sure it’s someone who has actually found vulnerabilities in cryptographic software before. Most evangelists have not.
CMYKatI’m not here to litigate the demerits of PGP. The Latacora article I linked above makes the same arguments I would make today, and is a more entertaining read.
It is of my opinion as a security engineer that specializes in applied cryptography that nobody should use PGP, because there’s virtually always a better tool for the job you want to use PGP for.
(And for the uncommon use cases, offering a secure, purpose-built replacement is a work-in-progress.)
Note: I’m deliberately being blunt in this post because literally more than a decade of softspokenness from cryptography experts has done nothing to talk users off the PGP cliff. Being direct seems more effective than being tactful.
If you want a gentler touch, ask your cryptographer. If you don’t have a cryptographer, hire one.
If you can accept that every billionaire is the result of a failed system, that’s how cryptographers feel about people using PGP.
Instead, let’s examine the “use cases” of PGP and what you should be using instead. (Some of this is redundant with the Latacora article, but I’m also writing it 5 years later, so some things have changed.)
CMYKatI’m focusing on the “what” in this post, not the “why”. If you want to know the why, read the Latacora blog, or the Matthew Green blog.
If you’re curious about the credibility of my recommendations, read my other blog posts or ask your cryptographer.
Instead of PGP, Use This
This section contains specific tools to solve the same problems that PGP tries to solve, but better.
What makes these recommendations better than PGP?
Simply, they don’t make cryptographers want to run the other way screaming when they look under the hood. PGP does.
Some people are forced to use PGP because they work for a government that legally requires them to use PGP. In that corner case, your hands are tied by lawyers, so you don’t need to bother with what cryptographers recommend.
CMYKatSigning Software Distributions
Use Sigstore.
Note that this is an ecosystem-wide consideration, not something that specific individuals must manually opt into for each of their hobby projects. The only downside to Sigstore is it hasn’t been widely adopted yet.
If you’re a Python developer, you can just use PEP 740 to get attestations with Trusted Publishers, which gives you Sigstore for free. For most developers, this is as simple as setting up a GitHub Action to publish to PyPI.
This is a developing trend: Other programming language and package management ecosystems are following suit. I expect to see Sigstore attestations baked into NPM and Maven before the next US presidential election. With any luck, your favorite programming language could be on this list too.
Sigstore doesn’t just give you a signature that you check with a long-lived public key, nor does it require you to do the Web Of Trust rigamarole.
Rather, Sigstore gives you a lot for free. Sigstore was designed around ephemeral signing certificates rather than a long-lived private key. It was purpose-built for preventing supply-chain attacks against open source software.
Combined with Reproducible Builds, Sigstore solves the triangle of secure code delivery.
Alternatively, use minisign. If your package ecosystem doesn’t support Sigstore yet, you can get by with minisign (which is signify-compatible) until they modernize.
You can also use SSH signatures, if you’d prefer. (More on that below.)
CMYKatSigning Git Tags/Commits
Use SSH Signatures, not PGP signatures.
With Ed25519. Stop using RSA.
Art by HarubakiSending Files Between Computers
Use Magic Wormhole.
You could also use SSH + rsync to do this job. That’s fine too.
CMYKatEncrypting Backups
Tarsnap is the usual recommendation here.
There are a lot of other encrypted backup tools that work fine, if you don’t want to give Colin Percival your business. I don’t have a financial stake in any of them, nor have I audited them thoroughly.
Borg uses reasonable cryptography, but I haven’t had the time to review it carefully.
Kopia looks fine, but I really hate that they misuse “zero knowledge” to describe an encryption protocol (rather than a proof system). We should not reward this misbehavior by marketers.
The point is: You’ve got options.
Too many options, in my opinion, to settle for PGP.
CMYKatEncrypting Application Data
Avoid: OpenPGP, OpenSSL and its competitors.
Not a lot to say here. I’ve written a lot about this over the years. Misuse-resistant cryptography libraries–especially ones that make key management less painful for users–are the way to go.
HarubakiEncrypting Files
Use age.
Age is what PGP file encryption would be if PGP didn’t suck shit.
Age has two modes: Public-key encryption, and password-based key derivation.
Here’s a quick comparison table between what age offers, and what PGP uses in the installed base:
agePGPData encryption modeAEAD (ChaPoly)CAST5 (64-bit block cipher) in CFB mode with a strippable SHA1 “MDC”Key-commitmentYes (via the header)Pah! You wish! Dream on.
PGP isn’t even AEAD.Password KDF memory hard?Yes, with scrypt.No.Vulnerable to chosen-ciphertext attacks?No.Yes, but PGP proponents stupidly consider this a good thing.Supports 90’s-era cryptography?No.Yes.Releases unauthenticated plaintext?No.Yes.Uses versioned protocols rather than “cipher agility”?Yes.No. See: 90’s era cryptography.Most common implementations are memory-safe?Yes (Go, Rust).No (C).Like, it’s not even close.
CMYKatSome PGP proponents will insist that AEAD is possible now, but as long as the installed base of PGP remains backwards compatible with the lowest common denominator, that’s what your software uses.
Just use age. Or rage, if you’re a Rust enthusiast.
(And if you have concerns about “which age key should I trust?”, I’m already planning an age-v1 extension for the Public Key Directory project. More on that below.)
Art by ScruffPrivate Messaging
Use Signal.
Security teams around the world insist that they need PGP for bug bounty submissions or security operations, but Signal does this job better than PGP ever did.
Once upon a time, you needed to give people a phone number to use Signal, but that hasn’t been the case for a long time. Still, many people have missed that memo and think it’s a requirement.
My Signal username is soatok.45. Go ahead and message me. You won’t learn my phone number that way.
In the near future, I plan on developing end-to-end encryption for direct messages on the Fediverse (including Mastodon). This is what motivated my work on the Public Key Directory to begin with.
But this is not intended to be a Signal competitor by any measure. It’s a bar-raising activity, nothing more.
CMYKatI understand some people don’t like or trust Signal for whatever reason, but every single alternative that’s been suggested to Signal has offered inferior cryptography to Signal’s. So I will continue to recommend Signal.
Miscellaneous PGP Alternatives
This section contains things people think they need PGP for.
Identity Verification
I’m actively working on something better!
via XKCDIf you want the ability to vend a transparently verifiable public key for a given user, that’s one of the use cases for the Public Key Directory I’m designing in order to build end-to-end encryption for the Fediverse.
Although this is purpose-built for the Fediverse, I’ve deliberately included support for Auxiliary Data messages, whose formats will be specified by protocol extensions.
Rather than trying to grok the Web-of-Trust, you can simply have your software check that multiple independent Public Key Directories have verified the record, since its inclusion is published in an append-only transparency log, secured by a Merkle tree.
My design doesn’t preclude any manual key verification, or key-signing parties, or whatever other PGP cultural weirdness you want to do with these public keys. It just establishes a baseline trustworthiness even if you’re not a paranoid computer nerd.
My project isn’t finished yet. In the meantime, you can manually check public keys when using the other recommendations on this page.
HarubakiEncrypted Email
Don’t encrypt email. From the Latacora article:
Email is insecure. Even with PGP, it’s default-plaintext, which means that even if you do everything right, some totally reasonable person you mail, doing totally reasonable things, will invariably CC the quoted plaintext of your encrypted message to someone else (we don’t know a PGP email user who hasn’t seen this happen). PGP email is forward-insecure. Email metadata, including the subject (which is literally message content), are always plaintext.
There isn’t a recommendation for encrypted email because that’s not a thing people should be doing.
Art by AJNow, there exists a minority of extremely technical computer user for which Signal is a nonstarter (because you need a smartphone and valid phone number to enroll in the first place).
Because those people are generally not the highest priority of cryptographers (who are commonly focused on the privacy of common folk–including people in poor and developing countries where smartphones are more common than desktop computers), there presently isn’t really a good recommendation for private messaging that meets their constraints.
Certainly not PGP, either.
What PGP offers here is security theater: the illusion of safety. But it’s not actually a robust private communication mechanism, as Latacora argues.
CMYKat“I insist that I need encrypted email!”
If you find someone insisting that they “need” encrypted email, read up on the XY Problem. In a lot of cases, that’s what’s happening here.
Do they ipso facto need email (as in, specifically the email protocols and email software)?
And do they care more about this constraint, or the privacy of their communications?
Because if their goal just to communicate privately, see above.
If the tool they’re using being email is more important than privacy, they should consider sending empty messages with an attachment, and use age to encrypt the actual message before attaching it.
That’s serviceable, just beware that everything Latacora wrote about encrypted emails still applies to your use case, so expect someone to CC or forward your message as plaintext.
(Unless you’re legally required to use PGP because of a government regulation… in which case, why do you care about my recommendations if you’re chained by the ankle to your government’s bad technology choices?)
Finally, miss me with the “but someone can screenshot Signal” genre of objections.
As Latacora noted, people accidentally fuck up PGP all the time! It’s very easy to do.
Conversely, you have to deliberately leak something from Signal. There is no plaintext mode.
That’s the fucking bar you need to meet to compete with Signal.
PGP fails to be a Signal competitor, in ways that are worse than Threema, Matrix, or OMEMO.
Watch This Space
With all that said, I am actually designing an encrypted messaging protocol that will have an email-like user experience, except:
- Everything is always end-to-end encrypted, with forward secrecy.
- It’s not backwards compatible with insecure email.
- It doesn’t use PGP, or any 1990’s era cryptography.
I can’t promise a release date yet. I’m prioritizing end-to-end encryption for the Fediverse before I write the specification for that project (tentatively called AWOO, but the cryptography underpinning both projects should be similar).
Maybe 2026? We’ll see!
If someone beats me to the punch, and their design is actually good, I’ll update the post and replace this with a specific recommendation.
CMYKatAgainst PGP
I don’t know how to get the message out louder or clearer about how cryptographers feel about PGP than what I wrote here.
Latacora wrote their criticism in 2019. As I write this, 2024 is almost over. When will the PGP-induced madness end?
CMYKatExperts are not divided here. There is no controversy to teach.
Every time a cryptographer has talked about PGP, it’s been to complain about how bad it is and opine that people shouldn’t be using it.
If you’ve read this far, you already know what you should be using instead.
Header art credits: CMYKat and the GnuPG logo.
Update (2024-11-16)
Someone tried to use their Fediverse software to submit an anti-furry comment to this blog post.
Therefore, I’ve added more furry art to it.
loviesophieeIf you’re curious about the cryptography used by other messaging apps, please refer to this page that collects my blogs about this topic.
#alternatives #codeSigning #digitalSignatures #encryption #PGP #security #SecurityGuidance #signing
-
Yesterday at #IETF124 we attended the session of one of the working groups that we actively contribute to: GROW (Global Routing Operations).
Not surprisingly, there were lots of good ideas around BMP, the BGP monitoring protocol.
@drk gave an update about two drafts that will allow creating and storing BMP snapshots.
We love how everybody in this WG works towards common goals.
-
Now that there are no special covid protocols in place (other than we should try and avoid getting it and spreading it, use vaccines, masks & self-isolation), why is there all that track and trace stuff still installed and active on my phone? I mean, nobody is notifying / reporting covid infections any more than they would flu or even a common cold, so all that tracking & contact tracing is being used for what, exactly?
-
Hype for the Future 107H: Never Compare Oneself to Others
Overview The most common causes for insecurities that are often disruptive in the case of distinct individual cases include self-directed comparison with other individuals. Such comparisons may focus on social capital, risk tolerance, safety protocols, financial access, and even elite status. -
Could the european #synchrotron get a common proposal /sample submission protocol developed for #MX and #SAXS. So much of my time seems to be spend reformatting / re-entering the same information in different formats and then getting the relevant user office complaining it isn't quite right.
-
What To Use Instead of PGP
It’s been more than five years since The PGP Problem was published, and I still hear from people who believe that using PGP (whether GnuPG or another OpenPGP implementation) is a thing they should be doing.
It isn’t.
I don’t blame individual Internet users for this confusion. There is a lot of cargo-culting around communication tools in the software community, and the evangelists for the various projects muddy the waters for the rest of us.
HarubakiThe part of the free and open source software community that thinks PGP is just dandy, and therefore evangelize the hell out of it to unsuspecting people, are the same kind of people that happily use XMPP+OMEMO, Matrix, or weird Signal forks that remove forward secrecy and think it’s fine.
Not to mince words: The same people who believe PGP is good are also famously not great at cryptography engineering.
If you’re going to outsource your opinions on privacy technology to someone else, make sure it’s someone who has actually found vulnerabilities in cryptographic software before. Most evangelists have not.
CMYKatI’m not here to litigate the demerits of PGP. The Latacora article I linked above makes the same arguments I would make today, and is a more entertaining read.
It is of my opinion as a security engineer that specializes in applied cryptography that nobody should use PGP, because there’s virtually always a better tool for the job you want to use PGP for.
(And for the uncommon use cases, offering a secure, purpose-built replacement is a work-in-progress.)
Note: I’m deliberately being blunt in this post because literally more than a decade of softspokenness from cryptography experts has done nothing to talk users off the PGP cliff. Being direct seems more effective than being tactful.
If you want a gentler touch, ask your cryptographer. If you don’t have a cryptographer, hire one.
If you can accept that every billionaire is the result of a failed system, that’s how cryptographers feel about people using PGP.
Instead, let’s examine the “use cases” of PGP and what you should be using instead. (Some of this is redundant with the Latacora article, but I’m also writing it 5 years later, so some things have changed.)
CMYKatI’m focusing on the “what” in this post, not the “why”. If you want to know the why, read the Latacora blog, or the Matthew Green blog.
If you’re curious about the credibility of my recommendations, read my other blog posts or ask your cryptographer.
Instead of PGP, Use This
This section contains specific tools to solve the same problems that PGP tries to solve, but better.
What makes these recommendations better than PGP?
Simply, they don’t make cryptographers want to run the other way screaming when they look under the hood. PGP does.
Some people are forced to use PGP because they work for a government that legally requires them to use PGP. In that corner case, your hands are tied by lawyers, so you don’t need to bother with what cryptographers recommend.
CMYKatSigning Software Distributions
Use Sigstore.
Note that this is an ecosystem-wide consideration, not something that specific individuals must manually opt into for each of their hobby projects. The only downside to Sigstore is it hasn’t been widely adopted yet.
If you’re a Python developer, you can just use PEP 740 to get attestations with Trusted Publishers, which gives you Sigstore for free. For most developers, this is as simple as setting up a GitHub Action to publish to PyPI.
This is a developing trend: Other programming language and package management ecosystems are following suit. I expect to see Sigstore attestations baked into NPM and Maven before the next US presidential election. With any luck, your favorite programming language could be on this list too.
Sigstore doesn’t just give you a signature that you check with a long-lived public key, nor does it require you to do the Web Of Trust rigamarole.
Rather, Sigstore gives you a lot for free. Sigstore was designed around ephemeral signing certificates rather than a long-lived private key. It was purpose-built for preventing supply-chain attacks against open source software.
Combined with Reproducible Builds, Sigstore solves the triangle of secure code delivery.
Alternatively, use minisign. If your package ecosystem doesn’t support Sigstore yet, you can get by with minisign (which is signify-compatible) until they modernize.
You can also use SSH signatures, if you’d prefer. (More on that below.)
CMYKatSigning Git Tags/Commits
Use SSH Signatures, not PGP signatures.
With Ed25519. Stop using RSA.
Art by HarubakiSending Files Between Computers
Use Magic Wormhole.
You could also use SSH + rsync to do this job. That’s fine too.
CMYKatEncrypting Backups
Tarsnap is the usual recommendation here.
There are a lot of other encrypted backup tools that work fine, if you don’t want to give Colin Percival your business. I don’t have a financial stake in any of them, nor have I audited them thoroughly.
Borg uses reasonable cryptography, but I haven’t had the time to review it carefully.
Kopia looks fine, but I really hate that they misuse “zero knowledge” to describe an encryption protocol (rather than a proof system). We should not reward this misbehavior by marketers.
The point is: You’ve got options.
Too many options, in my opinion, to settle for PGP.
CMYKatEncrypting Application Data
Avoid: OpenPGP, OpenSSL and its competitors.
Not a lot to say here. I’ve written a lot about this over the years. Misuse-resistant cryptography libraries–especially ones that make key management less painful for users–are the way to go.
HarubakiEncrypting Files
Use age.
Age is what PGP file encryption would be if PGP didn’t suck shit.
Age has two modes: Public-key encryption, and password-based key derivation.
Here’s a quick comparison table between what age offers, and what PGP uses in the installed base:
agePGPData encryption modeAEAD (ChaPoly)CAST5 (64-bit block cipher) in CFB mode with a strippable SHA1 “MDC”Key-commitmentYes (via the header)Pah! You wish! Dream on.
PGP isn’t even AEAD.Password KDF memory hard?Yes, with scrypt.No.Vulnerable to chosen-ciphertext attacks?No.Yes, but PGP proponents stupidly consider this a good thing.Supports 90’s-era cryptography?No.Yes.Releases unauthenticated plaintext?No.Yes.Uses versioned protocols rather than “cipher agility”?Yes.No. See: 90’s era cryptography.Most common implementations are memory-safe?Yes (Go, Rust).No (C).Like, it’s not even close.
CMYKatSome PGP proponents will insist that AEAD is possible now, but as long as the installed base of PGP remains backwards compatible with the lowest common denominator, that’s what your software uses.
Just use age. Or rage, if you’re a Rust enthusiast.
(And if you have concerns about “which age key should I trust?”, I’m already planning an age-v1 extension for the Public Key Directory project. More on that below.)
Art by ScruffPrivate Messaging
Use Signal.
Security teams around the world insist that they need PGP for bug bounty submissions or security operations, but Signal does this job better than PGP ever did.
Once upon a time, you needed to give people a phone number to use Signal, but that hasn’t been the case for a long time. Still, many people have missed that memo and think it’s a requirement.
My Signal username is soatok.45. Go ahead and message me. You won’t learn my phone number that way.
In the near future, I plan on developing end-to-end encryption for direct messages on the Fediverse (including Mastodon). This is what motivated my work on the Public Key Directory to begin with.
But this is not intended to be a Signal competitor by any measure. It’s a bar-raising activity, nothing more.
CMYKatI understand some people don’t like or trust Signal for whatever reason, but every single alternative that’s been suggested to Signal has offered inferior cryptography to Signal’s. So I will continue to recommend Signal.
Miscellaneous PGP Alternatives
This section contains things people think they need PGP for.
Identity Verification
I’m actively working on something better!
via XKCDIf you want the ability to vend a transparently verifiable public key for a given user, that’s one of the use cases for the Public Key Directory I’m designing in order to build end-to-end encryption for the Fediverse.
Although this is purpose-built for the Fediverse, I’ve deliberately included support for Auxiliary Data messages, whose formats will be specified by protocol extensions.
Rather than trying to grok the Web-of-Trust, you can simply have your software check that multiple independent Public Key Directories have verified the record, since its inclusion is published in an append-only transparency log, secured by a Merkle tree.
My design doesn’t preclude any manual key verification, or key-signing parties, or whatever other PGP cultural weirdness you want to do with these public keys. It just establishes a baseline trustworthiness even if you’re not a paranoid computer nerd.
My project isn’t finished yet. In the meantime, you can manually check public keys when using the other recommendations on this page.
HarubakiEncrypted Email
Don’t encrypt email. From the Latacora article:
Email is insecure. Even with PGP, it’s default-plaintext, which means that even if you do everything right, some totally reasonable person you mail, doing totally reasonable things, will invariably CC the quoted plaintext of your encrypted message to someone else (we don’t know a PGP email user who hasn’t seen this happen). PGP email is forward-insecure. Email metadata, including the subject (which is literally message content), are always plaintext.
There isn’t a recommendation for encrypted email because that’s not a thing people should be doing.
Art by AJNow, there exists a minority of extremely technical computer user for which Signal is a nonstarter (because you need a smartphone and valid phone number to enroll in the first place).
Because those people are generally not the highest priority of cryptographers (who are commonly focused on the privacy of common folk–including people in poor and developing countries where smartphones are more common than desktop computers), there presently isn’t really a good recommendation for private messaging that meets their constraints.
Certainly not PGP, either.
What PGP offers here is security theater: the illusion of safety. But it’s not actually a robust private communication mechanism, as Latacora argues.
CMYKat“I insist that I need encrypted email!”
If you find someone insisting that they “need” encrypted email, read up on the XY Problem. In a lot of cases, that’s what’s happening here.
Do they ipso facto need email (as in, specifically the email protocols and email software)?
And do they care more about this constraint, or the privacy of their communications?
Because if their goal just to communicate privately, see above.
If the tool they’re using being email is more important than privacy, they should consider sending empty messages with an attachment, and use age to encrypt the actual message before attaching it.
That’s serviceable, just beware that everything Latacora wrote about encrypted emails still applies to your use case, so expect someone to CC or forward your message as plaintext.
(Unless you’re legally required to use PGP because of a government regulation… in which case, why do you care about my recommendations if you’re chained by the ankle to your government’s bad technology choices?)
Finally, miss me with the “but someone can screenshot Signal” genre of objections.
As Latacora noted, people accidentally fuck up PGP all the time! It’s very easy to do.
Conversely, you have to deliberately leak something from Signal. There is no plaintext mode.
That’s the fucking bar you need to meet to compete with Signal.
PGP fails to be a Signal competitor, in ways that are worse than Threema, Matrix, or OMEMO.
Watch This Space
With all that said, I am actually designing an encrypted messaging protocol that will have an email-like user experience, except:
- Everything is always end-to-end encrypted, with forward secrecy.
- It’s not backwards compatible with insecure email.
- It doesn’t use PGP, or any 1990’s era cryptography.
I can’t promise a release date yet. I’m prioritizing end-to-end encryption for the Fediverse before I write the specification for that project (tentatively called AWOO, but the cryptography underpinning both projects should be similar).
Maybe 2026? We’ll see!
If someone beats me to the punch, and their design is actually good, I’ll update the post and replace this with a specific recommendation.
CMYKatAgainst PGP
I don’t know how to get the message out louder or clearer about how cryptographers feel about PGP than what I wrote here.
Latacora wrote their criticism in 2019. As I write this, 2024 is almost over. When will the PGP-induced madness end?
CMYKatExperts are not divided here. There is no controversy to teach.
Every time a cryptographer has talked about PGP, it’s been to complain about how bad it is and opine that people shouldn’t be using it.
If you’ve read this far, you already know what you should be using instead.
Header art credits: CMYKat and the GnuPG logo.
Update (2024-11-16)
Someone tried to use their Fediverse software to submit an anti-furry comment to this blog post.
Therefore, I’ve added more furry art to it.
loviesophiee#alternatives #codeSigning #digitalSignatures #encryption #PGP #security #SecurityGuidance #signing
-
What To Use Instead of PGP
It’s been more than five years since The PGP Problem was published, and I still hear from people who believe that using PGP (whether GnuPG or another OpenPGP implementation) is a thing they should be doing.
It isn’t.
I don’t blame individual Internet users for this confusion. There is a lot of cargo-culting around communication tools in the software community, and the evangelists for the various projects muddy the waters for the rest of us.
HarubakiThe part of the free and open source software community that thinks PGP is just dandy, and therefore evangelize the hell out of it to unsuspecting people, are the same kind of people that happily use XMPP+OMEMO, Matrix, or weird Signal forks that remove forward secrecy and think it’s fine.
Not to mince words: The same people who believe PGP is good are also famously not great at cryptography engineering.
If you’re going to outsource your opinions on privacy technology to someone else, make sure it’s someone who has actually found vulnerabilities in cryptographic software before. Most evangelists have not.
CMYKatI’m not here to litigate the demerits of PGP. The Latacora article I linked above makes the same arguments I would make today, and is a more entertaining read.
It is of my opinion as a security engineer that specializes in applied cryptography that nobody should use PGP, because there’s virtually always a better tool for the job you want to use PGP for.
(And for the uncommon use cases, offering a secure, purpose-built replacement is a work-in-progress.)
Note: I’m deliberately being blunt in this post because literally more than a decade of softspokenness from cryptography experts has done nothing to talk users off the PGP cliff. Being direct seems more effective than being tactful.
If you want a gentler touch, ask your cryptographer. If you don’t have a cryptographer, hire one.
If you can accept that every billionaire is the result of a failed system, that’s how cryptographers feel about people using PGP.
Instead, let’s examine the “use cases” of PGP and what you should be using instead. (Some of this is redundant with the Latacora article, but I’m also writing it 5 years later, so some things have changed.)
CMYKatI’m focusing on the “what” in this post, not the “why”. If you want to know the why, read the Latacora blog, or the Matthew Green blog.
If you’re curious about the credibility of my recommendations, read my other blog posts or ask your cryptographer.
Instead of PGP, Use This
This section contains specific tools to solve the same problems that PGP tries to solve, but better.
What makes these recommendations better than PGP?
Simply, they don’t make cryptographers want to run the other way screaming when they look under the hood. PGP does.
Some people are forced to use PGP because they work for a government that legally requires them to use PGP. In that corner case, your hands are tied by lawyers, so you don’t need to bother with what cryptographers recommend.
CMYKatSigning Software Distributions
Use Sigstore.
Note that this is an ecosystem-wide consideration, not something that specific individuals must manually opt into for each of their hobby projects. The only downside to Sigstore is it hasn’t been widely adopted yet.
If you’re a Python developer, you can just use PEP 740 to get attestations with Trusted Publishers, which gives you Sigstore for free. For most developers, this is as simple as setting up a GitHub Action to publish to PyPI.
This is a developing trend: Other programming language and package management ecosystems are following suit. I expect to see Sigstore attestations baked into NPM and Maven before the next US presidential election. With any luck, your favorite programming language could be on this list too.
Sigstore doesn’t just give you a signature that you check with a long-lived public key, nor does it require you to do the Web Of Trust rigamarole.
Rather, Sigstore gives you a lot for free. Sigstore was designed around ephemeral signing certificates rather than a long-lived private key. It was purpose-built for preventing supply-chain attacks against open source software.
Combined with Reproducible Builds, Sigstore solves the triangle of secure code delivery.
Alternatively, use minisign. If your package ecosystem doesn’t support Sigstore yet, you can get by with minisign (which is signify-compatible) until they modernize.
You can also use SSH signatures, if you’d prefer. (More on that below.)
CMYKatSigning Git Tags/Commits
Use SSH Signatures, not PGP signatures.
With Ed25519. Stop using RSA.
Art by HarubakiSending Files Between Computers
Use Magic Wormhole.
You could also use SSH + rsync to do this job. That’s fine too.
CMYKatEncrypting Backups
Tarsnap is the usual recommendation here.
There are a lot of other encrypted backup tools that work fine, if you don’t want to give Colin Percival your business. I don’t have a financial stake in any of them, nor have I audited them thoroughly.
Borg uses reasonable cryptography, but I haven’t had the time to review it carefully.
Kopia looks fine, but I really hate that they misuse “zero knowledge” to describe an encryption protocol (rather than a proof system). We should not reward this misbehavior by marketers.
The point is: You’ve got options.
Too many options, in my opinion, to settle for PGP.
CMYKatEncrypting Application Data
Avoid: OpenPGP, OpenSSL and its competitors.
Not a lot to say here. I’ve written a lot about this over the years. Misuse-resistant cryptography libraries–especially ones that make key management less painful for users–are the way to go.
HarubakiEncrypting Files
Use age.
Age is what PGP file encryption would be if PGP didn’t suck shit.
Age has two modes: Public-key encryption, and password-based key derivation.
Here’s a quick comparison table between what age offers, and what PGP uses in the installed base:
agePGPData encryption modeAEAD (ChaPoly)CAST5 (64-bit block cipher) in CFB mode with a strippable SHA1 “MDC”Key-commitmentYes (via the header)Pah! You wish! Dream on.
PGP isn’t even AEAD.Password KDF memory hard?Yes, with scrypt.No.Vulnerable to chosen-ciphertext attacks?No.Yes, but PGP proponents stupidly consider this a good thing.Supports 90’s-era cryptography?No.Yes.Releases unauthenticated plaintext?No.Yes.Uses versioned protocols rather than “cipher agility”?Yes.No. See: 90’s era cryptography.Most common implementations are memory-safe?Yes (Go, Rust).No (C).Like, it’s not even close.
CMYKatSome PGP proponents will insist that AEAD is possible now, but as long as the installed base of PGP remains backwards compatible with the lowest common denominator, that’s what your software uses.
Just use age. Or rage, if you’re a Rust enthusiast.
(And if you have concerns about “which age key should I trust?”, I’m already planning an age-v1 extension for the Public Key Directory project. More on that below.)
Art by ScruffPrivate Messaging
Use Signal.
Security teams around the world insist that they need PGP for bug bounty submissions or security operations, but Signal does this job better than PGP ever did.
Once upon a time, you needed to give people a phone number to use Signal, but that hasn’t been the case for a long time. Still, many people have missed that memo and think it’s a requirement.
My Signal username is soatok.45. Go ahead and message me. You won’t learn my phone number that way.
In the near future, I plan on developing end-to-end encryption for direct messages on the Fediverse (including Mastodon). This is what motivated my work on the Public Key Directory to begin with.
But this is not intended to be a Signal competitor by any measure. It’s a bar-raising activity, nothing more.
CMYKatI understand some people don’t like or trust Signal for whatever reason, but every single alternative that’s been suggested to Signal has offered inferior cryptography to Signal’s. So I will continue to recommend Signal.
Miscellaneous PGP Alternatives
This section contains things people think they need PGP for.
Identity Verification
I’m actively working on something better!
via XKCDIf you want the ability to vend a transparently verifiable public key for a given user, that’s one of the use cases for the Public Key Directory I’m designing in order to build end-to-end encryption for the Fediverse.
Although this is purpose-built for the Fediverse, I’ve deliberately included support for Auxiliary Data messages, whose formats will be specified by protocol extensions.
Rather than trying to grok the Web-of-Trust, you can simply have your software check that multiple independent Public Key Directories have verified the record, since its inclusion is published in an append-only transparency log, secured by a Merkle tree.
My design doesn’t preclude any manual key verification, or key-signing parties, or whatever other PGP cultural weirdness you want to do with these public keys. It just establishes a baseline trustworthiness even if you’re not a paranoid computer nerd.
My project isn’t finished yet. In the meantime, you can manually check public keys when using the other recommendations on this page.
HarubakiEncrypted Email
Don’t encrypt email. From the Latacora article:
Email is insecure. Even with PGP, it’s default-plaintext, which means that even if you do everything right, some totally reasonable person you mail, doing totally reasonable things, will invariably CC the quoted plaintext of your encrypted message to someone else (we don’t know a PGP email user who hasn’t seen this happen). PGP email is forward-insecure. Email metadata, including the subject (which is literally message content), are always plaintext.
There isn’t a recommendation for encrypted email because that’s not a thing people should be doing.
Art by AJNow, there exists a minority of extremely technical computer user for which Signal is a nonstarter (because you need a smartphone and valid phone number to enroll in the first place).
Because those people are generally not the highest priority of cryptographers (who are commonly focused on the privacy of common folk–including people in poor and developing countries where smartphones are more common than desktop computers), there presently isn’t really a good recommendation for private messaging that meets their constraints.
Certainly not PGP, either.
What PGP offers here is security theater: the illusion of safety. But it’s not actually a robust private communication mechanism, as Latacora argues.
CMYKat“I insist that I need encrypted email!”
If you find someone insisting that they “need” encrypted email, read up on the XY Problem. In a lot of cases, that’s what’s happening here.
Do they ipso facto need email (as in, specifically the email protocols and email software)?
And do they care more about this constraint, or the privacy of their communications?
Because if their goal just to communicate privately, see above.
If the tool they’re using being email is more important than privacy, they should consider sending empty messages with an attachment, and use age to encrypt the actual message before attaching it.
That’s serviceable, just beware that everything Latacora wrote about encrypted emails still applies to your use case, so expect someone to CC or forward your message as plaintext.
(Unless you’re legally required to use PGP because of a government regulation… in which case, why do you care about my recommendations if you’re chained by the ankle to your government’s bad technology choices?)
Finally, miss me with the “but someone can screenshot Signal” genre of objections.
As Latacora noted, people accidentally fuck up PGP all the time! It’s very easy to do.
Conversely, you have to deliberately leak something from Signal. There is no plaintext mode.
That’s the fucking bar you need to meet to compete with Signal.
PGP fails to be a Signal competitor, in ways that are worse than Threema, Matrix, or OMEMO.
Watch This Space
With all that said, I am actually designing an encrypted messaging protocol that will have an email-like user experience, except:
- Everything is always end-to-end encrypted, with forward secrecy.
- It’s not backwards compatible with insecure email.
- It doesn’t use PGP, or any 1990’s era cryptography.
I can’t promise a release date yet. I’m prioritizing end-to-end encryption for the Fediverse before I write the specification for that project (tentatively called AWOO, but the cryptography underpinning both projects should be similar).
Maybe 2026? We’ll see!
If someone beats me to the punch, and their design is actually good, I’ll update the post and replace this with a specific recommendation.
CMYKatAgainst PGP
I don’t know how to get the message out louder or clearer about how cryptographers feel about PGP than what I wrote here.
Latacora wrote their criticism in 2019. As I write this, 2024 is almost over. When will the PGP-induced madness end?
CMYKatExperts are not divided here. There is no controversy to teach.
Every time a cryptographer has talked about PGP, it’s been to complain about how bad it is and opine that people shouldn’t be using it.
If you’ve read this far, you already know what you should be using instead.
Header art credits: CMYKat and the GnuPG logo.
Update (2024-11-16)
Someone tried to use their Fediverse software to submit an anti-furry comment to this blog post.
Therefore, I’ve added more furry art to it.
loviesophieeIf you’re curious about the cryptography used by other messaging apps, please refer to this page that collects my blogs about this topic.
#alternatives #codeSigning #digitalSignatures #encryption #PGP #security #SecurityGuidance #signing
-
What To Use Instead of PGP
It’s been more than five years since The PGP Problem was published, and I still hear from people who believe that using PGP (whether GnuPG or another OpenPGP implementation) is a thing they should be doing.
It isn’t.
I don’t blame individual Internet users for this confusion. There is a lot of cargo-culting around communication tools in the software community, and the evangelists for the various projects muddy the waters for the rest of us.
HarubakiThe part of the free and open source software community that thinks PGP is just dandy, and therefore evangelize the hell out of it to unsuspecting people, are the same kind of people that happily use XMPP+OMEMO, Matrix, or weird Signal forks that remove forward secrecy and think it’s fine.
Not to mince words: The same people who believe PGP is good are also famously not great at cryptography engineering.
If you’re going to outsource your opinions on privacy technology to someone else, make sure it’s someone who has actually found vulnerabilities in cryptographic software before. Most evangelists have not.
CMYKatI’m not here to litigate the demerits of PGP. The Latacora article I linked above makes the same arguments I would make today, and is a more entertaining read.
It is of my opinion as a security engineer that specializes in applied cryptography that nobody should use PGP, because there’s virtually always a better tool for the job you want to use PGP for.
(And for the uncommon use cases, offering a secure, purpose-built replacement is a work-in-progress.)
Note: I’m deliberately being blunt in this post because literally more than a decade of softspokenness from cryptography experts has done nothing to talk users off the PGP cliff. Being direct seems more effective than being tactful.
If you want a gentler touch, ask your cryptographer. If you don’t have a cryptographer, hire one.
If you can accept that every billionaire is the result of a failed system, that’s how cryptographers feel about people using PGP.
Instead, let’s examine the “use cases” of PGP and what you should be using instead. (Some of this is redundant with the Latacora article, but I’m also writing it 5 years later, so some things have changed.)
CMYKatI’m focusing on the “what” in this post, not the “why”. If you want to know the why, read the Latacora blog, or the Matthew Green blog.
If you’re curious about the credibility of my recommendations, read my other blog posts or ask your cryptographer.
Instead of PGP, Use This
This section contains specific tools to solve the same problems that PGP tries to solve, but better.
What makes these recommendations better than PGP?
Simply, they don’t make cryptographers want to run the other way screaming when they look under the hood. PGP does.
Some people are forced to use PGP because they work for a government that legally requires them to use PGP. In that corner case, your hands are tied by lawyers, so you don’t need to bother with what cryptographers recommend.
CMYKatSigning Software Distributions
Use Sigstore.
Note that this is an ecosystem-wide consideration, not something that specific individuals must manually opt into for each of their hobby projects. The only downside to Sigstore is it hasn’t been widely adopted yet.
If you’re a Python developer, you can just use PEP 740 to get attestations with Trusted Publishers, which gives you Sigstore for free. For most developers, this is as simple as setting up a GitHub Action to publish to PyPI.
This is a developing trend: Other programming language and package management ecosystems are following suit. I expect to see Sigstore attestations baked into NPM and Maven before the next US presidential election. With any luck, your favorite programming language could be on this list too.
Sigstore doesn’t just give you a signature that you check with a long-lived public key, nor does it require you to do the Web Of Trust rigamarole.
Rather, Sigstore gives you a lot for free. Sigstore was designed around ephemeral signing certificates rather than a long-lived private key. It was purpose-built for preventing supply-chain attacks against open source software.
Combined with Reproducible Builds, Sigstore solves the triangle of secure code delivery.
Alternatively, use minisign. If your package ecosystem doesn’t support Sigstore yet, you can get by with minisign (which is signify-compatible) until they modernize.
You can also use SSH signatures, if you’d prefer. (More on that below.)
CMYKatSigning Git Tags/Commits
Use SSH Signatures, not PGP signatures.
With Ed25519. Stop using RSA.
Art by HarubakiSending Files Between Computers
Use Magic Wormhole.
You could also use SSH + rsync to do this job. That’s fine too.
CMYKatEncrypting Backups
Tarsnap is the usual recommendation here.
There are a lot of other encrypted backup tools that work fine, if you don’t want to give Colin Percival your business. I don’t have a financial stake in any of them, nor have I audited them thoroughly.
Borg uses reasonable cryptography, but I haven’t had the time to review it carefully.
Kopia looks fine, but I really hate that they misuse “zero knowledge” to describe an encryption protocol (rather than a proof system). We should not reward this misbehavior by marketers.
The point is: You’ve got options.
Too many options, in my opinion, to settle for PGP.
CMYKatEncrypting Application Data
Avoid: OpenPGP, OpenSSL and its competitors.
Not a lot to say here. I’ve written a lot about this over the years. Misuse-resistant cryptography libraries–especially ones that make key management less painful for users–are the way to go.
HarubakiEncrypting Files
Use age.
Age is what PGP file encryption would be if PGP didn’t suck shit.
Age has two modes: Public-key encryption, and password-based key derivation.
Here’s a quick comparison table between what age offers, and what PGP uses in the installed base:
agePGPData encryption modeAEAD (ChaPoly)CAST5 (64-bit block cipher) in CFB mode with a strippable SHA1 “MDC”Key-commitmentYes (via the header)Pah! You wish! Dream on.
PGP isn’t even AEAD.Password KDF memory hard?Yes, with scrypt.No.Vulnerable to chosen-ciphertext attacks?No.Yes, but PGP proponents stupidly consider this a good thing.Supports 90’s-era cryptography?No.Yes.Releases unauthenticated plaintext?No.Yes.Uses versioned protocols rather than “cipher agility”?Yes.No. See: 90’s era cryptography.Most common implementations are memory-safe?Yes (Go, Rust).No (C).Like, it’s not even close.
CMYKatSome PGP proponents will insist that AEAD is possible now, but as long as the installed base of PGP remains backwards compatible with the lowest common denominator, that’s what your software uses.
Just use age. Or rage, if you’re a Rust enthusiast.
(And if you have concerns about “which age key should I trust?”, I’m already planning an age-v1 extension for the Public Key Directory project. More on that below.)
Art by ScruffPrivate Messaging
Use Signal.
Security teams around the world insist that they need PGP for bug bounty submissions or security operations, but Signal does this job better than PGP ever did.
Once upon a time, you needed to give people a phone number to use Signal, but that hasn’t been the case for a long time. Still, many people have missed that memo and think it’s a requirement.
My Signal username is soatok.45. Go ahead and message me. You won’t learn my phone number that way.
In the near future, I plan on developing end-to-end encryption for direct messages on the Fediverse (including Mastodon). This is what motivated my work on the Public Key Directory to begin with.
But this is not intended to be a Signal competitor by any measure. It’s a bar-raising activity, nothing more.
CMYKatI understand some people don’t like or trust Signal for whatever reason, but every single alternative that’s been suggested to Signal has offered inferior cryptography to Signal’s. So I will continue to recommend Signal.
Miscellaneous PGP Alternatives
This section contains things people think they need PGP for.
Identity Verification
I’m actively working on something better!
via XKCDIf you want the ability to vend a transparently verifiable public key for a given user, that’s one of the use cases for the Public Key Directory I’m designing in order to build end-to-end encryption for the Fediverse.
Although this is purpose-built for the Fediverse, I’ve deliberately included support for Auxiliary Data messages, whose formats will be specified by protocol extensions.
Rather than trying to grok the Web-of-Trust, you can simply have your software check that multiple independent Public Key Directories have verified the record, since its inclusion is published in an append-only transparency log, secured by a Merkle tree.
My design doesn’t preclude any manual key verification, or key-signing parties, or whatever other PGP cultural weirdness you want to do with these public keys. It just establishes a baseline trustworthiness even if you’re not a paranoid computer nerd.
My project isn’t finished yet. In the meantime, you can manually check public keys when using the other recommendations on this page.
HarubakiEncrypted Email
Don’t encrypt email. From the Latacora article:
Email is insecure. Even with PGP, it’s default-plaintext, which means that even if you do everything right, some totally reasonable person you mail, doing totally reasonable things, will invariably CC the quoted plaintext of your encrypted message to someone else (we don’t know a PGP email user who hasn’t seen this happen). PGP email is forward-insecure. Email metadata, including the subject (which is literally message content), are always plaintext.
There isn’t a recommendation for encrypted email because that’s not a thing people should be doing.
Art by AJNow, there exists a minority of extremely technical computer user for which Signal is a nonstarter (because you need a smartphone and valid phone number to enroll in the first place).
Because those people are generally not the highest priority of cryptographers (who are commonly focused on the privacy of common folk–including people in poor and developing countries where smartphones are more common than desktop computers), there presently isn’t really a good recommendation for private messaging that meets their constraints.
Certainly not PGP, either.
What PGP offers here is security theater: the illusion of safety. But it’s not actually a robust private communication mechanism, as Latacora argues.
CMYKat“I insist that I need encrypted email!”
If you find someone insisting that they “need” encrypted email, read up on the XY Problem. In a lot of cases, that’s what’s happening here.
Do they ipso facto need email (as in, specifically the email protocols and email software)?
And do they care more about this constraint, or the privacy of their communications?
Because if their goal just to communicate privately, see above.
If the tool they’re using being email is more important than privacy, they should consider sending empty messages with an attachment, and use age to encrypt the actual message before attaching it.
That’s serviceable, just beware that everything Latacora wrote about encrypted emails still applies to your use case, so expect someone to CC or forward your message as plaintext.
(Unless you’re legally required to use PGP because of a government regulation… in which case, why do you care about my recommendations if you’re chained by the ankle to your government’s bad technology choices?)
Finally, miss me with the “but someone can screenshot Signal” genre of objections.
As Latacora noted, people accidentally fuck up PGP all the time! It’s very easy to do.
Conversely, you have to deliberately leak something from Signal. There is no plaintext mode.
That’s the fucking bar you need to meet to compete with Signal.
PGP fails to be a Signal competitor, in ways that are worse than Threema, Matrix, or OMEMO.
Watch This Space
With all that said, I am actually designing an encrypted messaging protocol that will have an email-like user experience, except:
- Everything is always end-to-end encrypted, with forward secrecy.
- It’s not backwards compatible with insecure email.
- It doesn’t use PGP, or any 1990’s era cryptography.
I can’t promise a release date yet. I’m prioritizing end-to-end encryption for the Fediverse before I write the specification for that project (tentatively called AWOO, but the cryptography underpinning both projects should be similar).
Maybe 2026? We’ll see!
If someone beats me to the punch, and their design is actually good, I’ll update the post and replace this with a specific recommendation.
CMYKatAgainst PGP
I don’t know how to get the message out louder or clearer about how cryptographers feel about PGP than what I wrote here.
Latacora wrote their criticism in 2019. As I write this, 2024 is almost over. When will the PGP-induced madness end?
CMYKatExperts are not divided here. There is no controversy to teach.
Every time a cryptographer has talked about PGP, it’s been to complain about how bad it is and opine that people shouldn’t be using it.
If you’ve read this far, you already know what you should be using instead.
Header art credits: CMYKat and the GnuPG logo.
Update (2024-11-16)
Someone tried to use their Fediverse software to submit an anti-furry comment to this blog post.
Therefore, I’ve added more furry art to it.
loviesophieeIf you’re curious about the cryptography used by other messaging apps, please refer to this page that collects my blogs about this topic.
#alternatives #codeSigning #digitalSignatures #encryption #PGP #security #SecurityGuidance #signing
-
What To Use Instead of PGP
It’s been more than five years since The PGP Problem was published, and I still hear from people who believe that using PGP (whether GnuPG or another OpenPGP implementation) is a thing they should be doing.
It isn’t.
I don’t blame individual Internet users for this confusion. There is a lot of cargo-culting around communication tools in the software community, and the evangelists for the various projects muddy the waters for the rest of us.
HarubakiThe part of the free and open source software community that thinks PGP is just dandy, and therefore evangelize the hell out of it to unsuspecting people, are the same kind of people that happily use XMPP+OMEMO, Matrix, or weird Signal forks that remove forward secrecy and think it’s fine.
Not to mince words: The same people who believe PGP is good are also famously not great at cryptography engineering.
If you’re going to outsource your opinions on privacy technology to someone else, make sure it’s someone who has actually found vulnerabilities in cryptographic software before. Most evangelists have not.
CMYKatI’m not here to litigate the demerits of PGP. The Latacora article I linked above makes the same arguments I would make today, and is a more entertaining read.
It is of my opinion as a security engineer that specializes in applied cryptography that nobody should use PGP, because there’s virtually always a better tool for the job you want to use PGP for.
(And for the uncommon use cases, offering a secure, purpose-built replacement is a work-in-progress.)
Note: I’m deliberately being blunt in this post because literally more than a decade of softspokenness from cryptography experts has done nothing to talk users off the PGP cliff. Being direct seems more effective than being tactful.
If you want a gentler touch, ask your cryptographer. If you don’t have a cryptographer, hire one.
If you can accept that every billionaire is the result of a failed system, that’s how cryptographers feel about people using PGP.
Instead, let’s examine the “use cases” of PGP and what you should be using instead. (Some of this is redundant with the Latacora article, but I’m also writing it 5 years later, so some things have changed.)
CMYKatInstead of PGP, Use This
This section contains specific tools to solve the same problems that PGP tries to solve, but better.
What makes these recommendations better than PGP?
Simply, they don’t make cryptographers want to run the other way screaming when they look under the hood. PGP does.
Some people are forced to use PGP because they work for a government that legally requires them to use PGP. In that corner case, your hands are tied by lawyers, so you don’t need to bother with what cryptographers recommend.
CMYKatSigning Software Distributions
Use Sigstore.
Note that this is an ecosystem-wide consideration, not something that specific individuals must manually opt into for each of their hobby projects. The only downside to Sigstore is it hasn’t been widely adopted yet.
If you’re a Python developer, you can just use PEP 740 to get attestations with Trusted Publishers, which gives you Sigstore for free. For most developers, this is as simple as setting up a GitHub Action to publish to PyPI.
This is a developing trend: Other programming language and package management ecosystems are following suit. I expect to see Sigstore attestations baked into NPM and Maven before the next US presidential election. With any luck, your favorite programming language could be on this list too.
Sigstore doesn’t just give you a signature that you check with a long-lived public key, nor does it require you to do the Web Of Trust rigamarole.
Rather, Sigstore gives you a lot for free. Sigstore was designed around ephemeral signing certificates rather than a long-lived private key. It was purpose-built for preventing supply-chain attacks against open source software.
Combined with Reproducible Builds, Sigstore solves the triangle of secure code delivery.
Alternatively, use minisign. If your package ecosystem doesn’t support Sigstore yet, you can get by with minisign (which is signify-compatible) until they modernize.
You can also use SSH signatures, if you’d prefer. (More on that below.)
CMYKatSigning Git Tags/Commits
Use SSH Signatures, not PGP signatures.
With Ed25519. Stop using RSA.
Art by HarubakiSending Files Between Computers
Use Magic Wormhole.
You could also use SSH + rsync to do this job. That’s fine too.
CMYKatEncrypting Backups
Tarsnap is the usual recommendation here.
There are a lot of other encrypted backup tools that work fine, if you don’t want to give Colin Percival your business. I don’t have a financial stake in any of them, nor have I audited them thoroughly.
Borg uses reasonable cryptography, but I haven’t had the time to review it carefully.
Kopia looks fine, but I really hate that they misuse “zero knowledge” to describe an encryption protocol (rather than a proof system). We should not reward this misbehavior by marketers.
The point is: You’ve got options.
Too many options, in my opinion, to settle for PGP.
CMYKatEncrypting Application Data
Avoid: OpenPGP, OpenSSL and its competitors.
Not a lot to say here. I’ve written a lot about this over the years. Misuse-resistant cryptography libraries–especially ones that make key management less painful for users–are the way to go.
HarubakiEncrypting Files
Use age.
Age is what PGP file encryption would be if PGP didn’t suck shit.
Age has two modes: Public-key encryption, and password-based key derivation.
Here’s a quick comparison table between what age offers, and what PGP uses in the installed base:
agePGPData encryption modeAEAD (ChaPoly)CAST5 (64-bit block cipher) in CFB mode with a strippable SHA1 “MDC”Key-commitmentYes (via the header)Pah! You wish! Dream on.
PGP isn’t even AEAD.Password KDF memory hard?Yes, with scrypt.No.Vulnerable to chosen-ciphertext attacks?No.Yes, but PGP proponents stupidly consider this a good thing.Supports 90’s-era cryptography?No.Yes.Releases unauthenticated plaintext?No.Yes.Uses versioned protocols rather than “cipher agility”?Yes.No. See: 90’s era cryptography.Most common implementations are memory-safe?Yes (Go, Rust).No (C).Like, it’s not even close.
CMYKatSome PGP proponents will insist that AEAD is possible now, but as long as the installed base of PGP remains backwards compatible with the lowest common denominator, that’s what your software uses.
Just use age. Or rage, if you’re a Rust enthusiast.
(And if you have concerns about “which age key should I trust?”, I’m already planning an age-v1 extension for the Public Key Directory project. More on that below.)
Art by ScruffPrivate Messaging
Use Signal.
Security teams around the world insist that they need PGP for bug bounty submissions or security operations, but Signal does this job better than PGP ever did.
Once upon a time, you needed to give people a phone number to use Signal, but that hasn’t been the case for a long time. Still, many people have missed that memo and think it’s a requirement.
My Signal username is soatok.45. Go ahead and message me. You won’t learn my phone number that way.
In the near future, I plan on developing end-to-end encryption for direct messages on the Fediverse (including Mastodon). This is what motivated my work on the Public Key Directory to begin with.
But this is not intended to be a Signal competitor by any measure. It’s a bar-raising activity, nothing more.
CMYKatI understand some people don’t like or trust Signal for whatever reason, but every single alternative that’s been suggested to Signal has offered inferior cryptography to Signal’s. So I will continue to recommend Signal.
Miscellaneous PGP Alternatives
This section contains things people think they need PGP for.
Identity Verification
I’m actively working on something better!
via XKCDIf you want the ability to vend a transparently verifiable public key for a given user, that’s one of the use cases for the Public Key Directory I’m designing in order to build end-to-end encryption for the Fediverse.
Although this is purpose-built for the Fediverse, I’ve deliberately included support for Auxiliary Data messages, whose formats will be specified by protocol extensions.
Rather than trying to grok the Web-of-Trust, you can simply have your software check that multiple independent Public Key Directories have verified the record, since its inclusion is published in an append-only transparency log, secured by a Merkle tree.
My design doesn’t preclude any manual key verification, or key-signing parties, or whatever other PGP cultural weirdness you want to do with these public keys. It just establishes a baseline trustworthiness even if you’re not a paranoid computer nerd.
My project isn’t finished yet. In the meantime, you can manually check public keys when using the other recommendations on this page.
HarubakiEncrypted Email
Don’t encrypt email. From the Latacora article:
Email is insecure. Even with PGP, it’s default-plaintext, which means that even if you do everything right, some totally reasonable person you mail, doing totally reasonable things, will invariably CC the quoted plaintext of your encrypted message to someone else (we don’t know a PGP email user who hasn’t seen this happen). PGP email is forward-insecure. Email metadata, including the subject (which is literally message content), are always plaintext.
There isn’t a recommendation for encrypted email because that’s not a thing people should be doing.
Art by AJNow, there exists a minority of extremely technical computer user for which Signal is a nonstarter (because you need a smartphone and valid phone number to enroll in the first place).
Because those people are generally not the highest priority of cryptographers (who are commonly focused on the privacy of common folk–including people in poor and developing countries where smartphones are more common than desktop computers), there presently isn’t really a good recommendation for private messaging that meets their constraints.
Certainly not PGP, either.
What PGP offers here is security theater: the illusion of safety. But it’s not actually a robust private communication mechanism, as Latacora argues.
CMYKat“I insist that I need encrypted email!”
If you find someone insisting that they “need” encrypted email, read up on the XY Problem. In a lot of cases, that’s what’s happening here.
Do they ipso facto need email (as in, specifically the email protocols and email software)?
And do they care more about this constraint, or the privacy of their communications?
Because if their goal just to communicate privately, see above.
If the tool they’re using being email is more important than privacy, they should consider sending empty messages with an attachment, and use age to encrypt the actual message before attaching it.
That’s serviceable, just beware that everything Latacora wrote about encrypted emails still applies to your use case, so expect someone to CC or forward your message as plaintext.
(Unless you’re legally required to use PGP because of a government regulation… in which case, why do you care about my recommendations if you’re chained by the ankle to your government’s bad technology choices?)
Finally, miss me with the “but someone can screenshot Signal” genre of objections.
As Latacora noted, people accidentally fuck up PGP all the time! It’s very easy to do.
Conversely, you have to deliberately leak something from Signal. There is no plaintext mode.
That’s the fucking bar you need to meet to compete with Signal.
PGP fails to be a Signal competitor, in ways that are worse than Threema, Matrix, or OMEMO.
Watch This Space
With all that said, I am actually designing an encrypted messaging protocol that will have an email-like user experience, except:
- Everything is always end-to-end encrypted, with forward secrecy.
- It’s not backwards compatible with insecure email.
- It doesn’t use PGP, or any 1990’s era cryptography.
I can’t promise a release date yet. I’m prioritizing end-to-end encryption for the Fediverse before I write the specification for that project (tentatively called AWOO, but the cryptography underpinning both projects should be similar).
Maybe 2026? We’ll see!
If someone beats me to the punch, and their design is actually good, I’ll update the post and replace this with a specific recommendation.
CMYKatAgainst PGP
I don’t know how to get the message out louder or clearer about how cryptographers feel about PGP than what I wrote here.
Latacora wrote their criticism in 2019. As I write this, 2024 is almost over. When will the PGP-induced madness end?
CMYKatExperts are not divided here. There is no controversy to teach.
Every time a cryptographer has talked about PGP, it’s been to complain about how bad it is and opine that people shouldn’t be using it.
If you’ve read this far, you already know what you should be using instead.
Header art credits: CMYKat and the GnuPG logo.
Update (2024-11-16)
Someone tried to use their Fediverse software to submit an anti-furry comment to this blog post.
Therefore, I’ve added more furry art to it.
loviesophiee#alternatives #codeSigning #digitalSignatures #encryption #PGP #security #SecurityGuidance #signing
-
Going Bark: A Furry’s Guide to End-to-End Encryption
Governments are back on their anti-encryption bullshit again.
Between the U.S. Senate’s “EARN IT” Act, the E.U.’s slew of anti-encryption proposals, and Australia’s new anti-encryption law, it’s become clear that the authoritarians in office view online privacy as a threat to their existence.
Normally, when the governments increase their anti-privacy sabre-rattling, technologists start talking more loudly about Tor, Signal, and other privacy technologies (usually only to be drowned out by paranoid people who think Tor and Signal are government backdoors or something stupid; conspiracy theories ruin everything!).
I’m not going to do that.
Instead, I’m going to show you how to add end-to-end encryption to any communication software you’re developing. (Hopefully, I’ll avoid making any bizarre design decisions along the way.)
But first, some important disclaimers:
- Yes, you should absolutely do this. I don’t care how banal your thing is; if you expect people to use it to communicate with each other, you should make it so that you can never decrypt their communications.
- You should absolutely NOT bill the thing you’re developing as an alternative to Signal or WhatsApp.
- The goal of doing this is to increase the amount of end-to-end encryption deployed on the Internet that the service operator cannot decrypt (even if compelled by court order) and make E2EE normalized. The goal is NOT to compete with highly specialized and peer-reviewed privacy technology.
- I am not a lawyer, I’m some furry who works in cryptography. The contents of this blog post is not legal advice, nor is it endorsed by any company or organization. Ask the EFF for legal questions.
The organization of this blog post is as follows: First, I’ll explain how to encrypt and decrypt data between users, assuming you have a key. Next, I’ll explain how to build an authenticated key exchange and a ratcheting protocol to determine the keys used in the first step. Afterwards, I’ll explore techniques for binding authentication keys to identities and managing trust. Finally, I’ll discuss strategies for making it impractical to ever backdoor your software (and impossible to silently backdoor it), just to piss the creeps and tyrants of the world off even more.
You don’t have to implement the full stack of solutions to protect users, but the further you can afford to go, the safer your users will be from privacy-invasive policing.
(Art by Kyume.)Preliminaries
Choosing a Cryptography Library
In the examples contained on this page, I will be using the Sodium cryptography library. Specifically, my example code will be written with the Sodium-Plus library for JavaScript, since it strikes a good balance between performance and being cross-platform.
const { SodiumPlus } = require('sodium-plus');(async function() { // Select a backend automatically const sodium = await SodiumPlus.auto(); // Do other stuff here})();Libsodium is generally the correct choice for developing cryptography features in software, and is available in most programming languages,
If you’re prone to choose a different library, you should consult your cryptographer (and yes, you should have one on your payroll if you’re doing things different) about your design choices.
Threat Modelling
Remember above when I said, “You don’t have to implement the full stack of solutions to protect users, but the further you can afford to go, the safer your users will be from privacy-invasive policing”?
How far you go in implementing the steps outlined on this blog post should be informed by a threat model, not an ad hoc judgment.
For example, if you’re encrypting user data and storing it in the cloud, you probably want to pass the Mud Puddle Test:
1. First, drop your device(s) in a mud puddle.
2. Next, slip in said puddle and crack yourself on the head. When you regain consciousness you’ll be perfectly fine, but won’t for the life of you be able to recall your device passwords or keys.
3. Now try to get your cloud data back.Did you succeed? If so, you’re screwed. Or to be a bit less dramatic, I should say: your cloud provider has access to your ‘encrypted’ data, as does the government if they want it, as does any rogue employee who knows their way around your provider’s internal policy checks.
Matthew Green describes the Mud Puddle Test, which Apple products definitely don’t pass.
If you must fail the Mud Puddle Test for your users, make sure you’re clear and transparent about this in the documentation for your product or service.
(Art by Swizz.)I. Symmetric-Key Encryption
The easiest piece of this puzzle is to encrypt data in transit between both ends (thus, satisfying the loosest definition of end-to-end encryption).
At this layer, you already have some kind of symmetric key to use for encrypting data before you send it, and for decrypting it as you receive it.
For example, the following code will encrypt/decrypt strings and return hexadecimal strings with a version prefix.
const VERSION = "v1";/** * @param {string|Uint8Array} message * @param {Uint8Array} key * @param {string|null} assocData * @returns {string} */async function encryptData(message, key, assocData = null) { const nonce = await sodium.randombytes_buf(24); const aad = JSON.stringify({ 'version': VERSION, 'nonce': await sodium.sodium_bin2hex(nonce), 'extra': assocData }); const encrypted = await sodium.crypto_aead_xchacha20poly1305_ietf_encrypt( message, nonce, key, aad ); return ( VERSION + await sodium.sodium_bin2hex(nonce) + await sodium.sodium_bin2hex(encrypted) );}/** * @param {string|Uint8Array} message * @param {Uint8Array} key * @param {string|null} assocData * @returns {string} */async function decryptData(encrypted, key, assocData = null) { const ver = encrypted.slice(0, 2); if (!await sodium.sodium_memcmp(ver, VERSION)) { throw new Error("Incorrect version: " + ver); } const nonce = await sodium.sodium_hex2bin(encrypted.slice(2, 50)); const ciphertext = await sodium.sodium_hex2bin(encrypted.slice(50)); const aad = JSON.stringify({ 'version': ver, 'nonce': encrypted.slice(2, 50), 'extra': assocData }); const plaintext = await sodium.crypto_aead_xchacha20poly1305_ietf_decrypt( ciphertext, nonce, key, aad ); return plaintext.toString('utf-8');}Under-the-hood, this is using XChaCha20-Poly1305, which is less sensitive to timing leaks than AES-GCM. However, like AES-GCM, this encryption mode doesn’t provide message- or key-commitment.
If you want key commitment, you should derive two keys from
$keyusing a KDF based on hash functions: One for actual encryption, and the other as a key commitment value.If you want message commitment, you can use AES-CTR + HMAC-SHA256 or XChaCha20 + BLAKE2b-MAC.
If you want both, ask Taylor Campbell about his BLAKE3-based design.
A modified version of the above code with key-commitment might look like this:
const VERSION = "v2";/** * Derive an encryption key and a commitment hash. * @param {CryptographyKey} key * @param {Uint8Array} nonce * @returns {{encKey: CryptographyKey, commitment: Uint8Array}} */async function deriveKeys(key, nonce) { const encKey = new CryptographyKey(await sodium.crypto_generichash( new Uint8Array([0x01].append(nonce)), key )); const commitment = await sodium.crypto_generichash( new Uint8Array([0x02].append(nonce)), key ); return {encKey, commitment};}/** * @param {string|Uint8Array} message * @param {Uint8Array} key * @param {string|null} assocData * @returns {string} */async function encryptData(message, key, assocData = null) { const nonce = await sodium.randombytes_buf(24); const aad = JSON.stringify({ 'version': VERSION, 'nonce': await sodium.sodium_bin2hex(nonce), 'extra': assocData }); const {encKey, commitment} = await deriveKeys(key, nonce); const encrypted = await sodium.crypto_aead_xchacha20poly1305_ietf_encrypt( message, nonce, encKey, aad ); return ( VERSION + await sodium.sodium_bin2hex(nonce) + await sodium.sodium_bin2hex(commitment) + await sodium.sodium_bin2hex(encrypted) );}/** * @param {string|Uint8Array} message * @param {Uint8Array} key * @param {string|null} assocData * @returns {string} */async function decryptData(encrypted, key, assocData = null) { const ver = encrypted.slice(0, 2); if (!await sodium.sodium_memcmp(ver, VERSION)) { throw new Error("Incorrect version: " + ver); } const nonce = await sodium.sodium_hex2bin(encrypted.slice(2, 50)); const ciphertext = await sodium.sodium_hex2bin(encrypted.slice(114)); const aad = JSON.stringify({ 'version': ver, 'nonce': encrypted.slice(2, 50), 'extra': assocData }); const storedCommitment = await sodium.sodium_hex2bin(encrypted.slice(50, 114)); const {encKey, commitment} = await deriveKeys(key, nonce); if (!(await sodium.sodium_memcmp(storedCommitment, commitment))) { throw new Error("Incorrect commitment value"); } const plaintext = await sodium.crypto_aead_xchacha20poly1305_ietf_decrypt( ciphertext, nonce, encKey, aad ); return plaintext.toString('utf-8');}Another design choice you might make is to encode ciphertext with base64 instead of hexadecimal. That doesn’t significantly alter the design here, but it does mean your decoding logic has to accommodate this.
You SHOULD version your ciphertexts, and include this in the AAD provided to your AEAD encryption mode. I used “v1” and “v2” as a version string above, but you can use your software name for that too.
II. Key Agreement
If you’re not familiar with Elliptic Curve Diffie-Hellman or Authenticated Key Exhcanges, the two of the earliest posts on this blog were dedicated to those topics.
Key agreement in libsodium uses Elliptic Curve Diffie-Hellman over Curve25519, or X25519 for short.
There are many schools of thought for extending ECDH into an authenticated key exchange protocol.
We’re going to implement what the Signal Protocol calls X3DH instead of doing some interactive EdDSA + ECDH hybrid, because X3DH provides cryptographic deniability (see this section of the X3DH specification for more information).
For the moment, I’m going to assume a client-server model. That may or may not be appropriate for your design. You can substitute “the server” for “the other participant” in a peer-to-peer configuration.
Head’s up: This section of the blog post is code-heavy.
Update (November 23, 2020): I implemented this design in TypeScript, if you’d like something tangible to work with. I call my library, Rawr X3DH.
X3DH Pre-Key Bundles
Each participant will need to upload an Ed25519 identity key once (which is a detail covered in another section), which will be used to sign bundles of X25519 public keys to use for X3DH.
Your implementation will involve a fair bit of boilerplate, like so:
/** * Generate an X25519 keypair. * * @returns {{secretKey: X25519SecretKey, publicKey: X25519PublicKey}} */async function generateKeyPair() { const keypair = await sodium.crypto_box_keypair(); return { secretKey: await sodium.crypto_box_secretkey(keypair), publicKey: await sodium.crypto_box_publickey(keypair) };}/** * Generates some number of X25519 keypairs. * * @param {number} preKeyCount * @returns {{secretKey: X25519SecretKey, publicKey: X25519PublicKey}[]} */async function generateBundle(preKeyCount = 100) { const bundle = []; for (let i = 0; i < preKeyCount; i++) { bundle.push(await generateKeyPair()); } return bundle;}/** * BLAKE2b( len(PK) | PK_0, PK_1, ... PK_n ) * * @param {X25519PublicKey[]} publicKeys * @returns {Uint8Array} */async function prehashPublicKeysForSigning(publicKeys) { const hashState = await sodium.crypto_generichash_init(); // First, update the state with the number of public keys const pkLen = new Uint8Array([ (publicKeys.length >>> 24) & 0xff, (publicKeys.length >>> 16) & 0xff, (publicKeys.length >>> 8) & 0xff, publicKeys.length & 0xff ]); await sodium.crypto_generichash_update(hashState, pkLen); // Next, update the state with each public key for (let pk of publicKeys) { await sodium.crypto_generichash_update( hashState, pk.getBuffer() ); } // Return the finalized BLAKE2b hash return await sodium.crypto_generichash_final(hashState);}/** * Signs a bundle. Returns the signature. * * @param {Ed25519SecretKey} signingKey * @param {X25519PublicKey[]} publicKeys * @returns {Uint8Array} */async function signBundle(signingKey, publicKeys) { return sodium.crypto_sign_detached( await prehashPublicKeysForSigning(publicKeys), signingKey );}/** * This is just so you can see how verification looks. * * @param {Ed25519PublicKey} verificationKey * @param {X25519PublicKey[]} publicKeys * @param {Uint8Array} signature */async function verifyBundle(verificationKey, publicKeys, signature) { return sodium.crypto_sign_verify_detached( await prehashPublicKeysForSigning(publicKeys), verificationKey, signature );}This boilerplate exists just so you can do something like this:
/** * Generate some number of X25519 keypairs. * Persist the bundle. * Sign the bundle of publickeys with the Ed25519 secret key. * Return the signed bundle (which can be transmitted to the server.) * * @param {Ed25519SecretKey} signingKey * @param {number} numKeys * @returns {{signature: string, bundle: string[]}} */async function x3dh_pre_key(signingKey, numKeys = 100) { const bundle = await generateBundle(numKeys); const publicKeys = bundle.map(x => x.publicKey); const signature = await signBundle(signingKey, publicKeys); // This is a stub; how you persist it is app-specific: persistBundleNotDefinedHere(signingKey, bundle); // Hex-encode all the public keys const encodedBundle = []; for (let pk of publicKeys) { encodedBundle.push(await sodium.sodium_bin2hex(pk.getBuffer())); } return { 'signature': await sodium.sodium_bin2hex(signature), 'bundle': encodedBundle };}And then you can drop the output of
x3dh_pre_key(secretKey)into a JSON-encoded HTTP request.In accordance to Signal’s X3DH spec, you want to use
x3dh_pre_key(secretKey, 1)to generate the “signed pre-key” bundle andx3dn_pre_key(secretKey, 100)when pushing 100 one-time keys to the server.X3DH Initiation
This section conforms to the Sending the Initial Message section of the X3DH specification.
When you initiate a conversation, the server should provide you with a bundle containing:
- Your peer’s Identity key (an Ed25519 public key)
- Your peer’s current Signed Pre-Key (an X25519 public key)
- (If any remain unburned) One of your key’s One-Time Keys (an X25519 public key) — and then delete it
If we assume the structure of this response looks like this:
{ "IdentityKey": "...", "SignedPreKey": { "Signature": "..." "PreKey": "..." }, "OneTimeKey": "..." // or NULL}Then we can write the initiation step of the handshake like so:
/** * Get SK for initializing an X3DH handshake * * @param {object} r -- See previous code block * @param {Ed25519SecretKey} senderKey */async function x3dh_initiate_send_get_sk(r, senderKey) { const identityKey = new Ed25519PublicKey( await sodium.sodium_hex2bin(r.IdentityKey) ); const signedPreKey = new X25519PublicKey( await sodium.sodium_hex2bin(r.SignedPreKey.PreKey) ); const signature = await sodium.sodium_hex2bin(r.SignedPreKey.Signature); // Check signature const valid = await verifyBundle(identityKey, [signedPreKey], signature); if (!valid) { throw new Error("Invalid signature"); } const ephemeral = await generateKeyPair(); const ephSecret = ephemeral.secretKey; const ephPublic = ephemeral.publicKey; // Turn the Ed25519 keys into X25519 keys for X3DH: const senderX = await sodium.crypto_sign_ed25519_sk_to_curve25519(senderKey); const recipientX = await sodium.crypto_sign_ed25519_pk_to_curve25519(identityKey); // See the X3DH specification to really understand this part: const DH1 = await sodium.crypto_scalarmult(senderX, signedPreKey); const DH2 = await sodium.crypto_scalarmult(ephSecret, recipientX); const DH3 = await sodium.crypto_scalarmult(ephSecret, signedPreKey); let SK; if (r.OneTimeKey) { let DH4 = await sodium.crypto_scalarmult( ephSecret, new X25519PublicKey(await sodium.sodium_hex2bin(r.OneTimeKey)) ); SK = kdf(new Uint8Array( [].concat(DH1.getBuffer()) .concat(DH2.getBuffer()) .concat(DH3.getBuffer()) .concat(DH4.getBuffer()) )); DH4.wipe(); } else { SK = kdf(new Uint8Array( [].concat(DH1.getBuffer()) .concat(DH2.getBuffer()) .concat(DH3.getBuffer()) )); } // Wipe keys DH1.wipe(); DH2.wipe(); DH3.wipe(); ephSecret.wipe(); senderX.wipe(); return { IK: identityKey, EK: ephPublic, SK: SK, OTK: r.OneTimeKey // might be NULL };}/** * Initialize an X3DH handshake * * @param {string} recipientIdentity - Some identifier for the user * @param {Ed25519SecretKey} secretKey - Sender's secret key * @param {Ed25519PublicKey} publicKey - Sender's public key * @param {string} message - The initial message to send * @returns {object} */async function x3dh_initiate_send(recipientIdentity, secretKey, publicKey, message) { const r = await get_server_response(recipientIdentity); const {IK, EK, SK, OTK} = await x3dh_initiate_send_get_sk(r, secretKey); const assocData = await sodium.sodium_bin2hex( new Uint8Array( [].concat(publicKey.getBuffer()) .concat(IK.getBuffer()) ) ); /* * We're going to set the session key for our recipient to SK. * This might invoke a ratchet. * * Either SK or the output of the ratchet derived from SK * will be returned by getEncryptionKey(). */ await setSessionKey(recipientIdentity, SK); const encrypted = await encryptData( message, await getEncryptionKey(recipientIdentity), assocData ); return { "Sender": my_identity_string, "IdentityKey": await sodium.sodium_bin2hex(publicKey), "EphemeralKey": await sodium.sodium_bin2hex(EK), "OneTimeKey": OTK, "CipherText": encrypted };}We didn’t define
setSessionKey()orgetEncryptionKey()above. It will be covered later.X3DH – Receiving an Initial Message
This section implements the Receiving the Initial Message section of the X3DH Specification.
We’re going to assume the structure of the request looks like this:
{ "Sender": "...", "IdentityKey": "...", "EphemeralKey": "...", "OneTimeKey": "...", "CipherText": "..."}The code to handle this should look like this:
/** * Handle an X3DH initiation message as a receiver * * @param {object} r -- See previous code block * @param {Ed25519SecretKey} identitySecret * @param {Ed25519PublicKey} identityPublic * @param {Ed25519SecretKey} preKeySecret */async function x3dh_initiate_recv_get_sk( r, identitySecret, identityPublic, preKeySecret) { // Decode strings const senderIdentityKey = new Ed25519PublicKey( await sodium.sodium_hex2bin(r.IdentityKey), ); const ephemeral = new X25519PublicKey( await sodium.sodium_hex2bin(r.EphemeralKey), ); // Ed25519 -> X25519 const senderX = await sodium.crypto_sign_ed25519_pk_to_curve25519(senderIdentityKey); const recipientX = await sodium.crypto_sign_ed25519_sk_to_curve25519(identitySecret); // See the X3DH specification to really understand this part: const DH1 = await sodium.crypto_scalarmult(preKeySecret, senderX); const DH2 = await sodium.crypto_scalarmult(recipientX, ephemeral); const DH3 = await sodium.crypto_scalarmult(preKeySecret, ephemeral); let SK; if (r.OneTimeKey) { let DH4 = await sodium.crypto_scalarmult( await fetchAndWipeOneTimeSecretKey(r.OneTimeKey), ephemeral ); SK = kdf(new Uint8Array( [].concat(DH1.getBuffer()) .concat(DH2.getBuffer()) .concat(DH3.getBuffer()) .concat(DH4.getBuffer()) )); DH4.wipe(); } else { SK = kdf(new Uint8Array( [].concat(DH1.getBuffer()) .concat(DH2.getBuffer()) .concat(DH3.getBuffer()) )); } // Wipe keys DH1.wipe(); DH2.wipe(); DH3.wipe(); recipientX.wipe(); return { Sender: r.Sender, SK: SK, IK: senderIdentityKey };}/** * Initiate an X3DH handshake as a recipient * * @param {object} req - Request object * @returns {string} - The initial message */async function x3dh_initiate_recv(req) { const {identitySecret, identityPublic} = await getIdentityKeypair(); const {preKeySecret, preKeyPublic} = await getPreKeyPair(); const {Sender, SK, IK} = await x3dh_initiate_recv_get_sk( req, identitySecret, identityPublic, preKeySecret, preKeyPublic ); const assocData = await sodium.sodium_bin2hex( new Uint8Array( [].concat(IK.getBuffer()) .concat(identityPublic.getBuffer()) ) ); try { await setSessionKey(senderIdentity, SK); return decryptData( req.CipherText, await getEncryptionKey(senderIdentity), assocData ); } catch (e) { await destroySessionKey(senderIdentity); throw e; }}And with that, you’ve successfully implemented X3DH and symmetric encryption in JavaScript.
We abstracted some of the details away (i.e.
kdf(), the transport mechanisms, the session key management mechanisms, and a few others). Some of them will be highly specific to your application, so it doesn’t make a ton of sense to flesh them out.One thing to keep in mind: According to the X3DH specification, participants should regularly (e.g. weekly) replace their Signed Pre-Key in the server with a fresh one. They should also publish more One-Time Keys when they start to run low.
If you’d like to see a complete reference implementation of X3DH, as I mentioned before, Rawr-X3DH implements it in TypeScript.
Session Key Management
Using X3DH to for every message is inefficient and unnecessary. Even the Signal Protocol doesn’t do that.
Instead, Signal specifies a Double Ratchet protocol that combines a Symmetric-Key Ratchet on subsequent messages, and a Diffie-Hellman-based ratcheting protocol.
Signal even specifies integration guidelines for the Double Ratchet with X3DH.
It’s worth reading through the specification to understand their usages of Key-Derivation Functions (KDFs) and KDF Chains.
Although it is recommended to use HKDF as the Signal protocol specifies, you can strictly speaking use any secure keyed PRF to accomplish the same goal.
What follows is an example of a symmetric KDF chain that uses BLAKE2b with 512-bit digests of the current session key; the leftmost half of the BLAKE2b digest becomes the new session key, while the rightmost half becomes the encryption key.
const SESSION_KEYS = {};/** * Note: In reality you'll want to have two separate sessions: * One for receiving data, one for sending data. * * @param {string} identity * @param {CryptographyKey} key */async function setSessionKey(identity, key) { SESSION_KEYS[identity] = key;}async function getEncryptionKey(identity) { if (!SESSION_KEYS[identity]) { throw new Error("No session key for " + identity"); } const blake2bMac = await sodium.crypto_generichash( SESSION_KEYS[identity], null, 64 ); SESSION_KEYS[identity] = new CryptographyKey(blake2bMac.slice(0, 32)); return new CryptographyKey(blake2bMac.slice(32, 64));}In the interest of time, a full DHRatchet implementation is left as an exercise to the reader (since it’s mostly a state machine), but using the appropriate functions provided by sodium-plus (
crypto_box_keypair(),crypto_scalarmult()) should be relatively straightforward.Make sure your KDFs use domain separation, as per the Signal Protocol specifications.
Group Key Agreement
The Signal Protocol specified X3DH and the Double Ratchet for securely encrypting information between two parties.
Group conversations are trickier, because you have to be able to encrypt information that multiple recipients can decrypt, add/remove participants to the conversation, etc.
(The same complexity comes with multi-device support for end-to-end encryption.)
The best design I’ve read to date for tackling group key agreement is the IETF Messaging Layer Security RFC draft.
I am not going to implement the entire MLS RFC in this blog post. If you want to support multiple devices or group conversations, you’ll want a complete MLS implementation to work with.
Brief Recap
That was a lot of ground to cover, but we’re not done yet.
(Art by Khia.)So far we’ve tackled encryption, initial key agreement, and session key management. However, we did not flesh out how Identity Keys (which are signing keys–Ed25519 specifically–rather than Diffie-Hellman keys) are managed. That detail was just sorta hand-waved until now.
So let’s talk about that.
III. Identity Key Management
There’s a meme among technology bloggers to write a post titled “Falsehoods Programmers Believe About _____”.
Fortunately for us, Identity is one of the topics that furries are positioned to understand better than most (due to fursonas): Identities have a many-to-many relationship with Humans.
In an end-to-end encryption protocol, each identity will consist of some identifier (phone number, email address, username and server hostname, etc.) and an Ed25519 keypair (for which the public key will be published).
But how do you know whether or not a given public key is correct for a given identity?
This is where we segue into one of the hard problems in cryptography, where the solutions available are entirely dependent on your threat model: Public Key Infrastructure (PKI).
Some common PKI designs include:
- Certificate Authorities (CAs) — TLS does this
- Web-of-Trust (WoT) — The PGP ecosystem does this
- Trust On First Use (TOFU) — SSH does this
- Key Transparency / Certificate Transparency (CT) — TLS also does this for ensuring CA-issued certificates are auditable (although it was originally meant to replace Certificate Authorities)
And you can sort of choose-your-own-adventure on this one, depending on what’s most appropriate for the type of software you’re building and who your customers are.
One design I’m particularly fond of is called Gossamer, which is a PKI design without Certificate Authorities, originally designed for making WordPress’s automatic updates more secure (i.e. so every developer can sign their theme and plugin updates).
Since we only need to maintain an up-to-date repository of Ed25519 identity keys for each participant in our end-to-end encryption protocol, this makes Gossamer a suitable starting point.
Gossamer specifies a limited grammar of Actions that can be performed: AppendKey, RevokeKey, AppendUpdate, RevokeUpdate, and AttestUpdate. These actions are signed and published to an append-only cryptographic ledger.
I would propose a sixth action: AttestKey, so you can have WoT-like assurances and key-signing parties. (If nothing else, you should be able to attest that the identity keys of other cryptographic ledgers in the network are authentic at a point in time.)
IV. Backdoor Resistance
In the previous section, I proposed the use of Gossamer as a PKI for Identity Keys. This would provide Ed25519 keypairs for use with X3DH and the Double Ratchet, which would in turn provide session keys to use for symmetric authenticated encryption.
If you’ve implemented everything preceding this section, you have a full-stack end-to-end encryption protocol. But let’s make intelligence agencies and surveillance capitalists even more mad by making it impractical to backdoor our software (and impossible to silently backdoor it).
How do we pull that off?
You want Binary Transparency.
For us, the implementation is simple: Use Gossamer as it was originally intended (i.e. to secure your software distribution channels).
Gossamer provides up-to-date verification keys and a commitment to a cryptographic ledger of every software update. You can learn more about its inspiration here.
It isn’t enough to merely use Gossamer to manage keys and update signatures. You need independent third parties to use the AttestUpdate action to assert one or more of the following:
- That builds are reproducible from the source code.
- That they have reviewed the source code and found no evidence of backdoors or exploitable vulnerabilities.
(And then you should let your users decide which of these independent third parties they trust to vet software updates.)
Closing Remarks
The U.S. Government cries and moans a lot about “criminals going dark” and wonders a lot about how to solve the “going dark problem”.
If more software developers implement end-to-end encryption in their communications software, then maybe one day they won’t be able to use dragnet surveillance to spy on citizens and they’ll be forced to do actual detective work to solve actual crimes.
Y’know, like their job description actually entails?
Let’s normalize end-to-end encryption. Let’s normalize backdoor-resistant software distribution.
Let’s collectively tell the intelligence community in every sophisticated nation state the one word they don’t hear often enough:
Especially if you’re a furry. Because we improve everything! :3
Questions You Might Have
What About Private Contact Discovery?
That’s one of the major reasons why the thing we’re building isn’t meant to compete with Signal (and it MUST NOT be advertised as such):
Signal is a privacy tool, and their servers have no way of identifying who can contact who.
What we’ve built here isn’t a complete privacy solution, it’s only providing end-to-end encryption (and possibly making NSA employees cry at their desk).
Does This Design Work with Federation?
Yes. Each identifier string can be [username] at [hostname].
What About Network Metadata?
If you want anonymity, you want to use Tor.
Why Are You Using Ed25519 Keys for X3DH?
If you only read the key agreement section of this blog post and the fact that I’m passing around Ed25519 public keys seems weird, you might have missed the identity section of this blog post where I suggested piggybacking on another protocol called Gossamer to handle the distribution of Ed25519 public keys. (Gossamer is also beneficial for backdoor resistance in software update distribution, as described in the subsequent section.)
Furthermore, we’re actually using birationally equivalent X25519 keys derived from the Ed25519 keypair for the X3DH step. This is a deviation from what Signal does (using X25519 keys everywhere, then inventing an EdDSA variant to support their usage).
const publicKeyX = await sodium.crypto_sign_ed25519_pk_to_curve25519(foxPublicKey);const secretKeyX = await sodium.crypto_sign_ed25519_sk_to_curve25519(wolfSecretKey);
(Using fox/wolf instead of Alice/Bob, because it’s cuter.)
This design pattern has a few advantages:
- It makes Gossamer integration seamless, which means you can use Ed25519 for identities and still have a deniable X3DH handshake for 1:1 conversations while implementing the rest of the designs proposed.
- This approach to X3DH can be implemented entirely with libsodium functions, without forcing you to write your own cryptography implementations (i.e. for XEdDSA).
The only disadvantages I’m aware of are:
- It deviates from Signal’s core design in a subtle way that means you don’t get to claim the exact same advantages Signal does when it comes to peer review.
- Some cryptographers are distrustful of the use of birationally equivalent X25519 keys from Ed25519 keys (although there isn’t a vulnerability any of them have been able to point me to that doesn’t involve torsion groups–which libsodium’s implementation already avoids).
If these concerns are valid enough to decide against my implementation above, I invite you to talk with cryptographers about your concerns and then propose alternatives.
Has Any of This Been Implemented Already?
You can find implementations for the designs discussed on this blog post below:
- Rawr-X3DH implements X3DH in TypeScript (added 2020-11-23)
I will update this section of the blog post as implementations surface.
#authenticatedEncryption #authenticatedKeyExchange #crypto #cryptography #encryption #endToEndEncryption #libsodium #OnlinePrivacy #privacy #SecurityGuidance #symmetricEncryption
-
The Broken Mesh: Why the Fight Between Meshtastic and MeshCore Matters
2,734 words, 14 minutes read time.
The fracture between the Meshtastic and MeshCore projects is a warning that you cannot ignore. For years, people thought a simple, off-grid data net was the answer for when the main lines go down. But now, the community is divided. This is not just a small fight over code. It is a total disagreement on how to handle communication when things get ugly. If you think you are ready just because you bought a cheap radio board and did not bother to learn how the software actually works, you are just a hobbyist playing with toys. The rift between Meshtastic and MeshCore shows how fragile these systems are and why you need to know your gear inside and out. A mesh net is only as good as its weakest link. If you do not master the tech, you are just a dead node in a silent town. We are seeing the growing pains of a decentralized technology that is outstripping the discipline of its users. You must choose your tools based on the reality of the physics, not the popularity of the app. Demand that your firmware be an efficient tool for data transmission, not a bloated social media platform for the 915 MHz band. If you do not take the time to understand the modulation, the packet structure, and the routing logic of the software you flash onto your hardware, you are just a child playing with a walkie-talkie while the grown-ups are trying to build a grid. Mastery of the radio spectrum is not an option; it is a requirement for anyone who claims to be prepared. This split is the first real test of whether civilian mesh can survive the chaos of its own success. You either learn to navigate the airwaves or you signal your own failure. Every packet you send without understanding the cost is a round wasted in a firefight. Stop treating your emergency comms like a smartphone app and start treating it like the life-support system it is. This technical mastery is the difference between a working link and a radio that does nothing but drain your battery in the dark.
Troubleshooting LoRa Mesh Protocol Inefficiency and Network Congestion
The fight between Meshtastic and MeshCore comes down to how they use the radio waves and the small chips that run them. Meshtastic has been the big name for a long time. It uses a flooding method where every radio repeats every message it hears. In the woods, that is fine. In a city with a hundred users, it is a train wreck. The air gets crowded, messages hit each other, and the whole system jams itself. MeshCore did not start because people wanted a new app. It started because the old way is inefficient. The core of the split is about the overhead—the extra data that hitches a ride on every message. Meshtastic adds a lot of features, but those features take up space. MeshCore wants to strip everything down to the bone so the network stays stable. When you have very little room to send data, every extra bit is a mistake. This is a battle between lots of features and it just has to work. If your software is fighting your hardware, you lose. The divergence between Meshtastic and MeshCore is rooted in the physics of the 900 MHz ISM band and the limitations of the ESP32 and nRF52 chipsets. As the node count grows, the airwaves become a chaotic mess of collisions and retransmissions, effectively jamming the very frequency the operators are trying to utilize. While Meshtastic has focused on a feature-rich user experience with a heavy reliance on a specific structure, MeshCore proponents argue for a leaner, more modular approach that prioritizes the stability of the underlying mesh over the bells and whistles of the interface. When you are operating on a low-bandwidth, high-latency medium like LoRa, every byte of overhead is a liability. You either master the protocol or you become a dead node. The math does not lie even if the marketing does. If your network protocol consumes more than ten percent of your bandwidth for heartbeats, your network is dying. Every extra feature in the code is another potential point of failure when the signal gets weak. You have to decide if you want a chat app or a survival tool. The flooding algorithm used by Meshtastic is a blunt instrument that was never meant for high-density urban deployment. It works by simply re-broadcasting every unique packet received until a hop limit is reached. In a sparse environment, this ensures the message gets through by any means necessary. But as the number of nodes increases, the probability of two nodes transmitting at the same time goes up. This leads to packet collisions where neither message is readable. MeshCore attempts to solve this by moving toward a more structured routing system. This means the software tries to figure out the best path for a message instead of just yelling it to everyone. This shift requires a level of technical discipline that many casual users find frustrating. It means the network is less plug-and-play and more of a precision tool. If you want a network that survives a real crisis, you have to move away from the chaos of flooding. You have to understand how the Media Access Control layer handles traffic. You have to know how to set your timing parameters so you are not stepping on your own neighbors. The split is a clear line in the sand between those who want ease of use and those who want engineering reliability. You cannot hide from the physics of the airwaves. Either your packets move or they die in the dirt. Stop assuming the software will fix your bad placement. Fix the engineering or get off the air.
Physics of LoRa Packet Collisions and Signal to Noise Ratio Analysis
To understand this split, you have to look at how these radios actually talk. They use a low-power system called LoRa. It is built for long range, but it is slow. There are strict rules on how long you can broadcast before you have to shut up and let others speak. Because Meshtastic repeats everything, adding more people makes the problem worse fast. This is not a glitch. It is physics. MeshCore was built to change how messages find their path through the net. Instead of everyone yelling at once, it wants a smarter way to move data that does not waste airtime. The split happened because one group likes the safety of repeating everything, while the other wants a clean, quiet network. If your radio is spending eighty percent of its power just saying I am here, you are not communicating—you are just making noise. The split proves that the current path is heading for a crash where no one can get a message through. LoRa is designed for long-range, low-power communication, but it is inherently limited by the Duty Cycle regulations of the FCC Part 15 and similar international bodies. Meshtastic’s current implementation of the flooding protocol means that as you add more users, the probability of packet storms increases exponentially. MeshCore was conceptualized to address the need for a more rigid, perhaps even more disciplined, routing logic that could potentially mitigate the hidden node problem and reduce the airtime usage per packet. The technical fallout between the two development paths stems from a disagreement on how to manage the limited airtime of the ISM band. One camp believes in the resilience of redundant flooding, while the other seeks a more surgical, routed approach to data delivery. This is a matter of Spectral Efficiency. If your mesh is using the majority of its available airtime just to say it exists, you have failed as an operator and an engineer. You are polluting the spectrum with digital noise. This noise prevents emergency traffic from getting through. It creates a false sense of security where people think they have a working link when they actually have a jammed one. You must look at the duty cycle of your own node. If you are transmitting more than one percent of the time in the 900 MHz band, you are likely part of the problem. MeshCore is an attempt to force the network into a more responsible state. It prioritizes the survival of the link over the convenience of the user. This is a hard truth that many do not want to hear. Physics does not care about your feelings or your user interface. It only cares about the signal-to-noise ratio. If your signal is lost in the noise of your own network, you have built nothing but a very expensive paperweight. Every packet sent is a risk. In a real-world scenario, a long transmission can be used to find your location. Flooding makes this risk much higher because your message is repeated over and over by every node in the area. A routed system like what MeshCore aims for reduces this risk by limiting the number of times a message is sent. This is not just about efficiency; it is about security. You have to understand that the airwaves are a shared resource. If you treat them like your own personal garbage dump, you will find yourself alone and unheard when the time comes to actually send a call for help. The split between Meshtastic and MeshCore is a debate over the very future of private, off-grid data. One side wants to make it accessible to everyone, while the other wants to make it work when nothing else does. You have to decide which side of that line you stand on. If you are not monitoring your packet loss and your noise floor, you are not an operator. You are just a passenger in a system that is bound to fail. Stop looking at the colorful screens and start looking at the spectrum. The truth is in the waterfall, not the icons. The physics of 915 MHz demand respect that a plug and play mindset cannot provide.
Off-Grid Communication Solutions and Technical Radio Discipline
The result of this fight is a mess where gear running one software will not talk to gear running the other. For you, that means your radio is a brick if your neighbor is on the other side of the fence. This is how a mesh net dies. A mesh needs everyone to speak the same language. When the builders split, the network breaks. This should wake up anyone who thinks they can just download a file and be safe. The hard truth is that we are seeing a new tech grow too fast for the people using it. You have to pick your tools based on facts, not what looks cool. Demand software that moves data fast and clean. If you do not know how your radio sends a packet or why some settings work better than others, you have no business relying on this in a pinch. The split between Meshtastic and MeshCore is a reminder that in the world of radio, there are no shortcuts. For the operator in the field, this means your gear might be useless if the person three blocks away is running a different branch of the protocol. This is the death of a mesh. A mesh requires a common language, a shared set of timing parameters, and a unified understanding of frequency hopping and spreading factors. When the developers split, the network breaks. This should serve as a wake-up call to anyone who thinks they can outsource their emergency communications to a GitHub repository they do not understand. The split between Meshtastic and MeshCore is a reminder that in the world of RF, there are no shortcuts. If you cannot explain the difference between a Spreading Factor of seven and twelve, or why a 125kHz bandwidth is preferable over 250kHz in a high-noise environment, you have no business relying on these tools. The hard truth is that we are witnessing the growing pains of a decentralized technology that is outstripping the discipline of its users. You must take personal responsibility for your station. This means testing your range with real-world obstacles. It means understanding how your antenna height and gain affect your local mesh. It means being able to re-flash your firmware in the dark while the rain is pouring down. If you cannot do these things, you are not prepared. You are just a collector of electronic gadgets. The discipline of the amateur radio spirit must be applied to these new digital modes. We are losing the technical edge that made the license worth having in the first place. The split is a chance to reset. It is a chance to move away from the appliance operator mindset and back toward the engineering mindset. You should be auditing your own mesh. Look at the traffic logs. See how many packets are being dropped. See how many of your traffic is just node discovery overhead. If you find that your network is inefficient, do not wait for a developer to fix it. Change your settings. Educate your neighbors. If the split leads to a better, more efficient protocol, then it was worth the friction. But if it just leads to two broken networks instead of one, then we have all lost. The practical application of this knowledge is simple: test everything. Do not assume your mesh will work because the light on the board is green. Prove it. Send data over the longest possible path. Monitor the battery drain. Watch the spectrum on an analyzer if you have one. If you do not have the tools to verify your network, you do not have a network. You have a hope. And hope is not a plan for communication. Secure your nodes, harden your protocol, and stop relying on software you have never bothered to read. The day is coming when the only thing between you and the void is the connection you built yourself. Don’t let it be a connection built on laziness. Clean up your messy node or accept that you will be silent when it matters.
Conclusion: The Future of Decentralized Mesh Networks and User Mastery
The discipline of the old-school radio operator has to be applied here or the whole thing will fail. The split between Meshtastic and MeshCore is a call to stop being a lazy user and start being a real operator. We do not have time for good enough when the grid is down. Check your gear, learn the rules of the airwaves, and be ready for a future where the channels are full and the software is broken. Build your setup expecting things to break. There is no room for being soft. Learn the math, understand your range, and make sure every message you send is worth the airtime. The grid is weak, the airwaves are crowded, and your own lack of knowledge is the only thing truly blocking your signal. Fix your gear, learn the system, and stop waiting for someone else to save you. The grid is fragile, the spectrum is finite, and your ignorance is the only thing standing between you and a total blackout. Fix your station, fix your protocol, and stop waiting for someone else to secure your link. The time for playing games with digital toys is over. Mastery is the only way forward. Master the code, master the RF, or stay off the air. This hobby demands engineers, not appliance operators. Be the asset the network needs, not the QRM that kills it. Finalize your build, test the link, and maintain the discipline required to keep the airwaves open for those who truly need them.
Call to Action
Join the Network and Master Your Comms Before the Grid Goes Dark. The split between Meshtastic and MeshCore is a wake-up call for every operator. You cannot afford to be a passive user when the lines of communication are at stake. Whether you choose the feature-rich path or the lean efficiency of the core, the responsibility for a working link lies with you. Don’t wait for a crisis to realize your nodes are misconfigured or your protocol is inefficient. Start auditing your setup today by getting out in the field to find your real-world limits, diving into the spreading factors to clear the noise, and educating your local mesh to ensure your neighborhood stays connected. The airwaves belong to those who master them. Secure your hardware, flash your firmware, and become a reliable node in the decentralized future. Join the conversation, build the grid, and stay off the silent list.
SUPPORTSUBSCRIBECONTACT MED. Bryan King
Sources
- FCC Part 15 Radio Frequency Devices – Federal Communications Commission
- SX1262 LoRa Transceiver Datasheet – Semtech
- Meshtastic Project Documentation – Meshtastic
- A Study of LoRa: Long Range and Low Power Networks for the Internet of Things – IEEE
- The ARRL Handbook for Radio Communications – ARRL
- Guide to Bluetooth Security (RF Protocol Standards) – NIST
- LoRaWAN 1.1 Specification – LoRa Alliance
- Do LoRa Low-Power Wide-Area Networks Scale? – IEEE
- ESP32 Series Datasheet – Espressif Systems
- nRF52840 Product Specification – Nordic Semiconductor
- Terminology for Constrained-Node Networks – IETF
- ITU Handbook on Land Mobile Communications – International Telecommunication Union
- Protocol Buffers Documentation – Google Developers
- Understanding the Basics of LoRa and LoRaWAN – DigiKey
- LoRa Technology: A Technical Overview – NXP Semiconductors
- LoRaWAN Documentation – The Things Network
- Guide to Bluetooth Security – NIST Special Publication
- LoRa Physical Layer Packet Structure – RF Wireless World
- LoRa Wireless Technology – Microchip Technology
- Understanding and Enhancing RF Link Budget – Analog Devices
- LoRaWAN Technology Overview – STMicroelectronics
- Analysis of the Capacity and Scalability of LoRaWAN – ResearchGate
- Fundamentals of the LoRa Physical Layer – EDN Network
- What is LoRa Technology? – everything RF
- Link Budget Basics – Microwaves101
- LoRa Long Range Technology Overview – Texas Instruments
- Scalability of LoRaWAN for Massive IoT Deployment – MDPI Sensors
- Detailed Study of LoRa Low Power Communications – PMC
- 11 Myths About LoRa and LoRaWAN – Electronic Design
- LoRa Modulation Basics – Microwave Journal
Disclaimer:
The views and opinions expressed in this post are solely those of the author. The information provided is based on personal research, experience, and understanding of the subject matter at the time of writing. Readers should consult relevant experts or authorities for specific guidance related to their unique situations.
Related Posts
Rate this:
#915MHz #airtimeOptimization #AmateurRadio #antennaGain #bandwidthManagement #communicationSecurity #communityMesh #constrainedNodes #dataTransmission #DecentralizedNetworks #digitalModes #DisasterRecovery #dutyCycle #emergencyComms #ESP32 #FCCPart15 #firmwareFlashing #floodingProtocol #gridDownComms #hiddenNodeProblem #IoTScalability #ISMBand #linkBudget #LoRa #LoRaWAN #meshNetworking #MeshCore #Meshtastic #networkCongestion #nodeDensity #nRF52840 #offGridCommunication #packetCollisions #packetLoss #protocolOverhead #radioDiscipline #radioFrequency #RFEngineering #RFInterference #routingLogic #signalPropagation #SignalToNoiseRatio #SNR #spectralEfficiency #spreadingFactor #survivalTech #SX1262 #TacticalComms #wirelessProtocols -
The Broken Mesh: Why the Fight Between Meshtastic and MeshCore Matters
2,734 words, 14 minutes read time.
The fracture between the Meshtastic and MeshCore projects is a warning that you cannot ignore. For years, people thought a simple, off-grid data net was the answer for when the main lines go down. But now, the community is divided. This is not just a small fight over code. It is a total disagreement on how to handle communication when things get ugly. If you think you are ready just because you bought a cheap radio board and did not bother to learn how the software actually works, you are just a hobbyist playing with toys. The rift between Meshtastic and MeshCore shows how fragile these systems are and why you need to know your gear inside and out. A mesh net is only as good as its weakest link. If you do not master the tech, you are just a dead node in a silent town. We are seeing the growing pains of a decentralized technology that is outstripping the discipline of its users. You must choose your tools based on the reality of the physics, not the popularity of the app. Demand that your firmware be an efficient tool for data transmission, not a bloated social media platform for the 915 MHz band. If you do not take the time to understand the modulation, the packet structure, and the routing logic of the software you flash onto your hardware, you are just a child playing with a walkie-talkie while the grown-ups are trying to build a grid. Mastery of the radio spectrum is not an option; it is a requirement for anyone who claims to be prepared. This split is the first real test of whether civilian mesh can survive the chaos of its own success. You either learn to navigate the airwaves or you signal your own failure. Every packet you send without understanding the cost is a round wasted in a firefight. Stop treating your emergency comms like a smartphone app and start treating it like the life-support system it is. This technical mastery is the difference between a working link and a radio that does nothing but drain your battery in the dark.
Troubleshooting LoRa Mesh Protocol Inefficiency and Network Congestion
The fight between Meshtastic and MeshCore comes down to how they use the radio waves and the small chips that run them. Meshtastic has been the big name for a long time. It uses a flooding method where every radio repeats every message it hears. In the woods, that is fine. In a city with a hundred users, it is a train wreck. The air gets crowded, messages hit each other, and the whole system jams itself. MeshCore did not start because people wanted a new app. It started because the old way is inefficient. The core of the split is about the overhead—the extra data that hitches a ride on every message. Meshtastic adds a lot of features, but those features take up space. MeshCore wants to strip everything down to the bone so the network stays stable. When you have very little room to send data, every extra bit is a mistake. This is a battle between lots of features and it just has to work. If your software is fighting your hardware, you lose. The divergence between Meshtastic and MeshCore is rooted in the physics of the 900 MHz ISM band and the limitations of the ESP32 and nRF52 chipsets. As the node count grows, the airwaves become a chaotic mess of collisions and retransmissions, effectively jamming the very frequency the operators are trying to utilize. While Meshtastic has focused on a feature-rich user experience with a heavy reliance on a specific structure, MeshCore proponents argue for a leaner, more modular approach that prioritizes the stability of the underlying mesh over the bells and whistles of the interface. When you are operating on a low-bandwidth, high-latency medium like LoRa, every byte of overhead is a liability. You either master the protocol or you become a dead node. The math does not lie even if the marketing does. If your network protocol consumes more than ten percent of your bandwidth for heartbeats, your network is dying. Every extra feature in the code is another potential point of failure when the signal gets weak. You have to decide if you want a chat app or a survival tool. The flooding algorithm used by Meshtastic is a blunt instrument that was never meant for high-density urban deployment. It works by simply re-broadcasting every unique packet received until a hop limit is reached. In a sparse environment, this ensures the message gets through by any means necessary. But as the number of nodes increases, the probability of two nodes transmitting at the same time goes up. This leads to packet collisions where neither message is readable. MeshCore attempts to solve this by moving toward a more structured routing system. This means the software tries to figure out the best path for a message instead of just yelling it to everyone. This shift requires a level of technical discipline that many casual users find frustrating. It means the network is less plug-and-play and more of a precision tool. If you want a network that survives a real crisis, you have to move away from the chaos of flooding. You have to understand how the Media Access Control layer handles traffic. You have to know how to set your timing parameters so you are not stepping on your own neighbors. The split is a clear line in the sand between those who want ease of use and those who want engineering reliability. You cannot hide from the physics of the airwaves. Either your packets move or they die in the dirt. Stop assuming the software will fix your bad placement. Fix the engineering or get off the air.
Physics of LoRa Packet Collisions and Signal to Noise Ratio Analysis
To understand this split, you have to look at how these radios actually talk. They use a low-power system called LoRa. It is built for long range, but it is slow. There are strict rules on how long you can broadcast before you have to shut up and let others speak. Because Meshtastic repeats everything, adding more people makes the problem worse fast. This is not a glitch. It is physics. MeshCore was built to change how messages find their path through the net. Instead of everyone yelling at once, it wants a smarter way to move data that does not waste airtime. The split happened because one group likes the safety of repeating everything, while the other wants a clean, quiet network. If your radio is spending eighty percent of its power just saying I am here, you are not communicating—you are just making noise. The split proves that the current path is heading for a crash where no one can get a message through. LoRa is designed for long-range, low-power communication, but it is inherently limited by the Duty Cycle regulations of the FCC Part 15 and similar international bodies. Meshtastic’s current implementation of the flooding protocol means that as you add more users, the probability of packet storms increases exponentially. MeshCore was conceptualized to address the need for a more rigid, perhaps even more disciplined, routing logic that could potentially mitigate the hidden node problem and reduce the airtime usage per packet. The technical fallout between the two development paths stems from a disagreement on how to manage the limited airtime of the ISM band. One camp believes in the resilience of redundant flooding, while the other seeks a more surgical, routed approach to data delivery. This is a matter of Spectral Efficiency. If your mesh is using the majority of its available airtime just to say it exists, you have failed as an operator and an engineer. You are polluting the spectrum with digital noise. This noise prevents emergency traffic from getting through. It creates a false sense of security where people think they have a working link when they actually have a jammed one. You must look at the duty cycle of your own node. If you are transmitting more than one percent of the time in the 900 MHz band, you are likely part of the problem. MeshCore is an attempt to force the network into a more responsible state. It prioritizes the survival of the link over the convenience of the user. This is a hard truth that many do not want to hear. Physics does not care about your feelings or your user interface. It only cares about the signal-to-noise ratio. If your signal is lost in the noise of your own network, you have built nothing but a very expensive paperweight. Every packet sent is a risk. In a real-world scenario, a long transmission can be used to find your location. Flooding makes this risk much higher because your message is repeated over and over by every node in the area. A routed system like what MeshCore aims for reduces this risk by limiting the number of times a message is sent. This is not just about efficiency; it is about security. You have to understand that the airwaves are a shared resource. If you treat them like your own personal garbage dump, you will find yourself alone and unheard when the time comes to actually send a call for help. The split between Meshtastic and MeshCore is a debate over the very future of private, off-grid data. One side wants to make it accessible to everyone, while the other wants to make it work when nothing else does. You have to decide which side of that line you stand on. If you are not monitoring your packet loss and your noise floor, you are not an operator. You are just a passenger in a system that is bound to fail. Stop looking at the colorful screens and start looking at the spectrum. The truth is in the waterfall, not the icons. The physics of 915 MHz demand respect that a plug and play mindset cannot provide.
Off-Grid Communication Solutions and Technical Radio Discipline
The result of this fight is a mess where gear running one software will not talk to gear running the other. For you, that means your radio is a brick if your neighbor is on the other side of the fence. This is how a mesh net dies. A mesh needs everyone to speak the same language. When the builders split, the network breaks. This should wake up anyone who thinks they can just download a file and be safe. The hard truth is that we are seeing a new tech grow too fast for the people using it. You have to pick your tools based on facts, not what looks cool. Demand software that moves data fast and clean. If you do not know how your radio sends a packet or why some settings work better than others, you have no business relying on this in a pinch. The split between Meshtastic and MeshCore is a reminder that in the world of radio, there are no shortcuts. For the operator in the field, this means your gear might be useless if the person three blocks away is running a different branch of the protocol. This is the death of a mesh. A mesh requires a common language, a shared set of timing parameters, and a unified understanding of frequency hopping and spreading factors. When the developers split, the network breaks. This should serve as a wake-up call to anyone who thinks they can outsource their emergency communications to a GitHub repository they do not understand. The split between Meshtastic and MeshCore is a reminder that in the world of RF, there are no shortcuts. If you cannot explain the difference between a Spreading Factor of seven and twelve, or why a 125kHz bandwidth is preferable over 250kHz in a high-noise environment, you have no business relying on these tools. The hard truth is that we are witnessing the growing pains of a decentralized technology that is outstripping the discipline of its users. You must take personal responsibility for your station. This means testing your range with real-world obstacles. It means understanding how your antenna height and gain affect your local mesh. It means being able to re-flash your firmware in the dark while the rain is pouring down. If you cannot do these things, you are not prepared. You are just a collector of electronic gadgets. The discipline of the amateur radio spirit must be applied to these new digital modes. We are losing the technical edge that made the license worth having in the first place. The split is a chance to reset. It is a chance to move away from the appliance operator mindset and back toward the engineering mindset. You should be auditing your own mesh. Look at the traffic logs. See how many packets are being dropped. See how many of your traffic is just node discovery overhead. If you find that your network is inefficient, do not wait for a developer to fix it. Change your settings. Educate your neighbors. If the split leads to a better, more efficient protocol, then it was worth the friction. But if it just leads to two broken networks instead of one, then we have all lost. The practical application of this knowledge is simple: test everything. Do not assume your mesh will work because the light on the board is green. Prove it. Send data over the longest possible path. Monitor the battery drain. Watch the spectrum on an analyzer if you have one. If you do not have the tools to verify your network, you do not have a network. You have a hope. And hope is not a plan for communication. Secure your nodes, harden your protocol, and stop relying on software you have never bothered to read. The day is coming when the only thing between you and the void is the connection you built yourself. Don’t let it be a connection built on laziness. Clean up your messy node or accept that you will be silent when it matters.
Conclusion: The Future of Decentralized Mesh Networks and User Mastery
The discipline of the old-school radio operator has to be applied here or the whole thing will fail. The split between Meshtastic and MeshCore is a call to stop being a lazy user and start being a real operator. We do not have time for good enough when the grid is down. Check your gear, learn the rules of the airwaves, and be ready for a future where the channels are full and the software is broken. Build your setup expecting things to break. There is no room for being soft. Learn the math, understand your range, and make sure every message you send is worth the airtime. The grid is weak, the airwaves are crowded, and your own lack of knowledge is the only thing truly blocking your signal. Fix your gear, learn the system, and stop waiting for someone else to save you. The grid is fragile, the spectrum is finite, and your ignorance is the only thing standing between you and a total blackout. Fix your station, fix your protocol, and stop waiting for someone else to secure your link. The time for playing games with digital toys is over. Mastery is the only way forward. Master the code, master the RF, or stay off the air. This hobby demands engineers, not appliance operators. Be the asset the network needs, not the QRM that kills it. Finalize your build, test the link, and maintain the discipline required to keep the airwaves open for those who truly need them.
Call to Action
Join the Network and Master Your Comms Before the Grid Goes Dark. The split between Meshtastic and MeshCore is a wake-up call for every operator. You cannot afford to be a passive user when the lines of communication are at stake. Whether you choose the feature-rich path or the lean efficiency of the core, the responsibility for a working link lies with you. Don’t wait for a crisis to realize your nodes are misconfigured or your protocol is inefficient. Start auditing your setup today by getting out in the field to find your real-world limits, diving into the spreading factors to clear the noise, and educating your local mesh to ensure your neighborhood stays connected. The airwaves belong to those who master them. Secure your hardware, flash your firmware, and become a reliable node in the decentralized future. Join the conversation, build the grid, and stay off the silent list.
SUPPORTSUBSCRIBECONTACT MED. Bryan King
Sources
- FCC Part 15 Radio Frequency Devices – Federal Communications Commission
- SX1262 LoRa Transceiver Datasheet – Semtech
- Meshtastic Project Documentation – Meshtastic
- A Study of LoRa: Long Range and Low Power Networks for the Internet of Things – IEEE
- The ARRL Handbook for Radio Communications – ARRL
- Guide to Bluetooth Security (RF Protocol Standards) – NIST
- LoRaWAN 1.1 Specification – LoRa Alliance
- Do LoRa Low-Power Wide-Area Networks Scale? – IEEE
- ESP32 Series Datasheet – Espressif Systems
- nRF52840 Product Specification – Nordic Semiconductor
- Terminology for Constrained-Node Networks – IETF
- ITU Handbook on Land Mobile Communications – International Telecommunication Union
- Protocol Buffers Documentation – Google Developers
- Understanding the Basics of LoRa and LoRaWAN – DigiKey
- LoRa Technology: A Technical Overview – NXP Semiconductors
- LoRaWAN Documentation – The Things Network
- Guide to Bluetooth Security – NIST Special Publication
- LoRa Physical Layer Packet Structure – RF Wireless World
- LoRa Wireless Technology – Microchip Technology
- Understanding and Enhancing RF Link Budget – Analog Devices
- LoRaWAN Technology Overview – STMicroelectronics
- Analysis of the Capacity and Scalability of LoRaWAN – ResearchGate
- Fundamentals of the LoRa Physical Layer – EDN Network
- What is LoRa Technology? – everything RF
- Link Budget Basics – Microwaves101
- LoRa Long Range Technology Overview – Texas Instruments
- Scalability of LoRaWAN for Massive IoT Deployment – MDPI Sensors
- Detailed Study of LoRa Low Power Communications – PMC
- 11 Myths About LoRa and LoRaWAN – Electronic Design
- LoRa Modulation Basics – Microwave Journal
Disclaimer:
The views and opinions expressed in this post are solely those of the author. The information provided is based on personal research, experience, and understanding of the subject matter at the time of writing. Readers should consult relevant experts or authorities for specific guidance related to their unique situations.
Related Posts
Rate this:
#915MHz #airtimeOptimization #AmateurRadio #antennaGain #bandwidthManagement #communicationSecurity #communityMesh #constrainedNodes #dataTransmission #DecentralizedNetworks #digitalModes #DisasterRecovery #dutyCycle #emergencyComms #ESP32 #FCCPart15 #firmwareFlashing #floodingProtocol #gridDownComms #hiddenNodeProblem #IoTScalability #ISMBand #linkBudget #LoRa #LoRaWAN #meshNetworking #MeshCore #Meshtastic #networkCongestion #nodeDensity #nRF52840 #offGridCommunication #packetCollisions #packetLoss #protocolOverhead #radioDiscipline #radioFrequency #RFEngineering #RFInterference #routingLogic #signalPropagation #SignalToNoiseRatio #SNR #spectralEfficiency #spreadingFactor #survivalTech #SX1262 #TacticalComms #wirelessProtocols -
The Broken Mesh: Why the Fight Between Meshtastic and MeshCore Matters
2,734 words, 14 minutes read time.
The fracture between the Meshtastic and MeshCore projects is a warning that you cannot ignore. For years, people thought a simple, off-grid data net was the answer for when the main lines go down. But now, the community is divided. This is not just a small fight over code. It is a total disagreement on how to handle communication when things get ugly. If you think you are ready just because you bought a cheap radio board and did not bother to learn how the software actually works, you are just a hobbyist playing with toys. The rift between Meshtastic and MeshCore shows how fragile these systems are and why you need to know your gear inside and out. A mesh net is only as good as its weakest link. If you do not master the tech, you are just a dead node in a silent town. We are seeing the growing pains of a decentralized technology that is outstripping the discipline of its users. You must choose your tools based on the reality of the physics, not the popularity of the app. Demand that your firmware be an efficient tool for data transmission, not a bloated social media platform for the 915 MHz band. If you do not take the time to understand the modulation, the packet structure, and the routing logic of the software you flash onto your hardware, you are just a child playing with a walkie-talkie while the grown-ups are trying to build a grid. Mastery of the radio spectrum is not an option; it is a requirement for anyone who claims to be prepared. This split is the first real test of whether civilian mesh can survive the chaos of its own success. You either learn to navigate the airwaves or you signal your own failure. Every packet you send without understanding the cost is a round wasted in a firefight. Stop treating your emergency comms like a smartphone app and start treating it like the life-support system it is. This technical mastery is the difference between a working link and a radio that does nothing but drain your battery in the dark.
Troubleshooting LoRa Mesh Protocol Inefficiency and Network Congestion
The fight between Meshtastic and MeshCore comes down to how they use the radio waves and the small chips that run them. Meshtastic has been the big name for a long time. It uses a flooding method where every radio repeats every message it hears. In the woods, that is fine. In a city with a hundred users, it is a train wreck. The air gets crowded, messages hit each other, and the whole system jams itself. MeshCore did not start because people wanted a new app. It started because the old way is inefficient. The core of the split is about the overhead—the extra data that hitches a ride on every message. Meshtastic adds a lot of features, but those features take up space. MeshCore wants to strip everything down to the bone so the network stays stable. When you have very little room to send data, every extra bit is a mistake. This is a battle between lots of features and it just has to work. If your software is fighting your hardware, you lose. The divergence between Meshtastic and MeshCore is rooted in the physics of the 900 MHz ISM band and the limitations of the ESP32 and nRF52 chipsets. As the node count grows, the airwaves become a chaotic mess of collisions and retransmissions, effectively jamming the very frequency the operators are trying to utilize. While Meshtastic has focused on a feature-rich user experience with a heavy reliance on a specific structure, MeshCore proponents argue for a leaner, more modular approach that prioritizes the stability of the underlying mesh over the bells and whistles of the interface. When you are operating on a low-bandwidth, high-latency medium like LoRa, every byte of overhead is a liability. You either master the protocol or you become a dead node. The math does not lie even if the marketing does. If your network protocol consumes more than ten percent of your bandwidth for heartbeats, your network is dying. Every extra feature in the code is another potential point of failure when the signal gets weak. You have to decide if you want a chat app or a survival tool. The flooding algorithm used by Meshtastic is a blunt instrument that was never meant for high-density urban deployment. It works by simply re-broadcasting every unique packet received until a hop limit is reached. In a sparse environment, this ensures the message gets through by any means necessary. But as the number of nodes increases, the probability of two nodes transmitting at the same time goes up. This leads to packet collisions where neither message is readable. MeshCore attempts to solve this by moving toward a more structured routing system. This means the software tries to figure out the best path for a message instead of just yelling it to everyone. This shift requires a level of technical discipline that many casual users find frustrating. It means the network is less plug-and-play and more of a precision tool. If you want a network that survives a real crisis, you have to move away from the chaos of flooding. You have to understand how the Media Access Control layer handles traffic. You have to know how to set your timing parameters so you are not stepping on your own neighbors. The split is a clear line in the sand between those who want ease of use and those who want engineering reliability. You cannot hide from the physics of the airwaves. Either your packets move or they die in the dirt. Stop assuming the software will fix your bad placement. Fix the engineering or get off the air.
Physics of LoRa Packet Collisions and Signal to Noise Ratio Analysis
To understand this split, you have to look at how these radios actually talk. They use a low-power system called LoRa. It is built for long range, but it is slow. There are strict rules on how long you can broadcast before you have to shut up and let others speak. Because Meshtastic repeats everything, adding more people makes the problem worse fast. This is not a glitch. It is physics. MeshCore was built to change how messages find their path through the net. Instead of everyone yelling at once, it wants a smarter way to move data that does not waste airtime. The split happened because one group likes the safety of repeating everything, while the other wants a clean, quiet network. If your radio is spending eighty percent of its power just saying I am here, you are not communicating—you are just making noise. The split proves that the current path is heading for a crash where no one can get a message through. LoRa is designed for long-range, low-power communication, but it is inherently limited by the Duty Cycle regulations of the FCC Part 15 and similar international bodies. Meshtastic’s current implementation of the flooding protocol means that as you add more users, the probability of packet storms increases exponentially. MeshCore was conceptualized to address the need for a more rigid, perhaps even more disciplined, routing logic that could potentially mitigate the hidden node problem and reduce the airtime usage per packet. The technical fallout between the two development paths stems from a disagreement on how to manage the limited airtime of the ISM band. One camp believes in the resilience of redundant flooding, while the other seeks a more surgical, routed approach to data delivery. This is a matter of Spectral Efficiency. If your mesh is using the majority of its available airtime just to say it exists, you have failed as an operator and an engineer. You are polluting the spectrum with digital noise. This noise prevents emergency traffic from getting through. It creates a false sense of security where people think they have a working link when they actually have a jammed one. You must look at the duty cycle of your own node. If you are transmitting more than one percent of the time in the 900 MHz band, you are likely part of the problem. MeshCore is an attempt to force the network into a more responsible state. It prioritizes the survival of the link over the convenience of the user. This is a hard truth that many do not want to hear. Physics does not care about your feelings or your user interface. It only cares about the signal-to-noise ratio. If your signal is lost in the noise of your own network, you have built nothing but a very expensive paperweight. Every packet sent is a risk. In a real-world scenario, a long transmission can be used to find your location. Flooding makes this risk much higher because your message is repeated over and over by every node in the area. A routed system like what MeshCore aims for reduces this risk by limiting the number of times a message is sent. This is not just about efficiency; it is about security. You have to understand that the airwaves are a shared resource. If you treat them like your own personal garbage dump, you will find yourself alone and unheard when the time comes to actually send a call for help. The split between Meshtastic and MeshCore is a debate over the very future of private, off-grid data. One side wants to make it accessible to everyone, while the other wants to make it work when nothing else does. You have to decide which side of that line you stand on. If you are not monitoring your packet loss and your noise floor, you are not an operator. You are just a passenger in a system that is bound to fail. Stop looking at the colorful screens and start looking at the spectrum. The truth is in the waterfall, not the icons. The physics of 915 MHz demand respect that a plug and play mindset cannot provide.
Off-Grid Communication Solutions and Technical Radio Discipline
The result of this fight is a mess where gear running one software will not talk to gear running the other. For you, that means your radio is a brick if your neighbor is on the other side of the fence. This is how a mesh net dies. A mesh needs everyone to speak the same language. When the builders split, the network breaks. This should wake up anyone who thinks they can just download a file and be safe. The hard truth is that we are seeing a new tech grow too fast for the people using it. You have to pick your tools based on facts, not what looks cool. Demand software that moves data fast and clean. If you do not know how your radio sends a packet or why some settings work better than others, you have no business relying on this in a pinch. The split between Meshtastic and MeshCore is a reminder that in the world of radio, there are no shortcuts. For the operator in the field, this means your gear might be useless if the person three blocks away is running a different branch of the protocol. This is the death of a mesh. A mesh requires a common language, a shared set of timing parameters, and a unified understanding of frequency hopping and spreading factors. When the developers split, the network breaks. This should serve as a wake-up call to anyone who thinks they can outsource their emergency communications to a GitHub repository they do not understand. The split between Meshtastic and MeshCore is a reminder that in the world of RF, there are no shortcuts. If you cannot explain the difference between a Spreading Factor of seven and twelve, or why a 125kHz bandwidth is preferable over 250kHz in a high-noise environment, you have no business relying on these tools. The hard truth is that we are witnessing the growing pains of a decentralized technology that is outstripping the discipline of its users. You must take personal responsibility for your station. This means testing your range with real-world obstacles. It means understanding how your antenna height and gain affect your local mesh. It means being able to re-flash your firmware in the dark while the rain is pouring down. If you cannot do these things, you are not prepared. You are just a collector of electronic gadgets. The discipline of the amateur radio spirit must be applied to these new digital modes. We are losing the technical edge that made the license worth having in the first place. The split is a chance to reset. It is a chance to move away from the appliance operator mindset and back toward the engineering mindset. You should be auditing your own mesh. Look at the traffic logs. See how many packets are being dropped. See how many of your traffic is just node discovery overhead. If you find that your network is inefficient, do not wait for a developer to fix it. Change your settings. Educate your neighbors. If the split leads to a better, more efficient protocol, then it was worth the friction. But if it just leads to two broken networks instead of one, then we have all lost. The practical application of this knowledge is simple: test everything. Do not assume your mesh will work because the light on the board is green. Prove it. Send data over the longest possible path. Monitor the battery drain. Watch the spectrum on an analyzer if you have one. If you do not have the tools to verify your network, you do not have a network. You have a hope. And hope is not a plan for communication. Secure your nodes, harden your protocol, and stop relying on software you have never bothered to read. The day is coming when the only thing between you and the void is the connection you built yourself. Don’t let it be a connection built on laziness. Clean up your messy node or accept that you will be silent when it matters.
Conclusion: The Future of Decentralized Mesh Networks and User Mastery
The discipline of the old-school radio operator has to be applied here or the whole thing will fail. The split between Meshtastic and MeshCore is a call to stop being a lazy user and start being a real operator. We do not have time for good enough when the grid is down. Check your gear, learn the rules of the airwaves, and be ready for a future where the channels are full and the software is broken. Build your setup expecting things to break. There is no room for being soft. Learn the math, understand your range, and make sure every message you send is worth the airtime. The grid is weak, the airwaves are crowded, and your own lack of knowledge is the only thing truly blocking your signal. Fix your gear, learn the system, and stop waiting for someone else to save you. The grid is fragile, the spectrum is finite, and your ignorance is the only thing standing between you and a total blackout. Fix your station, fix your protocol, and stop waiting for someone else to secure your link. The time for playing games with digital toys is over. Mastery is the only way forward. Master the code, master the RF, or stay off the air. This hobby demands engineers, not appliance operators. Be the asset the network needs, not the QRM that kills it. Finalize your build, test the link, and maintain the discipline required to keep the airwaves open for those who truly need them.
Call to Action
Join the Network and Master Your Comms Before the Grid Goes Dark. The split between Meshtastic and MeshCore is a wake-up call for every operator. You cannot afford to be a passive user when the lines of communication are at stake. Whether you choose the feature-rich path or the lean efficiency of the core, the responsibility for a working link lies with you. Don’t wait for a crisis to realize your nodes are misconfigured or your protocol is inefficient. Start auditing your setup today by getting out in the field to find your real-world limits, diving into the spreading factors to clear the noise, and educating your local mesh to ensure your neighborhood stays connected. The airwaves belong to those who master them. Secure your hardware, flash your firmware, and become a reliable node in the decentralized future. Join the conversation, build the grid, and stay off the silent list.
SUPPORTSUBSCRIBECONTACT MED. Bryan King
Sources
- FCC Part 15 Radio Frequency Devices – Federal Communications Commission
- SX1262 LoRa Transceiver Datasheet – Semtech
- Meshtastic Project Documentation – Meshtastic
- A Study of LoRa: Long Range and Low Power Networks for the Internet of Things – IEEE
- The ARRL Handbook for Radio Communications – ARRL
- Guide to Bluetooth Security (RF Protocol Standards) – NIST
- LoRaWAN 1.1 Specification – LoRa Alliance
- Do LoRa Low-Power Wide-Area Networks Scale? – IEEE
- ESP32 Series Datasheet – Espressif Systems
- nRF52840 Product Specification – Nordic Semiconductor
- Terminology for Constrained-Node Networks – IETF
- ITU Handbook on Land Mobile Communications – International Telecommunication Union
- Protocol Buffers Documentation – Google Developers
- Understanding the Basics of LoRa and LoRaWAN – DigiKey
- LoRa Technology: A Technical Overview – NXP Semiconductors
- LoRaWAN Documentation – The Things Network
- Guide to Bluetooth Security – NIST Special Publication
- LoRa Physical Layer Packet Structure – RF Wireless World
- LoRa Wireless Technology – Microchip Technology
- Understanding and Enhancing RF Link Budget – Analog Devices
- LoRaWAN Technology Overview – STMicroelectronics
- Analysis of the Capacity and Scalability of LoRaWAN – ResearchGate
- Fundamentals of the LoRa Physical Layer – EDN Network
- What is LoRa Technology? – everything RF
- Link Budget Basics – Microwaves101
- LoRa Long Range Technology Overview – Texas Instruments
- Scalability of LoRaWAN for Massive IoT Deployment – MDPI Sensors
- Detailed Study of LoRa Low Power Communications – PMC
- 11 Myths About LoRa and LoRaWAN – Electronic Design
- LoRa Modulation Basics – Microwave Journal
Disclaimer:
The views and opinions expressed in this post are solely those of the author. The information provided is based on personal research, experience, and understanding of the subject matter at the time of writing. Readers should consult relevant experts or authorities for specific guidance related to their unique situations.
Related Posts
Rate this:
#915MHz #airtimeOptimization #AmateurRadio #antennaGain #bandwidthManagement #communicationSecurity #communityMesh #constrainedNodes #dataTransmission #DecentralizedNetworks #digitalModes #DisasterRecovery #dutyCycle #emergencyComms #ESP32 #FCCPart15 #firmwareFlashing #floodingProtocol #gridDownComms #hiddenNodeProblem #IoTScalability #ISMBand #linkBudget #LoRa #LoRaWAN #meshNetworking #MeshCore #Meshtastic #networkCongestion #nodeDensity #nRF52840 #offGridCommunication #packetCollisions #packetLoss #protocolOverhead #radioDiscipline #radioFrequency #RFEngineering #RFInterference #routingLogic #signalPropagation #SignalToNoiseRatio #SNR #spectralEfficiency #spreadingFactor #survivalTech #SX1262 #TacticalComms #wirelessProtocols -
The Broken Mesh: Why the Fight Between Meshtastic and MeshCore Matters
2,734 words, 14 minutes read time.
The fracture between the Meshtastic and MeshCore projects is a warning that you cannot ignore. For years, people thought a simple, off-grid data net was the answer for when the main lines go down. But now, the community is divided. This is not just a small fight over code. It is a total disagreement on how to handle communication when things get ugly. If you think you are ready just because you bought a cheap radio board and did not bother to learn how the software actually works, you are just a hobbyist playing with toys. The rift between Meshtastic and MeshCore shows how fragile these systems are and why you need to know your gear inside and out. A mesh net is only as good as its weakest link. If you do not master the tech, you are just a dead node in a silent town. We are seeing the growing pains of a decentralized technology that is outstripping the discipline of its users. You must choose your tools based on the reality of the physics, not the popularity of the app. Demand that your firmware be an efficient tool for data transmission, not a bloated social media platform for the 915 MHz band. If you do not take the time to understand the modulation, the packet structure, and the routing logic of the software you flash onto your hardware, you are just a child playing with a walkie-talkie while the grown-ups are trying to build a grid. Mastery of the radio spectrum is not an option; it is a requirement for anyone who claims to be prepared. This split is the first real test of whether civilian mesh can survive the chaos of its own success. You either learn to navigate the airwaves or you signal your own failure. Every packet you send without understanding the cost is a round wasted in a firefight. Stop treating your emergency comms like a smartphone app and start treating it like the life-support system it is. This technical mastery is the difference between a working link and a radio that does nothing but drain your battery in the dark.
Troubleshooting LoRa Mesh Protocol Inefficiency and Network Congestion
The fight between Meshtastic and MeshCore comes down to how they use the radio waves and the small chips that run them. Meshtastic has been the big name for a long time. It uses a flooding method where every radio repeats every message it hears. In the woods, that is fine. In a city with a hundred users, it is a train wreck. The air gets crowded, messages hit each other, and the whole system jams itself. MeshCore did not start because people wanted a new app. It started because the old way is inefficient. The core of the split is about the overhead—the extra data that hitches a ride on every message. Meshtastic adds a lot of features, but those features take up space. MeshCore wants to strip everything down to the bone so the network stays stable. When you have very little room to send data, every extra bit is a mistake. This is a battle between lots of features and it just has to work. If your software is fighting your hardware, you lose. The divergence between Meshtastic and MeshCore is rooted in the physics of the 900 MHz ISM band and the limitations of the ESP32 and nRF52 chipsets. As the node count grows, the airwaves become a chaotic mess of collisions and retransmissions, effectively jamming the very frequency the operators are trying to utilize. While Meshtastic has focused on a feature-rich user experience with a heavy reliance on a specific structure, MeshCore proponents argue for a leaner, more modular approach that prioritizes the stability of the underlying mesh over the bells and whistles of the interface. When you are operating on a low-bandwidth, high-latency medium like LoRa, every byte of overhead is a liability. You either master the protocol or you become a dead node. The math does not lie even if the marketing does. If your network protocol consumes more than ten percent of your bandwidth for heartbeats, your network is dying. Every extra feature in the code is another potential point of failure when the signal gets weak. You have to decide if you want a chat app or a survival tool. The flooding algorithm used by Meshtastic is a blunt instrument that was never meant for high-density urban deployment. It works by simply re-broadcasting every unique packet received until a hop limit is reached. In a sparse environment, this ensures the message gets through by any means necessary. But as the number of nodes increases, the probability of two nodes transmitting at the same time goes up. This leads to packet collisions where neither message is readable. MeshCore attempts to solve this by moving toward a more structured routing system. This means the software tries to figure out the best path for a message instead of just yelling it to everyone. This shift requires a level of technical discipline that many casual users find frustrating. It means the network is less plug-and-play and more of a precision tool. If you want a network that survives a real crisis, you have to move away from the chaos of flooding. You have to understand how the Media Access Control layer handles traffic. You have to know how to set your timing parameters so you are not stepping on your own neighbors. The split is a clear line in the sand between those who want ease of use and those who want engineering reliability. You cannot hide from the physics of the airwaves. Either your packets move or they die in the dirt. Stop assuming the software will fix your bad placement. Fix the engineering or get off the air.
Physics of LoRa Packet Collisions and Signal to Noise Ratio Analysis
To understand this split, you have to look at how these radios actually talk. They use a low-power system called LoRa. It is built for long range, but it is slow. There are strict rules on how long you can broadcast before you have to shut up and let others speak. Because Meshtastic repeats everything, adding more people makes the problem worse fast. This is not a glitch. It is physics. MeshCore was built to change how messages find their path through the net. Instead of everyone yelling at once, it wants a smarter way to move data that does not waste airtime. The split happened because one group likes the safety of repeating everything, while the other wants a clean, quiet network. If your radio is spending eighty percent of its power just saying I am here, you are not communicating—you are just making noise. The split proves that the current path is heading for a crash where no one can get a message through. LoRa is designed for long-range, low-power communication, but it is inherently limited by the Duty Cycle regulations of the FCC Part 15 and similar international bodies. Meshtastic’s current implementation of the flooding protocol means that as you add more users, the probability of packet storms increases exponentially. MeshCore was conceptualized to address the need for a more rigid, perhaps even more disciplined, routing logic that could potentially mitigate the hidden node problem and reduce the airtime usage per packet. The technical fallout between the two development paths stems from a disagreement on how to manage the limited airtime of the ISM band. One camp believes in the resilience of redundant flooding, while the other seeks a more surgical, routed approach to data delivery. This is a matter of Spectral Efficiency. If your mesh is using the majority of its available airtime just to say it exists, you have failed as an operator and an engineer. You are polluting the spectrum with digital noise. This noise prevents emergency traffic from getting through. It creates a false sense of security where people think they have a working link when they actually have a jammed one. You must look at the duty cycle of your own node. If you are transmitting more than one percent of the time in the 900 MHz band, you are likely part of the problem. MeshCore is an attempt to force the network into a more responsible state. It prioritizes the survival of the link over the convenience of the user. This is a hard truth that many do not want to hear. Physics does not care about your feelings or your user interface. It only cares about the signal-to-noise ratio. If your signal is lost in the noise of your own network, you have built nothing but a very expensive paperweight. Every packet sent is a risk. In a real-world scenario, a long transmission can be used to find your location. Flooding makes this risk much higher because your message is repeated over and over by every node in the area. A routed system like what MeshCore aims for reduces this risk by limiting the number of times a message is sent. This is not just about efficiency; it is about security. You have to understand that the airwaves are a shared resource. If you treat them like your own personal garbage dump, you will find yourself alone and unheard when the time comes to actually send a call for help. The split between Meshtastic and MeshCore is a debate over the very future of private, off-grid data. One side wants to make it accessible to everyone, while the other wants to make it work when nothing else does. You have to decide which side of that line you stand on. If you are not monitoring your packet loss and your noise floor, you are not an operator. You are just a passenger in a system that is bound to fail. Stop looking at the colorful screens and start looking at the spectrum. The truth is in the waterfall, not the icons. The physics of 915 MHz demand respect that a plug and play mindset cannot provide.
Off-Grid Communication Solutions and Technical Radio Discipline
The result of this fight is a mess where gear running one software will not talk to gear running the other. For you, that means your radio is a brick if your neighbor is on the other side of the fence. This is how a mesh net dies. A mesh needs everyone to speak the same language. When the builders split, the network breaks. This should wake up anyone who thinks they can just download a file and be safe. The hard truth is that we are seeing a new tech grow too fast for the people using it. You have to pick your tools based on facts, not what looks cool. Demand software that moves data fast and clean. If you do not know how your radio sends a packet or why some settings work better than others, you have no business relying on this in a pinch. The split between Meshtastic and MeshCore is a reminder that in the world of radio, there are no shortcuts. For the operator in the field, this means your gear might be useless if the person three blocks away is running a different branch of the protocol. This is the death of a mesh. A mesh requires a common language, a shared set of timing parameters, and a unified understanding of frequency hopping and spreading factors. When the developers split, the network breaks. This should serve as a wake-up call to anyone who thinks they can outsource their emergency communications to a GitHub repository they do not understand. The split between Meshtastic and MeshCore is a reminder that in the world of RF, there are no shortcuts. If you cannot explain the difference between a Spreading Factor of seven and twelve, or why a 125kHz bandwidth is preferable over 250kHz in a high-noise environment, you have no business relying on these tools. The hard truth is that we are witnessing the growing pains of a decentralized technology that is outstripping the discipline of its users. You must take personal responsibility for your station. This means testing your range with real-world obstacles. It means understanding how your antenna height and gain affect your local mesh. It means being able to re-flash your firmware in the dark while the rain is pouring down. If you cannot do these things, you are not prepared. You are just a collector of electronic gadgets. The discipline of the amateur radio spirit must be applied to these new digital modes. We are losing the technical edge that made the license worth having in the first place. The split is a chance to reset. It is a chance to move away from the appliance operator mindset and back toward the engineering mindset. You should be auditing your own mesh. Look at the traffic logs. See how many packets are being dropped. See how many of your traffic is just node discovery overhead. If you find that your network is inefficient, do not wait for a developer to fix it. Change your settings. Educate your neighbors. If the split leads to a better, more efficient protocol, then it was worth the friction. But if it just leads to two broken networks instead of one, then we have all lost. The practical application of this knowledge is simple: test everything. Do not assume your mesh will work because the light on the board is green. Prove it. Send data over the longest possible path. Monitor the battery drain. Watch the spectrum on an analyzer if you have one. If you do not have the tools to verify your network, you do not have a network. You have a hope. And hope is not a plan for communication. Secure your nodes, harden your protocol, and stop relying on software you have never bothered to read. The day is coming when the only thing between you and the void is the connection you built yourself. Don’t let it be a connection built on laziness. Clean up your messy node or accept that you will be silent when it matters.
Conclusion: The Future of Decentralized Mesh Networks and User Mastery
The discipline of the old-school radio operator has to be applied here or the whole thing will fail. The split between Meshtastic and MeshCore is a call to stop being a lazy user and start being a real operator. We do not have time for good enough when the grid is down. Check your gear, learn the rules of the airwaves, and be ready for a future where the channels are full and the software is broken. Build your setup expecting things to break. There is no room for being soft. Learn the math, understand your range, and make sure every message you send is worth the airtime. The grid is weak, the airwaves are crowded, and your own lack of knowledge is the only thing truly blocking your signal. Fix your gear, learn the system, and stop waiting for someone else to save you. The grid is fragile, the spectrum is finite, and your ignorance is the only thing standing between you and a total blackout. Fix your station, fix your protocol, and stop waiting for someone else to secure your link. The time for playing games with digital toys is over. Mastery is the only way forward. Master the code, master the RF, or stay off the air. This hobby demands engineers, not appliance operators. Be the asset the network needs, not the QRM that kills it. Finalize your build, test the link, and maintain the discipline required to keep the airwaves open for those who truly need them.
Call to Action
Join the Network and Master Your Comms Before the Grid Goes Dark. The split between Meshtastic and MeshCore is a wake-up call for every operator. You cannot afford to be a passive user when the lines of communication are at stake. Whether you choose the feature-rich path or the lean efficiency of the core, the responsibility for a working link lies with you. Don’t wait for a crisis to realize your nodes are misconfigured or your protocol is inefficient. Start auditing your setup today by getting out in the field to find your real-world limits, diving into the spreading factors to clear the noise, and educating your local mesh to ensure your neighborhood stays connected. The airwaves belong to those who master them. Secure your hardware, flash your firmware, and become a reliable node in the decentralized future. Join the conversation, build the grid, and stay off the silent list.
SUPPORTSUBSCRIBECONTACT MED. Bryan King
Sources
- FCC Part 15 Radio Frequency Devices – Federal Communications Commission
- SX1262 LoRa Transceiver Datasheet – Semtech
- Meshtastic Project Documentation – Meshtastic
- A Study of LoRa: Long Range and Low Power Networks for the Internet of Things – IEEE
- The ARRL Handbook for Radio Communications – ARRL
- Guide to Bluetooth Security (RF Protocol Standards) – NIST
- LoRaWAN 1.1 Specification – LoRa Alliance
- Do LoRa Low-Power Wide-Area Networks Scale? – IEEE
- ESP32 Series Datasheet – Espressif Systems
- nRF52840 Product Specification – Nordic Semiconductor
- Terminology for Constrained-Node Networks – IETF
- ITU Handbook on Land Mobile Communications – International Telecommunication Union
- Protocol Buffers Documentation – Google Developers
- Understanding the Basics of LoRa and LoRaWAN – DigiKey
- LoRa Technology: A Technical Overview – NXP Semiconductors
- LoRaWAN Documentation – The Things Network
- Guide to Bluetooth Security – NIST Special Publication
- LoRa Physical Layer Packet Structure – RF Wireless World
- LoRa Wireless Technology – Microchip Technology
- Understanding and Enhancing RF Link Budget – Analog Devices
- LoRaWAN Technology Overview – STMicroelectronics
- Analysis of the Capacity and Scalability of LoRaWAN – ResearchGate
- Fundamentals of the LoRa Physical Layer – EDN Network
- What is LoRa Technology? – everything RF
- Link Budget Basics – Microwaves101
- LoRa Long Range Technology Overview – Texas Instruments
- Scalability of LoRaWAN for Massive IoT Deployment – MDPI Sensors
- Detailed Study of LoRa Low Power Communications – PMC
- 11 Myths About LoRa and LoRaWAN – Electronic Design
- LoRa Modulation Basics – Microwave Journal
Disclaimer:
The views and opinions expressed in this post are solely those of the author. The information provided is based on personal research, experience, and understanding of the subject matter at the time of writing. Readers should consult relevant experts or authorities for specific guidance related to their unique situations.
Related Posts
Rate this:
#915MHz #airtimeOptimization #AmateurRadio #antennaGain #bandwidthManagement #communicationSecurity #communityMesh #constrainedNodes #dataTransmission #DecentralizedNetworks #digitalModes #DisasterRecovery #dutyCycle #emergencyComms #ESP32 #FCCPart15 #firmwareFlashing #floodingProtocol #gridDownComms #hiddenNodeProblem #IoTScalability #ISMBand #linkBudget #LoRa #LoRaWAN #meshNetworking #MeshCore #Meshtastic #networkCongestion #nodeDensity #nRF52840 #offGridCommunication #packetCollisions #packetLoss #protocolOverhead #radioDiscipline #radioFrequency #RFEngineering #RFInterference #routingLogic #signalPropagation #SignalToNoiseRatio #SNR #spectralEfficiency #spreadingFactor #survivalTech #SX1262 #TacticalComms #wirelessProtocols -
curl
Daniël Stenberg
facts and praise
I'm fortunate that I am allowed to follow Daniël, lead programmer of the mighty
curl. The reason I formulated the line in this way, is because only through the power of the FediVerse I've gotten a boost from someone I follow, who found a post of the lead programmer or curl interestingstats:
install base => 20000*106 devices
20 billion+ installations!
curlis used in command lines or scripts to transfer data. curl is alsolibcurl, used in:- cars
- television sets
- routers
- printers
- audio equipment
- mobile phones
- tablets
- medical devices
- settop boxes
- computer games
- media players
Curl is THE Internet transfer engine for countless software applications in over twenty billion installations!
curl is used daily by virtually every Internet-using human on the globe!
curl is 30 years old
Let that sink in!
Opinion
curlis mature critical network infrastructure software that we all need to have our internet powered software / hardware to function in respect to data transfer.The syntax to use
curlin simple implementations is IMHO quite easy. In case you need to know an extra option, the executable andlibcurlhave excellent documentation. End users normally interact withcurlusing the (elf) binary on Linux based POSIX operating systems. The more mature BSDs have another binary formatJust type
curlto get an initial output which looks like this on my current systemcurl
curl: try 'curl --help' or 'curl --manual' for more informationthen type
curl --help
Usage: curl [options...] <url>
-d, --data <data> HTTP POST data
-f, --fail Fail fast with no output on HTTP errors
-h, --help <subject> Get help for commands
-o, --output <file> Write to file instead of stdout
-O, --remote-name Write output to file named as remote file
-i, --show-headers Show response headers in output
-s, --silent Silent mode
-T, --upload-file <file> Transfer local FILE to destination
-u, --user <user:password> Server user and password
-A, --user-agent <name> Send User-Agent <name> to server
-v, --verbose Make the operation more talkative
-V, --version Show version number and quit
This is not the full help; this menu is split into categories.
Use "--help category" to get an overview of all categories, which are:
auth, connection, curl, deprecated, dns, file, ftp, global, http, imap, ldap, output, pop3, post, proxy,
scp, sftp, smtp, ssh, telnet, tftp, timeout, tls, upload, verbose.
Use "--help all" to list all options
Use "--help [option]" to view documentation for a given optionWhen you type
curl --manual|lessyou get the manpages which I delimited withlessthrough a vertical pipe_ _ ____ _
___| | | | _ \| |
/ __| | | | |_) | |
| (__| |_| | _ <| |___
\___|\___/|_| \_\_____|
NAME
curl - transfer a URL
SYNOPSIS
curl [options / URLs]
DESCRIPTION
curl is a tool for transferring data from or to a server using URLs. It
supports these protocols: DICT, FILE, FTP, FTPS, GOPHER, GOPHERS, HTTP,
HTTPS, IMAP, IMAPS, LDAP, LDAPS, MQTT, POP3, POP3S, RTMP, RTMPS, RTSP,
SCP, SFTP, SMB, SMBS, SMTP, SMTPS, TELNET, TFTP, WS and WSS.
curl is powered by libcurl for all transfer-related features. See
libcurl(3) for details.
URL
The URL syntax is protocol-dependent. You find a detailed description in
RFC 3986.I can also type
man curlto get a nice output:curl(1) curl Manual curl(1)
NAME
curl - transfer a URL
SYNOPSIS
curl [options / URLs]
DESCRIPTION
curl is a tool for transferring data from or to a server using URLs. It supports these protocols:
DICT, FILE, FTP, FTPS, GOPHER, GOPHERS, HTTP, HTTPS, IMAP, IMAPS, LDAP, LDAPS, MQTT, POP3, POP3S,
RTMP, RTMPS, RTSP, SCP, SFTP, SMB, SMBS, SMTP, SMTPS, TELNET, TFTP, WS and WSS.
curl is powered by libcurl for all transfer-related features. See libcurl(3) for details.
URL
The URL syntax is protocol-dependent. You find a detailed description in RFC 3986.
If you provide a URL without a leading protocol:// scheme, curl guesses what protocol you want. It
then defaults to HTTP but assumes others based on often-used hostname prefixes. For example, for
hostnames starting with "ftp." curl assumes you want FTP.
You can specify any amount of URLs on the command line. They are fetched in a sequential manner in
the specified order unless you use -Z, --parallel. You can specify command line options and URLs
Manual page curl(1) line 1 (press h for help or q to quit)The reasoning behind curl --manual is simple. On a machine without the manual system you still need access to the full manual. This is one of the reasons why
man curlis also implemented ascurl --manualAn important RFC is echoed to my terminal in the
man curloutput which is RFC 3986A Uniform Resource Identifier (URI) is a compact sequence of
characters that identifies an abstract or physical resource. This
specification defines the generic URI syntax and a process for
resolving URI references that might be in relative form, along with
guidelines and security considerations for the use of URIs on the
Internet. The URI syntax defines a grammar that is a superset of all
valid URIs, allowing an implementation to parse the common components
of a URI reference without knowing the scheme-specific requirements
of every possible identifier. This specification does not define a
generative grammar for URIs; that task is performed by the individual
specifications of each URI scheme.I shall not quote the whole RFC 3986 here. You can read all about it on the RFC site (see sources)
As you can see
curlis thorougly documented, has all the features a simple end user needs to fetch all kind of data, scaled up all the way to the extensive complex features router hardware et all, needs to transfer data.programming route
I came to this toot when I saw that certain external feature code, which lives in stable external libraries, is now being removed from curl. I should say the code is depreciated then phased out.
This is a logical step
- It takes resources to maintain external code
- If the (shared) libraries are stable and mature, it's much better to just call those libraries and be done.
- The more external code you can remove from your project the better it is for all the programmers
The same is also happening in the Linux kernel, they are following in the footsteps of curl
Conclusion
There is a treasure trove of information in the sources. Just reading the pages on RFC 3986 will keep you occupied for hours.
Have fun and keep reading / learning and programming!sources:
https://www.rfc-editor.org/rfc/rfc3986
https://curl.se/mail/lib-2026-03/0026.html
#curl #programming #mathematics #linear #algebra #libcurl #Linux #BSD #freeBSD #openBSD #netBSD #POSIX #bash #csh #ksh #sh #fish #radio #TV #smartTV #router
-
curl
Daniël Stenberg
facts and praise
I'm fortunate that I am allowed to follow Daniël, lead programmer of the mighty
curl. The reason I formulated the line in this way, is because only through the power of the FediVerse I've gotten a boost from someone I follow, who found a post of the lead programmer or curl interestingstats:
install base => 20000*106 devices
20 billion+ installations!
curlis used in command lines or scripts to transfer data. curl is alsolibcurl, used in:- cars
- television sets
- routers
- printers
- audio equipment
- mobile phones
- tablets
- medical devices
- settop boxes
- computer games
- media players
Curl is THE Internet transfer engine for countless software applications in over twenty billion installations!
curl is used daily by virtually every Internet-using human on the globe!
curl is 30 years old
Let that sink in!
Opinion
curlis mature critical network infrastructure software that we all need to have our internet powered software / hardware to function in respect to data transfer.The syntax to use
curlin simple implementations is IMHO quite easy. In case you need to know an extra option, the executable andlibcurlhave excellent documentation. End users normally interact withcurlusing the (elf) binary on Linux based POSIX operating systems. The more mature BSDs have another binary formatJust type
curlto get an initial output which looks like this on my current systemcurl
curl: try 'curl --help' or 'curl --manual' for more informationthen type
curl --help
Usage: curl [options...] <url>
-d, --data <data> HTTP POST data
-f, --fail Fail fast with no output on HTTP errors
-h, --help <subject> Get help for commands
-o, --output <file> Write to file instead of stdout
-O, --remote-name Write output to file named as remote file
-i, --show-headers Show response headers in output
-s, --silent Silent mode
-T, --upload-file <file> Transfer local FILE to destination
-u, --user <user:password> Server user and password
-A, --user-agent <name> Send User-Agent <name> to server
-v, --verbose Make the operation more talkative
-V, --version Show version number and quit
This is not the full help; this menu is split into categories.
Use "--help category" to get an overview of all categories, which are:
auth, connection, curl, deprecated, dns, file, ftp, global, http, imap, ldap, output, pop3, post, proxy,
scp, sftp, smtp, ssh, telnet, tftp, timeout, tls, upload, verbose.
Use "--help all" to list all options
Use "--help [option]" to view documentation for a given optionWhen you type
curl --manual|lessyou get the manpages which I delimited withlessthrough a vertical pipe_ _ ____ _
___| | | | _ \| |
/ __| | | | |_) | |
| (__| |_| | _ <| |___
\___|\___/|_| \_\_____|
NAME
curl - transfer a URL
SYNOPSIS
curl [options / URLs]
DESCRIPTION
curl is a tool for transferring data from or to a server using URLs. It
supports these protocols: DICT, FILE, FTP, FTPS, GOPHER, GOPHERS, HTTP,
HTTPS, IMAP, IMAPS, LDAP, LDAPS, MQTT, POP3, POP3S, RTMP, RTMPS, RTSP,
SCP, SFTP, SMB, SMBS, SMTP, SMTPS, TELNET, TFTP, WS and WSS.
curl is powered by libcurl for all transfer-related features. See
libcurl(3) for details.
URL
The URL syntax is protocol-dependent. You find a detailed description in
RFC 3986.I can also type
man curlto get a nice output:curl(1) curl Manual curl(1)
NAME
curl - transfer a URL
SYNOPSIS
curl [options / URLs]
DESCRIPTION
curl is a tool for transferring data from or to a server using URLs. It supports these protocols:
DICT, FILE, FTP, FTPS, GOPHER, GOPHERS, HTTP, HTTPS, IMAP, IMAPS, LDAP, LDAPS, MQTT, POP3, POP3S,
RTMP, RTMPS, RTSP, SCP, SFTP, SMB, SMBS, SMTP, SMTPS, TELNET, TFTP, WS and WSS.
curl is powered by libcurl for all transfer-related features. See libcurl(3) for details.
URL
The URL syntax is protocol-dependent. You find a detailed description in RFC 3986.
If you provide a URL without a leading protocol:// scheme, curl guesses what protocol you want. It
then defaults to HTTP but assumes others based on often-used hostname prefixes. For example, for
hostnames starting with "ftp." curl assumes you want FTP.
You can specify any amount of URLs on the command line. They are fetched in a sequential manner in
the specified order unless you use -Z, --parallel. You can specify command line options and URLs
Manual page curl(1) line 1 (press h for help or q to quit)The reasoning behind curl --manual is simple. On a machine without the manual system you still need access to the full manual. This is one of the reasons why
man curlis also implemented ascurl --manualAn important RFC is echoed to my terminal in the
man curloutput which is RFC 3986A Uniform Resource Identifier (URI) is a compact sequence of
characters that identifies an abstract or physical resource. This
specification defines the generic URI syntax and a process for
resolving URI references that might be in relative form, along with
guidelines and security considerations for the use of URIs on the
Internet. The URI syntax defines a grammar that is a superset of all
valid URIs, allowing an implementation to parse the common components
of a URI reference without knowing the scheme-specific requirements
of every possible identifier. This specification does not define a
generative grammar for URIs; that task is performed by the individual
specifications of each URI scheme.I shall not quote the whole RFC 3986 here. You can read all about it on the RFC site (see sources)
As you can see
curlis thorougly documented, has all the features a simple end user needs to fetch all kind of data, scaled up all the way to the extensive complex features router hardware et all, needs to transfer data.programming route
I came to this toot when I saw that certain external feature code, which lives in stable external libraries, is now being removed from curl. I should say the code is depreciated then phased out.
This is a logical step
- It takes resources to maintain external code
- If the (shared) libraries are stable and mature, it's much better to just call those libraries and be done.
- The more external code you can remove from your project the better it is for all the programmers
The same is also happening in the Linux kernel, they are following in the footsteps of curl
Conclusion
There is a treasure trove of information in the sources. Just reading the pages on RFC 3986 will keep you occupied for hours.
Have fun and keep reading / learning and programming!sources:
https://www.rfc-editor.org/rfc/rfc3986
https://curl.se/mail/lib-2026-03/0026.html
#curl #programming #mathematics #linear #algebra #libcurl #Linux #BSD #freeBSD #openBSD #netBSD #POSIX #bash #csh #ksh #sh #fish #radio #TV #smartTV #router
-
curl
Daniël Stenberg
facts and praise
I'm fortunate that I am allowed to follow Daniël, lead programmer of the mighty
curl. The reason I formulated the line in this way, is because only through the power of the FediVerse I've gotten a boost from someone I follow, who found a post of the lead programmer or curl interestingstats:
install base => 20000*106 devices
20 billion+ installations!
curlis used in command lines or scripts to transfer data. curl is alsolibcurl, used in:- cars
- television sets
- routers
- printers
- audio equipment
- mobile phones
- tablets
- medical devices
- settop boxes
- computer games
- media players
Curl is THE Internet transfer engine for countless software applications in over twenty billion installations!
curl is used daily by virtually every Internet-using human on the globe!
curl is 30 years old
Let that sink in!
Opinion
curlis mature critical network infrastructure software that we all need to have our internet powered software / hardware to function in respect to data transfer.The syntax to use
curlin simple implementations is IMHO quite easy. In case you need to know an extra option, the executable andlibcurlhave excellent documentation. End users normally interact withcurlusing the (elf) binary on Linux based POSIX operating systems. The more mature BSDs have another binary formatJust type
curlto get an initial output which looks like this on my current systemcurl
curl: try 'curl --help' or 'curl --manual' for more informationthen type
curl --help
Usage: curl [options...] <url>
-d, --data <data> HTTP POST data
-f, --fail Fail fast with no output on HTTP errors
-h, --help <subject> Get help for commands
-o, --output <file> Write to file instead of stdout
-O, --remote-name Write output to file named as remote file
-i, --show-headers Show response headers in output
-s, --silent Silent mode
-T, --upload-file <file> Transfer local FILE to destination
-u, --user <user:password> Server user and password
-A, --user-agent <name> Send User-Agent <name> to server
-v, --verbose Make the operation more talkative
-V, --version Show version number and quit
This is not the full help; this menu is split into categories.
Use "--help category" to get an overview of all categories, which are:
auth, connection, curl, deprecated, dns, file, ftp, global, http, imap, ldap, output, pop3, post, proxy,
scp, sftp, smtp, ssh, telnet, tftp, timeout, tls, upload, verbose.
Use "--help all" to list all options
Use "--help [option]" to view documentation for a given optionWhen you type
curl --manual|lessyou get the manpages which I delimited withlessthrough a vertical pipe_ _ ____ _
___| | | | _ \| |
/ __| | | | |_) | |
| (__| |_| | _ <| |___
\___|\___/|_| \_\_____|
NAME
curl - transfer a URL
SYNOPSIS
curl [options / URLs]
DESCRIPTION
curl is a tool for transferring data from or to a server using URLs. It
supports these protocols: DICT, FILE, FTP, FTPS, GOPHER, GOPHERS, HTTP,
HTTPS, IMAP, IMAPS, LDAP, LDAPS, MQTT, POP3, POP3S, RTMP, RTMPS, RTSP,
SCP, SFTP, SMB, SMBS, SMTP, SMTPS, TELNET, TFTP, WS and WSS.
curl is powered by libcurl for all transfer-related features. See
libcurl(3) for details.
URL
The URL syntax is protocol-dependent. You find a detailed description in
RFC 3986.I can also type
man curlto get a nice output:curl(1) curl Manual curl(1)
NAME
curl - transfer a URL
SYNOPSIS
curl [options / URLs]
DESCRIPTION
curl is a tool for transferring data from or to a server using URLs. It supports these protocols:
DICT, FILE, FTP, FTPS, GOPHER, GOPHERS, HTTP, HTTPS, IMAP, IMAPS, LDAP, LDAPS, MQTT, POP3, POP3S,
RTMP, RTMPS, RTSP, SCP, SFTP, SMB, SMBS, SMTP, SMTPS, TELNET, TFTP, WS and WSS.
curl is powered by libcurl for all transfer-related features. See libcurl(3) for details.
URL
The URL syntax is protocol-dependent. You find a detailed description in RFC 3986.
If you provide a URL without a leading protocol:// scheme, curl guesses what protocol you want. It
then defaults to HTTP but assumes others based on often-used hostname prefixes. For example, for
hostnames starting with "ftp." curl assumes you want FTP.
You can specify any amount of URLs on the command line. They are fetched in a sequential manner in
the specified order unless you use -Z, --parallel. You can specify command line options and URLs
Manual page curl(1) line 1 (press h for help or q to quit)The reasoning behind curl --manual is simple. On a machine without the manual system you still need access to the full manual. This is one of the reasons why
man curlis also implemented ascurl --manualAn important RFC is echoed to my terminal in the
man curloutput which is RFC 3986A Uniform Resource Identifier (URI) is a compact sequence of
characters that identifies an abstract or physical resource. This
specification defines the generic URI syntax and a process for
resolving URI references that might be in relative form, along with
guidelines and security considerations for the use of URIs on the
Internet. The URI syntax defines a grammar that is a superset of all
valid URIs, allowing an implementation to parse the common components
of a URI reference without knowing the scheme-specific requirements
of every possible identifier. This specification does not define a
generative grammar for URIs; that task is performed by the individual
specifications of each URI scheme.I shall not quote the whole RFC 3986 here. You can read all about it on the RFC site (see sources)
As you can see
curlis thorougly documented, has all the features a simple end user needs to fetch all kind of data, scaled up all the way to the extensive complex features router hardware et all, needs to transfer data.programming route
I came to this toot when I saw that certain external feature code, which lives in stable external libraries, is now being removed from curl. I should say the code is depreciated then phased out.
This is a logical step
- It takes resources to maintain external code
- If the (shared) libraries are stable and mature, it's much better to just call those libraries and be done.
- The more external code you can remove from your project the better it is for all the programmers
The same is also happening in the Linux kernel, they are following in the footsteps of curl
Conclusion
There is a treasure trove of information in the sources. Just reading the pages on RFC 3986 will keep you occupied for hours.
Have fun and keep reading / learning and programming!sources:
https://www.rfc-editor.org/rfc/rfc3986
https://curl.se/mail/lib-2026-03/0026.html
#curl #programming #mathematics #linear #algebra #libcurl #Linux #BSD #freeBSD #openBSD #netBSD #POSIX #bash #csh #ksh #sh #fish #radio #TV #smartTV #router
-
curl
Daniël Stenberg
facts and praise
I'm fortunate that I am allowed to follow Daniël, lead programmer of the mighty
curl. The reason I formulated the line in this way, is because only through the power of the FediVerse I've gotten a boost from someone I follow, who found a post of the lead programmer or curl interestingstats:
install base => 20000*106 devices
20 billion+ installations!
curlis used in command lines or scripts to transfer data. curl is alsolibcurl, used in:- cars
- television sets
- routers
- printers
- audio equipment
- mobile phones
- tablets
- medical devices
- settop boxes
- computer games
- media players
Curl is THE Internet transfer engine for countless software applications in over twenty billion installations!
curl is used daily by virtually every Internet-using human on the globe!
curl is 30 years old
Let that sink in!
Opinion
curlis mature critical network infrastructure software that we all need to have our internet powered software / hardware to function in respect to data transfer.The syntax to use
curlin simple implementations is IMHO quite easy. In case you need to know an extra option, the executable andlibcurlhave excellent documentation. End users normally interact withcurlusing the (elf) binary on Linux based POSIX operating systems. The more mature BSDs have another binary formatJust type
curlto get an initial output which looks like this on my current systemcurl
curl: try 'curl --help' or 'curl --manual' for more informationthen type
curl --help
Usage: curl [options...] <url>
-d, --data <data> HTTP POST data
-f, --fail Fail fast with no output on HTTP errors
-h, --help <subject> Get help for commands
-o, --output <file> Write to file instead of stdout
-O, --remote-name Write output to file named as remote file
-i, --show-headers Show response headers in output
-s, --silent Silent mode
-T, --upload-file <file> Transfer local FILE to destination
-u, --user <user:password> Server user and password
-A, --user-agent <name> Send User-Agent <name> to server
-v, --verbose Make the operation more talkative
-V, --version Show version number and quit
This is not the full help; this menu is split into categories.
Use "--help category" to get an overview of all categories, which are:
auth, connection, curl, deprecated, dns, file, ftp, global, http, imap, ldap, output, pop3, post, proxy,
scp, sftp, smtp, ssh, telnet, tftp, timeout, tls, upload, verbose.
Use "--help all" to list all options
Use "--help [option]" to view documentation for a given optionWhen you type
curl --manual|lessyou get the manpages which I delimited withlessthrough a vertical pipe_ _ ____ _
___| | | | _ \| |
/ __| | | | |_) | |
| (__| |_| | _ <| |___
\___|\___/|_| \_\_____|
NAME
curl - transfer a URL
SYNOPSIS
curl [options / URLs]
DESCRIPTION
curl is a tool for transferring data from or to a server using URLs. It
supports these protocols: DICT, FILE, FTP, FTPS, GOPHER, GOPHERS, HTTP,
HTTPS, IMAP, IMAPS, LDAP, LDAPS, MQTT, POP3, POP3S, RTMP, RTMPS, RTSP,
SCP, SFTP, SMB, SMBS, SMTP, SMTPS, TELNET, TFTP, WS and WSS.
curl is powered by libcurl for all transfer-related features. See
libcurl(3) for details.
URL
The URL syntax is protocol-dependent. You find a detailed description in
RFC 3986.I can also type
man curlto get a nice output:curl(1) curl Manual curl(1)
NAME
curl - transfer a URL
SYNOPSIS
curl [options / URLs]
DESCRIPTION
curl is a tool for transferring data from or to a server using URLs. It supports these protocols:
DICT, FILE, FTP, FTPS, GOPHER, GOPHERS, HTTP, HTTPS, IMAP, IMAPS, LDAP, LDAPS, MQTT, POP3, POP3S,
RTMP, RTMPS, RTSP, SCP, SFTP, SMB, SMBS, SMTP, SMTPS, TELNET, TFTP, WS and WSS.
curl is powered by libcurl for all transfer-related features. See libcurl(3) for details.
URL
The URL syntax is protocol-dependent. You find a detailed description in RFC 3986.
If you provide a URL without a leading protocol:// scheme, curl guesses what protocol you want. It
then defaults to HTTP but assumes others based on often-used hostname prefixes. For example, for
hostnames starting with "ftp." curl assumes you want FTP.
You can specify any amount of URLs on the command line. They are fetched in a sequential manner in
the specified order unless you use -Z, --parallel. You can specify command line options and URLs
Manual page curl(1) line 1 (press h for help or q to quit)The reasoning behind curl --manual is simple. On a machine without the manual system you still need access to the full manual. This is one of the reasons why
man curlis also implemented ascurl --manualAn important RFC is echoed to my terminal in the
man curloutput which is RFC 3986A Uniform Resource Identifier (URI) is a compact sequence of
characters that identifies an abstract or physical resource. This
specification defines the generic URI syntax and a process for
resolving URI references that might be in relative form, along with
guidelines and security considerations for the use of URIs on the
Internet. The URI syntax defines a grammar that is a superset of all
valid URIs, allowing an implementation to parse the common components
of a URI reference without knowing the scheme-specific requirements
of every possible identifier. This specification does not define a
generative grammar for URIs; that task is performed by the individual
specifications of each URI scheme.I shall not quote the whole RFC 3986 here. You can read all about it on the RFC site (see sources)
As you can see
curlis thorougly documented, has all the features a simple end user needs to fetch all kind of data, scaled up all the way to the extensive complex features router hardware et all, needs to transfer data.programming route
I came to this toot when I saw that certain external feature code, which lives in stable external libraries, is now being removed from curl. I should say the code is depreciated then phased out.
This is a logical step
- It takes resources to maintain external code
- If the (shared) libraries are stable and mature, it's much better to just call those libraries and be done.
- The more external code you can remove from your project the better it is for all the programmers
The same is also happening in the Linux kernel, they are following in the footsteps of curl
Conclusion
There is a treasure trove of information in the sources. Just reading the pages on RFC 3986 will keep you occupied for hours.
Have fun and keep reading / learning and programming!sources:
https://www.rfc-editor.org/rfc/rfc3986
https://curl.se/mail/lib-2026-03/0026.html
#curl #programming #mathematics #linear #algebra #libcurl #Linux #BSD #freeBSD #openBSD #netBSD #POSIX #bash #csh #ksh #sh #fish #radio #TV #smartTV #router
-
I was going to leave things at Part 3 blog-wise, and just get on with filling in the gaps in code now, but I’ve come back to add a few more notes. But this is likely to be the final part now.
Recall so far, I have:
- Part 1 where I work out how to build Synth_Dexed using the Pico SDK and get some sounds coming out.
- Part 2 where I take a detailed look at the performance with a diversion into the workings of the pico_audio library and floating point maths on the pico, on the way.
- Part 3 where I managed to get up to 16-note polyphony, by overclocking, and some basic serial MIDI support.
This is building on the last part and includes notes on how I’ve implemented the following:
- Fuller MIDI support, including control change, program change and pitch bend messages.
- Voice and voice banks, selectable over MIDI.
- MIDI SysEx messages for voice parameters.
- USB MIDI device support.
The latest code can be found on GitHub here: https://github.com/diyelectromusic/picodexed
Warning! I strongly recommend using old or second hand equipment for your experiments. I am not responsible for any damage to expensive instruments!
If you are new to microcontrollers, see the Getting Started pages.
MIDI Support
I’m not going to walk through all the details of how I’ve added MIDI but suffice to say that once again the implementation owes a lot to MiniDexed and the Arduino MIDI Library.
At the time of writing the following are all supported as they were already supported in Synth_Dexed, so I just needed to glue the bits together.
Channel Voice Messages (only channel 1 at present)
0x80MIDI Note Offnote=0..127, vel=0..1270x90MIDI Note Onnote=0..127, vel=0..1270xA0Channel Aftertouchnote=0..127, val=0..1270xB0Control ChangeSee below0xC0Program Change0..31 (If used with BANKSEL)
0..127 (if used independently)0xE0Pitch Bend0..16383 (in LSB/MSB 2×7-bit format)Channel Control Change Messages
0Bank Select (MSB)01Modulation0..1272Breath Control0..1274Foot Control0..1277Channel Volume0..12732Bank Select (LSB)0..864Sustain<=63 Off, 64=> On65Portamento<=63 Off, 64=> On95Master Tune0..127 *120All Sound Off0123All Notes Off0126Mono Mode0 **127Poly Mode0* There is a bug with the master tuning. It ought to accept -99 to 99 I believe, but only 0..99 will actually register and there is no way to send -99 via MIDI at the moment. I need to read up on what is going on here and what it ought to do!
** The Mono Mode parameter has the option for specifying how many of the playable voices can be dedicated to mono mode (at least I think that is what it is saying). I only support a value of 0 which I believe is meant to mean “all available voices”.
System Messages
0xF0..0xF7Start/End System ExclusiveSee below0xFEActive SensingFiltered out0xFnOther system messagesIgnoredSystem Exclusive Messages
Any valid Yamaha (DX) system exclusive messages are passed straight into Synth_Dexed. A Yamaha (DX) message has the following format (see the “DX7IIFD/D Supplemental Booklet: Advanced MIDI Data and Charts”):
F0 - start SysEx message
43 - Yamaha manufacturer ID
sd - s=substatus (command class:0,1,2); d=device ID (0..F)
.. data ..
F7 - end SysEx messageThe device ID can be set using the UI on a real DX7 to a value between 1 and 16, which becomes a value between 0 and 15 (0..F) as part of the SysEx message (see “DX7IIFD/D Supplemental Booklet: Advanced MIDI Applications, Section 8”). It is a Systems Exclusive value analogous to the MIDI channel for regular channel messages.
There are a range of Sys Ex parameter settings that have been passed onto Synth_Dexed as follows:
Mono Mode0..1Pitch Bend Range0..12Pitch Bend Step0..12Portamento Mode0..1Portamento Glissando0..1Portamento Time0..99Mod Wheel Range0..99Mod Wheel Target0..7Foot Control Range0..99Foot Control Target0..7Breath Control Range0..99Breath Control Target0..7Aftertouch Range0..99Aftertouch Target0..7Voice Dump Load<156 bytes of voice data>Voice Parameter SetParameter=0..155; Data=0..99At this stage, all of the MIDI support is on a “it’s probably something like this” basis, so it will evolve as I find out what it is meant to be doing!
Voice and Bank Loading
Banks of voices are programmed directly into the code. There is a python script from Synth_Dexed that will take a .syx format voice bank and generate a block of C code. I’ve included a script to download the main 8 banks of standard DX voices and run the script:
#!/bin/sh
# Get voices from
# https://yamahablackboxes.com/collection/yamaha-dx7-synthesizer/patches/
mkdir -p voices
DIR="https://yamahablackboxes.com/patches/dx7/factory"
wget -c "${DIR}"/rom1a.syx -O voices/rom1a.syx
wget -c "${DIR}"/rom1b.syx -O voices/rom1b.syx
wget -c "${DIR}"/rom2a.syx -O voices/rom2a.syx
wget -c "${DIR}"/rom2b.syx -O voices/rom2b.syx
wget -c "${DIR}"/rom3a.syx -O voices/rom3a.syx
wget -c "${DIR}"/rom3b.syx -O voices/rom3b.syx
wget -c "${DIR}"/rom4a.syx -O voices/rom4a.syx
wget -c "${DIR}"/rom4b.syx -O voices/rom4b.syx
./synth_dexed/Synth_Dexed/tools/sysex2c.py voices/* > src/voices.hThis only needs to be run once to create the src/voices.h file which is then included in the build.
Voices have the following format:
uint8_t progmem_bank[8][32][128] PROGMEM =
{
{ // Bank 1
{<--128 bytes of packed voice data-->} // Voice 1
...
{<--128 bytes of packed voice data-->} // Voice 32
}
{ // Bank 2
...
}
...
{ // Bank 8
{<--128 bytes of packed voice data-->} // Voice 1
...
{<--128 bytes of packed voice data-->} // Voice 32
}
}The system assumes 8 banks of 32 voices each, in the “packed” SYX header format, meaning each voice consists of 128 bytes.
MIDI Bank and Voice Selection
As there are only 8 banks, only BANKSEL (LSB) values 0..7 are valid. Program Change will work in two ways however:
- 0..31 will select voices 1 to 32 in the current bank.
- 31..127 will select voices from the following three adjacent banks.
To select any voice in all 8 banks thus requires the following sequence:
BANKSEL MSB = 0
BANKSEL LSB = 0..7
PROG CHANGE = 0..31But if bank selection is skipped, then Program Change messages can still be used to select one of the first 128 voices across four consecutive banks.
USB MIDI
The Raspberry Pi Pico SDK uses the TinyUSB protocol stack to implement USB device or host modes and there is an additional option to implement a second USB host port using the Pico’s PIO.
However, USB MIDI appears to only be supported for USB devices at the time of writing, so I’m just using the built-in USB port as a USB device, based on the code provided as part of the TinyUSB examples (more details of how to get basic USB MIDI running here).
TinyUSB MIDI supports two interfaces for reading data, and this wasn’t immediately obvious from the example as that is only sending data and ignores anything coming in.
- USB MIDI Stream mode: this will fill a provided buffer with MIDI data received over USB.
- USB MIDI Packet mode: this will return each 4-byte USB packet individually.
From what I can see of the USB MIDI Spec, all MIDI messages are turned into 4-byte packets for transferring over USB. All normal MIDI messages will consist of 1, 2 or 3 byte messages, and so will fit in a packet each – any unused bytes are padded with 0.
However SysEx messages are a little more complicated and have to be split across multiple packets.
This is the format for a USB MIDI Event Packet (see the “Universal Serial Bus Device Class Definition for MIDI Devices”, Release 1.0):
The code index number is an indication of the contents of each packet. For channel messages, this is basically a repeat of the MIDI command, so a MIDI Note On message might look something like the following:
09 92 3C 64
Cable 0
Code Index Number 9
MIDI Cmd 0x90 (Note On)
MIDI Channel 3 (0x0=1; 0x1=2; 0x2=3; ... 0xF=16)
Note 0x3C (60 = C4)
Velocity 0x64 (100)But things get a little more complex with System Common or System Exclusive messages which have their own set of codes, depending on the chunking of the packets required.
The critical ones for SysEx are CIN=4,5,6,7 which correspond to SysEx start and then various versions of continuation or end packets. So a larger SysEx message might look something like the following
04 F0 43 10 -- SysEx Start or Continuation
04 34 44 4D -- SysEx Start or Continuation
06 3E F7 00 -- SysEx End after two bytes
Complete message: F0 43 10 34 44 4D 3E F7So, if I opt to use the packet interface to TinyUSB MIDI then all this has to be sorted out in user code myself. However, the streaming interface will take care of all this for me and just return a buffer full of “traditional” MIDI messages.
Note that there is no concept of Running Status in USB MIDI. Even the oldest USB standard protocol speeds are an order of magnitude, or more, higher than serial MIDI so it isn’t necessary. Every MIDI message will either be a complete 1,2,3 byte message in a single USB packet, or a SysEx multi-packet message as described above.
The basic structure of the USB MIDI handler is as follows:
Init:
Initialise TinyUSB MIDI stack
Process:
Run the TinyUSB MIDI task
IF TinyUSB says MIDI data available:
Call the stream API to fill our RX buffer
WHILE data in the RX buffer:
Call the MIDIParser which reads from the RX buffer
IF MIDI messages found:
Call the MIDI Message Handler
Read:
Grab the next byte from the RX bufferI’ve actually split this over two files: usbmidi.cpp is the companion to serialmidi.cpp and provides the class that inherits from MIDIDevice (which provides the parser and message handler); usbtask.c provides the interface into the TinyUSB C driver code.
I haven’t done anything special with a USB manufacturer/vendor and device ID yet – so at some point I should see what TinyUSB is using by default and find something unique to PicoDexed (assuming I take it forward in any useful way).
Closing Thoughts
I have a fairly complete implementation now, which is quite nice. I do need to find some way to properly exercise the voice loading over SysEx and it would be good to get some idea of the performance when I throw a MIDI file at it over USB!
I’ve tested some of the parameter changes using the PC version of Dexed. When configured correctly, this can be used to send voice parameter changes to PicoDexed, but I haven’t found a way to download the entire voice as yet.
It’s a shame I can’t just plug in a USB MIDI controller and play it now, but I’ll work on some kind of interface board that should allow me to do it. It will need to be independently powered to act as a USB host anyway.
This is probably going to be my last blog post on PicoDexed for now, but I plan to keep tinkering away at the GitHub repository to see how things go. There are still a couple of limitations, the main one being that everything has to be hard-coded in at present. It would be nice to be able to have some kind of system configuration facility for the MIDI channel if nothing else.
At some point it would also be nice to have a build on the GitHub so others can try it too. And I still need to decide how best to manage the changes I needed to make to Synth_Dexed.
Kevin
https://diyelectromusic.wordpress.com/2024/02/16/raspberry-pi-pico-synth_dexed-part-4/
-
@alanz OK, so it turns out that it is probably Onyx who have fuxnored this one:
https://github.com/AntennaPod/AntennaPod/issues/6244#issuecomment-1356846312
I've dropped them a couple of lengthy notes on this and some related UI/UX churn which has become annoying.
@jwz has a few excellent commentaries on the value of GUIs, how much improvement is possible through changing them (little if any), and the importance of consistent and common interfaces, rather than domain-specific specialisation. See especially:
"Unity of Interface" (1998)
Short of being cross-platform (which deserves a document of its own) Mozilla's greatest strength is that it manages to provide a unified interface to a number of useful services and protocols.
It is more interesting to support a concept than to support a particular implementation of it.
https://www.jwz.org/doc/unity-of-interface.html
"Why I use Safari instead of Firefox"
The Firefox UI is a moving target. It is under constant "improvement", which means "change" which means every few months I'm forced to upgrade it and shit has moved around and I need to re-learn how to do a task that I was happily doing before. This does not often happen with Safari. Their UI has been remarkably stable for many, many years. ...
Maybe the Firefox team is right, and you can develop a better UI that way. Well, they haven't yet proved this, because Apple's UI is better.
Look, in the case of all other software, I believe strongly in "release early, release often". Hell, I damned near invented it. But I think history has proven that UI is different than software.
https://www.jwz.org/blog/2012/04/why-i-use-safari-instead-of-firefox/
#Onyx #Boox #UIUX #DontFuckWithTheInterface #jwz #Mozilla #Safari
-
^🧵 My Musings About #devRant Alternative, 7
Platforms here are distributed, but have a lot of features in common. One being the protocol, ActivityPub. You can even integrate its implementation into your blog! Flipbook and other previously separate platforms cross the barrier and unite.
What does posting on Fediverse look like and how different it is from devRant posts and comments? Post can have plain text and rich media. Particularly neat thing is that you are presented with ability to add an alt text to image/video/audio, making it accessible to visually impaired. Orphaned post published without a context already acts as a "rant"/"story" of sorts, you just should remember to add categorization hashtags to it for clarity or hide the entire thing behind CW (content warning), which is handy for... hard or boiling hot topics. Post made in reply to another can act as a "comment". Nevertheless, each post is an individual piece that can be boosted without context.